Пример #1
0
        private static int GetIndentationSteps(IndentationSettings indentationSettings, 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 = indentationSettings.TabSize;
            var indentationCount = 0;
            for (var i = 0; i < builder.Length; i++)
            {
                indentationCount += builder[i] == '\t' ? tabSize - (indentationCount % tabSize) : 1;
            }

            StringBuilderPool.ReturnAndFree(builder);

            return (indentationCount + (indentationSettings.IndentationSize / 2)) / indentationSettings.IndentationSize;
        }
        private SyntaxToken GetPreviousToken(
            SyntaxTrivia current,
            SyntaxTriviaList list,
            Func<SyntaxToken, bool> predicate,
            Func<SyntaxTrivia, bool> stepInto,
            ref bool returnPrevious)
        {
            foreach (var trivia in list.Reverse())
            {
                if (returnPrevious)
                {
                    SyntaxToken token;
                    if (TryGetLastTokenForStructuredTrivia(trivia, predicate, stepInto, out token))
                    {
                        return token;
                    }
                }
                else if (trivia == current)
                {
                    returnPrevious = true;
                }
            }

            return default(SyntaxToken);
        }
        private SyntaxToken GetLastToken(
            SyntaxTriviaList list,
            Func<SyntaxToken, bool> predicate,
            Func<SyntaxTrivia, bool> stepInto)
        {
            Debug.Assert(stepInto != null);

            foreach (var trivia in list.Reverse())
            {
                SyntaxToken token;
                if (TryGetLastTokenForStructuredTrivia(trivia, predicate, stepInto, out token))
                {
                    return token;
                }
            }

            return default(SyntaxToken);
        }
Пример #4
0
        private static int GetIndentationSteps(IndentationOptions indentationOptions, SyntaxTriviaList leadingTrivia)
        {
            SyntaxTriviaList.Reversed reversed = leadingTrivia.Reverse();
            int indentationCount = 0;

            foreach (SyntaxTrivia trivia in reversed)
            {
                if (!trivia.IsKind(SyntaxKind.WhitespaceTrivia))
                {
                    break;
                }

                foreach (char c in trivia.ToFullString())
                {
                    indentationCount += c == '\t' ? indentationOptions.TabSize : 1;
                }
            }

            return indentationCount / indentationOptions.IndentationSize;
        }
