Skip to content

Add authoring analyzers for [ApiContract] and [ContractVersion]#2407

Open
Sergio0694 wants to merge 17 commits intostaging/3.0from
user/sergiopedri/authoring-analyzers
Open

Add authoring analyzers for [ApiContract] and [ContractVersion]#2407
Sergio0694 wants to merge 17 commits intostaging/3.0from
user/sergiopedri/authoring-analyzers

Conversation

@Sergio0694
Copy link
Copy Markdown
Member

Summary

Adds a set of new Roslyn diagnostic analyzers in the WinRT.SourceGenerator2 project that validate Windows Runtime component authoring usage of [ApiContract] and [ContractVersion]. Also introduces small reusable extension helpers and refines the public surface of ContractVersionAttribute.

All new analyzers are scoped to component-authoring scenarios (CsWinRTComponent = true) and are skipped otherwise.

Motivation

Authoring Windows Runtime components in C# has a number of WinMD-level constraints that are easy to get wrong silently — invalid [ApiContract] enum cases, mismatched [ContractVersion] constructor usage, missing contract version metadata, etc. These analyzers surface those issues at edit/build time with actionable diagnostics, rather than producing a malformed .winmd that fails (or worse, succeeds with wrong metadata) downstream.

Changes

New diagnostics (CSWINRT2010CSWINRT2015)

  • CSWINRT2010ValidApiContractEnumTypeAnalyzer (Warning): warns when an [ApiContract] enum defines enum cases. API contract types are represented as empty struct types in WinRT and any enum cases are ignored when generating the .winmd.
  • CSWINRT2011 / CSWINRT2012 / CSWINRT2013ValidContractVersionAttributeAnalyzer (Warning): validates [ContractVersion] applications:
    • 2011: the (uint) and (string, uint) constructors must target an API contract type.
    • 2012: the (Type, uint) constructor must not target an API contract type.
    • 2013: the Type argument of the (Type, uint) constructor must itself be a valid API contract type.
  • CSWINRT2014ApiContractTypeRequiresContractVersionAnalyzer (Warning): every [ApiContract] enum must declare its contract version using a version-only constructor of [ContractVersion].
  • CSWINRT2015PublicTypeRequiresContractVersionAnalyzer (Info): public top-level types in a component should declare their associated API contract via [ContractVersion(typeof(SomeContract), version)]. Skips API contract enums (covered by CSWINRT2014) and types that already have any [ContractVersion] applied (validity is reported by CSWINRT2011CSWINRT2013).

Files

  • src/Authoring/WinRT.SourceGenerator2/Diagnostics/Analyzers/: new analyzers ValidApiContractEnumTypeAnalyzer, ValidContractVersionAttributeAnalyzer, ApiContractTypeRequiresContractVersionAnalyzer, PublicTypeRequiresContractVersionAnalyzer.
  • src/Authoring/WinRT.SourceGenerator2/Diagnostics/DiagnosticDescriptors.cs: descriptors for CSWINRT2010CSWINRT2015.
  • src/Authoring/WinRT.SourceGenerator2/AnalyzerReleases.Shipped.md: release tracking entries for the new diagnostics.
  • src/Authoring/WinRT.SourceGenerator2/Extensions/AttributeDataExtensions.cs: new AttributeData.GetLocation(...) and AttributeData.GetArgumentLocation(int, ...) extensions, factored out of the analyzer code.
  • src/Authoring/WinRT.SourceGenerator2/Extensions/ISymbolExtensions.cs: new ISymbol.GetAttributes(INamedTypeSymbol) overload that yields only attributes of the specified type, eliminating the manual foreach + SymbolEqualityComparer filter pattern at call sites.
  • src/WinRT.Runtime2/Windows.Foundation.Metadata/ContractVersionAttribute.cs: small API/doc tweaks aligned with the new analyzer expectations.
  • src/Tests/SourceGenerator2Test/:
    • Test_ValidApiContractEnumTypeAnalyzer.cs, Test_ValidContractVersionAttributeAnalyzer.cs, Test_ApiContractTypeRequiresContractVersionAnalyzer.cs, Test_PublicTypeRequiresContractVersionAnalyzer.cs.
    • Helpers/CSharpAnalyzerTest{TAnalyzer}.cs: extended VerifyAnalyzerAsync with an isCsWinRTComponent parameter that injects a .globalconfig setting build_property.CsWinRTComponent = true so the gated analyzers actually run under test.

Sergio0694 and others added 16 commits April 24, 2026 11:38
…m cases

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ractVersion]' usage

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-Authored-By: Copilot <223556219+Copilot@users.noreply.github.com>
Replace AttributeTargets.All with an explicit list of allowed targets and reformat AttributeUsage for clarity. Swap the Type/string constructor signatures and add XML <remarks> to each constructor to clarify when each overload applies (API-contract vs non-API-contract types). Note: the constructor signature order changed, which can be a breaking change for callers and may require code updates.
Iterate and validate each [ContractVersion] attribute instance and report diagnostics per-attribute. Simplifies and corrects the condition for version-only constructors by combining checks (isVersionOnlyConstructor && !isApiContractType) so the diagnostic is raised for each attribute applied to non-API contract types. Also updates minor comment wording.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…'ContractVersionAttribute'

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…actVersionAttribute'

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…nalyzers

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Sergio0694 Sergio0694 added enhancement New feature or request authoring Related to authoring feature work CsWinRT 3.0 labels Apr 24, 2026
@Sergio0694 Sergio0694 requested a review from manodasanW April 24, 2026 19:55
Refactor PublicTypeRequiresContractVersionAnalyzer to combine the cast and accessibility/containing-type checks into a single pattern-matching expression on context.Symbol. Removes a separate INamedTypeSymbol assignment and simplifies the early-return check without changing behavior.
@Sergio0694 Sergio0694 enabled auto-merge (squash) April 29, 2026 21:17
return;
}

context.ReportDiagnostic(Diagnostic.Create(
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

They might be doing regular versioning rather than contract versioning which we should take into account.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

and I believe we default version attribute if not specified.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Yeah this is why this diagnostic is just info, not a warning. Is that fine or should we still change it?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Given regular versioning and contract versioning have different audiences, I think we basically have a property that someone can set to true if they want to use contract versioning and if that is set, all the diagnostics for it are enabled and enforced. If it isn't set and it will default to false, then regular versioning is done and the diagnostics are not enforced. Thoughts?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Mh having an additional MSBuild property feels a bit overkill perhaps. What about:

  • Having an analyzer (info level) that fires if a public type has neither a version nor a contract version
    • I know we add a version by default, this is why the level would just be info, not a warning
  • Having an analyzer that warns if there's a public type without a contract version, only if there's at least another public type with a contract version. As in: if you do use contract versioning, you should be consistent and not mix.
  • All other analyzers are always on, since they're about general correctness things.

This way there's also no property to worry about, things just adapt automatically to your code.
Thoughts?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

That could work as long as the diagnostic message for the first one is clear enough to be like you are not using regular or contract versioning, so we will default version to 1 unless you manually specify or so.

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

Labels

authoring Related to authoring feature work CsWinRT 3.0 enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants