private static void Analyze(
            SyntaxNodeAnalysisContext context,
            SyntaxToken token,
            SyntaxNode node)
        {
            SyntaxTriviaList trailingTrivia = token.TrailingTrivia;
            SyntaxTriviaList leadingTrivia  = node.GetLeadingTrivia();

            if (!IsStandardTriviaBetweenLines(trailingTrivia, leadingTrivia) &&
                token
                .SyntaxTree
                .GetLineSpan(TextSpan.FromBounds(token.Span.End, node.Span.Start), context.CancellationToken)
                .GetLineCount() == 3)
            {
                SyntaxTrivia trivia = leadingTrivia
                                      .SkipWhile(f => f.IsWhitespaceTrivia())
                                      .FirstOrDefault();

                if (trivia.IsEndOfLineTrivia() &&
                    trailingTrivia.All(f => f.IsWhitespaceOrEndOfLineTrivia()) &&
                    leadingTrivia.All(f => f.IsWhitespaceOrEndOfLineTrivia()))
                {
                    context.ReportDiagnostic(
                        DiagnosticDescriptors.RemoveRedundantEmptyLine,
                        Location.Create(token.SyntaxTree, TextSpan.FromBounds(node.FullSpan.Start, trivia.Span.End)));
                }
            }
        }
예제 #2
0
        private static T RemoveNode <T>(
            T declaration,
            Func <T, SyntaxList <MemberDeclarationSyntax> > getMembers,
            int index,
            SyntaxRemoveOptions removeOptions) where T : SyntaxNode
        {
            SyntaxList <MemberDeclarationSyntax> members = getMembers(declaration);

            T newDeclaration = declaration.RemoveNode(members[index], removeOptions);

            if (index == 0 &&
                index < members.Count - 1)
            {
                members = getMembers(newDeclaration);

                MemberDeclarationSyntax nextMember = members[index];

                SyntaxTriviaList leadingTrivia = nextMember.GetLeadingTrivia();

                SyntaxTrivia trivia = leadingTrivia.FirstOrDefault();

                if (trivia.IsEndOfLineTrivia())
                {
                    MemberDeclarationSyntax newNextMember = nextMember.WithLeadingTrivia(leadingTrivia.RemoveAt(0));

                    newDeclaration = newDeclaration.ReplaceNode(nextMember, newNextMember);
                }
            }

            return(newDeclaration);
        }
예제 #3
0
        public static SyntaxTrivia DetermineEndOfLine(SyntaxToken token, SyntaxTrivia?defaultValue = null)
        {
            SyntaxTrivia trivia = FindEndOfLine(token);

            return((trivia.IsEndOfLineTrivia())
                ? trivia
                : defaultValue ?? CSharpFactory.NewLine());
        }
        private static void Analyze(
            SyntaxNodeAnalysisContext context,
            StatementSyntax containingStatement,
            SyntaxToken token,
            StatementSyntax statement)
        {
            if (token.IsMissing)
            {
                return;
            }

            if (statement?.IsKind(SyntaxKind.Block, SyntaxKind.EmptyStatement) != false)
            {
                return;
            }

            if (!containingStatement.SyntaxTree.IsMultiLineSpan(TextSpan.FromBounds(token.SpanStart, statement.SpanStart)))
            {
                return;
            }

            SyntaxNode parent = containingStatement.Parent;

            if (parent?.Kind() != SyntaxKind.Block)
            {
                return;
            }

            var block = (BlockSyntax)parent;

            SyntaxList <StatementSyntax> statements = block.Statements;

            int index = statements.IndexOf(containingStatement);

            if (index == statements.Count - 1)
            {
                return;
            }

            if (containingStatement
                .SyntaxTree
                .GetLineCount(TextSpan.FromBounds(statement.Span.End, statements[index + 1].SpanStart)) > 2)
            {
                return;
            }

            SyntaxTrivia trivia = statement
                                  .GetTrailingTrivia()
                                  .FirstOrDefault(f => f.IsEndOfLineTrivia());

            if (!trivia.IsEndOfLineTrivia())
            {
                return;
            }

            context.ReportDiagnostic(DiagnosticDescriptors.AddEmptyLineAfterEmbeddedStatement, trivia);
        }
