diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ModelProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ModelProvider.cs index e0766da6f75..5dae59bf948 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ModelProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ModelProvider.cs @@ -27,12 +27,13 @@ protected override FormattableString BuildDescription() { var description = DocHelpers.GetFormattableDescription(_inputModel.Summary, _inputModel.Doc) ?? $"The {Name}."; - if (DeclarationModifiers.HasFlag(TypeSignatureModifiers.Abstract)) + if (_isDiscriminatedBaseType) { _derivedModels = BuildDerivedModels(); var publicDerivedModels = _derivedModels.Where(m => m.DeclarationModifiers.HasFlag(TypeSignatureModifiers.Public)).ToList(); - var derivedClassesDescription = - "Please note this is the abstract base class. The derived classes available for instantiation are: "; + var derivedClassesDescription = DeclarationModifiers.HasFlag(TypeSignatureModifiers.Abstract) + ? "Please note this is the abstract base class. The derived classes available for instantiation are: " + : "Please note this is the base class. The derived classes available for instantiation are: "; bool addComma = publicDerivedModels.Count > 2; for (int i = 0; i < publicDerivedModels.Count; i++) { @@ -65,11 +66,15 @@ protected override FormattableString BuildDescription() private ModelProvider? _baseModelProvider; private ConstructorProvider? _fullConstructor; internal PropertyProvider? DiscriminatorProperty { get; private set; } + + private readonly bool _isDiscriminatedBaseType; + private ValueExpression DiscriminatorLiteral => Literal(_inputModel.DiscriminatorValue ?? ""); public ModelProvider(InputModelType inputModel) : base(inputModel) { _inputModel = inputModel; + _isDiscriminatedBaseType = inputModel.DiscriminatorProperty is not null && inputModel.DiscriminatorValue is null; _isMultiLevelDiscriminator = ComputeIsMultiLevelDiscriminator(); _useObjectAdditionalProperties = new Lazy(ShouldUseObjectAdditionalProperties); } @@ -324,7 +329,7 @@ protected override TypeSignatureModifiers BuildDeclarationModifiers() declarationModifiers |= TypeSignatureModifiers.Internal; } - if (_inputModel.DiscriminatorProperty is not null && _inputModel.DiscriminatorValue is null) + if (_isDiscriminatedBaseType) { declarationModifiers |= TypeSignatureModifiers.Abstract; } diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/DiscriminatorTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/DiscriminatorTests.cs index a3666593986..5e5e6cb31ec 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/DiscriminatorTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/DiscriminatorTests.cs @@ -120,6 +120,34 @@ public void BaseShouldBeAbstract(InputModelType inputModel, string expectedSumma Assert.AreEqual(expectedSummary, baseModel.XmlDocs.Summary!.ToDisplayString()); } + [TestCase(true, "Please note this is the abstract base class. The derived classes available for instantiation are: , , and .")] + [TestCase(false, "Please note this is the base class. The derived classes available for instantiation are: , , and .")] + public void DiscriminatedBaseDescriptionReflectsAbstractness(bool isAbstract, string expectedDescription) + { + MockHelpers.LoadMockGenerator(); + // When not abstract, simulate a downstream emitter that does not model the discriminated base type as abstract. + var baseModel = isAbstract + ? CodeModelGenerator.Instance.TypeFactory.CreateModel(_baseModel)! + : new NonAbstractModelProvider(_baseModel); + Assert.AreEqual(isAbstract, baseModel.DeclarationModifiers.HasFlag(TypeSignatureModifiers.Abstract)); + + // The discriminated base description should reference derived models regardless of abstractness. + Assert.IsNotNull(baseModel.XmlDocs.Summary); + StringAssert.Contains(expectedDescription, baseModel.XmlDocs.Summary!.ToDisplayString()); + } + + private class NonAbstractModelProvider : ModelProvider + { + public NonAbstractModelProvider(InputModelType inputModel) : base(inputModel) + { + } + + protected override TypeSignatureModifiers BuildDeclarationModifiers() + { + return base.BuildDeclarationModifiers() & ~TypeSignatureModifiers.Abstract; + } + } + [Test] public void DiscriminatorPropertyShouldBeInternal() {