Skip to content

[http-client-csharp] Emit Obsolete attributes for deprecated APIs - #12394

Open
JoshLove-msft wants to merge 9 commits into
microsoft:mainfrom
JoshLove-msft:joshlove-msft-csharp-deprecation-attributes
Open

JoshLove-msft wants to merge 9 commits into
microsoft:mainfrom
JoshLove-msft:joshlove-msft-csharp-deprecation-attributes

Conversation

@JoshLove-msft

Copy link
Copy Markdown
Contributor

Fixes #12392.

Changes

  • Emit warning-only Obsolete attributes from TypeSpec #deprecated metadata on models, fixed/extensible enums, and synchronous/asynchronous protocol and convenience methods. Preserve messages, including empty strings and C# escaping.
  • Preserve the last released GA contract: existing APIs that were not obsolete do not gain the attribute. Apply the same rule after parameter reordering and to compatibility overloads. New APIs and previously experimental APIs can be marked obsolete; already obsolete APIs use the current message.
  • Respect customization-supplied attributes without duplicating them on partial implementations.
  • Suppress obsolete-reference diagnostics within generated implementation code while retaining consumer warnings.
  • Add metadata, provider, output-baseline, customization, compatibility, and generated-library coverage; regenerate the sample and all Spector libraries.

Validation

  • Package build and API extraction passed; the generator solution, including generated libraries, builds with warnings as errors.
  • Core generator: 2,967 passed; client generator: 2,620 passed; input: 307 passed; generated local libraries: 738 passed.
  • Emitter: 396 passed, 2 skipped (serial run to avoid an existing five-second test timeout under concurrent builds).
  • Repository/package formatting, emitter type-aware oxlint, and Cop checks passed. The package's existing ESLint script references an unavailable tool, so linting used the repository's configured oxlint instead.
  • A separate consumer build reported the expected CS0618 diagnostics for the model, both enum forms, and the operation.

Windows validation used temporary drive mappings to avoid existing long-path limitations. Regeneration reported restore/artifact-path warnings for some long Spector paths; the subsequent shortened-path solution build succeeded.

Preserve non-obsolete GA contracts and compatibility overloads while exposing TypeSpec deprecation messages on new APIs.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI balanced review requested due to automatic review settings October 23, 2026 20:25
@microsoft-github-policy-service microsoft-github-policy-service Bot added emitter:client:csharp Issue for the C# client emitter: @typespec/http-client-csharp auto-merge Automatically merge the pull request after all requirements pass labels Oct 23, 2026

@microsoft-github-policy-service microsoft-github-policy-service Bot left a comment

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.

Approved automatically for a Dependabot update.

@pkg-pr-new

pkg-pr-new Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

Open in StackBlitz

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

commit: 60343df

@github-actions

Copy link
Copy Markdown
Contributor

No changes needing a change description found.

Copilot AI left a comment

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.

🟡 Changes recommended

Shared partial-method handling duplicates customization-supplied obsolete attributes, causing generated-library compilation errors.

1 open issue
What changed in this PR

Adds native C# deprecation warnings from TypeSpec #deprecated metadata, addressing #12392 while preserving published API compatibility.

Changes:

  • Emit warning-only Obsolete attributes on models, enums, and operation methods.
  • Handle published contracts, customization attributes, and generated-code warning suppression.
  • Add metadata, provider, baseline, and generated-library coverage, plus documentation.
