Skip to content

Commit c8e4b60

Browse files
committed
Update SA1200 to support configuration
This commit changes the title of SA1200 to indicate that it can report violations of using directives placement according to the project configuration (specifically based on the usingDirectivesPlacement property in stylecop.json).
1 parent 170eed7 commit c8e4b60

10 files changed

Lines changed: 455 additions & 42 deletions

File tree

StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/OrderingRules/UsingCodeFixProvider.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ internal sealed class UsingCodeFixProvider : CodeFixProvider
3030
/// <inheritdoc/>
3131
public override ImmutableArray<string> FixableDiagnosticIds { get; } =
3232
ImmutableArray.Create(
33-
SA1200UsingDirectivesMustBePlacedWithinNamespace.DiagnosticId,
33+
SA1200UsingDirectivesMustBePlacedCorrectly.DiagnosticId,
3434
SA1208SystemUsingDirectivesMustBePlacedBeforeOtherUsingDirectives.DiagnosticId,
3535
SA1209UsingAliasDirectivesMustBePlacedAfterOtherUsingDirectives.DiagnosticId,
3636
SA1210UsingDirectivesMustBeOrderedAlphabeticallyByNamespace.DiagnosticId,
@@ -53,7 +53,7 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context)
5353
foreach (Diagnostic diagnostic in context.Diagnostics)
5454
{
5555
// do not offer a code fix for SA1200 when there are multiple namespaces in the source file
56-
if ((diagnostic.Id == SA1200UsingDirectivesMustBePlacedWithinNamespace.DiagnosticId)
56+
if ((diagnostic.Id == SA1200UsingDirectivesMustBePlacedCorrectly.DiagnosticId)
5757
&& (CountNamespaces(compilationUnit.Members) > 1))
5858
{
5959
continue;
@@ -82,7 +82,7 @@ private static Task<Document> GetTransformedDocumentAsync(Document document, Syn
8282
// - There are no global attributes
8383
// - There is only a single namespace declared at the top level
8484
var moveInsideNamespace =
85-
!document.Project.CompilationOptions.IsAnalyzerSuppressed(SA1200UsingDirectivesMustBePlacedWithinNamespace.DiagnosticId)
85+
!document.Project.CompilationOptions.IsAnalyzerSuppressed(SA1200UsingDirectivesMustBePlacedCorrectly.DiagnosticId)
8686
&& !compilationUnit.AttributeLists.Any()
8787
&& compilationUnit.Members.Count == 1
8888
&& namespaceCount == 1;
Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
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.OrderingRules
5+
{
6+
using System.Collections.Generic;
7+
using System.Threading;
8+
using System.Threading.Tasks;
9+
using Analyzers.Settings.ObjectModel;
10+
using Microsoft.CodeAnalysis.CodeFixes;
11+
using Microsoft.CodeAnalysis.Diagnostics;
12+
using StyleCop.Analyzers.OrderingRules;
13+
using TestHelper;
14+
using Xunit;
15+
16+
/// <summary>
17+
/// Unit tests for the <see cref="SA1200UsingDirectivesMustBePlacedCorrectly"/> when configured to use
18+
/// <see cref="UsingDirectivesPlacement.OutsideNamespace"/>.
19+
/// </summary>
20+
public class SA1200OutsideNamespaceUnitTests : CodeFixVerifier
21+
{
22+
private const string TestSettings = @"
23+
{
24+
""settings"": {
25+
""orderingRules"": {
26+
""usingDirectivesPlacement"": ""outsideNamespace""
27+
}
28+
}
29+
}
30+
";
31+
32+
private const string ClassDefinition = @"public class TestClass
33+
{
34+
}";
35+
36+
private const string StructDefinition = @"public struct TestStruct
37+
{
38+
}";
39+
40+
private const string InterfaceDefinition = @"public interface TestInterface
41+
{
42+
}";
43+
44+
private const string EnumDefinition = @"public enum TestEnum
45+
{
46+
TestValue
47+
}";
48+
49+
private const string DelegateDefinition = @"public delegate void TestDelegate();";
50+
51+
/// <summary>
52+
/// Verifies that using statements in a namespace produces the expected diagnostics.
53+
/// </summary>
54+
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
55+
[Fact]
56+
public async Task TestInvalidUsingStatementsInNamespaceAsync()
57+
{
58+
var testCode = @"namespace TestNamespace
59+
{
60+
using System;
61+
using System.Threading;
62+
}
63+
";
64+
var fixedTestCode = @"using System;
65+
using System.Threading;
66+
67+
namespace TestNamespace
68+
{
69+
}
70+
";
71+
72+
DiagnosticResult[] expectedResults =
73+
{
74+
this.CSharpDiagnostic(SA1200UsingDirectivesMustBePlacedCorrectly.DescriptorOutside).WithLocation(3, 5),
75+
this.CSharpDiagnostic(SA1200UsingDirectivesMustBePlacedCorrectly.DescriptorOutside).WithLocation(4, 5)
76+
};
77+
78+
await this.VerifyCSharpDiagnosticAsync(testCode, expectedResults, CancellationToken.None).ConfigureAwait(false);
79+
await this.VerifyCSharpDiagnosticAsync(fixedTestCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
80+
////await this.VerifyCSharpFixAsync(testCode, fixedTestCode).ConfigureAwait(false);
81+
}
82+
83+
/// <summary>
84+
/// Verifies that simplified using statements in a namespace are expanded during the code fix operation.
85+
/// </summary>
86+
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
87+
[Fact]
88+
public async Task TestInvalidSimplifiedUsingStatementsInNamespaceAsync()
89+
{
90+
var testCode = @"namespace System
91+
{
92+
using System;
93+
using System.Threading;
94+
using Reflection;
95+
}
96+
";
97+
var fixedTestCode = @"using System;
98+
using System.Reflection;
99+
using System.Threading;
100+
101+
namespace System
102+
{
103+
}
104+
";
105+
106+
DiagnosticResult[] expectedResults =
107+
{
108+
this.CSharpDiagnostic(SA1200UsingDirectivesMustBePlacedCorrectly.DescriptorOutside).WithLocation(3, 5),
109+
this.CSharpDiagnostic(SA1200UsingDirectivesMustBePlacedCorrectly.DescriptorOutside).WithLocation(4, 5),
110+
this.CSharpDiagnostic(SA1200UsingDirectivesMustBePlacedCorrectly.DescriptorOutside).WithLocation(5, 5),
111+
};
112+
113+
await this.VerifyCSharpDiagnosticAsync(testCode, expectedResults, CancellationToken.None).ConfigureAwait(false);
114+
await this.VerifyCSharpDiagnosticAsync(fixedTestCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
115+
////await this.VerifyCSharpFixAsync(testCode, fixedTestCode).ConfigureAwait(false);
116+
}
117+
118+
/// <summary>
119+
/// Verifies that having using statements in the compilation unit will not produce any diagnostics when there are type definition present.
120+
/// </summary>
121+
/// <param name="typeDefinition">The type definition to test.</param>
122+
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
123+
[Theory]
124+
[InlineData(ClassDefinition)]
125+
[InlineData(StructDefinition)]
126+
[InlineData(InterfaceDefinition)]
127+
[InlineData(EnumDefinition)]
128+
[InlineData(DelegateDefinition)]
129+
public async Task TestValidUsingStatementsInCompilationUnitWithTypeDefinitionAsync(string typeDefinition)
130+
{
131+
var testCode = $@"using System;
132+
133+
{typeDefinition}
134+
";
135+
136+
await this.VerifyCSharpDiagnosticAsync(testCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
137+
}
138+
139+
/// <summary>
140+
/// Verifies that having using statements in the compilation unit will not produce any diagnostics when there are attributes present.
141+
/// </summary>
142+
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
143+
[Fact]
144+
public async Task TestValidUsingStatementsInCompilationUnitWithAttributesAsync()
145+
{
146+
var testCode = @"using System.Reflection;
147+
148+
[assembly: AssemblyVersion(""1.0.0.0"")]
149+
150+
namespace TestNamespace
151+
{
152+
using System;
153+
using System.Threading;
154+
}
155+
";
156+
var fixedCode = @"using System;
157+
using System.Reflection;
158+
using System.Threading;
159+
160+
[assembly: AssemblyVersion(""1.0.0.0"")]
161+
162+
namespace TestNamespace
163+
{
164+
}
165+
";
166+
167+
DiagnosticResult[] expectedResults =
168+
{
169+
this.CSharpDiagnostic(SA1200UsingDirectivesMustBePlacedCorrectly.DescriptorOutside).WithLocation(7, 5),
170+
this.CSharpDiagnostic(SA1200UsingDirectivesMustBePlacedCorrectly.DescriptorOutside).WithLocation(8, 5)
171+
};
172+
173+
await this.VerifyCSharpDiagnosticAsync(testCode, expectedResults, CancellationToken.None).ConfigureAwait(false);
174+
await this.VerifyCSharpDiagnosticAsync(fixedCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
175+
////await this.VerifyCSharpFixAsync(testCode, fixedCode).ConfigureAwait(false);
176+
}
177+
178+
/// <summary>
179+
/// Verifies that having using statements in the compilation unit will not produce diagnostics.
180+
/// </summary>
181+
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
182+
[Fact]
183+
public async Task TestValidUsingStatementsInCompilationUnitAsync()
184+
{
185+
var testCode = @"using System;
186+
using System.Threading;
187+
188+
namespace TestNamespace
189+
{
190+
}
191+
";
192+
193+
await this.VerifyCSharpDiagnosticAsync(testCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
194+
}
195+
196+
/// <inheritdoc/>
197+
protected override string GetSettings()
198+
{
199+
return TestSettings;
200+
}
201+
202+
/// <inheritdoc/>
203+
protected override IEnumerable<DiagnosticAnalyzer> GetCSharpDiagnosticAnalyzers()
204+
{
205+
yield return new SA1200UsingDirectivesMustBePlacedCorrectly();
206+
}
207+
208+
/// <inheritdoc/>
209+
protected override CodeFixProvider GetCSharpCodeFixProvider()
210+
{
211+
return new UsingCodeFixProvider();
212+
}
213+
}
214+
}
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
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.OrderingRules
5+
{
6+
using System.Collections.Generic;
7+
using System.Threading;
8+
using System.Threading.Tasks;
9+
using Analyzers.Settings.ObjectModel;
10+
using Microsoft.CodeAnalysis.CodeFixes;
11+
using Microsoft.CodeAnalysis.Diagnostics;
12+
using StyleCop.Analyzers.OrderingRules;
13+
using TestHelper;
14+
using Xunit;
15+
16+
/// <summary>
17+
/// Unit tests for the <see cref="SA1200UsingDirectivesMustBePlacedCorrectly"/> when configured to use
18+
/// <see cref="UsingDirectivesPlacement.Preserve"/>.
19+
/// </summary>
20+
public class SA1200PreserveUnitTests : CodeFixVerifier
21+
{
22+
private const string SettingsFileName = "stylecop.json";
23+
private const string TestSettings = @"
24+
{
25+
""settings"": {
26+
""orderingRules"": {
27+
""usingDirectivesPlacement"": ""preserve""
28+
}
29+
}
30+
}
31+
";
32+
33+
private const string ClassDefinition = @"public class TestClass
34+
{
35+
}";
36+
37+
private const string StructDefinition = @"public struct TestStruct
38+
{
39+
}";
40+
41+
private const string InterfaceDefinition = @"public interface TestInterface
42+
{
43+
}";
44+
45+
private const string EnumDefinition = @"public enum TestEnum
46+
{
47+
TestValue
48+
}";
49+
50+
private const string DelegateDefinition = @"public delegate void TestDelegate();";
51+
52+
/// <summary>
53+
/// Verifies that valid using statements in a namespace does not produce any diagnostics.
54+
/// </summary>
55+
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
56+
[Fact]
57+
public async Task TestValidUsingStatementsInNamespaceAsync()
58+
{
59+
var testCode = @"namespace TestNamespace
60+
{
61+
using System;
62+
using System.Threading;
63+
}
64+
";
65+
66+
await this.VerifyCSharpDiagnosticAsync(testCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
67+
}
68+
69+
/// <summary>
70+
/// Verifies that having using statements in the compilation unit will not produce any diagnostics when there are type definition present.
71+
/// </summary>
72+
/// <param name="typeDefinition">The type definition to test.</param>
73+
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
74+
[Theory]
75+
[InlineData(ClassDefinition)]
76+
[InlineData(StructDefinition)]
77+
[InlineData(InterfaceDefinition)]
78+
[InlineData(EnumDefinition)]
79+
[InlineData(DelegateDefinition)]
80+
public async Task TestValidUsingStatementsInCompilationUnitWithTypeDefinitionAsync(string typeDefinition)
81+
{
82+
var testCode = $@"using System;
83+
84+
{typeDefinition}
85+
";
86+
87+
await this.VerifyCSharpDiagnosticAsync(testCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
88+
}
89+
90+
/// <summary>
91+
/// Verifies that having using statements in the compilation unit will not produce any diagnostics when there are attributes present.
92+
/// </summary>
93+
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
94+
[Fact]
95+
public async Task TestValidUsingStatementsInCompilationUnitWithAttributesAsync()
96+
{
97+
var testCode = @"using System.Reflection;
98+
99+
[assembly: AssemblyVersion(""1.0.0.0"")]
100+
101+
namespace TestNamespace
102+
{
103+
using System;
104+
using System.Threading;
105+
}
106+
";
107+
108+
await this.VerifyCSharpDiagnosticAsync(testCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
109+
}
110+
111+
/// <summary>
112+
/// Verifies that having using statements in the compilation unit will not diagnostics, even if they could be
113+
/// moved inside a namespace.
114+
/// </summary>
115+
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
116+
[Fact]
117+
public async Task TestIgnoredUsingStatementsInCompilationUnitAsync()
118+
{
119+
var testCode = @"using System;
120+
using System.Threading;
121+
122+
namespace TestNamespace
123+
{
124+
}
125+
";
126+
127+
await this.VerifyCSharpDiagnosticAsync(testCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
128+
}
129+
130+
/// <inheritdoc/>
131+
protected override string GetSettings()
132+
{
133+
return TestSettings;
134+
}
135+
136+
/// <inheritdoc/>
137+
protected override IEnumerable<DiagnosticAnalyzer> GetCSharpDiagnosticAnalyzers()
138+
{
139+
yield return new SA1200UsingDirectivesMustBePlacedCorrectly();
140+
}
141+
142+
/// <inheritdoc/>
143+
protected override CodeFixProvider GetCSharpCodeFixProvider()
144+
{
145+
return new UsingCodeFixProvider();
146+
}
147+
}
148+
}

0 commit comments

Comments
 (0)