diff --git a/src/Config/Analyzer.ANcpLua.Analyzers.editorconfig b/src/Config/Analyzer.ANcpLua.Analyzers.editorconfig index 543de2e..b40f467 100644 --- a/src/Config/Analyzer.ANcpLua.Analyzers.editorconfig +++ b/src/Config/Analyzer.ANcpLua.Analyzers.editorconfig @@ -126,7 +126,10 @@ dotnet_diagnostic.AL0024.severity = error # AL0025: Anonymous function can be made static # Help link: https://ancplua.mintlify.app/analyzers/rules/AL0025 # Enabled: True, Severity: warning -dotnet_diagnostic.AL0025.severity = warning +# Demoted: micro-perf hint (avoids implicit `this` capture). IDE0200 covers the +# same ground at suggestion; keeping AL0025 as suggestion avoids 100+ build-errors +# on existing code while leaving the fix one click away in the IDE. +dotnet_diagnostic.AL0025.severity = suggestion # AL0026: Avoid DateTime/DateTimeOffset time accessors # Help link: https://ancplua.mintlify.app/analyzers/rules/AL0026 @@ -191,7 +194,9 @@ dotnet_diagnostic.AL0037.severity = warning # AL0039: Use StringComparison extension # Help link: https://ancplua.mintlify.app/analyzers/rules/AL0039 # Enabled: True, Severity: warning -dotnet_diagnostic.AL0039.severity = warning +# Demoted: style preference toward ANcpLua.Roslyn.Utilities extensions. The real +# correctness rule is CA1310 (kept at warning). Fix is one click in the IDE. +dotnet_diagnostic.AL0039.severity = suggestion # AL0040: Use attribute argument extraction extension # Help link: https://ancplua.mintlify.app/analyzers/rules/AL0040 @@ -349,7 +354,10 @@ dotnet_diagnostic.AL0069.severity = suggestion # AL0070: Collector endpoint should use OTLP protocol # Help link: https://ancplua.mintlify.app/analyzers/rules/AL0070 # Enabled: True, Severity: warning -dotnet_diagnostic.AL0070.severity = warning +# Demoted: false-positives on non-collector endpoint strings (config URLs, +# health check probes, sample-data URLs). The platform-level OTLP exporter +# configuration is what actually matters. +dotnet_diagnostic.AL0070.severity = suggestion # AL0071: [Meter] class must be partial static # Help link: https://ancplua.mintlify.app/analyzers/rules/AL0071 @@ -405,7 +413,10 @@ dotnet_diagnostic.AL0080.severity = warning # AL0081: Missing health checks # Help link: https://ancplua.mintlify.app/analyzers/rules/AL0081 # Enabled: True, Severity: warning -dotnet_diagnostic.AL0081.severity = warning +# Demoted: operational guidance, not a correctness bug. Many services +# legitimately defer health check wiring to platform infrastructure (Kubernetes +# liveness/readiness probes, container orchestrator health checks). +dotnet_diagnostic.AL0081.severity = suggestion # AL0082: Consider using configuration for connection string # Help link: https://ancplua.mintlify.app/analyzers/rules/AL0082 @@ -472,27 +483,36 @@ dotnet_diagnostic.AL0093.severity = suggestion # AL0094: Avoid 'dynamic' keyword in AOT-published code # Help link: https://ancplua.mintlify.app/analyzers/rules/AL0094 # Enabled: True, Severity: warning -dotnet_diagnostic.AL0094.severity = warning +# Demoted: AOT advisory. Non-AOT projects use `dynamic` legitimately (DLR scripting, +# interop). AOT projects should re-promote to warning/error in their editorconfig. +dotnet_diagnostic.AL0094.severity = suggestion # AL0095: Avoid Expression.Compile() in AOT context # Help link: https://ancplua.mintlify.app/analyzers/rules/AL0095 # Enabled: True, Severity: warning -dotnet_diagnostic.AL0095.severity = warning +# Demoted: AOT advisory — see AL0094/AL0101 rationale. +dotnet_diagnostic.AL0095.severity = suggestion # AL0096: Enable EventSourceSupport for AOT with telemetry # Help link: https://ancplua.mintlify.app/analyzers/rules/AL0096 # Enabled: True, Severity: warning -dotnet_diagnostic.AL0096.severity = warning +# Demoted: AOT advisory — see AL0094/AL0101 rationale. +dotnet_diagnostic.AL0096.severity = suggestion # AL0101: Activator.CreateInstance is not AOT-safe # Help link: https://ancplua.mintlify.app/analyzers/rules/AL0101 # Enabled: True, Severity: warning -dotnet_diagnostic.AL0101.severity = warning +# Demoted: not every project ships AOT. The analyzer flags Activator.CreateInstance +# regardless of , so non-AOT projects (most services + tests) get +# unconditional warnings. AOT-bound projects should bump this back to error via +# their .editorconfig along with true. +dotnet_diagnostic.AL0101.severity = suggestion # AL0102: Type.GetType with dynamic name is not AOT-safe # Help link: https://ancplua.mintlify.app/analyzers/rules/AL0102 # Enabled: True, Severity: warning -dotnet_diagnostic.AL0102.severity = warning +# Demoted: AOT advisory — see AL0094/AL0101 rationale. +dotnet_diagnostic.AL0102.severity = suggestion # AL0103: Closed hierarchy match is not exhaustive # Help link: https://ancplua.mintlify.app/analyzers/rules/AL0103 @@ -552,7 +572,9 @@ dotnet_diagnostic.AL0113.severity = warning # AL0114: Prefer TryParse over Parse # Help link: https://ancplua.mintlify.app/analyzers/rules/AL0114 # Enabled: True, Severity: warning -dotnet_diagnostic.AL0114.severity = warning +# Demoted: style preference. Parse is correct when the caller verifies input +# upstream (route params, config) or when an exception IS the desired signal. +dotnet_diagnostic.AL0114.severity = suggestion # AL0115: Empty catch block swallows exceptions # Help link: https://ancplua.mintlify.app/analyzers/rules/AL0115 @@ -667,7 +689,11 @@ dotnet_diagnostic.AL0136.severity = warning # AL0137: Use Guard.* helpers instead of throw helpers # Help link: https://ancplua.mintlify.app/analyzers/rules/AL0137 # Enabled: True, Severity: warning -dotnet_diagnostic.AL0137.severity = warning +# Demoted: style migration to ANcpLua.Roslyn.Utilities Guard.* helpers. +# Codebases that haven't taken that dependency get hundreds of warnings on +# valid BCL ArgumentNullException.ThrowIfNull / ArgumentException.ThrowIfNullOrEmpty +# usage. The RS0030 banned-symbols rule still flags the BCL calls themselves. +dotnet_diagnostic.AL0137.severity = suggestion # AL0138: Use Math.Round/MathF.Round overload with explicit MidpointRounding # Help link: https://ancplua.mintlify.app/analyzers/rules/AL0138 diff --git a/src/Config/Analyzer.Microsoft.CodeAnalysis.NetAnalyzers.editorconfig b/src/Config/Analyzer.Microsoft.CodeAnalysis.NetAnalyzers.editorconfig index d2f0b71..93d2b9d 100644 --- a/src/Config/Analyzer.Microsoft.CodeAnalysis.NetAnalyzers.editorconfig +++ b/src/Config/Analyzer.Microsoft.CodeAnalysis.NetAnalyzers.editorconfig @@ -18,7 +18,9 @@ dotnet_diagnostic.CA1001.severity = warning # CA1002: Do not expose generic lists # Help link: https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1002 # Enabled: False, Severity: warning -dotnet_diagnostic.CA1002.severity = warning +# Demoted from warning: wire-format DTOs, protobuf, System.Text.Json and EF projections +# legitimately expose List. Per dotnet/roslyn-analyzers#1705 DTOs are exceptions. +dotnet_diagnostic.CA1002.severity = suggestion # CA1003: Use generic event handler instances # Help link: https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1003 @@ -103,7 +105,9 @@ dotnet_diagnostic.CA1031.severity = none # CA1032: Implement standard exception constructors # Help link: https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1032 # Enabled: False, Severity: warning -dotnet_diagnostic.CA1032.severity = warning +# Demoted: most custom exception types intentionally restrict construction +# (sealed default ctor, single-arg-only). Keeping it visible as suggestion. +dotnet_diagnostic.CA1032.severity = suggestion # CA1033: Interface methods should be callable by child types # Help link: https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1033 @@ -113,7 +117,9 @@ dotnet_diagnostic.CA1033.severity = none # CA1034: Nested types should not be visible # Help link: https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1034 # Enabled: False, Severity: warning -dotnet_diagnostic.CA1034.severity = warning +# Demoted: legitimate builder/options patterns (e.g. ConfigureOptions.Builder), +# protobuf and C# 14 extension blocks routinely nest types. +dotnet_diagnostic.CA1034.severity = suggestion # CA1036: Override methods on comparable types # Help link: https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1036 @@ -168,22 +174,28 @@ dotnet_diagnostic.CA1051.severity = warning # CA1052: Static holder types should be Static or NotInheritable # Help link: https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1052 # Enabled: False, Severity: warning -dotnet_diagnostic.CA1052.severity = warning +# Demoted: source generators and xUnit fixture base classes can't be sealed/static +# without breaking the generator contract. Style hint, not a real bug. +dotnet_diagnostic.CA1052.severity = suggestion # CA1054: URI-like parameters should not be strings # Help link: https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1054 # Enabled: False, Severity: warning -dotnet_diagnostic.CA1054.severity = warning +# Demoted: JSON DTOs, config-bound options and minimal-API route handlers +# routinely pass URLs as strings. Style hint only. +dotnet_diagnostic.CA1054.severity = suggestion # CA1055: URI-like return values should not be strings # Help link: https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1055 # Enabled: False, Severity: warning -dotnet_diagnostic.CA1055.severity = warning +# Demoted with CA1054/CA1056 — wire-format reality. +dotnet_diagnostic.CA1055.severity = suggestion # CA1056: URI-like properties should not be strings # Help link: https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1056 # Enabled: False, Severity: warning -dotnet_diagnostic.CA1056.severity = warning +# Demoted: JSON DTOs require string URLs for serialization round-trip. +dotnet_diagnostic.CA1056.severity = suggestion # CA1058: Types should not extend certain base types # Help link: https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1058 @@ -269,7 +281,9 @@ dotnet_diagnostic.CA1305.severity = none # CA1307: Specify StringComparison for clarity # Help link: https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1307 # Enabled: False, Severity: warning -dotnet_diagnostic.CA1307.severity = warning +# Demoted: clarity hint only — the correctness rule is CA1310 (kept at warning). +# CA1307 is also covered by AL0039 (StringComparison ext) at suggestion. +dotnet_diagnostic.CA1307.severity = suggestion # CA1308: Normalize strings to uppercase # Help link: https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1308 @@ -464,7 +478,8 @@ dotnet_diagnostic.CA1724.severity = none # CA1725: Parameter names should match base declaration # Help link: https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1725 # Enabled: True, Severity: silent -dotnet_diagnostic.CA1725.severity = warning +# Demoted: pure naming style — does not affect correctness or behavior. +dotnet_diagnostic.CA1725.severity = suggestion # CA1727: Use PascalCase for named placeholders # Help link: https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1727 @@ -521,7 +536,9 @@ dotnet_diagnostic.CA1816.severity = none # CA1819: Properties should not return arrays # Help link: https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1819 # Enabled: False, Severity: warning -dotnet_diagnostic.CA1819.severity = warning +# Demoted: protobuf, schemas, OTLP, token validation and JSON DTOs require +# array-typed properties. Per dotnet/roslyn-analyzers#1705 wire types are exceptions. +dotnet_diagnostic.CA1819.severity = suggestion # CA1820: Test for empty strings using string length # Help link: https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1820 @@ -536,12 +553,17 @@ dotnet_diagnostic.CA1821.severity = warning # CA1822: Mark members as static # Help link: https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1822 # Enabled: True, Severity: suggestion -dotnet_diagnostic.CA1822.severity = warning +# Demoted to suggestion (matches the analyzer default): micro-perf hint, often +# blocked by inheritance, interfaces or test instance harnesses (xUnit fixtures). +dotnet_diagnostic.CA1822.severity = suggestion # CA1823: Avoid unused private fields # Help link: https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1823 # Enabled: False, Severity: warning -dotnet_diagnostic.CA1823.severity = warning +# Demoted: high false-positive rate on DI-injected fields read via reflection, +# source-generator pattern fields, and incremental-build scaffolding. Real +# dead-code detection is better served by IDE0052 (kept at warning in CodingStyle). +dotnet_diagnostic.CA1823.severity = suggestion # CA1824: Mark assemblies with NeutralResourcesLanguageAttribute # Help link: https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1824 @@ -686,7 +708,9 @@ dotnet_diagnostic.CA1851.severity = suggestion # CA1852: Seal internal types # Help link: https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1852 # Enabled: True, Severity: silent -dotnet_diagnostic.CA1852.severity = warning +# Demoted: micro-perf hint; mocking frameworks (Moq, NSubstitute) and test +# scaffolding routinely require open internal types. The default is silent. +dotnet_diagnostic.CA1852.severity = suggestion # CA1853: Unnecessary call to 'Dictionary.ContainsKey(key)' # Help link: https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1853 @@ -721,7 +745,9 @@ dotnet_diagnostic.CA1858.severity = warning # CA1859: Use concrete types when possible for improved performance # Help link: https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1859 # Enabled: True, Severity: suggestion -dotnet_diagnostic.CA1859.severity = warning +# Demoted: micro-perf hint that fights DIP (e.g. method returning IList). +# Default is suggestion. +dotnet_diagnostic.CA1859.severity = suggestion # CA1860: Avoid using 'Enumerable.Any()' extension method # Help link: https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1860 diff --git a/tools/ConfigFilesGenerator/Program.cs b/tools/ConfigFilesGenerator/Program.cs index 286b675..ac03059 100644 --- a/tools/ConfigFilesGenerator/Program.cs +++ b/tools/ConfigFilesGenerator/Program.cs @@ -145,19 +145,62 @@ HashSet GetRuleIdsConfiguredOutside(FullPath configurationFilePath) if (!Directory.Exists(configRoot)) return configuredRuleIds; - foreach (var editorconfig in Directory.EnumerateFiles(configRoot, "*.editorconfig", SearchOption.AllDirectories)) + // Path-scoped editorconfigs (no `is_global = true`) override rules only inside + // their [glob] sections, not project-wide. Skipping them keeps the global + // analyzer files authoritative for default severities; otherwise rules + // relaxed only in tests/generated paths would disappear from the global file. + var allEditorConfigs = Directory.EnumerateFiles(configRoot, "*.editorconfig", SearchOption.AllDirectories) + .Select(FullPath.FromPath) + .ToArray(); + var pathScopedConfigs = allEditorConfigs.Where(IsPathScopedEditorConfig).ToHashSet(); + + foreach (var editorconfig in allEditorConfigs) { - if (string.Equals(Path.GetFullPath(editorconfig), Path.GetFullPath(configurationFilePath.Value), - StringComparison.OrdinalIgnoreCase)) + if (editorconfig == configurationFilePath) continue; - foreach (var rule in GetConfiguration(FullPath.FromPath(editorconfig)).Rules) + if (pathScopedConfigs.Contains(editorconfig)) + continue; + + foreach (var rule in GetConfiguration(editorconfig).Rules) configuredRuleIds.Add(rule.Id); } return configuredRuleIds; } +static bool IsPathScopedEditorConfig(FullPath filePath) +{ + if (!File.Exists(filePath)) + return false; + + // An editorconfig is path-scoped if it lacks `is_global = true`. + // Global editorconfigs apply project-wide; path-scoped ones only + // apply within their [glob] sections. + foreach (var line in File.ReadLines(filePath)) + { + var trimmed = line.Trim(); + + // Ignore section headers + if (trimmed.StartsWith("[", StringComparison.Ordinal)) + continue; + + var parts = trimmed.Split('=', 2, StringSplitOptions.TrimEntries); + if (parts.Length != 2) + continue; + + // Check for exact key match to "is_global" + if (!string.Equals(parts[0], "is_global", StringComparison.OrdinalIgnoreCase)) + continue; + + // Only return false if value is "true" + if (string.Equals(parts[1], "true", StringComparison.OrdinalIgnoreCase)) + return false; + } + + return true; +} + static async Task GetCompilerAnalyzerReferences() { var sdkPath = await GetDotNetSdkPath().ConfigureAwait(false);