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;
        }
Beispiel #5
0
 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;
            }
Beispiel #17
0
        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;
 }
Beispiel #20
0
        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] });
        }
Beispiel #31
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)));
                }
Beispiel #32
0
 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);
                    }
                }
Beispiel #36
0
 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 : "");
 }
Beispiel #38
0
 protected abstract TStatementSyntax CreateUsingStatement(TLocalDeclarationSyntax declarationStatement, SyntaxTriviaList sameLineTrivia, SyntaxList <TStatementSyntax> statementsToSurround);
Beispiel #39
0
 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);
        }
Beispiel #42
0
 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)));
 }
Beispiel #44
0
        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());
                }
            }
        }
Beispiel #46
0
        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);
        }
Beispiel #51
0
 private static SyntaxToken CreateToken(SyntaxKind kind, SyntaxTriviaList triviaList)
 {
     return(Token(kind)
            .WithLeadingTrivia(triviaList)
            .WithTrailingSpace());
 }
Beispiel #52
0
        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);
        }
Beispiel #56
0
 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);
        }
Beispiel #59
0
        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);
        }
Beispiel #60
0
        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;
            }
            }
        }