Skip to content

feat(analyzers): regenerate Orleans contracts project-wide - #10869

Merged
ReubenBond merged 11 commits into
dotnet:mainfrom
ReubenBond:rb-regenerate-orleans-contracts
Aug 28, 2026
Merged

feat(analyzers): regenerate Orleans contracts project-wide#10869
ReubenBond merged 11 commits into
dotnet:mainfrom
ReubenBond:rb-regenerate-orleans-contracts

Conversation

@ReubenBond

@ReubenBond ReubenBond commented Aug 27, 2026

Copy link
Copy Markdown
Member

OrleansContracts.txt updates currently require applying individual fixes, which makes project- or solution-wide regeneration cumbersome and leaves generated diffs without enough guidance about their wire-compatibility significance.

This adds a deterministic Regenerate OrleansContracts.txt code fix with project and solution Fix All support. The fix creates missing manifests, honors configured manifest paths, rebuilds active contracts from source, excludes generated code, and preserves removed identities as retired history. Contract parsing and identity matching now follow Orleans runtime conventions, including legacy declarations and nested generic grain types.

The analyzer now reports ORLEANS0027 when a manifest RPC method is absent from source. Regeneration retains removed method signatures so a potential wire break remains visible until the developer explicitly accepts the removal.

Diagnostics and generated file headers now link to https://aka.ms/orleans/OrleansContracts.txt and tell developers and coding agents how to regenerate the file and review identity, version, and signature changes as potential wire breaks. The contract analyzer documentation includes IDE and dotnet format workflows plus actionable diff interpretation guidance.

Fixes #10870
Fixes #10871

Microsoft Reviewers: Open in CodeFlow

Copilot AI lite review requested due to automatic review settings August 27, 2026 22:46

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.

Copilot review overview

Review tier: Lite
Findings: 1 Medium severity

New issues introduced by this change (1)
Severity Finding
Medium severity test/​Orleans.Analyzers.Tests/​GrainInterfaceVersionAnalyzerTest.cs — CreateProjectWithAdditionalFilesForCodeFix can throw when configuredContractsPath is a relative…
What changed in this PR

Adds deterministic, project-/solution-wide regeneration support for OrleansContracts.txt in the Orleans analyzer/code-fix pipeline, aligning identity parsing/matching with runtime conventions and improving developer guidance around wire-compatibility.

Changes:

  • Introduces a Regenerate OrleansContracts.txt code fix with Fix All (project/solution) support, honoring configured manifest paths and excluding generated code.
  • Updates the analyzer/parsing logic to better match runtime identity conventions (including legacy declarations and nested generic types) and to preserve/retire historical entries.
  • Refreshes diagnostics messaging, documentation, and generated manifest headers to include regeneration workflow and compatibility-review guidance.
