Skip to content

Commit 3f098f5

Browse files
authored
Merge pull request #2389 from sharwell/csharp7-spacing
Update spacing rules for C# 7
2 parents 26858c3 + 187bcc8 commit 3f098f5

43 files changed

Lines changed: 2692 additions & 87 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
2+
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
3+
4+
namespace StyleCop.Analyzers.Test.CSharp7.SpacingRules
5+
{
6+
using System.Threading;
7+
using System.Threading.Tasks;
8+
using StyleCop.Analyzers.Test.SpacingRules;
9+
using TestHelper;
10+
using Xunit;
11+
12+
public class SA1000CSharp7UnitTests : SA1000UnitTests
13+
{
14+
[Fact]
15+
public async Task TestOutVariableDeclarationAsync()
16+
{
17+
string statementWithoutSpace = @"int.TryParse(""0"", out@Int32 x);";
18+
19+
string statementWithSpace = @"int.TryParse(""0"", out @Int32 x);";
20+
21+
await this.TestKeywordStatementAsync(statementWithSpace, EmptyDiagnosticResults, statementWithSpace).ConfigureAwait(false);
22+
23+
DiagnosticResult expected = this.CSharpDiagnostic().WithArguments("out", string.Empty, "followed").WithLocation(12, 31);
24+
25+
await this.TestKeywordStatementAsync(statementWithoutSpace, expected, statementWithSpace).ConfigureAwait(false);
26+
}
27+
28+
[Fact]
29+
public async Task TestVarKeywordTupleTypeAsync()
30+
{
31+
string statementWithoutSpace = @"var(a, b) = (2, 3);";
32+
33+
string statementWithSpace = @"var (a, b) = (2, 3);";
34+
35+
await this.TestKeywordStatementAsync(statementWithSpace, EmptyDiagnosticResults, statementWithSpace).ConfigureAwait(false);
36+
37+
DiagnosticResult expected = this.CSharpDiagnostic().WithArguments("var", string.Empty, "followed").WithLocation(12, 13);
38+
39+
await this.TestKeywordStatementAsync(statementWithoutSpace, expected, statementWithSpace).ConfigureAwait(false);
40+
}
41+
42+
[Fact]
43+
public async Task TestRefExpressionAndTypeAsync()
44+
{
45+
string statementWithoutSpace = @"
46+
int a = 0;
47+
ref@Int32 b = ref@Call(ref@a);
48+
49+
ref@Int32 Call(ref@Int32 p)
50+
=> ref@p;
51+
";
52+
53+
string statementWithSpace = @"
54+
int a = 0;
55+
ref @Int32 b = ref @Call(ref @a);
56+
57+
ref @Int32 Call(ref @Int32 p)
58+
=> ref @p;
59+
";
60+
61+
await this.TestKeywordStatementAsync(statementWithSpace, EmptyDiagnosticResults, statementWithSpace).ConfigureAwait(false);
62+
63+
DiagnosticResult[] expected =
64+
{
65+
this.CSharpDiagnostic().WithArguments("ref", string.Empty, "followed").WithLocation(14, 1),
66+
this.CSharpDiagnostic().WithArguments("ref", string.Empty, "followed").WithLocation(14, 15),
67+
this.CSharpDiagnostic().WithArguments("ref", string.Empty, "followed").WithLocation(14, 24),
68+
this.CSharpDiagnostic().WithArguments("ref", string.Empty, "followed").WithLocation(16, 1),
69+
this.CSharpDiagnostic().WithArguments("ref", string.Empty, "followed").WithLocation(16, 16),
70+
this.CSharpDiagnostic().WithArguments("ref", string.Empty, "followed").WithLocation(17, 8),
71+
};
72+
73+
await this.TestKeywordStatementAsync(statementWithoutSpace, expected, statementWithSpace).ConfigureAwait(false);
74+
}
75+
76+
/// <summary>
77+
/// Verifies that spacing for tuple expressions is handled properly.
78+
/// </summary>
79+
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
80+
/// <seealso cref="SA1008CSharp7UnitTests.TestTupleExpressionsAsync"/>
81+
[Fact]
82+
public async Task TestReturnTupleExpressionsAsync()
83+
{
84+
var testCode = @"using System.Collections.Generic;
85+
86+
namespace TestNamespace
87+
{
88+
public class TestClass
89+
{
90+
public void TestMethod()
91+
{
92+
// Returns (leading spaces after keyword checked in SA1000, not SA1008)
93+
(int, int) LocalFunction1() { return( 1, 2); }
94+
(int, int) LocalFunction2() { return(1, 2); }
95+
(int, int) LocalFunction3() { return ( 1, 2); }
96+
}
97+
}
98+
}
99+
";
100+
101+
var fixedCode = @"using System.Collections.Generic;
102+
103+
namespace TestNamespace
104+
{
105+
public class TestClass
106+
{
107+
public void TestMethod()
108+
{
109+
// Returns (leading spaces after keyword checked in SA1000, not SA1008)
110+
(int, int) LocalFunction1() { return ( 1, 2); }
111+
(int, int) LocalFunction2() { return (1, 2); }
112+
(int, int) LocalFunction3() { return ( 1, 2); }
113+
}
114+
}
115+
}
116+
";
117+
118+
DiagnosticResult[] expectedDiagnostics =
119+
{
120+
// Returns
121+
this.CSharpDiagnostic().WithArguments("return", string.Empty, "followed").WithLocation(10, 43),
122+
this.CSharpDiagnostic().WithArguments("return", string.Empty, "followed").WithLocation(11, 43),
123+
};
124+
125+
await this.VerifyCSharpDiagnosticAsync(testCode, expectedDiagnostics, CancellationToken.None).ConfigureAwait(false);
126+
await this.VerifyCSharpDiagnosticAsync(fixedCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
127+
await this.VerifyCSharpFixAsync(testCode, fixedCode).ConfigureAwait(false);
128+
}
129+
}
130+
}
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
2+
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
3+
4+
namespace StyleCop.Analyzers.Test.CSharp7.SpacingRules
5+
{
6+
using System.Threading;
7+
using System.Threading.Tasks;
8+
using StyleCop.Analyzers.Test.SpacingRules;
9+
using TestHelper;
10+
using Xunit;
11+
12+
public class SA1001CSharp7UnitTests : SA1001UnitTests
13+
{
14+
/// <summary>
15+
/// Verifies spacing around a <c>]</c> character in tuple types and expressions.
16+
/// </summary>
17+
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
18+
/// <seealso cref="SA1009CSharp7UnitTests.TestBracketsInTupleTypesNotFollowedBySpaceAsync"/>
19+
/// <seealso cref="SA1011CSharp7UnitTests.TestBracketsInTupleTypesNotFollowedBySpaceAsync"/>
20+
[Fact]
21+
public async Task TestBracketsInTupleTypesNotFollowedBySpaceAsync()
22+
{
23+
const string testCode = @"using System;
24+
25+
public class Foo
26+
{
27+
public (int[] , int[] ) TestMethod((int[] , int[] ) a)
28+
{
29+
(int[] , int[] ) ints = (new int[][] { new[] { 3 } }[0] , new int[][] { new[] { 3 } }[0] );
30+
return ints;
31+
}
32+
}";
33+
const string fixedCode = @"using System;
34+
35+
public class Foo
36+
{
37+
public (int[], int[] ) TestMethod((int[], int[] ) a)
38+
{
39+
(int[], int[] ) ints = (new int[][] { new[] { 3 } }[0], new int[][] { new[] { 3 } }[0] );
40+
return ints;
41+
}
42+
}";
43+
44+
DiagnosticResult[] expected =
45+
{
46+
this.CSharpDiagnostic().WithLocation(5, 19).WithArguments(" not", "preceded"),
47+
this.CSharpDiagnostic().WithLocation(5, 47).WithArguments(" not", "preceded"),
48+
this.CSharpDiagnostic().WithLocation(7, 16).WithArguments(" not", "preceded"),
49+
this.CSharpDiagnostic().WithLocation(7, 65).WithArguments(" not", "preceded"),
50+
};
51+
52+
await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
53+
await this.VerifyCSharpDiagnosticAsync(fixedCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
54+
await this.VerifyCSharpFixAsync(testCode, fixedCode, cancellationToken: CancellationToken.None).ConfigureAwait(false);
55+
}
56+
57+
/// <summary>
58+
/// Verifies spacing around a <c>}</c> character in tuple expressions.
59+
/// </summary>
60+
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
61+
/// <seealso cref="SA1009CSharp7UnitTests.TestSpacingAroundClosingBraceInTupleExpressionsAsync"/>
62+
/// <seealso cref="SA1013CSharp7UnitTests.TestSpacingAroundClosingBraceInTupleExpressionsAsync"/>
63+
[Fact]
64+
public async Task TestSpacingAroundClosingBraceInTupleExpressionsAsync()
65+
{
66+
const string testCode = @"using System;
67+
68+
public class Foo
69+
{
70+
public void TestMethod()
71+
{
72+
var values = (new[] { 3} , new[] { 3} );
73+
}
74+
}";
75+
const string fixedCode = @"using System;
76+
77+
public class Foo
78+
{
79+
public void TestMethod()
80+
{
81+
var values = (new[] { 3}, new[] { 3} );
82+
}
83+
}";
84+
85+
DiagnosticResult expected = this.CSharpDiagnostic().WithLocation(7, 34).WithArguments(" not", "preceded");
86+
87+
await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
88+
await this.VerifyCSharpDiagnosticAsync(fixedCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
89+
await this.VerifyCSharpFixAsync(testCode, fixedCode, cancellationToken: CancellationToken.None).ConfigureAwait(false);
90+
}
91+
92+
/// <summary>
93+
/// Verifies spacing around a <c>&gt;</c> character in tuple types.
94+
/// </summary>
95+
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
96+
/// <seealso cref="SA1009CSharp7UnitTests.TestClosingGenericBracketsInTupleTypesNotFollowedBySpaceAsync"/>
97+
/// <seealso cref="SA1015CSharp7UnitTests.TestClosingGenericBracketsInTupleTypesNotPrecededBySpaceAsync"/>
98+
[Fact]
99+
public async Task TestClosingGenericBracketsInTupleTypesNotFollowedBySpaceAsync()
100+
{
101+
const string testCode = @"using System;
102+
103+
public class Foo
104+
{
105+
public void TestMethod()
106+
{
107+
(Func<int > , Func<int > ) value = (null, null);
108+
}
109+
}";
110+
const string fixedCode = @"using System;
111+
112+
public class Foo
113+
{
114+
public void TestMethod()
115+
{
116+
(Func<int >, Func<int > ) value = (null, null);
117+
}
118+
}";
119+
120+
DiagnosticResult expected = this.CSharpDiagnostic().WithLocation(7, 21).WithArguments(" not", "preceded");
121+
122+
await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
123+
await this.VerifyCSharpDiagnosticAsync(fixedCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
124+
await this.VerifyCSharpFixAsync(testCode, fixedCode, cancellationToken: CancellationToken.None).ConfigureAwait(false);
125+
}
126+
}
127+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
2+
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
3+
4+
namespace StyleCop.Analyzers.Test.CSharp7.SpacingRules
5+
{
6+
using Test.SpacingRules;
7+
8+
public class SA1002CSharp7UnitTests : SA1002UnitTests
9+
{
10+
}
11+
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
2+
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
3+
4+
namespace StyleCop.Analyzers.Test.CSharp7.SpacingRules
5+
{
6+
using System.Threading;
7+
using System.Threading.Tasks;
8+
using Test.SpacingRules;
9+
using TestHelper;
10+
using Xunit;
11+
12+
using static StyleCop.Analyzers.SpacingRules.SA1003SymbolsMustBeSpacedCorrectly;
13+
14+
public class SA1003CSharp7UnitTests : SA1003UnitTests
15+
{
16+
/// <summary>
17+
/// Verifies that the additional expression-bodied members supported in C# 7 trigger diagnostics as expected.
18+
/// </summary>
19+
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
20+
[Fact]
21+
public async Task TestCSharp7ExpressionBodiedMembersAsync()
22+
{
23+
var testCode = @"using System;
24+
namespace N1
25+
{
26+
public class C1
27+
{
28+
private int x;
29+
private EventHandler e;
30+
31+
public C1()=>x = 1; // Constructors
32+
~C1()=>x = 0; // Finalizers
33+
public event EventHandler E { add=>e += value; remove=>e -= value; } // Event accessors
34+
public int Answer { get=>42; set=>x = 2; } // Property accessors
35+
public int this[int index] { get=>42; set=>x = value; } // Indexer accessors
36+
public void Method()
37+
{
38+
int LocalFunction()=>42; // Local functions
39+
}
40+
}
41+
}
42+
";
43+
var fixedTestCode = @"using System;
44+
namespace N1
45+
{
46+
public class C1
47+
{
48+
private int x;
49+
private EventHandler e;
50+
51+
public C1() => x = 1; // Constructors
52+
~C1() => x = 0; // Finalizers
53+
public event EventHandler E { add => e += value; remove => e -= value; } // Event accessors
54+
public int Answer { get => 42; set => x = 2; } // Property accessors
55+
public int this[int index] { get => 42; set => x = value; } // Indexer accessors
56+
public void Method()
57+
{
58+
int LocalFunction() => 42; // Local functions
59+
}
60+
}
61+
}
62+
";
63+
DiagnosticResult[] expected =
64+
{
65+
this.CSharpDiagnostic(DescriptorPrecededByWhitespace).WithLocation(9, 20).WithArguments("=>"),
66+
this.CSharpDiagnostic(DescriptorFollowedByWhitespace).WithLocation(9, 20).WithArguments("=>"),
67+
68+
this.CSharpDiagnostic(DescriptorPrecededByWhitespace).WithLocation(10, 14).WithArguments("=>"),
69+
this.CSharpDiagnostic(DescriptorFollowedByWhitespace).WithLocation(10, 14).WithArguments("=>"),
70+
71+
this.CSharpDiagnostic(DescriptorPrecededByWhitespace).WithLocation(11, 42).WithArguments("=>"),
72+
this.CSharpDiagnostic(DescriptorFollowedByWhitespace).WithLocation(11, 42).WithArguments("=>"),
73+
this.CSharpDiagnostic(DescriptorPrecededByWhitespace).WithLocation(11, 62).WithArguments("=>"),
74+
this.CSharpDiagnostic(DescriptorFollowedByWhitespace).WithLocation(11, 62).WithArguments("=>"),
75+
76+
this.CSharpDiagnostic(DescriptorPrecededByWhitespace).WithLocation(12, 32).WithArguments("=>"),
77+
this.CSharpDiagnostic(DescriptorFollowedByWhitespace).WithLocation(12, 32).WithArguments("=>"),
78+
this.CSharpDiagnostic(DescriptorPrecededByWhitespace).WithLocation(12, 41).WithArguments("=>"),
79+
this.CSharpDiagnostic(DescriptorFollowedByWhitespace).WithLocation(12, 41).WithArguments("=>"),
80+
81+
this.CSharpDiagnostic(DescriptorPrecededByWhitespace).WithLocation(13, 41).WithArguments("=>"),
82+
this.CSharpDiagnostic(DescriptorFollowedByWhitespace).WithLocation(13, 41).WithArguments("=>"),
83+
this.CSharpDiagnostic(DescriptorPrecededByWhitespace).WithLocation(13, 50).WithArguments("=>"),
84+
this.CSharpDiagnostic(DescriptorFollowedByWhitespace).WithLocation(13, 50).WithArguments("=>"),
85+
86+
this.CSharpDiagnostic(DescriptorPrecededByWhitespace).WithLocation(16, 32).WithArguments("=>"),
87+
this.CSharpDiagnostic(DescriptorFollowedByWhitespace).WithLocation(16, 32).WithArguments("=>"),
88+
};
89+
90+
await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
91+
await this.VerifyCSharpFixAsync(testCode, fixedTestCode).ConfigureAwait(false);
92+
}
93+
}
94+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
2+
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
3+
4+
namespace StyleCop.Analyzers.Test.CSharp7.SpacingRules
5+
{
6+
using Test.SpacingRules;
7+
8+
public class SA1004CSharp7UnitTests : SA1004UnitTests
9+
{
10+
}
11+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
2+
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
3+
4+
namespace StyleCop.Analyzers.Test.CSharp7.SpacingRules
5+
{
6+
using Test.SpacingRules;
7+
8+
public class SA1005CSharp7UnitTests : SA1005UnitTests
9+
{
10+
}
11+
}

0 commit comments

Comments
 (0)