File Description
packages/​http-client-csharp/​generator/​TestProjects/​Local/​Sample-TypeSpec/​src/​Generated/​SampleTypeSpecModelFactory.cs Adds factories for deprecation samples with warning suppression.
packages/​http-client-csharp/​generator/​TestProjects/​Local/​Sample-TypeSpec/​src/​Generated/​SampleTypeSpecClient.cs Exposes the deprecation sample subclient.
packages/​http-client-csharp/​generator/​TestProjects/​Local/​Sample-TypeSpec/​src/​Generated/​Models/​SampleTypeSpecContext.cs Registers sample models and suppresses obsolete-reference warnings.
packages/​http-client-csharp/​generator/​TestProjects/​Local/​Sample-TypeSpec/​src/​Generated/​Models/​LegacyExtensibleChoice.cs Demonstrates a deprecated extensible enum.
packages/​http-client-csharp/​generator/​TestProjects/​Local/​Sample-TypeSpec/​src/​Generated/​Models/​LegacyDetails.Serialization.cs Adds serialization for the deprecated model.
packages/​http-client-csharp/​generator/​TestProjects/​Local/​Sample-TypeSpec/​src/​Generated/​Models/​LegacyDetails.cs Demonstrates an escaped deprecation message.
packages/​http-client-csharp/​generator/​TestProjects/​Local/​Sample-TypeSpec/​src/​Generated/​Models/​LegacyChoice.Serialization.cs Suppresses warnings in deprecated enum serialization.
packages/​http-client-csharp/​generator/​TestProjects/​Local/​Sample-TypeSpec/​src/​Generated/​Models/​LegacyChoice.cs Demonstrates a deprecated fixed enum.
packages/​http-client-csharp/​generator/​TestProjects/​Local/​Sample-TypeSpec/​src/​Generated/​Models/​CurrentDetails.Serialization.cs Handles deprecated references during serialization.
packages/​http-client-csharp/​generator/​TestProjects/​Local/​Sample-TypeSpec/​src/​Generated/​Models/​CurrentDetails.cs Demonstrates inheritance and collections involving deprecated types.
packages/​http-client-csharp/​generator/​TestProjects/​Local/​Sample-TypeSpec/​src/​Generated/​DeprecationSamples.RestClient.cs Adds request builders for sample operations.
packages/​http-client-csharp/​generator/​TestProjects/​Local/​Sample-TypeSpec/​src/​Generated/​DeprecationSamples.cs Demonstrates deprecated protocol and convenience methods.
packages/​http-client-csharp/​generator/​TestProjects/​Local/​Sample-TypeSpec/​Sample-TypeSpec.tsp Defines deprecation sample types and operations.
packages/​http-client-csharp/​generator/​TestProjects/​Local.Tests/​CustomizationTests.cs Verifies generated attributes and warning-only messages.
packages/​http-client-csharp/​generator/​Microsoft.TypeSpec.Generator/​test/​Writers/​TypeProviderWriterTests.cs Adds escaped-message output coverage.
packages/​http-client-csharp/​generator/​Microsoft.TypeSpec.Generator/​test/​Writers/​TestData/​TypeProviderWriterTests/​WriteDeprecatedEnumWithEscapedMessage.cs Records the expected escaped attribute output.
packages/​http-client-csharp/​generator/​Microsoft.TypeSpec.Generator/​test/​Providers/​TypeProviderTests.cs Tests attributes, customization, and contract preservation.
packages/​http-client-csharp/​generator/​Microsoft.TypeSpec.Generator/​test/​Providers/​TestData/​TypeProviderTests/​DeprecationPreservesLastContract/​Types.cs Supplies published type-contract fixtures.
packages/​http-client-csharp/​generator/​Microsoft.TypeSpec.Generator/​test/​Providers/​TestData/​TypeProviderTests/​DeprecationPreservesBackCompatOverloads/​LegacyClient.cs Supplies compatibility-overload contract fixtures.
packages/​http-client-csharp/​generator/​Microsoft.TypeSpec.Generator/​test/​Providers/​TestData/​TypeProviderTests/​DeprecatedCustomModelKeepsExistingAttribute/​Legacy.cs Supplies custom obsolete type declarations.
packages/​http-client-csharp/​generator/​Microsoft.TypeSpec.Generator/​test/​common/​InputFactory.cs Supports deprecation metadata in test inputs.
packages/​http-client-csharp/​generator/​Microsoft.TypeSpec.Generator/​src/​Utilities/​BackCompatHelper.cs Preserves obsolete status on compatibility overloads.
packages/​http-client-csharp/​generator/​Microsoft.TypeSpec.Generator/​src/​Shared/​ExperimentalApiHelpers.cs Extends reference suppression to obsolete APIs.
packages/​http-client-csharp/​generator/​Microsoft.TypeSpec.Generator/​src/​Shared/​DeprecationApiHelpers.cs Centralizes obsolete attributes and warning suppressions.
packages/​http-client-csharp/​generator/​Microsoft.TypeSpec.Generator/​src/​Providers/​TypeProvider.cs Emits type attributes and preserves published method status.
packages/​http-client-csharp/​generator/​Microsoft.TypeSpec.Generator/​src/​Providers/​NamedTypeSymbolProvider.cs Reads obsolete metadata from method symbols.
packages/​http-client-csharp/​generator/​Microsoft.TypeSpec.Generator/​src/​Providers/​EnumProvider.cs Uses shared deprecation metadata initialization.
packages/​http-client-csharp/​generator/​Microsoft.TypeSpec.Generator.ClientModel/​test/​Providers/​TestData/​ScmMethodProviderCollectionTests/​DeprecationPreservesLastContractMethods/​TestClient.cs Supplies published client-method fixtures.
packages/​http-client-csharp/​generator/​Microsoft.TypeSpec.Generator.ClientModel/​test/​Providers/​TestData/​ScmMethodProviderCollectionTests/​DeprecatedCustomizedPartialMethodsKeepExistingAttributes/​TestClient.cs Supplies custom obsolete partial-method declarations.
packages/​http-client-csharp/​generator/​Microsoft.TypeSpec.Generator.ClientModel/​test/​Providers/​ScmMethodProviderCollectionTests.cs Tests client-method deprecation and customization behavior.
packages/​http-client-csharp/​generator/​Microsoft.TypeSpec.Generator.ClientModel/​src/​Providers/​ScmMethodProviderCollection.cs Applies operation attributes and dependency suppressions.
packages/​http-client-csharp/​emitter/​test/​Unit/​operation-converter.test.ts Tests operation metadata propagation and serialization.
packages/​http-client-csharp/​emitter/​test/​Unit/​model-type.test.ts Tests model and enum metadata propagation.
packages/​http-client-csharp/​docs/​emitter.md Documents deprecation and compatibility behavior.

