Skip to content

Commit 3c635f8

Browse files
authored
Merge pull request #2655 from vweijsters/fix-2632
Fixed issue in SA1500 with multi-dimensional array initializers
2 parents e523335 + 4b4bfdb commit 3c635f8

3 files changed

Lines changed: 203 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: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,5 +342,185 @@ 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+
}
436+
437+
/// <summary>
438+
/// Verifies that a jagged array initialization produces the expected diagnostics.
439+
/// </summary>
440+
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
441+
[Fact]
442+
[WorkItem(2632, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/2632")]
443+
public async Task VerifyJaggedArrayInitializationAsync()
444+
{
445+
var testCode = @"
446+
public class TestClass
447+
{
448+
private static readonly int[][] TestMatrix1 =
449+
new int[][]
450+
{
451+
new[] { 0, 0, 1, 1 },
452+
new[] { 1, 1, 1, 0 },
453+
new[] { 0, 1, 0, 0 }
454+
};
455+
456+
private static readonly int[][] TestMatrix2 =
457+
new int[][]
458+
{ new[] { 0, 0, 1, 1 },
459+
new[] { 1, 1, 1, 0 },
460+
new[] { 0, 1, 0, 0 }
461+
};
462+
463+
private static readonly int[][] TestMatrix3 =
464+
new int[][]
465+
{
466+
new[] { 0, 0, 1, 1 },
467+
new[] { 1, 1, 1, 0 },
468+
new[] { 0, 1, 0, 0 } };
469+
470+
private static readonly int[][] TestMatrix4 =
471+
new int[][]
472+
{
473+
new[] { 0, 0, 1, 1 }, new[] { 1, 1, 1, 0 },
474+
new[] { 0, 1, 0, 0 }
475+
};
476+
}
477+
";
478+
479+
var fixedTestCode = @"
480+
public class TestClass
481+
{
482+
private static readonly int[][] TestMatrix1 =
483+
new int[][]
484+
{
485+
new[] { 0, 0, 1, 1 },
486+
new[] { 1, 1, 1, 0 },
487+
new[] { 0, 1, 0, 0 }
488+
};
489+
490+
private static readonly int[][] TestMatrix2 =
491+
new int[][]
492+
{
493+
new[] { 0, 0, 1, 1 },
494+
new[] { 1, 1, 1, 0 },
495+
new[] { 0, 1, 0, 0 }
496+
};
497+
498+
private static readonly int[][] TestMatrix3 =
499+
new int[][]
500+
{
501+
new[] { 0, 0, 1, 1 },
502+
new[] { 1, 1, 1, 0 },
503+
new[] { 0, 1, 0, 0 }
504+
};
505+
506+
private static readonly int[][] TestMatrix4 =
507+
new int[][]
508+
{
509+
new[] { 0, 0, 1, 1 }, new[] { 1, 1, 1, 0 },
510+
new[] { 0, 1, 0, 0 }
511+
};
512+
}
513+
";
514+
515+
DiagnosticResult[] expectedDiagnostics =
516+
{
517+
this.CSharpDiagnostic().WithLocation(14, 9),
518+
this.CSharpDiagnostic().WithLocation(24, 34),
519+
};
520+
521+
await this.VerifyCSharpDiagnosticAsync(testCode, expectedDiagnostics, CancellationToken.None).ConfigureAwait(false);
522+
await this.VerifyCSharpDiagnosticAsync(fixedTestCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
523+
await this.VerifyCSharpFixAsync(testCode, fixedTestCode).ConfigureAwait(false);
524+
}
345525
}
346526
}

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)