예제 #5
0
        private static void Analyze(
            SyntaxNodeAnalysisContext context,
            StatementSyntax containingStatement,
            SyntaxToken token,
            StatementSyntax statement)
        {
            if (token.IsMissing)
            {
                return;
            }

            if (statement?.IsKind(SyntaxKind.Block, SyntaxKind.EmptyStatement) != false)
            {
                return;
            }

            StatementListInfo statementsInfo = SyntaxInfo.StatementListInfo(containingStatement);

            if (!statementsInfo.Success)
            {
                return;
            }

            SyntaxTree syntaxTree = containingStatement.SyntaxTree;

            if (!syntaxTree.IsMultiLineSpan(TextSpan.FromBounds(token.SpanStart, statement.SpanStart)))
            {
                return;
            }

            StatementSyntax nextStatement = containingStatement.NextStatement();

            if (nextStatement == null)
            {
                return;
            }

            if (syntaxTree.GetLineCount(TextSpan.FromBounds(statement.Span.End, nextStatement.SpanStart)) > 2)
            {
                return;
            }

            SyntaxTrivia trivia = statement
                                  .GetTrailingTrivia()
                                  .FirstOrDefault(f => f.IsEndOfLineTrivia());

            if (!trivia.IsEndOfLineTrivia())
            {
                return;
            }

            DiagnosticHelpers.ReportDiagnostic(
                context,
                DiagnosticRules.AddEmptyLineAfterEmbeddedStatement,
                Location.Create(syntaxTree, trivia.Span.WithLength(0)));
        }
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            SyntaxNode root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);

            SyntaxTrivia trivia = root.FindTrivia(context.Span.Start);

            Debug.Assert(trivia.IsEndOfLineTrivia(), $"{nameof(trivia)} is not EOF");

            if (!trivia.IsEndOfLineTrivia())
            {
                return;
            }

            CodeAction codeAction = CodeAction.Create(
                "Add empty line",
                cancellationToken => RefactorAsync(context.Document, trivia.Token, cancellationToken),
                DiagnosticIdentifiers.AddEmptyLineAfterClosingBrace + EquivalenceKeySuffix);

            context.RegisterCodeFix(codeAction, context.Diagnostics);
        }
        private static void Analyze(SyntaxNodeAnalysisContext context, MemberDeclarationSyntax declaration, SyntaxToken openToken, SyntaxToken closeToken)
        {
            if (declaration.IsParentKind(SyntaxKind.CompilationUnit))
            {
                return;
            }

            if (openToken.IsMissing)
            {
                return;
            }

            if (closeToken.IsMissing)
            {
                return;
            }

            int closeTokenLine = closeToken.GetSpanEndLine();

            if (openToken.GetSpanEndLine() == closeTokenLine)
            {
                return;
            }

            MemberDeclarationSyntax nextDeclaration = GetNextDeclaration(declaration);

            if (nextDeclaration == null)
            {
                return;
            }

            int diff = nextDeclaration.GetSpanStartLine() - closeTokenLine;

            if (diff >= 2)
            {
                return;
            }

            SyntaxTrivia trivia = declaration.GetTrailingTrivia().LastOrDefault();

            if (trivia.IsEndOfLineTrivia())
            {
                context.ReportDiagnostic(DiagnosticDescriptors.AddEmptyLineBetweenDeclarations, trivia);
            }
            else
            {
                context.ReportDiagnostic(DiagnosticDescriptors.AddEmptyLineBetweenDeclarations, closeToken);
            }
        }
        public static void Analyze(SyntaxNodeAnalysisContext context, SwitchStatementSyntax switchStatement)
        {
            SyntaxList <SwitchSectionSyntax> sections = switchStatement.Sections;

            if (sections.Any())
            {
                AnalyzeStart(context, sections.First(), switchStatement.OpenBraceToken);
                AnalyzeEnd(context, sections.Last(), switchStatement.CloseBraceToken);

                if (sections.Count > 1)
                {
                    SwitchSectionSyntax prevSection = sections.First();

                    for (int i = 1; i < sections.Count; i++)
                    {
                        if (prevSection.Statements.LastOrDefault()?.IsKind(SyntaxKind.Block) == true)
                        {
                            SwitchSectionSyntax section = sections[i];

                            SyntaxTriviaList trailingTrivia = prevSection.GetTrailingTrivia();
                            SyntaxTriviaList leadingTrivia  = section.GetLeadingTrivia();

                            if (!IsStandardTriviaBetweenSections(trailingTrivia, leadingTrivia) &&
                                switchStatement
                                .SyntaxTree
                                .GetLineSpan(TextSpan.FromBounds(prevSection.Span.End, section.Span.Start), context.CancellationToken)
                                .GetLineCount() == 3)
                            {
                                SyntaxTrivia trivia = leadingTrivia
                                                      .SkipWhile(f => f.IsWhitespaceTrivia())
                                                      .FirstOrDefault();

                                if (trivia.IsEndOfLineTrivia() &&
                                    trailingTrivia.All(f => f.IsWhitespaceOrEndOfLineTrivia()) &&
                                    leadingTrivia.All(f => f.IsWhitespaceOrEndOfLineTrivia()))
                                {
                                    context.ReportDiagnostic(
                                        DiagnosticDescriptors.RemoveRedundantEmptyLine,
                                        Location.Create(switchStatement.SyntaxTree, TextSpan.FromBounds(section.FullSpan.Start, trivia.Span.End)));
                                }
                            }
                        }

                        prevSection = sections[i];
                    }
                }
            }
        }
