All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
- DI001 / DI014: Reduced false positives by recognising explicit disposal inside the same lambda/local-function execution boundary while still warning when disposal is only deferred into a different boundary.
- DI007: Reduced false positives by continuing context analysis from lambdas up to containing methods (for example
Create*/Build*factory methods), instead of stopping early. - DI008: Reduced false positives with stricter symbol-based
AddTransientdetection and factory method-group detection for member-access expressions (for exampleFactoryMethods.Create). - Tests: Added dedicated regression coverage for all fixed cases plus negative guardrail scenarios to ensure diagnostics still fire for deferred-lambda disposal patterns.
- DI016: New analyser detecting
BuildServiceProvider()misuse during service-registration composition (for example inConfigureServices,IServiceCollectionextension registration methods, and registration lambdas).
- Documentation/Samples: Added DI016 rule documentation and sample coverage, including conservative false-positive guardrail notes.
- DI015: Expanded dependency resolution from direct constructor parameters to transitive constructor chains, including open-generic dependency closures.
- DI015: Factory registrations using
GetRequiredService/GetRequiredKeyedServicenow resolve transitive dependency graphs and report missing leaf dependencies. - DI015: Added conservative cycle handling (treat cycles as resolvable) and preserved framework/factory assumptions to keep false positives low.
- Tests: Added transitive DI015 regression coverage for constructor chains, factory-rooted chains, open-generic transitive resolution, and circular dependency paths.
- DI002: Reduced false positives by reporting scope-escape diagnostics only when the resolved service lifetime is known and scoped.
- DI004: Reduced false positives by reporting use-after-dispose diagnostics only when the resolved service lifetime is known and scoped/transient.
- RegistrationCollector: Improved fallback symbol handling to track DI registrations in unresolved/ambiguous invocation cases, including
Add*(typeof(...))patterns. - Tests: Added and updated regression coverage for unknown-lifetime suppression and
typeof-based registration tracking in collector/rule/code-fix scenarios.
- Quality Gates: Added CI coverage thresholds (line + branch) and release-time tag/version validation.
- Community Files: Added issue templates, pull request template, and
CODE_OF_CONDUCT.md. - Documentation: Added
docs/RULES.mdas the deep-dive rule reference and reshapedREADME.mdinto a quickstart-focused guide.
- RegistrationCollector: Added all-registration tracking (
AllRegistrations) so analyzers can inspect duplicateAdd*registrations instead of only the last one. - Analyzer Coverage for Duplicates: Updated DI003, DI009, DI010, DI011, DI013, and DI015 to analyze all discovered
Add*registrations. - DI002: Switched to symbol-based tracking and lifetime-aware filtering to reduce false positives (known singleton/transient registrations no longer trigger scope-escape diagnostics).
- DI004: Switched to symbol-based tracking and lifetime-aware filtering (known singleton services resolved from scope are excluded from use-after-dispose diagnostics).
- DI001 / DI014: Hardened explicit-dispose detection by requiring symbol-matched dispose calls that occur after creation, reducing false negatives from name-only matching.
- Symbol Matching: Improved service-provider and registration matching logic to prefer robust symbol/namespace checks while preserving compatibility with test stubs.
- Tests: Expanded regression coverage for variable shadowing, singleton scope-usage scenarios, duplicate registration analysis, and dispose-before-create edge cases.
- DI015: Added factory method-group analysis support (for registrations such as
AddSingleton<IMyService>(CreateMyService)) and corresponding test coverage. - DI015: Added factory-path analysis for
ActivatorUtilities.CreateInstance(...)and introduced.editorconfigoptiondotnet_code_quality.DI015.assume_framework_services_registeredfor strict vs framework-assumed dependency checks. - DI015: Hardened factory analysis by supporting named factory arguments, limiting method-body traversal to true method-group registrations, and applying
.editorconfigframework-service assumptions per syntax tree.
- DI015: New analyzer detecting registered services that depend on unregistered dependencies in constructor injection and
GetRequiredServicefactory paths, including keyed and open-generic checks. - Samples: Added
samples/DI015InAction, a dedicated runnable sample showing broken and fixed DI015 registration patterns.
- DI015: Reduced false positives for multi-constructor services by only reporting when no constructor is fully resolvable, and avoided duplicate reports for factory registrations that include implementation type metadata.
- DI001 / DI014: Avoided false negatives where any enclosing
usingstatement was incorrectly treated as disposing a scope/provider created elsewhere. - DI003: Fixed non-generic service-resolution argument mapping for reduced extension methods (
GetService(typeof(...)),GetRequiredService(typeof(...))), preventing missed captive-dependency reports. - Constructor Selection: Added shared constructor-selection logic honoring
[ActivatorUtilitiesConstructor]and preventing regressions with new analyzer tests.
- DI003: Expanded non-generic and keyed resolution handling for factory delegates.
- CI/Tooling: Added
global.json, updated CI/release workflows to install .NET 8 and .NET 10, and aligned test infrastructure/packages with current Roslyn testing defaults. - Tests: Added targeted regression coverage across DI003, DI009, DI010, and DI011 for constructor-selection behavior and factory-resolution edge cases.
- DI012 (Conditional Registration Misuse): Keyed service registrations are now grouped by
(serviceType, key)so different keys no longer trigger false duplicate/TryAdd diagnostics.
- RegistrationCollector: Returns
nullwhenIServiceCollectionis unavailable, avoiding unnecessary analysis in projects without DI references. - Dependencies: Upgraded Roslyn to 5.0.0 and analyzer infrastructure packages to latest stable versions.
- Tests: Migrated from deprecated
*.Testing.XUnitpackages to core testing packages withXUnitVerifier, and bumped xUnit/Test SDK/Coverlet to current versions.
- RegistrationCollector: Improved robustness for parsing
ServiceDescriptorarguments, correctly handling named arguments and integer-castedServiceLifetimevalues. - DI014 Code Fix: Enhanced to apply
await usingin asynchronous contexts and to preserve all leading/trailing trivia (comments, indentation) correctly.
- DI014 Code Fix: Added code fix to automatically dispose root
IServiceProviderinstances.
- RegistrationCollector: Enhanced to support services registered via
new ServiceDescriptor(...)andServiceDescriptor.Describe(...). This improves detection accuracy for all analyzers relying on service registration data.
- DI013: New analyzer detecting implementation type mismatches in
typeofregistrations (e.g.AddSingleton(typeof(IService), typeof(BadImpl))). - DI014: New analyzer detecting undisposed root
IServiceProviderinstances created byBuildServiceProvider().
- DI003: Enhanced Captive Dependency analyzer to support factory delegate registrations (e.g.,
AddSingleton(sp => new Service(sp.GetRequiredService<IScoped>()))).
- RegistrationCollector: Updated to parse and store factory expressions for analysis.
- DI010: New analyzer detecting constructor over-injection (5+ dependencies suggests class may violate SRP)
- DI011: New analyzer detecting
IServiceProvider,IServiceScopeFactory, orIKeyedServiceProviderinjection- Excludes factory classes (name ends with "Factory") and middleware classes (has Invoke/InvokeAsync method)
- .NET 8 Keyed Services Support: All analyzers now support keyed service patterns
AddKeyedSingleton,AddKeyedScoped,AddKeyedTransientregistrationsGetKeyedService,GetRequiredKeyedService,GetKeyedServicesservice resolutionIKeyedServiceProviderdetection in DI006, DI007, DI011
- Enhanced
WellKnownTypeswithIKeyedServiceProvidersupport - Updated
RegistrationCollectorto track keyed service registrations - Updated
DI006_StaticProviderCacheAnalyzerto detectIKeyedServiceProviderin static fields - Updated
DI007_ServiceLocatorAntiPatternAnalyzerto detect keyed service resolution methods - Updated
DI008_DisposableTransientAnalyzerto detectAddKeyedTransientregistrations
- DI012: New analyzer detecting conditional registration misuse
- DI012:
TryAdd*called afterAdd*for the same service type (will be silently ignored) - DI012b: Multiple
Add*calls for the same service type (later registration overrides earlier)
- DI012:
- DI002 Code Fix: Added pragma suppression and TODO comment code fixes for scope escape diagnostics
- Extended
RegistrationCollectorinfrastructure to track registration order for DI012 analysis
- Updated README with DI012 documentation and corrected DI002 code fix availability
- DI004: Support for modern
using vardeclarations (previously onlyusingstatements were detected) - Additional edge case test coverage for DI001, DI004, and DI007 analyzers
- Analyzer release tracking files for Roslyn best practices
- CONTRIBUTING.md with contribution guidelines
- Known Limitations section in README
- Build warnings RS2008 and RS1037 resolved
- DI004 now properly detects services used after
using varscope ends in nested blocks
- Version bumped to 1.0.0 for stable release
- DI001: Detect undisposed
IServiceScopeinstances - DI002: Detect scoped services escaping their scope lifetime
- DI003: Detect captive dependencies (singleton capturing scoped/transient)
- DI004: Detect service usage after scope disposal
- DI005: Detect
CreateScope()usage in async methods (should useCreateAsyncScope()) - DI006: Detect
IServiceProviderorIServiceScopeFactorycached in static members - DI007: Detect service locator anti-pattern
- DI008: Detect transient services implementing
IDisposable/IAsyncDisposable - DI009: Detect open generic singletons capturing scoped/transient dependencies
- DI001: Add
usingorawait usingstatement - DI003: Change service lifetime to
ScopedorTransient - DI005: Replace
CreateScope()withCreateAsyncScope() - DI006: Remove
staticmodifier from field/property - DI008: Change lifetime to
ScopedorSingleton - DI009: Change open generic lifetime to
ScopedorTransient