Пример #5
0
        public static Task <Document> FixBinaryExpressionAsync(
            Document document,
            BinaryExpressionSyntax binaryExpression,
            TextSpan span,
            CancellationToken cancellationToken)
        {
            IndentationAnalysis indentationAnalysis = AnalyzeIndentation(binaryExpression, cancellationToken);

            string indentation;

            if (indentationAnalysis.Indentation == binaryExpression.GetLeadingTrivia().LastOrDefault() &&
                document.IsAnalyzerOptionEnabled(AnalyzerOptions.AddNewLineAfterBinaryOperatorInsteadOfBeforeIt))
            {
                indentation = indentationAnalysis.Indentation.ToString();
            }
            else
            {
                indentation = indentationAnalysis.GetIncreasedIndentation();
            }

            string endOfLineAndIndentation = DetermineEndOfLine(binaryExpression).ToString() + indentation;

            var textChanges = new List <TextChange>();
            int prevIndex   = binaryExpression.Span.End;

            SyntaxKind binaryKind = binaryExpression.Kind();

            while (true)
            {
                SyntaxToken token = binaryExpression.OperatorToken;

                if (token.Span.End > span.End)
                {
                    continue;
                }

                if (token.SpanStart < span.Start)
                {
                    break;
                }

                ExpressionSyntax left          = binaryExpression.Left;
                ExpressionSyntax right         = binaryExpression.Right;
                SyntaxTriviaList leftTrailing  = left.GetTrailingTrivia();
                SyntaxTriviaList tokenTrailing = token.TrailingTrivia;

                if (IsOptionalWhitespaceThenOptionalSingleLineCommentThenEndOfLineTrivia(leftTrailing))
                {
                    if (!SetIndentation(token))
                    {
                        break;
                    }
                }
                else if (IsOptionalWhitespaceThenOptionalSingleLineCommentThenEndOfLineTrivia(tokenTrailing))
                {
                    if (!SetIndentation(right))
                    {
                        break;
                    }
                }
                else if (leftTrailing.IsEmptyOrWhitespace() &&
                         tokenTrailing.IsEmptyOrWhitespace())
                {
                    if (document.IsAnalyzerOptionEnabled(AnalyzerOptions.AddNewLineAfterBinaryOperatorInsteadOfBeforeIt))
                    {
                        if (!SetIndentation(right))
                        {
                            break;
                        }
                    }
                    else if (!SetIndentation(token))
                    {
                        break;
                    }
                }

                if (!left.IsKind(binaryKind))
                {
                    break;
                }

                binaryExpression = (BinaryExpressionSyntax)left;
            }

            if (textChanges.Count > 0)
            {
                SyntaxTriviaList leading = binaryExpression.GetLeadingTrivia();

                if (!leading.Any())
                {
                    SyntaxTrivia trivia = binaryExpression.GetFirstToken().GetPreviousToken().TrailingTrivia.LastOrDefault();

                    if (trivia.IsEndOfLineTrivia() &&
                        trivia.Span.End == binaryExpression.SpanStart)
                    {
                        textChanges.Add(new TextSpan(binaryExpression.SpanStart, 0), indentation);
                    }
                }
            }

            FormattingVerifier.VerifyChangedSpansAreWhitespace(binaryExpression, textChanges);

            return(document.WithTextChangesAsync(textChanges, cancellationToken));

            bool SetIndentation(SyntaxNodeOrToken nodeOrToken)
            {
                SyntaxTriviaList leading = nodeOrToken.GetLeadingTrivia();

                SyntaxTriviaList.Reversed.Enumerator en = leading.Reverse().GetEnumerator();

                if (!en.MoveNext())
                {
                    SyntaxTrivia trivia = binaryExpression.FindTrivia(nodeOrToken.SpanStart - 1);

                    string newText = (trivia.IsEndOfLineTrivia()) ? indentation : endOfLineAndIndentation;

                    int start = (trivia.IsWhitespaceTrivia()) ? trivia.SpanStart : nodeOrToken.SpanStart;

                    TextSpan span = (trivia.IsWhitespaceTrivia())
                        ? trivia.Span
                        : new TextSpan(nodeOrToken.SpanStart, 0);

                    textChanges.Add(span, newText);
                    SetIndendation(nodeOrToken, prevIndex);
                    prevIndex = start;
                    return(true);
                }

                SyntaxTrivia last = en.Current;

                SyntaxKind kind = en.Current.Kind();

                if (kind == SyntaxKind.WhitespaceTrivia)
                {
                    if (en.Current.Span.Length != indentation.Length)
                    {
                        if (!en.MoveNext() ||
                            en.Current.IsEndOfLineTrivia())
                        {
                            SyntaxTrivia trivia = binaryExpression.FindTrivia(nodeOrToken.FullSpan.Start - 1);

                            if (trivia.IsEndOfLineTrivia())
                            {
                                AddTextChange((leading.IsEmptyOrWhitespace()) ? leading.Span : last.Span);
                                SetIndendation(nodeOrToken, prevIndex);
                                prevIndex = trivia.SpanStart;
                                return(true);
                            }
                        }
                    }
                }
                else if (kind == SyntaxKind.EndOfLineTrivia)
                {
                    SyntaxTrivia trivia = binaryExpression.FindTrivia(nodeOrToken.FullSpan.Start - 1);

                    if (trivia.IsEndOfLineTrivia())
                    {
                        AddTextChange((leading.IsEmptyOrWhitespace()) ? leading.Span : last.Span);
                        SetIndendation(nodeOrToken, prevIndex);
                        prevIndex = trivia.SpanStart;
                        return(true);
                    }
                }

                prevIndex = leading.Span.Start - 1;
                return(true);

                void AddTextChange(TextSpan span) => textChanges.Add(span, indentation);
            }

            void SetIndendation(SyntaxNodeOrToken nodeOrToken, int endIndex)
            {
                ImmutableArray <IndentationInfo> indentations = FindIndentations(
                    binaryExpression,
                    TextSpan.FromBounds(nodeOrToken.SpanStart, endIndex))
                                                                .ToImmutableArray();

                if (!indentations.Any())
                {
                    return;
                }

                int firstIndentationLength = indentations[0].Span.Length;

                for (int j = 0; j < indentations.Length; j++)
                {
                    IndentationInfo indentationInfo = indentations[j];

                    string replacement = indentation + indentationAnalysis.GetSingleIndentation();

                    if (j > 0 &&
                        indentationInfo.Span.Length > firstIndentationLength)
                    {
                        replacement += indentationInfo.ToString().Substring(firstIndentationLength);
                    }

                    if (indentationInfo.Span.Length != replacement.Length)
                    {
                        textChanges.Add(indentationInfo.Span, replacement);
                    }
                }
            }
        }