Review effort: Balanced

Keep customization-owned Obsolete attributes on the defining declaration in the shared partial-signature builder, covering non-client methods as well as operation methods.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI balanced review requested due to automatic review settings October 23, 2026 21:21

Copilot AI left a comment

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.

🟡 Changes recommended

Combined experimental/deprecated models can leave build warnings unsuppressed, and compatibility overloads can lose existing deprecation warnings.

1 open issue
1 previously missed issue

In code that hasn't changed since last review

Medium severity Preserve Obsolete message when restoring GA overloads

packages/​http-client-csharp/​generator/​Microsoft.TypeSpec.Generator.ClientModel/​src/​Providers/​ScmMethodProviderCollection.cs:1166

If the GA contract contains obsolete Read(int value) and non-obsolete Read(int value, bool added = false), this early filtering removes the current deprecation message, so BackCompatHelper.cs:534–543 strips Obsolete from the restored one-parameter overload. Defer GA filtering to the existing post-overload pass in TypeProvider.cs:1254–1263 so the stable signature stays unchanged while the already-obsolete overload retains the current message.

1 resolved since last review

Review effort: Balanced

Suppress all experimental and obsolete diagnostics on generated model registrations. Defer GA method filtering until after compatibility overload restoration so previously obsolete overloads retain the current message.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI balanced review requested due to automatic review settings October 23, 2026 22:13
@JoshLove-msft

Copy link
Copy Markdown
Contributor Author

