private static void HandleSyntaxTree(SyntaxTreeAnalysisContext context) { if (context.Tree.IsWhitespaceOnly(context.CancellationToken)) { // Handling of empty documents is now the responsibility of the analyzers return; } var firstToken = context.Tree.GetRoot().GetFirstToken(includeZeroWidth: true); if (firstToken.HasLeadingTrivia) { var leadingTrivia = firstToken.LeadingTrivia; var firstNonBlankLineTriviaIndex = TriviaHelper.IndexOfFirstNonBlankLineTrivia(leadingTrivia); switch (firstNonBlankLineTriviaIndex) { case 0: // no blank lines break; case -1: // only blank lines context.ReportDiagnostic(Diagnostic.Create(Descriptor, Location.Create(context.Tree, leadingTrivia.Span))); break; default: var textSpan = TextSpan.FromBounds(leadingTrivia[0].Span.Start, leadingTrivia[firstNonBlankLineTriviaIndex].Span.Start); context.ReportDiagnostic(Diagnostic.Create(Descriptor, Location.Create(context.Tree, textSpan))); break; } } }
private static void HandleUsings(SyntaxNodeAnalysisContext context, SyntaxList <UsingDirectiveSyntax> usings, StyleCopSettings settings) { if (usings.Count < 2) { return; } var blankLinesBetweenUsingGroups = settings.OrderingRules.BlankLinesBetweenUsingGroups; var previousGroupType = usings[0].GetUsingGroupType(settings); var previousLineSpan = usings[0].GetLineSpan(); for (var i = 1; i < usings.Count; i++) { var currentGroupType = usings[i].GetUsingGroupType(settings); var currentLineSpan = usings[i].GetLineSpan(); var partOfSameGroup = previousGroupType == currentGroupType; var lineDistance = currentLineSpan.StartLinePosition.Line - previousLineSpan.EndLinePosition.Line; previousGroupType = currentGroupType; previousLineSpan = currentLineSpan; if (partOfSameGroup) { // if the using statements are part of the same group, there is no need to check. continue; } if (blankLinesBetweenUsingGroups == OptionSetting.Require) { if (lineDistance > 1) { var separatingTrivia = TriviaHelper.MergeTriviaLists(usings[i - 1].GetTrailingTrivia(), usings[i].GetLeadingTrivia()); if (separatingTrivia.ContainsBlankLines(false)) { continue; } } context.ReportDiagnostic(Diagnostic.Create(DescriptorRequire, usings[i].UsingKeyword.GetLocation(), DiagnosticPropertiesRequire)); } else if (blankLinesBetweenUsingGroups == OptionSetting.Omit) { if (lineDistance < 2) { // no point in checking the trivia if the using statements are not separated. continue; } var separatingTrivia = TriviaHelper.MergeTriviaLists(usings[i - 1].GetTrailingTrivia(), usings[i].GetLeadingTrivia()); if (!separatingTrivia.ContainsBlankLines(false)) { continue; } context.ReportDiagnostic(Diagnostic.Create(DescriptorOmit, usings[i].UsingKeyword.GetLocation(), DiagnosticPropertiesOmit)); } } }
private static void HandleNullableType(SyntaxNodeAnalysisContext context) { var nullableType = (NullableTypeSyntax)context.Node; var questionToken = nullableType.QuestionToken; if (questionToken.IsMissing) { return; } if (nullableType.ElementType.IsMissing) { return; } /* Do not test for the first character on the line! * The StyleCop documentation is wrong there, the actual StyleCop code does not accept it. */ SyntaxToken precedingToken = questionToken.GetPreviousToken(); var triviaList = TriviaHelper.MergeTriviaLists(precedingToken.TrailingTrivia, questionToken.LeadingTrivia); if (triviaList.Any(t => t.IsKind(SyntaxKind.WhitespaceTrivia) || t.IsKind(SyntaxKind.EndOfLineTrivia))) { context.ReportDiagnostic(Diagnostic.Create(Descriptor, questionToken.GetLocation())); } }
private static void HandleSyntaxTreeAnalysis(SyntaxTreeAnalysisContext context) { var firstToken = context.Tree.GetRoot().GetFirstToken(includeZeroWidth: true); if (firstToken.HasLeadingTrivia) { var leadingTrivia = firstToken.LeadingTrivia; var firstNonBlankLineTriviaIndex = TriviaHelper.IndexOfFirstNonBlankLineTrivia(leadingTrivia); switch (firstNonBlankLineTriviaIndex) { case 0: // no blank lines break; case -1: // only blank lines context.ReportDiagnostic(Diagnostic.Create(Descriptor, Location.Create(context.Tree, leadingTrivia.Span))); break; default: var textSpan = TextSpan.FromBounds(leadingTrivia[0].Span.Start, leadingTrivia[firstNonBlankLineTriviaIndex].Span.Start); context.ReportDiagnostic(Diagnostic.Create(Descriptor, Location.Create(context.Tree, textSpan))); break; } } }
private static async Task <SyntaxNode> GetTransformedSyntaxRootAsync(Document document, CancellationToken cancellationToken) { var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var settings = document.Project.AnalyzerOptions.GetStyleCopSettings(root.SyntaxTree, cancellationToken); var fileHeader = FileHeaderHelpers.ParseFileHeader(root); SyntaxNode newSyntaxRoot; if (fileHeader.IsMissing) { newSyntaxRoot = AddHeader(document, root, GetFileName(document), settings); } else { var trivia = root.GetLeadingTrivia(); var commentIndex = TriviaHelper.IndexOfFirstNonWhitespaceTrivia(trivia, false); // Safe to do this as fileHeader.IsMissing is false. var isMultiLineComment = trivia[commentIndex].IsKind(SyntaxKind.MultiLineCommentTrivia); var xmlFileHeader = FileHeaderHelpers.ParseXmlFileHeader(root); if (isMultiLineComment && !xmlFileHeader.IsMalformed) { newSyntaxRoot = ReplaceWellFormedMultiLineCommentHeader(document, root, settings, commentIndex, xmlFileHeader); } else { newSyntaxRoot = ReplaceHeader(document, root, settings, xmlFileHeader.IsMalformed); } } return(newSyntaxRoot); }
private static BlockSyntax ReformatBodyAsMultipleLines(BlockSyntax body, SyntaxTrivia indentation, SyntaxTrivia indentationStatements) { SyntaxTriviaList reformattedOpenBraceTrailingTrivia; SyntaxTriviaList reformattedCloseBraceLeadingTrivia; SyntaxList <StatementSyntax> newStatements; if (body.Statements.Count > 0) { var reformattedStatement = body.Statements[0] .WithLeadingTrivia(ReformatTriviaListNoLeadingSpace(body.Statements[0].GetLeadingTrivia()).Insert(0, indentationStatements)) .WithTrailingTrivia(ReformatTriviaListNoTrailingSpace(body.Statements[0].GetTrailingTrivia()).Add(SyntaxFactory.CarriageReturnLineFeed)); reformattedOpenBraceTrailingTrivia = ReformatTriviaListNoTrailingSpace(body.OpenBraceToken.TrailingTrivia); newStatements = SyntaxFactory.List <StatementSyntax>().Add(reformattedStatement); reformattedCloseBraceLeadingTrivia = ReformatTriviaListNoLeadingSpace(body.CloseBraceToken.LeadingTrivia); } else { var triviaBetweenBraces = TriviaHelper.MergeTriviaLists(body.OpenBraceToken.TrailingTrivia, body.CloseBraceToken.LeadingTrivia); reformattedOpenBraceTrailingTrivia = ReformatTriviaListNoTrailingSpace(triviaBetweenBraces); newStatements = body.Statements; reformattedCloseBraceLeadingTrivia = SyntaxFactory.TriviaList(); } var newOpenBraceToken = body.OpenBraceToken .WithLeadingTrivia(ReformatTriviaListNoLeadingSpace(body.OpenBraceToken.LeadingTrivia).Insert(0, indentation)) .WithTrailingTrivia(reformattedOpenBraceTrailingTrivia.Add(SyntaxFactory.CarriageReturnLineFeed)); var newCloseBraceToken = body.CloseBraceToken .WithLeadingTrivia(reformattedCloseBraceLeadingTrivia.Insert(0, indentation)) .WithTrailingTrivia(ReformatTriviaListNoTrailingSpace(body.CloseBraceToken.TrailingTrivia).Add(SyntaxFactory.CarriageReturnLineFeed)); return(body.Update(newOpenBraceToken, newStatements, newCloseBraceToken)); }
private static void HandleSingleLineComment(SyntaxTreeAnalysisContext context, SyntaxTrivia singleLineComment) { int index = 0; // PERF: Explicitly cast to IReadOnlyList so we only box once. IReadOnlyList <SyntaxTrivia> list = TriviaHelper.GetContainingTriviaList(singleLineComment, out index); var firstNonWhiteSpace = TriviaHelper.IndexOfFirstNonWhitespaceTrivia(list); // When we encounter a block of single line comments, we only want to raise this diagnostic // on the first or last line. This ensures that whitespace in code commented out using // the Comment Selection option in Visual Studio will not raise the diagnostic for every // blank line in the code which is commented out. bool isFirst = index == firstNonWhiteSpace; if (!isFirst) { // This is -2 because we need to go back past the end of line trivia as well. var lastNonWhiteSpace = TriviaHelper.IndexOfTrailingWhitespace(list) - 2; if (index != lastNonWhiteSpace) { return; } } if (IsNullOrWhiteSpace(singleLineComment.ToString(), 2)) { var diagnostic = Diagnostic.Create(Descriptor, singleLineComment.GetLocation()); context.ReportDiagnostic(diagnostic); } }
private static async Task <Document> GetTransformedDocumentAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken) { var syntaxRoot = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var accessorToken = syntaxRoot.FindToken(diagnostic.Location.SourceSpan.Start); var accessorList = (AccessorListSyntax)accessorToken.Parent.Parent; var firstAccesor = accessorList.Accessors[0]; var secondAccessor = accessorList.Accessors[1]; var trackedRoot = syntaxRoot.TrackNodes(firstAccesor, secondAccessor); var trackedFirstAccessor = trackedRoot.GetCurrentNode(firstAccesor); var newAccessor = GetNewAccessor(accessorList, firstAccesor, secondAccessor); syntaxRoot = trackedRoot.InsertNodesBefore(trackedFirstAccessor, new[] { newAccessor }); trackedFirstAccessor = syntaxRoot.GetCurrentNode(firstAccesor); if (secondAccessor.GetFirstToken().HasLeadingBlankLines()) { var newFirstAccessor = trackedFirstAccessor.WithLeadingTrivia( TriviaHelper.MergeTriviaLists(new[] { SyntaxFactory.CarriageReturnLineFeed }, trackedFirstAccessor.GetLeadingTrivia())); syntaxRoot = syntaxRoot.ReplaceNode(trackedFirstAccessor, newFirstAccessor); } var trackedLastAccessor = syntaxRoot.GetCurrentNode(secondAccessor); var keepTriviaOptions = AccessorsAreOnTheSameLine(firstAccesor, secondAccessor) ? SyntaxRemoveOptions.KeepEndOfLine : SyntaxRemoveOptions.KeepNoTrivia; syntaxRoot = syntaxRoot.RemoveNode(trackedLastAccessor, keepTriviaOptions); return(document.WithSyntaxRoot(syntaxRoot)); }
public override SyntaxNode VisitUsingDirective(UsingDirectiveSyntax node) { // The strip list is used to remove using directives that will be moved. if (this.stripList.Contains(node)) { var nextToken = node.SemicolonToken.GetNextToken(); if (!nextToken.IsKind(SyntaxKind.None)) { var index = TriviaHelper.IndexOfFirstNonBlankLineTrivia(nextToken.LeadingTrivia); if (index != 0) { this.tokensToStrip.AddLast(nextToken); } } return(null); } // The replacement map is used to replace using declarations in place in sorted order (inside directive trivia) UsingDirectiveSyntax replacementNode; if (this.replaceMap.TryGetValue(node, out replacementNode)) { return(replacementNode); } return(base.VisitUsingDirective(node)); }
/// <inheritdoc/> public override async Task RegisterCodeFixesAsync(CodeFixContext context) { foreach (Diagnostic diagnostic in context.Diagnostics.Where(d => FixableDiagnostics.Contains(d.Id))) { var syntaxRoot = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); var firstToken = syntaxRoot.GetFirstToken(includeZeroWidth: true); var leadingTrivia = firstToken.LeadingTrivia; var newTriviaList = SyntaxFactory.TriviaList(); var firstNonBlankLineTriviaIndex = TriviaHelper.IndexOfFirstNonBlankLineTrivia(leadingTrivia); if (firstNonBlankLineTriviaIndex != -1) { for (var index = firstNonBlankLineTriviaIndex; index < leadingTrivia.Count; index++) { newTriviaList = newTriviaList.Add(leadingTrivia[index]); } } var newFirstToken = firstToken.WithLeadingTrivia(newTriviaList); var newSyntaxRoot = syntaxRoot.ReplaceToken(firstToken, newFirstToken); var newDocument = context.Document.WithSyntaxRoot(newSyntaxRoot); context.RegisterCodeFix(CodeAction.Create("Remove blank lines at the start of the file", token => Task.FromResult(newDocument)), diagnostic); } }
// If you want a full implementation of this analyzer with system tests and a code fix, go to // https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/StyleCop.Analyzers/StyleCop.Analyzers/ReadabilityRules/SA1120CommentsMustContainText.cs private void HandleSyntaxTree(SyntaxTreeAnalysisContext context) { SyntaxNode root = context.Tree.GetCompilationUnitRoot(context.CancellationToken); foreach (var node in root.DescendantTrivia()) { switch (node.Kind()) { case SyntaxKind.SingleLineCommentTrivia: // Remove the leading // from the comment var commentText = node.ToString().Substring(2); int index = 0; var list = TriviaHelper.GetContainingTriviaList(node, out index); bool isFirst = IsFirstComment(list, index); bool isLast = IsLastComment(list, index); if (string.IsNullOrWhiteSpace(commentText) && (isFirst || isLast)) { var diagnostic = Diagnostic.Create(Rule, node.GetLocation()); context.ReportDiagnostic(diagnostic); } break; } } }
/// <summary> /// Checks if a given <see cref="SyntaxTree"/> only contains whitespaces. We don't want to analyze empty files. /// </summary> /// <param name="tree">The syntax tree to examine.</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> that the task will observe.</param> /// <returns> /// <para><see langword="true"/> if <paramref name="tree"/> only contains whitespaces; otherwise, <see langword="false"/>.</para> /// </returns> private static bool IsEmpty(SyntaxTree tree, CancellationToken cancellationToken) { var root = tree.GetRoot(cancellationToken); var firstToken = root.GetFirstToken(includeZeroWidth: true); return(firstToken.IsKind(SyntaxKind.EndOfFileToken) && TriviaHelper.IndexOfFirstNonWhitespaceTrivia(firstToken.LeadingTrivia, true) == -1); }
private static void HandleSyntaxTree(SyntaxTreeAnalysisContext context) { var syntaxRoot = context.Tree.GetRoot(context.CancellationToken); foreach (var trivia in syntaxRoot.DescendantTrivia().Where(trivia => trivia.IsKind(SyntaxKind.SingleLineCommentTrivia))) { if (trivia.FullSpan.Start == 0) { // skip the trivia if it is at the start of the file continue; } if (trivia.ToString().StartsWith("////", StringComparison.Ordinal)) { // ignore commented out code continue; } int triviaIndex; // PERF: Explicitly cast to IReadOnlyList so we only box once. var triviaList = TriviaHelper.GetContainingTriviaList(trivia, out triviaIndex); if (!IsOnOwnLine(triviaList, triviaIndex)) { // ignore comments after other code elements. continue; } if (IsPrecededByBlankLine(triviaList, triviaIndex)) { // allow properly formatted blank line comments. continue; } if (IsPrecededBySingleLineCommentOrDocumentation(triviaList, triviaIndex)) { // allow consecutive single line comments. continue; } if (IsAtStartOfScope(trivia)) { // allow single line comment at scope start. continue; } if (IsPrecededByDirectiveTrivia(triviaList, triviaIndex)) { // allow single line comment that is preceded by some directive trivia (if, elif, else) continue; } var diagnosticSpan = TextSpan.FromBounds(trivia.SpanStart, trivia.SpanStart + 2); context.ReportDiagnostic(Diagnostic.Create(Descriptor, Location.Create(context.Tree, diagnosticSpan))); } }
private void AddQuestion_Click(object sender, EventArgs e) { string message = ""; if (!TriviaHelper.AddQuestion(this, ref message)) { MessageBox.Show(message); } }
private void DeleteButton_Click(object sender, EventArgs e) { string message = ""; if (TriviaHelper.DeleteCourse(this, ref message)) { MessageBox.Show(message); } }
private static void AnalyzeCloseBrace(SyntaxNodeAnalysisContext context, SyntaxToken closeBraceToken) { if (closeBraceToken.IsKind(SyntaxKind.None)) { return; } var previousToken = closeBraceToken.GetPreviousToken(); if ((closeBraceToken.GetLineSpan().StartLinePosition.Line - previousToken.GetLineSpan().EndLinePosition.Line) < 2) { // there will be no blank lines when the closing brace and the preceding token are not at least two lines apart. return; } var separatingTrivia = TriviaHelper.MergeTriviaLists(previousToken.TrailingTrivia, closeBraceToken.LeadingTrivia); // skip all leading whitespace for the close brace // the index must be checked because two tokens can be more than two lines apart and // still only be separated by whitespace trivia due to compilation errors var index = separatingTrivia.Count - 1; while (index >= 0 && separatingTrivia[index].IsKind(SyntaxKind.WhitespaceTrivia)) { index--; } var done = false; var eolCount = 0; while (!done && index >= 0) { switch (separatingTrivia[index].Kind()) { case SyntaxKind.WhitespaceTrivia: break; case SyntaxKind.EndOfLineTrivia: eolCount++; break; default: done = true; break; } index--; } if (eolCount > 1) { context.ReportDiagnostic(Diagnostic.Create(Descriptor, closeBraceToken.GetLocation())); } }
private async Task <Document> FixCommentSpacingAsync(Document document, SyntaxToken token, CancellationToken cancellationToken) { var newDeclaration = token .WithLeadingTrivia(TriviaHelper.FixSingleLineCommentSpacing(token.LeadingTrivia)) .WithTrailingTrivia(TriviaHelper.FixSingleLineCommentSpacing(token.TrailingTrivia)); var root = await document.GetSyntaxRootAsync(); var newRoot = root.ReplaceToken(token, newDeclaration); return(document.WithSyntaxRoot(newRoot)); }
private static void HandlePrefixUnaryExpression(SyntaxNodeAnalysisContext context) { var unaryExpression = (PrefixUnaryExpressionSyntax)context.Node; var precedingToken = unaryExpression.OperatorToken.GetPreviousToken(); var followingToken = unaryExpression.OperatorToken.GetNextToken(); var followingTrivia = TriviaHelper.MergeTriviaLists(unaryExpression.OperatorToken.TrailingTrivia, followingToken.LeadingTrivia); /* let the outer operator handle things like the following, so no error is reported for '++': * c ^= *++buf4; * * if the unary expression is inside parenthesis or an indexer, there should be no leading space */ var mustHaveLeadingWhitespace = !(unaryExpression.Parent is PrefixUnaryExpressionSyntax) && !(unaryExpression.Parent is CastExpressionSyntax) && !precedingToken.IsKind(SyntaxKind.OpenParenToken) && !precedingToken.IsKind(SyntaxKind.OpenBracketToken) && !(precedingToken.IsKind(SyntaxKind.OpenBraceToken) && (precedingToken.Parent is InterpolationSyntax)); bool analyze; switch (unaryExpression.OperatorToken.Kind()) { case SyntaxKind.PlusToken: analyze = context.IsAnalyzerSuppressed(SA1022PositiveSignsMustBeSpacedCorrectly.DiagnosticId); break; case SyntaxKind.MinusToken: analyze = context.IsAnalyzerSuppressed(SA1021NegativeSignsMustBeSpacedCorrectly.DiagnosticId); break; case SyntaxKind.PlusPlusToken: case SyntaxKind.MinusMinusToken: analyze = context.IsAnalyzerSuppressed(SA1020IncrementDecrementSymbolsMustBeSpacedCorrectly.DiagnosticId); break; default: analyze = true; break; } if (analyze) { if (followingTrivia.Any(t => t.IsKind(SyntaxKind.SingleLineCommentTrivia)) || followingTrivia.Any(t => t.IsKind(SyntaxKind.MultiLineCommentTrivia))) { context.ReportDiagnostic(Diagnostic.Create(DescriptorNotFollowedByComment, unaryExpression.OperatorToken.GetLocation(), unaryExpression.OperatorToken.Text)); } else { CheckToken(context, unaryExpression.OperatorToken, mustHaveLeadingWhitespace, false, false); } } }
private static void AnalyzeOpenBrace(SyntaxNodeAnalysisContext context, SyntaxToken openBraceToken) { var nextToken = openBraceToken.GetNextToken(); if (nextToken.IsMissingOrDefault()) { return; } if ((GetLine(nextToken) - GetLine(openBraceToken)) < 2) { // there will be no blank lines when the opening brace and the following token are not at least two lines apart. return; } var separatingTrivia = TriviaHelper.MergeTriviaLists(openBraceToken.TrailingTrivia, nextToken.LeadingTrivia); // skip everything until the first end of line (as this is considered part of the line of the opening brace) var startIndex = 0; while ((startIndex < separatingTrivia.Count) && !separatingTrivia[startIndex].IsKind(SyntaxKind.EndOfLineTrivia)) { startIndex++; } startIndex = (startIndex == separatingTrivia.Count) ? 0 : startIndex + 1; var done = false; var eolCount = 0; for (var i = startIndex; !done && (i < separatingTrivia.Count); i++) { switch (separatingTrivia[i].Kind()) { case SyntaxKind.WhitespaceTrivia: break; case SyntaxKind.EndOfLineTrivia: eolCount++; break; default: done = true; break; } } if (eolCount > 0) { context.ReportDiagnostic(Diagnostic.Create(Descriptor, openBraceToken.GetLocation())); } }
public override SyntaxToken VisitToken(SyntaxToken token) { if (this.tokensToStrip.Contains(token)) { this.tokensToStrip.Remove(token); var index = TriviaHelper.IndexOfFirstNonBlankLineTrivia(token.LeadingTrivia); var newLeadingTrivia = (index == -1) ? SyntaxFactory.TriviaList() : SyntaxFactory.TriviaList(token.LeadingTrivia.Skip(index)); return(token.WithLeadingTrivia(newLeadingTrivia)); } return(base.VisitToken(token)); }
private static SyntaxToken StripViolatingWhitespace(SyntaxToken token) { SyntaxToken result = token; var trailingWhitespaceIndex = TriviaHelper.IndexOfTrailingWhitespace(token.LeadingTrivia); if (trailingWhitespaceIndex != -1) { var newTriviaList = SyntaxFactory.TriviaList(token.LeadingTrivia.Take(trailingWhitespaceIndex)); result = token.WithLeadingTrivia(newTriviaList); } return(result); }
private static async Task <Document> GetTransformedDocumentAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken) { var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var node = root.FindTrivia(diagnostic.Location.SourceSpan.Start, true); int diagnosticIndex = 0; var triviaList = TriviaHelper.GetContainingTriviaList(node, out diagnosticIndex); var nodesToRemove = new List <SyntaxTrivia>(); nodesToRemove.Add(node); // If there is trialing content on the line, we don't want to remove the leading whitespace bool hasTrailingContent = TriviaHasTrailingContentOnLine(root, triviaList); if (diagnosticIndex > 0 && !hasTrailingContent) { var previousStart = triviaList[diagnosticIndex - 1].SpanStart; var previousNode = root.FindTrivia(previousStart, true); nodesToRemove.Add(previousNode); } // If there is leading content on the line, then we don't want to remove the trailing end of lines bool hasLeadingContent = TriviaHasLeadingContentOnLine(root, triviaList); if (diagnosticIndex < triviaList.Count - 1) { var nextStart = triviaList[diagnosticIndex + 1].SpanStart; var nextNode = root.FindTrivia(nextStart, true); if (nextNode.IsKind(SyntaxKind.EndOfLineTrivia) && !hasLeadingContent) { nodesToRemove.Add(nextNode); } } // Replace all roots with an empty node var newRoot = root.ReplaceTrivia(nodesToRemove, (original, rewritten) => { return(new SyntaxTrivia()); }); newRoot = newRoot.NormalizeWhitespace(); Document updatedDocument = document.WithSyntaxRoot(newRoot); return(updatedDocument); }
private static async Task <Document> GetTransformedDocumentAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken) { var syntaxRoot = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var indentationOptions = IndentationOptions.FromDocument(document); var newLine = TriviaHelper.GetNewLineTrivia(document); var constructorInitializer = (ConstructorInitializerSyntax)syntaxRoot.FindNode(diagnostic.Location.SourceSpan); var constructorDeclaration = (ConstructorDeclarationSyntax)constructorInitializer.Parent; var newConstructorDeclaration = ReformatConstructorDeclaration(constructorDeclaration, indentationOptions, newLine); var newSyntaxRoot = syntaxRoot.ReplaceNode(constructorDeclaration, newConstructorDeclaration); return(document.WithSyntaxRoot(newSyntaxRoot)); }
private static void HandleSyntaxTreeAction(SyntaxTreeAnalysisContext context) { var lastToken = context.Tree.GetRoot().GetLastToken(includeZeroWidth: true); if (lastToken.HasLeadingTrivia) { var leadingTrivia = lastToken.LeadingTrivia; var trailingWhitespaceIndex = TriviaHelper.IndexOfTrailingWhitespace(leadingTrivia); if (trailingWhitespaceIndex != -1) { var textSpan = TextSpan.FromBounds(leadingTrivia[trailingWhitespaceIndex].SpanStart, leadingTrivia[leadingTrivia.Count - 1].Span.End); context.ReportDiagnostic(Diagnostic.Create(Descriptor, Location.Create(context.Tree, textSpan))); } } }
private static AccessorDeclarationSyntax GetNewAccessor(AccessorListSyntax accessorList, AccessorDeclarationSyntax firstAccessor, AccessorDeclarationSyntax secondAccessor) { var newLeadingTrivia = GetLeadingTriviaWithoutLeadingBlankLines(secondAccessor); if (AccessorsAreOnTheSameLine(firstAccessor, secondAccessor)) { var leadingWhitespace = firstAccessor.GetLeadingTrivia().Where(x => x.IsKind(SyntaxKind.WhitespaceTrivia)); newLeadingTrivia = SyntaxFactory.TriviaList(TriviaHelper.MergeTriviaLists(newLeadingTrivia, SyntaxTriviaList.Empty.AddRange(leadingWhitespace))); } var newAccessor = accessorList.Accessors[1] .WithBody(secondAccessor.Body) .WithLeadingTrivia(newLeadingTrivia); return(newAccessor); }
private static async Task <Document> GetTransformedDocumentAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken) { var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var trivia = root.FindTrivia(diagnostic.Location.SourceSpan.Start, true); int diagnosticIndex = 0; var triviaList = TriviaHelper.GetContainingTriviaList(trivia, out diagnosticIndex); var triviaToRemove = new List <SyntaxTrivia>(); triviaToRemove.Add(trivia); bool hasTrailingContent = TriviaHasTrailingContentOnLine(root, trivia); if (!hasTrailingContent && diagnosticIndex > 0) { var previousTrivia = triviaList[diagnosticIndex - 1]; if (previousTrivia.IsKind(SyntaxKind.WhitespaceTrivia)) { triviaToRemove.Add(previousTrivia); } } bool hasLeadingContent = TriviaHasLeadingContentOnLine(root, trivia); if (!hasLeadingContent && diagnosticIndex < triviaList.Count - 1) { var nextTrivia = triviaList[diagnosticIndex + 1]; if (nextTrivia.IsKind(SyntaxKind.EndOfLineTrivia)) { triviaToRemove.Add(nextTrivia); } } // Replace all roots with an empty node var newRoot = root.ReplaceTrivia(triviaToRemove, (original, rewritten) => { return(default(SyntaxTrivia)); }); Document updatedDocument = document.WithSyntaxRoot(newRoot); return(updatedDocument); }
protected override async Task <SyntaxNode> FixAllInDocumentAsync(FixAllContext fixAllContext, Document document) { var diagnostics = await fixAllContext.GetDocumentDiagnosticsAsync(document).ConfigureAwait(false); if (diagnostics.IsEmpty) { return(null); } var syntaxRoot = await document.GetSyntaxRootAsync(fixAllContext.CancellationToken).ConfigureAwait(false); var indentationOptions = IndentationOptions.FromDocument(document); var newLine = TriviaHelper.GetNewLineTrivia(document); var nodes = diagnostics.Select(diagnostic => syntaxRoot.FindNode(diagnostic.Location.SourceSpan).Parent); return(syntaxRoot.ReplaceNodes(nodes, (originalNode, rewrittenNode) => ReformatConstructorDeclaration((ConstructorDeclarationSyntax)rewrittenNode, indentationOptions, newLine))); }
private static SyntaxNode GetReplacement(ParenthesizedExpressionSyntax oldNode) { var leadingTrivia = SyntaxFactory.TriviaList(oldNode.OpenParenToken.GetAllTrivia().Concat(oldNode.Expression.GetLeadingTrivia())); var trailingTrivia = oldNode.Expression.GetTrailingTrivia().AddRange(oldNode.CloseParenToken.GetAllTrivia()); // Workaround for Roslyn not handling elastic markers for directive trivia correctly. if (!leadingTrivia.Any()) { var previousToken = oldNode.OpenParenToken.GetPreviousToken(); if (!previousToken.IsKind(SyntaxKind.OpenParenToken) && (TriviaHelper.IndexOfTrailingWhitespace(previousToken.TrailingTrivia) == -1)) { leadingTrivia = SyntaxFactory.TriviaList(SyntaxFactory.Space); } } return(oldNode.Expression .WithLeadingTrivia(leadingTrivia) .WithTrailingTrivia(trailingTrivia.Any() ? trailingTrivia : SyntaxFactory.TriviaList(SyntaxFactory.ElasticMarker))); }
private static AccessorDeclarationSyntax GetNewAccessor(AccessorListSyntax accessorList, AccessorDeclarationSyntax firstAccessor, AccessorDeclarationSyntax secondAccessor) { var newLeadingTrivia = GetLeadingTriviaWithoutLeadingBlankLines(secondAccessor); if (AccessorsAreOnTheSameLine(firstAccessor, secondAccessor)) { var leadingWhitespace = firstAccessor.GetLeadingTrivia().Where(x => x.IsKind(SyntaxKind.WhitespaceTrivia)).ToList(); newLeadingTrivia = SyntaxFactory.TriviaList(TriviaHelper.MergeTriviaLists(newLeadingTrivia, leadingWhitespace)); } var newAccessor = accessorList.Accessors[1] .WithBody(secondAccessor.Body) .WithLeadingTrivia(newLeadingTrivia); if (secondAccessor.GetFirstToken().HasLeadingBlankLines()) { newAccessor.WithTrailingTrivia(SyntaxFactory.CarriageReturnLineFeed, SyntaxFactory.CarriageReturnLineFeed); } return(newAccessor); }
private static async Task <Document> RemoveSemicolonTextAsync(Document document, SyntaxToken token, CancellationToken cancellationToken) { TextChange textChange; SourceText sourceText = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); TextLine line = sourceText.Lines.GetLineFromPosition(token.SpanStart); if (sourceText.ToString(line.Span).Trim() == token.Text) { // remove the line containing the semicolon token textChange = new TextChange(line.SpanIncludingLineBreak, string.Empty); return(document.WithText(sourceText.WithChanges(textChange))); } TextSpan spanToRemove; var whitespaceIndex = TriviaHelper.IndexOfTrailingWhitespace(token.LeadingTrivia); if (whitespaceIndex >= 0) { spanToRemove = TextSpan.FromBounds(token.LeadingTrivia[whitespaceIndex].Span.Start, token.Span.End); } else { var previousToken = token.GetPreviousToken(); whitespaceIndex = TriviaHelper.IndexOfTrailingWhitespace(previousToken.TrailingTrivia); if (whitespaceIndex >= 0) { spanToRemove = TextSpan.FromBounds(previousToken.TrailingTrivia[whitespaceIndex].Span.Start, token.Span.End); } else { spanToRemove = token.Span; } } textChange = new TextChange(spanToRemove, string.Empty); return(document.WithText(sourceText.WithChanges(textChange))); }