Skip to content

Centralize C# type attribute back-compat merging in TypeProvider#11237

Draft
jorgerangel-msft with Copilot wants to merge 8 commits into
mainfrom
copilot/centralize-type-attribute-merging
Draft

Centralize C# type attribute back-compat merging in TypeProvider#11237
jorgerangel-msft with Copilot wants to merge 8 commits into
mainfrom
copilot/centralize-type-attribute-merging

Conversation

Copilot AI commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Attribute back-compat merging (generated + last-contract + custom-code) was owned locally by CanonicalTypeProvider.BuildAttributes(). This moves that logic into a shared TypeProvider API so it follows the existing centralized back-compat pattern (Build*ForBackCompatibility).

Changes

  • TypeProvider: Added BuildAttributesForBackCompatibility() that:
    • restores compatible attributes from the last contract (non-public types only),
    • merges generated (Attributes) and custom-code (CustomCodeView.Attributes) attributes,
    • filters CodeGen-specific attributes (CodeGenSuppress/CodeGenMember/CodeGenType/CodeGenSerialization) that should not be preserved,
    • deduplicates by rendered display string.
  • CanonicalTypeProvider: BuildAttributes() now delegates to the shared API instead of owning merge/dedup logic.
  • Tests: Added coverage for the merge/dedup behavior.

Because the method reads Attributes, CustomCodeView, LastContractView, and DeclarationModifiers from the provider, invoking it on the generated provider reproduces the previous merge exactly:

protected override IReadOnlyList<MethodBodyStatement> BuildAttributes()
    => _generatedTypeProvider.BuildAttributesForBackCompatibility();

Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com>
@microsoft-github-policy-service microsoft-github-policy-service Bot added the emitter:client:csharp Issue for the C# client emitter: @typespec/http-client-csharp label Jul 13, 2026
/// types and exclude CodeGen-specific attributes that should not be preserved. The merged result is
/// deduplicated so identical attributes are only emitted once.
/// </summary>
protected internal IReadOnlyList<AttributeStatement> BuildAttributesForBackCompatibility()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot this method should simply add any new back compat attributes that don't exist in the original list (generated + custom).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reworked in 4f3265a. BuildAttributesForBackCompatibility() now only appends back-compat attributes from the last contract that aren't already in the original (generated + custom) set, returning the original list unchanged when there's nothing new. It's now invoked from the centralized ProcessTypeForBackCompatibility flow (which updates the generated provider's attributes) rather than from CanonicalTypeProvider.

Copilot AI and others added 2 commits July 13, 2026 20:37
Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com>
Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com>
Copilot AI changed the title [WIP] Centralize type attribute back-compat merging in C# generator Centralize C# type attribute back-compat merging in TypeProvider Jul 13, 2026
Copilot AI requested a review from jorgerangel-msft July 13, 2026 20:39
Copilot AI and others added 2 commits July 13, 2026 21:03
… attributes, perf

Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com>
Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com>
/// <summary>
/// Builds the set of type-level attributes to emit, adding any back-compatibility attributes
/// restored from the last contract that are not already present in the original set of generated
/// and custom-code attributes. Attributes are only restored for non-public types (which are the

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot "Attributes are only restored for non-public type" . We should only be restoring attributes for public types. Why are we doing the opposite based on this comment?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed the public/non-public gating (and the misleading comment) entirely. The method no longer conditions restoration on type visibility — it simply appends any new back-compat attributes from the last contract.

/// only ones that can be internalized) and CodeGen-specific attributes are never restored. The
/// original attributes are returned unchanged when there is nothing new to add.
/// </summary>
protected internal IReadOnlyList<AttributeStatement> BuildAttributesForBackCompatibility()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot this signature should be BuildAttributesForBackCompatibility(IEnumerable<AttributeStatement> originalattributes

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the signature to BuildAttributesForBackCompatibility(IEnumerable<AttributeStatement> originalAttributes), matching the other Build*ForBackCompatibility methods.

{
var originalAttributes = Attributes;

// Only non-public types can be internalized for back-compatibility, so attributes from the last

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot why are we internalizing anything?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed the internalization logic. There's no longer any public/non-public gating — the method just merges new back-compat attributes into the original set.

@pkg-pr-new

pkg-pr-new Bot commented Jul 13, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@typespec/http-client-csharp@11237

commit: 921c0ec

…p internalize gating, add tests

Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com>
Comment on lines +739 to +742
// Restore any back-compat attributes from the last contract that are not already present in the
// generated or custom-code attributes. BuildAttributesForBackCompatibility returns either the
// current attributes unchanged or a superset with the restored attributes appended, so a larger
// count reliably signals that new attributes were added.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot remove this comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed the comment.

var attributes = provider.GetBackCompatibilityAttributes([]);

Assert.AreEqual(1, attributes.Count);
Assert.AreEqual("ObsoleteAttribute", attributes[0].Type.Name);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot we should be using TestData for all assertions against generated code

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the back-compat attribute tests to render the type and compare against TestData .cs files (via Helpers.GetExpectedFromFile()) instead of inspecting attributes[0].Type.Name.

…tions

Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

emitter:client:csharp Issue for the C# client emitter: @typespec/http-client-csharp

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Centralize type attribute back-compat merging in C# generator

2 participants