/// <summary> /// Gets a value indicating whether the <paramref name="token"/> is preceded by a whitespace. /// </summary> /// <param name="token">The token to process.</param> /// <returns>true if token is preceded by a whitespace, otherwise false.</returns> internal static bool IsPrecededByWhitespace(this SyntaxToken token) { SyntaxTriviaList triviaList = token.LeadingTrivia; if (triviaList.Count > 0) { return(triviaList.Last().IsKind(SyntaxKind.WhitespaceTrivia)); } triviaList = token.GetPreviousToken().TrailingTrivia; return(triviaList.Count > 0 && triviaList.Last().IsKind(SyntaxKind.WhitespaceTrivia)); }
/// <summary> /// Remove all extra new lines from the begining of a close brace token. This is only called in /// the case at least one new line is present hence we don't have to worry about the single line /// case. /// </summary> private static SyntaxTriviaList RemoveNewLinesFromBottom(SyntaxTriviaList triviaList) { var index = triviaList.Count - 1; var searching = true; while (index >= 0 && searching) { var current = triviaList[index]; switch (current.Kind()) { case SyntaxKind.WhitespaceTrivia: case SyntaxKind.EndOfLineTrivia: index--; break; default: searching = false; break; } } // Nothing to adjust, the removal of new lines from the top of the list will handle all of the // important cases. if (index < 0) { return(triviaList); } var list = new List <SyntaxTrivia>(triviaList.Count); for (int i = 0; i <= index; i++) { list.Add(triviaList[i]); } // A directive has an implicit new line after it. if (!list[index].IsDirective) { list.Add(SyntaxUtil.GetBestNewLineTrivia(triviaList)); } if (triviaList.Last().IsKind(SyntaxKind.WhitespaceTrivia)) { list.Add(triviaList.Last()); } return(SyntaxFactory.TriviaList(list)); }
private static void Analyze( SyntaxNodeAnalysisContext context, UsingDirectiveSyntax usingDirective, SyntaxToken nextToken) { SyntaxTriviaList trailingTrivia = usingDirective.GetTrailingTrivia(); if (!SyntaxTriviaAnalysis.IsOptionalWhitespaceThenOptionalSingleLineCommentThenEndOfLineTrivia(triviaList: trailingTrivia)) { return; } SyntaxTriviaList.Enumerator en = nextToken.LeadingTrivia.GetEnumerator(); if (en.MoveNext()) { if (en.Current.IsWhitespaceTrivia() && !en.MoveNext()) { ReportDiagnostic(trailingTrivia.Last().SpanStart); } else { switch (en.Current.Kind()) { case SyntaxKind.SingleLineCommentTrivia: case SyntaxKind.SingleLineDocumentationCommentTrivia: case SyntaxKind.MultiLineDocumentationCommentTrivia: { ReportDiagnostic(trailingTrivia.Last().SpanStart); break; } } } } else { ReportDiagnostic(trailingTrivia.Last().SpanStart); } void ReportDiagnostic(int position) { DiagnosticHelpers.ReportDiagnostic( context, DiagnosticRules.AddBlankLineAfterUsingDirectiveList, Location.Create(usingDirective.SyntaxTree, new TextSpan(position, 0))); } }
private static void AnalyzeElseClause(SyntaxNodeAnalysisContext context) { var elseClause = (ElseClauseSyntax)context.Node; StatementSyntax statement = elseClause.Statement; if (!statement.IsKind(SyntaxKind.IfStatement)) { return; } SyntaxTriviaList trailingTrivia = elseClause.ElseKeyword.TrailingTrivia; if (!SyntaxTriviaAnalysis.IsOptionalWhitespaceThenEndOfLineTrivia(trailingTrivia)) { return; } if (!statement.GetLeadingTrivia().IsEmptyOrWhitespace()) { return; } DiagnosticHelpers.ReportDiagnostic( context, DiagnosticDescriptors.RemoveNewLineBetweenIfKeywordAndElseKeyword, Location.Create(elseClause.SyntaxTree, new TextSpan(trailingTrivia.Last().SpanStart, 0))); }
private static void AnalyzeDoStatement(SyntaxNodeAnalysisContext context) { var doStatement = (DoStatementSyntax)context.Node; StatementSyntax statement = doStatement.Statement; if (!statement.IsKind(SyntaxKind.Block)) { return; } SyntaxTriviaList trailingTrivia = statement.GetTrailingTrivia(); if (!SyntaxTriviaAnalysis.IsOptionalWhitespaceThenEndOfLineTrivia(trailingTrivia)) { return; } if (!doStatement.WhileKeyword.LeadingTrivia.IsEmptyOrWhitespace()) { return; } context.ReportDiagnostic( DiagnosticDescriptors.RemoveNewLineBetweenClosingBraceAndWhileKeyword, Location.Create(doStatement.SyntaxTree, new TextSpan(trailingTrivia.Last().SpanStart, 0))); }
private async Task <Document> AddSuppressionCommentAsync(CodeFixContext context, Diagnostic diagnostic, CancellationToken cancellationToken) { var document = context.Document; var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var node = root?.FindNode(context.Span); if (diagnostic == null || node == null || cancellationToken.IsCancellationRequested) { return(document); } var(diagnosticShortName, diagnosticJustification) = GetDiagnosticShortNameAndJustification(diagnostic); if (!string.IsNullOrWhiteSpace(diagnosticShortName)) { SyntaxTriviaList commentNode = SyntaxFactory.TriviaList( SyntaxFactory.SyntaxTrivia(SyntaxKind.SingleLineCommentTrivia, string.Format(_comment, diagnostic.Id, diagnosticShortName, diagnosticJustification)), SyntaxFactory.ElasticEndOfLine("")); while (!(node == null || node is StatementSyntax || node is MemberDeclarationSyntax)) { node = node.Parent; } SyntaxTriviaList leadingTrivia = node.GetLeadingTrivia(); var modifiedRoot = root.InsertTriviaAfter(leadingTrivia.Last(), commentNode); return(document.WithSyntaxRoot(modifiedRoot)); } return(document); }
private static void AnalyzeSwitchStatement(SyntaxNodeAnalysisContext context) { var switchStatement = (SwitchStatementSyntax)context.Node; SyntaxList <SwitchSectionSyntax> sections = switchStatement.Sections; SyntaxList <SwitchSectionSyntax> .Enumerator en = sections.GetEnumerator(); if (!en.MoveNext()) { return; } SwitchSectionSyntax previousSection = en.Current; while (en.MoveNext()) { SyntaxTriviaList leadingTrivia = en.Current.Labels[0].GetLeadingTrivia(); if (SyntaxTriviaAnalysis.IsEmptyOrSingleWhitespaceTrivia(leadingTrivia)) { SyntaxTriviaList trailingTrivia = previousSection.GetTrailingTrivia(); if (SyntaxTriviaAnalysis.IsOptionalWhitespaceThenOptionalSingleLineCommentThenEndOfLineTrivia(trailingTrivia)) { DiagnosticHelpers.ReportDiagnostic( context, DiagnosticDescriptors.AddEmptyLineBetweenSwitchSections, Location.Create(switchStatement.SyntaxTree, trailingTrivia.Last().Span.WithLength(0))); } } previousSection = en.Current; } }
internal T WithPrependedLeadingTrivia <T>(T node, SyntaxTriviaList trivia) where T : SyntaxNode { if (trivia.Count == 0) { return(node); } if (trivia.Last().IsKind(VB.SyntaxKind.CommentTrivia)) { trivia = trivia.Add(global::VisualBasicSyntaxFactory.VBEOLTrivia); } return(node.WithLeadingTrivia(trivia.Concat(node.GetLeadingTrivia()))); }
private static List <BaseFieldDeclarationSyntax> DeclarationSplitter( Document document, VariableDeclarationSyntax declaration, Func <VariableDeclarationSyntax, BaseFieldDeclarationSyntax> declarationFactory, SyntaxTriviaList declarationTrailingTrivia) { SeparatedSyntaxList <VariableDeclaratorSyntax> variables = declaration.Variables; VariableDeclaratorSyntax first = variables.First(); BaseFieldDeclarationSyntax previous = null; var newFieldDeclarations = new List <BaseFieldDeclarationSyntax>(variables.Count); foreach (SyntaxNodeOrToken nodeOrToken in variables.GetWithSeparators()) { if (previous == null) { VariableDeclaratorSyntax variable = (VariableDeclaratorSyntax)nodeOrToken.AsNode(); variable = variable.WithIdentifier(variable.Identifier.WithoutLeadingWhitespace()); var variableDeclarator = SyntaxFactory.SingletonSeparatedList(variable); previous = declarationFactory(declaration.WithVariables(variableDeclarator)); if (variable != first) { var triviaList = previous.GetLeadingTrivia().WithoutDirectiveTrivia(); previous = previous.WithLeadingTrivia(triviaList); } } else { SyntaxToken commaToken = nodeOrToken.AsToken(); SyntaxTriviaList trailingTrivia = commaToken.TrailingTrivia; if (trailingTrivia.Any()) { if (!trailingTrivia.Last().IsKind(SyntaxKind.EndOfLineTrivia)) { trailingTrivia = trailingTrivia.WithoutTrailingWhitespace().Add(FormattingHelper.GetNewLineTrivia(document)); } } else { trailingTrivia = SyntaxTriviaList.Create(FormattingHelper.GetNewLineTrivia(document)); } newFieldDeclarations.Add(previous.WithTrailingTrivia(trailingTrivia)); previous = null; } } newFieldDeclarations.Add(previous.WithTrailingTrivia(declarationTrailingTrivia)); return(newFieldDeclarations); }
private static void AnalyzeDoStatement(SyntaxNodeAnalysisContext context) { var doStatement = (DoStatementSyntax)context.Node; StatementSyntax statement = doStatement.Statement; if (!statement.IsKind(SyntaxKind.Block)) { return; } NewLineStyle newLineStyle = context.GetNewLineBeforeWhileInDoStatement(); if (newLineStyle == NewLineStyle.None) { return; } SyntaxTriviaList trailingTrivia = statement.GetTrailingTrivia(); if (!trailingTrivia.Any() || trailingTrivia.SingleOrDefault(shouldThrow: false).IsWhitespaceTrivia()) { if (!doStatement.WhileKeyword.LeadingTrivia.Any() && newLineStyle == NewLineStyle.Add) { context.ReportDiagnostic( DiagnosticRules.AddOrRemoveNewLineBeforeWhileInDoStatement, Location.Create(doStatement.SyntaxTree, new TextSpan(statement.FullSpan.End, 0)), "Add"); } } else if (SyntaxTriviaAnalysis.IsOptionalWhitespaceThenEndOfLineTrivia(trailingTrivia)) { if (doStatement.WhileKeyword.LeadingTrivia.IsEmptyOrWhitespace() && newLineStyle == NewLineStyle.Remove) { context.ReportDiagnostic( DiagnosticRules.AddOrRemoveNewLineBeforeWhileInDoStatement, Location.Create(doStatement.SyntaxTree, new TextSpan(trailingTrivia.Last().SpanStart, 0)), properties: DiagnosticProperties.AnalyzerOption_Invert, "Remove"); } } }
private static void Analyze(SyntaxNodeAnalysisContext context, BaseListSyntax baseList, SyntaxToken previousToken) { SyntaxTriviaList trailingTrivia = previousToken.TrailingTrivia; if (!SyntaxTriviaAnalysis.IsOptionalWhitespaceThenEndOfLineTrivia(trailingTrivia)) { return; } if (!baseList.ColonToken.LeadingTrivia.IsEmptyOrWhitespace()) { return; } context.ReportDiagnostic( DiagnosticDescriptors.RemoveNewLineBeforeBaseList, Location.Create(baseList.SyntaxTree, new TextSpan(trailingTrivia.Last().SpanStart, 0))); }
internal static bool IsFixable(ExpressionSyntax expression, SyntaxToken token) { SyntaxTriviaList expressionTrailing = expression.GetTrailingTrivia(); if (expressionTrailing.IsEmptyOrWhitespace()) { SyntaxTriviaList tokenLeading = token.LeadingTrivia; if (tokenLeading.IsEmptyOrWhitespace()) { SyntaxTriviaList tokenTrailing = token.TrailingTrivia; int count = tokenTrailing.Count; if (count == 1) { if (tokenTrailing[0].IsEndOfLineTrivia()) { return(true); } } else if (count > 1) { for (int i = 0; i < count - 1; i++) { if (!tokenTrailing[i].IsWhitespaceTrivia()) { return(false); } } if (tokenTrailing.Last().IsEndOfLineTrivia()) { return(true); } } } } return(false); }
private static void AnalyzeSwitchStatement(SyntaxNodeAnalysisContext context) { var switchStatement = (SwitchStatementSyntax)context.Node; SyntaxList <SwitchSectionSyntax> sections = switchStatement.Sections; SyntaxList <SwitchSectionSyntax> .Enumerator en = sections.GetEnumerator(); if (!en.MoveNext()) { return; } SwitchSectionSyntax previousSection = en.Current; var previousBlock = previousSection.Statements.SingleOrDefault(shouldThrow: false) as BlockSyntax; while (en.MoveNext()) { SyntaxTriviaList leadingTrivia = en.Current.Labels[0].GetLeadingTrivia(); if (SyntaxTriviaAnalysis.IsEmptyOrSingleWhitespaceTrivia(leadingTrivia)) { SyntaxTriviaList trailingTrivia = previousSection.GetTrailingTrivia(); if (SyntaxTriviaAnalysis.IsOptionalWhitespaceThenOptionalSingleLineCommentThenEndOfLineTrivia(trailingTrivia) && (context.GetBlankLineBetweenClosingBraceAndSwitchSection() != false || previousBlock == null)) { DiagnosticHelpers.ReportDiagnostic( context, DiagnosticRules.AddBlankLineBetweenSwitchSections, Location.Create(switchStatement.SyntaxTree, trailingTrivia.Last().Span.WithLength(0))); } } previousSection = en.Current; previousBlock = en.Current.Statements.SingleOrDefault(shouldThrow: false) as BlockSyntax; } }
private static Task <Document> AddBlankLineBeforeUsingDirectiveAsync( Document document, UsingDirectiveSyntax usingDirective, CancellationToken cancellationToken) { SyntaxTriviaList leadingTrivia = usingDirective.GetLeadingTrivia(); int index = leadingTrivia.Count; if (index > 0 && leadingTrivia.Last().IsWhitespaceTrivia()) { index--; } SyntaxTriviaList newLeadingTrivia = leadingTrivia.Insert(index, SyntaxTriviaAnalysis.DetermineEndOfLine(usingDirective)); UsingDirectiveSyntax newUsingDirective = usingDirective.WithLeadingTrivia(newLeadingTrivia); return(document.ReplaceNodeAsync(usingDirective, newUsingDirective, cancellationToken)); }
private static void AnalyzeDoStatement(SyntaxNodeAnalysisContext context) { var doStatement = (DoStatementSyntax)context.Node; StatementSyntax statement = doStatement.Statement; if (!statement.IsKind(SyntaxKind.Block)) { return; } SyntaxTriviaList trailingTrivia = statement.GetTrailingTrivia(); if (!trailingTrivia.Any() || trailingTrivia.SingleOrDefault(shouldThrow: false).IsWhitespaceTrivia()) { if (!doStatement.WhileKeyword.LeadingTrivia.Any() && !AnalyzerOptions.RemoveNewLineBetweenClosingBraceAndWhileKeyword.IsEnabled(context)) { context.ReportDiagnostic( DiagnosticRules.AddNewLineBetweenClosingBraceAndWhileKeywordOrViceVersa, Location.Create(doStatement.SyntaxTree, new TextSpan(statement.FullSpan.End, 0)), AnalyzerOptions.RemoveNewLineBetweenClosingBraceAndWhileKeyword); } } else if (SyntaxTriviaAnalysis.IsOptionalWhitespaceThenEndOfLineTrivia(trailingTrivia)) { if (doStatement.WhileKeyword.LeadingTrivia.IsEmptyOrWhitespace() && AnalyzerOptions.RemoveNewLineBetweenClosingBraceAndWhileKeyword.IsEnabled(context)) { context.ReportDiagnostic( DiagnosticRules.ReportOnly.RemoveNewLineBetweenClosingBraceAndWhileKeyword, Location.Create(doStatement.SyntaxTree, new TextSpan(trailingTrivia.Last().SpanStart, 0)), properties: DiagnosticProperties.AnalyzerOption_Invert, AnalyzerOptions.RemoveNewLineBetweenClosingBraceAndWhileKeyword); } } }
private static SyntaxTrivia GetIndentation(SyntaxNode node, CancellationToken cancellationToken = default(CancellationToken)) { SyntaxTree tree = node.SyntaxTree; if (tree != null) { TextSpan span = node.Span; int lineStartIndex = span.Start - tree.GetLineSpan(span, cancellationToken).StartLinePosition.Character; while (!node.FullSpan.Contains(lineStartIndex)) { node = node.Parent; } SyntaxToken token = node.FindToken(lineStartIndex); if (!token.IsKind(SyntaxKind.None)) { SyntaxTriviaList leadingTrivia = token.LeadingTrivia; if (leadingTrivia.Any() && leadingTrivia.FullSpan.Contains(lineStartIndex)) { SyntaxTrivia trivia = leadingTrivia.Last(); if (trivia.IsWhitespaceTrivia()) { return(trivia); } } } } return(EmptyWhitespace()); }
internal static List <TextChange> GetFixListChanges <TNode>( SyntaxNode containingNode, SyntaxNodeOrToken openNodeOrToken, IReadOnlyList <TNode> nodes, ListFixMode fixMode = ListFixMode.Fix, CancellationToken cancellationToken = default) where TNode : SyntaxNode { IndentationAnalysis indentationAnalysis = AnalyzeIndentation(containingNode, cancellationToken); string increasedIndentation = indentationAnalysis.GetIncreasedIndentation(); bool isSingleLine; SeparatedSyntaxList <TNode> separatedList = default; if (nodes is SyntaxList <TNode> list) { isSingleLine = list.IsSingleLine(includeExteriorTrivia: false, cancellationToken: cancellationToken); } else { separatedList = (SeparatedSyntaxList <TNode>)nodes; isSingleLine = separatedList.IsSingleLine( includeExteriorTrivia: false, cancellationToken: cancellationToken); } if (isSingleLine && fixMode == ListFixMode.Fix) { TNode node = nodes[0]; SyntaxTriviaList leading = node.GetLeadingTrivia(); TextSpan span = (leading.Any() && leading.Last().IsWhitespaceTrivia()) ? leading.Last().Span : new TextSpan(node.SpanStart, 0); return(new List <TextChange>() { new TextChange(span, increasedIndentation) }); } var textChanges = new List <TextChange>(); TextLineCollection lines = null; string endOfLine = DetermineEndOfLine(containingNode).ToString(); for (int i = 0; i < nodes.Count; i++) { SyntaxToken token; if (i == 0) { token = (openNodeOrToken.IsNode) ? openNodeOrToken.AsNode().GetLastToken() : openNodeOrToken.AsToken(); } else { token = (list == default) ? separatedList.GetSeparator(i - 1) : list[i - 1].GetLastToken(); } SyntaxTriviaList trailing = token.TrailingTrivia; TNode node = nodes[i]; var indentationAdded = false; if (IsOptionalWhitespaceThenOptionalSingleLineCommentThenEndOfLineTrivia(trailing)) { SyntaxTrivia last = node.GetLeadingTrivia().LastOrDefault(); if (last.IsWhitespaceTrivia()) { if (last.Span.Length == increasedIndentation.Length) { continue; } textChanges.Add(last.Span, increasedIndentation); } else { textChanges.Add(new TextSpan(node.SpanStart, 0), increasedIndentation); } indentationAdded = true; } else { if (nodes.Count == 1 && node is ArgumentSyntax argument) { LambdaBlock lambdaBlock = GetLambdaBlock(argument, lines ??= argument.SyntaxTree.GetText().Lines); if (lambdaBlock.Block != null) { increasedIndentation = indentationAnalysis.Indentation.ToString(); } } if ((nodes.Count > 1 || fixMode == ListFixMode.Wrap) && ShouldWrapAndIndent(containingNode, i)) { textChanges.Add( (trailing.Any() && trailing.Last().IsWhitespaceTrivia()) ? trailing.Last().Span : new TextSpan(token.FullSpan.End, 0), endOfLine); textChanges.Add(new TextSpan(node.FullSpan.Start, 0), increasedIndentation); indentationAdded = true; } } ImmutableArray <IndentationInfo> indentations = FindIndentations(node, node.Span).ToImmutableArray(); if (!indentations.Any()) { continue; } LambdaBlock lambdaBlock2 = GetLambdaBlock(node, lines ??= node.SyntaxTree.GetText().Lines); bool isLambdaBlockWithOpenBraceAtEndOfLine = lambdaBlock2.Token == indentations.Last().Token; int baseIndentationLength = (isLambdaBlockWithOpenBraceAtEndOfLine) ? indentations.Last().Span.Length : indentations[0].Span.Length; for (int j = indentations.Length - 1; j >= 0; j--) { IndentationInfo indentationInfo = indentations[j]; if (indentationAdded && node is ArgumentSyntax argument && (argument.Expression as AnonymousFunctionExpressionSyntax)?.Block != null) { indentationAdded = false; } string replacement = increasedIndentation; if (indentationAdded) { replacement += indentationAnalysis.GetSingleIndentation(); } if ((j > 0 || isLambdaBlockWithOpenBraceAtEndOfLine) && indentationInfo.Span.Length > baseIndentationLength) { replacement += indentationInfo.ToString().Substring(baseIndentationLength); } if (indentationInfo.Span.Length != replacement.Length) { textChanges.Add(indentationInfo.Span, replacement); } } } FormattingVerifier.VerifyChangedSpansAreWhitespace(containingNode, textChanges); return(textChanges); }
private static void AnalyzeAccessorList(SyntaxNodeAnalysisContext context) { var accessorList = (AccessorListSyntax)context.Node; SyntaxList <AccessorDeclarationSyntax> accessors = accessorList.Accessors; if (accessors.Count <= 1) { return; } Debug.Assert(accessors.Count == 2, accessors.Count.ToString()); AccessorDeclarationSyntax accessor1 = accessors[0]; if (accessor1.BodyOrExpressionBody() == null) { return; } AccessorDeclarationSyntax accessor2 = accessors[1]; if (accessor2.BodyOrExpressionBody() == null) { return; } SyntaxTriviaList trailingTrivia = accessor1.GetTrailingTrivia(); if (!SyntaxTriviaAnalysis.IsOptionalWhitespaceThenOptionalSingleLineCommentThenEndOfLineTrivia(trailingTrivia)) { return; } SyntaxTriviaList leadingTrivia = accessor2.GetLeadingTrivia(); bool isEmptyLine = SyntaxTriviaAnalysis.StartsWithOptionalWhitespaceThenEndOfLineTrivia(leadingTrivia); if (accessorList.SyntaxTree.IsSingleLineSpan(accessor1.Span, context.CancellationToken) && accessorList.SyntaxTree.IsSingleLineSpan(accessor2.Span, context.CancellationToken)) { if (isEmptyLine) { ReportDiagnostic(context, DiagnosticDescriptors.RemoveEmptyLineBetweenSingleLineAccessors, leadingTrivia[0]); } else { ReportDiagnostic(context, DiagnosticDescriptors.AddEmptyLineBetweenSingleLineAccessors, trailingTrivia.Last()); } } else if (!isEmptyLine) { ReportDiagnostic(context, DiagnosticDescriptors.AddEmptyLineBetweenAccessors, trailingTrivia.Last()); } }
public SyntaxNode TraverseAndConvert(SyntaxNode node, SyntaxNode newNode) { // Step 1: Handle current node // Find out if this node is a documentable API declaration // If not, skip to go to the child nodes. string docCommentId = GetAPIForNode(node); if (docCommentId != null) { // Look up the comment text string docCommentText = GetDocCommentForId(docCommentId); // Get the SyntaxTrivia for the comment SyntaxTree newTree = (CSharpSyntaxTree)CSharpSyntaxTree.ParseText(docCommentText); var newTrivia = newTree.GetRoot().GetLeadingTrivia(); // Read a doc comment from a syntax tree. //var classNode = (ClassDeclarationSyntax)newTree.GetRoot().ChildNodes().First(); //var newTrivia = classNode.GetLeadingTrivia(); //var docCommentTrivia = newTrivia.Single(t => t.Kind() == SyntaxKind.SingleLineDocumentationCommentTrivia || // t.Kind() == SyntaxKind.MultiLineDocumentationCommentTrivia); // Find out if there is an existing comment or doc comment if (node.HasLeadingTrivia) { SyntaxTriviaList triviaList = node.GetLeadingTrivia(); SyntaxTrivia firstComment = triviaList.Last(); foreach (var trivia in triviaList.Reverse()) { SyntaxKind kind = trivia.Kind(); switch (kind) { case SyntaxKind.SingleLineCommentTrivia: case SyntaxKind.MultiLineCommentTrivia: // Found existing comment firstComment = trivia; break; case SyntaxKind.MultiLineDocumentationCommentTrivia: case SyntaxKind.SingleLineDocumentationCommentTrivia: // Found existing XML doc comment firstComment = trivia; break; default: break; } } // Append the doc comment newNode = node.InsertTriviaBefore(firstComment, newTrivia); } else // no leading trivia { newNode = node.WithLeadingTrivia(newTrivia); } } else // not an API node { newNode = node; } if (node.ChildNodes().Count() > 0) { newNode = newNode.ReplaceNodes(newNode.ChildNodes(), TraverseAndConvert); } return(newNode); }
private static void AnalyzeUsings(SyntaxNodeAnalysisContext context, SyntaxList <UsingDirectiveSyntax> usings) { int count = usings.Count; if (count <= 1) { return; } UsingDirectiveSyntax usingDirective1 = usings[0]; for (int i = 1; i < count; i++, usingDirective1 = usings[i - 1]) { if (usingDirective1.StaticKeyword.IsKind(SyntaxKind.StaticKeyword)) { return; } if (usingDirective1.Alias != null) { return; } UsingDirectiveSyntax usingDirective2 = usings[i]; if (usingDirective2.StaticKeyword.IsKind(SyntaxKind.StaticKeyword)) { return; } if (usingDirective2.Alias != null) { return; } SyntaxTriviaList trailingTrivia = usingDirective1.GetTrailingTrivia(); if (!SyntaxTriviaAnalysis.IsOptionalWhitespaceThenOptionalSingleLineCommentThenEndOfLineTrivia(trailingTrivia)) { continue; } IdentifierNameSyntax rootNamespace1 = usingDirective1.GetRootNamespace(); if (rootNamespace1 == null) { continue; } IdentifierNameSyntax rootNamespace2 = usingDirective2.GetRootNamespace(); if (rootNamespace2 == null) { continue; } SyntaxTriviaList leadingTrivia = usingDirective2.GetLeadingTrivia(); bool isEmptyLine = SyntaxTriviaAnalysis.StartsWithOptionalWhitespaceThenEndOfLineTrivia(leadingTrivia); if (string.Equals(rootNamespace1.Identifier.ValueText, rootNamespace2.Identifier.ValueText, StringComparison.Ordinal)) { if (isEmptyLine) { DiagnosticHelpers.ReportDiagnosticIfNotSuppressed( context, DiagnosticDescriptors.RemoveEmptyLineBetweenUsingDirectivesWithSameRootNamespace, Location.Create(context.Node.SyntaxTree, leadingTrivia[0].Span.WithLength(0))); } } else if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.AddEmptyLineBetweenUsingDirectivesWithDifferentRootNamespaceOrViceVersa)) { if (isEmptyLine) { if (!context.IsAnalyzerSuppressed(AnalyzerOptions.RemoveEmptyLineBetweenUsingDirectivesWithDifferentRootNamespace)) { DiagnosticHelpers.ReportDiagnostic( context, DiagnosticDescriptors.ReportOnly.RemoveEmptyLineBetweenUsingDirectivesWithDifferentRootNamespace, Location.Create(context.Node.SyntaxTree, leadingTrivia[0].Span.WithLength(0)), properties: DiagnosticProperties.AnalyzerOption_Invert); } } else if (context.IsAnalyzerSuppressed(AnalyzerOptions.RemoveEmptyLineBetweenUsingDirectivesWithDifferentRootNamespace)) { DiagnosticHelpers.ReportDiagnostic( context, DiagnosticDescriptors.AddEmptyLineBetweenUsingDirectivesWithDifferentRootNamespaceOrViceVersa, Location.Create(context.Node.SyntaxTree, trailingTrivia.Last().Span.WithLength(0))); } } } }
private static void HandleSemicolonToken(SyntaxTreeAnalysisContext context, SyntaxToken token) { if (token.IsMissing) { return; } // check for a following space bool missingFollowingSpace = true; if (token.HasTrailingTrivia) { if (token.TrailingTrivia.First().IsKind(SyntaxKind.WhitespaceTrivia)) { missingFollowingSpace = false; } else if (token.TrailingTrivia.First().IsKind(SyntaxKind.EndOfLineTrivia)) { missingFollowingSpace = false; } } else { SyntaxToken nextToken = token.GetNextToken(); switch (nextToken.Kind()) { case SyntaxKind.CloseParenToken: // Special handling for the following case: // for (; ;) missingFollowingSpace = false; break; case SyntaxKind.SemicolonToken: // Special handling for the following case: // Statement();; if (nextToken.Parent.IsKind(SyntaxKind.EmptyStatement)) { missingFollowingSpace = false; } break; case SyntaxKind.None: // The semi colon is the last character in the file. return; default: break; } } bool hasPrecedingSpace = false; bool ignorePrecedingSpace = false; if (!token.IsFirstInLine()) { // only the first token on the line has leading trivia, and those are ignored SyntaxToken precedingToken = token.GetPreviousToken(); SyntaxTriviaList trailingTrivia = precedingToken.TrailingTrivia; if (trailingTrivia.Any() && trailingTrivia.Last().IsKind(SyntaxKind.WhitespaceTrivia)) { hasPrecedingSpace = true; } if (precedingToken.IsKind(SyntaxKind.SemicolonToken)) { // Special handling for the following case: // for (; ;) ignorePrecedingSpace = true; } } if (missingFollowingSpace) { // semicolon should{} be {followed} by a space context.ReportDiagnostic(Diagnostic.Create(Descriptor, token.GetLocation(), TokenSpacingProperties.InsertFollowing, string.Empty, "followed")); } if (hasPrecedingSpace && !ignorePrecedingSpace) { // semicolon should{ not} be {preceded} by a space context.ReportDiagnostic(Diagnostic.Create(Descriptor, token.GetLocation(), TokenSpacingProperties.RemoveImmediatePreceding, " not", "preceded")); } }
public override async Task RegisterCodeFixesAsync(CodeFixContext context) { SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false); if (!TryFindFirstAncestorOrSelf(root, context.Span, out CompilationUnitSyntax compilationUnit)) { return; } Document document = context.Document; Diagnostic diagnostic = context.Diagnostics[0]; switch (diagnostic.Id) { case DiagnosticIdentifiers.NormalizeWhitespaceAtEndOfFile: { bool preferNewLineAtEndOfFile = document.GetConfigOptions(compilationUnit.SyntaxTree).PreferNewLineAtEndOfFile() ?? false; CodeAction codeAction = CodeAction.Create( (preferNewLineAtEndOfFile) ? CodeFixTitles.AddNewLine : CodeFixTitles.RemoveNewLine, ct => { SyntaxToken endOfFile = compilationUnit.EndOfFileToken; SyntaxTriviaList leading = endOfFile.LeadingTrivia; SyntaxToken oldToken; SyntaxToken newToken; if (!preferNewLineAtEndOfFile) { if (leading.Any()) { SyntaxTrivia last = leading.Last(); if (last.GetStructure() is DirectiveTriviaSyntax directive) { SyntaxTriviaList trailing = directive.GetTrailingTrivia(); DirectiveTriviaSyntax newDirective = directive.WithTrailingTrivia(trailing.RemoveAt(trailing.Count - 1)); return(document.ReplaceNodeAsync(directive, newDirective, ct)); } else { oldToken = endOfFile; int index = leading.Count - 1; for (int i = leading.Count - 2; i >= 0; i--) { if (leading[i].IsWhitespaceOrEndOfLineTrivia()) { index--; } } newToken = oldToken.WithLeadingTrivia(leading.RemoveRange(index, leading.Count - index)); } } else { oldToken = endOfFile.GetPreviousToken(); SyntaxTriviaList trailing = oldToken.TrailingTrivia; newToken = oldToken.WithTrailingTrivia(trailing.RemoveAt(trailing.Count - 1)); } } else if (leading.Any()) { oldToken = endOfFile; if (leading.Span.Start == 0 && leading.All(f => f.IsWhitespaceOrEndOfLineTrivia())) { newToken = oldToken.WithoutLeadingTrivia(); } else { newToken = oldToken.AppendEndOfLineToLeadingTrivia(); } } else { oldToken = endOfFile.GetPreviousToken(); newToken = oldToken.AppendEndOfLineToTrailingTrivia(); } return(document.ReplaceTokenAsync(oldToken, newToken, ct)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } } }
private static void AnalyzeEnumDeclaration(SyntaxNodeAnalysisContext context) { var enumDeclaration = (EnumDeclarationSyntax)context.Node; SeparatedSyntaxList <EnumMemberDeclarationSyntax> members = enumDeclaration.Members; int count = members.Count; if (count <= 1) { return; } SyntaxTree tree = enumDeclaration.SyntaxTree; CancellationToken cancellationToken = context.CancellationToken; EnumMemberDeclarationSyntax member; bool?isSingleLine; bool?isPreviousSingleLine = null; for (int i = 1; i < count; i++, isPreviousSingleLine = isSingleLine) { member = members[i]; isSingleLine = null; SyntaxToken commaToken = members.GetSeparator(i - 1); SyntaxTriviaList trailingTrivia = commaToken.TrailingTrivia; if (!SyntaxTriviaAnalysis.IsOptionalWhitespaceThenOptionalSingleLineCommentThenEndOfLineTrivia(trailingTrivia)) { continue; } SyntaxTriviaList leadingTrivia = member.GetLeadingTrivia(); (bool emptyOrWhitespaceTrivia, bool documentationComment, bool emptyLine) = AnalyzeLeadingTrivia(leadingTrivia); if (documentationComment) { ReportDiagnostic(context, DiagnosticDescriptors.AddEmptyLineBetweenDeclarationAndDocumentationComment, trailingTrivia.Last()); continue; } if (!emptyOrWhitespaceTrivia && !emptyLine) { continue; } if ((isSingleLine ?? (isSingleLine = tree.IsSingleLineSpan(member.Span, cancellationToken)).Value) && (isPreviousSingleLine ?? tree.IsSingleLineSpan(members[i - 1].Span, cancellationToken))) { if (emptyLine) { ReportDiagnostic(context, DiagnosticDescriptors.RemoveEmptyLineBetweenSingleLineDeclarationsOfSameKind, leadingTrivia[0]); } else if (emptyOrWhitespaceTrivia) { ReportDiagnostic(context, DiagnosticDescriptors.AddEmptyLineBetweenSingleLineDeclarations, trailingTrivia.Last()); } } else if (emptyOrWhitespaceTrivia) { ReportDiagnostic(context, DiagnosticDescriptors.AddEmptyLineBetweenDeclarations, trailingTrivia.Last()); } } }
private static void Analyze(SyntaxNodeAnalysisContext context, SyntaxList <MemberDeclarationSyntax> members) { int count = members.Count; if (count <= 1) { return; } SyntaxTree tree = context.Node.SyntaxTree; CancellationToken cancellationToken = context.CancellationToken; MemberDeclarationSyntax member; MemberDeclarationSyntax previousMember = members[0]; bool?isSingleLine; bool?isPreviousSingleLine = null; for (int i = 1; i < count; i++, previousMember = member, isPreviousSingleLine = isSingleLine) { member = members[i]; isSingleLine = null; SyntaxTriviaList trailingTrivia = previousMember.GetTrailingTrivia(); if (!SyntaxTriviaAnalysis.IsOptionalWhitespaceThenOptionalSingleLineCommentThenEndOfLineTrivia(trailingTrivia)) { continue; } SyntaxTriviaList leadingTrivia = member.GetLeadingTrivia(); (bool emptyOrWhitespaceTrivia, bool documentationComment, bool emptyLine) = AnalyzeLeadingTrivia(leadingTrivia); if (documentationComment) { ReportDiagnostic(context, DiagnosticDescriptors.AddEmptyLineBetweenDeclarationAndDocumentationComment, trailingTrivia.Last()); continue; } if (!emptyOrWhitespaceTrivia && !emptyLine) { continue; } if ((isSingleLine ?? (isSingleLine = tree.IsSingleLineSpan(member.Span, cancellationToken)).Value) && (isPreviousSingleLine ?? tree.IsSingleLineSpan(members[i - 1].Span, cancellationToken))) { if (emptyLine) { if (MemberKindEquals(previousMember, member)) { ReportDiagnostic(context, DiagnosticDescriptors.RemoveEmptyLineBetweenSingleLineDeclarationsOfSameKind, leadingTrivia[0]); } } else if (emptyOrWhitespaceTrivia) { ReportDiagnostic(context, DiagnosticDescriptors.AddEmptyLineBetweenSingleLineDeclarations, trailingTrivia.Last()); if (!MemberKindEquals(previousMember, member)) { ReportDiagnostic(context, DiagnosticDescriptors.AddEmptyLineBetweenSingleLineDeclarationsOfDifferentKind, trailingTrivia.Last()); } } } else if (emptyOrWhitespaceTrivia) { ReportDiagnostic(context, DiagnosticDescriptors.AddEmptyLineBetweenDeclarations, trailingTrivia.Last()); } } }
public static SyntaxTrivia LastOrDefault(this SyntaxTriviaList triviaList) => triviaList.Any() ? triviaList.Last() : default;
private static void AnalyzeUsings(SyntaxNodeAnalysisContext context, SyntaxList <UsingDirectiveSyntax> usings) { int count = usings.Count; if (count <= 1) { return; } UsingDirectiveSyntax usingDirective1 = usings[0]; for (int i = 1; i < count; i++, usingDirective1 = usings[i - 1]) { if (usingDirective1.StaticKeyword.IsKind(SyntaxKind.StaticKeyword)) { return; } if (usingDirective1.Alias != null) { return; } UsingDirectiveSyntax usingDirective2 = usings[i]; if (usingDirective2.StaticKeyword.IsKind(SyntaxKind.StaticKeyword)) { return; } if (usingDirective2.Alias != null) { return; } SyntaxTriviaList trailingTrivia = usingDirective1.GetTrailingTrivia(); if (!SyntaxTriviaAnalysis.IsOptionalWhitespaceThenOptionalSingleLineCommentThenEndOfLineTrivia(trailingTrivia)) { continue; } IdentifierNameSyntax rootNamespace1 = usingDirective1.GetRootNamespace(); if (rootNamespace1 == null) { continue; } IdentifierNameSyntax rootNamespace2 = usingDirective2.GetRootNamespace(); if (rootNamespace2 == null) { continue; } SyntaxTriviaList leadingTrivia = usingDirective2.GetLeadingTrivia(); bool isEmptyLine = SyntaxTriviaAnalysis.StartsWithOptionalWhitespaceThenEndOfLineTrivia(leadingTrivia); if (string.Equals(rootNamespace1.Identifier.ValueText, rootNamespace2.Identifier.ValueText, StringComparison.Ordinal)) { if (isEmptyLine) { if (DiagnosticRules.RemoveBlankLineBetweenUsingDirectivesWithSameRootNamespace.IsEffective(context)) { DiagnosticHelpers.ReportDiagnostic( context, DiagnosticRules.RemoveBlankLineBetweenUsingDirectivesWithSameRootNamespace, Location.Create(context.Node.SyntaxTree, leadingTrivia[0].Span.WithLength(0))); } if (DiagnosticRules.BlankLineBetweenUsingDirectives.IsEffective(context) && context.GetBlankLineBetweenUsingDirectives() == UsingDirectiveBlankLineStyle.Never) { DiagnosticHelpers.ReportDiagnostic( context, DiagnosticRules.BlankLineBetweenUsingDirectives, Location.Create(context.Node.SyntaxTree, leadingTrivia[0].Span.WithLength(0)), properties: DiagnosticProperties.AnalyzerOption_Invert, "Remove"); } } } else if (DiagnosticRules.BlankLineBetweenUsingDirectives.IsEffective(context)) { UsingDirectiveBlankLineStyle style = context.GetBlankLineBetweenUsingDirectives(); if (isEmptyLine) { if (style == UsingDirectiveBlankLineStyle.Never) { DiagnosticHelpers.ReportDiagnostic( context, DiagnosticRules.BlankLineBetweenUsingDirectives, Location.Create(context.Node.SyntaxTree, leadingTrivia[0].Span.WithLength(0)), properties: DiagnosticProperties.AnalyzerOption_Invert, "Remove"); } } else if (style == UsingDirectiveBlankLineStyle.SeparateGroups) { DiagnosticHelpers.ReportDiagnostic( context, DiagnosticRules.BlankLineBetweenUsingDirectives, Location.Create(context.Node.SyntaxTree, trailingTrivia.Last().Span.WithLength(0)), "Add"); } } } }
/// <summary> /// Remove all extra new lines from the begining of a close brace token. This is only called in /// the case at least one new line is present hence we don't have to worry about the single line /// case. /// </summary> private static SyntaxTriviaList RemoveNewLinesFromBottom(SyntaxTriviaList triviaList) { var index = triviaList.Count - 1; var searching = true; while (index >= 0 && searching) { var current = triviaList[index]; switch (current.Kind()) { case SyntaxKind.WhitespaceTrivia: case SyntaxKind.EndOfLineTrivia: index--; break; default: searching = false; break; } } // Nothing to adjust, the removal of new lines from the top of the list will handle all of the // important cases. if (index < 0) { return triviaList; } var list = new List<SyntaxTrivia>(triviaList.Count); for (int i = 0; i <= index; i++) { list.Add(triviaList[i]); } // A directive has an implicit new line after it. if (!list[index].IsDirective) { list.Add(SyntaxUtil.GetBestNewLineTrivia(triviaList)); } if (triviaList.Last().IsKind(SyntaxKind.WhitespaceTrivia)) { list.Add(triviaList.Last()); } return SyntaxFactory.TriviaList(list); }
private static List <BaseFieldDeclarationSyntax> DeclarationSplitter( Document document, VariableDeclarationSyntax declaration, Func <VariableDeclarationSyntax, BaseFieldDeclarationSyntax> declarationFactory, SyntaxTriviaList declarationTrailingTrivia) { SeparatedSyntaxList <VariableDeclaratorSyntax> variables = declaration.Variables; VariableDeclaratorSyntax first = variables.First(); BaseFieldDeclarationSyntax previous = null; var newFieldDeclarations = new List <BaseFieldDeclarationSyntax>(variables.Count); foreach (SyntaxNodeOrToken nodeOrToken in variables.GetWithSeparators()) { if (previous == null) { VariableDeclaratorSyntax variable = (VariableDeclaratorSyntax)nodeOrToken.AsNode(); variable = variable.WithIdentifier(variable.Identifier.WithoutLeadingWhitespace()); var variableDeclarator = SyntaxFactory.SingletonSeparatedList(variable); previous = declarationFactory(declaration.WithVariables(variableDeclarator)); if (variable != first) { var triviaList = previous.GetLeadingTrivia().WithoutDirectiveTrivia(); // Remove all leading blank lines var nonBlankLinetriviaIndex = TriviaHelper.IndexOfFirstNonBlankLineTrivia(triviaList); if (nonBlankLinetriviaIndex > 0) { triviaList = triviaList.RemoveRange(0, nonBlankLinetriviaIndex); } // Add a blank line if the first line contains a comment. var nonWhitespaceTriviaIndex = TriviaHelper.IndexOfFirstNonWhitespaceTrivia(triviaList, false); if (nonWhitespaceTriviaIndex >= 0) { switch (triviaList[nonWhitespaceTriviaIndex].Kind()) { case SyntaxKind.SingleLineCommentTrivia: case SyntaxKind.MultiLineCommentTrivia: triviaList = triviaList.Insert(0, SyntaxFactory.CarriageReturnLineFeed); break; } } previous = previous.WithLeadingTrivia(triviaList); } } else { SyntaxToken commaToken = nodeOrToken.AsToken(); SyntaxTriviaList trailingTrivia = commaToken.TrailingTrivia; if (trailingTrivia.Any()) { if (!trailingTrivia.Last().IsKind(SyntaxKind.EndOfLineTrivia)) { trailingTrivia = trailingTrivia.WithoutTrailingWhitespace().Add(FormattingHelper.GetNewLineTrivia(document)); } } else { trailingTrivia = SyntaxTriviaList.Create(FormattingHelper.GetNewLineTrivia(document)); } newFieldDeclarations.Add(previous.WithTrailingTrivia(trailingTrivia)); previous = null; } } newFieldDeclarations.Add(previous.WithTrailingTrivia(declarationTrailingTrivia)); return(newFieldDeclarations); }
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 Analyze <TNode>( SyntaxNodeAnalysisContext context, SyntaxNodeOrToken openNodeOrToken, SeparatedSyntaxList <TNode> nodes) where TNode : SyntaxNode { TNode first = nodes.FirstOrDefault(); if (first == null) { return; } TextSpan span = nodes.GetSpan(includeExteriorTrivia: false); if (span.IsSingleLine(first.SyntaxTree)) { SyntaxTriviaList trailing = openNodeOrToken.GetTrailingTrivia(); if (!IsOptionalWhitespaceThenOptionalSingleLineCommentThenEndOfLineTrivia(trailing)) { return; } int indentationLength = GetIncreasedIndentationLength(openNodeOrToken.Parent); if (indentationLength == 0) { return; } if (ShouldFixIndentation(first.GetLeadingTrivia(), indentationLength)) { ReportDiagnostic(); } } else { TextLineCollection lines = null; IndentationAnalysis indentationAnalysis = IndentationAnalysis.Create(openNodeOrToken.Parent); int indentationLength = indentationAnalysis.IncreasedIndentationLength; if (indentationLength == 0) { return; } for (int i = nodes.Count - 1; i >= 0; i--) { SyntaxTriviaList trailing = (i == 0) ? openNodeOrToken.GetTrailingTrivia() : nodes.GetSeparator(i - 1).TrailingTrivia; if (IsOptionalWhitespaceThenOptionalSingleLineCommentThenEndOfLineTrivia(trailing)) { if (ShouldFixIndentation(nodes[i].GetLeadingTrivia(), indentationLength)) { ReportDiagnostic(); break; } } else { if (nodes.Count > 1 && ShouldWrapAndIndent(context.Node, i)) { ReportDiagnostic(); break; } if (nodes.Count == 1 && first.IsKind(SyntaxKind.Argument)) { var argument = (ArgumentSyntax)(SyntaxNode)first; LambdaBlock lambdaBlock = GetLambdaBlock(argument, lines ??= first.SyntaxTree.GetText().Lines); if (lambdaBlock.Block != null) { 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; } return; } } if (lines == null) { lines = first.SyntaxTree.GetText().Lines; } int lineIndex = lines.IndexOf(span.Start); if (lineIndex < lines.Count - 1) { int lineStartIndex = lines[lineIndex + 1].Start; if (first.Span.Contains(lineStartIndex)) { SyntaxToken token = first.FindToken(lineStartIndex); if (!token.IsKind(SyntaxKind.None)) { SyntaxTriviaList leading = token.LeadingTrivia; if (leading.Any()) { if (leading.FullSpan.Contains(lineStartIndex)) { SyntaxTrivia trivia = leading.Last(); if (trivia.IsWhitespaceTrivia() && trivia.SpanStart == lineStartIndex && trivia.Span.Length != indentationLength) { ReportDiagnostic(); break; } } } else if (lineStartIndex == token.SpanStart) { ReportDiagnostic(); break; } } } } } } } void ReportDiagnostic() { DiagnosticHelpers.ReportDiagnostic( context, DiagnosticDescriptors.FixFormattingOfList, Location.Create(first.SyntaxTree, nodes.Span), GetTitle()); }
private static void UpdateReplaceMap(Dictionary <SyntaxToken, SyntaxToken> replaceMap, SyntaxToken token, Diagnostic diagnostic) { string location; if (!diagnostic.Properties.TryGetValue(TokenSpacingProperties.LocationKey, out location)) { return; } string action; if (!diagnostic.Properties.TryGetValue(TokenSpacingProperties.ActionKey, out action)) { return; } string layout; if (!diagnostic.Properties.TryGetValue(TokenSpacingProperties.LayoutKey, out layout)) { layout = TokenSpacingProperties.LayoutPack; } SyntaxTriviaList triviaList; switch (location) { case TokenSpacingProperties.LocationPreceding: var prevToken = token.GetPreviousToken(); switch (action) { case TokenSpacingProperties.ActionInsert: if (!replaceMap.ContainsKey(prevToken)) { replaceMap[token] = token.WithLeadingTrivia(token.LeadingTrivia.Add(SyntaxFactory.Space)); } break; case TokenSpacingProperties.ActionRemove: bool tokenIsFirstInLine = token.IsFirstInLine(); bool preserveLayout = layout == TokenSpacingProperties.LayoutPreserve; triviaList = prevToken.TrailingTrivia.AddRange(token.LeadingTrivia); if (triviaList.Any(t => t.IsDirective)) { break; } replaceMap[prevToken] = prevToken.WithTrailingTrivia(); if ((!preserveLayout || !tokenIsFirstInLine) && triviaList.All(i => i.IsKind(SyntaxKind.WhitespaceTrivia) || i.IsKind(SyntaxKind.EndOfLineTrivia))) { replaceMap[token] = token.WithLeadingTrivia(); } else if (tokenIsFirstInLine && token.IsLastInLine()) { /* This block covers the case where `token` is the only non-trivia token on its line. However, * the line may still contain non-whitespace trivia which we want the removal process to * preserve. This code fix only removes the whitespace surrounding `token` if it is the only * non-whitespace token on the line. */ int lastNewLineLeading = token.LeadingTrivia.LastIndexOf(SyntaxKind.EndOfLineTrivia); int firstNewLineFollowing = token.TrailingTrivia.IndexOf(SyntaxKind.EndOfLineTrivia); bool onlyWhitespace = true; for (int i = lastNewLineLeading + 1; i < token.LeadingTrivia.Count; i++) { onlyWhitespace &= token.LeadingTrivia[i].IsKind(SyntaxKind.WhitespaceTrivia); } firstNewLineFollowing = firstNewLineFollowing == -1 ? token.TrailingTrivia.Count : firstNewLineFollowing; for (int i = 0; i < firstNewLineFollowing; i++) { onlyWhitespace &= token.TrailingTrivia[i].IsKind(SyntaxKind.WhitespaceTrivia); } if (onlyWhitespace) { // Move the token, and remove the other tokens from its line. Keep all other surrounding // trivia. Keep the last newline that precedes token, but not the first that follows it. SyntaxTriviaList trailingTrivia = prevToken.TrailingTrivia; if (lastNewLineLeading >= 0) { trailingTrivia = trailingTrivia.AddRange(token.LeadingTrivia.Take(lastNewLineLeading + 1)); } // firstNewLineFollowing was adjusted above to account for the missing case. trailingTrivia = trailingTrivia.AddRange(token.TrailingTrivia.Take(firstNewLineFollowing)); replaceMap[token] = token.WithLeadingTrivia().WithTrailingTrivia(trailingTrivia); } else { // Just move the token and keep all surrounding trivia. SyntaxTriviaList trailingTrivia = triviaList.AddRange(token.TrailingTrivia); replaceMap[token] = token.WithLeadingTrivia().WithTrailingTrivia(trailingTrivia); } } else { SyntaxTriviaList trailingTrivia = triviaList.AddRange(token.TrailingTrivia.WithoutLeadingWhitespace(endOfLineIsWhitespace: false)); replaceMap[token] = token.WithLeadingTrivia().WithTrailingTrivia(trailingTrivia); } break; case TokenSpacingProperties.ActionRemoveImmediate: SyntaxTriviaList tokenLeadingTrivia = token.LeadingTrivia; while (tokenLeadingTrivia.Any() && tokenLeadingTrivia.Last().IsKind(SyntaxKind.WhitespaceTrivia)) { tokenLeadingTrivia = tokenLeadingTrivia.RemoveAt(tokenLeadingTrivia.Count - 1); } replaceMap[token] = token.WithLeadingTrivia(tokenLeadingTrivia); if (!tokenLeadingTrivia.Any()) { SyntaxTriviaList previousTrailingTrivia = prevToken.TrailingTrivia; while (previousTrailingTrivia.Any() && previousTrailingTrivia.Last().IsKind(SyntaxKind.WhitespaceTrivia)) { previousTrailingTrivia = previousTrailingTrivia.RemoveAt(previousTrailingTrivia.Count - 1); } replaceMap[prevToken] = prevToken.WithTrailingTrivia(previousTrailingTrivia); } break; } break; case TokenSpacingProperties.LocationFollowing: var nextToken = token.GetNextToken(); switch (action) { case TokenSpacingProperties.ActionInsert: if (!replaceMap.ContainsKey(nextToken)) { replaceMap[token] = token.WithTrailingTrivia(token.TrailingTrivia.Insert(0, SyntaxFactory.Space)); } break; case TokenSpacingProperties.ActionRemove: triviaList = token.TrailingTrivia.AddRange(nextToken.LeadingTrivia); replaceMap[token] = token.WithTrailingTrivia(); replaceMap[nextToken] = nextToken.WithLeadingTrivia(triviaList.WithoutLeadingWhitespace(true)); break; } break; } }