diff --git a/StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp9/LayoutRules/SA1516CSharp9UnitTests.cs b/StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp9/LayoutRules/SA1516CSharp9UnitTests.cs
index d7caa71f5..9b8b94dd9 100644
--- a/StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp9/LayoutRules/SA1516CSharp9UnitTests.cs
+++ b/StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp9/LayoutRules/SA1516CSharp9UnitTests.cs
@@ -3,9 +3,60 @@
namespace StyleCop.Analyzers.Test.CSharp9.LayoutRules
{
+ using System.Threading;
+ using System.Threading.Tasks;
+ using Microsoft.CodeAnalysis;
+ using Microsoft.CodeAnalysis.CSharp;
+ using Microsoft.CodeAnalysis.Testing;
using StyleCop.Analyzers.Test.CSharp8.LayoutRules;
+ using Xunit;
+ using static StyleCop.Analyzers.Test.Verifiers.StyleCopCodeFixVerifier<
+ StyleCop.Analyzers.LayoutRules.SA1516ElementsMustBeSeparatedByBlankLine,
+ StyleCop.Analyzers.LayoutRules.SA1516CodeFixProvider>;
public class SA1516CSharp9UnitTests : SA1516CSharp8UnitTests
{
+ ///
+ /// Verifies that SA1516 is reported at the correct location in top-level programs.
+ ///
+ /// A representing the asynchronous unit test.
+ [Fact]
+ [WorkItem(3242, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3242")]
+ public async Task TestStatementSpacingInTopLevelProgramAsync()
+ {
+ var testCode = @"using System;
+using System.Threading;
+{|#0:return|} 0;
+";
+ var fixedCode = @"using System;
+using System.Threading;
+
+return 0;
+";
+
+ await new CSharpTest(LanguageVersion.CSharp9)
+ {
+ ReferenceAssemblies = ReferenceAssemblies.Net.Net50,
+ TestCode = testCode,
+ ExpectedDiagnostics =
+ {
+ // /0/Test0.cs(3,1): warning SA1516: Elements should be separated by blank line
+ Diagnostic().WithLocation(0),
+
+ // /0/Test0.cs(3,1): warning SA1516: Elements should be separated by blank line
+ Diagnostic().WithLocation(0),
+ },
+ FixedCode = fixedCode,
+ SolutionTransforms =
+ {
+ (solution, projectId) =>
+ {
+ var project = solution.GetProject(projectId);
+ var options = project.CompilationOptions;
+ return solution.WithProjectCompilationOptions(projectId, options.WithOutputKind(OutputKind.ConsoleApplication));
+ },
+ },
+ }.RunAsync(CancellationToken.None).ConfigureAwait(false);
+ }
}
}
diff --git a/StyleCop.Analyzers/StyleCop.Analyzers/LayoutRules/SA1516ElementsMustBeSeparatedByBlankLine.cs b/StyleCop.Analyzers/StyleCop.Analyzers/LayoutRules/SA1516ElementsMustBeSeparatedByBlankLine.cs
index a0dea7a2c..7ee38b5f3 100644
--- a/StyleCop.Analyzers/StyleCop.Analyzers/LayoutRules/SA1516ElementsMustBeSeparatedByBlankLine.cs
+++ b/StyleCop.Analyzers/StyleCop.Analyzers/LayoutRules/SA1516ElementsMustBeSeparatedByBlankLine.cs
@@ -366,10 +366,16 @@ private static Location GetDiagnosticLocation(SyntaxNode node)
return node.GetLeadingTrivia()[0].GetLocation();
}
+ // Prefer the first token which is a direct child, but fall back to the first descendant token
var firstToken = node.ChildTokens().FirstOrDefault();
+ if (firstToken.IsKind(SyntaxKind.None))
+ {
+ firstToken = node.GetFirstToken();
+ }
+
if (firstToken != default)
{
- return node.ChildTokens().First().GetLocation();
+ return firstToken.GetLocation();
}
return Location.None;