Fixed the mixed GA-overload case from the latest review in fb5bf95 as well. Deprecation metadata is now retained until compatibility overloads are restored, then the existing final GA pass removes it only from signatures that were previously non-obsolete. An already-obsolete restored overload keeps the current message, while the stable overload remains non-obsolete. Added a sync/async regression covering the mixed contract.

--generated by Copilot

Copilot AI left a comment

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.

🔵 Needs a closer look

The interacting changes to published-contract preservation, partial-method attributes, and diagnostic suppression warrant final human review despite the extensive regression coverage.

No open issues 🎉

1 resolved since last review

Review effort: Balanced

Keep custom Experimental and Obsolete attributes on partial declarations through the shared signature builder. Cover non-client block- and expression-bodied methods, and remove the requested emitter documentation changes.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI balanced review requested due to automatic review settings October 24, 2026 02:11

Copilot AI left a comment

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.

🔵 Needs a closer look

Released-contract compatibility remains unresolved, and the interactions between attribute caching, visitors, and warning suppression warrant final human review.

No open issues 🎉

1 previously missed issue

In code that hasn't changed since last review

Medium severity Refresh obsolete metadata after identity changes

packages/​http-client-csharp/​generator/​Microsoft.TypeSpec.Generator/​src/​Providers/​TypeProvider.cs:775

If a visitor renames or moves a deprecated type to an existing, non-obsolete GA identity after Attributes has been read, the cached Obsolete attribute survives and introduces consumer warnings on that stable API. ResetMembersBasedOnIdentityChange refreshes LastContractView but leaves _attributes intact (TypeProvider.cs:986–1013). Re-evaluate generated deprecation metadata against the final identity without discarding visitor-supplied attributes, and add a regression that reads attributes before renaming.

Review effort: Balanced

Re-evaluate generated obsolete metadata after visitor renames and namespace changes while preserving visitor-added attributes and explicit removals. Prevent stale attribute snapshots from restoring obsolete warnings on non-obsolete GA types.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI balanced review requested due to automatic review settings October 24, 2026 03:11
@JoshLove-msft

Copy link
Copy Markdown
Contributor Author

Fixed the cached-attribute identity issue from the latest review in 96f0a6e. Generated deprecation metadata is now re-evaluated after type updates against the final identity and released contract. Visitor-added attributes, explicit removals, and replacement Obsolete messages are preserved; applying a stale pre-rename attribute list cannot reintroduce a generated warning on a non-obsolete GA type.

Added rename/namespace-change regressions for models and both enum forms, transitions to and from GA identities, customization precedence, visitor overrides, stale attribute snapshots, and final generated output.

--generated by Copilot

Copilot AI left a comment

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.

🔵 Needs a closer look

Compatibility and customization interactions warrant human validation, with an unresolved suppression gap for custom obsolete diagnostic IDs.

No open issues 🎉

1 previously missed issue

In code that hasn't changed since last review

Medium severity Preserve custom Obsolete DiagnosticId in generated suppressions

packages/​http-client-csharp/​generator/​Microsoft.TypeSpec.Generator/​src/​Shared/​ExperimentalApiHelpers.cs:114

A customization such as [Obsolete("Use Current instead.", DiagnosticId = "OBS001")] produces OBS001, not CS0618, but this branch reduces every obsolete attribute to the two default warning codes. Generated serialization references to that customized API therefore still fail warnings-as-errors builds; retain and suppress the attribute's named DiagnosticId, as ModelReaderWriterContextDefinition.cs:667–669 already does for framework types.

Review effort: Balanced

Read named Obsolete DiagnosticId values for generated reference and context suppressions. Preserve custom diagnostics in compatibility forwarding and cover model/enum references, deserialization output, defaults, and invalid identifiers.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI balanced review requested due to automatic review settings October 24, 2026 04:09
@JoshLove-msft

Copy link
Copy Markdown
Contributor Author