File Description
test/​Orleans.Analyzers.Tests/​GrainInterfaceVersionAnalyzerTest.cs Expands code-fix and Fix All test coverage for regeneration, configured paths, legacy identity behavior, and generated-code exclusion.
src/​Orleans.Analyzers/​GrainInterfaceVersionCodeFix.cs Implements regeneration code action + Fix All provider; adds manifest discovery/configured path support and improves retirement matching.
src/​Orleans.Analyzers/​GrainInterfaceVersionAnalyzer.cs Aligns identity matching with runtime conventions; improves missing-manifest diagnostic location and legacy declaration handling.
src/​Orleans.Analyzers/​Resources.resx Updates diagnostic messages with regeneration instructions and a compatibility-review link.
src/​Orleans.Analyzers/​build/​Microsoft.Orleans.Analyzers.props Exposes OrleansContractsPath as a compiler-visible property for analyzer/config access.
src/​Directory.Build.targets Exposes OrleansContractsPath for compiler/analyzer visibility at the repo level.
src/​Orleans.Core.Abstractions/​OrleansContracts.txt Updates generated header guidance text.
src/​Orleans.Core/​OrleansContracts.txt Updates generated header guidance text.
src/​Orleans.Runtime/​OrleansContracts.txt Updates generated header guidance text.
src/​Orleans.Streaming/​OrleansContracts.txt Updates generated header guidance text.
src/​Orleans.Reminders/​OrleansContracts.txt Updates generated header guidance text.
src/​Orleans.Persistence.Memory/​OrleansContracts.txt Updates generated header guidance text.
src/​Orleans.EventSourcing/​OrleansContracts.txt Updates generated header guidance text.
src/​Orleans.DurableJobs/​OrleansContracts.txt Updates generated header guidance text.
src/​Orleans.Transactions/​OrleansContracts.txt Updates generated header guidance text.
src/​Orleans.Transactions.TestKit.Base/​OrleansContracts.txt Updates generated header guidance text.
src/​Orleans.TestingHost/​OrleansContracts.txt Updates generated header guidance text.
src/​Orleans.BroadcastChannel/​OrleansContracts.txt Updates generated header guidance text.
src/​Dashboard/​Orleans.Dashboard/​OrleansContracts.txt Updates generated header guidance text.
docs/​site/​src/​content/​docs/​grains/​grain-versioning/​contract-compatibility-analyzer.md Documents regeneration workflow (IDE + dotnet format), and adds diff interpretation guidance focused on compatibility impact.
docs/​site/​src/​content/​docs/​diagnostics/​orleans0025.md Updates diagnostic guidance to reflect “effective identity” semantics and regeneration workflow.
docs/​site/​src/​content/​docs/​diagnostics/​orleans0024.md Adds regeneration workflow guidance and updated references.
docs/​site/​src/​content/​docs/​diagnostics/​orleans0023.md Adds regeneration workflow guidance and updated references.
docs/​site/​src/​content/​docs/​diagnostics/​orleans0022.md Adds regeneration workflow guidance and updated references.
docs/​site/​src/​content/​docs/​diagnostics/​orleans0021.md Updates diagnostic guidance to reflect “effective identity” semantics.
docs/​site/​src/​content/​docs/​diagnostics/​orleans0020.md Marks the code fix as available and updates remediation guidance to regeneration/Fix All.
docs/​site/​src/​content/​docs/​diagnostics/​orleans0019.md Adds regeneration workflow guidance and updated references.
docs/​site/​src/​content/​docs/​diagnostics/​orleans0018.md Adds regeneration workflow guidance and updated references.
docs/​site/​src/​content/​docs/​diagnostics/​orleans0017.md Adds regeneration workflow guidance and updated references.
docs/​site/​src/​content/​docs/​diagnostics/​orleans0016.md Adds regeneration workflow guidance and updated references.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread test/Orleans.Analyzers.Tests/GrainInterfaceVersionAnalyzerTest.cs
Copilot AI review requested due to automatic review settings August 27, 2026 23:59

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.

Copilot review overview

Review tier: Lite
Findings: 2 Medium severity

New issues introduced by this change (1)
Severity Finding
Medium severity src/​Orleans.Analyzers/​GrainInterfaceVersionAnalyzer.cs_grainInterfacesFile.GetText(...) is called inside AnalyzeNamedType for every RPC interface…
Pre-existing issues (1)
Severity Finding
Medium severity test/​Orleans.Analyzers.Tests/​GrainInterfaceVersionAnalyzerTest.cs — CreateProjectWithAdditionalFilesForCodeFix can throw when configuredContractsPath is a relative… View comment
Files not reviewed (1)
  • src/Orleans.Analyzers/Resources.Designer.cs: Generated file

Comment thread src/Orleans.Analyzers/GrainInterfaceVersionAnalyzer.cs Outdated
Copilot AI review requested due to automatic review settings August 28, 2026 00:59
@ReubenBond
ReubenBond force-pushed the rb-regenerate-orleans-contracts branch from 28cfd74 to 6d8ed50 Compare August 28, 2026 00:59

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.

Copilot review overview

Review tier: Lite
Findings: 2 Medium severity

