diff --git a/CLAUDE.md b/CLAUDE.md index 3ccddff..22d5aa0 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -440,6 +440,16 @@ The project implements two separate analyzers for enforcing global usings, follo - Best for: Library projects, projects with many third-party dependencies - Implementation: `GlobalUsingsCommonAnalyzer.cs` + `GlobalUsingsCommonCodeFixProvider.cs` +**Automatic Mutual Exclusivity:** + +By default, ATC220 excludes namespaces that ATC221 handles (configured via `dotnet_diagnostic.ATC220.exclude_common_namespaces`, default `true`). This means both rules can be enabled simultaneously without producing duplicate warnings: +- ATC220 flags **non-common** namespaces (third-party, custom) +- ATC221 flags **common** namespaces (System, Microsoft, Atc) + +ATC220 reads ATC221's `namespace_prefixes` setting to determine which namespaces to skip, so custom prefix configurations stay in sync. + +To make ATC220 flag ALL namespaces (original behavior), set `exclude_common_namespaces = false` in `.editorconfig`. + **Why Two Separate Analyzers?** While these analyzers could theoretically be merged into one with different rule IDs, they are kept separate to: @@ -493,6 +503,19 @@ dotnet_diagnostic.ATC210.max_line_length = 100 The configuration uses the standard Roslyn `.editorconfig` option naming convention: `dotnet_diagnostic.{RULE_ID}.option_name` +#### Exclude Common Namespaces (ATC220) + +ATC220 supports excluding common namespaces to avoid overlap with ATC221: + +```editorconfig +[*.cs] +# Exclude common namespaces handled by ATC221 (default: true) +dotnet_diagnostic.ATC220.exclude_common_namespaces = false +``` + +- **Default value**: true (common namespaces are excluded) +- When true, ATC220 reads ATC221's `namespace_prefixes` to determine which namespaces to skip + #### Reading Configuration in Analyzers To read custom `.editorconfig` options in an analyzer, use the `AnalyzerConfigOptionsExtensions` helper: diff --git a/docs/rules/ATC220.md b/docs/rules/ATC220.md index 6fa276e..fc8500f 100644 --- a/docs/rules/ATC220.md +++ b/docs/rules/ATC220.md @@ -34,52 +34,44 @@ Centralizing all namespace imports in GlobalUsings.cs provides several benefits: This is the most aggressive global usings policy, suitable for projects where you want absolutely minimal boilerplate. -## 🔀 ATC220 vs ATC221: Which Rule to Use? +## 🔀 ATC220 and ATC221: Working Together -Both ATC220 and ATC221 enforce global usings, but they differ in scope and strictness: +Both ATC220 and ATC221 enforce global usings, but they differ in scope: | Aspect | ATC220 (Strict) | ATC221 (Lenient) | |--------|----------------|------------------| -| **Policy** | All namespaces | Only System/Microsoft/Atc | -| **Flags** | Every using directive | Only common framework usings | +| **Policy** | Non-common namespaces (by default) | Only System/Microsoft/Atc | +| **Flags** | Third-party and custom using directives | Only common framework usings | | **Third-party libs** | Must be in GlobalUsings.cs | Can stay in individual files | -| **Use when** | You want zero using statements in code files | You want flexibility for third-party dependencies | -| **Best for** | Highly controlled codebases, internal projects | Projects with many third-party libraries | +| **Best for** | Catching all remaining non-common usings | Centralizing common framework usings | -### When to Use ATC220 (This Rule) +### Automatic Mutual Exclusivity -Choose ATC220 if you want: +By default, both rules can be enabled simultaneously **without producing duplicate warnings**. ATC220 automatically excludes namespaces that ATC221 handles (System, Microsoft, Atc), so each using directive triggers at most one warning. -- **Maximum consistency**: Every file looks identical (no using statements at all) -- **Zero exceptions**: All usings centralized, no local decisions needed -- **Internal projects**: Where you control all dependencies -- **Minimal boilerplate**: Absolutely cleanest possible code files +| Scenario | ATC220 fires on | ATC221 fires on | +|----------|----------------|----------------| +| Both enabled (default) | Third-party/custom namespaces | System/Microsoft/Atc | +| Only ATC220 (`exclude_common_namespaces = false`) | Everything | n/a | +| Only ATC221 | n/a | System/Microsoft/Atc | -### When to Use ATC221 Instead - -Choose ATC221 if you want: - -- **Flexibility**: Allow third-party usings to remain in individual files -- **Context clarity**: See third-party dependencies where they're used -- **Migration friendliness**: Easier to adopt incrementally -- **Library projects**: Where different files may use different third-party packages - -### Configuration Example - -You can enable only one rule at a time in your `.editorconfig`: +### Configuration Examples ```ini -# Use strict policy (all usings must be global) +# Both enabled (default) - no overlap, each rule covers its own scope +dotnet_diagnostic.ATC220.severity = warning +dotnet_diagnostic.ATC221.severity = warning + +# Use ATC220 for ALL namespaces (disable ATC221 and the exclusion) dotnet_diagnostic.ATC220.severity = warning +dotnet_diagnostic.ATC220.exclude_common_namespaces = false dotnet_diagnostic.ATC221.severity = none -# OR use lenient policy (only System/Microsoft/Atc must be global) +# Use only ATC221 for common namespaces dotnet_diagnostic.ATC220.severity = none dotnet_diagnostic.ATC221.severity = warning ``` -**Note**: It's recommended to enable only one of these rules to avoid conflicting guidance. - ## 📝 Examples ### Scenario 1: All namespaces should be in GlobalUsings.cs @@ -113,7 +105,20 @@ public class Sample ## ⚙️ Configuration -This rule is not configurable. It applies to all using directives. +Configure in `.editorconfig`: + +```ini +[*.cs] +# Exclude common namespaces handled by ATC221 (default: true) +# Set to false if you want ATC220 to flag ALL namespaces (use with ATC221 disabled) +dotnet_diagnostic.ATC220.exclude_common_namespaces = true +``` + +| Option | Default | Description | +|--------|---------|-------------| +| `exclude_common_namespaces` | `true` | When true, skips namespaces matching ATC221's configured prefixes (System, Microsoft, Atc) to avoid duplicate diagnostics | + +When `exclude_common_namespaces` is `true` (default), ATC220 reads ATC221's `namespace_prefixes` setting to determine which namespaces to skip. If you customize ATC221's prefixes, ATC220 automatically respects that. ## 🔧 Code Fix diff --git a/docs/rules/ATC221.md b/docs/rules/ATC221.md index ba2887d..38ccfe5 100644 --- a/docs/rules/ATC221.md +++ b/docs/rules/ATC221.md @@ -37,53 +37,44 @@ Centralizing common namespace imports in GlobalUsings.cs provides several benefi This is particularly useful for large projects where the same namespaces (like `System.Linq`, `System.Collections.Generic`) are used throughout the codebase. -## 🔀 ATC220 vs ATC221: Which Rule to Use? +## 🔀 ATC220 and ATC221: Working Together -Both ATC220 and ATC221 enforce global usings, but they differ in scope and strictness: +Both ATC220 and ATC221 enforce global usings, but they differ in scope: | Aspect | ATC220 (Strict) | ATC221 (Lenient) | |--------|----------------|------------------| -| **Policy** | All namespaces | Only System/Microsoft/Atc | -| **Flags** | Every using directive | Only common framework usings | +| **Policy** | Non-common namespaces (by default) | Only System/Microsoft/Atc | +| **Flags** | Third-party and custom using directives | Only common framework usings | | **Third-party libs** | Must be in GlobalUsings.cs | Can stay in individual files | -| **Use when** | You want zero using statements in code files | You want flexibility for third-party dependencies | -| **Best for** | Highly controlled codebases, internal projects | Projects with many third-party libraries | +| **Best for** | Catching all remaining non-common usings | Centralizing common framework usings | -### When to Use ATC221 (This Rule) +### Automatic Mutual Exclusivity -Choose ATC221 if you want: +By default, both rules can be enabled simultaneously **without producing duplicate warnings**. ATC220 automatically excludes namespaces that ATC221 handles (System, Microsoft, Atc), so each using directive triggers at most one warning. -- **Flexibility**: Allow third-party usings to remain in individual files -- **Context clarity**: See third-party dependencies where they're used (Xunit, FluentAssertions, etc.) -- **Migration friendliness**: Easier to adopt incrementally in existing projects -- **Library projects**: Where different files may use different third-party packages -- **Balanced approach**: Centralize framework usings while keeping context for external dependencies +| Scenario | ATC220 fires on | ATC221 fires on | +|----------|----------------|----------------| +| Both enabled (default) | Third-party/custom namespaces | System/Microsoft/Atc | +| Only ATC220 (`exclude_common_namespaces = false`) | Everything | n/a | +| Only ATC221 | n/a | System/Microsoft/Atc | -### When to Use ATC220 Instead - -Choose ATC220 if you want: - -- **Maximum consistency**: Every file looks identical (no using statements at all) -- **Zero exceptions**: All usings centralized, no local decisions needed -- **Internal projects**: Where you control all dependencies -- **Minimal boilerplate**: Absolutely cleanest possible code files - -### Configuration Example - -You can enable only one rule at a time in your `.editorconfig`: +### Configuration Examples ```ini -# Use lenient policy (only System/Microsoft/Atc must be global) +# Both enabled (default) - no overlap, each rule covers its own scope +dotnet_diagnostic.ATC220.severity = warning +dotnet_diagnostic.ATC221.severity = warning + +# Use only ATC221 for common namespaces dotnet_diagnostic.ATC220.severity = none dotnet_diagnostic.ATC221.severity = warning -# OR use strict policy (all usings must be global) +# Use ATC220 for ALL namespaces (disable ATC221 and the exclusion) dotnet_diagnostic.ATC220.severity = warning +dotnet_diagnostic.ATC220.exclude_common_namespaces = false dotnet_diagnostic.ATC221.severity = none ``` -**Note**: It's recommended to enable only one of these rules to avoid conflicting guidance. - ## 📝 Examples ### Scenario 1: System namespaces should be in GlobalUsings.cs diff --git a/sample/Atc.Analyzer.Sample.Atc220/InvalidExamples.cs b/sample/Atc.Analyzer.Sample.Atc220/InvalidExamples.cs index d1de3de..db85c6e 100644 --- a/sample/Atc.Analyzer.Sample.Atc220/InvalidExamples.cs +++ b/sample/Atc.Analyzer.Sample.Atc220/InvalidExamples.cs @@ -1,11 +1,13 @@ namespace Atc.Analyzer.Sample.Atc220; -// These usings SHOULD be moved to GlobalUsings.cs and will trigger ATC220 +// These usings SHOULD be moved to GlobalUsings.cs +// By default, ATC220 skips common namespaces (System/Microsoft/Atc) to avoid overlap with ATC221 +// System.Linq and System.Text are flagged by ATC221, while Xunit is flagged by ATC220 #pragma warning disable ATC220, ATC221 -using System.Linq; // ATC220: Should be in GlobalUsings.cs -using System.Text; // ATC220: Should be in GlobalUsings.cs -using Xunit; // ATC220: Should be in GlobalUsings.cs (ALL namespaces) +using System.Linq; // ATC221: Should be in GlobalUsings.cs (common namespace) +using System.Text; // ATC221: Should be in GlobalUsings.cs (common namespace) +using Xunit; // ATC220: Should be in GlobalUsings.cs (non-common namespace) #pragma warning disable CA1303 #pragma warning disable CA1822 diff --git a/sample/Atc.Analyzer.Sample.Atc221/InvalidExamples.cs b/sample/Atc.Analyzer.Sample.Atc221/InvalidExamples.cs index fb68f5b..afbdaef 100644 --- a/sample/Atc.Analyzer.Sample.Atc221/InvalidExamples.cs +++ b/sample/Atc.Analyzer.Sample.Atc221/InvalidExamples.cs @@ -1,7 +1,8 @@ namespace Atc.Analyzer.Sample.Atc221; // These usings SHOULD be moved to GlobalUsings.cs and will trigger ATC221 -#pragma warning disable ATC220, ATC221 +// ATC220 automatically skips these common namespaces (System/Microsoft/Atc) by default +#pragma warning disable ATC221 using System.IO; // ATC221: Should be in GlobalUsings.cs using System.Linq; // ATC221: Should be in GlobalUsings.cs diff --git a/sample/Atc.Analyzer.Sample.Atc221/ValidExamples.cs b/sample/Atc.Analyzer.Sample.Atc221/ValidExamples.cs index cc51a0c..aa2f1aa 100644 --- a/sample/Atc.Analyzer.Sample.Atc221/ValidExamples.cs +++ b/sample/Atc.Analyzer.Sample.Atc221/ValidExamples.cs @@ -1,9 +1,9 @@ namespace Atc.Analyzer.Sample.Atc221; -#pragma warning disable ATC220 +#pragma warning disable ATC220 // ATC220 still flags third-party namespaces like Xunit // No usings from System/Microsoft/Atc here - they're in GlobalUsings.cs -using Xunit; // Third-party namespace - this is OK +using Xunit; // Third-party namespace - OK for ATC221, but ATC220 flags non-common namespaces #pragma warning disable CA1303 #pragma warning disable CA1822 diff --git a/src/Atc.Analyzer/Extensions/AnalyzerConfigOptionsExtensions.cs b/src/Atc.Analyzer/Extensions/AnalyzerConfigOptionsExtensions.cs index 7f2ce55..b09389a 100644 --- a/src/Atc.Analyzer/Extensions/AnalyzerConfigOptionsExtensions.cs +++ b/src/Atc.Analyzer/Extensions/AnalyzerConfigOptionsExtensions.cs @@ -120,6 +120,38 @@ public int GetMinChainLength(string ruleId) return Math.Max(MinMinCount, Math.Min(MaxMinCount, length)); } + /// + /// Gets whether common namespaces should be excluded from the specified rule. + /// When true, namespaces matching ATC221's configured prefixes are skipped to avoid duplicate diagnostics. + /// + /// The rule identifier (e.g., "ATC220"). + /// + /// True if common namespaces should be excluded (default), false otherwise. + /// + /// + /// Configure in .editorconfig using: + /// + /// dotnet_diagnostic.ATC220.exclude_common_namespaces = false + /// + /// + public bool GetExcludeCommonNamespaces(string ruleId) + { + if (options is null) + { + return true; + } + + var key = $"dotnet_diagnostic.{ruleId}.exclude_common_namespaces"; + + if (!options.TryGetValue(key, out var value) || + string.IsNullOrWhiteSpace(value)) + { + return true; + } + + return !value.Equals("false", StringComparison.OrdinalIgnoreCase); + } + /// /// Gets the configured namespace prefixes for the specified rule from .editorconfig. /// diff --git a/src/Atc.Analyzer/Rules/Style/GlobalUsingsAllAnalyzer.cs b/src/Atc.Analyzer/Rules/Style/GlobalUsingsAllAnalyzer.cs index acfbdfc..51ef101 100644 --- a/src/Atc.Analyzer/Rules/Style/GlobalUsingsAllAnalyzer.cs +++ b/src/Atc.Analyzer/Rules/Style/GlobalUsingsAllAnalyzer.cs @@ -28,6 +28,7 @@ public override void Initialize(AnalysisContext context) context.RegisterSyntaxNodeAction(AnalyzeUsingDirective, SyntaxKind.UsingDirective); } + [SuppressMessage("Design", "MA0051:Method is too long", Justification = "OK.")] private static void AnalyzeUsingDirective(SyntaxNodeAnalysisContext context) { if (context.Node.SyntaxTree.IsAutoGeneratedFile()) @@ -76,6 +77,19 @@ private static void AnalyzeUsingDirective(SyntaxNodeAnalysisContext context) return; } + // Check if common namespaces should be excluded (deferred to ATC221) + var options = context.Options.AnalyzerConfigOptionsProvider.GetOptions(context.Node.SyntaxTree); + var excludeCommon = options.GetExcludeCommonNamespaces(RuleIdentifierConstants.Style.GlobalUsingsAll); + + if (excludeCommon) + { + var commonPrefixes = options.GetNamespacePrefixes(RuleIdentifierConstants.Style.GlobalUsingsCommon); + if (commonPrefixes.Any(prefix => namespaceName!.StartsWith(prefix, StringComparison.Ordinal))) + { + return; + } + } + // All non-static, non-alias using directives should be global var diagnostic = Diagnostic.Create( Rule, diff --git a/test/Atc.Analyzer.Tests/Rules/Style/GlobalUsingsAllAnalyzerNoDiagnosticTests.cs b/test/Atc.Analyzer.Tests/Rules/Style/GlobalUsingsAllAnalyzerNoDiagnosticTests.cs index c5f364c..5fe1be4 100644 --- a/test/Atc.Analyzer.Tests/Rules/Style/GlobalUsingsAllAnalyzerNoDiagnosticTests.cs +++ b/test/Atc.Analyzer.Tests/Rules/Style/GlobalUsingsAllAnalyzerNoDiagnosticTests.cs @@ -118,4 +118,49 @@ public static void DoSomething() await AnalyzerVerifier.VerifyAnalyzerAsync(code); } + + [Fact] + public async Task NoDiagnostic_SystemNamespace_DefaultExcludesCommon() + { + const string code = """ + using System; + + public class Sample + { + public static void DoSomething() + { + } + } + """; + + await AnalyzerVerifier.VerifyAnalyzerAsync(code); + } + + [Fact] + public async Task NoDiagnostic_MicrosoftNamespace_DefaultExcludesCommon() + { + const string code = """ + using Microsoft.Extensions.Logging; + + public class Sample + { + } + """; + + await AnalyzerVerifier.VerifyAnalyzerAsync(code); + } + + [Fact] + public async Task NoDiagnostic_AtcNamespace_DefaultExcludesCommon() + { + const string code = """ + using Atc.Utilities; + + public class Sample + { + } + """; + + await AnalyzerVerifier.VerifyAnalyzerAsync(code); + } } \ No newline at end of file diff --git a/test/Atc.Analyzer.Tests/Rules/Style/GlobalUsingsAllAnalyzerReportsDiagnosticTests.cs b/test/Atc.Analyzer.Tests/Rules/Style/GlobalUsingsAllAnalyzerReportsDiagnosticTests.cs index d358ce2..42e273c 100644 --- a/test/Atc.Analyzer.Tests/Rules/Style/GlobalUsingsAllAnalyzerReportsDiagnosticTests.cs +++ b/test/Atc.Analyzer.Tests/Rules/Style/GlobalUsingsAllAnalyzerReportsDiagnosticTests.cs @@ -6,11 +6,12 @@ namespace Atc.Analyzer.Tests.Rules.Style; [SuppressMessage("", "AsyncFixer01:The method does not need to use async/await", Justification = "OK - Test code")] [SuppressMessage("", "SA1135::The method does not need to use async/await", Justification = "OK - Test code")] +[SuppressMessage("", "S2699:Add at least one assertion to this test case", Justification = "OK - RunAsync is the assertion")] [SuppressMessage("Naming", "MA0048:File name must match type name", Justification = "OK - Partial class")] public sealed partial class GlobalUsingsAllAnalyzerTests { [Fact] - public async Task ReportsDiagnostic_SystemNamespace() + public async Task ReportsDiagnostic_SystemNamespace_WhenExcludeCommonDisabled() { const string code = """ [|using System;|] @@ -23,11 +24,27 @@ public static void DoSomething() } """; - await AnalyzerVerifier.VerifyAnalyzerAsync(code); + var test = new CSharpAnalyzerTest + { + ReferenceAssemblies = ReferenceAssemblies.Net.Net90, + TestCode = code, + CompilerDiagnostics = CompilerDiagnostics.None, + }; + + test.TestState.AnalyzerConfigFiles.Add(( + "/.editorconfig", + """ + root = true + + [*] + dotnet_diagnostic.ATC220.exclude_common_namespaces = false + """)); + + await test.RunAsync(); } [Fact] - public async Task ReportsDiagnostic_SystemCollectionsGeneric() + public async Task ReportsDiagnostic_SystemCollectionsGeneric_WhenExcludeCommonDisabled() { const string code = """ [|using System.Collections.Generic;|] @@ -38,7 +55,23 @@ public class Sample } """; - await AnalyzerVerifier.VerifyAnalyzerAsync(code); + var test = new CSharpAnalyzerTest + { + ReferenceAssemblies = ReferenceAssemblies.Net.Net90, + TestCode = code, + CompilerDiagnostics = CompilerDiagnostics.None, + }; + + test.TestState.AnalyzerConfigFiles.Add(( + "/.editorconfig", + """ + root = true + + [*] + dotnet_diagnostic.ATC220.exclude_common_namespaces = false + """)); + + await test.RunAsync(); } [Fact] @@ -70,7 +103,7 @@ public class Sample } [Fact] - public async Task ReportsDiagnostic_MicrosoftNamespace() + public async Task ReportsDiagnostic_MicrosoftNamespace_WhenExcludeCommonDisabled() { const string code = """ [|using Microsoft.Extensions.Logging;|] @@ -80,11 +113,27 @@ public class Sample } """; - await AnalyzerVerifier.VerifyAnalyzerAsync(code); + var test = new CSharpAnalyzerTest + { + ReferenceAssemblies = ReferenceAssemblies.Net.Net90, + TestCode = code, + CompilerDiagnostics = CompilerDiagnostics.None, + }; + + test.TestState.AnalyzerConfigFiles.Add(( + "/.editorconfig", + """ + root = true + + [*] + dotnet_diagnostic.ATC220.exclude_common_namespaces = false + """)); + + await test.RunAsync(); } [Fact] - public async Task ReportsDiagnostic_AtcNamespace() + public async Task ReportsDiagnostic_AtcNamespace_WhenExcludeCommonDisabled() { const string code = """ [|using Atc.Utilities;|] @@ -94,11 +143,43 @@ public class Sample } """; + var test = new CSharpAnalyzerTest + { + ReferenceAssemblies = ReferenceAssemblies.Net.Net90, + TestCode = code, + CompilerDiagnostics = CompilerDiagnostics.None, + }; + + test.TestState.AnalyzerConfigFiles.Add(( + "/.editorconfig", + """ + root = true + + [*] + dotnet_diagnostic.ATC220.exclude_common_namespaces = false + """)); + + await test.RunAsync(); + } + + [Fact] + public async Task ReportsDiagnostic_MultipleNamespaces_OnlyNonCommon() + { + const string code = """ + using System; + [|using Xunit;|] + [|using MyCompany.Utilities;|] + + public class Sample + { + } + """; + await AnalyzerVerifier.VerifyAnalyzerAsync(code); } [Fact] - public async Task ReportsDiagnostic_MultipleNamespaces() + public async Task ReportsDiagnostic_AllNamespaces_WhenExcludeCommonDisabled() { const string code = """ [|using System;|] @@ -110,6 +191,22 @@ public class Sample } """; - await AnalyzerVerifier.VerifyAnalyzerAsync(code); + var test = new CSharpAnalyzerTest + { + ReferenceAssemblies = ReferenceAssemblies.Net.Net90, + TestCode = code, + CompilerDiagnostics = CompilerDiagnostics.None, + }; + + test.TestState.AnalyzerConfigFiles.Add(( + "/.editorconfig", + """ + root = true + + [*] + dotnet_diagnostic.ATC220.exclude_common_namespaces = false + """)); + + await test.RunAsync(); } } \ No newline at end of file diff --git a/test/Atc.Analyzer.Tests/Rules/Style/GlobalUsingsAllCodeFixProviderTests.cs b/test/Atc.Analyzer.Tests/Rules/Style/GlobalUsingsAllCodeFixProviderTests.cs index 7555dbf..0093638 100644 --- a/test/Atc.Analyzer.Tests/Rules/Style/GlobalUsingsAllCodeFixProviderTests.cs +++ b/test/Atc.Analyzer.Tests/Rules/Style/GlobalUsingsAllCodeFixProviderTests.cs @@ -5,10 +5,11 @@ namespace Atc.Analyzer.Tests.Rules.Style; #pragma warning restore SA1135 // Using directives must be qualified [SuppressMessage("", "AsyncFixer01:The method does not need to use async/await", Justification = "OK - Test code")] +[SuppressMessage("", "S2699:Add at least one assertion to this test case", Justification = "OK - RunAsync is the assertion")] public sealed class GlobalUsingsAllCodeFixProviderTests { [Fact] - public Task FixUsing_MoveSystemNamespaceToGlobalUsings() + public async Task FixUsing_MoveSystemNamespaceToGlobalUsings() { const string source = """ using System; @@ -40,7 +41,18 @@ public static void DoSomething() .WithSpan(1, 1, 1, 14), }; - return CodeFixVerifier.VerifyCodeFixAsync(source, expected, fixedSource); + var test = new CSharpCodeFixTest + { + ReferenceAssemblies = ReferenceAssemblies.Net.Net90, + TestCode = source.NormalizeLineEndings(), + FixedCode = fixedSource.NormalizeLineEndings(), + CompilerDiagnostics = CompilerDiagnostics.None, + }; + + test.ExpectedDiagnostics.AddRange(expected); + test.TestState.AnalyzerConfigFiles.Add(("/.editorconfig", "root = true\n\n[*]\nend_of_line = lf\ndotnet_diagnostic.ATC220.exclude_common_namespaces = false\n")); + + await test.RunAsync(); } [Fact] @@ -207,7 +219,7 @@ public class Sample test.FixedState.Sources.Add(("GlobalUsings.cs", fixedGlobalUsingsSource.NormalizeLineEndings())); test.ExpectedDiagnostics.AddRange(expected); - test.TestState.AnalyzerConfigFiles.Add(("/.editorconfig", "root = true\n\n[*]\nend_of_line = lf\n")); + test.TestState.AnalyzerConfigFiles.Add(("/.editorconfig", "root = true\n\n[*]\nend_of_line = lf\ndotnet_diagnostic.ATC220.exclude_common_namespaces = false\n")); await test.RunAsync(); @@ -266,7 +278,7 @@ public class Sample test.FixedState.Sources.Add(("GlobalUsings.cs", fixedGlobalUsingsSource.NormalizeLineEndings())); test.ExpectedDiagnostics.AddRange(expected); - test.TestState.AnalyzerConfigFiles.Add(("/.editorconfig", "root = true\n\n[*]\nend_of_line = lf\n")); + test.TestState.AnalyzerConfigFiles.Add(("/.editorconfig", "root = true\n\n[*]\nend_of_line = lf\ndotnet_diagnostic.ATC220.exclude_common_namespaces = false\n")); await test.RunAsync();