diff --git a/StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/LayoutRules/SA1516CodeFixProvider.cs b/StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/LayoutRules/SA1516CodeFixProvider.cs
index 73c5bcfb7..b8d7940fa 100644
--- a/StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/LayoutRules/SA1516CodeFixProvider.cs
+++ b/StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/LayoutRules/SA1516CodeFixProvider.cs
@@ -152,6 +152,11 @@ private static SyntaxNode GetRelevantNode(SyntaxNode innerNode)
return currentNode;
}
+ if (currentNode is ExternAliasDirectiveSyntax)
+ {
+ return currentNode;
+ }
+
currentNode = currentNode.Parent;
}
diff --git a/StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp10/LayoutRules/SA1516CSharp10UnitTests.cs b/StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp10/LayoutRules/SA1516CSharp10UnitTests.cs
index baa1ba110..f6020b139 100644
--- a/StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp10/LayoutRules/SA1516CSharp10UnitTests.cs
+++ b/StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp10/LayoutRules/SA1516CSharp10UnitTests.cs
@@ -3,9 +3,241 @@
namespace StyleCop.Analyzers.Test.CSharp10.LayoutRules
{
+ using System.Threading;
+ using System.Threading.Tasks;
+ using Microsoft.CodeAnalysis;
+ using Microsoft.CodeAnalysis.CSharp;
+ using Microsoft.CodeAnalysis.Testing;
using StyleCop.Analyzers.Test.CSharp9.LayoutRules;
+ using Xunit;
+ using static StyleCop.Analyzers.Test.Verifiers.StyleCopCodeFixVerifier<
+ StyleCop.Analyzers.LayoutRules.SA1516ElementsMustBeSeparatedByBlankLine,
+ StyleCop.Analyzers.LayoutRules.SA1516CodeFixProvider>;
public class SA1516CSharp10UnitTests : SA1516CSharp9UnitTests
{
+ ///
+ /// Verifies that SA1516 is reported for usings and extern alias outside a file scoped namespace.
+ ///
+ /// A representing the asynchronous unit test.
+ [Fact]
+ [WorkItem(3512, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3512")]
+ public async Task TestThatDiagnosticIIsReportedOnUsingsAndExternAliasOutsideFileScopedNamespaceAsync()
+ {
+ var testCode = @"extern alias corlib;
+[|using|] System;
+using System.Linq;
+using a = System.Collections;
+[|namespace|] Foo;
+";
+
+ var fixedCode = @"extern alias corlib;
+
+using System;
+using System.Linq;
+using a = System.Collections;
+
+namespace Foo;
+";
+
+ await VerifyCSharpFixAsync(testCode, fixedCode).ConfigureAwait(false);
+ }
+
+ ///
+ /// Verifies that SA1516 is reported for usings inside a file scoped namespace.
+ ///
+ /// A representing the asynchronous unit test.
+ [Fact]
+ [WorkItem(3512, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3512")]
+ public async Task TestThatDiagnosticIIsReportedOnSpacingWithUsingsInsideFileScopedNamespaceAsync()
+ {
+ var testCode = @"namespace Foo;
+[|using|] System;
+using System.Linq;
+using a = System.Collections;
+";
+
+ var fixedCode = @"namespace Foo;
+
+using System;
+using System.Linq;
+using a = System.Collections;
+";
+
+ await VerifyCSharpFixAsync(testCode, fixedCode).ConfigureAwait(false);
+ }
+
+ ///
+ /// Verifies that SA1516 is reported for member declarations inside a file scoped namespace.
+ ///
+ /// A representing the asynchronous unit test.
+ [Fact]
+ [WorkItem(3512, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3512")]
+ public async Task TestThatDiagnosticIIsReportedOnMemberDeclarationsInsideFileScopedNamespaceAsync()
+ {
+ var testCode = @"namespace Foo;
+[|public|] class Bar
+{
+}
+[|public|] enum Foobar
+{
+}
+";
+
+ var fixedCode = @"namespace Foo;
+
+public class Bar
+{
+}
+
+public enum Foobar
+{
+}
+";
+
+ await VerifyCSharpFixAsync(testCode, fixedCode).ConfigureAwait(false);
+ }
+
+ ///
+ /// Verifies that SA1516 is reported for usings and member declarations inside a file scoped namespace.
+ ///
+ /// A representing the asynchronous unit test.
+ [Fact]
+ [WorkItem(3512, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3512")]
+ public async Task TestThatDiagnosticIIsReportedOnUsingsAndMemberDeclarationsInsideFileScopedNamespaceAsync()
+ {
+ var testCode = @"namespace Foo;
+[|using|] System;
+using System.Linq;
+using a = System.Collections;
+[|public|] class Bar
+{
+}
+[|public|] enum Foobar
+{
+}
+";
+
+ var fixedCode = @"namespace Foo;
+
+using System;
+using System.Linq;
+using a = System.Collections;
+
+public class Bar
+{
+}
+
+public enum Foobar
+{
+}
+";
+
+ await VerifyCSharpFixAsync(testCode, fixedCode).ConfigureAwait(false);
+ }
+
+ ///
+ /// Verifies that SA1516 is reported extern alias inside a file scoped namespace.
+ ///
+ /// A representing the asynchronous unit test.
+ [Fact]
+ [WorkItem(3512, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3512")]
+ public async Task TestThatDiagnosticIIsReportedOnExternAliasInsideFileScopedNamespaceAsync()
+ {
+ var testCode = @"namespace Foo;
+[|extern|] alias corlib;
+";
+
+ var fixedCode = @"namespace Foo;
+
+extern alias corlib;
+";
+
+ await VerifyCSharpFixAsync(testCode, fixedCode).ConfigureAwait(false);
+ }
+
+ ///
+ /// Verifies that SA1516 is reported extern alias and usings inside a file scoped namespace.
+ ///
+ /// A representing the asynchronous unit test.
+ [Fact]
+ [WorkItem(3512, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3512")]
+ public async Task TestThatDiagnosticIIsReportedOnExternAliasAndUsingsInsideFileScopedNamespaceAsync()
+ {
+ var testCode = @"namespace Foo;
+[|extern|] alias corlib;
+[|using|] System;
+using System.Linq;
+using a = System.Collections;
+";
+
+ var fixedCode = @"namespace Foo;
+
+extern alias corlib;
+
+using System;
+using System.Linq;
+using a = System.Collections;
+";
+
+ await VerifyCSharpFixAsync(testCode, fixedCode).ConfigureAwait(false);
+ }
+
+ ///
+ /// Verifies that SA1516 is reported extern alias, usings and member declarations
+ /// inside a file scoped namespace.
+ ///
+ /// A representing the asynchronous unit test.
+ [Fact]
+ [WorkItem(3512, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3512")]
+ public async Task TestThatDiagnosticIIsReportedOnExternAliasUsingsAndMemberDeclarationsInsideFileScopedNamespaceAsync()
+ {
+ var testCode = @"namespace Foo;
+[|extern|] alias corlib;
+[|using|] System;
+using System.Linq;
+using a = System.Collections;
+[|public|] class Bar
+{
+}
+[|public|] enum Foobar
+{
+}
+";
+
+ var fixedCode = @"namespace Foo;
+
+extern alias corlib;
+
+using System;
+using System.Linq;
+using a = System.Collections;
+
+public class Bar
+{
+}
+
+public enum Foobar
+{
+}
+";
+
+ await VerifyCSharpFixAsync(testCode, fixedCode).ConfigureAwait(false);
+ }
+
+ private static Task VerifyCSharpFixAsync(string testCode, string fixedCode)
+ {
+ var test = new CSharpTest
+ {
+ ReferenceAssemblies = ReferenceAssemblies.Net.Net60,
+ TestState =
+ {
+ Sources = { testCode },
+ },
+ FixedCode = fixedCode,
+ };
+
+ return test.RunAsync(CancellationToken.None);
+ }
}
}
diff --git a/StyleCop.Analyzers/StyleCop.Analyzers/LayoutRules/SA1516ElementsMustBeSeparatedByBlankLine.cs b/StyleCop.Analyzers/StyleCop.Analyzers/LayoutRules/SA1516ElementsMustBeSeparatedByBlankLine.cs
index bd1ea17ea..2ac731989 100644
--- a/StyleCop.Analyzers/StyleCop.Analyzers/LayoutRules/SA1516ElementsMustBeSeparatedByBlankLine.cs
+++ b/StyleCop.Analyzers/StyleCop.Analyzers/LayoutRules/SA1516ElementsMustBeSeparatedByBlankLine.cs
@@ -15,6 +15,7 @@ namespace StyleCop.Analyzers.LayoutRules
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Text;
using StyleCop.Analyzers.Helpers;
+ using StyleCop.Analyzers.Lightup;
using StyleCop.Analyzers.Settings.ObjectModel;
///
@@ -87,6 +88,7 @@ internal class SA1516ElementsMustBeSeparatedByBlankLine : DiagnosticAnalyzer
private static readonly Action TypeDeclarationAction = HandleTypeDeclaration;
private static readonly Action CompilationUnitAction = HandleCompilationUnit;
private static readonly Action NamespaceDeclarationAction = HandleNamespaceDeclaration;
+ private static readonly Action FileScopedNamespaceDeclarationAction = HandleFileScopedNamespaceDeclaration;
private static readonly Action BasePropertyDeclarationAction = HandleBasePropertyDeclaration;
private static readonly ImmutableDictionary DiagnosticProperties = ImmutableDictionary.Empty.Add(CodeFixActionKey, InsertBlankLineValue);
@@ -129,6 +131,7 @@ public override void Initialize(AnalysisContext context)
context.RegisterSyntaxNodeAction(TypeDeclarationAction, SyntaxKinds.TypeDeclaration);
context.RegisterSyntaxNodeAction(CompilationUnitAction, SyntaxKind.CompilationUnit);
context.RegisterSyntaxNodeAction(NamespaceDeclarationAction, SyntaxKind.NamespaceDeclaration);
+ context.RegisterSyntaxNodeAction(FileScopedNamespaceDeclarationAction, SyntaxKindEx.FileScopedNamespaceDeclaration);
context.RegisterSyntaxNodeAction(BasePropertyDeclarationAction, SyntaxKinds.BasePropertyDeclaration);
});
}
@@ -212,6 +215,42 @@ private static void HandleCompilationUnit(SyntaxNodeAnalysisContext context, Sty
}
}
+ private static void HandleFileScopedNamespaceDeclaration(SyntaxNodeAnalysisContext context, StyleCopSettings settings)
+ {
+ var namespaceDeclaration = (BaseNamespaceDeclarationSyntaxWrapper)context.Node;
+
+ var usings = namespaceDeclaration.Usings;
+ var members = namespaceDeclaration.Members;
+
+ HandleUsings(context, usings, settings);
+ HandleMemberList(context, members);
+
+ if (namespaceDeclaration.Externs.Count > 0)
+ {
+ ReportIfThereIsNoBlankLine(context, namespaceDeclaration.Name, namespaceDeclaration.Externs[0]);
+ }
+
+ if (namespaceDeclaration.Usings.Count > 0)
+ {
+ ReportIfThereIsNoBlankLine(context, namespaceDeclaration.Name, namespaceDeclaration.Usings[0]);
+
+ if (namespaceDeclaration.Externs.Count > 0)
+ {
+ ReportIfThereIsNoBlankLine(context, namespaceDeclaration.Externs[namespaceDeclaration.Externs.Count - 1], namespaceDeclaration.Usings[0]);
+ }
+ }
+
+ if (members.Count > 0)
+ {
+ ReportIfThereIsNoBlankLine(context, namespaceDeclaration.Name, members[0]);
+
+ if (namespaceDeclaration.Usings.Count > 0)
+ {
+ ReportIfThereIsNoBlankLine(context, usings[usings.Count - 1], members[0]);
+ }
+ }
+ }
+
private static void HandleNamespaceDeclaration(SyntaxNodeAnalysisContext context, StyleCopSettings settings)
{
var namespaceDeclaration = (NamespaceDeclarationSyntax)context.Node;