Pre-existing issues (2)
Severity Finding
Medium severity src/​Orleans.Analyzers/​GrainInterfaceVersionAnalyzer.cs_grainInterfacesFile.GetText(...) is called inside AnalyzeNamedType for every RPC interface… View comment
Medium severity test/​Orleans.Analyzers.Tests/​GrainInterfaceVersionAnalyzerTest.cs — CreateProjectWithAdditionalFilesForCodeFix can throw when configuredContractsPath is a relative… View comment
Files not reviewed (1)
  • src/Orleans.Analyzers/Resources.Designer.cs: Generated file
Suppressed comments (1)

test/Orleans.Analyzers.Tests/GrainInterfaceVersionAnalyzerTest.cs:1286

  • Path.GetDirectoryName(configuredContractsPath)! can be null when configuredContractsPath is just a filename (no directory component), which would throw in these tests. Avoid the null-forgiving operator here and fall back to a safe path for the analyzer config document.

Copilot AI review requested due to automatic review settings August 28, 2026 03:45

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.

Copilot review overview

Review tier: Lite
Findings: None

Issues resolved since last review (2)
Severity Finding
Medium severity src/​Orleans.Analyzers/​GrainInterfaceVersionAnalyzer.cs_grainInterfacesFile.GetText(...) is called inside AnalyzeNamedType for every RPC interface… View resolved comment
Medium severity test/​Orleans.Analyzers.Tests/​GrainInterfaceVersionAnalyzerTest.cs — CreateProjectWithAdditionalFilesForCodeFix can throw when configuredContractsPath is a relative… View resolved comment
Files not reviewed (1)
  • src/Orleans.Analyzers/Resources.Designer.cs: Generated file
Suppressed comments (1)

Previously missed (1) — in code that hasn't changed since the last review.

docs/site/src/content/docs/grains/grain-versioning/contract-compatibility-analyzer.md:45

  • The docs say to apply Regenerate OrleansContracts.txt “from any Orleans contract diagnostic”, but ORLEANS0027 explicitly has no code fix and the code-fix provider doesn’t include ORLEANS0027 in FixableDiagnosticIds (so the regenerate action won’t be offered when ORLEANS0027 is the only diagnostic). Please narrow this wording to diagnostics which offer code fixes, or clarify the exception for ORLEANS0027.
Apply **Regenerate OrleansContracts.txt** from any Orleans contract diagnostic. One application regenerates the entire project manifest. In an IDE, use **Fix all in project** or **Fix all in solution** to regenerate every affected project.

@github-actions

Copy link
Copy Markdown
Contributor

Code coverage

78.21% line coverage - 99,551 / 127,293 lines

Coverage details

Copilot AI review requested due to automatic review settings August 28, 2026 05: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.

Copilot review overview

Review tier: Lite
Findings: 1 Medium severity

New issues introduced by this change (1)
Severity Finding
Medium severity docs/​site/​src/​content/​docs/​grains/​grain-versioning/​contract-compatibility-analyzer.md — The docs say the Regenerate OrleansContracts.txt code fix can be applied "from any Orleans…
Files not reviewed (1)
  • src/Orleans.Analyzers/Resources.Designer.cs: Generated file

Copilot AI review requested due to automatic review settings August 28, 2026 06:52

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.

Copilot review overview

Review tier: Lite
Findings: None

Issues resolved since last review (1)
Severity Finding
Medium severity docs/​site/​src/​content/​docs/​grains/​grain-versioning/​contract-compatibility-analyzer.md — The docs say the Regenerate OrleansContracts.txt code fix can be applied "from any Orleans… View resolved comment
Files not reviewed (1)
  • src/Orleans.Analyzers/Resources.Designer.cs: Generated file
Suppressed comments (1)

Previously missed (1) — in code that hasn't changed since the last review.

src/Orleans.Analyzers/GrainInterfaceVersionAnalyzer.cs:543

  • ORLEANS0023 (grain class identity mismatch) currently returns early when the manifest declaration omits an explicit [GrainType(...)] (i.e., declaredClass.Alias is null). That makes a legacy entry like class MyGrain appear to match a source class with [GrainType("my-grain")], even though the effective identities differ (derived-from-CLR vs explicit). This can hide a real runtime identity mismatch.