Fixed the custom obsolete diagnostic-ID finding from the latest review in 7f98ceb. Generated suppressions now read the named Obsolete.DiagnosticId and preserve it for type references, deserialization, model registrations, and compatibility forwarding instead of reducing it to CS0612/CS0618. Missing, null, and empty IDs retain the existing default behavior.

Added regressions for custom model/enum and collection references, deserialization output, context registration, compatibility overloads, and diagnostic identifier handling. Compiled the generated deserialization with warnings treated as errors and verified a separate consumer still receives OBS001.

--generated by Copilot

Copilot AI left a comment

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.

🔵 Needs a closer look

Customization-owned protocol deprecation diagnostics can remain unsuppressed in generated convenience methods, breaking warnings-as-errors builds.

No open issues 🎉

1 previously missed issue

In code that hasn't changed since last review

Medium severity Preserve Obsolete attributes when collecting protocol suppressions

packages/​http-client-csharp/​generator/​Microsoft.TypeSpec.Generator.ClientModel/​src/​Providers/​ScmMethodProviderCollection.cs:303

BuildPartialSignature removes customization-owned Obsolete attributes from the generated protocol signature (PartialMethodCustomization.cs:209–210), so this lookup misses them. If only the protocol partial declaration is marked [Obsolete(..., DiagnosticId = "OBS001")], its non-obsolete convenience method calls it without suppressing OBS001 and fails a warnings-as-errors build; also inspect the matching custom protocol declaration when collecting these suppressions.

Review effort: Balanced

Include matching custom protocol declarations when collecting convenience call-site warnings and avoid inheriting partial modifiers onto ordinary convenience overloads. Cover sync/async obsolete, experimental, combined, and stable declarations plus a compiled sample.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI balanced review requested due to automatic review settings October 24, 2026 05:08
@JoshLove-msft

Copy link
Copy Markdown
Contributor Author

Fixed the custom protocol-declaration suppression gap from the latest review in 86cd139. Convenience methods now collect call-site diagnostics from both the generated protocol signature and its matching custom declaration, including custom obsolete IDs and experimental IDs. Diagnostics already covered by the convenience declaration are not added redundantly, and the convenience API does not gain the attributes from the protocol declaration.

The regression also exposed the protocol-only partial modifier being copied to a non-customized convenience overload; that modifier is now cleared. Added sync/async custom-ID, parameterless-obsolete, experimental, combined, unrelated-overload, and stable controls. A generated sample with protocol-only OBS001/OBS002 declarations builds with warnings treated as errors, and reflection verifies the convenience overloads remain non-obsolete.

--generated by Copilot

Copilot AI left a comment

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.

🟡 Changes recommended

Renamed deprecated fixed enums can lose serialization warning suppressions and break generated-library warnings-as-errors builds.

1 open issue

Review effort: Balanced

Remove mutable type-map keys before name or namespace updates and reinsert owned mappings afterward. Refresh serialization caches so renamed enum helpers retain warning suppressions and final identities.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI balanced review requested due to automatic review settings October 24, 2026 06:02

Copilot AI left a comment

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.

🔵 Needs a closer look

An unresolved provider-mapping collision and coupled compatibility, customization, and diagnostic changes require correction and final human review.

1 open issue
1 resolved since last review

Review effort: Balanced

Resolve name and namespace together so provider reindexing never overwrites an unrelated intermediate identity. Cover models and both enum forms with retained warning lookup.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI balanced review requested due to automatic review settings October 24, 2026 06:55

Copilot AI left a comment

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.

🔵 Needs a closer look

Interactions among published API compatibility, partial customization, diagnostic suppression, and provider identity updates warrant final human review.

No open issues 🎉

1 resolved since last review

Review effort: Balanced

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

auto-merge Automatically merge the pull request after all requirements pass 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.

[http-client-csharp] Generate Obsolete attributes from TypeSpec deprecation metadata

2 participants