Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug fixes and improvements for SA1313 #1443

Merged
merged 2 commits into from
Sep 10, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,118 @@ public override void Method(int Param1, int param2, int Other)
await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
}

/// <summary>
/// This is a regression test for DotNetAnalyzers/StyleCopAnalyzers#1442:
/// https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/1442
/// </summary>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
[Fact]
public async Task TestSimpleLambaExpressionAsync()
{
var testCode = @"public class TypeName
{
public void MethodName()
{
System.Action<int> action = Ignored => { };
}
}";

DiagnosticResult expected = this.CSharpDiagnostic().WithArguments("Ignored").WithLocation(5, 37);

await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
}

/// <summary>
/// This is a regression test for DotNetAnalyzers/StyleCopAnalyzers#1343:
/// https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/1343
/// </summary>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
[Fact]
public async Task TestLambdaParameterNamedUnderscoreAsync()
{
var testCode = @"public class TypeName
{
public void MethodName()
{
System.Action<int> action1 = _ => { };
System.Action<int> action2 = (_) => { };
System.Action<int> action3 = delegate(int _) { };
}
}";

await this.VerifyCSharpDiagnosticAsync(testCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
}

/// <summary>
/// This is a regression test for DotNetAnalyzers/StyleCopAnalyzers#1343:
/// https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/1343
/// </summary>
/// <remarks>
/// <para>This diagnostic does not check whether or not a parameter named <c>_</c> is being used.</para>
/// </remarks>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
[Fact]
public async Task TestLambdaParameterNamedUnderscoreUsageAsync()
{
var testCode = @"public class TypeName
{
public void MethodName()
{
System.Func<int, int> function1 = _ => _;
System.Func<int, int> function2 = (_) => _;
System.Func<int, int> function3 = delegate(int _) { return _; };
}
}";

await this.VerifyCSharpDiagnosticAsync(testCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
}

/// <summary>
/// This is a regression test for DotNetAnalyzers/StyleCopAnalyzers#1343:
/// https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/1343
/// </summary>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
[Fact]
public async Task TestLambdaParameterMultipleUnderscoresAsync()
{
var testCode = @"public class TypeName
{
public void MethodName()
{
System.Action<int> action1 = __ => { };
System.Action<int> action2 = (__) => { };
System.Action<int> action3 = delegate(int __) { };
}
}";

DiagnosticResult[] expected =
{
this.CSharpDiagnostic().WithArguments("__").WithLocation(5, 38),
this.CSharpDiagnostic().WithArguments("__").WithLocation(6, 39),
this.CSharpDiagnostic().WithArguments("__").WithLocation(7, 51)
};
await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
}

/// <summary>
/// This is a regression test for DotNetAnalyzers/StyleCopAnalyzers#1343:
/// https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/1343
/// </summary>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
[Fact]
public async Task TestMethodParameterNamedUnderscoreAsync()
{
var testCode = @"public class TypeName
{
public void MethodName(int _)
{
}
}";

DiagnosticResult expected = this.CSharpDiagnostic().WithArguments("_").WithLocation(3, 32);
await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
}

protected override IEnumerable<DiagnosticAnalyzer> GetCSharpDiagnosticAnalyzers()
{
yield return new SA1313ParameterNamesMustBeginWithLowerCaseLetter();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ namespace StyleCop.Analyzers.NamingRules
/// <remarks>
/// <para>A violation of this rule occurs when the name of a parameter does not begin with a lower-case letter.</para>
///
/// <para>An exception to this rule is made for lambda parameters named <c>_</c>. These parameters are often used to
/// designate a placeholder parameter which is not actually used in the body of the lambda expression.</para>
///
/// <para>If the parameter name is intended to match the name of an item associated with Win32 or COM, and thus
/// needs to begin with an upper-case letter, place the parameter within a special <c>NativeMethods</c> class. A
/// <c>NativeMethods</c> class is any class which contains a name ending in <c>NativeMethods</c>, and is intended as
Expand Down Expand Up @@ -80,6 +83,11 @@ private static void HandleParameterSyntax(SyntaxNodeAnalysisContext context)
return;
}

if (name == "_" && IsInLambda(syntax))
{
return;
}

if (NameMatchesAbstraction(syntax, context.SemanticModel))
{
return;
Expand All @@ -89,9 +97,31 @@ private static void HandleParameterSyntax(SyntaxNodeAnalysisContext context)
context.ReportDiagnostic(Diagnostic.Create(Descriptor, identifier.GetLocation(), name));
}

private static bool IsInLambda(ParameterSyntax syntax)
{
if (syntax.Parent.IsKind(SyntaxKind.SimpleLambdaExpression))
{
return true;
}

if (syntax.Parent.Parent.IsKind(SyntaxKind.ParenthesizedLambdaExpression)
|| syntax.Parent.Parent.IsKind(SyntaxKind.AnonymousMethodExpression))
{
return true;
}

return false;
}

private static bool NameMatchesAbstraction(ParameterSyntax syntax, SemanticModel semanticModel)
{
var parameterList = (ParameterListSyntax)syntax.Parent;
var parameterList = syntax.Parent as ParameterListSyntax;
if (parameterList == null)
{
// This occurs for simple lambda expressions (without parentheses)
return false;
}

var index = parameterList.Parameters.IndexOf(syntax);
var declaringMember = syntax.Parent.Parent;

Expand Down
3 changes: 3 additions & 0 deletions documentation/SA1313.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ The name of a parameter in C# does not begin with a lower-case letter.

A violation of this rule occurs when the name of a parameter does not begin with a lower-case letter.

An exception to this rule is made for lambda parameters named `_`. These parameters are often used to designate a
placeholder parameter which is not actually used in the body of the lambda expression.

If the parameter name is intended to match the name of an item associated with Win32 or COM, and thus needs to begin
with an upper-case letter, place the parameter within a special `NativeMethods` class. A `NativeMethods` class is any
class which contains a name ending in `NativeMethods`, and is intended as a placeholder for Win32 or COM wrappers.
Expand Down