예제 #9
0
        public static void Analyze(SyntaxNodeAnalysisContext context, DoStatementSyntax doStatement)
        {
            StatementSyntax statement = doStatement.Statement;

            if (statement?.IsKind(SyntaxKind.Block) == true)
            {
                var block = (BlockSyntax)statement;

                SyntaxList <StatementSyntax> statements = block.Statements;

                if (statements.Any())
                {
                    SyntaxToken closeBrace = block.CloseBraceToken;

                    if (!closeBrace.IsMissing)
                    {
                        SyntaxToken whileKeyword = doStatement.WhileKeyword;

                        if (!whileKeyword.IsMissing)
                        {
                            int closeBraceLine = closeBrace.GetSpanEndLine();

                            if (closeBraceLine == whileKeyword.GetSpanStartLine())
                            {
                                StatementSyntax last = statements.Last();

                                int line = last.GetSpanEndLine(context.CancellationToken);

                                if (closeBraceLine - line == 1)
                                {
                                    SyntaxTrivia trivia = last
                                                          .GetTrailingTrivia()
                                                          .FirstOrDefault(f => f.IsEndOfLineTrivia());

                                    if (trivia.IsEndOfLineTrivia())
                                    {
                                        context.ReportDiagnostic(
                                            DiagnosticDescriptors.AddEmptyLineAfterLastStatementInDoStatement,
                                            Location.Create(doStatement.SyntaxTree, trivia.Span));
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
예제 #10
0
        public static void AnalyzeMemberDeclaration(SyntaxNodeAnalysisContext context)
        {
            var declaration = (MemberDeclarationSyntax)context.Node;

            if (!declaration.IsParentKind(SyntaxKind.CompilationUnit))
            {
                TokenPair   tokenPair  = GetTokenPair(declaration);
                SyntaxToken openToken  = tokenPair.OpenToken;
                SyntaxToken closeToken = tokenPair.CloseToken;

                if (!openToken.IsKind(SyntaxKind.None) &&
                    !openToken.IsMissing &&
                    !closeToken.IsKind(SyntaxKind.None) &&
                    !closeToken.IsMissing)
                {
                    int closeTokenLine = closeToken.GetSpanEndLine();

                    if (openToken.GetSpanEndLine() != closeTokenLine)
                    {
                        MemberDeclarationSyntax nextDeclaration = GetNextDeclaration(declaration);

                        if (nextDeclaration != null)
                        {
                            int diff = nextDeclaration.GetSpanStartLine() - closeTokenLine;

                            if (diff < 2)
                            {
                                SyntaxTrivia trivia = declaration.GetTrailingTrivia().LastOrDefault();

                                if (trivia.IsEndOfLineTrivia())
                                {
                                    context.ReportDiagnostic(
                                        DiagnosticDescriptors.AddEmptyLineBetweenDeclarations,
                                        trivia);
                                }
                                else
                                {
                                    context.ReportDiagnostic(
                                        DiagnosticDescriptors.AddEmptyLineBetweenDeclarations,
                                        closeToken);
                                }
                            }
                        }
                    }
                }
            }
        }
예제 #11
0
        public static async Task ComputeRefactoringAsync(RefactoringContext context, LocalDeclarationStatementSyntax localDeclaration)
        {
            VariableDeclarationSyntax declaration = localDeclaration.Declaration;

            TypeSyntax type = declaration?.Type;

            if (type?.IsVar == false)
            {
                VariableDeclaratorSyntax declarator = declaration.Variables.FirstOrDefault();

                if (declarator != null &&
                    context.Span.Start >= type.Span.Start)
                {
                    SyntaxTriviaList triviaList = type.GetTrailingTrivia();

                    if (triviaList.Any())
                    {
                        SyntaxTrivia trivia = triviaList
                                              .SkipWhile(f => f.IsWhitespaceTrivia())
                                              .FirstOrDefault();

                        if (trivia.IsEndOfLineTrivia() &&
                            context.Span.End <= trivia.Span.Start)
                        {
                            SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                            ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(type, context.CancellationToken);

                            string name = NameGenerator.Default.CreateUniqueLocalName(
                                typeSymbol,
                                semanticModel,
                                declarator.SpanStart,
                                cancellationToken: context.CancellationToken);

                            if (name != null)
                            {
                                context.RegisterRefactoring(
                                    $"Add identifier '{name}'",
                                    c => RefactorAsync(context.Document, type, name, c));
                            }
                        }
                    }
                }
            }
        }
예제 #12
0
        private static IEnumerable <TextLine> GetEmptyLines(SourceText sourceText, SyntaxNode root, TextSpan span)
        {
            foreach (TextLine line in sourceText
                     .Lines
                     .SkipWhile(f => f.Start < span.Start)
                     .TakeWhile(f => f.EndIncludingLineBreak <= span.End))
            {
                if (line.Span.Length == 0 || StringUtility.IsWhitespace(line.ToString()))
                {
                    SyntaxTrivia endOfLine = root.FindTrivia(line.End, findInsideTrivia: true);

                    if (endOfLine.IsEndOfLineTrivia())
                    {
                        yield return(line);
                    }
                }
            }
        }
예제 #13
0
        private static void Analyze(SyntaxNodeAnalysisContext context, SyntaxToken closeBrace, StatementSyntax blockOrStatement)
        {
            StatementSyntax nextStatement = blockOrStatement.NextStatement();

            if (nextStatement != null &&
                closeBrace.SyntaxTree.GetLineCount(TextSpan.FromBounds(closeBrace.Span.End, nextStatement.SpanStart)) == 2)
            {
                SyntaxTrivia endOfLine = closeBrace
                                         .TrailingTrivia
                                         .FirstOrDefault(f => f.IsEndOfLineTrivia());

                if (endOfLine.IsEndOfLineTrivia())
                {
                    context.ReportDiagnostic(
                        DiagnosticDescriptors.AddEmptyLineBetweenBlockAndStatement,
                        Location.Create(endOfLine.SyntaxTree, endOfLine.Span.WithLength(0)));
                }
            }
        }
예제 #14
0
        private static void Analyze(
            SyntaxNodeAnalysisContext context,
            StatementSyntax containingStatement,
            SyntaxToken token,
            StatementSyntax statement)
        {
            if (!token.IsKind(SyntaxKind.None) &&
                !token.IsMissing &&
                statement?.IsKind(SyntaxKind.Block, SyntaxKind.EmptyStatement) == false &&
                context.SyntaxTree().IsMultiLineSpan(TextSpan.FromBounds(token.SpanStart, statement.SpanStart)))
            {
                SyntaxNode parent = containingStatement.Parent;

                if (parent?.IsKind(SyntaxKind.Block) == true)
                {
                    var block = (BlockSyntax)parent;

                    SyntaxList <StatementSyntax> statements = block.Statements;

                    int index = statements.IndexOf(containingStatement);

                    if (index < statements.Count - 1 &&
                        context
                        .SyntaxTree()
                        .GetLineCount(TextSpan.FromBounds(statement.Span.End, statements[index + 1].SpanStart)) <= 2)
                    {
                        SyntaxTrivia trivia = statement
                                              .GetTrailingTrivia()
                                              .FirstOrDefault(f => f.IsEndOfLineTrivia());

                        if (trivia.IsEndOfLineTrivia())
                        {
                            context.ReportDiagnostic(
                                DiagnosticDescriptors.AddEmptyLineAfterEmbeddedStatement,
                                trivia.GetLocation());
                        }
                    }
                }
            }
        }
예제 #15
0
        private static void Analyze(SyntaxNodeAnalysisContext context, SyntaxToken closeBrace, StatementSyntax blockOrStatement)
        {
            StatementSyntax nextStatement = (blockOrStatement is IfStatementSyntax ifStatement)
                ? ifStatement.GetTopmostIf().NextStatement()
                : blockOrStatement.NextStatement();

            if (nextStatement != null &&
                closeBrace.SyntaxTree.GetLineCount(TextSpan.FromBounds(closeBrace.Span.End, nextStatement.SpanStart)) == 2)
            {
                SyntaxTrivia endOfLine = closeBrace
                                         .TrailingTrivia
                                         .FirstOrDefault(f => f.IsEndOfLineTrivia());

                if (endOfLine.IsEndOfLineTrivia())
                {
                    DiagnosticHelpers.ReportDiagnostic(
                        context,
                        DiagnosticRules.AddBlankLineBetweenClosingBraceAndNextStatement,
                        Location.Create(endOfLine.SyntaxTree, endOfLine.Span.WithLength(0)));
                }
            }
        }
예제 #16
0
        private void AnalyzeStatement(SyntaxNodeAnalysisContext context, StatementSyntax statement, SyntaxToken openBrace, SyntaxToken closeBrace)
        {
            var block = (BlockSyntax)statement.Parent;

            SyntaxList <StatementSyntax> statements = block.Statements;

            int index = statements.IndexOf(statement);

            Debug.Assert(index != -1, "");

            if (index != -1 &&
                index < statements.Count - 1)
            {
                int startLine = openBrace.GetSpanStartLine();

                int endLine = closeBrace.GetSpanEndLine();

                if (startLine < endLine)
                {
                    StatementSyntax nextStatement = statements[index + 1];

                    if (nextStatement.GetSpanStartLine() - endLine == 1)
                    {
                        SyntaxTrivia trivia = closeBrace
                                              .TrailingTrivia
                                              .FirstOrDefault(f => f.IsEndOfLineTrivia());

                        if (trivia.IsEndOfLineTrivia())
                        {
                            context.ReportDiagnostic(
                                DiagnosticDescriptors.AddEmptyLineAfterClosingBrace,
                                trivia);
                        }
                    }
                }
            }
        }
예제 #17
0
        public static SyntaxTrivia GetEndOfLine(SyntaxToken token)
        {
            SyntaxTrivia trivia = FindEndOfLine(token);

            return((trivia.IsEndOfLineTrivia()) ? trivia : CSharpFactory.NewLine());
        }
예제 #18
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() &&
                AnalyzerOptions.AddNewLineAfterBinaryOperatorInsteadOfBeforeIt.IsEnabled(document, binaryExpression))
            {
                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 (AnalyzerOptions.AddNewLineAfterBinaryOperatorInsteadOfBeforeIt.IsEnabled(document, binaryExpression))
                    {
                        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);
                    }
                }
            }
        }
예제 #19
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);
                    }
                }
            }
        }
