Skip to content

Commit dc7e71a

Browse files
committed
Merge pull request #1809 from sharwell/fix-1747
Add the systemUsingDirectivesFirst ordering option
2 parents d5b2ca7 + 45bd260 commit dc7e71a

8 files changed

Lines changed: 63 additions & 26 deletions

File tree

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

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,11 @@ private static async Task<Document> GetTransformedDocumentAsync(Document documen
7474
{
7575
var compilationUnit = (CompilationUnitSyntax)syntaxRoot;
7676

77+
var settings = SettingsHelper.GetStyleCopSettings(document.Project.AnalyzerOptions, cancellationToken);
7778
var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
7879
var indentationOptions = IndentationOptions.FromDocument(document);
7980

80-
var usingsHelper = new UsingsHelper(semanticModel, document, compilationUnit);
81+
var usingsHelper = new UsingsHelper(settings, semanticModel, document, compilationUnit);
8182
var namespaceCount = CountNamespaces(compilationUnit.Members);
8283

8384
// Only move using declarations inside the namespace when
@@ -436,15 +437,17 @@ public DirectiveSpan FindContainingSpan(SyntaxNode node)
436437

437438
private class UsingsHelper
438439
{
440+
private readonly StyleCopSettings settings;
439441
private readonly SemanticModel semanticModel;
440442
private readonly DirectiveSpan conditionalDirectiveTree;
441443
private readonly bool separateSystemDirectives;
442444

443-
public UsingsHelper(SemanticModel semanticModel, Document document, CompilationUnitSyntax compilationUnit)
445+
public UsingsHelper(StyleCopSettings settings, SemanticModel semanticModel, Document document, CompilationUnitSyntax compilationUnit)
444446
{
447+
this.settings = settings;
445448
this.semanticModel = semanticModel;
446449
this.conditionalDirectiveTree = DirectiveSpan.BuildConditionalDirectiveTree(compilationUnit);
447-
this.separateSystemDirectives = !document.Project.CompilationOptions.IsAnalyzerSuppressed(SA1208SystemUsingDirectivesMustBePlacedBeforeOtherUsingDirectives.DiagnosticId);
450+
this.separateSystemDirectives = settings.OrderingRules.SystemUsingDirectivesFirst;
448451

449452
this.ProcessUsingDirectives(compilationUnit.Usings);
450453
this.ProcessMembers(compilationUnit.Members);

StyleCop.Analyzers/StyleCop.Analyzers.Test/OrderingRules/SA1210CombinedSystemDirectivesUnitTests.cs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,16 @@ namespace StyleCop.Analyzers.Test.OrderingRules
66
using System.Collections.Generic;
77
using System.Threading;
88
using System.Threading.Tasks;
9+
using Analyzers.OrderingRules;
10+
using Analyzers.Settings.ObjectModel;
911
using Microsoft.CodeAnalysis.CodeFixes;
1012
using Microsoft.CodeAnalysis.Diagnostics;
11-
using StyleCop.Analyzers.OrderingRules;
1213
using TestHelper;
1314
using Xunit;
1415

1516
/// <summary>
1617
/// Unit tests for <see cref="SA1210UsingDirectivesMustBeOrderedAlphabeticallyByNamespace"/> for the special case
17-
/// where <see cref="SA1208SystemUsingDirectivesMustBePlacedBeforeOtherUsingDirectives"/> is disabled.
18+
/// where <see cref="OrderingSettings.SystemUsingDirectivesFirst"/> is <see langword="false"/>.
1819
/// </summary>
1920
public class SA1210CombinedSystemDirectivesUnitTests : CodeFixVerifier
2021
{
@@ -209,9 +210,19 @@ public async Task TestPreprocessorDirectivesAsync()
209210
}
210211

211212
/// <inheritdoc/>
212-
protected override IEnumerable<string> GetDisabledDiagnostics()
213+
protected override string GetSettings()
213214
{
214-
yield return SA1208SystemUsingDirectivesMustBePlacedBeforeOtherUsingDirectives.DiagnosticId;
215+
const string CombinedUsingDirectivesTestSettings = @"
216+
{
217+
""settings"": {
218+
""orderingRules"": {
219+
""systemUsingDirectivesFirst"": false
220+
}
221+
}
222+
}
223+
";
224+
225+
return CombinedUsingDirectivesTestSettings;
215226
}
216227

217228
/// <inheritdoc/>

StyleCop.Analyzers/StyleCop.Analyzers.Test/OrderingRules/UsingCodeFixProviderCombinedSystemDirectivesUnitTests.cs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ namespace StyleCop.Analyzers.Test.OrderingRules
1515

1616
/// <summary>
1717
/// Unit tests for the <see cref="UsingCodeFixProvider"/> for the special case where
18-
/// <see cref="SA1208SystemUsingDirectivesMustBePlacedBeforeOtherUsingDirectives"/> is disabled.
18+
/// <see cref="OrderingSettings.SystemUsingDirectivesFirst"/> is <see langword="false"/>.
1919
/// </summary>
2020
public class UsingCodeFixProviderCombinedSystemDirectivesUnitTests : CodeFixVerifier
2121
{
@@ -397,19 +397,14 @@ public class Bar
397397
await this.VerifyCSharpFixAsync(testCode, fixedTestCode).ConfigureAwait(false);
398398
}
399399

400-
/// <inheritdoc/>
401-
protected override IEnumerable<string> GetDisabledDiagnostics()
402-
{
403-
yield return SA1208SystemUsingDirectivesMustBePlacedBeforeOtherUsingDirectives.DiagnosticId;
404-
}
405-
406400
/// <inheritdoc/>
407401
protected override string GetSettings()
408402
{
409403
string testSettings = $@"
410404
{{
411405
""settings"": {{
412406
""orderingRules"": {{
407+
""systemUsingDirectivesFirst"": false,
413408
""usingDirectivesPlacement"": ""{this.usingDirectivesPlacement}""
414409
}}
415410
}}

StyleCop.Analyzers/StyleCop.Analyzers/OrderingRules/SA1208SystemUsingDirectivesMustBePlacedBeforeOtherUsingDirectives.cs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ namespace StyleCop.Analyzers.OrderingRules
1010
using Microsoft.CodeAnalysis.CSharp.Syntax;
1111
using Microsoft.CodeAnalysis.Diagnostics;
1212
using StyleCop.Analyzers.Helpers;
13+
using StyleCop.Analyzers.Settings.ObjectModel;
1314

1415
/// <summary>
1516
/// A using directive which declares a member of the <see cref="System"/> namespace appears after a using directive
@@ -38,8 +39,8 @@ internal class SA1208SystemUsingDirectivesMustBePlacedBeforeOtherUsingDirectives
3839
new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, AnalyzerCategory.OrderingRules, DiagnosticSeverity.Warning, AnalyzerConstants.EnabledByDefault, Description, HelpLink);
3940

4041
private static readonly Action<CompilationStartAnalysisContext> CompilationStartAction = HandleCompilationStart;
41-
private static readonly Action<SyntaxNodeAnalysisContext> CompilationUnitAction = HandleCompilationUnit;
42-
private static readonly Action<SyntaxNodeAnalysisContext> NamespaceDeclarationAction = HandleNamespaceDeclaration;
42+
private static readonly Action<SyntaxNodeAnalysisContext, StyleCopSettings> CompilationUnitAction = HandleCompilationUnit;
43+
private static readonly Action<SyntaxNodeAnalysisContext, StyleCopSettings> NamespaceDeclarationAction = HandleNamespaceDeclaration;
4344

4445
/// <inheritdoc/>
4546
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } =
@@ -57,17 +58,27 @@ private static void HandleCompilationStart(CompilationStartAnalysisContext conte
5758
context.RegisterSyntaxNodeActionHonorExclusions(NamespaceDeclarationAction, SyntaxKind.NamespaceDeclaration);
5859
}
5960

60-
private static void HandleCompilationUnit(SyntaxNodeAnalysisContext context)
61+
private static void HandleCompilationUnit(SyntaxNodeAnalysisContext context, StyleCopSettings settings)
6162
{
63+
if (!settings.OrderingRules.SystemUsingDirectivesFirst)
64+
{
65+
return;
66+
}
67+
6268
var compilationUnit = context.Node as CompilationUnitSyntax;
6369

6470
var usings = compilationUnit.Usings;
6571

6672
ProcessUsingsAndReportDiagnostic(usings, context);
6773
}
6874

69-
private static void HandleNamespaceDeclaration(SyntaxNodeAnalysisContext context)
75+
private static void HandleNamespaceDeclaration(SyntaxNodeAnalysisContext context, StyleCopSettings settings)
7076
{
77+
if (!settings.OrderingRules.SystemUsingDirectivesFirst)
78+
{
79+
return;
80+
}
81+
7182
var namespaceDeclaration = context.Node as NamespaceDeclarationSyntax;
7283

7384
var usings = namespaceDeclaration.Usings;

StyleCop.Analyzers/StyleCop.Analyzers/OrderingRules/SA1210UsingDirectivesMustBeOrderedAlphabeticallyByNamespace.cs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ namespace StyleCop.Analyzers.OrderingRules
1212
using Microsoft.CodeAnalysis.CSharp.Syntax;
1313
using Microsoft.CodeAnalysis.Diagnostics;
1414
using StyleCop.Analyzers.Helpers;
15+
using StyleCop.Analyzers.Settings.ObjectModel;
1516

1617
/// <summary>
1718
/// The using directives within a C# code file are not sorted alphabetically by namespace.
@@ -40,8 +41,8 @@ internal class SA1210UsingDirectivesMustBeOrderedAlphabeticallyByNamespace : Dia
4041
new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, AnalyzerCategory.OrderingRules, DiagnosticSeverity.Warning, AnalyzerConstants.EnabledByDefault, Description, HelpLink);
4142

4243
private static readonly Action<CompilationStartAnalysisContext> CompilationStartAction = HandleCompilationStart;
43-
private static readonly Action<SyntaxNodeAnalysisContext> CompilationUnitAction = HandleCompilationUnit;
44-
private static readonly Action<SyntaxNodeAnalysisContext> NamespaceDeclarationAction = HandleNamespaceDeclaration;
44+
private static readonly Action<SyntaxNodeAnalysisContext, StyleCopSettings> CompilationUnitAction = HandleCompilationUnit;
45+
private static readonly Action<SyntaxNodeAnalysisContext, StyleCopSettings> NamespaceDeclarationAction = HandleNamespaceDeclaration;
4546

4647
/// <inheritdoc/>
4748
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } =
@@ -59,21 +60,21 @@ private static void HandleCompilationStart(CompilationStartAnalysisContext conte
5960
context.RegisterSyntaxNodeActionHonorExclusions(NamespaceDeclarationAction, SyntaxKind.NamespaceDeclaration);
6061
}
6162

62-
private static void HandleCompilationUnit(SyntaxNodeAnalysisContext context)
63+
private static void HandleCompilationUnit(SyntaxNodeAnalysisContext context, StyleCopSettings settings)
6364
{
6465
var compilationUnit = (CompilationUnitSyntax)context.Node;
6566

66-
ProcessUsings(context, compilationUnit.Usings);
67+
ProcessUsings(context, settings.OrderingRules, compilationUnit.Usings);
6768
}
6869

69-
private static void HandleNamespaceDeclaration(SyntaxNodeAnalysisContext context)
70+
private static void HandleNamespaceDeclaration(SyntaxNodeAnalysisContext context, StyleCopSettings settings)
7071
{
7172
var namespaceDeclaration = (NamespaceDeclarationSyntax)context.Node;
7273

73-
ProcessUsings(context, namespaceDeclaration.Usings);
74+
ProcessUsings(context, settings.OrderingRules, namespaceDeclaration.Usings);
7475
}
7576

76-
private static void ProcessUsings(SyntaxNodeAnalysisContext context, SyntaxList<UsingDirectiveSyntax> usings)
77+
private static void ProcessUsings(SyntaxNodeAnalysisContext context, OrderingSettings orderingSettings, SyntaxList<UsingDirectiveSyntax> usings)
7778
{
7879
var usingDirectives = new List<UsingDirectiveSyntax>();
7980
var systemUsingDirectives = new List<UsingDirectiveSyntax>();
@@ -95,7 +96,7 @@ private static void ProcessUsings(SyntaxNodeAnalysisContext context, SyntaxList<
9596

9697
if (usingDirective.HasNamespaceAliasQualifier()
9798
|| !usingDirective.IsSystemUsingDirective()
98-
|| context.IsAnalyzerSuppressed(SA1208SystemUsingDirectivesMustBePlacedBeforeOtherUsingDirectives.DiagnosticId))
99+
|| !orderingSettings.SystemUsingDirectivesFirst)
99100
{
100101
usingDirectives.Add(usingDirective);
101102
}

StyleCop.Analyzers/StyleCop.Analyzers/Settings/ObjectModel/OrderingSettings.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@ namespace StyleCop.Analyzers.Settings.ObjectModel
88
[JsonObject(MemberSerialization.OptIn)]
99
internal class OrderingSettings
1010
{
11+
/// <summary>
12+
/// This is the backing field for the <see cref="SystemUsingDirectivesFirst"/> property.
13+
/// </summary>
14+
[JsonProperty("systemUsingDirectivesFirst", DefaultValueHandling = DefaultValueHandling.Include)]
15+
private bool systemUsingDirectivesFirst;
16+
1117
/// <summary>
1218
/// This is the backing field for the <see cref="UsingDirectivesPlacement"/> property.
1319
/// </summary>
@@ -20,9 +26,13 @@ internal class OrderingSettings
2026
[JsonConstructor]
2127
protected internal OrderingSettings()
2228
{
29+
this.systemUsingDirectivesFirst = true;
2330
this.usingDirectivesPlacement = UsingDirectivesPlacement.InsideNamespace;
2431
}
2532

33+
public bool SystemUsingDirectivesFirst =>
34+
this.systemUsingDirectivesFirst;
35+
2636
public UsingDirectivesPlacement UsingDirectivesPlacement =>
2737
this.usingDirectivesPlacement;
2838
}

StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@
2929
"description": "Configuration for ordering rules (SA1200-)",
3030
"additionalProperties": false,
3131
"properties": {
32+
"systemUsingDirectivesFirst": {
33+
"type": "boolean",
34+
"description": "When true, System using directives must be placed before other using directives.",
35+
"default": true
36+
},
3237
"usingDirectivesPlacement": {
3338
"type": "string",
3439
"description": "Specifies the desired placement of using directives.\r\ninsideNamespace: Place using directives inside the namespace definition\r\noutsideNamespace: Place using directives outside the namespace definition\r\npreserve: Allow using directives inside or outside the namespace definition",

documentation/Configuration.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ The following properties are used to configure using directives in StyleCop Anal
8989

9090
| Property | Default Value | Summary |
9191
| --- | --- | --- |
92+
| `systemUsingDirectivesFirst` | true | Specifies whether `System` using directives are placed before other using directives |
9293
| `usingDirectivesPlacement` | `"insideNamespace"` | Specifies the desired placement of using directives |
9394

9495
#### Using Directives Placement

0 commit comments

Comments
 (0)