From b59cfef123d105afa5a5003acde855714ed5ed54 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Tue, 16 Jun 2026 08:41:31 +0000 Subject: [PATCH] fix: ignore discard variables in SMA8001 and split granular tests - Updated ExplicitNumberDeclarationAnalyzer to ignore variables named `_`. - Split `SMA8001_Violation_OtherVarDeclarationsWithPrimitiveNumbers` into specific test cases for out variables, foreach loops, and deconstructions. - Added test cases for discards in various contexts to ensure they are not flagged. --- .../ExplicitNumberDeclarationAnalyzer.cs | 5 + ..._ExplicitNumberDeclarationAnalyzerTests.cs | 151 ++++++++++++++++-- 2 files changed, 146 insertions(+), 10 deletions(-) diff --git a/src/analysis/Analyzers/ExplicitNumberDeclarationAnalyzer.cs b/src/analysis/Analyzers/ExplicitNumberDeclarationAnalyzer.cs index 368c02a..50bf20e 100644 --- a/src/analysis/Analyzers/ExplicitNumberDeclarationAnalyzer.cs +++ b/src/analysis/Analyzers/ExplicitNumberDeclarationAnalyzer.cs @@ -110,6 +110,11 @@ private static void AnalyzeForEachStatement(SyntaxNodeAnalysisContext context) private static void ReportIfPrimitiveNumber(SyntaxNodeAnalysisContext context, SyntaxToken identifier, ISymbol? symbol) { + if (identifier.Text == "_") + { + return; + } + if (symbol is ILocalSymbol local && IsSystemPrimitiveNumber(local.Type)) { context.ReportDiagnostic(Diagnostic.Create( diff --git a/test/AnalyzerTests/SMA8001_ExplicitNumberDeclarationAnalyzerTests.cs b/test/AnalyzerTests/SMA8001_ExplicitNumberDeclarationAnalyzerTests.cs index c1bf375..a62958e 100644 --- a/test/AnalyzerTests/SMA8001_ExplicitNumberDeclarationAnalyzerTests.cs +++ b/test/AnalyzerTests/SMA8001_ExplicitNumberDeclarationAnalyzerTests.cs @@ -157,7 +157,7 @@ await VerifyCS.VerifyAnalyzerAsync(test, } [TestMethod] - public async Task SMA8001_Violation_OtherVarDeclarationsWithPrimitiveNumbers() + public async Task SMA8001_Violation_OutVarDeclaration() { var test = @" using System.Collections.Generic; @@ -171,14 +171,69 @@ public void M(Dictionary dict) if (dict.TryGetValue(""key"", out var {|#0:value|})) { } + } + } +} +"; + await VerifyCS.VerifyAnalyzerAsync(test, + VerifyCS.Diagnostic(ExplicitNumberDeclarationAnalyzer.RuleId_ExplicitNumber).WithLocation(0).WithArguments("value") + ); + } - foreach (var {|#1:item|} in new int[] { 1, 2, 3 }) + [TestMethod] + public async Task SMA8001_Violation_ForEachVariable() + { + var test = @" +namespace Test +{ + public class C + { + public void M() + { + foreach (var {|#0:item|} in new int[] { 1, 2, 3 }) { } + } + } +} +"; + await VerifyCS.VerifyAnalyzerAsync(test, + VerifyCS.Diagnostic(ExplicitNumberDeclarationAnalyzer.RuleId_ExplicitNumber).WithLocation(0).WithArguments("item") + ); + } - var ({|#2:a|}, {|#3:b|}) = (1, 2.0); + [TestMethod] + public async Task SMA8001_Violation_Deconstruction() + { + var test = @" +namespace Test +{ + public class C + { + public void M() + { + var ({|#0:a|}, {|#1:b|}) = (1, 2.0); + } + } +} +"; + await VerifyCS.VerifyAnalyzerAsync(test, + VerifyCS.Diagnostic(ExplicitNumberDeclarationAnalyzer.RuleId_ExplicitNumber).WithLocation(0).WithArguments("a"), + VerifyCS.Diagnostic(ExplicitNumberDeclarationAnalyzer.RuleId_ExplicitNumber).WithLocation(1).WithArguments("b") + ); + } - foreach (var ({|#4:x|}, {|#5:y|}) in new (int, int)[] { (1, 2) }) + [TestMethod] + public async Task SMA8001_Violation_ForEachDeconstruction() + { + var test = @" +namespace Test +{ + public class C + { + public void M() + { + foreach (var ({|#0:x|}, {|#1:y|}) in new (int, int)[] { (1, 2) }) { } } @@ -186,13 +241,89 @@ public void M(Dictionary dict) } "; await VerifyCS.VerifyAnalyzerAsync(test, - VerifyCS.Diagnostic(ExplicitNumberDeclarationAnalyzer.RuleId_ExplicitNumber).WithLocation(0).WithArguments("value"), - VerifyCS.Diagnostic(ExplicitNumberDeclarationAnalyzer.RuleId_ExplicitNumber).WithLocation(1).WithArguments("item"), - VerifyCS.Diagnostic(ExplicitNumberDeclarationAnalyzer.RuleId_ExplicitNumber).WithLocation(2).WithArguments("a"), - VerifyCS.Diagnostic(ExplicitNumberDeclarationAnalyzer.RuleId_ExplicitNumber).WithLocation(3).WithArguments("b"), - VerifyCS.Diagnostic(ExplicitNumberDeclarationAnalyzer.RuleId_ExplicitNumber).WithLocation(4).WithArguments("x"), - VerifyCS.Diagnostic(ExplicitNumberDeclarationAnalyzer.RuleId_ExplicitNumber).WithLocation(5).WithArguments("y") + VerifyCS.Diagnostic(ExplicitNumberDeclarationAnalyzer.RuleId_ExplicitNumber).WithLocation(0).WithArguments("x"), + VerifyCS.Diagnostic(ExplicitNumberDeclarationAnalyzer.RuleId_ExplicitNumber).WithLocation(1).WithArguments("y") ); } + + [TestMethod] + public async Task SMA8001_Violation_DeconstructionWithDiscard() + { + var test = @" +namespace Test +{ + public class C + { + public void M() + { + var (_, {|#0:b|}) = (1, 2); + } + } +} +"; + await VerifyCS.VerifyAnalyzerAsync(test, + VerifyCS.Diagnostic(ExplicitNumberDeclarationAnalyzer.RuleId_ExplicitNumber).WithLocation(0).WithArguments("b") + ); + } + + [TestMethod] + public async Task SMA8001_Compliant_OutVarWithDiscard() + { + var test = @" +using System.Collections.Generic; + +namespace Test +{ + public class C + { + public void M(Dictionary dict) + { + if (dict.TryGetValue(""key"", out var _)) + { + } + } + } +} +"; + await VerifyCS.VerifyAnalyzerAsync(test); + } + + [TestMethod] + public async Task SMA8001_Compliant_ForEachWithDiscard() + { + var test = @" +namespace Test +{ + public class C + { + public void M() + { + foreach (var _ in new int[] { 1, 2, 3 }) + { + } + } + } +} +"; + await VerifyCS.VerifyAnalyzerAsync(test); + } + + [TestMethod] + public async Task SMA8001_Compliant_DiscardAssignment() + { + var test = @" +namespace Test +{ + public class C + { + public void M() + { + var _ = 1; + } + } +} +"; + await VerifyCS.VerifyAnalyzerAsync(test); + } } }