Compare the source identity against the manifest’s effective identity (Alias when present, otherwise the derived default) and report ORLEANS0023 when they differ. Also use the effective manifest identity in the diagnostic message instead of "".

            _visitedClasses.TryAdd(GetDeclarationKey(declaredClass), true);
            if (declaredClass.Alias is null
                || string.Equals(codeAlias, declaredClass.Alias, StringComparison.Ordinal))
            {
                return;

Copilot AI review requested due to automatic review settings August 28, 2026 08:07
@ReubenBond
ReubenBond force-pushed the rb-regenerate-orleans-contracts branch from ac1dd4e to 57fe208 Compare August 28, 2026 08:07

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.

Copilot review overview

Review tier: Lite
Findings: 1 Low severity

New issues introduced by this change (1)
Severity Finding
Low severity docs/​site/​src/​content/​docs/​diagnostics/​orleans0027.md — The .editorconfig suppression snippet uses [*.cs], but ORLEANS0027 is reported on the manifest…
Files not reviewed (1)
  • src/Orleans.Analyzers/Resources.Designer.cs: Generated file

Comment thread docs/site/src/content/docs/diagnostics/orleans0027.md Outdated
Copilot AI review requested due to automatic review settings August 28, 2026 09:28

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.

Copilot review overview

Review tier: Lite
Findings: 1 Medium severity

New issues introduced by this change (1)
Severity Finding
Medium severity src/​Orleans.Analyzers/​GrainInterfaceVersionCodeFix.cs — FindContractsDocument only recognizes the manifest via (a) a file named OrleansContracts.txt or (b)…
Issues resolved since last review (1)
Severity Finding
Low severity docs/​site/​src/​content/​docs/​diagnostics/​orleans0027.md — The .editorconfig suppression snippet uses [*.cs], but ORLEANS0027 is reported on the manifest… View resolved comment
Files not reviewed (1)
  • src/Orleans.Analyzers/Resources.Designer.cs: Generated file

Comment thread src/Orleans.Analyzers/GrainInterfaceVersionCodeFix.cs
Copilot AI review requested due to automatic review settings August 28, 2026 10: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.

Copilot review overview

Review tier: Lite
Findings: None

Issues resolved since last review (1)
Severity Finding
Medium severity src/​Orleans.Analyzers/​GrainInterfaceVersionCodeFix.cs — FindContractsDocument only recognizes the manifest via (a) a file named OrleansContracts.txt or (b)… View resolved comment
Files not reviewed (1)
  • src/Orleans.Analyzers/Resources.Designer.cs: Generated file
Suppressed comments (1)

Previously missed (1) — in code that hasn't changed since the last review.

src/Orleans.Analyzers/GrainInterfaceVersionAnalyzer.cs:806

  • GetDefaultGrainInterfaceType(string) returns the input unchanged when there are no generic type parameters. For nested types represented in the manifest using C# syntax (eg Outer.IInnerGrain), this produces an identity with . separators instead of the runtime’s + nested-type separator (and this differs from GetDefaultGrainInterfaceType(INamedTypeSymbol), which always uses + for nested types). This can cause identity-based matching/duplicate detection (eg in GrainInterfaceFileParser.Parse) to treat semantically identical declarations as different identities, potentially missing ORLEANS0021/ORLEANS0025 duplicates when one entry uses explicit GrainInterfaceType/GrainType and another uses a legacy declaration.
    internal static string GetDefaultGrainInterfaceType(string typeName)
    {
        var segments = typeName.Split('.');
        var firstGenericSegment = Array.FindIndex(segments, segment => segment.IndexOf('<') >= 0);
        if (firstGenericSegment < 0)
        {
            return typeName;
        }

        for (var index = firstGenericSegment; index < segments.Length; index++)
        {
            var genericStart = segments[index].IndexOf('<');
            if (genericStart < 0)
            {
                continue;
            }

            var genericEnd = segments[index].LastIndexOf('>');
            var arity = 1;
            for (var characterIndex = genericStart + 1; characterIndex < genericEnd; characterIndex++)
            {
                if (segments[index][characterIndex] == ',')
                {
                    arity++;
                }
            }

            segments[index] = $"{segments[index].Substring(0, genericStart)}`{arity}";
        }

        return string.Join(".", segments.Take(firstGenericSegment))
            + (firstGenericSegment > 0 ? "." : string.Empty)
            + string.Join("+", segments.Skip(firstGenericSegment));
    }

Copilot AI review requested due to automatic review settings August 28, 2026 15:27

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.

Copilot review overview

Review tier: Lite
Findings: 1 Low severity

New issues introduced by this change (1)
Severity Finding
Low severity docs/​site/​src/​content/​docs/​grains/​grain-versioning/​contract-compatibility-analyzer.md — In the manifest-format example code block, the method line is missing the two-space indentation…
Files not reviewed (1)
  • src/Orleans.Analyzers/Resources.Designer.cs: Generated file

Copilot AI review requested due to automatic review settings August 28, 2026 15:46

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.

Copilot review overview

Review tier: Lite
Findings: 1 Low severity

Pre-existing issues (1)
Severity Finding
Low severity docs/​site/​src/​content/​docs/​grains/​grain-versioning/​contract-compatibility-analyzer.md — In the manifest-format example code block, the method line is missing the two-space indentation… View comment
Files not reviewed (1)
  • src/Orleans.Analyzers/Resources.Designer.cs: Generated file
Suppressed comments (1)

Previously missed (1) — in code that hasn't changed since the last review.

src/Orleans.Analyzers/GrainInterfaceVersionCodeFix.cs:371

  • HasGeneratedCodeAttribute compares attribute types using constructor?.ContainingType.ToDisplayString() without a SymbolDisplayFormat, but then matches against fully-qualified type names. Depending on Roslyn's default display format, this can fail to recognize [GeneratedCode]/[CompilerGenerated] attributes and accidentally include generated types during regeneration. Use FullyQualifiedFormat (and strip the global:: prefix) for the comparison, consistent with other type-name handling in this file (e.g., GetFullyQualifiedName).
        return declaration.AncestorsAndSelf()
            .OfType<TypeDeclarationSyntax>()
            .SelectMany(type => type.AttributeLists)
            .SelectMany(list => list.Attributes)
            .Select(attribute => semanticModel.GetSymbolInfo(attribute).Symbol as IMethodSymbol)
            .Select(constructor => constructor?.ContainingType.ToDisplayString())
            .Any(attributeType => attributeType is
                "System.CodeDom.Compiler.GeneratedCodeAttribute"
                or "System.Runtime.CompilerServices.CompilerGeneratedAttribute");

Copilot AI review requested due to automatic review settings August 28, 2026 16:09

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.

Copilot review overview

Review tier: Lite
Findings: None

Issues resolved since last review (1)
Severity Finding
Low severity docs/​site/​src/​content/​docs/​grains/​grain-versioning/​contract-compatibility-analyzer.md — In the manifest-format example code block, the method line is missing the two-space indentation… View resolved comment
Files not reviewed (1)
  • src/Orleans.Analyzers/Resources.Designer.cs: Generated file
Suppressed comments (1)

Previously missed (1) — in code that hasn't changed since the last review.

src/Orleans.CodeGenerator.Shared/MethodIdProvider.cs:20

  • MethodIdProvider.Create converts the 4-byte xxHash result to hex via a StringBuilder plus per-byte ToString("X2"), which allocates a new string for each byte. Since the codebase already has Orleans.CodeGenerator.Hashing.HexConverter (used elsewhere for xxHash output), using it here would be allocation-free and consistent.
        var result = new StringBuilder(hash.Length * 2);
        foreach (var value in hash)
        {
            result.Append(value.ToString("X2"));
        }

@ReubenBond
ReubenBond merged commit 29acb79 into dotnet:main Aug 28, 2026
72 checks passed
@ReubenBond
ReubenBond deleted the rb-regenerate-orleans-contracts branch August 28, 2026 16:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ORLEANS0020 should offer a code fix to create OrleansContracts.txt Contract analyzer does not detect removed grain interface methods

2 participants