Skip to content

Commit f1f2491

Browse files
authored
Merge pull request #2422 from sharwell/var-type
Fix analysis of spacing after 'var'
2 parents e809b29 + f3bf64e commit f1f2491

4 files changed

Lines changed: 132 additions & 1 deletion

File tree

StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp7/SpacingRules/SA1000CSharp7UnitTests.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,24 @@ public async Task TestOutVariableDeclarationAsync()
2525
await this.TestKeywordStatementAsync(statementWithoutSpace, expected, statementWithSpace).ConfigureAwait(false);
2626
}
2727

28+
[Fact]
29+
[WorkItem(2419, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/2419")]
30+
public async Task TestOutVarDiscardAsync()
31+
{
32+
string statementWithSpace = @"int.TryParse(""0"", out var _);";
33+
34+
await this.TestKeywordStatementAsync(statementWithSpace, EmptyDiagnosticResults, statementWithSpace).ConfigureAwait(false);
35+
}
36+
37+
[Fact]
38+
[WorkItem(2419, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/2419")]
39+
public async Task TestOutDiscardAsync()
40+
{
41+
string statementWithSpace = @"int.TryParse(""0"", out _);";
42+
43+
await this.TestKeywordStatementAsync(statementWithSpace, EmptyDiagnosticResults, statementWithSpace).ConfigureAwait(false);
44+
}
45+
2846
[Fact]
2947
public async Task TestVarKeywordTupleTypeAsync()
3048
{

StyleCop.Analyzers/StyleCop.Analyzers.Test/SpacingRules/SA1000UnitTests.cs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -646,6 +646,39 @@ public async Task TestNewImplicitArrayStatementAsync()
646646
await this.TestKeywordStatementAsync(statementWithSpace, EmptyDiagnosticResults, statementWithSpace).ConfigureAwait(false);
647647
}
648648

649+
[Fact]
650+
[WorkItem(2419, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/2419")]
651+
public async Task TestVarIdentifierAsync()
652+
{
653+
string statementWithoutSpace = @"int[] x = null; x.Select(var => var.ToString());";
654+
655+
string statementWithSpace = @"int[] x = null; x.Select(var => var .ToString());";
656+
657+
await this.TestKeywordStatementAsync(statementWithoutSpace, EmptyDiagnosticResults, statementWithoutSpace).ConfigureAwait(false);
658+
659+
// this case is handled by SA1019, so it shouldn't be reported here
660+
await this.TestKeywordStatementAsync(statementWithSpace, EmptyDiagnosticResults, statementWithSpace).ConfigureAwait(false);
661+
}
662+
663+
/// <summary>
664+
/// Verifies that calls on 'var' are handled properly.
665+
/// </summary>
666+
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
667+
/// <seealso cref="SA1008UnitTests.TestVarIdentifierInvocationAsync"/>
668+
[Fact]
669+
[WorkItem(2419, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/2419")]
670+
public async Task TestVarIdentifierInvocationAsync()
671+
{
672+
string statementWithoutSpace = @"Func<int>[] x = null; x.Select(var => var());";
673+
674+
string statementWithSpace = @"Func<int>[] x = null; x.Select(var => var ());";
675+
676+
await this.TestKeywordStatementAsync(statementWithoutSpace, EmptyDiagnosticResults, statementWithoutSpace).ConfigureAwait(false);
677+
678+
// this case is handled by SA1008, so it shouldn't be reported here
679+
await this.TestKeywordStatementAsync(statementWithSpace, EmptyDiagnosticResults, statementWithSpace).ConfigureAwait(false);
680+
}
681+
649682
[Fact]
650683
public async Task TestNewConstructorContraintStatement_TypeAsync()
651684
{

StyleCop.Analyzers/StyleCop.Analyzers.Test/SpacingRules/SA1008UnitTests.cs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2011,6 +2011,62 @@ public void Method()
20112011
await this.VerifyCSharpFixAsync(testCode, fixedCode).ConfigureAwait(false);
20122012
}
20132013

2014+
/// <summary>
2015+
/// Verifies that calls on 'var' are handled properly.
2016+
/// </summary>
2017+
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
2018+
/// <seealso cref="SA1000UnitTests.TestVarIdentifierInvocationAsync"/>
2019+
[Fact]
2020+
[WorkItem(2419, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/2419")]
2021+
public async Task TestVarIdentifierInvocationAsync()
2022+
{
2023+
var testCode = @"namespace TestNamespace
2024+
{
2025+
using System;
2026+
using System.Linq;
2027+
2028+
public class TestClass
2029+
{
2030+
public void TestMethod()
2031+
{
2032+
Func<int>[] x = null;
2033+
x.Select(var => var ( ));
2034+
x.Select(var => var ());
2035+
x.Select(var => var( ));
2036+
}
2037+
}
2038+
}";
2039+
2040+
var fixedTestCode = @"namespace TestNamespace
2041+
{
2042+
using System;
2043+
using System.Linq;
2044+
2045+
public class TestClass
2046+
{
2047+
public void TestMethod()
2048+
{
2049+
Func<int>[] x = null;
2050+
x.Select(var => var());
2051+
x.Select(var => var());
2052+
x.Select(var => var());
2053+
}
2054+
}
2055+
}";
2056+
2057+
DiagnosticResult[] expectedDiagnostics =
2058+
{
2059+
this.CSharpDiagnostic(DescriptorNotPreceded).WithLocation(11, 33),
2060+
this.CSharpDiagnostic(DescriptorNotFollowed).WithLocation(11, 33),
2061+
this.CSharpDiagnostic(DescriptorNotPreceded).WithLocation(12, 33),
2062+
this.CSharpDiagnostic(DescriptorNotFollowed).WithLocation(13, 32),
2063+
};
2064+
2065+
await this.VerifyCSharpDiagnosticAsync(testCode, expectedDiagnostics, CancellationToken.None).ConfigureAwait(false);
2066+
await this.VerifyCSharpDiagnosticAsync(fixedTestCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
2067+
await this.VerifyCSharpFixAsync(testCode, fixedTestCode).ConfigureAwait(false);
2068+
}
2069+
20142070
[Fact]
20152071
public async Task TestMissingTokenAsync()
20162072
{

StyleCop.Analyzers/StyleCop.Analyzers/SpacingRules/SA1000KeywordsMustBeSpacedCorrectly.cs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,9 +187,33 @@ private static void HandleInvocationExpression(SyntaxNodeAnalysisContext context
187187

188188
private static void HandleIdentifierName(SyntaxNodeAnalysisContext context)
189189
{
190-
IdentifierNameSyntax identifierNameSyntax = (IdentifierNameSyntax)context.Node;
190+
var identifierNameSyntax = (IdentifierNameSyntax)context.Node;
191191
if (identifierNameSyntax.IsVar)
192192
{
193+
var nextToken = identifierNameSyntax.Identifier.GetNextToken();
194+
switch (nextToken.Kind())
195+
{
196+
case SyntaxKind.IdentifierToken:
197+
case SyntaxKindEx.UnderscoreToken:
198+
// Always check these
199+
break;
200+
201+
case SyntaxKind.OpenParenToken:
202+
if (nextToken.Parent.IsKind(SyntaxKindEx.ParenthesizedVariableDesignation))
203+
{
204+
// We have something like this:
205+
// var (x, i) = (a, b);
206+
break;
207+
}
208+
209+
// Could be calling a function named 'var'
210+
return;
211+
212+
default:
213+
// Not something to check
214+
return;
215+
}
216+
193217
HandleRequiredSpaceToken(ref context, identifierNameSyntax.Identifier);
194218
}
195219
}

0 commit comments

Comments
 (0)