diff --git a/src/Analyzers/CSharp/Tests/NamingStyles/NamingStylesTests.cs b/src/Analyzers/CSharp/Tests/NamingStyles/NamingStylesTests.cs index d3c71398f2058..d970743029292 100644 --- a/src/Analyzers/CSharp/Tests/NamingStyles/NamingStylesTests.cs +++ b/src/Analyzers/CSharp/Tests/NamingStyles/NamingStylesTests.cs @@ -1334,5 +1334,36 @@ await TestInRegularAndScriptAsync( @"public record Foo(int [|MyInt|]);", options: s_options.MergeStyles(s_options.PropertyNamesArePascalCase, s_options.ParameterNamesAreCamelCaseWithPUnderscorePrefix)); } + + [Theory] + [InlineData("_")] + [InlineData("_1")] + [InlineData("_123")] + public async Task TestDiscardParameterAsync(string identifier) + { + await TestMissingInRegularAndScriptAsync( +$@"class C +{{ + void M(int [|{identifier}|]) + {{ + }} +}}", new TestParameters(options: s_options.ParameterNamesAreCamelCase)); + } + + [Theory] + [InlineData("_")] + [InlineData("_1")] + [InlineData("_123")] + public async Task TestDiscardLocalAsync(string identifier) + { + await TestMissingInRegularAndScriptAsync( +$@"class C +{{ + void M() + {{ + int [|{identifier}|] = 0; + }} +}}", new TestParameters(options: s_options.LocalNamesAreCamelCase)); + } } } diff --git a/src/Analyzers/Core/Analyzers/NamingStyle/NamingStyleDiagnosticAnalyzerBase.cs b/src/Analyzers/Core/Analyzers/NamingStyle/NamingStyleDiagnosticAnalyzerBase.cs index 17ec407f421b7..e35c2f2de973c 100644 --- a/src/Analyzers/Core/Analyzers/NamingStyle/NamingStyleDiagnosticAnalyzerBase.cs +++ b/src/Analyzers/Core/Analyzers/NamingStyle/NamingStyleDiagnosticAnalyzerBase.cs @@ -9,6 +9,7 @@ using System.Threading; using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.NamingStyles; +using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Simplification; using Roslyn.Utilities; @@ -116,6 +117,11 @@ void SyntaxNodeAction(SyntaxNodeAnalysisContext syntaxContext) return null; } + if (symbol.IsSymbolWithSpecialDiscardName()) + { + return null; + } + var namingPreferences = GetNamingStylePreferences(compilation, symbol, options, cancellationToken); if (namingPreferences == null) { diff --git a/src/Analyzers/Core/Analyzers/RemoveUnusedParametersAndValues/AbstractRemoveUnusedParametersAndValuesDiagnosticAnalyzer.SymbolStartAnalyzer.BlockAnalyzer.cs b/src/Analyzers/Core/Analyzers/RemoveUnusedParametersAndValues/AbstractRemoveUnusedParametersAndValuesDiagnosticAnalyzer.SymbolStartAnalyzer.BlockAnalyzer.cs index 57cfdc4c01a5f..72915ad1d0f37 100644 --- a/src/Analyzers/Core/Analyzers/RemoveUnusedParametersAndValues/AbstractRemoveUnusedParametersAndValuesDiagnosticAnalyzer.SymbolStartAnalyzer.BlockAnalyzer.cs +++ b/src/Analyzers/Core/Analyzers/RemoveUnusedParametersAndValues/AbstractRemoveUnusedParametersAndValuesDiagnosticAnalyzer.SymbolStartAnalyzer.BlockAnalyzer.cs @@ -622,7 +622,7 @@ bool ShouldReportUnusedValueDiagnostic( if (_options.UnusedValueAssignmentSeverity == ReportDiagnostic.Suppress || symbol.GetSymbolType().IsErrorType() || (symbol.IsStatic && symbol.Kind == SymbolKind.Local) || - IsSymbolWithSpecialDiscardName(symbol)) + symbol.IsSymbolWithSpecialDiscardName()) { return false; } diff --git a/src/Analyzers/Core/Analyzers/RemoveUnusedParametersAndValues/AbstractRemoveUnusedParametersAndValuesDiagnosticAnalyzer.SymbolStartAnalyzer.cs b/src/Analyzers/Core/Analyzers/RemoveUnusedParametersAndValues/AbstractRemoveUnusedParametersAndValuesDiagnosticAnalyzer.SymbolStartAnalyzer.cs index 99905f446a1a8..486f1d1e1bee9 100644 --- a/src/Analyzers/Core/Analyzers/RemoveUnusedParametersAndValues/AbstractRemoveUnusedParametersAndValuesDiagnosticAnalyzer.SymbolStartAnalyzer.cs +++ b/src/Analyzers/Core/Analyzers/RemoveUnusedParametersAndValues/AbstractRemoveUnusedParametersAndValuesDiagnosticAnalyzer.SymbolStartAnalyzer.cs @@ -259,7 +259,7 @@ private bool IsUnusedParameterCandidate(IParameterSymbol parameter) // without disabling the diagnostic completely. // We ignore parameter names that start with an underscore and are optionally followed by an integer, // such as '_', '_1', '_2', etc. - if (IsSymbolWithSpecialDiscardName(parameter)) + if (parameter.IsSymbolWithSpecialDiscardName()) { return false; } diff --git a/src/Analyzers/Core/Analyzers/RemoveUnusedParametersAndValues/AbstractRemoveUnusedParametersAndValuesDiagnosticAnalyzer.cs b/src/Analyzers/Core/Analyzers/RemoveUnusedParametersAndValues/AbstractRemoveUnusedParametersAndValuesDiagnosticAnalyzer.cs index 1c8fe54d2bbe6..b29f07e285047 100644 --- a/src/Analyzers/Core/Analyzers/RemoveUnusedParametersAndValues/AbstractRemoveUnusedParametersAndValuesDiagnosticAnalyzer.cs +++ b/src/Analyzers/Core/Analyzers/RemoveUnusedParametersAndValues/AbstractRemoveUnusedParametersAndValuesDiagnosticAnalyzer.cs @@ -323,14 +323,5 @@ public static bool GetIsRemovableAssignmentDiagnostic(Diagnostic diagnostic) Debug.Assert(TryGetUnusedValuePreference(diagnostic, out _)); return diagnostic.Properties.ContainsKey(IsRemovableAssignmentKey); } - - /// - /// Returns true for symbols whose name starts with an underscore and - /// are optionally followed by an integer, such as '_', '_1', '_2', etc. - /// These are treated as special discard symbol names. - /// - private static bool IsSymbolWithSpecialDiscardName(ISymbol symbol) - => symbol.Name.StartsWith("_") && - (symbol.Name.Length == 1 || uint.TryParse(symbol.Name.Substring(1), out _)); } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ISymbolExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ISymbolExtensions.cs index 60efd1c5ea7cd..4ac7f6e976f24 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ISymbolExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ISymbolExtensions.cs @@ -740,5 +740,14 @@ public static bool IsKind(this ISymbol symbol, SymbolKind kind, [NotNul result = (TSymbol)symbol; return true; } + + /// + /// Returns true for symbols whose name starts with an underscore and + /// are optionally followed by an integer, such as '_', '_1', '_2', etc. + /// These are treated as special discard symbol names. + /// + public static bool IsSymbolWithSpecialDiscardName(this ISymbol symbol) + => symbol.Name.StartsWith("_") && + (symbol.Name.Length == 1 || uint.TryParse(symbol.Name.Substring(1), out _)); } }