internal static MemberDeclarationSyntax RemoveSingleLineDocumentationComment(MemberDeclarationSyntax declaration) { if (declaration == null) { throw new ArgumentNullException(nameof(declaration)); } SyntaxTriviaList leadingTrivia = declaration.GetLeadingTrivia(); SyntaxTriviaList.Reversed.Enumerator en = leadingTrivia.Reverse().GetEnumerator(); int i = 0; while (en.MoveNext()) { SyntaxKind kind = en.Current.Kind(); if (kind == SyntaxKind.WhitespaceTrivia || kind == SyntaxKind.EndOfLineTrivia) { i++; } else if (kind == SyntaxKind.SingleLineDocumentationCommentTrivia) { return(declaration.WithLeadingTrivia(leadingTrivia.Take(leadingTrivia.Count - (i + 1)))); } else { return(declaration); } } return(declaration); }
static bool ShouldFixIndentation(SyntaxTriviaList leading, int indentationLength) { SyntaxTriviaList.Reversed.Enumerator en = leading.Reverse().GetEnumerator(); if (!en.MoveNext()) { return(true); } switch (en.Current.Kind()) { case SyntaxKind.WhitespaceTrivia: { if (en.Current.Span.Length != indentationLength) { if (!en.MoveNext() || en.Current.IsEndOfLineTrivia()) { return(true); } } break; } case SyntaxKind.EndOfLineTrivia: { return(true); } } return(false); }
internal static MemberDeclarationSyntax RemoveSingleLineDocumentationComment(MemberDeclarationSyntax member) { if (member == null) { throw new ArgumentNullException(nameof(member)); } SyntaxTriviaList leadingTrivia = member.GetLeadingTrivia(); SyntaxTriviaList.Reversed.Enumerator en = leadingTrivia.Reverse().GetEnumerator(); int i = 0; while (en.MoveNext()) { if (en.Current.IsWhitespaceOrEndOfLineTrivia()) { i++; } else if (en.Current.IsKind(SyntaxKind.SingleLineDocumentationCommentTrivia)) { return(member.WithLeadingTrivia(leadingTrivia.Take(leadingTrivia.Count - (i + 1)))); } else { return(member); } } return(member); }
private static void AnalyzeCompilationUnit(SyntaxNodeAnalysisContext context) { var compilationUnit = (CompilationUnitSyntax)context.Node; UsingDirectiveSyntax usingDirective = compilationUnit.Usings.FirstOrDefault(); if (usingDirective == null) { return; } SyntaxTriviaList.Reversed.Enumerator en = usingDirective.GetLeadingTrivia().Reverse().GetEnumerator(); if (en.MoveNext()) { if (en.Current.IsWhitespaceTrivia() && !en.MoveNext()) { if (IsPrecededWithExternAliasDirective()) { ReportDiagnostic(usingDirective.SpanStart); } } else if (en.Current.IsEndOfLineTrivia() && en.MoveNext() && en.Current.IsKind(SyntaxKind.SingleLineCommentTrivia)) { ReportDiagnostic(usingDirective.SpanStart); } } else if (IsPrecededWithExternAliasDirective()) { ReportDiagnostic(usingDirective.SpanStart); } bool IsPrecededWithExternAliasDirective() { ExternAliasDirectiveSyntax externAliasDirective = compilationUnit.Externs.LastOrDefault(); return(externAliasDirective?.FullSpan.End == usingDirective.FullSpan.Start && SyntaxTriviaAnalysis.IsOptionalWhitespaceThenOptionalSingleLineCommentThenEndOfLineTrivia(externAliasDirective.GetTrailingTrivia())); } void ReportDiagnostic(int position) { DiagnosticHelpers.ReportDiagnostic( context, DiagnosticDescriptors.AddEmptyLineBeforeUsingDirectiveList, Location.Create(compilationUnit.SyntaxTree, new TextSpan(position, 0))); } }
public static (TextSpan span, bool hasDocumentationComment) AnalyzeLeadingTrivia(SyntaxNode declaration) { SyntaxTriviaList leadingTrivia = declaration.GetLeadingTrivia(); SyntaxTriviaList.Reversed.Enumerator en = leadingTrivia.Reverse().GetEnumerator(); var span = default(TextSpan); while (en.MoveNext()) { if (en.Current.Kind() == SyntaxKind.WhitespaceTrivia && !en.MoveNext()) { break; } if (en.Current.Kind() == SyntaxKind.EndOfLineTrivia) { if (!en.MoveNext()) { break; } if (en.Current.Kind() == SyntaxKind.SingleLineCommentTrivia) { span = (span == default(TextSpan)) ? en.Current.Span : TextSpan.FromBounds(en.Current.SpanStart, span.End); } } else { do { if (SyntaxFacts.IsDocumentationCommentTrivia(en.Current.Kind())) { return(default(TextSpan), true); } } while (en.MoveNext()); break; } } return(span, false); }
private static void AnalyzeEndRegionDirectiveTrivia(SyntaxNodeAnalysisContext context) { var endRegionDirective = (EndRegionDirectiveTriviaSyntax)context.Node; if (IsPrecededWithEmptyLineOrRegionDirective()) { return; } DiagnosticHelpers.ReportDiagnostic( context, DiagnosticDescriptors.AddEmptyLineBeforeEndRegionDirective, Location.Create(endRegionDirective.SyntaxTree, endRegionDirective.Span.WithLength(0))); bool IsPrecededWithEmptyLineOrRegionDirective() { SyntaxTrivia parentTrivia = endRegionDirective.ParentTrivia; SyntaxTriviaList.Reversed.Enumerator en = parentTrivia.Token.LeadingTrivia.Reverse().GetEnumerator(); while (en.MoveNext()) { if (en.Current == parentTrivia) { if (!en.MoveNext()) { return(false); } if (en.Current.IsWhitespaceTrivia() && !en.MoveNext()) { return(false); } if (en.Current.IsKind(SyntaxKind.RegionDirectiveTrivia)) { return(true); } if (!en.Current.IsEndOfLineTrivia()) { return(false); } if (!en.MoveNext()) { return(true); } if (en.Current.IsWhitespaceTrivia() && !en.MoveNext()) { return(false); } return(en.Current.IsEndOfLineTrivia()); } } return(false); } }
public static Task <Document> FixBinaryExpressionAsync( Document document, BinaryExpressionSyntax binaryExpression, TextSpan span, CancellationToken cancellationToken) { IndentationAnalysis indentationAnalysis = AnalyzeIndentation(binaryExpression, cancellationToken); string indentation; if (indentationAnalysis.Indentation == binaryExpression.GetLeadingTrivia().LastOrDefault() && AnalyzerOptions.AddNewLineAfterBinaryOperatorInsteadOfBeforeIt.IsEnabled(document, binaryExpression)) { indentation = indentationAnalysis.Indentation.ToString(); } else { indentation = indentationAnalysis.GetIncreasedIndentation(); } string endOfLineAndIndentation = DetermineEndOfLine(binaryExpression).ToString() + indentation; var textChanges = new List <TextChange>(); int prevIndex = binaryExpression.Span.End; SyntaxKind binaryKind = binaryExpression.Kind(); while (true) { SyntaxToken token = binaryExpression.OperatorToken; if (token.Span.End > span.End) { continue; } if (token.SpanStart < span.Start) { break; } ExpressionSyntax left = binaryExpression.Left; ExpressionSyntax right = binaryExpression.Right; SyntaxTriviaList leftTrailing = left.GetTrailingTrivia(); SyntaxTriviaList tokenTrailing = token.TrailingTrivia; if (IsOptionalWhitespaceThenOptionalSingleLineCommentThenEndOfLineTrivia(leftTrailing)) { if (!SetIndentation(token)) { break; } } else if (IsOptionalWhitespaceThenOptionalSingleLineCommentThenEndOfLineTrivia(tokenTrailing)) { if (!SetIndentation(right)) { break; } } else if (leftTrailing.IsEmptyOrWhitespace() && tokenTrailing.IsEmptyOrWhitespace()) { if (AnalyzerOptions.AddNewLineAfterBinaryOperatorInsteadOfBeforeIt.IsEnabled(document, binaryExpression)) { if (!SetIndentation(right)) { break; } } else if (!SetIndentation(token)) { break; } } if (!left.IsKind(binaryKind)) { break; } binaryExpression = (BinaryExpressionSyntax)left; } if (textChanges.Count > 0) { SyntaxTriviaList leading = binaryExpression.GetLeadingTrivia(); if (!leading.Any()) { SyntaxTrivia trivia = binaryExpression.GetFirstToken().GetPreviousToken().TrailingTrivia.LastOrDefault(); if (trivia.IsEndOfLineTrivia() && trivia.Span.End == binaryExpression.SpanStart) { textChanges.Add(new TextSpan(binaryExpression.SpanStart, 0), indentation); } } } FormattingVerifier.VerifyChangedSpansAreWhitespace(binaryExpression, textChanges); return(document.WithTextChangesAsync(textChanges, cancellationToken)); bool SetIndentation(SyntaxNodeOrToken nodeOrToken) { SyntaxTriviaList leading = nodeOrToken.GetLeadingTrivia(); SyntaxTriviaList.Reversed.Enumerator en = leading.Reverse().GetEnumerator(); if (!en.MoveNext()) { SyntaxTrivia trivia = binaryExpression.FindTrivia(nodeOrToken.SpanStart - 1); string newText = (trivia.IsEndOfLineTrivia()) ? indentation : endOfLineAndIndentation; int start = (trivia.IsWhitespaceTrivia()) ? trivia.SpanStart : nodeOrToken.SpanStart; TextSpan span = (trivia.IsWhitespaceTrivia()) ? trivia.Span : new TextSpan(nodeOrToken.SpanStart, 0); textChanges.Add(span, newText); SetIndendation(nodeOrToken, prevIndex); prevIndex = start; return(true); } SyntaxTrivia last = en.Current; SyntaxKind kind = en.Current.Kind(); if (kind == SyntaxKind.WhitespaceTrivia) { if (en.Current.Span.Length != indentation.Length) { if (!en.MoveNext() || en.Current.IsEndOfLineTrivia()) { SyntaxTrivia trivia = binaryExpression.FindTrivia(nodeOrToken.FullSpan.Start - 1); if (trivia.IsEndOfLineTrivia()) { AddTextChange((leading.IsEmptyOrWhitespace()) ? leading.Span : last.Span); SetIndendation(nodeOrToken, prevIndex); prevIndex = trivia.SpanStart; return(true); } } } } else if (kind == SyntaxKind.EndOfLineTrivia) { SyntaxTrivia trivia = binaryExpression.FindTrivia(nodeOrToken.FullSpan.Start - 1); if (trivia.IsEndOfLineTrivia()) { AddTextChange((leading.IsEmptyOrWhitespace()) ? leading.Span : last.Span); SetIndendation(nodeOrToken, prevIndex); prevIndex = trivia.SpanStart; return(true); } } prevIndex = leading.Span.Start - 1; return(true); void AddTextChange(TextSpan span) => textChanges.Add(span, indentation); } void SetIndendation(SyntaxNodeOrToken nodeOrToken, int endIndex) { ImmutableArray <IndentationInfo> indentations = FindIndentations( binaryExpression, TextSpan.FromBounds(nodeOrToken.SpanStart, endIndex)) .ToImmutableArray(); if (!indentations.Any()) { return; } int firstIndentationLength = indentations[0].Span.Length; for (int j = 0; j < indentations.Length; j++) { IndentationInfo indentationInfo = indentations[j]; string replacement = indentation + indentationAnalysis.GetSingleIndentation(); if (j > 0 && indentationInfo.Span.Length > firstIndentationLength) { replacement += indentationInfo.ToString().Substring(firstIndentationLength); } if (indentationInfo.Span.Length != replacement.Length) { textChanges.Add(indentationInfo.Span, replacement); } } } }
public static Task <Document> FixCallChainAsync( Document document, ExpressionSyntax expression, TextSpan span, CancellationToken cancellationToken = default) { IndentationAnalysis indentationAnalysis = AnalyzeIndentation(expression, cancellationToken); string indentation = indentationAnalysis.GetIncreasedIndentation(); string endOfLineAndIndentation = DetermineEndOfLine(expression).ToString() + indentation; var textChanges = new List <TextChange>(); int prevIndex = expression.Span.End; foreach (SyntaxNode node in new MethodChain(expression)) { SyntaxKind kind = node.Kind(); if (kind == SyntaxKind.SimpleMemberAccessExpression) { var memberAccess = (MemberAccessExpressionSyntax)node; if (!SetIndentation(memberAccess.OperatorToken)) { break; } } else if (kind == SyntaxKind.MemberBindingExpression) { var memberBinding = (MemberBindingExpressionSyntax)node; if (!SetIndentation(memberBinding.OperatorToken)) { break; } } } FormattingVerifier.VerifyChangedSpansAreWhitespace(expression, textChanges); return(document.WithTextChangesAsync(textChanges, cancellationToken)); bool SetIndentation(SyntaxToken token) { if (token.Span.End > span.End) { return(true); } if (token.SpanStart < span.Start) { return(false); } SyntaxTriviaList leading = token.LeadingTrivia; SyntaxTriviaList.Reversed.Enumerator en = leading.Reverse().GetEnumerator(); if (!en.MoveNext()) { SyntaxTrivia trivia = expression.FindTrivia(token.SpanStart - 1); string newText = (trivia.IsEndOfLineTrivia()) ? indentation : endOfLineAndIndentation; textChanges.Add(new TextSpan(token.SpanStart, 0), newText); SetIndendation(token, prevIndex); prevIndex = (trivia.IsEndOfLineTrivia()) ? trivia.SpanStart : token.SpanStart; return(true); } SyntaxTrivia last = en.Current; SyntaxKind kind = en.Current.Kind(); if (kind == SyntaxKind.WhitespaceTrivia) { if (en.Current.Span.Length != indentation.Length) { if (!en.MoveNext() || en.Current.IsEndOfLineTrivia()) { SyntaxTrivia trivia = expression.FindTrivia(token.FullSpan.Start - 1); if (trivia.IsEndOfLineTrivia()) { textChanges.Add((leading.IsEmptyOrWhitespace()) ? leading.Span : last.Span, indentation); SetIndendation(token, prevIndex); prevIndex = trivia.SpanStart; return(true); } } } } else if (kind == SyntaxKind.EndOfLineTrivia) { SyntaxTrivia trivia = expression.FindTrivia(token.FullSpan.Start - 1); if (trivia.IsEndOfLineTrivia()) { textChanges.Add((leading.IsEmptyOrWhitespace()) ? leading.Span : last.Span, indentation); SetIndendation(token, prevIndex); prevIndex = trivia.SpanStart; return(true); } } prevIndex = leading.Span.Start - 1; return(true); } void SetIndendation(SyntaxToken token, int endIndex) { ImmutableArray <IndentationInfo> indentations = FindIndentations( expression, TextSpan.FromBounds(token.SpanStart, endIndex)) .ToImmutableArray(); if (!indentations.Any()) { return; } int firstIndentationLength = indentations[0].Span.Length; for (int j = 0; j < indentations.Length; j++) { IndentationInfo indentationInfo = indentations[j]; string replacement = indentation + indentationAnalysis.GetSingleIndentation(); if (j > 0 && indentationInfo.Span.Length > firstIndentationLength) { replacement += indentationInfo.ToString().Substring(firstIndentationLength); } if (indentationInfo.Span.Length != replacement.Length) { textChanges.Add(indentationInfo.Span, replacement); } } } }
private static void AnalyzeExpression(SyntaxNodeAnalysisContext context) { var expression = (ExpressionSyntax)context.Node; if (expression.IsParentKind( SyntaxKind.ConditionalAccessExpression, SyntaxKind.SimpleMemberAccessExpression, SyntaxKind.ElementAccessExpression, SyntaxKind.MemberBindingExpression, SyntaxKind.InvocationExpression)) { return; } MethodChain.Enumerator en = new MethodChain(expression).GetEnumerator(); if (!en.MoveNext()) { return; } TextLineCollection lines = null; int startLine = -1; IndentationAnalysis indentationAnalysis = default; do { context.CancellationToken.ThrowIfCancellationRequested(); SyntaxKind kind = en.Current.Kind(); if (kind == SyntaxKind.SimpleMemberAccessExpression) { var memberAccess = (MemberAccessExpressionSyntax)en.Current; if (AnalyzeToken(memberAccess.OperatorToken)) { return; } } else if (en.Current.Kind() == SyntaxKind.MemberBindingExpression) { var memberBinding = (MemberBindingExpressionSyntax)en.Current; if (AnalyzeToken(memberBinding.OperatorToken)) { return; } } } while (en.MoveNext()); bool AnalyzeToken(SyntaxToken token) { SyntaxTriviaList.Reversed.Enumerator en = token.LeadingTrivia.Reverse().GetEnumerator(); if (!en.MoveNext()) { if (lines == null) { lines = expression.SyntaxTree.GetText().Lines; startLine = lines.IndexOf(expression.SpanStart); } int endLine = lines.IndexOf(token.SpanStart); if (startLine != endLine) { ReportDiagnostic(); } return(true); } switch (en.Current.Kind()) { case SyntaxKind.WhitespaceTrivia: { if (indentationAnalysis.IsDefault) { indentationAnalysis = AnalyzeIndentation(expression); } if (en.Current.Span.Length != indentationAnalysis.IncreasedIndentationLength) { if (!en.MoveNext() || en.Current.IsEndOfLineTrivia()) { if (expression.FindTrivia(token.FullSpan.Start - 1).IsEndOfLineTrivia()) { ReportDiagnostic(); return(true); } } break; } break; } case SyntaxKind.EndOfLineTrivia: { if (expression.FindTrivia(token.FullSpan.Start - 1).IsEndOfLineTrivia()) { ReportDiagnostic(); return(true); } break; } } return(false); } void ReportDiagnostic() { DiagnosticHelpers.ReportDiagnostic( context, DiagnosticDescriptors.FixFormattingOfCallChain, expression); } }
private static void AnalyzeBinaryExpression(SyntaxNodeAnalysisContext context) { var topBinaryExpression = (BinaryExpressionSyntax)context.Node; SyntaxKind binaryKind = topBinaryExpression.Kind(); if (topBinaryExpression.IsParentKind(binaryKind)) { return; } if (topBinaryExpression.IsSingleLine(includeExteriorTrivia: false)) { return; } int?indentationLength = null; BinaryExpressionSyntax binaryExpression = topBinaryExpression; while (true) { context.CancellationToken.ThrowIfCancellationRequested(); ExpressionSyntax left = binaryExpression.Left; SyntaxToken token = binaryExpression.OperatorToken; SyntaxTriviaList leftTrailing = left.GetTrailingTrivia(); SyntaxTriviaList tokenTrailing = token.TrailingTrivia; if (IsOptionalWhitespaceThenOptionalSingleLineCommentThenEndOfLineTrivia(leftTrailing)) { if (Analyze(token)) { return; } } else if (IsOptionalWhitespaceThenOptionalSingleLineCommentThenEndOfLineTrivia(tokenTrailing)) { if (Analyze(binaryExpression.Right)) { return; } } else if (leftTrailing.IsEmptyOrWhitespace() && tokenTrailing.IsEmptyOrWhitespace()) { ReportDiagnostic(); return; } if (!left.IsKind(binaryKind)) { break; } binaryExpression = (BinaryExpressionSyntax)left; } bool Analyze(SyntaxNodeOrToken nodeOrToken) { SyntaxTriviaList.Reversed.Enumerator en = nodeOrToken.GetLeadingTrivia().Reverse().GetEnumerator(); if (!en.MoveNext()) { if ((indentationLength ??= GetIndentationLength()) == -1) { return(true); } ReportDiagnostic(); return(true); } switch (en.Current.Kind()) { case SyntaxKind.WhitespaceTrivia: { if ((indentationLength ??= GetIndentationLength()) == -1) { return(true); } if (en.Current.Span.Length != indentationLength) { if (!en.MoveNext() || en.Current.IsEndOfLineTrivia()) { if (topBinaryExpression.FindTrivia(nodeOrToken.FullSpan.Start - 1).IsEndOfLineTrivia()) { ReportDiagnostic(); return(true); } } break; } break; } case SyntaxKind.EndOfLineTrivia: { if (topBinaryExpression.FindTrivia(nodeOrToken.FullSpan.Start - 1).IsEndOfLineTrivia()) { if ((indentationLength ??= GetIndentationLength()) == -1) { return(true); } ReportDiagnostic(); return(true); } break; } } return(false); } int GetIndentationLength() { IndentationAnalysis indentationAnalysis = AnalyzeIndentation(topBinaryExpression); if (indentationAnalysis.IndentSize == 0) { return(-1); } SyntaxTriviaList leadingTrivia = topBinaryExpression.GetLeadingTrivia(); if (leadingTrivia.Any() && leadingTrivia.Last() == indentationAnalysis.Indentation && context.GetConfigOptions().GetBinaryOperatorNewLinePosition() == NewLinePosition.After) { return(indentationAnalysis.IndentationLength); } else { return(indentationAnalysis.IncreasedIndentationLength); } } void ReportDiagnostic() { DiagnosticHelpers.ReportDiagnostic( context, DiagnosticRules.FixFormattingOfBinaryExpressionChain, topBinaryExpression); } }
private static void AnalyzeCompilationUnit(SyntaxNodeAnalysisContext context) { var compilationUnit = (CompilationUnitSyntax)context.Node; SyntaxToken endOfFile = compilationUnit.EndOfFileToken; SyntaxTriviaList.Reversed.Enumerator en = endOfFile.LeadingTrivia.Reverse().GetEnumerator(); bool?preferNewLineAtEndOfFile = context.PreferNewLineAtEndOfFile(); if (preferNewLineAtEndOfFile == null) { return; } if (preferNewLineAtEndOfFile == false) { if (en.MoveNext() && (!en.Current.IsWhitespaceTrivia() || en.MoveNext())) { if (en.Current.IsEndOfLineTrivia()) { ReportDiagnostic(context, endOfFile); } else if (SyntaxFacts.IsPreprocessorDirective(en.Current.Kind()) && en.Current.GetStructure() is DirectiveTriviaSyntax directiveTrivia && directiveTrivia.GetTrailingTrivia().LastOrDefault().IsEndOfLineTrivia()) { ReportDiagnostic(context, endOfFile); } } else { SyntaxTriviaList trailing = endOfFile.GetPreviousToken().TrailingTrivia; if (trailing.Any()) { Debug.Assert(endOfFile.FullSpan.Start == trailing.Span.End); if (endOfFile.FullSpan.Start == trailing.Span.End && trailing.LastOrDefault().IsEndOfLineTrivia()) { ReportDiagnostic(context, endOfFile); } } } } else if (en.MoveNext()) { if (CSharpFacts.IsCommentTrivia(en.Current.Kind()) || SyntaxFacts.IsPreprocessorDirective(en.Current.Kind())) { ReportDiagnostic(context, endOfFile); } else if (en.Current.IsWhitespaceOrEndOfLineTrivia() && endOfFile.LeadingTrivia.Span.Start == 0) { while (en.MoveNext()) { if (!en.Current.IsWhitespaceOrEndOfLineTrivia()) { return; } } ReportDiagnostic(context, endOfFile); } } else if (endOfFile.SpanStart > 0) { SyntaxTriviaList trailing = endOfFile.GetPreviousToken().TrailingTrivia; if (!trailing.Any()) { ReportDiagnostic(context, endOfFile); } else { Debug.Assert(endOfFile.FullSpan.Start == trailing.Span.End); if (endOfFile.FullSpan.Start == trailing.Span.End && !trailing.Last().IsEndOfLineTrivia()) { ReportDiagnostic(context, endOfFile); } } }