Skip to content

Add XPC2002: duplicate plugin step registration (error)#21

Merged
mkholt merged 5 commits into
mainfrom
xpc2002-duplicate-registration
Jul 3, 2026
Merged

Add XPC2002: duplicate plugin step registration (error)#21
mkholt merged 5 commits into
mainfrom
xpc2002-duplicate-registration

Conversation

@mkholt

@mkholt mkholt commented Jul 3, 2026

Copy link
Copy Markdown
Member

Reports at compile time when a plugin registers the same entity/operation/stage combination more than once via RegisterStep or RegisterPluginStep. The platform rejects such duplicates at registration time, and they would make the source-generated image/wrapper type names (derived from that tuple) ambiguous — this establishes the uniqueness invariant the upcoming flat image-naming scheme relies on.

Also renames the pending CHANGELOG entry to v1.5.0 (folding in the unreleased XPC3007 work), since the image-generation rework ships as part of this minor.

Reports at compile time when a plugin registers the same entity/operation/stage
combination more than once via RegisterStep or RegisterPluginStep. The platform
rejects such duplicates at registration time, and they would make the
source-generated image/wrapper type names (derived from that tuple) ambiguous —
this establishes the uniqueness invariant the upcoming flat image-naming scheme
relies on.

Also renames the pending CHANGELOG entry to v1.5.0 (folding in the unreleased
XPC3007 work), since the image-generation rework ships as part of this minor.

Co-Authored-By: Claude <noreply@anthropic.com> via Conducktor <conducktor@contextand.com>

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.

Pull request overview

This PR introduces a new Roslyn diagnostic (XPC2002) to enforce the invariant that a plugin must not register the same entity/operation/stage step tuple more than once, since duplicates are rejected by the Dataverse platform and would make generated wrapper/image type names ambiguous.

Changes:

  • Add analyzer XPC2002 (error) to detect duplicate step registrations (including legacy RegisterPluginStep).
  • Add rule documentation and announce the new rule in analyzer release notes + project changelog.
  • Add unit tests covering core duplicate/non-duplicate scenarios.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
XrmPluginCore/CHANGELOG.md Bumps unreleased heading to v1.5.0 and documents XPC2002.
XrmPluginCore.SourceGenerator/rules/XPC2002.md Adds rule documentation for XPC2002 with examples and guidance.
XrmPluginCore.SourceGenerator/Helpers/RegisterStepHelper.cs Adds helper to recognize both RegisterStep and RegisterPluginStep invocations.
XrmPluginCore.SourceGenerator/DiagnosticDescriptors.cs Defines the XPC2002 DiagnosticDescriptor.
XrmPluginCore.SourceGenerator/Constants.cs Adds RegisterPluginStepMethodName constant.
XrmPluginCore.SourceGenerator/Analyzers/DuplicateStepRegistrationAnalyzer.cs Implements the XPC2002 analyzer logic.
XrmPluginCore.SourceGenerator/AnalyzerReleases.Unshipped.md Records the new rule in analyzer release notes.
XrmPluginCore.SourceGenerator.Tests/DiagnosticTests/DuplicateStepRegistrationAnalyzerTests.cs Adds tests for XPC2002 analyzer behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread XrmPluginCore.SourceGenerator/Analyzers/DuplicateStepRegistrationAnalyzer.cs Outdated
Comment thread XrmPluginCore.SourceGenerator/Constants.cs
Comment thread XrmPluginCore.SourceGenerator/Analyzers/DuplicateStepRegistrationAnalyzer.cs Outdated
Comment thread XrmPluginCore.SourceGenerator/Analyzers/DuplicateStepRegistrationAnalyzer.cs Outdated
- Only analyze types that derive from XrmPluginCore.Plugin, so unrelated classes
  with a generic RegisterStep/RegisterPluginStep method aren't flagged.
- Aggregate registrations per plugin type across all syntax trees and evaluate at
  compilation end, so duplicates split across partial declarations are detected;
  also seed with inherited base-plugin registrations so a derived class that
  re-registers an inherited tuple is caught. (Uses the compilation-start pattern
  to stay within RS1030; descriptor tagged CompilationEnd.)
- Resolve const/literal custom-message names via GetConstantValue instead of
  treating them as unresolved, fixing a false negative.
- Reuse Constants.RegisterPluginStepMethodName in LocalPluginContextAsService
  code fix instead of a duplicate hard-coded string.
- Add tests for legacy RegisterPluginStep, const message names, partial-split
  registrations, derived re-registration, and the non-plugin exclusion.

Co-Authored-By: Claude <noreply@anthropic.com> via Conducktor <conducktor@contextand.com>

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.

Pull request overview

Copilot reviewed 9 out of 9 changed files in this pull request and generated 2 comments.

Comment thread XrmPluginCore.SourceGenerator/Analyzers/DuplicateStepRegistrationAnalyzer.cs Outdated
ResolveTupleValue now maps a const enum reference (e.g.
const EventOperation Op = EventOperation.Update) from its underlying constant
value back to the enum member name, so such registrations are keyed correctly
instead of being skipped. Adds tests for duplicate and distinct const enum
operation arguments.

Co-Authored-By: Claude <noreply@anthropic.com> via Conducktor <conducktor@contextand.com>

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.

Pull request overview

Copilot reviewed 9 out of 9 changed files in this pull request and generated 1 comment.

Comment thread XrmPluginCore.SourceGenerator/Analyzers/DuplicateStepRegistrationAnalyzer.cs Outdated
ResolveTupleValue no longer short-circuits on member access. Constant evaluation
now drives resolution uniformly, so a const string message member (Msgs.DoThing)
resolves to its string value rather than the member identifier — two distinct
members sharing a value are correctly treated as duplicates. Enum constants are
still mapped back to the member name. Adds tests for shared and distinct const
string message members.

Co-Authored-By: Claude <noreply@anthropic.com> via Conducktor <conducktor@contextand.com>

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.

Pull request overview

Copilot reviewed 9 out of 9 changed files in this pull request and generated 2 comments.

ResolveTupleValue now falls back to the underlying integral's string form for
enum constants with no matching member (e.g. (EventOperation)999), matching
Enum.ToString(), so duplicates using undefined enum values are still detected
instead of skipped. Adds duplicate and distinct undefined-enum-cast tests.

Co-Authored-By: Claude <noreply@anthropic.com> via Conducktor <conducktor@contextand.com>
@mkholt mkholt merged commit 2a800c3 into main Jul 3, 2026
1 check passed
@mkholt mkholt deleted the xpc2002-duplicate-registration branch July 3, 2026 08:16
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.

2 participants