diff --git a/StyleCop.Analyzers/StyleCop.Analyzers.Test/LayoutRules/SA1514UnitTests.cs b/StyleCop.Analyzers/StyleCop.Analyzers.Test/LayoutRules/SA1514UnitTests.cs
index 582223d19..a71a69b66 100644
--- a/StyleCop.Analyzers/StyleCop.Analyzers.Test/LayoutRules/SA1514UnitTests.cs
+++ b/StyleCop.Analyzers/StyleCop.Analyzers.Test/LayoutRules/SA1514UnitTests.cs
@@ -1151,5 +1151,199 @@ public enum TestEnum
await VerifyCSharpFixAsync(testCode, expected, fixedCode, CancellationToken.None).ConfigureAwait(false);
}
+
+ [Fact]
+ [WorkItem(3849, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3849")]
+ public async Task TestClassInGlobalNamespaceAsync()
+ {
+ var testCode = @"
+///
+/// X.
+///
+public class TestClass
+{
+}
+";
+
+ var expected = DiagnosticResult.EmptyDiagnosticResults;
+
+ await VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
+ }
+
+ [Fact]
+ public async Task TestClassInGlobalNamespaceWithoutNewlineAsync()
+ {
+ var testCode = @"///
+/// X.
+///
+public class TestClass
+{
+}
+";
+
+ var expected = DiagnosticResult.EmptyDiagnosticResults;
+
+ await VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
+ }
+
+ [Fact]
+ public async Task TestClassInNamespaceAsync()
+ {
+ var testCode = @"
+namespace TestNamespace
+{
+ ///
+ /// X.
+ ///
+ public class TestClass
+ {
+ }
+}
+";
+
+ var expected = DiagnosticResult.EmptyDiagnosticResults;
+
+ await VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
+ }
+
+ [Fact]
+ public async Task TestClassInNamespaceWithCommentAsync()
+ {
+ var testCode = @"
+namespace TestNamespace
+{
+ // Normal comment
+ {|#0:///|}
+ /// X.
+ ///
+ public class TestClass
+ {
+ }
+}
+";
+
+ var fixedCode = @"
+namespace TestNamespace
+{
+ // Normal comment
+
+ ///
+ /// X.
+ ///
+ public class TestClass
+ {
+ }
+}
+";
+
+ var expected = new[]
+ {
+ Diagnostic().WithLocation(0).WithArguments(" not", "preceded"),
+ };
+
+ await VerifyCSharpFixAsync(testCode, expected, fixedCode, CancellationToken.None).ConfigureAwait(false);
+ }
+
+ [Fact]
+ public async Task TestClassInGlobalNamespaceWithCommentAsync()
+ {
+ var testCode = @"
+// Normal comment
+{|#0:///|}
+/// X.
+///
+public class TestClass
+{
+}
+";
+
+ var fixedCode = @"
+// Normal comment
+
+///
+/// X.
+///
+public class TestClass
+{
+}
+";
+
+ var expected = new[]
+ {
+ Diagnostic().WithLocation(0).WithArguments(" not", "preceded"),
+ };
+
+ await VerifyCSharpFixAsync(testCode, expected, fixedCode, CancellationToken.None).ConfigureAwait(false);
+ }
+
+ [Fact]
+ public async Task TestClassInGlobalNamespaceWithPreprocessorDirectiveAsync()
+ {
+ var testCode = @"
+#if DEBUG
+#endif
+{|#0:///|}
+/// X.
+///
+public class TestClass
+{
+}
+";
+
+ var fixedCode = @"
+#if DEBUG
+#endif
+
+///
+/// X.
+///
+public class TestClass
+{
+}
+";
+
+ var expected = new[]
+ {
+ Diagnostic().WithLocation(0).WithArguments(" not", "preceded"),
+ };
+
+ await VerifyCSharpFixAsync(testCode, expected, fixedCode, CancellationToken.None).ConfigureAwait(false);
+ }
+
+ [Fact]
+ public async Task TestClassInGlobalNamespaceWithMultilineCommentAsync()
+ {
+ var testCode = @"
+/* Normal
+ * multiline
+ * comment */
+{|#0:///|}
+/// X.
+///
+public class TestClass
+{
+}
+";
+
+ var fixedCode = @"
+/* Normal
+ * multiline
+ * comment */
+
+///
+/// X.
+///
+public class TestClass
+{
+}
+";
+
+ var expected = new[]
+ {
+ Diagnostic().WithLocation(0).WithArguments(" not", "preceded"),
+ };
+
+ await VerifyCSharpFixAsync(testCode, expected, fixedCode, CancellationToken.None).ConfigureAwait(false);
+ }
}
}
diff --git a/StyleCop.Analyzers/StyleCop.Analyzers/LayoutRules/SA1514ElementDocumentationHeaderMustBePrecededByBlankLine.cs b/StyleCop.Analyzers/StyleCop.Analyzers/LayoutRules/SA1514ElementDocumentationHeaderMustBePrecededByBlankLine.cs
index 377dfe327..932349990 100644
--- a/StyleCop.Analyzers/StyleCop.Analyzers/LayoutRules/SA1514ElementDocumentationHeaderMustBePrecededByBlankLine.cs
+++ b/StyleCop.Analyzers/StyleCop.Analyzers/LayoutRules/SA1514ElementDocumentationHeaderMustBePrecededByBlankLine.cs
@@ -170,6 +170,13 @@ private static void HandleDeclaration(SyntaxNodeAnalysisContext context)
// no leading blank line necessary at start of scope.
return;
}
+
+ // Logic to handle global namespace case
+ if (prevToken.IsKind(SyntaxKind.None))
+ {
+ // Node is the first element in the global namespace
+ return;
+ }
}
context.ReportDiagnostic(Diagnostic.Create(Descriptor, GetDiagnosticLocation(documentationHeader)));