Skip to content

Commit 6644806

Browse files
committed
Fixed issue in SA1500 with multi-dimensional array initializers
1 parent f01be7a commit 6644806

3 files changed

Lines changed: 114 additions & 8 deletions

File tree

StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/LayoutRules/SA1500CodeFixProvider.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,9 +110,11 @@ private static Dictionary<SyntaxToken, SyntaxToken> GenerateBraceFixes(Document
110110
// - The closing brace is the last token in the file
111111
var nextToken = braceToken.GetNextToken();
112112
var nextTokenLine = nextToken.IsKind(SyntaxKind.None) ? -1 : LocationHelpers.GetLineSpan(nextToken).StartLinePosition.Line;
113+
var isMultiDimensionArrayInitializer = braceToken.IsKind(SyntaxKind.OpenBraceToken) && braceToken.Parent.IsKind(SyntaxKind.ArrayInitializerExpression) && braceToken.Parent.Parent.IsKind(SyntaxKind.ArrayInitializerExpression);
113114

114115
if ((nextTokenLine == braceLine) &&
115-
(!braceToken.IsKind(SyntaxKind.CloseBraceToken) || !IsValidFollowingToken(nextToken)))
116+
(!braceToken.IsKind(SyntaxKind.CloseBraceToken) || !IsValidFollowingToken(nextToken)) &&
117+
!isMultiDimensionArrayInitializer)
116118
{
117119
var sharedTrivia = nextToken.LeadingTrivia.WithoutTrailingWhitespace();
118120
var newTrailingTrivia = braceReplacementToken.TrailingTrivia

StyleCop.Analyzers/StyleCop.Analyzers.Test/LayoutRules/SA1500/SA1500UnitTests.ArrayInitializers.cs

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,5 +342,96 @@ public void TestMethod()
342342
await this.VerifyCSharpDiagnosticAsync(fixedTestCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
343343
await this.VerifyCSharpFixAsync(testCode, fixedTestCode).ConfigureAwait(false);
344344
}
345+
346+
/// <summary>
347+
/// Verifies that a multi-dimensional array initialization produces the expected diagnostics.
348+
/// </summary>
349+
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
350+
[Fact]
351+
[WorkItem(2632, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/2632")]
352+
public async Task VerifyMultidimensionalArrayInitializationAsync()
353+
{
354+
var testCode = @"
355+
public class TestClass
356+
{
357+
private static readonly float[,] TestMatrix1 =
358+
new float[,]
359+
{
360+
{ 0, 0, 1, 1 },
361+
{ 1, 1, 1, 0 },
362+
{ 0, 1, 0, 0 }
363+
};
364+
365+
private static readonly float[,] TestMatrix2 =
366+
new float[,]
367+
{ { 0, 0, 1, 1 },
368+
{ 1, 1, 1, 0 },
369+
{ 0, 1, 0, 0 }
370+
};
371+
372+
private static readonly float[,] TestMatrix3 =
373+
new float[,]
374+
{
375+
{ 0, 0, 1, 1 },
376+
{ 1, 1, 1, 0 },
377+
{ 0, 1, 0, 0 } };
378+
379+
private static readonly float[,] TestMatrix4 =
380+
new float[,]
381+
{
382+
{ 0, 0, 1, 1 }, { 1, 1, 1, 0 },
383+
{ 0, 1, 0, 0 }
384+
};
385+
}
386+
";
387+
388+
var fixedTestCode = @"
389+
public class TestClass
390+
{
391+
private static readonly float[,] TestMatrix1 =
392+
new float[,]
393+
{
394+
{ 0, 0, 1, 1 },
395+
{ 1, 1, 1, 0 },
396+
{ 0, 1, 0, 0 }
397+
};
398+
399+
private static readonly float[,] TestMatrix2 =
400+
new float[,]
401+
{
402+
{ 0, 0, 1, 1 },
403+
{ 1, 1, 1, 0 },
404+
{ 0, 1, 0, 0 }
405+
};
406+
407+
private static readonly float[,] TestMatrix3 =
408+
new float[,]
409+
{
410+
{ 0, 0, 1, 1 },
411+
{ 1, 1, 1, 0 },
412+
{ 0, 1, 0, 0 }
413+
};
414+
415+
private static readonly float[,] TestMatrix4 =
416+
new float[,]
417+
{
418+
{ 0, 0, 1, 1 },
419+
{ 1, 1, 1, 0 },
420+
{ 0, 1, 0, 0 }
421+
};
422+
}
423+
";
424+
425+
DiagnosticResult[] expectedDiagnostics =
426+
{
427+
this.CSharpDiagnostic().WithLocation(14, 9),
428+
this.CSharpDiagnostic().WithLocation(24, 28),
429+
this.CSharpDiagnostic().WithLocation(29, 29),
430+
};
431+
432+
await this.VerifyCSharpDiagnosticAsync(testCode, expectedDiagnostics, CancellationToken.None).ConfigureAwait(false);
433+
await this.VerifyCSharpDiagnosticAsync(fixedTestCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
434+
await this.VerifyCSharpFixAsync(testCode, fixedTestCode).ConfigureAwait(false);
435+
}
345436
}
346437
}

StyleCop.Analyzers/StyleCop.Analyzers/LayoutRules/SA1500BracesForMultiLineStatementsMustNotShareLine.cs

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -140,37 +140,47 @@ private static void HandleAnonymousObjectCreationExpression(SyntaxNodeAnalysisCo
140140
private static void CheckBraces(SyntaxNodeAnalysisContext context, SyntaxToken openBraceToken, SyntaxToken closeBraceToken)
141141
{
142142
bool checkCloseBrace = true;
143+
int openBraceTokenLine = openBraceToken.GetLine();
143144

144-
if (GetStartLine(openBraceToken) == GetStartLine(closeBraceToken))
145+
if (openBraceTokenLine == closeBraceToken.GetLine())
145146
{
146147
if (context.Node.IsKind(SyntaxKind.ArrayInitializerExpression))
147148
{
148149
switch (context.Node.Parent.Kind())
149150
{
150151
case SyntaxKind.EqualsValueClause:
151-
if (GetStartLine(((EqualsValueClauseSyntax)context.Node.Parent).EqualsToken) == GetStartLine(openBraceToken))
152+
if (((EqualsValueClauseSyntax)context.Node.Parent).EqualsToken.GetLine() == openBraceTokenLine)
152153
{
153154
return;
154155
}
155156

156157
break;
157158

158159
case SyntaxKind.ArrayCreationExpression:
159-
if (GetStartLine(((ArrayCreationExpressionSyntax)context.Node.Parent).NewKeyword) == GetStartLine(openBraceToken))
160+
if (((ArrayCreationExpressionSyntax)context.Node.Parent).NewKeyword.GetLine() == openBraceTokenLine)
160161
{
161162
return;
162163
}
163164

164165
break;
165166

166167
case SyntaxKind.ImplicitArrayCreationExpression:
167-
if (GetStartLine(((ImplicitArrayCreationExpressionSyntax)context.Node.Parent).NewKeyword) == GetStartLine(openBraceToken))
168+
if (((ImplicitArrayCreationExpressionSyntax)context.Node.Parent).NewKeyword.GetLine() == openBraceTokenLine)
168169
{
169170
return;
170171
}
171172

172173
break;
173174

175+
case SyntaxKind.ArrayInitializerExpression:
176+
if (!InitializerExpressionSharesLine((InitializerExpressionSyntax)context.Node))
177+
{
178+
return;
179+
}
180+
181+
checkCloseBrace = false;
182+
break;
183+
174184
default:
175185
break;
176186
}
@@ -184,7 +194,7 @@ private static void CheckBraces(SyntaxNodeAnalysisContext context, SyntaxToken o
184194
case SyntaxKind.AddAccessorDeclaration:
185195
case SyntaxKind.RemoveAccessorDeclaration:
186196
case SyntaxKind.UnknownAccessorDeclaration:
187-
if (GetStartLine(((AccessorDeclarationSyntax)context.Node.Parent).Keyword) == GetStartLine(openBraceToken))
197+
if (((AccessorDeclarationSyntax)context.Node.Parent).Keyword.GetLine() == openBraceTokenLine)
188198
{
189199
// reported as SA1504, if at all
190200
return;
@@ -207,9 +217,12 @@ private static void CheckBraces(SyntaxNodeAnalysisContext context, SyntaxToken o
207217
}
208218
}
209219

210-
private static int GetStartLine(SyntaxToken token)
220+
private static bool InitializerExpressionSharesLine(InitializerExpressionSyntax node)
211221
{
212-
return token.GetLineSpan().StartLinePosition.Line;
222+
var parent = (InitializerExpressionSyntax)node.Parent;
223+
var index = parent.Expressions.IndexOf(node);
224+
225+
return (index > 0) && (parent.Expressions[index - 1].GetEndLine() == parent.Expressions[index].GetLine());
213226
}
214227

215228
private static void CheckBraceToken(SyntaxNodeAnalysisContext context, SyntaxToken token)

0 commit comments

Comments
 (0)