Skip to content

Add MA0226: EventSource class should be sealed - #1446

Merged
meziantou merged 2 commits into
mainfrom
feature/eventsource-sealed-validation-8c7d7b
Sep 10, 2026
Merged

meziantou merged 2 commits into
mainfrom
feature/eventsource-sealed-validation-8c7d7b

Conversation

@meziantou

Copy link
Copy Markdown
Owner

What

New rule MA0226 - EventSource class should be sealed, reported on a class that inherits from EventSource and is neither sealed nor abstract. Disabled by default (Warning severity when enabled), with a code fix adding the sealed modifier.

Why

Sealing a derived event source is not only a documented convention — the runtime validates it:

  • EventSource.CreateManifestAndDescriptors reports Event source types must be sealed or abstract. when the type is neither sealed nor abstract (only under EventManifestOptions.Strict, i.e. GenerateManifest validation, so an unsealed source does not throw at construction on its own).
  • GetEventSourceBaseType walks up the base chain skipping only abstract types and requires the first non-abstract ancestor to be exactly EventSource, so a class deriving from a concrete event source is not a valid event source.
  • Descriptors are built from eventSourceType.GetMethods(BindingFlags.DeclaredOnly | ...), so events declared on a concrete base class are never registered for the derived provider (which also gets its own provider name/GUID).

The abstract "Utility EventSource" pattern is explicitly supported by the framework, so abstract classes are not reported.

Notes for reviewers

  • The rule also recognizes Microsoft.Diagnostics.Tracing.EventSource (the EventSource NuGet redist type), matching the runtime's own namespace-tolerant handling of Diagnostics.Tracing attributes.
  • This is not covered by MA0053: MA0053 only fires when there is no inheritor in the compilation, skips public types by default, and is Info. An unsealed concrete EventSource is wrong regardless of visibility or whether anything derives from it today.
  • No entry added to docs/comparison-with-other-analyzers.md: no equivalent or similar rule found in the CA/IDE/Sonar rule sets.

Verification

  • dotnet build (all Roslyn versions): succeeded, 0 warnings.
  • dotnet test tests/Meziantou.Analyzer.Test/Meziantou.Analyzer.Test.roslyn5.9.csproj: 4240/4240 passed.
  • dotnet test tests/Meziantou.Analyzer.Test/Meziantou.Analyzer.Test.roslyn4.8.csproj --filter "FullyQualifiedName~EventSourceMustBeSealedAnalyzerTests": 7/7 passed.
  • dotnet run --project src/DocumentationGenerator re-run after the doc edits: exit code 0, no further markdown changes.

A class deriving from EventSource must be sealed or abstract. The runtime
validates it: EventSource.GenerateManifest reports "Event source types must
be sealed or abstract." under EventManifestOptions.Strict. Deriving from a
concrete event source also breaks the derived type, as EventSource only walks
through abstract base types when looking for its EventSource base class, and
builds the event metadata from the methods declared on the type itself.

The abstract "Utility EventSource" pattern is supported, so abstract classes
are not reported. The rule also recognizes the Microsoft.Diagnostics.Tracing
base type of the EventSource NuGet package.

The rule is disabled by default.
…base type

Array.TrueForAll and Array.Exists invoke a delegate, and the lambda captured
the analyzed symbol, so a closure was allocated for every named type. The two
symbols are now properties of the analyzer context, checked directly.
@meziantou
meziantou enabled auto-merge (squash) September 10, 2026 00:58
@meziantou
meziantou disabled auto-merge September 10, 2026 00:58
@meziantou
meziantou enabled auto-merge (squash) September 10, 2026 00:58
@meziantou
meziantou merged commit 4a9aed4 into main Sep 10, 2026
13 checks passed
@meziantou
meziantou deleted the feature/eventsource-sealed-validation-8c7d7b branch September 10, 2026 01:02
This was referenced Sep 10, 2026
This was referenced Sep 17, 2026
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.

1 participant