Skip to content

Commit

Permalink
Merge pull request #3625 from bjornhellander/feature/sa1015-explicit-…
Browse files Browse the repository at this point in the history
…generic-lambda-return-type

Update SA1015 to require trailing space after an explicit generic return type in a lambda expression
  • Loading branch information
sharwell authored Apr 1, 2023
2 parents 84e2324 + d932ea1 commit ef1f91c
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,42 @@

namespace StyleCop.Analyzers.Test.CSharp10.SpacingRules
{
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Testing;
using StyleCop.Analyzers.Test.CSharp9.SpacingRules;
using Xunit;
using static StyleCop.Analyzers.Test.Verifiers.StyleCopCodeFixVerifier<
StyleCop.Analyzers.SpacingRules.SA1015ClosingGenericBracketsMustBeSpacedCorrectly,
StyleCop.Analyzers.SpacingRules.TokenSpacingCodeFixProvider>;

public class SA1015CSharp10UnitTests : SA1015CSharp9UnitTests
{
[Fact]
[WorkItem(3624, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3624")]
public async Task TestLambdaWithExplicitGenericReturnTypeAsync()
{
const string testCode = @"using System.Threading.Tasks;
public class TestClass
{
public void TestMethod()
{
var _ = Task<int[|>|](int x) => Task.FromResult(x);
}
}";

const string fixedCode = @"using System.Threading.Tasks;
public class TestClass
{
public void TestMethod()
{
var _ = Task<int> (int x) => Task.FromResult(x);
}
}";

await VerifyCSharpFixAsync(testCode, DiagnosticResult.EmptyDiagnosticResults, fixedCode, CancellationToken.None).ConfigureAwait(false);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,6 @@ private static void HandleGreaterThanToken(SyntaxTreeAnalysisContext context, Sy
SyntaxToken nextToken = token.GetNextToken();
switch (nextToken.Kind())
{
case SyntaxKind.OpenParenToken:
// DotToken isn't listed above, but it's required for reasonable member access formatting
case SyntaxKind.DotToken:
// CommaToken isn't listed above, but it's required for reasonable nested generic type arguments formatting
Expand All @@ -122,6 +121,10 @@ private static void HandleGreaterThanToken(SyntaxTreeAnalysisContext context, Sy
allowTrailingSpace = false;
break;

case SyntaxKind.OpenParenToken:
AnalyzeWithTrailingOpenParen(nextToken, out allowTrailingNoSpace, out allowTrailingSpace);
break;

case SyntaxKind.CloseParenToken:
case SyntaxKind.GreaterThanToken:
allowTrailingNoSpace = true;
Expand Down Expand Up @@ -187,5 +190,33 @@ private static void HandleGreaterThanToken(SyntaxTreeAnalysisContext context, Sy
}
}
}

private static void AnalyzeWithTrailingOpenParen(
SyntaxToken nextToken,
out bool allowTrailingNoSpace,
out bool allowTrailingSpace)
{
switch (nextToken.Parent.Kind())
{
// List<int> (int x) => new List<int> { x }
// ^ ^
case SyntaxKind.ParameterList when nextToken.Parent.Parent.IsKind(SyntaxKind.ParenthesizedLambdaExpression):
allowTrailingNoSpace = false;
allowTrailingSpace = true;
break;

// NOTE: Intentionally keeping redundant cases here as documentation of what is known to occur
// M<int>()
// ^^
case SyntaxKind.ArgumentList:
// void M<T>(T x) { }
// ^^
case SyntaxKind.ParameterList when nextToken.Parent.Parent.IsKind(SyntaxKind.MethodDeclaration):
default:
allowTrailingNoSpace = true;
allowTrailingSpace = false;
break;
}
}
}
}

0 comments on commit ef1f91c

Please sign in to comment.