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)));