Skip to content

Commit 9b67feb

Browse files
committed
Merge pull request #1599 from vweijsters/fix-1595
2 parents 062caf0 + fcb1434 commit 9b67feb

2 files changed

Lines changed: 49 additions & 7 deletions

File tree

StyleCop.Analyzers/StyleCop.Analyzers.Test/LayoutRules/SA1516UnitTests.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,26 @@ public event System.EventHandler FooProperty
523523
await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
524524
}
525525

526+
/// <summary>
527+
/// Verifies that private fields with attributes are handled properly.
528+
/// This is a regression test for #1595
529+
/// </summary>
530+
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
531+
[Fact]
532+
public async Task VerifyThatPrivateFieldsAreHandledProperlyAsync()
533+
{
534+
string testCode = @"using System;
535+
536+
public class TestClass
537+
{
538+
[Obsolete]
539+
private int test1;
540+
private bool test2;
541+
}";
542+
543+
await this.VerifyCSharpDiagnosticAsync(testCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
544+
}
545+
526546
protected override IEnumerable<DiagnosticAnalyzer> GetCSharpDiagnosticAnalyzers()
527547
{
528548
yield return new SA1516ElementsMustBeSeparatedByBlankLine();

StyleCop.Analyzers/StyleCop.Analyzers/LayoutRules/SA1516ElementsMustBeSeparatedByBlankLine.cs

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -192,24 +192,46 @@ private static void HandleMemberList(SyntaxNodeAnalysisContext context, SyntaxLi
192192
if (!members[i - 1].ContainsDiagnostics && !members[i].ContainsDiagnostics)
193193
{
194194
// Report if
195-
// the previous declaration spans across multiple lines
195+
// the current declaration is not a field declaration
196196
// or the previous declaration is of different type
197-
// or the current declaration has documentation
198-
// or the current declaration is not a field declaration,
199-
if (IsMultiline(members[i - 1])
197+
// or the previous declaration spans across multiple lines
198+
//
199+
// Note that the order of checking is important, as the call to IsMultiLine requires a FieldDeclarationSyntax,
200+
// something that can only be guaranteed if the first two checks fail.
201+
if (!members[i].IsKind(SyntaxKind.FieldDeclaration)
200202
|| !members[i - 1].IsKind(members[i].Kind())
201-
|| !members[i].IsKind(SyntaxKind.FieldDeclaration))
203+
|| IsMultiline((FieldDeclarationSyntax)members[i - 1]))
202204
{
203205
ReportIfThereIsNoBlankLine(context, members[i - 1], members[i]);
204206
}
205207
}
206208
}
207209
}
208210

209-
private static bool IsMultiline(SyntaxNode node)
211+
private static bool IsMultiline(FieldDeclarationSyntax fieldDeclaration)
210212
{
211-
var lineSpan = node.GetLineSpan();
213+
var lineSpan = fieldDeclaration.GetLineSpan();
214+
var attributeLists = fieldDeclaration.AttributeLists;
212215

216+
int startLine;
217+
218+
// Exclude attributes when determining if a field declaration spans multiple lines
219+
if (attributeLists.Count > 0)
220+
{
221+
var lastAttributeSpan = fieldDeclaration.SyntaxTree.GetLineSpan(attributeLists.Last().FullSpan);
222+
startLine = lastAttributeSpan.EndLinePosition.Line;
223+
}
224+
else
225+
{
226+
startLine = lineSpan.StartLinePosition.Line;
227+
}
228+
229+
return startLine != lineSpan.EndLinePosition.Line;
230+
}
231+
232+
private static bool IsMultiline(AccessorDeclarationSyntax accessorDeclaration)
233+
{
234+
var lineSpan = accessorDeclaration.GetLineSpan();
213235
return lineSpan.StartLinePosition.Line != lineSpan.EndLinePosition.Line;
214236
}
215237

0 commit comments

Comments
 (0)