Пример #6
0
        public static Task <Document> FixCallChainAsync(
            Document document,
            ExpressionSyntax expression,
            TextSpan span,
            CancellationToken cancellationToken = default)
        {
            IndentationAnalysis indentationAnalysis = AnalyzeIndentation(expression, cancellationToken);
            string indentation             = indentationAnalysis.GetIncreasedIndentation();
            string endOfLineAndIndentation = DetermineEndOfLine(expression).ToString() + indentation;

            var textChanges = new List <TextChange>();
            int prevIndex   = expression.Span.End;

            foreach (SyntaxNode node in new MethodChain(expression))
            {
                SyntaxKind kind = node.Kind();

                if (kind == SyntaxKind.SimpleMemberAccessExpression)
                {
                    var memberAccess = (MemberAccessExpressionSyntax)node;

                    if (!SetIndentation(memberAccess.OperatorToken))
                    {
                        break;
                    }
                }
                else if (kind == SyntaxKind.MemberBindingExpression)
                {
                    var memberBinding = (MemberBindingExpressionSyntax)node;

                    if (!SetIndentation(memberBinding.OperatorToken))
                    {
                        break;
                    }
                }
            }

            FormattingVerifier.VerifyChangedSpansAreWhitespace(expression, textChanges);

            return(document.WithTextChangesAsync(textChanges, cancellationToken));

            bool SetIndentation(SyntaxToken token)
            {
                if (token.Span.End > span.End)
                {
                    return(true);
                }

                if (token.SpanStart < span.Start)
                {
                    return(false);
                }

                SyntaxTriviaList leading = token.LeadingTrivia;

                SyntaxTriviaList.Reversed.Enumerator en = leading.Reverse().GetEnumerator();

                if (!en.MoveNext())
                {
                    SyntaxTrivia trivia = expression.FindTrivia(token.SpanStart - 1);

                    string newText = (trivia.IsEndOfLineTrivia()) ? indentation : endOfLineAndIndentation;

                    textChanges.Add(new TextSpan(token.SpanStart, 0), newText);

                    SetIndendation(token, prevIndex);
                    prevIndex = (trivia.IsEndOfLineTrivia()) ? trivia.SpanStart : token.SpanStart;
                    return(true);
                }

                SyntaxTrivia last = en.Current;

                SyntaxKind kind = en.Current.Kind();

                if (kind == SyntaxKind.WhitespaceTrivia)
                {
                    if (en.Current.Span.Length != indentation.Length)
                    {
                        if (!en.MoveNext() ||
                            en.Current.IsEndOfLineTrivia())
                        {
                            SyntaxTrivia trivia = expression.FindTrivia(token.FullSpan.Start - 1);

                            if (trivia.IsEndOfLineTrivia())
                            {
                                textChanges.Add((leading.IsEmptyOrWhitespace()) ? leading.Span : last.Span, indentation);
                                SetIndendation(token, prevIndex);
                                prevIndex = trivia.SpanStart;
                                return(true);
                            }
                        }
                    }
                }
                else if (kind == SyntaxKind.EndOfLineTrivia)
                {
                    SyntaxTrivia trivia = expression.FindTrivia(token.FullSpan.Start - 1);

                    if (trivia.IsEndOfLineTrivia())
                    {
                        textChanges.Add((leading.IsEmptyOrWhitespace()) ? leading.Span : last.Span, indentation);
                        SetIndendation(token, prevIndex);
                        prevIndex = trivia.SpanStart;
                        return(true);
                    }
                }

                prevIndex = leading.Span.Start - 1;
                return(true);
            }

            void SetIndendation(SyntaxToken token, int endIndex)
            {
                ImmutableArray <IndentationInfo> indentations = FindIndentations(
                    expression,
                    TextSpan.FromBounds(token.SpanStart, endIndex))
                                                                .ToImmutableArray();

                if (!indentations.Any())
                {
                    return;
                }

                int firstIndentationLength = indentations[0].Span.Length;

                for (int j = 0; j < indentations.Length; j++)
                {
                    IndentationInfo indentationInfo = indentations[j];

                    string replacement = indentation + indentationAnalysis.GetSingleIndentation();

                    if (j > 0 &&
                        indentationInfo.Span.Length > firstIndentationLength)
                    {
                        replacement += indentationInfo.ToString().Substring(firstIndentationLength);
                    }

                    if (indentationInfo.Span.Length != replacement.Length)
                    {
                        textChanges.Add(indentationInfo.Span, replacement);
                    }
                }
            }
        }