private SyntaxTriviaList FixCommentWhitespace(SyntaxTriviaList textLines) { var changedLines = new SyntaxTriviaList(); bool skipNextNewline = false; foreach (var text in textLines) { if (skipNextNewline) { skipNextNewline = false; if (text.Kind() == SyntaxKind.EndOfLineTrivia) { continue; } } var removeTrivia = this.HasEmptyComment(text); if (!removeTrivia) { changedLines = changedLines.Add(text); } else { skipNextNewline = true; } } return changedLines; }
private static List<SyntaxTrivia> RemoveBlankLineTrivia(SyntaxTriviaList trivia, ref bool changed) { var newTrivia = new List<SyntaxTrivia>(); for (int i = 0; i < trivia.Count;) { var trivia1 = trivia[i]; newTrivia.Add(trivia1); if (i < trivia.Count - 2) { var trivia2 = trivia[i + 1]; var trivia3 = trivia[i + 2]; if (trivia1.Kind == SyntaxKind.EndOfLineTrivia && trivia2.Kind == SyntaxKind.WhitespaceTrivia && trivia3.Kind == SyntaxKind.EndOfLineTrivia) { // Skip the whitespace with a newline. newTrivia.Add(trivia3); changed = true; i += 3; continue; } } i++; } return newTrivia; }
private static List<SyntaxTrivia> RemoveBlankLines(SyntaxTriviaList trivia, ref bool changed) { var newTrivia = new List<SyntaxTrivia>(); for (int i = 0; i < trivia.Count;) { var trivia1 = trivia[i]; newTrivia.Add(trivia1); if (i < trivia.Count - 1) { var trivia2 = trivia[i + 1]; if (trivia1.Kind == SyntaxKind.EndOfLineTrivia && trivia2.Kind == SyntaxKind.EndOfLineTrivia) { changed = true; i += 2; continue; } } i++; } return newTrivia; }
/// <summary> /// Returns the index of the first non-whitespace trivia in the given trivia list. /// </summary> /// <param name="triviaList">The trivia list to process.</param> /// <param name="endOfLineIsWhitespace"><see langword="true"/> to treat <see cref="SyntaxKind.EndOfLineTrivia"/> /// as whitespace; otherwise, <see langword="false"/>.</param> /// <returns>The index where the non-whitespace starts, or -1 if there is no non-whitespace trivia.</returns> internal static int IndexOfFirstNonWhitespaceTrivia(SyntaxTriviaList triviaList, bool endOfLineIsWhitespace) { for (var index = 0; index < triviaList.Count; index++) { var currentTrivia = triviaList[index]; switch (currentTrivia.Kind()) { case SyntaxKind.EndOfLineTrivia: if (!endOfLineIsWhitespace) { return index; } break; case SyntaxKind.WhitespaceTrivia: break; default: // encountered non-whitespace trivia -> the search is done. return index; } } return -1; }
static string GetImportsFromTrivia(SyntaxTriviaList triviaList) { return triviaList .Where(trivia => trivia.IsKind(SyntaxKind.MultiLineCommentTrivia) || trivia.IsKind(SyntaxKind.SingleLineCommentTrivia)) .Select(trivia => trivia.ToString().TrimStart('/', '*').Trim()) .Where(comment => comment.StartsWith("import")) .Aggregate("", (current, comment) => current + (comment + ConvertToSwift.NewLine)); }
public void Add(SyntaxTriviaList list, int offset, int length) { if (nodes == null || count + length > nodes.Length) { this.Grow(count + length); } list.CopyTo(offset, nodes, count, length); count += length; }
internal static SyntaxTrivia GetBestNewLineTrivia(SyntaxTriviaList list, SyntaxTrivia? defaultNewLineTrivia = null) { SyntaxTrivia trivia; if (TryGetExistingNewLine(list, out trivia)) { return trivia; } return defaultNewLineTrivia ?? SyntaxFactory.CarriageReturnLineFeed; }
private void ClassifyExteriorTrivia(SyntaxTriviaList triviaList) { foreach (var t in triviaList) { if (t.CSharpKind() == SyntaxKind.DocumentationCommentExteriorTrivia) { AddClassification(t, ClassificationTypeNames.XmlDocCommentDelimiter); } } }
public void Add(SyntaxTriviaList list, int offset, int length) { if (_nodes == null || _count + length > _nodes.Length) { this.Grow(_count + length); } list.CopyTo(offset, _nodes, _count, length); _count += length; }
private static Task<Document> GetTransformedDocumentAsync(CodeFixContext context, SyntaxNode syntaxRoot, SyntaxNode node, SyntaxTriviaList leadingTrivia) { var newTriviaList = leadingTrivia; newTriviaList = newTriviaList.Insert(0, SyntaxFactory.CarriageReturnLineFeed); var newNode = node.WithLeadingTrivia(newTriviaList); var newSyntaxRoot = syntaxRoot.ReplaceNode(node, newNode); var newDocument = context.Document.WithSyntaxRoot(newSyntaxRoot); return Task.FromResult(newDocument); }
public override SyntaxTriviaList VisitList(SyntaxTriviaList list) { list = base.VisitList(list); var lineBreaksAtBeginning = list.TakeWhile(t => t.IsKind(SyntaxKind.EndOfLineTrivia)).Count(); if (lineBreaksAtBeginning > 1) { list = SyntaxFactory.TriviaList(list.Skip(lineBreaksAtBeginning - 1)); } return list; }
private SyntaxTriviaList FixCommentWhitespace(SyntaxTriviaList textLines) { var changedLines = new SyntaxTriviaList(); foreach (var text in textLines) { var fixedText = this.FixCommentWhitespaceForLine(text); changedLines = changedLines.Add(fixedText); } return changedLines; }
private static bool TryGetExistingNewLine(SyntaxTriviaList list, out SyntaxTrivia newLineTrivia) { foreach (var trivia in list) { if (trivia.IsKind(SyntaxKind.EndOfLineTrivia)) { newLineTrivia = trivia; return true; } } newLineTrivia = default(SyntaxTrivia); return false; }
private static IEnumerable<SyntaxTrivia> Filter(SyntaxTriviaList triviaList, SyntaxTrivia start, SyntaxTrivia end) { var inHeader = false; foreach (var trivia in triviaList) { if (trivia == start) inHeader = true; else if (trivia == end) inHeader = false; else if (!inHeader) yield return trivia; } }
private static SyntaxTriviaList FixTriviaList(SyntaxTriviaList triviaList, IEnumerable<SyntaxTrivia> commentTrivias) { foreach (var singleLineComment in commentTrivias) { int commentLocation = triviaList.IndexOf(singleLineComment); if (commentLocation == -1) { continue; } int index = commentLocation + 1; index++; while (index < triviaList.Count && index > 0) { switch (triviaList[index].Kind()) { case SyntaxKind.EndOfLineTrivia: case SyntaxKind.WhitespaceTrivia: index++; break; default: if (triviaList[index - 1].IsKind(SyntaxKind.WhitespaceTrivia)) { index--; } triviaList = SyntaxTriviaList.Empty.AddRange(triviaList.Take(commentLocation + 2).Concat(triviaList.Skip(index))); // We found the trivia so we don't have to loop any longer index = -1; break; } } if (index == triviaList.Count) { if (triviaList[index - 1].IsKind(SyntaxKind.WhitespaceTrivia)) { index--; } triviaList = SyntaxTriviaList.Empty.AddRange(triviaList.Take(commentLocation + 2).Concat(triviaList.Skip(index))); } } return triviaList; }
private List<string> GetExistingHeader(SyntaxTriviaList triviaList) { var i = 0; MovePastBlankLines(triviaList, ref i); var headerList = new List<string>(); while (i < triviaList.Count && IsLineComment(triviaList[i])) { headerList.Add(GetCommentText(triviaList[i].ToFullString())); i++; MoveToNextLineOrTrivia(triviaList, ref i); } return headerList; }
private void GetOutliningSpans(SyntaxTriviaList triviaList) { foreach (var trivia in triviaList) { _cancellationToken.ThrowIfCancellationRequested(); if (_triviaProviderMap.TryGetValue(trivia.RawKind, out var providers)) { foreach (var provider in providers) { _cancellationToken.ThrowIfCancellationRequested(); provider.CollectBlockSpans(_document, trivia, _spans, _cancellationToken); } } } }
internal static bool CheckForAssignmentOfLiteral(StatementSyntax statement, SyntaxKind literalExpressionType, out ExpressionSyntax assignmentTarget, out SyntaxTriviaList assignmentTrailingTriviaList) { assignmentTarget = null; assignmentTrailingTriviaList = SyntaxFactory.TriviaList(SyntaxFactory.SyntaxTrivia(SyntaxKind.DisabledTextTrivia, "")); var expressionStatement = statement as ExpressionStatementSyntax; if (expressionStatement == null) return false; var assignmentExpression = expressionStatement.Expression as AssignmentExpressionSyntax; if ((assignmentExpression == null) || !assignmentExpression.IsKind(SyntaxKind.SimpleAssignmentExpression)) return false; assignmentTarget = assignmentExpression.Left as IdentifierNameSyntax; assignmentTrailingTriviaList = assignmentExpression.OperatorToken.TrailingTrivia; if (assignmentTarget == null) assignmentTarget = assignmentExpression.Left as MemberAccessExpressionSyntax; var rightAssignment = assignmentExpression.Right as LiteralExpressionSyntax; return (assignmentTarget != null) && (rightAssignment != null) && (rightAssignment.IsKind(literalExpressionType)); }
public static SyntaxToken ToIdentifierToken(this string identifier, bool isQueryContext = false) { string text = identifier.EscapeIdentifier(isQueryContext); if ((text.Length == 0) || (text[0] != '@')) { return SyntaxFactory.Identifier(text); } string valueText = identifier.StartsWith("@") ? identifier.Substring(1) : identifier; SyntaxTriviaList leading = new SyntaxTriviaList(); SyntaxToken token = SyntaxFactory.Identifier(leading, SyntaxKind.None, '@' + valueText, valueText, new SyntaxTriviaList()); if (!identifier.StartsWith("@")) { SyntaxAnnotation[] annotations = new SyntaxAnnotation[] { Simplifier.Annotation }; token = token.WithAdditionalAnnotations(annotations); } return token; }
private void GetOutliningSpans(SyntaxTriviaList triviaList) { foreach (var trivia in triviaList) { _cancellationToken.ThrowIfCancellationRequested(); ImmutableArray<AbstractSyntaxTriviaOutliner> outliners; if (_triviaOutlinerMap.TryGetValue(trivia.RawKind, out outliners)) { foreach (var outliner in outliners) { _cancellationToken.ThrowIfCancellationRequested(); outliner.CollectOutliningSpans(_document.Document, trivia, _regions, _cancellationToken); } } } }
static SyntaxTriviaList FlushDuplicateTrivia( SyntaxTriviaList trivia, int startIndex, int endIndex, bool allowExtraNewLine) { int allowedNewLines = allowExtraNewLine ? 2 : 1; var newLineCount = 0; for (; endIndex >= startIndex; endIndex--) { if (newLineCount == allowedNewLines) { trivia = trivia.RemoveAt(endIndex); } else if (trivia[endIndex].IsKind(SyntaxKind.EndOfLineTrivia)) { newLineCount++; } } return trivia; }
private static bool TryGetStartAndEndOfXmlHeader(SyntaxTriviaList triviaList, out SyntaxTrivia start, out SyntaxTrivia end) { start = default(SyntaxTrivia); end = default(SyntaxTrivia); var hasStart = false; var hasEnd = false; foreach (var trivia in triviaList) { if (!hasStart && IsBeginningOfXmlHeader(trivia, out start)) hasStart = true; if (!hasEnd && IsEndOfXmlHeader(trivia, out end)) hasEnd = true; } return hasStart && hasEnd; }
private void ClassifyXmlTrivia(SyntaxTriviaList triviaList, string whitespaceClassificationType = null) { foreach (var t in triviaList) { switch (t.Kind()) { case SyntaxKind.DocumentationCommentExteriorTrivia: ClassifyExteriorTrivia(t); break; case SyntaxKind.WhitespaceTrivia: if (whitespaceClassificationType != null) { AddClassification(t, whitespaceClassificationType); } break; } } }
static SyntaxTriviaList BuildCommentTrivia(IEnumerable<string> headerComments, string newLineText) { SyntaxTrivia newLineTrivia = SyntaxFactory.EndOfLine(newLineText); var commentTrivia = new SyntaxTriviaList(); var hasHeaderComments = false; foreach (string headerComment in headerComments) { hasHeaderComments = true; commentTrivia = commentTrivia.Add(SyntaxFactory.Comment(CommentPrefix + headerComment)); commentTrivia = commentTrivia.Add(newLineTrivia); } if (hasHeaderComments) { // Add an extra empty line below the header comments, if present. commentTrivia = commentTrivia.Add(newLineTrivia); } return commentTrivia; }
private void GenerateComments(SyntaxTriviaList triviaList) { foreach (var trivia in triviaList) { // Multi-line comment forms are ignored. if (trivia.Kind() == SyntaxKind.SingleLineCommentTrivia) { // In order to be valid, the comment must appear on its own line. var line = Text.Lines.GetLineFromPosition(trivia.SpanStart); var firstNonWhitespacePosition = line.GetFirstNonWhitespacePosition() ?? -1; if (firstNonWhitespacePosition == trivia.SpanStart) { using (var tag = CommentTag()) { // Skip initial slashes var trimmedComment = trivia.ToString().Substring(2); EncodedText(trimmedComment); } } } } }
public override SyntaxNode VisitBlock(BlockSyntax node) { var newNode = base.VisitBlock(node); node = newNode as BlockSyntax; if (node == null) { return newNode; } var triviaList = node.OpenBraceToken.GetNextToken().LeadingTrivia; var newList = new SyntaxTriviaList(); foreach (var trivia in triviaList) { if (trivia.Kind() != SyntaxKind.EndOfLineTrivia) { newList.Add(trivia); } } return node.WithLeadingTrivia(newList); }
private static void Analyze(SyntaxTriviaList list, ref AnalysisResult result) { if (list.Count == 0) { return; } foreach (var trivia in list) { if (trivia.Kind() == SyntaxKind.WhitespaceTrivia) { AnalyzeWhitespacesInTrivia(trivia, ref result); } else if (trivia.Kind() == SyntaxKind.EndOfLineTrivia) { AnalyzeLineBreak(trivia, ref result); } else if (trivia.IsRegularOrDocComment()) { result.HasComments = true; } else if (trivia.Kind() == SyntaxKind.SkippedTokensTrivia) { result.HasSkippedTokens = true; } else if (trivia.Kind() == SyntaxKind.DisabledTextTrivia || trivia.Kind() == SyntaxKind.PreprocessingMessageTrivia) { result.HasSkippedOrDisabledText = true; } else { Contract.ThrowIfFalse(SyntaxFacts.IsPreprocessorDirective(trivia.Kind())); result.HasPreprocessor = true; } } }
static SyntaxTriviaList Clean(SyntaxTriviaList trivia) { var flushStartIndex = 0; var allowExtraNewLine = false; for (int i = 0; i < trivia.Count; i++) { SyntaxTrivia currentTrivia = trivia[i]; if (!currentTrivia.IsKind(SyntaxKind.WhitespaceTrivia) && !currentTrivia.IsKind(SyntaxKind.EndOfLineTrivia)) { // Found a non-spacing trivia - time to flush the pending trivia SyntaxTriviaList newTrivia = FlushDuplicateTrivia( trivia, flushStartIndex, i, allowExtraNewLine); // Correct the loop index so when we finish our flush, we will resume the iteration at the next // unprocessed trivia. i -= trivia.Count - newTrivia.Count; trivia = newTrivia; flushStartIndex = i + 1; // If the non-spacing trivia does not contain a new line in trailing structured sub-trivia, // then allow an extra new line (this allows for scenarios like a comment followed by a blank // line). allowExtraNewLine = !currentTrivia.HasStructure || !currentTrivia.GetStructure().GetTrailingTrivia().Any(SyntaxKind.EndOfLineTrivia); } } // Perform a final flush if (flushStartIndex < trivia.Count) { trivia = FlushDuplicateTrivia(trivia, flushStartIndex, trivia.Count - 1, allowExtraNewLine); } return trivia; }
private void ProcessUsings( SyntaxList<UsingDirectiveSyntax> usings, ISet<UsingDirectiveSyntax> usingsToRemove, out SyntaxList<UsingDirectiveSyntax> finalUsings, out SyntaxTriviaList finalTrivia) { var currentUsings = new List<UsingDirectiveSyntax>(usings); finalTrivia = default(SyntaxTriviaList); for (int i = 0; i < usings.Count; i++) { if (usingsToRemove.Contains(usings[i])) { var currentUsing = currentUsings[i]; currentUsings[i] = null; var leadingTrivia = currentUsing.GetLeadingTrivia(); if (leadingTrivia.Any(t => t.Kind() != SyntaxKind.EndOfLineTrivia && t.Kind() != SyntaxKind.WhitespaceTrivia)) { // This using had trivia we want to preserve. If we're the last // directive, then copy this trivia out so that our caller can place // it on the next token. If there is any directive following us, // then place it on that. if (i < usings.Count - 1) { currentUsings[i + 1] = currentUsings[i + 1].WithPrependedLeadingTrivia(leadingTrivia); } else { finalTrivia = leadingTrivia; } } } } finalUsings = currentUsings.WhereNotNull().ToSyntaxList(); }
private static SyntaxNode ProcessTriviaList(SyntaxNode syntaxRoot, SyntaxTriviaList triviaList, SyntaxTrivia singleLineComment) { var index = triviaList.IndexOf(singleLineComment); if (index == -1) { return null; } index--; while (index >= 0) { switch (triviaList[index].Kind()) { case SyntaxKind.WhitespaceTrivia: index--; break; default: return syntaxRoot.ReplaceTrivia(triviaList[index], new[] { triviaList[index], SyntaxFactory.CarriageReturnLineFeed }); } } return syntaxRoot.ReplaceTrivia(triviaList[0], new[] { SyntaxFactory.CarriageReturnLineFeed, triviaList[0] }); }
public override SyntaxNode VisitLocalDeclarationStatement(LocalDeclarationStatementSyntax node) { node = (LocalDeclarationStatementSyntax)base.VisitLocalDeclarationStatement(node); var list = new List <VariableDeclaratorSyntax>(); var triviaList = new List <SyntaxTrivia>(); // go through each var decls in decl statement foreach (var variable in node.Declaration.Variables) { if (_variableToRemoveMap.HasSyntaxAnnotation(variable)) { // if it had initialization, it shouldn't reach here. Contract.ThrowIfFalse(variable.Initializer == null); // we don't remove trivia around tokens we remove triviaList.AddRange(variable.GetLeadingTrivia()); triviaList.AddRange(variable.GetTrailingTrivia()); continue; } if (triviaList.Count > 0) { list.Add(variable.WithPrependedLeadingTrivia(triviaList)); triviaList.Clear(); continue; } list.Add(variable); } if (list.Count == 0) { // nothing has survived. remove this from the list if (triviaList.Count == 0) { return(null); } // well, there are trivia associated with the node. // we can't just delete the node since then, we will lose // the trivia. unfortunately, it is not easy to attach the trivia // to next token. for now, create an empty statement and associate the // trivia to the statement // TODO : think about a way to move the trivia to next token. return(SyntaxFactory.EmptyStatement(SyntaxFactory.Token(SyntaxFactory.TriviaList(triviaList), SyntaxKind.SemicolonToken, SyntaxTriviaList.Create(SyntaxFactory.ElasticMarker)))); } if (list.Count == node.Declaration.Variables.Count) { // nothing has changed, return as it is return(node); } // TODO : fix how it manipulate trivia later // if there is left over syntax trivia, it will be attached to leading trivia // of semicolon return (SyntaxFactory.LocalDeclarationStatement( node.Modifiers, SyntaxFactory.VariableDeclaration( node.Declaration.Type, SyntaxFactory.SeparatedList(list)), node.SemicolonToken.WithPrependedLeadingTrivia(triviaList))); }
private bool ContainsNoisyTrivia(SyntaxTriviaList list) { return(list.Any(t => !_nonNoisySet.Contains(t.RawKind))); }
/// <summary> /// Strips all leading whitespace trivia from the trivia list until a non-whitespace trivia is encountered. /// </summary> /// <param name="triviaList">The trivia list to strip of its leading whitespace.</param> /// <param name="endOfLineIsWhitespace"><see langword="true"/> to treat <see cref="SyntaxKind.EndOfLineTrivia"/> /// as whitespace; otherwise, <see langword="false"/>.</param> /// <returns>The modified triviaList.</returns> internal static SyntaxTriviaList WithoutLeadingWhitespace(this SyntaxTriviaList triviaList, bool endOfLineIsWhitespace = true) { var nonWhitespaceIndex = IndexOfFirstNonWhitespaceTrivia(triviaList, endOfLineIsWhitespace); return((nonWhitespaceIndex >= 0) ? SyntaxFactory.TriviaList(triviaList.Skip(nonWhitespaceIndex)) : SyntaxFactory.TriviaList()); }
/// <summary> /// Merges the given trivia lists into a new single trivia list. /// </summary> /// <param name="list1">The first part of the new list.</param> /// <param name="list2">The second part of the new list.</param> /// <returns>The merged trivia list.</returns> internal static DualTriviaListHelper MergeTriviaLists(SyntaxTriviaList list1, SyntaxTriviaList list2) { return(new DualTriviaListHelper(list1, list2)); }
private static (bool emptyOrWhitespaceTrivia, bool documentationComment, bool emptyLine) AnalyzeLeadingTrivia(SyntaxTriviaList leadingTrivia) { SyntaxTriviaList.Enumerator en = leadingTrivia.GetEnumerator(); if (!en.MoveNext()) { return(true, false, false); } if (en.Current.IsWhitespaceTrivia() && !en.MoveNext()) { return(true, false, false); } switch (en.Current.Kind()) { case SyntaxKind.SingleLineDocumentationCommentTrivia: case SyntaxKind.MultiLineDocumentationCommentTrivia: { return(false, true, false); } case SyntaxKind.EndOfLineTrivia: { while (en.MoveNext()) { if (!en.Current.IsWhitespaceOrEndOfLineTrivia()) { return(default); } }
private static SyntaxToken UpdateTriviaList(SyntaxToken token, bool isStartToken, SyntaxTriviaList triviaList, AbstractSuppressionCodeFixProvider fixer) { return(isStartToken || fixer.IsEndOfFileToken(token) ? token.WithLeadingTrivia(triviaList) : token.WithTrailingTrivia(triviaList)); }
public static string GetNewLineIfExist(SyntaxTriviaList triviaList) { return(triviaList.Any(f => f.IsKind(SyntaxKind.EndOfLineTrivia)) ? Environment.NewLine : ""); }
protected abstract TStatementSyntax CreateUsingStatement(TLocalDeclarationSyntax declarationStatement, SyntaxTriviaList sameLineTrivia, SyntaxList <TStatementSyntax> statementsToSurround);
public static T WithTrivia <T>([NotNull] this T syntaxNode, SyntaxTriviaList leadingTrivia, SyntaxTriviaList trailingTrivia) where T : SyntaxNode { Requires.NotNull(syntaxNode, nameof(syntaxNode)); return(syntaxNode.WithTrailingTrivia(trailingTrivia).WithLeadingTrivia(leadingTrivia)); }
private static int GetIndentationSteps(IndentationOptions indentationOptions, SyntaxTree syntaxTree, SyntaxTriviaList leadingTrivia) { var triviaSpan = syntaxTree.GetLineSpan(leadingTrivia.FullSpan); // There is no indentation when the leading trivia doesn't begin at the start of the line. if ((triviaSpan.StartLinePosition == triviaSpan.EndLinePosition) && (triviaSpan.StartLinePosition.Character > 0)) { return(0); } var builder = StringBuilderPool.Allocate(); foreach (SyntaxTrivia trivia in leadingTrivia.Reverse()) { if (!trivia.IsKind(SyntaxKind.WhitespaceTrivia)) { break; } builder.Insert(0, trivia.ToFullString()); } var tabSize = indentationOptions.TabSize; var indentationCount = 0; for (var i = 0; i < builder.Length; i++) { indentationCount += builder[i] == '\t' ? tabSize - (indentationCount % tabSize) : 1; } StringBuilderPool.ReturnAndFree(builder); return((indentationCount + (indentationOptions.IndentationSize / 2)) / indentationOptions.IndentationSize); }
private static int GetIndentationStepsUnchecked(IndentationSettings indentationSettings, SyntaxTriviaList leadingTrivia) { var builder = StringBuilderPool.Allocate(); foreach (SyntaxTrivia trivia in leadingTrivia.Reverse()) { if (!trivia.IsKind(SyntaxKind.WhitespaceTrivia)) { break; } builder.Insert(0, trivia.ToFullString()); } var tabSize = indentationSettings.TabSize; var indentationCount = 0; for (var i = 0; i < builder.Length; i++) { indentationCount += builder[i] == '\t' ? tabSize - (indentationCount % tabSize) : 1; } StringBuilderPool.ReturnAndFree(builder); return((indentationCount + (indentationSettings.IndentationSize / 2)) / indentationSettings.IndentationSize); }
private static SyntaxToken CreateNewToken(SyntaxTriviaList leadingTrivia, SyntaxToken token, SyntaxTriviaList trailingTrivia) => token.With(leadingTrivia, trailingTrivia);
private static bool ContainsComment(SyntaxTriviaList trivias) { return(trivias.Any(trivia => trivia.IsKind(SyntaxKind.SingleLineCommentTrivia) || trivia.IsKind(SyntaxKind.MultiLineCommentTrivia))); }
private bool TryGetMacroDescriptor(SyntaxTriviaList triviaList, out MacroDescriptor descriptor, out SyntaxTriviaList leadingTrivia) { var(beforeMacro, macroTrivia) = SplitByMacro(triviaList); leadingTrivia = beforeMacro; if (macroTrivia.Count == 0) { descriptor = null; return(false); } var header = macroTrivia.First().ToString(); var templateLines = macroTrivia.Skip(1).SkipWhile(x => x.ToString().Equals("\r\n")).Select(x => x.ToString()); var matches = macroHeaderSyntax.Match(header); descriptor = new MacroDescriptor() { MacroName = matches.Groups["macro"].Value.Trim(), Param = matches.Groups["param"].Value.Trim(), Template = string.Join("", templateLines).TrimEnd(' ') }; return(true); }
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 CompilationUnitSyntax Reduce() { CompileResult debug = Compiler.Compile(Original, Compiler.DebugOptions); CompileResult release = Compiler.Compile(Original, Compiler.ReleaseOptions); if (debug.CompileDiagnostics.Length > 0 || release.CompileDiagnostics.Length > 0) { ImmutableArray <Diagnostic> diags = debug.CompileDiagnostics.Length > 0 ? debug.CompileDiagnostics : release.CompileDiagnostics; IEnumerable <Diagnostic> errs = diags.Where(d => d.Severity == DiagnosticSeverity.Error); string errorString = string.Join(Environment.NewLine, errs.Select(e => " " + e)); throw new InvalidOperationException("Program has compile errors: " + Environment.NewLine + errorString); } Func <CompilationUnitSyntax, bool> isInteresting; if (debug.RoslynException != null || release.RoslynException != null) { CSharpCompilationOptions opts = debug.RoslynException != null ? Compiler.DebugOptions : Compiler.ReleaseOptions; isInteresting = program => Compiler.Compile(program, opts).RoslynException != null; } else { var origPair = new ProgramPair(debug.Assembly, release.Assembly); ProgramPairResults origResults = ProgramExecutor.RunPair(origPair); if (origResults.DebugResult.Checksum == origResults.ReleaseResult.Checksum && origResults.DebugResult.ExceptionType == origResults.ReleaseResult.ExceptionType) { throw new InvalidOperationException("Program has no errors"); } isInteresting = prog => { ProgramPairResults results = CompileAndRun(prog); if (results == null) { return(false); } // Do exceptions first because they will almost always change checksum if (origResults.DebugResult.ExceptionType != origResults.ReleaseResult.ExceptionType) { // Must throw same exceptions in debug and release to be bad. return(results.DebugResult.ExceptionType == origResults.DebugResult.ExceptionType && results.ReleaseResult.ExceptionType == origResults.ReleaseResult.ExceptionType); } else { if (results.DebugResult.ExceptionType != origResults.DebugResult.ExceptionType || results.ReleaseResult.ExceptionType != origResults.ReleaseResult.ExceptionType) { return(false); } } return(results.DebugResult.Checksum != results.ReleaseResult.Checksum); }; } // Save original comments as simplification may remove it by removing an unnecessary type. SyntaxTriviaList originalTrivia = Original.GetLeadingTrivia(); Reduced = Original.WithLeadingTrivia(); Reduced = CoarseSimplify(Reduced, isInteresting); List <SyntaxNode> simplifiedNodes = new List <SyntaxNode>(); bool first = true; bool any = true; while (any) { any = false; while (true) { if (!SimplifyOne("Statements", Reduced.DescendantNodes().Where(n => n is StatementSyntax).ToList())) { break; } any = true; } while (true) { if (!SimplifyOne("Expressions", Reduced.DescendantNodes().Where(n => n is ExpressionSyntax).ToList())) { break; } any = true; } while (true) { List <SyntaxNode> members = Reduced.DescendantNodesAndSelf().Where(n => n is MemberDeclarationSyntax || n is CompilationUnitSyntax).ToList(); if (!SimplifyOne("Members", members)) { break; } any = true; } first = false; bool SimplifyOne(string name, List <SyntaxNode> list) { for (int i = 0; i < 2000; i++) { Console.Title = $"Simplifying {name}. Iter: {i}"; SyntaxNode node = list[_rng.Next(list.Count)]; // Do not optimize checksum args and call itself. // We still want to remove these statements, however, so we focus on the expression only. InvocationExpressionSyntax invocParent = node.FirstAncestorOrSelf <InvocationExpressionSyntax>(); if (invocParent != null && IsChecksumCall(invocParent)) { continue; } // If we fail at creating a new bad example, then we want to be able to restore the state // so the reducer will not blow these up unnecessarily. int origVarCounter = _varCounter; simplifiedNodes.Clear(); SimplifyNode(node, !first, simplifiedNodes); foreach (SyntaxNode candidateNode in simplifiedNodes) { CompilationUnitSyntax candidate = Reduced.ReplaceNode(node, candidateNode); if (isInteresting(candidate)) { Reduced = candidate; return(true); } } _varCounter = origVarCounter; } return(false); } } List <SyntaxTrivia> outputComments = GetOutputComments(debug, release).Select(Comment).ToList(); SimplifyRuntime(); double oldSizeKiB = Original.NormalizeWhitespace().ToString().Length / 1024.0; double newSizeKiB = Reduced.NormalizeWhitespace().ToString().Length / 1024.0; SyntaxTriviaList newTrivia = originalTrivia.Add(Comment(FormattableString.Invariant($"// Reduced from {oldSizeKiB:F1} KiB to {newSizeKiB:F1} KiB"))) .AddRange(outputComments); Reduced = Reduced.WithLeadingTrivia(newTrivia); return(Reduced); }
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()); } } }
protected override async Task <SyntaxNode> RewriteFieldNameAndAccessibilityAsync(string originalFieldName, bool makePrivate, Document document, SyntaxAnnotation declarationAnnotation, CodeAndImportGenerationOptionsProvider fallbackOptions, CancellationToken cancellationToken) { var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var declarator = root.GetAnnotatedNodes <VariableDeclaratorSyntax>(declarationAnnotation).FirstOrDefault(); // There may be no field to rewrite if this document is part of a set of linked files // and the declaration is not conditionally compiled in this document's project. if (declarator == null) { return(root); } var tempAnnotation = new SyntaxAnnotation(); var escapedName = originalFieldName.EscapeIdentifier(); var newIdentifier = SyntaxFactory.Identifier( leading: SyntaxTriviaList.Create(SyntaxFactory.ElasticMarker), contextualKind: SyntaxKind.IdentifierName, text: escapedName, valueText: originalFieldName, trailing: SyntaxTriviaList.Create(SyntaxFactory.ElasticMarker)) .WithTrailingTrivia(declarator.Identifier.TrailingTrivia) .WithLeadingTrivia(declarator.Identifier.LeadingTrivia); var updatedDeclarator = declarator.WithIdentifier(newIdentifier).WithAdditionalAnnotations(tempAnnotation); root = root.ReplaceNode(declarator, updatedDeclarator); document = document.WithSyntaxRoot(root); var declaration = root.GetAnnotatedNodes <SyntaxNode>(tempAnnotation).First().Parent as VariableDeclarationSyntax; if (declaration.Variables.Count == 1) { var fieldSyntax = declaration.Parent as FieldDeclarationSyntax; var modifierKinds = new[] { SyntaxKind.PrivateKeyword, SyntaxKind.ProtectedKeyword, SyntaxKind.InternalKeyword, SyntaxKind.PublicKeyword }; if (makePrivate) { var modifiers = SpecializedCollections.SingletonEnumerable(SyntaxFactory.Token(SyntaxKind.PrivateKeyword)) .Concat(fieldSyntax.Modifiers.Where(m => !modifierKinds.Contains(m.Kind()))); root = root.ReplaceNode(fieldSyntax, fieldSyntax.WithModifiers( SyntaxFactory.TokenList(modifiers)) .WithAdditionalAnnotations(Formatter.Annotation) .WithLeadingTrivia(fieldSyntax.GetLeadingTrivia()) .WithTrailingTrivia(fieldSyntax.GetTrailingTrivia())); } } else if (declaration.Variables.Count > 1 && makePrivate) { document = document.WithSyntaxRoot(root); var codeGenService = document.GetLanguageService <ICodeGenerationService>(); var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); declarator = root.GetAnnotatedNodes <VariableDeclaratorSyntax>(tempAnnotation).First(); declaration = declarator.Parent as VariableDeclarationSyntax; var field = semanticModel.GetDeclaredSymbol(declarator, cancellationToken) as IFieldSymbol; var fieldToAdd = declarationAnnotation.AddAnnotationToSymbol(CodeGenerationSymbolFactory.CreateFieldSymbol( field.GetAttributes(), Accessibility.Private, new DeclarationModifiers(isStatic: field.IsStatic, isReadOnly: field.IsReadOnly, isConst: field.IsConst), field.Type, field.Name, field.HasConstantValue, field.ConstantValue, declarator.Initializer)); var withField = await codeGenService.AddFieldAsync( new CodeGenerationSolutionContext( document.Project.Solution, CodeGenerationContext.Default, fallbackOptions), field.ContainingType, fieldToAdd, cancellationToken).ConfigureAwait(false); root = await withField.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); declarator = root.GetAnnotatedNodes <VariableDeclaratorSyntax>(tempAnnotation).First(); declaration = declarator.Parent as VariableDeclarationSyntax; return(root.RemoveNode(declarator, SyntaxRemoveOptions.KeepNoTrivia)); } return(root); }
/// <summary> /// Get's the language specific trivia that should be inserted before an operator if the /// user wants to wrap the operator to the next line. For C# this is a simple newline-trivia. /// For VB, this will be a line-continuation char (<c>_</c>), followed by a newline. /// </summary> protected abstract SyntaxTriviaList GetNewLineBeforeOperatorTrivia(SyntaxTriviaList newLine);
/// <summary> /// Strips all trailing whitespace trivia from the trivia list until a non-whitespace trivia is encountered. /// </summary> /// <param name="triviaList">The trivia list to strip of its trailing whitespace.</param> /// <returns>The modified triviaList.</returns> internal static SyntaxTriviaList WithoutTrailingWhitespace(this SyntaxTriviaList triviaList) { var trailingWhitespaceIndex = IndexOfTrailingWhitespace(triviaList); return((trailingWhitespaceIndex >= 0) ? SyntaxFactory.TriviaList(triviaList.Take(trailingWhitespaceIndex)) : triviaList); }
private static SyntaxToken CreateToken(SyntaxKind kind, SyntaxTriviaList triviaList) { return(Token(kind) .WithLeadingTrivia(triviaList) .WithTrailingSpace()); }
public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false); if (!TryFindFirstAncestorOrSelf(root, context.Span, out ReturnStatementSyntax returnStatement)) { return; } foreach (Diagnostic diagnostic in context.Diagnostics) { switch (diagnostic.Id) { case CompilerDiagnosticIdentifiers.CannotReturnValueFromIterator: { if (!Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.UseYieldReturnInsteadOfReturn)) { break; } ExpressionSyntax expression = returnStatement.Expression; if (expression != null) { SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); ISymbol containingSymbol = semanticModel.GetEnclosingSymbol(returnStatement.SpanStart, context.CancellationToken); if (containingSymbol?.Kind == SymbolKind.Method) { var methodSymbol = (IMethodSymbol)containingSymbol; ITypeSymbol returnType = methodSymbol.ReturnType; var replacementKind = SyntaxKind.None; if (returnType.SpecialType == SpecialType.System_Collections_IEnumerable) { if (semanticModel .GetTypeSymbol(expression, context.CancellationToken) .OriginalDefinition .IsIEnumerableOrIEnumerableOfT()) { replacementKind = SyntaxKind.ForEachStatement; } else { replacementKind = SyntaxKind.YieldReturnStatement; } } else if (returnType.Kind == SymbolKind.NamedType) { var namedTypeSymbol = (INamedTypeSymbol)returnType; if (namedTypeSymbol.OriginalDefinition.IsIEnumerableOfT()) { if (semanticModel.IsImplicitConversion(expression, namedTypeSymbol.TypeArguments[0])) { replacementKind = SyntaxKind.YieldReturnStatement; } else { replacementKind = SyntaxKind.ForEachStatement; } } } if (replacementKind == SyntaxKind.YieldReturnStatement || (replacementKind == SyntaxKind.ForEachStatement && !returnStatement.SpanContainsDirectives())) { CodeAction codeAction = CodeAction.Create( "Use yield return instead of return", cancellationToken => UseYieldReturnInsteadOfReturnRefactoring.RefactorAsync(context.Document, returnStatement, replacementKind, semanticModel, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); } } } break; } case CompilerDiagnosticIdentifiers.SinceMethodReturnsVoidReturnKeywordMustNotBeFollowedByObjectExpression: case CompilerDiagnosticIdentifiers.SinceMethodIsAsyncMethodThatReturnsTaskReturnKeywordMustNotBeFollowedByObjectExpression: { SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.ChangeMemberTypeAccordingToReturnExpression)) { ChangeMemberTypeRefactoring.ComputeCodeFix(context, diagnostic, returnStatement.Expression, semanticModel); } if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveReturnExpression)) { ISymbol symbol = semanticModel.GetEnclosingSymbol(returnStatement.SpanStart, context.CancellationToken); if (symbol?.Kind == SymbolKind.Method) { var methodSymbol = (IMethodSymbol)symbol; if (methodSymbol.ReturnsVoid || methodSymbol.ReturnType.HasMetadataName(MetadataNames.System_Threading_Tasks_Task)) { CodeAction codeAction = CodeAction.Create( "Remove return expression", cancellationToken => { ReturnStatementSyntax newNode = returnStatement .WithExpression(null) .WithFormatterAnnotation(); return(context.Document.ReplaceNodeAsync(returnStatement, newNode, cancellationToken)); }, GetEquivalenceKey(diagnostic, CodeFixIdentifiers.RemoveReturnExpression)); context.RegisterCodeFix(codeAction, diagnostic); } } } if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveReturnKeyword)) { ExpressionSyntax expression = returnStatement.Expression; if (expression.IsKind( SyntaxKind.InvocationExpression, SyntaxKind.ObjectCreationExpression, SyntaxKind.PreDecrementExpression, SyntaxKind.PreIncrementExpression, SyntaxKind.PostDecrementExpression, SyntaxKind.PostIncrementExpression) || expression is AssignmentExpressionSyntax) { CodeAction codeAction = CodeAction.Create( "Remove 'return'", cancellationToken => { SyntaxTriviaList leadingTrivia = returnStatement .GetLeadingTrivia() .AddRange(returnStatement.ReturnKeyword.TrailingTrivia.EmptyIfWhitespace()) .AddRange(expression.GetLeadingTrivia().EmptyIfWhitespace()); ExpressionStatementSyntax newNode = SyntaxFactory.ExpressionStatement( expression.WithLeadingTrivia(leadingTrivia), returnStatement.SemicolonToken); return(context.Document.ReplaceNodeAsync(returnStatement, newNode, cancellationToken)); }, GetEquivalenceKey(diagnostic, CodeFixIdentifiers.RemoveReturnKeyword)); context.RegisterCodeFix(codeAction, diagnostic); } } break; } } } }
public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { if (!Settings.IsEnabled(CodeFixIdentifiers.AddArgumentList) && !Settings.IsEnabled(CodeFixIdentifiers.OrderModifiers) && !Settings.IsEnabled(CodeFixIdentifiers.ReplaceNullLiteralExpressionWithDefaultValue) && !Settings.IsEnabled(CodeFixIdentifiers.ReturnDefaultValue) && !Settings.IsEnabled(CodeFixIdentifiers.AddMissingType) && !Settings.IsEnabled(CodeFixIdentifiers.RemoveSemicolon) && !Settings.IsEnabled(CodeFixIdentifiers.RemoveConditionalAccess) && !Settings.IsEnabled(CodeFixIdentifiers.ChangeForEachType) && !Settings.IsEnabled(CodeFixIdentifiers.AddDefaultValueToParameter) && !Settings.IsEnabled(CodeFixIdentifiers.ChangeParameterType)) { return; } SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false); if (!TryFindToken(root, context.Span.Start, out SyntaxToken token)) { return; } SyntaxKind kind = token.Kind(); foreach (Diagnostic diagnostic in context.Diagnostics) { switch (diagnostic.Id) { case CompilerDiagnosticIdentifiers.OperatorCannotBeAppliedToOperand: { if (kind == SyntaxKind.QuestionToken && token.Parent is ConditionalAccessExpressionSyntax conditionalAccess) { SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(conditionalAccess.Expression, context.CancellationToken); if (typeSymbol?.IsErrorType() == false && !typeSymbol.IsNullableType()) { if (typeSymbol.IsValueType) { if (Settings.IsEnabled(CodeFixIdentifiers.RemoveConditionalAccess)) { CodeAction codeAction = CodeAction.Create( "Remove '?' operator", cancellationToken => { var textChange = new TextChange(token.Span, ""); return(context.Document.WithTextChangeAsync(textChange, cancellationToken)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); } } else if (typeSymbol.IsReferenceType) { if (Settings.IsEnabled(CodeFixIdentifiers.AddArgumentList) && conditionalAccess.WhenNotNull is MemberBindingExpressionSyntax memberBindingExpression) { ConditionalAccessExpressionSyntax newNode = conditionalAccess.WithWhenNotNull( InvocationExpression( memberBindingExpression.WithoutTrailingTrivia(), ArgumentList().WithTrailingTrivia(memberBindingExpression.GetTrailingTrivia()))); CodeAction codeAction = CodeAction.Create( "Add argument list", cancellationToken => context.Document.ReplaceNodeAsync(conditionalAccess, newNode, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); } } } if (Settings.IsEnabled(CodeFixIdentifiers.AddArgumentList)) { break; } if (Settings.IsEnabled(CodeFixIdentifiers.RemoveConditionalAccess)) { } } break; } case CompilerDiagnosticIdentifiers.PartialModifierCanOnlyAppearImmediatelyBeforeClassStructInterfaceOrVoid: { if (!Settings.IsEnabled(CodeFixIdentifiers.OrderModifiers)) { break; } ModifiersCodeFixRegistrator.MoveModifier(context, diagnostic, token.Parent, token); break; } case CompilerDiagnosticIdentifiers.ValueCannotBeUsedAsDefaultParameter: { if (!Settings.IsAnyEnabled(CodeFixIdentifiers.ReplaceNullLiteralExpressionWithDefaultValue, CodeFixIdentifiers.ChangeParameterType)) { break; } if (!(token.Parent is ParameterSyntax parameter)) { break; } ExpressionSyntax value = parameter.Default?.Value; if (value == null) { break; } if (value.IsKind(SyntaxKind.NullLiteralExpression)) { if (Settings.IsEnabled(CodeFixIdentifiers.ReplaceNullLiteralExpressionWithDefaultValue)) { SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); CodeFixRegistrator.ReplaceNullWithDefaultValue(context, diagnostic, value, semanticModel); } } else if (!value.IsKind(SyntaxKind.DefaultExpression, SyntaxKind.DefaultLiteralExpression)) { if (Settings.IsEnabled(CodeFixIdentifiers.ChangeParameterType)) { SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(value, context.CancellationToken); if (!typeSymbol.IsKind(SymbolKind.ErrorType)) { CodeFixRegistrator.ChangeType(context, diagnostic, parameter.Type, typeSymbol, semanticModel); } } } break; } case CompilerDiagnosticIdentifiers.ObjectOfTypeConvertibleToTypeIsRequired: { if (!Settings.IsEnabled(CodeFixIdentifiers.ReturnDefaultValue)) { break; } if (token.Kind() != SyntaxKind.ReturnKeyword) { break; } if (!token.IsParentKind(SyntaxKind.ReturnStatement)) { break; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); ISymbol symbol = semanticModel.GetEnclosingSymbol(token.SpanStart, context.CancellationToken); if (symbol == null) { break; } SymbolKind symbolKind = symbol.Kind; ITypeSymbol typeSymbol = null; if (symbolKind == SymbolKind.Method) { var methodSymbol = (IMethodSymbol)symbol; typeSymbol = methodSymbol.ReturnType; if (methodSymbol.IsAsync && (typeSymbol is INamedTypeSymbol namedTypeSymbol)) { ImmutableArray <ITypeSymbol> typeArguments = namedTypeSymbol.TypeArguments; if (typeArguments.Any()) { typeSymbol = typeArguments[0]; } } } else if (symbolKind == SymbolKind.Property) { typeSymbol = ((IPropertySymbol)symbol).Type; } else { Debug.Fail(symbolKind.ToString()); } if (typeSymbol == null) { break; } if (typeSymbol.Kind == SymbolKind.ErrorType) { break; } if (!typeSymbol.SupportsExplicitDeclaration()) { break; } var returnStatement = (ReturnStatementSyntax)token.Parent; CodeAction codeAction = CodeAction.Create( "Return default value", cancellationToken => { ExpressionSyntax expression = typeSymbol.GetDefaultValueSyntax(context.Document.GetDefaultSyntaxOptions()); if (expression.IsKind(SyntaxKind.DefaultExpression) && context.Document.SupportsLanguageFeature(CSharpLanguageFeature.DefaultLiteral)) { expression = CSharpFactory.DefaultLiteralExpression().WithTriviaFrom(expression); } ReturnStatementSyntax newNode = returnStatement.WithExpression(expression); return(context.Document.ReplaceNodeAsync(returnStatement, newNode, cancellationToken)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case CompilerDiagnosticIdentifiers.TypeExpected: { if (!Settings.IsEnabled(CodeFixIdentifiers.AddMissingType)) { break; } if (token.Kind() != SyntaxKind.CloseParenToken) { break; } if (!(token.Parent is DefaultExpressionSyntax defaultExpression)) { break; } if (!(defaultExpression.Type is IdentifierNameSyntax identifierName)) { break; } if (!identifierName.IsMissing) { break; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); TypeInfo typeInfo = semanticModel.GetTypeInfo(defaultExpression, context.CancellationToken); ITypeSymbol convertedType = typeInfo.ConvertedType; if (convertedType?.SupportsExplicitDeclaration() != true) { break; } CodeAction codeAction = CodeAction.Create( $"Add type '{SymbolDisplay.ToMinimalDisplayString(convertedType, semanticModel, defaultExpression.SpanStart, SymbolDisplayFormats.Default)}'", cancellationToken => { TypeSyntax newNode = convertedType.ToMinimalTypeSyntax(semanticModel, defaultExpression.SpanStart); newNode = newNode .WithTriviaFrom(identifierName) .WithFormatterAnnotation(); return(context.Document.ReplaceNodeAsync(identifierName, newNode, cancellationToken)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case CompilerDiagnosticIdentifiers.SemicolonAfterMethodOrAccessorBlockIsNotValid: { if (!Settings.IsEnabled(CodeFixIdentifiers.RemoveSemicolon)) { break; } if (token.Kind() != SyntaxKind.SemicolonToken) { break; } switch (token.Parent) { case MethodDeclarationSyntax methodDeclaration: { BlockSyntax body = methodDeclaration.Body; if (body == null) { break; } CodeAction codeAction = CodeAction.Create( "Remove semicolon", cancellationToken => { SyntaxTriviaList trivia = body .GetTrailingTrivia() .EmptyIfWhitespace() .AddRange(token.LeadingTrivia.EmptyIfWhitespace()) .AddRange(token.TrailingTrivia); MethodDeclarationSyntax newNode = methodDeclaration .WithBody(body.WithTrailingTrivia(trivia)) .WithSemicolonToken(default(SyntaxToken)); return(context.Document.ReplaceNodeAsync(methodDeclaration, newNode, cancellationToken)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case PropertyDeclarationSyntax propertyDeclaration: { AccessorListSyntax accessorList = propertyDeclaration.AccessorList; if (accessorList == null) { break; } CodeAction codeAction = CodeAction.Create( "Remove semicolon", cancellationToken => { SyntaxTriviaList trivia = accessorList .GetTrailingTrivia() .EmptyIfWhitespace() .AddRange(token.LeadingTrivia.EmptyIfWhitespace()) .AddRange(token.TrailingTrivia); PropertyDeclarationSyntax newNode = propertyDeclaration .WithAccessorList(accessorList.WithTrailingTrivia(trivia)) .WithSemicolonToken(default(SyntaxToken)); return(context.Document.ReplaceNodeAsync(propertyDeclaration, newNode, cancellationToken)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case AccessorDeclarationSyntax accessorDeclaration: { BlockSyntax body = accessorDeclaration.Body; if (body == null) { break; } CodeAction codeAction = CodeAction.Create( "Remove semicolon", cancellationToken => { SyntaxTriviaList trivia = body .GetTrailingTrivia() .EmptyIfWhitespace() .AddRange(token.LeadingTrivia.EmptyIfWhitespace()) .AddRange(token.TrailingTrivia); AccessorDeclarationSyntax newNode = accessorDeclaration .WithBody(body.WithTrailingTrivia(trivia)) .WithSemicolonToken(default(SyntaxToken)); return(context.Document.ReplaceNodeAsync(accessorDeclaration, newNode, cancellationToken)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } } break; } case CompilerDiagnosticIdentifiers.CannotConvertType: { if (!Settings.IsEnabled(CodeFixIdentifiers.ChangeForEachType)) { break; } if (token.Kind() != SyntaxKind.ForEachKeyword) { break; } if (!(token.Parent is ForEachStatementSyntax forEachStatement)) { break; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); ForEachStatementInfo info = semanticModel.GetForEachStatementInfo(forEachStatement); ITypeSymbol typeSymbol = info.ElementType; if (typeSymbol.SupportsExplicitDeclaration()) { CodeFixRegistrator.ChangeType(context, diagnostic, forEachStatement.Type, typeSymbol, semanticModel, CodeFixIdentifiers.ChangeForEachType); } CodeFixRegistrator.ChangeTypeToVar(context, diagnostic, forEachStatement.Type, CodeFixIdentifiers.ChangeTypeToVar); break; } case CompilerDiagnosticIdentifiers.OptionalParametersMustAppearAfterAllRequiredParameters: { if (!Settings.IsEnabled(CodeFixIdentifiers.AddDefaultValueToParameter)) { break; } if (!(token.Parent is BaseParameterListSyntax parameterList)) { break; } SeparatedSyntaxList <ParameterSyntax> parameters = parameterList.Parameters; ParameterSyntax parameter = null; for (int i = 0; i < parameters.Count; i++) { ParameterSyntax p = parameters[i]; if (p.FullSpan.End <= token.SpanStart) { parameter = p; } else { break; } } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); IParameterSymbol parameterSymbol = semanticModel.GetDeclaredSymbol(parameter, context.CancellationToken); ITypeSymbol typeSymbol = parameterSymbol.Type; if (typeSymbol.Kind == SymbolKind.ErrorType) { break; } CodeAction codeAction = CodeAction.Create( "Add default value", cancellationToken => { ExpressionSyntax defaultValue = typeSymbol.GetDefaultValueSyntax(context.Document.GetDefaultSyntaxOptions()); ParameterSyntax newParameter = parameter .WithDefault(EqualsValueClause(defaultValue).WithTrailingTrivia(parameter.GetTrailingTrivia())) .WithoutTrailingTrivia() .WithFormatterAnnotation(); return(context.Document.ReplaceNodeAsync(parameter, newParameter, cancellationToken)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } } } }
public static async Task <Document> RefactorAsync( Document document, ConditionalExpressionSyntax conditionalExpression, CancellationToken cancellationToken) { ConditionalExpressionInfo info = SyntaxInfo.ConditionalExpressionInfo(conditionalExpression); ExpressionSyntax whenTrue = info.WhenTrue; ExpressionSyntax whenFalse = info.WhenFalse; SyntaxKind trueKind = whenTrue.Kind(); SyntaxKind falseKind = whenFalse.Kind(); ExpressionSyntax newNode = null; if (trueKind == SyntaxKind.TrueLiteralExpression) { if (falseKind == SyntaxKind.FalseLiteralExpression) { newNode = CreateNewNode(conditionalExpression, info.Condition); } else { SyntaxTriviaList trailingTrivia = info .QuestionToken .LeadingTrivia .AddRange(info.QuestionToken.TrailingTrivia) .AddRange(whenTrue.GetLeadingTrivia()) .EmptyIfWhitespace(); newNode = LogicalOrExpression( conditionalExpression.Condition.Parenthesize().AppendToTrailingTrivia(trailingTrivia), Token(info.ColonToken.LeadingTrivia, SyntaxKind.BarBarToken, info.ColonToken.TrailingTrivia), whenFalse.Parenthesize()); } } else if (falseKind == SyntaxKind.FalseLiteralExpression) { SyntaxTriviaList trailingTrivia = whenTrue .GetTrailingTrivia() .AddRange(info.ColonToken.LeadingTrivia) .AddRange(info.ColonToken.TrailingTrivia) .AddRange(whenFalse.GetLeadingTrivia()) .EmptyIfWhitespace() .AddRange(whenFalse.GetTrailingTrivia()); newNode = LogicalAndExpression( conditionalExpression.Condition.Parenthesize(), Token(info.QuestionToken.LeadingTrivia, SyntaxKind.AmpersandAmpersandToken, info.QuestionToken.TrailingTrivia), whenTrue.WithTrailingTrivia(trailingTrivia).Parenthesize()); } else if (trueKind == SyntaxKind.FalseLiteralExpression && falseKind == SyntaxKind.TrueLiteralExpression) { SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); newNode = CreateNewNode(conditionalExpression, SyntaxInverter.LogicallyInvert(info.Condition, semanticModel, cancellationToken)); } newNode = newNode.Parenthesize(); return(await document.ReplaceNodeAsync(conditionalExpression, newNode, cancellationToken).ConfigureAwait(false)); }
private static ExpressionSyntax GetExpression(AccessorListSyntax accessorList, out SyntaxTriviaList leadingTrivia) { var returnStatement = (ReturnStatementSyntax)accessorList.Accessors[0].Body.Statements[0]; leadingTrivia = returnStatement.GetLeadingTrivia(); // TODO: Concatenate any trivia between the return keyword and the expression? return(returnStatement.Expression); }
protected abstract SyntaxNode TryGetDocCommentNode(SyntaxTriviaList parameter);
private static ExpressionSyntax GetExpressionAndLeadingTrivia(BlockSyntax block, out SyntaxTriviaList leadingTrivia) { var returnStatement = (ReturnStatementSyntax)block.Statements[0]; leadingTrivia = returnStatement.GetLeadingTrivia(); // TODO: Concatenate any trivia between the return keyword and the expression? return(returnStatement.Expression); }
private void TestNormalize(SyntaxTriviaList trivia, string expected) { var actual = trivia.NormalizeWhitespace(" ").ToFullString().NormalizeLineEndings(); Assert.Equal(expected.NormalizeLineEndings(), actual); }
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); }
public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false); if (!TryFindFirstAncestorOrSelf(root, context.Span, out ExpressionSyntax expression)) { return; } Diagnostic diagnostic = context.Diagnostics[0]; Document document = context.Document; switch (expression) { case SimpleNameSyntax simpleName: { Debug.Assert(expression.IsKind(SyntaxKind.IdentifierName, SyntaxKind.GenericName), expression.Kind().ToString()); if (simpleName.IsParentKind(SyntaxKind.SimpleMemberAccessExpression)) { var memberAccessExpression = (MemberAccessExpressionSyntax)simpleName.Parent; SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); if (memberAccessExpression.IsParentKind(SyntaxKind.InvocationExpression)) { if (!memberAccessExpression.Parent.IsParentKind(SyntaxKind.ConditionalAccessExpression) && Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.ReplaceInvocationWithMemberAccessOrViceVersa)) { var invocationExpression = (InvocationExpressionSyntax)memberAccessExpression.Parent; if (!invocationExpression.ArgumentList.Arguments.Any()) { ReplaceInvocationWithMemberAccess(context, diagnostic, memberAccessExpression, invocationExpression, semanticModel); } } } else { if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.FixMemberAccessName)) { CodeFixRegistrationResult result = ReplaceCountWithLengthOrViceVersa(context, diagnostic, memberAccessExpression.Expression, simpleName, semanticModel); if (result.Success) { break; } } if (!memberAccessExpression.IsParentKind(SyntaxKind.ConditionalAccessExpression) && Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.ReplaceInvocationWithMemberAccessOrViceVersa)) { ReplaceMemberAccessWithInvocation(context, diagnostic, memberAccessExpression, semanticModel); } } } break; } case MemberBindingExpressionSyntax memberBindingExpression: { if (!Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.FixMemberAccessName)) { break; } if (!(memberBindingExpression.Parent is ConditionalAccessExpressionSyntax conditionalAccessExpression)) { break; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); CodeFixRegistrationResult result = ReplaceCountWithLengthOrViceVersa(context, diagnostic, conditionalAccessExpression.Expression, memberBindingExpression.Name, semanticModel); break; } case AwaitExpressionSyntax awaitExpression: { if (!Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveAwaitKeyword)) { break; } CodeAction codeAction = CodeAction.Create( "Remove 'await'", cancellationToken => { ExpressionSyntax expression2 = awaitExpression.Expression; SyntaxTriviaList leadingTrivia = awaitExpression .GetLeadingTrivia() .AddRange(awaitExpression.AwaitKeyword.TrailingTrivia.EmptyIfWhitespace()) .AddRange(expression2.GetLeadingTrivia().EmptyIfWhitespace()); ExpressionSyntax newNode = expression2.WithLeadingTrivia(leadingTrivia); return(document.ReplaceNodeAsync(awaitExpression, newNode, cancellationToken)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } } }