Skip to content

Commit 8e24044

Browse files
authored
Merge pull request #2589 from ali-hk/master
SA1210 is inconsistent with IDE's Remove and Sort Usings
2 parents 7098339 + 5835b85 commit 8e24044

5 files changed

Lines changed: 155 additions & 2 deletions

File tree

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -438,7 +438,7 @@ private bool IsSeparatedSystemUsing(UsingDirectiveSyntax syntax)
438438
var namespaceTypeName = namespaceSymbol.ToDisplayString(FullNamespaceDisplayFormat);
439439
var firstPart = namespaceTypeName.Split('.')[0];
440440

441-
return string.Equals(SystemUsingDirectiveIdentifier, firstPart, StringComparison.Ordinal);
441+
return string.Equals(SystemUsingDirectiveIdentifier, firstPart, StringComparison.Ordinal) || string.Equals(WindowsUsingDirectiveIdentifier, firstPart, StringComparison.Ordinal);
442442
}
443443

444444
private void ProcessMembers(SyntaxList<MemberDeclarationSyntax> members)

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ namespace StyleCop.Analyzers.OrderingRules
2626
internal sealed partial class UsingCodeFixProvider : CodeFixProvider
2727
{
2828
private const string SystemUsingDirectiveIdentifier = nameof(System);
29+
private const string WindowsUsingDirectiveIdentifier = "Windows";
2930

3031
private static readonly List<UsingDirectiveSyntax> EmptyUsingsList = new List<UsingDirectiveSyntax>();
3132
private static readonly SyntaxAnnotation UsingCodeFixAnnotation = new SyntaxAnnotation(nameof(UsingCodeFixAnnotation));

StyleCop.Analyzers/StyleCop.Analyzers.Test/OrderingRules/SA1208UnitTests.cs

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,92 @@ class A
115115
await this.VerifyCSharpDiagnosticAsync(usingsInNamespaceDeclaration, expected, CancellationToken.None).ConfigureAwait(false);
116116
}
117117

118+
[Fact]
119+
public async Task TestWhenSystemAndWindowsUsingDirectivesAreNotOnTopInCompilationAsync()
120+
{
121+
var usingsInCompilationUnit = new[]
122+
{
123+
"namespace Windows.Foundation {}",
124+
"namespace Xyz {}",
125+
"namespace AnotherNamespace {}",
126+
@"using Xyz;
127+
using System;
128+
using System.IO;
129+
using AnotherNamespace;
130+
using Windows.Foundation;
131+
using System.Threading.Tasks;
132+
133+
class A
134+
{
135+
}",
136+
};
137+
138+
DiagnosticResult[] expected =
139+
{
140+
this.CSharpDiagnostic().WithLocation("Test3.cs", 2, 1).WithArguments("System", "Xyz"),
141+
this.CSharpDiagnostic().WithLocation("Test3.cs", 3, 1).WithArguments("System.IO", "Xyz"),
142+
this.CSharpDiagnostic().WithLocation("Test3.cs", 5, 1).WithArguments("Windows.Foundation", "Xyz"),
143+
this.CSharpDiagnostic().WithLocation("Test3.cs", 6, 1).WithArguments("System.Threading.Tasks", "Xyz"),
144+
};
145+
146+
await this.VerifyCSharpDiagnosticAsync(usingsInCompilationUnit, expected, CancellationToken.None).ConfigureAwait(false);
147+
}
148+
149+
[Fact]
150+
public async Task TestWhenSystemAndWindowsUsingDirectivesAreNotOnTopInNamespaceAsync()
151+
{
152+
var usingsInNamespaceDeclaration = new[]
153+
{
154+
"namespace Windows.Foundation {}",
155+
"namespace Namespace {}",
156+
"namespace AnotherNamespace {}",
157+
@"namespace Test
158+
{
159+
using Namespace;
160+
using System.Threading;
161+
using System.IO;
162+
using Windows.Foundation;
163+
using AnotherNamespace;
164+
165+
class A
166+
{
167+
}
168+
}",
169+
};
170+
171+
DiagnosticResult[] expected =
172+
{
173+
this.CSharpDiagnostic().WithLocation("Test3.cs", 4, 5).WithArguments("System.Threading", "Namespace"),
174+
this.CSharpDiagnostic().WithLocation("Test3.cs", 5, 5).WithArguments("System.IO", "Namespace"),
175+
this.CSharpDiagnostic().WithLocation("Test3.cs", 6, 5).WithArguments("Windows.Foundation", "Namespace"),
176+
};
177+
178+
await this.VerifyCSharpDiagnosticAsync(usingsInNamespaceDeclaration, expected, CancellationToken.None).ConfigureAwait(false);
179+
}
180+
181+
[Fact]
182+
public async Task TestWhenWindowsUsingDirectivesAreNotOnTopAsync()
183+
{
184+
var usingsInCompilationUnit = new[]
185+
{
186+
"namespace Windows.Foundation {}",
187+
"namespace Namespace {}",
188+
@"using Namespace;
189+
using Windows.Foundation;
190+
191+
class A
192+
{
193+
}",
194+
};
195+
196+
DiagnosticResult[] expected =
197+
{
198+
this.CSharpDiagnostic().WithLocation("Test2.cs", 2, 1).WithArguments("Windows.Foundation", "Namespace"),
199+
};
200+
201+
await this.VerifyCSharpDiagnosticAsync(usingsInCompilationUnit, expected, CancellationToken.None).ConfigureAwait(false);
202+
}
203+
118204
[Fact]
119205
public async Task TestSystemUsingDirectivesInCompilationUnitAndInNamespaceDeclarationAsync()
120206
{

StyleCop.Analyzers/StyleCop.Analyzers.Test/OrderingRules/SA1210UnitTests.cs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,65 @@ namespace Bar
114114
await this.VerifyCSharpFixAsync(testCode, fixedTestCode).ConfigureAwait(false);
115115
}
116116