예제 #20
0
        private static void AnalyzeTrailingTrivia(SyntaxTreeAnalysisContext context)
        {
            if (!context.Tree.TryGetText(out SourceText sourceText))
            {
                return;
            }

            if (!context.Tree.TryGetRoot(out SyntaxNode root))
            {
                return;
            }

            var  emptyLines          = default(TextSpan);
            bool previousLineIsEmpty = false;
            int  i = 0;

            foreach (TextLine textLine in sourceText.Lines)
            {
                bool lineIsEmpty = false;

                if (textLine.Span.Length == 0)
                {
                    SyntaxTrivia endOfLine = root.FindTrivia(textLine.End);

                    if (endOfLine.IsEndOfLineTrivia())
                    {
                        lineIsEmpty = true;

                        if (previousLineIsEmpty)
                        {
                            if (emptyLines.IsEmpty)
                            {
                                emptyLines = endOfLine.Span;
                            }
                            else
                            {
                                emptyLines = TextSpan.FromBounds(emptyLines.Start, endOfLine.Span.End);
                            }
                        }
                    }
                    else
                    {
                        emptyLines = default;
                    }
                }
                else
                {
                    if (!emptyLines.IsEmpty)
                    {
                        DiagnosticHelpers.ReportDiagnostic(context,
                                                           DiagnosticDescriptors.RemoveRedundantEmptyLine,
                                                           Location.Create(context.Tree, emptyLines));
                    }

                    emptyLines = default;

                    int end = textLine.End - 1;

                    if (char.IsWhiteSpace(sourceText[end]))
                    {
                        int start = end;

                        while (start > textLine.Span.Start && char.IsWhiteSpace(sourceText[start - 1]))
                        {
                            start--;
                        }

                        TextSpan whitespace = TextSpan.FromBounds(start, end + 1);

                        if (root.FindTrivia(start).IsWhitespaceTrivia() ||
                            root.FindToken(start, findInsideTrivia: true).IsKind(SyntaxKind.XmlTextLiteralToken))
                        {
                            if (previousLineIsEmpty && start == textLine.Start)
                            {
                                whitespace = TextSpan.FromBounds(
                                    sourceText.Lines[i - 1].End,
                                    whitespace.End);
                            }

                            DiagnosticHelpers.ReportDiagnostic(context,
                                                               DiagnosticDescriptors.RemoveTrailingWhitespace,
                                                               Location.Create(context.Tree, whitespace));
                        }
                    }
                }

                previousLineIsEmpty = lineIsEmpty;
                i++;
            }
        }
        private static void AnalyzeDoStatement(SyntaxNodeAnalysisContext context)
        {
            var doStatement = (DoStatementSyntax)context.Node;

            StatementSyntax statement = doStatement.Statement;

            if (statement?.Kind() != SyntaxKind.Block)
            {
                return;
            }

            var block = (BlockSyntax)statement;

            StatementSyntax lastStatement = block.Statements.LastOrDefault();

            if (lastStatement == null)
            {
                return;
            }

            SyntaxToken closeBrace = block.CloseBraceToken;

            if (closeBrace.IsMissing)
            {
                return;
            }

            SyntaxToken whileKeyword = doStatement.WhileKeyword;

            if (whileKeyword.IsMissing)
            {
                return;
            }

            int closeBraceLine = closeBrace.GetSpanEndLine();

            if (closeBraceLine != whileKeyword.GetSpanStartLine())
            {
                return;
            }

            int line = lastStatement.GetSpanEndLine(context.CancellationToken);

            if (closeBraceLine - line != 1)
            {
                return;
            }

            SyntaxTrivia trivia = lastStatement
                                  .GetTrailingTrivia()
                                  .FirstOrDefault(f => f.IsEndOfLineTrivia());

            if (!trivia.IsEndOfLineTrivia())
            {
                return;
            }

            DiagnosticHelpers.ReportDiagnostic(context,
                                               DiagnosticDescriptors.AddEmptyLineBeforeWhileInDoStatement,
                                               Location.Create(doStatement.SyntaxTree, trivia.Span));
        }
