Skip to content

Commit b60f574

Browse files
committed
Implemented SA1117 diagnostic + unit tests
1 parent 6875128 commit b60f574

5 files changed

Lines changed: 542 additions & 9 deletions

File tree

Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
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.ReadabilityRules
5+
{
6+
using System.Collections.Generic;
7+
using System.Threading;
8+
using System.Threading.Tasks;
9+
using Microsoft.CodeAnalysis.Diagnostics;
10+
using StyleCop.Analyzers.ReadabilityRules;
11+
using TestHelper;
12+
using Xunit;
13+
14+
public class SA1117UnitTests : DiagnosticVerifier
15+
{
16+
public static IEnumerable<object[]> GetTestDeclarations(string delimiter)
17+
{
18+
yield return new object[] { $"public Foo(int a, int b,{delimiter} string s) {{ }}" };
19+
yield return new object[] { $"public object Bar(int a, int b,{delimiter} string s) => null;" };
20+
yield return new object[] { $"public object this[int a, int b,{delimiter} string s] => null;" };
21+
yield return new object[] { $"public delegate void Bar(int a, int b,{delimiter} string s);" };
22+
}
23+
24+
public static IEnumerable<object[]> GetTestConstructorInitializers(string delimiter)
25+
{
26+
yield return new object[] { $"this(42, 43, {delimiter} \"hello\")" };
27+
yield return new object[] { $"base(42, 43, {delimiter} \"hello\")" };
28+
}
29+
30+
public static IEnumerable<object[]> GetTestExpressions(string delimiter)
31+
{
32+
yield return new object[] { $"Bar(1, 2, {delimiter} 2)", 13 };
33+
yield return new object[] { $"System.Action<int, int, int> func = (int x, int y, {delimiter} int z) => Bar(x, y, z)", 41 };
34+
yield return new object[] { $"System.Action<int, int, int> func = delegate(int x, int y, {delimiter} int z) {{ Bar(x, y, z); }}", 49 };
35+
yield return new object[] { $"new System.DateTime(2015, 9, {delimiter} 14)", 20 };
36+
yield return new object[] { $"var arr = new string[2, 2, {delimiter} 2];", 30 };
37+
yield return new object[] { $"char cc = (new char[3, 3, 3])[2, 2,{delimiter} 2];", 36 };
38+
yield return new object[] { $"char? c = (new char[3, 3, 3])?[2, 2,{delimiter} 2];", 37 };
39+
yield return new object[] { $"long ll = this[2, 2,{delimiter} 2];", 24 };
40+
}
41+
42+
public static IEnumerable<object[]> ValidTestExpressions()
43+
{
44+
yield return new object[] { $"System.Action func = () => Bar(0, 2, 3)", 0 };
45+
yield return new object[] { $"System.Action<int> func = x => Bar(x, 2, 3)", 0 };
46+
yield return new object[] { $"System.Action func = delegate {{ Bar(0, 0, 0); }}", 0 };
47+
}
48+
49+
[Theory]
50+
[MemberData(nameof(GetTestDeclarations), "")]
51+
public async Task TestValidDeclarationAsync(string declaration)
52+
{
53+
var testCode = $@"
54+
class Foo
55+
{{
56+
{declaration}
57+
}}";
58+
await this.VerifyCSharpDiagnosticAsync(testCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
59+
}
60+
61+
[Theory]
62+
[MemberData(nameof(GetTestDeclarations), "\r\n")]
63+
public async Task TestInvalidDeclarationAsync(string declaration)
64+
{
65+
var testCode = $@"
66+
class Foo
67+
{{
68+
{declaration}
69+
}}";
70+
71+
DiagnosticResult expected = this.CSharpDiagnostic().WithLocation(5, 2);
72+
await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
73+
}
74+
75+
[Theory]
76+
[MemberData(nameof(GetTestConstructorInitializers), "")]
77+
public async Task TestValidConstructorInitializerAsync(string initializer)
78+
{
79+
var testCode = $@"
80+
class Base
81+
{{
82+
public Base(int a, int b, string s)
83+
{{
84+
}}
85+
}}
86+
87+
class Derived : Base
88+
{{
89+
public Derived()
90+
: {initializer}
91+
{{
92+
}}
93+
94+
public Derived(int i, int j, string z)
95+
: base(i, j, z)
96+
{{
97+
}}
98+
}}";
99+
100+
await this.VerifyCSharpDiagnosticAsync(testCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
101+
}
102+
103+
[Theory]
104+
[MemberData(nameof(GetTestConstructorInitializers), "\r\n")]
105+
public async Task TestInvalidConstructorInitializerAsync(string initializer)
106+
{
107+
var testCode = $@"
108+
class Base
109+
{{
110+
public Base(int a, int b, string s)
111+
{{
112+
}}
113+
}}
114+
115+
class Derived : Base
116+
{{
117+
public Derived()
118+
: {initializer}
119+
{{
120+
}}
121+
122+
public Derived(int i, int j, string z)
123+
: base(i, j, z)
124+
{{
125+
}}
126+
}}";
127+
128+
DiagnosticResult expected = this.CSharpDiagnostic().WithLocation(13, 2);
129+
await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
130+
}
131+
132+
[Theory]
133+
[MemberData(nameof(GetTestExpressions), "")]
134+
[MemberData(nameof(ValidTestExpressions))]
135+
public async Task TestValidExpressionAsync(string expression, int column)
136+
{
137+
var testCode = $@"
138+
class Foo
139+
{{
140+
public void Bar(int i, int j, int k)
141+
{{
142+
}}
143+
144+
public void Baz()
145+
{{
146+
{expression};
147+
}}
148+
149+
public long this[int a, int b, int s] => a + b + s;
150+
}}";
151+
152+
await this.VerifyCSharpDiagnosticAsync(testCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
153+
}
154+
155+
[Theory]
156+
[MemberData(nameof(GetTestExpressions), "\r\n")]
157+
public async Task TestInvalidExpressionAsync(string expression, int column)
158+
{
159+
var testCode = $@"
160+
class Foo
161+
{{
162+
public void Bar(int i, int j, int k)
163+
{{
164+
}}
165+
166+
public void Baz()
167+
{{
168+
{expression};
169+
}}
170+
171+
public long this[int a, int b, int s] => a + b + s;
172+
}}";
173+
174+
DiagnosticResult expected = this.CSharpDiagnostic().WithLocation(11, 2);
175+
await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
176+
}
177+
178+
[Fact]
179+
public async Task TestValidAttributeAsync()
180+
{
181+
var testCode = @"
182+
[System.AttributeUsage(System.AttributeTargets.Class)]
183+
public class MyAttribute : System.Attribute
184+
{
185+
public MyAttribute(int a, int b, int c)
186+
{
187+
}
188+
}
189+
190+
[MyAttribute(1, 2, 3)]
191+
class Foo
192+
{
193+
}
194+
195+
// This is a regression test for https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/1211
196+
[System.Obsolete]
197+
class ObsoleteType
198+
{
199+
}";
200+
201+
await this.VerifyCSharpDiagnosticAsync(testCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
202+
}
203+
204+
[Fact]
205+
public async Task TestInvalidAttributeAsync()
206+
{
207+
var testCode = @"
208+
[System.AttributeUsage(System.AttributeTargets.Class)]
209+
public class MyAttribute : System.Attribute
210+
{
211+
public MyAttribute(int a, int b, int c)
212+
{
213+
}
214+
}
215+
216+
[MyAttribute(
217+
1,
218+
2, 3)]
219+
class Foo
220+
{
221+
}";
222+
223+
DiagnosticResult expected = this.CSharpDiagnostic().WithLocation(12, 8);
224+
await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
225+
}
226+
227+
/// <inheritdoc/>
228+
protected override IEnumerable<DiagnosticAnalyzer> GetCSharpDiagnosticAnalyzers()
229+
{
230+
yield return new SA1117ParametersMustBeOnSameLineOrSeparateLines();
231+
}
232+
}
233+
}

StyleCop.Analyzers/StyleCop.Analyzers.Test/StyleCop.Analyzers.Test.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,7 @@
289289
<Compile Include="ReadabilityRules\SA1113UnitTests.cs" />
290290
<Compile Include="ReadabilityRules\SA1114UnitTests.cs" />
291291
<Compile Include="ReadabilityRules\SA1115UnitTests.cs" />
292+
<Compile Include="ReadabilityRules\SA1117UnitTests.cs" />
292293
<Compile Include="ReadabilityRules\SA1116UnitTests.cs" />
293294
<Compile Include="ReadabilityRules\SA1118UnitTests.cs" />
294295
<Compile Include="ReadabilityRules\SA1120UnitTests.cs" />

StyleCop.Analyzers/StyleCop.Analyzers/ReadabilityRules/ReadabilityResources.Designer.cs

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

StyleCop.Analyzers/StyleCop.Analyzers/ReadabilityRules/ReadabilityResources.resx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,7 @@
301301
<value>The parameters to a C# method or indexer call or declaration are not all on the same line or each on a separate line.</value>
302302
</data>
303303
<data name="SA1117MessageFormat" xml:space="preserve">
304-
<value />
304+
<value>The parameters must all be placed on the same line or alternatively, each parameter must be placed on its own line.</value>
305305
</data>
306306
<data name="SA1117Title" xml:space="preserve">
307307
<value>Parameters must be on same line or separate lines</value>

0 commit comments

Comments
 (0)