117+
[Fact]
118+
public async Task TestInvalidOrderedUsingDirectivesWithWindowsUsingDirectiveAsync()
119+
{
120+
var testCode = @"namespace Windows.Foundation {}
121+
namespace Windows.Foundation.Collections {}
122+
namespace Foo
123+
{
124+
using Windows.Foundation.Collections;
125+
using Windows.Foundation;
126+
using System.Threading;
127+
using System;
128+
}
129+
130+
namespace Bar
131+
{
132+
using Foo;
133+
using Bar;
134+
using Windows.Foundation.Collections;
135+
using Windows.Foundation;
136+
using System.Threading;
137+
using System;
138+
}";
139+
140+
var fixedTestCode = @"namespace Windows.Foundation {}
141+
namespace Windows.Foundation.Collections {}
142+
namespace Foo
143+
{
144+
using System;
145+
using System.Threading;
146+
using Windows.Foundation;
147+
using Windows.Foundation.Collections;
148+
}
149+
150+
namespace Bar
151+
{
152+
using System;
153+
using System.Threading;
154+
using Windows.Foundation;
155+
using Windows.Foundation.Collections;
156+
using Bar;
157+
using Foo;
158+
}";
159+
160+
DiagnosticResult[] expected =
161+
{
162+
this.CSharpDiagnostic().WithLocation(5, 5),
163+
this.CSharpDiagnostic().WithLocation(6, 5),
164+
this.CSharpDiagnostic().WithLocation(7, 5),
165+
this.CSharpDiagnostic().WithLocation(13, 5),
166+
this.CSharpDiagnostic().WithLocation(15, 5),
167+
this.CSharpDiagnostic().WithLocation(16, 5),
168+
this.CSharpDiagnostic().WithLocation(17, 5),
169+
};
170+
171+
await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
172+
await this.VerifyCSharpDiagnosticAsync(fixedTestCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
173+
await this.VerifyCSharpFixAsync(testCode, fixedTestCode).ConfigureAwait(false);
174+
}
175+
117176
[Fact]
118177
[WorkItem(2336, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/2336")]
119178
public async Task TestUsingDirectivesCaseSensitivityAsync()

StyleCop.Analyzers/StyleCop.Analyzers/Helpers/UsingDirectiveSyntaxHelpers.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,20 @@ namespace StyleCop.Analyzers.Helpers
1616
internal static class UsingDirectiveSyntaxHelpers
1717
{
1818
private const string SystemUsingDirectiveIdentifier = nameof(System);
19+
private const string WindowsUsingDirectiveIdentifier = "Windows";
1920

2021
/// <summary>
2122
/// Check if <see cref="UsingDirectiveSyntax"/> is system using directive.
2223
/// </summary>
2324
/// <param name="usingDirective">The <see cref="UsingDirectiveSyntax"/> that will be checked.</param>
2425
/// <returns>Return true if the <see cref="UsingDirectiveSyntax"/>is system using directive, otherwise false.</returns>
25-
internal static bool IsSystemUsingDirective(this UsingDirectiveSyntax usingDirective) => string.Equals(SystemUsingDirectiveIdentifier, GetFirstIdentifierInUsingDirective(usingDirective)?.ValueText, StringComparison.Ordinal);
26+
internal static bool IsSystemUsingDirective(this UsingDirectiveSyntax usingDirective)
27+
{
28+
string firstIdentifier = GetFirstIdentifierInUsingDirective(usingDirective)?.ValueText;
29+
30+
// Visual Studio treats Windows.* namespaces as system namespaces.
31+
return string.Equals(SystemUsingDirectiveIdentifier, firstIdentifier, StringComparison.Ordinal) || string.Equals(WindowsUsingDirectiveIdentifier, firstIdentifier, StringComparison.Ordinal);
32+
}
2633

2734
/// <summary>
2835
/// Check if <see cref="UsingDirectiveSyntax"/> is preceded by a preprocessor directive.

0 commit comments

Comments
 (0)