Skip to content

C# emitter: discriminated base type with no public derived models emits a dangling "instantiation are: " with trailing whitespace #11769

Description

@JoshLove-msft

Describe the bug

ModelProvider.BuildDescription appends the sentence "...The derived classes available for instantiation are: " for any discriminated base type, and then loops over the public derived models to fill in the list:

https://github.com/microsoft/typespec/blob/main/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ModelProvider.cs

var publicDerivedModels = _derivedModels.Where(m => m.DeclarationModifiers.HasFlag(TypeSignatureModifiers.Public)).ToList();
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: ";

for (int i = 0; i < publicDerivedModels.Count; i++) { ... }

description = $"{description}\n{derivedClassesDescription}";

When every derived model is internal, publicDerivedModels is empty, the loop body never executes, and the sentence is emitted with nothing after it. Two problems result:

  1. Semantic — the doc promises a list of instantiable derived classes and then provides none. There are no public derived classes, so the sentence should not be emitted at all.
  2. Trailing whitespace — the description ends with the dangling "are: ", so the generated /// line has a trailing space. This trips git diff --check and any whitespace linting on generated output.

Reproduction

A discriminated base type whose only derived type is the generated Unknown* fallback (which is internal). Generated output:

/// <summary>
/// LimitJson abstract class.
/// Please note this is the abstract base class. The derived classes available for instantiation are: 
/// </summary>

Note the trailing space after are:. Compare with a type that does have a public derived model, which renders correctly:

/// Please note this is the abstract base class. The derived classes available for instantiation are: <see cref="Models.TypeAPolyDevice"/>.

Real-world impact

This is present in committed output today. In Azure/azure-sdk-for-net, on main:

  • eng/packages/http-client-csharp-mgmt/generator/TestProjects/Local/Mgmt-TypeSpec/src/Generated/Models/LimitJsonObject.cs:16
  • eng/packages/http-client-csharp-mgmt/generator/TestProjects/Local/Mgmt-TypeSpec/src/Generated/Models/LimitJsonObject.Serialization.cs:17

and in shipped SDKs, e.g. sdk/machinelearningservices/Azure.Provisioning.MachineLearning/src/Generated/Models/MachineLearningDatastoreSecrets.cs:14 and sdk/servicefabric/Azure.Provisioning.ServiceFabric/src/Generated/Models/ServicePlacementPolicyDescription.cs:14.

Suggested fix

Skip the appended sentence entirely when publicDerivedModels.Count == 0, which resolves both the dangling prose and the trailing whitespace.

Checklist

  • Follow our Code of Conduct
  • Check that there isn't already an issue that reports the same bug

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingemitter:client:csharpIssue for the C# client emitter: @typespec/http-client-csharp

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions