Skip to content

Commit

Permalink
Merge pull request #2905 from vweijsters/fix-2902
Browse files Browse the repository at this point in the history
Fixed SA1130 code fix for return statements and arrow expression clauses
  • Loading branch information
sharwell authored Mar 1, 2019
2 parents cbec141 + ffe11e1 commit 1204911
Show file tree
Hide file tree
Showing 3 changed files with 193 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ private static SyntaxNode ReplaceWithLambda(SemanticModel semanticModel, Anonymo
{
var parameterList = anonymousMethod.ParameterList;
SyntaxNode lambdaExpression;
SyntaxToken arrowToken;

if (parameterList == null)
{
Expand All @@ -98,6 +99,16 @@ private static SyntaxNode ReplaceWithLambda(SemanticModel semanticModel, Anonymo

argumentList = list.Value;
break;

case SyntaxKind.ArrowExpressionClause:
case SyntaxKind.ReturnStatement:
argumentList = GetMemberReturnTypeArgumentList(semanticModel, anonymousMethod);
if (argumentList.IsEmpty)
{
return null;
}

break;
}

List<ParameterSyntax> parameters = GenerateUniqueParameterNames(semanticModel, anonymousMethod, argumentList);
Expand All @@ -107,12 +118,17 @@ private static SyntaxNode ReplaceWithLambda(SemanticModel semanticModel, Anonymo
: SyntaxFactory.SeparatedList<ParameterSyntax>();

parameterList = SyntaxFactory.ParameterList(newList)
.WithLeadingTrivia(anonymousMethod.DelegateKeyword.LeadingTrivia)
.WithLeadingTrivia(anonymousMethod.DelegateKeyword.LeadingTrivia);

arrowToken = SyntaxFactory.Token(SyntaxKind.EqualsGreaterThanToken)
.WithTrailingTrivia(anonymousMethod.DelegateKeyword.TrailingTrivia);
}
else
{
parameterList = parameterList.WithLeadingTrivia(anonymousMethod.DelegateKeyword.TrailingTrivia);

arrowToken = SyntaxFactory.Token(SyntaxKind.EqualsGreaterThanToken)
.WithTrailingTrivia(SyntaxFactory.ElasticSpace);
}

foreach (var parameter in parameterList.Parameters)
Expand All @@ -123,9 +139,6 @@ private static SyntaxNode ReplaceWithLambda(SemanticModel semanticModel, Anonymo
}
}

var arrowToken = SyntaxFactory.Token(SyntaxKind.EqualsGreaterThanToken)
.WithTrailingTrivia(SyntaxFactory.ElasticSpace);

if (parameterList.Parameters.Count == 1)
{
var parameterSyntax = RemoveType(parameterList.Parameters[0]);
Expand Down Expand Up @@ -193,6 +206,13 @@ private static ImmutableArray<string> GetEqualsArgumentList(SemanticModel semant
return namedTypeSymbol.DelegateInvokeMethod.Parameters.Select(ps => ps.Name).ToImmutableArray();
}

private static ImmutableArray<string> GetMemberReturnTypeArgumentList(SemanticModel semanticModel, AnonymousMethodExpressionSyntax anonymousMethod)
{
var enclosingSymbol = semanticModel.GetEnclosingSymbol(anonymousMethod.Parent.SpanStart);
var returnType = ((IMethodSymbol)enclosingSymbol).ReturnType as INamedTypeSymbol;
return (returnType == null) ? ImmutableArray<string>.Empty : returnType.DelegateInvokeMethod.Parameters.Select(ps => ps.Name).ToImmutableArray();
}

private static List<ParameterSyntax> GenerateUniqueParameterNames(SemanticModel semanticModel, AnonymousMethodExpressionSyntax anonymousMethod, ImmutableArray<string> argumentNames)
{
var parameters = new List<ParameterSyntax>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,47 @@

namespace StyleCop.Analyzers.Test.CSharp7.ReadabilityRules
{
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Testing;
using StyleCop.Analyzers.Test.ReadabilityRules;
using Xunit;
using static StyleCop.Analyzers.Test.Verifiers.StyleCopCodeFixVerifier<
StyleCop.Analyzers.ReadabilityRules.SA1130UseLambdaSyntax,
StyleCop.Analyzers.ReadabilityRules.SA1130CodeFixProvider>;

public class SA1130CSharp7UnitTests : SA1130UnitTests
{
[Fact]
[WorkItem(2902, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/2902")]
public async Task VerifyLocalFunctionAsync()
{
var testCode = @"using System;
public class TestClass
{
public void TestMethod()
{
EventHandler LocalTestFunction() => delegate { };
}
}
";

var fixedCode = @"using System;
public class TestClass
{
public void TestMethod()
{
EventHandler LocalTestFunction() => (sender, e) => { };
}
}
";

DiagnosticResult[] expected =
{
Diagnostic().WithLocation(6, 45),
};

await VerifyCSharpFixAsync(testCode, expected, fixedCode, CancellationToken.None).ConfigureAwait(false);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ public class TypeName
{
public void Test()
{
Action action1 = /*a*/()/*b*/ => { };
Action action1 = /*a*/() =>/*b*/{ };
Action action2 = /*a*//*b*/(/*c*/)/*d*/ => { };
Action<int> action3 = /*a*//*b*//*c*//*d*/i/*e*//*f*/ => { };
Action<List<int>> action4 = i => { };
Expand Down Expand Up @@ -710,5 +710,135 @@ static void Main(string[] args)

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

[Fact]
[WorkItem(2902, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/2902")]
public async Task VerifyThatCodeFixDoesNotCrashOnDelegateReturnAsync()
{
var testCode = @"using System;
public class TestClass
{
public static EventHandler TestMethod1()
{
return delegate
{
};
}
public static EventHandler TestMethod2() => delegate
{
};
public static EventHandler TestProperty1
{
get
{
return delegate
{
};
}
}
public static EventHandler TestProperty2 => delegate
{
};
}";

var fixedCode = @"using System;
public class TestClass
{
public static EventHandler TestMethod1()
{
return (sender, e) =>
{
};
}
public static EventHandler TestMethod2() => (sender, e) =>
{
};
public static EventHandler TestProperty1
{
get
{
return (sender, e) =>
{
};
}
}
public static EventHandler TestProperty2 => (sender, e) =>
{
};
}";

DiagnosticResult[] expected =
{
Diagnostic().WithLocation(6, 16),
Diagnostic().WithLocation(11, 49),
Diagnostic().WithLocation(19, 20),
Diagnostic().WithLocation(25, 49),
};

await VerifyCSharpFixAsync(testCode, expected, fixedCode, CancellationToken.None).ConfigureAwait(false);
}

[Fact]
[WorkItem(2902, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/2902")]
public async Task VerifyThatEventInitializersWorkAsExpectedAsync()
{
var testCode = @"using System;
public class TestClass
{
public static event EventHandler StaticEvent = delegate { };
public event EventHandler InstanceEvent = delegate { };
}
";

var fixedCode = @"using System;
public class TestClass
{
public static event EventHandler StaticEvent = (sender, e) => { };
public event EventHandler InstanceEvent = (sender, e) => { };
}
";

DiagnosticResult[] expected =
{
Diagnostic().WithLocation(4, 52),
Diagnostic().WithLocation(5, 47),
};

await VerifyCSharpFixAsync(testCode, expected, fixedCode, CancellationToken.None).ConfigureAwait(false);
}

[Fact]
[WorkItem(2902, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/2902")]
public async Task VerifyInvalidCodeConstructionsAsync()
{
var testCode = @"using System;
public class TestClass
{
public static EventHandler[] TestMethod() => delegate { };
}
";

DiagnosticResult[] expected =
{
Diagnostic().WithSpan(4, 50, 4, 58),
DiagnosticResult.CompilerError("CS1660").WithMessage("Cannot convert anonymous method to type 'EventHandler[]' because it is not a delegate type").WithSpan(4, 50, 4, 62),
};

var test = new CSharpTest
{
TestCode = testCode,
FixedCode = testCode,
};

test.ExpectedDiagnostics.AddRange(expected);
test.RemainingDiagnostics.AddRange(expected);
await test.RunAsync(CancellationToken.None).ConfigureAwait(false);
}
}
}

0 comments on commit 1204911

Please sign in to comment.