예제 #22
0
        private static void AnalyzeEmbeddedStatement(SyntaxNodeAnalysisContext context)
        {
            SyntaxToken token = GetToken(context.Node);

            if (token.IsMissing)
            {
                return;
            }

            StatementSyntax statement = GetStatement(context.Node);

            if (statement.IsKind(SyntaxKind.Block))
            {
                return;
            }

            if (statement.IsKind(SyntaxKind.EmptyStatement))
            {
                return;
            }

            if (token.GetSpanStartLine() == statement.GetSpanStartLine())
            {
                context.ReportDiagnostic(
                    DiagnosticDescriptors.FormatEmbeddedStatementOnSeparateLine,
                    statement.GetLocation());
            }
            else
            {
                var parentStatement = (StatementSyntax)context.Node;

                var block = parentStatement.Parent as BlockSyntax;
                if (block == null)
                {
                    return;
                }

                int index = block.Statements.IndexOf(parentStatement);

                if (index == block.Statements.Count - 1)
                {
                    return;
                }

                int diff = block.Statements[index + 1].GetSpanStartLine() - statement.GetSpanEndLine();

                if (diff < 2)
                {
                    SyntaxTrivia trivia = statement
                                          .GetTrailingTrivia()
                                          .FirstOrDefault(f => f.IsEndOfLineTrivia());

                    if (trivia.IsEndOfLineTrivia())
                    {
                        context.ReportDiagnostic(
                            DiagnosticDescriptors.AddEmptyLineAfterEmbeddedStatement,
                            trivia.GetLocation());
                    }
                }
            }
        }
예제 #23
0
 public static bool IsWhitespaceOrEndOfLineTrivia(this SyntaxTrivia trivia)
 {
     return(trivia.IsWhitespaceTrivia() || trivia.IsEndOfLineTrivia());
 }