feat(analyzers): detect RPC contract changes - #10337
Draft
ReubenBond wants to merge 2 commits into
Draft
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
This PR introduces a new Orleans analyzer + code fix workflow to detect RPC contract drift by comparing grain interfaces in source against a GrainInterfaces.txt manifest, helping prevent accidental incompatibilities during rolling upgrades.
Changes:
- Added
GrainInterfaceVersionAnalyzer(ORLEANS0016–ORLEANS0021) to validate interface declarations, versions, members, file presence, retirements, and duplicates. - Added
GrainInterfaceVersionCodeFixto update/createGrainInterfaces.txtentries based on diagnostics. - Added extensive analyzer/code-fix unit tests and registered new diagnostics in analyzer release notes and resources.
Show a summary per file
| File | Description |
|---|---|
| test/Orleans.Analyzers.Tests/GrainInterfaceVersionAnalyzerTest.cs | Adds coverage for new diagnostics and code fixes across aliases, versions, generics, and inheritance. |
| src/Orleans.Analyzers/Resources.resx | Adds localized strings for new diagnostics and code fix titles. |
| src/Orleans.Analyzers/Resources.Designer.cs | Updates strongly-typed resource accessors for the new strings. |
| src/Orleans.Analyzers/GrainInterfaceVersionCodeFix.cs | Implements code fixes which update/create GrainInterfaces.txt based on diagnostics. |
| src/Orleans.Analyzers/GrainInterfaceVersionAnalyzer.cs | Implements analyzer + manifest parser for interface/member/version tracking. |
| src/Orleans.Analyzers/Constants.cs | Adds constants for VersionAttribute FQN and GrainInterfaces.txt filename. |
| src/Orleans.Analyzers/AnalyzerReleases.Unshipped.md | Documents the newly introduced diagnostic IDs and severities. |
Copilot's findings
Files not reviewed (1)
- src/Orleans.Analyzers/Resources.Designer.cs: Generated file
Suppressed comments (2)
src/Orleans.Analyzers/GrainInterfaceVersionCodeFix.cs:366
- AddMemberToFileAsync suppresses insertion when the next interface declaration line
StartsWith(interfaceName). This fails when the next interface name happens to share the same prefix (for example,IMyGrainfollowed byIMyGrainExtended), causing the new member to be inserted in the wrong section.
// If next line is empty, a comment, or another interface, insert the member here
if (string.IsNullOrEmpty(nextLine) ||
nextLine.StartsWith("#", StringComparison.Ordinal) ||
(nextLine.Contains("[Version(") && !nextLine.StartsWith(interfaceName, StringComparison.Ordinal)))
{
src/Orleans.Analyzers/GrainInterfaceVersionCodeFix.cs:422
- RetireInterfaceInFileAsync uses
trimmedLine.Contains(interfaceName), which can retire the wrong interface when one interface name is a substring/prefix of another. It should ensure it matched the full interface-name token before adding the RETIRED prefix.
// Check if this line contains the interface declaration
if (trimmedLine.Contains(interfaceName) && trimmedLine.Contains("[Version(") &&
!trimmedLine.StartsWith(GrainInterfaceVersionAnalyzer.RetiredPrefix, StringComparison.Ordinal))
{
- Files reviewed: 6/7 changed files
- Comments generated: 4
Recover the grain interface version analyzer and its code fixes. Track grain interface signatures in GrainInterfaces.txt so incompatible changes are identified during development. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 72583b82-973f-4897-939d-e29e6cedd2a0
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 20a2d18d-fb94-43cc-8f92-67274910d221
ReubenBond
force-pushed
the
recover-rpc-contract-analyzer
branch
from
August 5, 2026 23:49
df743cf to
2c62824
Compare
Contributor
There was a problem hiding this comment.
Copilot's findings
Files not reviewed (1)
- src/Orleans.Analyzers/Resources.Designer.cs: Generated file
Suppressed comments (1)
src/Orleans.Analyzers/GrainInterfaceVersionCodeFix.cs:263
- AddGrainClassToFileAsync only reactivates an existing contracts entry when the declared CLR name matches
className. If a grain class is renamed but keeps a stable[GrainType("...")]alias, the analyzer can still match by alias, but the code fix will append a new entry instead of updating the existing (possibly RETIRED) one. That can introduce duplicate alias declarations, which are treated as errors by the parser (see GrainInterfaceFileParser.Parse duplicate check in GrainInterfaceVersionAnalyzer.cs:1003-1005). Consider matching existing entries by alias (and updating/unretiring that line) before appending a new declaration.
for (var i = 0; i < lines.Length; i++)
{
if (GrainInterfaceFileParser.TryGetGrainClassName(lines[i], out var declaredName)
&& string.Equals(declaredName, className, StringComparison.Ordinal))
{
- Files reviewed: 23/24 changed files
- Comments generated: 0 new
Contributor
There was a problem hiding this comment.
Copilot's findings
Files not reviewed (1)
- src/Orleans.Analyzers/Resources.Designer.cs: Generated file
Suppressed comments (1)
src/Orleans.Runtime/OrleansContracts.txt:31
- The contract manifest entry for
IGrainDirectoryPartition.GetSnapshotAsyncdrops the nullable annotation from the return type. The source interface returnsValueTask<GrainDirectoryPartitionSnapshot?>, so this signature should include?to match the analyzer's contract type rendering (it preserves nullable reference modifiers, e.g.,GrainAddress?).
GetSnapshotAsync(Orleans.Runtime.MembershipVersion, Orleans.Runtime.MembershipVersion, RingRange, System.Threading.CancellationToken) -> ValueTask<GrainDirectoryPartitionSnapshot>
- Files reviewed: 23/24 changed files
- Comments generated: 0 new
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Orleans RPC contracts can change without an explicit record of the prior interface shape, making accidental incompatibilities difficult to catch before rolling upgrades.
This adds a grain interface version analyzer and code fixes which compare source interfaces with a
GrainInterfaces.txtcontract manifest. It reports undeclared interfaces and members, version mismatches, unretired removals, missing manifests, and duplicate declarations, with focused analyzer coverage for versioning, aliases, generics, inheritance, and code fixes.Microsoft Reviewers: Open in CodeFlow