Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fix analyzer [RCS1214](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1214) ([PR](https://github.com/dotnet/roslynator/pull/1500))
- Fix analyzer [RCS1018](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1018) ([PR](https://github.com/dotnet/roslynator/pull/1510))
- Fix analyzer [RCS1264](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1264) ([PR](https://github.com/dotnet/roslynator/pull/1511))
- Fix analyzer [RCS0053](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS0053) ([PR](https://github.com/dotnet/roslynator/pull/1512))

### Changed

Expand Down
8 changes: 4 additions & 4 deletions src/Formatting.Analyzers.CodeFixes/CSharp/CodeFixHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -749,9 +749,9 @@ internal static List<TextChange> GetFixListChanges<TNode>(
if (nodes.Count == 1
&& node is ArgumentSyntax argument)
{
LambdaBlock lambdaBlock = GetLambdaBlock(argument, lines ??= argument.SyntaxTree.GetText(cancellationToken).Lines);
BracesBlock bracesBlock = GetBracesBlock(argument, lines ??= argument.SyntaxTree.GetText(cancellationToken).Lines);

if (lambdaBlock.Block is not null)
if (!bracesBlock.Token.IsKind(SyntaxKind.None))
increasedIndentation = indentationAnalysis.Indentation.ToString();
}

Expand All @@ -775,9 +775,9 @@ internal static List<TextChange> GetFixListChanges<TNode>(
if (!indentations.Any())
continue;

LambdaBlock lambdaBlock2 = GetLambdaBlock(node, lines ??= node.SyntaxTree.GetText(cancellationToken).Lines);
BracesBlock bracesBlock2 = GetBracesBlock(node, lines ??= node.SyntaxTree.GetText(cancellationToken).Lines);

bool isLambdaBlockWithOpenBraceAtEndOfLine = lambdaBlock2.Token == indentations.Last().Token;
bool isLambdaBlockWithOpenBraceAtEndOfLine = bracesBlock2.Token == indentations.Last().Token;

int baseIndentationLength = (isLambdaBlockWithOpenBraceAtEndOfLine)
? indentations.Last().Span.Length
Expand Down
182 changes: 127 additions & 55 deletions src/Formatting.Analyzers/CSharp/FixFormattingOfListAnalyzer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,19 @@ private static void Analyze<TNode>(

if (TriviaBlock.FromTrailing(nodeOrToken).IsWrapped)
{
if (i == 0
&& nodes.Count == 1
&& first.IsKind(SyntaxKind.Argument))
{
BracesBlock bracesBlock = GetBracesBlock(first, lines ??= first.SyntaxTree.GetText().Lines);

if (bracesBlock.Token.IsKind(SyntaxKind.CloseBracketToken))
{
AnalyzeBlock(indentationAnalysis, bracesBlock);
return;
}
}

if (ShouldFixIndentation(nodes[i].GetLeadingTrivia(), indentationLength))
{
ReportDiagnostic();
Expand All @@ -202,33 +215,11 @@ private static void Analyze<TNode>(
if (nodes.Count == 1
&& first.IsKind(SyntaxKind.Argument))
{
var argument = (ArgumentSyntax)(SyntaxNode)first;
BracesBlock bracesBlock = GetBracesBlock(first, lines ??= first.SyntaxTree.GetText().Lines);

LambdaBlock lambdaBlock = GetLambdaBlock(argument, lines ??= first.SyntaxTree.GetText().Lines);

if (lambdaBlock.Block is not null)
if (bracesBlock.Token.IsKind(SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken))
{
SyntaxToken token = lambdaBlock.Token;
SyntaxTriviaList leading = token.LeadingTrivia;

if (leading.Any())
{
SyntaxTrivia trivia = leading.Last();

if (trivia.IsWhitespaceTrivia()
&& trivia.SpanStart == lambdaBlock.LineStartIndex
&& trivia.Span.Length != indentationAnalysis.IndentationLength)
{
ReportDiagnostic();
break;
}
}
else if (lambdaBlock.LineStartIndex == token.SpanStart)
{
ReportDiagnostic();
break;
}

AnalyzeBlock(indentationAnalysis, bracesBlock);
return;
}
}
Expand Down Expand Up @@ -345,9 +336,31 @@ string GetTitle()
throw new InvalidOperationException();
}
}

void AnalyzeBlock(IndentationAnalysis indentationAnalysis, BracesBlock bracesBlock)
{
SyntaxToken token = bracesBlock.Token;
SyntaxTriviaList leading = token.LeadingTrivia;

if (leading.Any())
{
SyntaxTrivia trivia = leading.Last();

if (trivia.IsWhitespaceTrivia()
&& trivia.SpanStart == bracesBlock.LineStartIndex
&& trivia.Span.Length != indentationAnalysis.IndentationLength)
{
ReportDiagnostic();
}
}
else if (bracesBlock.LineStartIndex == token.SpanStart)
{
ReportDiagnostic();
}
}
}

internal static LambdaBlock GetLambdaBlock(SyntaxNode node, TextLineCollection lines)
internal static BracesBlock GetBracesBlock(SyntaxNode node, TextLineCollection lines)
{
TextLine line = lines.GetLineFromPosition(node.SpanStart);

Expand All @@ -356,67 +369,129 @@ internal static LambdaBlock GetLambdaBlock(SyntaxNode node, TextLineCollection l
if (!node.FullSpan.Contains(startIndex))
return default;

SyntaxToken openBrace = node.FindToken(startIndex);
BlockSyntax block = null;
SyntaxToken openToken = node.FindToken(startIndex);
SyntaxNode enclosedNode = null;
var isOpenBraceAtEndOfLine = false;

if (IsBraceToken(openBrace, SyntaxKind.OpenBraceToken))
if (IsOpenToken(openToken))
{
SyntaxTriviaList trailing = openBrace.TrailingTrivia;
SyntaxTriviaList trailing = openToken.TrailingTrivia;

if (trailing.Any()
&& trailing.Span.Contains(startIndex))
{
block = (BlockSyntax)openBrace.Parent;
enclosedNode = openToken.Parent;
isOpenBraceAtEndOfLine = true;
}
}

if (block is null)
if (enclosedNode is null)
{
startIndex = line.EndIncludingLineBreak;
openBrace = node.FindToken(startIndex);
openToken = node.FindToken(startIndex);

if (IsBraceToken(openBrace, SyntaxKind.OpenBraceToken))
if (IsOpenToken(openToken))
{
SyntaxTriviaList leading = openBrace.LeadingTrivia;
SyntaxTriviaList leading = openToken.LeadingTrivia;

if ((leading.Any() && leading.Span.Contains(startIndex))
|| (!leading.Any() && openBrace.SpanStart == startIndex))
|| (!leading.Any() && openToken.SpanStart == startIndex))
{
block = (BlockSyntax)openBrace.Parent;
enclosedNode = openToken.Parent;
}
}
}

if (block is not null)
if (enclosedNode is not null)
{
int endIndex = lines.GetLineFromPosition(node.Span.End).Start;
SyntaxToken closeBrace = node.FindToken(endIndex);
SyntaxToken closeToken = node.FindToken(endIndex);

if (IsBraceToken(closeBrace, SyntaxKind.CloseBraceToken)
&& object.ReferenceEquals(block, closeBrace.Parent))
if (IsCloseToken(closeToken)
&& object.ReferenceEquals(enclosedNode, closeToken.Parent))
{
SyntaxTriviaList leading = closeBrace.LeadingTrivia;
SyntaxTriviaList leading = closeToken.LeadingTrivia;

if ((leading.Any() && leading.Span.Contains(endIndex))
|| (!leading.Any() && closeBrace.SpanStart == endIndex))
|| (!leading.Any() && closeToken.SpanStart == endIndex))
{
return new LambdaBlock(
block,
(isOpenBraceAtEndOfLine) ? closeBrace : openBrace,
return new BracesBlock(
(isOpenBraceAtEndOfLine) ? closeToken : openToken,
(isOpenBraceAtEndOfLine) ? endIndex : startIndex);
}
}
}

return default;

static bool IsBraceToken(SyntaxToken token, SyntaxKind kind)
static bool IsOpenToken(SyntaxToken token)
{
return token.IsKind(kind)
&& token.IsParentKind(SyntaxKind.Block)
&& CSharpFacts.IsAnonymousFunctionExpression(token.Parent.Parent.Kind());
if (token.IsKind(SyntaxKind.OpenBraceToken))
{
if (token.IsParentKind(SyntaxKind.Block)
&& (CSharpFacts.IsAnonymousFunctionExpression(token.Parent.Parent.Kind())))
{
return true;
}

if (token.IsParentKind(SyntaxKind.ObjectInitializerExpression)
&& token.Parent.Parent.IsKind(
SyntaxKind.ObjectCreationExpression,
SyntaxKind.AnonymousObjectCreationExpression,
SyntaxKind.ImplicitObjectCreationExpression))
{
return true;
}

if (token.IsParentKind(SyntaxKind.ArrayInitializerExpression)
&& token.Parent.Parent.IsKind(
SyntaxKind.ArrayCreationExpression,
SyntaxKind.ImplicitArrayCreationExpression))
{
return true;
}
}
#if ROSLYN_4_7
return token.IsKind(SyntaxKind.OpenBracketToken)
&& token.IsParentKind(SyntaxKind.CollectionExpression);
#else
return false;
#endif
}

static bool IsCloseToken(SyntaxToken token)
{
if (token.IsKind(SyntaxKind.CloseBraceToken))
{
if (token.IsParentKind(SyntaxKind.Block)
&& (CSharpFacts.IsAnonymousFunctionExpression(token.Parent.Parent.Kind())))
{
return true;
}

if (token.IsParentKind(SyntaxKind.ObjectInitializerExpression)
&& token.Parent.Parent.IsKind(
SyntaxKind.ObjectCreationExpression,
SyntaxKind.AnonymousObjectCreationExpression,
SyntaxKind.ImplicitObjectCreationExpression))
{
return true;
}

if (token.IsParentKind(SyntaxKind.ArrayInitializerExpression)
&& token.Parent.Parent.IsKind(
SyntaxKind.ArrayCreationExpression,
SyntaxKind.ImplicitArrayCreationExpression))
{
return true;
}
}
#if ROSLYN_4_7
return token.IsKind(SyntaxKind.CloseBracketToken)
&& token.IsParentKind(SyntaxKind.CollectionExpression);
#else
return false;
#endif
}
}

Expand All @@ -439,17 +514,14 @@ internal static bool ShouldWrapAndIndent(SyntaxNode node, int index)
return true;
}

internal readonly struct LambdaBlock
internal readonly struct BracesBlock
{
public LambdaBlock(BlockSyntax block, SyntaxToken token, int lineStartIndex)
public BracesBlock(SyntaxToken token, int lineStartIndex)
{
Block = block;
Token = token;
LineStartIndex = lineStartIndex;
}

public BlockSyntax Block { get; }

public SyntaxToken Token { get; }

public int LineStartIndex { get; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1296,4 +1296,55 @@ internal static void Method(Foo[] foo)
}
", }, options: Options.WithCompilationOptions(Options.CompilationOptions.WithOutputKind(OutputKind.ConsoleApplication)));
}

[Fact, Trait(Traits.Analyzer, DiagnosticIdentifiers.FixFormattingOfList)]
public async Task TestNoDiagnostic_Multiline_ObjectInitializer()
{
await VerifyNoDiagnosticAsync("""
class C
{
public C() { }

public C(C value) { }

public string P1 { get; set; }

C M()
{
return new C(new C
{
P1 = "a"
});
}
}
""");
}

[Fact, Trait(Traits.Analyzer, DiagnosticIdentifiers.FixFormattingOfList)]
public async Task TestNoDiagnostic_Multiline_CollectionExpression()
{
await VerifyNoDiagnosticAsync(@"
class C
{
public C P { get; set; }

public string M(string[] values)
{
return null;
}

public void M2()
{
object x =
P
.M(
[
// some comment
null,
])
.ToString();
}
}
");
}
}