Пример #1
0
        private static Task <Document> AddNewLineBeforeOrAfterConditionalOperatorAsync(
            Document document,
            ConditionalExpressionSyntax conditionalExpression,
            CancellationToken cancellationToken = default)
        {
            string indentation = SyntaxTriviaAnalysis.GetIncreasedIndentation(conditionalExpression, cancellationToken);

            if (document.GetConfigOptions(conditionalExpression.SyntaxTree).GetEqualsTokenNewLinePosition() == NewLinePosition.After)
            {
                return(document.WithTextChangesAsync(
                           new TextChange[]
                {
                    GetNewLineAfterTextChange(conditionalExpression.QuestionToken, indentation),
                    GetNewLineAfterTextChange(conditionalExpression.ColonToken, indentation),
                },
                           cancellationToken));
            }
            else
            {
                return(document.WithTextChangesAsync(
                           new TextChange[]
                {
                    GetNewLineBeforeTextChange(conditionalExpression.QuestionToken, indentation),
                    GetNewLineBeforeTextChange(conditionalExpression.ColonToken, indentation),
                },
                           cancellationToken));
            }
        }
Пример #2
0
        public static Task <Document> AddNewLineBeforeInsteadOfAfterAsync(
            Document document,
            SyntaxNodeOrToken left,
            SyntaxNodeOrToken middle,
            SyntaxNodeOrToken right,
            CancellationToken cancellationToken = default)
        {
            StringBuilder sb = StringBuilderCache.GetInstance();

            SyntaxTriviaList trailingTrivia = middle.GetTrailingTrivia();

            if (SyntaxTriviaAnalysis.IsOptionalWhitespaceThenEndOfLineTrivia(trailingTrivia))
            {
                sb.Append(SyntaxTriviaAnalysis.DetermineEndOfLine(middle).ToString());
            }
            else
            {
                sb.Append(trailingTrivia.ToString());
            }

            sb.Append(right.GetLeadingTrivia().ToString());
            sb.Append(middle.ToString());
            sb.Append(" ");

            string newText = StringBuilderCache.GetStringAndFree(sb);

            var textChange = new TextChange(
                TextSpan.FromBounds(left.Span.End, right.SpanStart),
                newText);

            return(document.WithTextChangeAsync(textChange, cancellationToken));
        }
Пример #3
0
        public override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            if (!TryFindFirstAncestorOrSelf(root, context.Span, out TypeParameterConstraintClauseSyntax constraintClause))
            {
                return;
            }

            Document   document   = context.Document;
            Diagnostic diagnostic = context.Diagnostics[0];

            CodeAction codeAction = CodeAction.Create(
                CodeFixTitles.AddNewLine,
                ct =>
            {
                return(CodeFixHelpers.AddNewLineBeforeAndIncreaseIndentationAsync(
                           document,
                           constraintClause.WhereKeyword,
                           SyntaxTriviaAnalysis.AnalyzeIndentation(constraintClause.Parent, ct),
                           ct));
            },
                GetEquivalenceKey(diagnostic));

            context.RegisterCodeFix(codeAction, diagnostic);
        }
Пример #4
0
        private static Task <Document> WrapAndIndentEachNodeInListAsync <TNode>(
            Document document,
            SeparatedSyntaxList <TNode> nodes,
            CancellationToken cancellationToken) where TNode : SyntaxNode
        {
            return(document.WithTextChangesAsync(GetTextChanges().Where(f => f != default), cancellationToken));

            IEnumerable <TextChange> GetTextChanges()
            {
                string newText = SyntaxTriviaAnalysis.GetEndOfLine(nodes[0]).ToString() + GetIndentation();

                yield return(GetTextChange(nodes[0].GetFirstToken().GetPreviousToken(), nodes[0]));

                for (int i = 1; i < nodes.Count; i++)
                {
                    yield return(GetTextChange(nodes.GetSeparator(i - 1), nodes[i]));
                }

                TextChange GetTextChange(SyntaxToken token, SyntaxNode node)
                {
                    TextSpan span = TextSpan.FromBounds(token.Span.End, node.SpanStart);

                    return((node.SyntaxTree.IsSingleLineSpan(span))
                        ? new TextChange(span, newText)
                        : default);
        private static Task <Document> AddNewLineBeforeOrAfterConditionalOperatorAsync(
            Document document,
            ConditionalExpressionSyntax conditionalExpression,
            CancellationToken cancellationToken = default)
        {
            string indentation = SyntaxTriviaAnalysis.GetIncreasedIndentation(conditionalExpression, cancellationToken);

            if (AnalyzerOptions.AddNewLineAfterEqualsSignInsteadOfBeforeIt.IsEnabled(document, conditionalExpression))
            {
                return(document.WithTextChangesAsync(
                           new TextChange[]
                {
                    GetNewLineAfterTextChange(conditionalExpression.QuestionToken, indentation),
                    GetNewLineAfterTextChange(conditionalExpression.ColonToken, indentation),
                },
                           cancellationToken));
            }
            else
            {
                return(document.WithTextChangesAsync(
                           new TextChange[]
                {
                    GetNewLineBeforeTextChange(conditionalExpression.QuestionToken, indentation),
                    GetNewLineBeforeTextChange(conditionalExpression.ColonToken, indentation),
                },
                           cancellationToken));
            }
        }
Пример #6
0
 public static Task <Document> AddNewLineBeforeAndIncreaseIndentationAsync(
     Document document,
     SyntaxToken token,
     CancellationToken cancellationToken = default)
 {
     return(AddNewLineBeforeAndIncreaseIndentationAsync(
                document,
                token,
                SyntaxTriviaAnalysis.AnalyzeIndentation(token.Parent, cancellationToken),
                cancellationToken));
 }
Пример #7
0
 public static Task <Document> AddNewLineAfterAsync(
     Document document,
     SyntaxToken token,
     string indentation,
     CancellationToken cancellationToken = default)
 {
     return(document.WithTextChangeAsync(
                TextSpan.FromBounds(token.Span.End, token.GetNextToken().SpanStart),
                SyntaxTriviaAnalysis.DetermineEndOfLine(token).ToString() + indentation,
                cancellationToken));
 }
        private static Task <Document> AddNewLineBeforeOrAfterAsync(
            Document document,
            SyntaxToken token,
            bool addNewLineAfter,
            CancellationToken cancellationToken = default)
        {
            string indentation = SyntaxTriviaAnalysis.GetIncreasedIndentation(token.Parent, cancellationToken);

            return((addNewLineAfter)
                ? AddNewLineAfterAsync(document, token, indentation, cancellationToken)
                : AddNewLineBeforeAsync(document, token, indentation, cancellationToken));
        }
Пример #9
0
        public static Task <Document> AddNewLineBeforeAsync(
            Document document,
            SyntaxToken token,
            string indentation,
            CancellationToken cancellationToken = default)
        {
            var textChange = new TextChange(
                TextSpan.FromBounds(token.GetPreviousToken().Span.End, token.SpanStart),
                SyntaxTriviaAnalysis.DetermineEndOfLine(token).ToString() + indentation);

            return(document.WithTextChangeAsync(textChange, cancellationToken));
        }
Пример #10
0
        public static Task <Document> AddNewLineBeforeAsync(
            Document document,
            SyntaxToken token,
            CancellationToken cancellationToken = default)
        {
            SyntaxTrivia indentation = SyntaxTriviaAnalysis.DetermineIndentation(token.Parent, cancellationToken);

            return(AddNewLineBeforeAsync(
                       document,
                       token,
                       indentation.ToString(),
                       cancellationToken));
        }
Пример #11
0
        private static Task <Document> AddCallToConfigureAwaitRefactorAsync(
            Document document,
            AwaitExpressionSyntax awaitExpression,
            CancellationToken cancellationToken)
        {
            ExpressionSyntax expression = awaitExpression.Expression;

            SyntaxTriviaList leading = default;

            switch (expression.Kind())
            {
            case SyntaxKind.SimpleMemberAccessExpression:
            {
                var memberAccess = (MemberAccessExpressionSyntax)expression;

                leading = memberAccess.OperatorToken.LeadingTrivia;
                break;
            }

            case SyntaxKind.InvocationExpression:
            {
                var invocation = (InvocationExpressionSyntax)expression;

                SimpleMemberInvocationExpressionInfo invocationInfo = SyntaxInfo.SimpleMemberInvocationExpressionInfo(invocation);

                leading = invocationInfo.OperatorToken.LeadingTrivia;
                break;
            }
            }

            SyntaxTrivia last = leading.LastOrDefault();

            last = (last.IsWhitespaceTrivia()) ? last : default;

            ParenthesizedExpressionSyntax expression2 = expression.WithoutTrailingTrivia().Parenthesize();

            if (last.IsWhitespaceTrivia())
            {
                expression2 = expression2.WithTrailingTrivia(SyntaxTriviaAnalysis.DetermineEndOfLine(awaitExpression));
            }

            InvocationExpressionSyntax newInvocationExpression = InvocationExpression(
                SimpleMemberAccessExpression(
                    expression2,
                    Token(SyntaxKind.DotToken).WithLeadingTrivia(last),
                    IdentifierName("ConfigureAwait")),
                ArgumentList(
                    Token(SyntaxKind.OpenParenToken),
                    SingletonSeparatedList(Argument(FalseLiteralExpression())),
                    Token(default, SyntaxKind.CloseParenToken, expression.GetTrailingTrivia())));
        private static Task <Document> WrapForStatementAsync(
            Document document,
            ForStatementSyntax forStatement,
            CancellationToken cancellationToken = default)
        {
            string indentation = SyntaxTriviaAnalysis.GetIncreasedIndentation(forStatement, cancellationToken);

            return(document.WithTextChangesAsync(
                       new TextChange[]
            {
                GetNewLineAfterTextChange(forStatement.OpenParenToken, indentation),
                GetNewLineAfterTextChange(forStatement.FirstSemicolonToken, indentation),
                GetNewLineAfterTextChange(forStatement.SecondSemicolonToken, indentation),
            },
                       cancellationToken));
        }
Пример #13
0
        public static Task <Document> AddEmptyLineAfterDirectiveAsync(
            Document document,
            DirectiveTriviaSyntax directiveTrivia,
            CancellationToken cancellationToken = default)
        {
            SyntaxTrivia     parentTrivia  = directiveTrivia.ParentTrivia;
            SyntaxToken      token         = parentTrivia.Token;
            SyntaxTriviaList leadingTrivia = token.LeadingTrivia;

            int index = leadingTrivia.IndexOf(parentTrivia);

            SyntaxTriviaList newLeadingTrivia = leadingTrivia.Insert(index + 1, SyntaxTriviaAnalysis.DetermineEndOfLine(token));

            SyntaxToken newToken = token.WithLeadingTrivia(newLeadingTrivia);

            return(document.ReplaceTokenAsync(token, newToken, cancellationToken));
        }
Пример #14
0
        public override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            if (!TryFindFirstAncestorOrSelf(root, context.Span, out MemberDeclarationSyntax memberDeclaration))
            {
                return;
            }

            Document   document   = context.Document;
            Diagnostic diagnostic = context.Diagnostics[0];

            switch (diagnostic.Id)
            {
            case DiagnosticIdentifiers.FormatTypeDeclarationBraces:
            {
                CodeAction codeAction = CodeAction.Create(
                    "Format braces on multiple lines",
                    ct => FormatTypeDeclarationBracesOnMultipleLinesAsync(document, memberDeclaration, ct),
                    GetEquivalenceKey(diagnostic));

                context.RegisterCodeFix(codeAction, diagnostic);
                break;
            }

            case DiagnosticIdentifiers.PutConstructorInitializerOnItsOwnLine:
            {
                CodeAction codeAction = CodeAction.Create(
                    "Put constructor initializer on its own line",
                    ct =>
                    {
                        return(CodeFixHelpers.AddNewLineBeforeAndIncreaseIndentationAsync(
                                   document,
                                   ((ConstructorDeclarationSyntax)memberDeclaration).Initializer.ColonToken,
                                   SyntaxTriviaAnalysis.AnalyzeIndentation(memberDeclaration, ct),
                                   ct));
                    },
                    GetEquivalenceKey(diagnostic));

                context.RegisterCodeFix(codeAction, diagnostic);
                break;
            }
            }
        }
Пример #15
0
        private static Task <Document> AddNewLineAfterConditionalOperatorInsteadOfBeforeItAsync(
            Document document,
            ConditionalExpressionSyntax conditionalExpression,
            CancellationToken cancellationToken)
        {
            ExpressionSyntax condition     = conditionalExpression.Condition;
            ExpressionSyntax whenTrue      = conditionalExpression.WhenTrue;
            ExpressionSyntax whenFalse     = conditionalExpression.WhenFalse;
            SyntaxToken      questionToken = conditionalExpression.QuestionToken;
            SyntaxToken      colonToken    = conditionalExpression.ColonToken;

            ExpressionSyntax newCondition     = condition;
            ExpressionSyntax newWhenTrue      = whenTrue;
            ExpressionSyntax newWhenFalse     = whenFalse;
            SyntaxToken      newQuestionToken = questionToken;
            SyntaxToken      newColonToken    = colonToken;

            if (SyntaxTriviaAnalysis.IsTokenPrecededWithNewLineAndNotFollowedWithNewLine(condition, questionToken, whenTrue))
            {
                var(left, token, right) = CodeFixHelpers.AddNewLineAfterTokenInsteadOfBeforeIt(condition, questionToken, whenTrue);

                newCondition     = left;
                newQuestionToken = token;
                newWhenTrue      = right;
            }

            if (SyntaxTriviaAnalysis.IsTokenPrecededWithNewLineAndNotFollowedWithNewLine(whenTrue, colonToken, whenFalse))
            {
                var(left, token, right) = CodeFixHelpers.AddNewLineAfterTokenInsteadOfBeforeIt(newWhenTrue, colonToken, whenFalse);

                newWhenTrue   = left;
                newColonToken = token;
                newWhenFalse  = right;
            }

            ConditionalExpressionSyntax newConditionalExpression = ConditionalExpression(
                newCondition,
                newQuestionToken,
                newWhenTrue,
                newColonToken,
                newWhenFalse);

            return(document.ReplaceNodeAsync(conditionalExpression, newConditionalExpression, cancellationToken));
        }
Пример #16
0
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            if (!TryFindFirstAncestorOrSelf(root, context.Span, out MemberDeclarationSyntax memberDeclaration))
            {
                return;
            }

            Document   document   = context.Document;
            Diagnostic diagnostic = context.Diagnostics[0];

            switch (diagnostic.Id)
            {
            case DiagnosticIdentifiers.AddNewLineAfterOpeningBraceOfTypeDeclaration:
            {
                CodeAction codeAction = CodeAction.Create(
                    CodeFixTitles.AddNewLine,
                    ct => AddNewLineAfterOpeningBraceOfTypeDeclarationAsync(document, memberDeclaration, ct),
                    GetEquivalenceKey(diagnostic));

                context.RegisterCodeFix(codeAction, diagnostic);
                break;
            }

            case DiagnosticIdentifiers.AddNewLineBeforeConstructorInitializer:
            {
                CodeAction codeAction = CodeAction.Create(
                    CodeFixTitles.AddNewLine,
                    ct =>
                    {
                        return(CodeFixHelpers.AddNewLineBeforeAndIncreaseIndentationAsync(
                                   document,
                                   ((ConstructorDeclarationSyntax)memberDeclaration).Initializer.ColonToken,
                                   SyntaxTriviaAnalysis.AnalyzeIndentation(memberDeclaration, ct),
                                   ct));
                    },
                    GetEquivalenceKey(diagnostic));

                context.RegisterCodeFix(codeAction, diagnostic);
                break;
            }
            }
        }
        private static void AnalyzeBlock(SyntaxNodeAnalysisContext context, BlockSyntax block, BlockExpressionAnalysis analysis, BodyStyle style)
        {
            if (style.UseBlockWhenExpressionIsMultiLine == true
                && analysis.Expression.IsMultiLine())
            {
                return;
            }

            if (!style.UseExpression)
                return;

            if (!SyntaxTriviaAnalysis.IsExteriorTriviaEmptyOrWhitespace(block.OpenBraceToken))
                return;

            if (!analysis.ReturnOrThrowKeyword.LeadingTrivia.IsEmptyOrWhitespace())
                return;

            ReportDiagnostic(context, analysis.Block);
        }
Пример #18
0
        private static void AnalyzeBlock(SyntaxNodeAnalysisContext context, BlockSyntax block, BlockExpressionAnalysis analysis)
        {
            if (AnalyzerOptions.ConvertExpressionBodyToBlockBodyWhenExpressionIsMultiLine.IsEnabled(context) &&
                analysis.Expression.IsMultiLine())
            {
                return;
            }

            if (!SyntaxTriviaAnalysis.IsExteriorTriviaEmptyOrWhitespace(block.OpenBraceToken))
            {
                return;
            }

            if (!analysis.ReturnOrThrowKeyword.LeadingTrivia.IsEmptyOrWhitespace())
            {
                return;
            }

            ReportDiagnostic(context, analysis.Block, analysis.Expression);
        }
Пример #19
0
        public static async Task <Document> RefactorAsync(
            Document document,
            ArrowExpressionClauseSyntax expressionBody,
            CancellationToken cancellationToken = default)
        {
            SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            SyntaxNode newNode = Refactor(expressionBody, semanticModel, cancellationToken);

            SyntaxToken token = expressionBody.ArrowToken.GetPreviousToken();

            if (SyntaxTriviaAnalysis.IsOptionalWhitespaceThenEndOfLineTrivia(token.TrailingTrivia))
            {
                SyntaxToken newToken = token.WithTrailingTrivia(ElasticSpace);

                newNode = newNode.ReplaceToken(token, newToken);
            }

            return(await document.ReplaceNodeAsync(expressionBody.Parent, newNode, cancellationToken).ConfigureAwait(false));
        }
        private static Task <Document> AddBlankLineBeforeUsingDirectiveAsync(
            Document document,
            UsingDirectiveSyntax usingDirective,
            CancellationToken cancellationToken)
        {
            SyntaxTriviaList leadingTrivia = usingDirective.GetLeadingTrivia();

            int index = leadingTrivia.Count;

            if (index > 0 &&
                leadingTrivia.Last().IsWhitespaceTrivia())
            {
                index--;
            }

            SyntaxTriviaList newLeadingTrivia = leadingTrivia.Insert(index, SyntaxTriviaAnalysis.DetermineEndOfLine(usingDirective));

            UsingDirectiveSyntax newUsingDirective = usingDirective.WithLeadingTrivia(newLeadingTrivia);

            return(document.ReplaceNodeAsync(usingDirective, newUsingDirective, cancellationToken));
        }
        private static ArrowExpressionClauseSyntax CreateExpressionBody(BlockExpressionAnalysis analysis, SyntaxNode declaration)
        {
            SyntaxToken arrowToken = Token(SyntaxKind.EqualsGreaterThanToken);

            ExpressionSyntax expression = analysis.Expression;

            SyntaxToken keyword = analysis.ReturnOrThrowKeyword;

            switch (keyword.Kind())
            {
            case SyntaxKind.ThrowKeyword:
            {
                expression = ThrowExpression(keyword, expression);
                break;
            }

            case SyntaxKind.ReturnKeyword:
            {
                SyntaxTriviaList leading = keyword.LeadingTrivia;

                if (!leading.IsEmptyOrWhitespace())
                {
                    arrowToken = arrowToken.WithLeadingTrivia(leading);
                }

                SyntaxTriviaList trailing = keyword.TrailingTrivia;

                if (!trailing.IsEmptyOrWhitespace())
                {
                    arrowToken = arrowToken.WithTrailingTrivia(trailing);
                }

                break;
            }
            }

            expression = SyntaxTriviaAnalysis.SetIndentation(expression, declaration);

            return(ArrowExpressionClause(arrowToken, expression));
        }
Пример #22
0
        public static Task <Document> AddEmptyLineBeforeDirectiveAsync(
            Document document,
            DirectiveTriviaSyntax directiveTrivia,
            CancellationToken cancellationToken = default)
        {
            SyntaxTrivia     parentTrivia  = directiveTrivia.ParentTrivia;
            SyntaxToken      token         = parentTrivia.Token;
            SyntaxTriviaList leadingTrivia = token.LeadingTrivia;

            int index = leadingTrivia.IndexOf(parentTrivia);

            if (index > 0 &&
                leadingTrivia[index - 1].IsWhitespaceTrivia())
            {
                index--;
            }

            SyntaxTriviaList newLeadingTrivia = leadingTrivia.Insert(index, SyntaxTriviaAnalysis.GetEndOfLine(token));

            SyntaxToken newToken = token.WithLeadingTrivia(newLeadingTrivia);

            return(document.ReplaceTokenAsync(token, newToken, cancellationToken));
        }
        public static async Task <Document> RefactorAsync(
            Document document,
            UseMethodChainingAnalysis analysis,
            ExpressionStatementSyntax expressionStatement,
            CancellationToken cancellationToken)
        {
            SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            InvocationExpressionSyntax invocationExpression = GetInvocationExpression(expressionStatement);

            SimpleMemberInvocationExpressionInfo invocationInfo = SyntaxInfo.SimpleMemberInvocationExpressionInfo(invocationExpression);

            ITypeSymbol returnType = semanticModel.GetMethodSymbol(invocationExpression, cancellationToken).ReturnType;

            string name = ((IdentifierNameSyntax)UseMethodChainingAnalysis.WalkDownMethodChain(invocationInfo).Expression).Identifier.ValueText;

            StatementListInfo statementsInfo = SyntaxInfo.StatementListInfo(expressionStatement);

            SyntaxList <StatementSyntax> statements = statementsInfo.Statements;

            int index = statements.IndexOf(expressionStatement);

            string indentation = SyntaxTriviaAnalysis.GetIncreasedIndentation(expressionStatement, cancellationToken);

            var sb = new StringBuilder(invocationExpression.ToString());

            int j = index;

            while (j < statements.Count - 1)
            {
                StatementSyntax statement = statements[j + 1];

                if (!analysis.IsFixableStatement(statement, name, returnType, semanticModel, cancellationToken))
                {
                    break;
                }

                sb.AppendLine();
                sb.Append(indentation);
                sb.Append(GetTextToAppend((ExpressionStatementSyntax)statement));

                j++;
            }

            StatementSyntax lastStatement = statements[j];

            SyntaxList <StatementSyntax> newStatements = statements;

            while (j > index)
            {
                newStatements = newStatements.RemoveAt(j);
                j--;
            }

            ExpressionSyntax newInvocationExpression = SyntaxFactory.ParseExpression(sb.ToString());

            SyntaxTriviaList trailingTrivia = statementsInfo
                                              .Parent
                                              .DescendantTrivia(TextSpan.FromBounds(invocationExpression.Span.End, lastStatement.Span.End))
                                              .ToSyntaxTriviaList()
                                              .EmptyIfWhitespace()
                                              .AddRange(lastStatement.GetTrailingTrivia());

            ExpressionStatementSyntax newExpressionStatement = expressionStatement
                                                               .ReplaceNode(invocationExpression, newInvocationExpression)
                                                               .WithLeadingTrivia(expressionStatement.GetLeadingTrivia())
                                                               .WithTrailingTrivia(trailingTrivia)
                                                               .WithFormatterAndSimplifierAnnotation();

            newStatements = newStatements.ReplaceAt(index, newExpressionStatement);

            return(await document.ReplaceStatementsAsync(statementsInfo, newStatements, cancellationToken).ConfigureAwait(false));
        }
        private static Task <Document> RefactorAsync(
            Document document,
            RecordDeclarationSyntax recordDeclaration,
            CancellationToken cancellationToken = default)
        {
            ParameterListSyntax parameterList = recordDeclaration.ParameterList;
            BaseListSyntax      baseList      = recordDeclaration.BaseList;
            SeparatedSyntaxList <ParameterSyntax> parameters = parameterList.Parameters;

            var identifiersMap    = new Dictionary <string, SyntaxToken>();
            var statements        = new List <StatementSyntax>();
            var properties        = new List <PropertyDeclarationSyntax>();
            var allAttributeLists = new List <AttributeListSyntax>();

            var baseType = baseList?
                           .Types
                           .FirstOrDefault(f => f.IsKind(SyntaxKind.PrimaryConstructorBaseType)) as PrimaryConstructorBaseTypeSyntax;

            ImmutableHashSet <string> basePropertyNames = ImmutableHashSet <string> .Empty;

            if (baseType != null)
            {
                basePropertyNames = baseType
                                    .ArgumentList?
                                    .Arguments
                                    .Select(f => f.ToString())
                                    .ToImmutableHashSet();
            }

            bool isWritable = !recordDeclaration.Modifiers.Contains(SyntaxKind.ReadOnlyKeyword) &&
                              recordDeclaration.ClassOrStructKeyword.IsKind(SyntaxKind.StructKeyword);

            foreach (ParameterSyntax parameter in parameters)
            {
                SyntaxToken identifier          = parameter.Identifier;
                string      identifierText      = identifier.ValueText;
                SyntaxToken parameterIdentifier = Identifier(StringUtility.FirstCharToLower(identifierText));
                SyntaxToken propertyIdentifier  = Identifier(StringUtility.FirstCharToUpper(identifierText));
                identifiersMap.Add(identifier.ValueText, parameterIdentifier);

                IEnumerable <AttributeListSyntax> attributeLists = parameter.AttributeLists.Where(f => f.Target?.Identifier.IsKind(SyntaxKind.PropertyKeyword) == true);

                allAttributeLists.AddRange(attributeLists);

                statements.Add(SimpleAssignmentStatement(
                                   IdentifierName(propertyIdentifier).QualifyWithThis(),
                                   IdentifierName(parameterIdentifier.WithTriviaFrom(identifier))));

                if (!basePropertyNames.Contains(identifierText))
                {
                    properties.Add(PropertyDeclaration(
                                       attributeLists.Select(f => f.WithTarget(null)).ToSyntaxList(),
                                       Modifiers.Public(),
                                       parameter.Type,
                                       default(ExplicitInterfaceSpecifierSyntax),
                                       propertyIdentifier,
                                       AccessorList(
                                           AutoGetAccessorDeclaration(),
                                           (isWritable) ? AutoSetAccessorDeclaration() : AutoInitAccessorDeclaration()
                                           )));
                }
            }

            ParameterListSyntax newParameterList = parameterList.RemoveNodes(
                allAttributeLists,
                SyntaxRemoveOptions.KeepLeadingTrivia | SyntaxRemoveOptions.KeepUnbalancedDirectives);

            newParameterList = newParameterList.ReplaceTokens(
                newParameterList.Parameters.Select(parameter => parameter.Identifier),
                (identifier, _) => identifiersMap[identifier.ValueText]);

            ParameterSyntax firstParameter = parameterList.Parameters[0];

            if (firstParameter.GetLeadingTrivia().SingleOrDefault(shouldThrow: false).IsKind(SyntaxKind.WhitespaceTrivia))
            {
                SyntaxTriviaList newIndentation = SyntaxTriviaAnalysis.GetIncreasedIndentationTriviaList(firstParameter, cancellationToken);

                newParameterList = newParameterList.ReplaceNodes(
                    newParameterList.Parameters,
                    (parameter, _) =>
                {
                    return((parameter.GetLeadingTrivia().SingleOrDefault().IsKind(SyntaxKind.WhitespaceTrivia))
                            ? parameter.WithLeadingTrivia(newIndentation)
                            : parameter);
                });
            }

            ConstructorDeclarationSyntax constructor = ConstructorDeclaration(
                Modifiers.Public(),
                recordDeclaration.Identifier.WithoutTrivia(),
                newParameterList,
                Block(statements));

            RecordDeclarationSyntax newRecord = recordDeclaration
                                                .WithIdentifier(recordDeclaration.Identifier.WithTrailingTrivia(recordDeclaration.ParameterList.GetTrailingTrivia()))
                                                .WithParameterList(null)
                                                .WithSemicolonToken(default);
Пример #25
0
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            if (!TryFindToken(root, context.Span.Start, out SyntaxToken token))
            {
                return;
            }

            Document   document   = context.Document;
            Diagnostic diagnostic = context.Diagnostics[0];

            switch (diagnostic.Id)
            {
            case DiagnosticIdentifiers.AddEmptyLineBetweenBlockAndStatement:
            {
                CodeAction codeAction = CodeAction.Create(
                    CodeFixTitles.AddEmptyLine,
                    ct => CodeFixHelpers.AppendEndOfLineAsync(document, token, ct),
                    GetEquivalenceKey(diagnostic));

                context.RegisterCodeFix(codeAction, diagnostic);
                break;
            }

            case DiagnosticIdentifiers.AddNewLineBeforeConditionalOperatorInsteadOfAfterIt:
            {
                var conditionalExpression = (ConditionalExpressionSyntax)token.Parent;

                string title = null;
                if (token.IsKind(SyntaxKind.QuestionToken))
                {
                    title = (SyntaxTriviaAnalysis.IsTokenFollowedWithNewLineAndNotPrecededWithNewLine(conditionalExpression.WhenTrue, conditionalExpression.ColonToken, conditionalExpression.WhenFalse))
                                ? "Add newline before '?' and ':' instead of after it"
                                : "Add newline before '?' instead of after it";
                }
                else
                {
                    title = "Add newline before ':' instead of after it";
                }

                CodeAction codeAction = CodeAction.Create(
                    title,
                    ct => AddNewLineBeforeConditionalOperatorInsteadOfAfterItAsync(document, conditionalExpression, ct),
                    GetEquivalenceKey(diagnostic));

                context.RegisterCodeFix(codeAction, diagnostic);
                break;
            }

            case DiagnosticIdentifiers.AddNewLineAfterConditionalOperatorInsteadOfBeforeIt:
            {
                var conditionalExpression = (ConditionalExpressionSyntax)token.Parent;

                string title = null;
                if (token.IsKind(SyntaxKind.QuestionToken))
                {
                    title = (SyntaxTriviaAnalysis.IsTokenFollowedWithNewLineAndNotPrecededWithNewLine(conditionalExpression.WhenTrue, conditionalExpression.ColonToken, conditionalExpression.WhenFalse))
                                ? "Add newline after '?' and ':' instead of before it"
                                : "Add newline after '?' instead of before it";
                }
                else
                {
                    title = "Add newline after ':' instead of before it";
                }

                CodeAction codeAction = CodeAction.Create(
                    title,
                    ct => AddNewLineAfterConditionalOperatorInsteadOfBeforeItAsync(document, conditionalExpression, ct),
                    GetEquivalenceKey(diagnostic));

                context.RegisterCodeFix(codeAction, diagnostic);
                break;
            }

            case DiagnosticIdentifiers.AddNewLineAfterExpressionBodyArrowInsteadOfBeforeIt:
            {
                CodeAction codeAction = CodeAction.Create(
                    "Add newline after '=>' instead of before it",
                    ct =>
                    {
                        var expressionBody = (ArrowExpressionClauseSyntax)token.Parent;

                        return(CodeFixHelpers.AddNewLineAfterInsteadOfBeforeAsync(document, token.GetPreviousToken(), token, expressionBody.Expression, ct));
                    },
                    GetEquivalenceKey(diagnostic));

                context.RegisterCodeFix(codeAction, diagnostic);
                break;
            }

            case DiagnosticIdentifiers.AddNewLineBeforeExpressionBodyArrowInsteadOfAfterIt:
            {
                CodeAction codeAction = CodeAction.Create(
                    "Add newline before '=>' instead of after it",
                    ct =>
                    {
                        var expressionBody = (ArrowExpressionClauseSyntax)token.Parent;

                        return(CodeFixHelpers.AddNewLineBeforeInsteadOfAfterAsync(document, token.GetPreviousToken(), token, expressionBody.Expression, ct));
                    },
                    GetEquivalenceKey(diagnostic));

                context.RegisterCodeFix(codeAction, diagnostic);
                break;
            }

            case DiagnosticIdentifiers.AddNewLineAfterAttributeList:
            {
                CodeAction codeAction = CodeAction.Create(
                    CodeFixTitles.AddNewLine,
                    ct => CodeFixHelpers.AddNewLineBeforeAsync(document, token, ct),
                    GetEquivalenceKey(diagnostic));

                context.RegisterCodeFix(codeAction, diagnostic);
                break;
            }
            }
        }
        private static void AnalyzeAccessorDeclarationBlock(
            SyntaxNodeAnalysisContext context,
            AccessorDeclarationSyntax accessor,
            BlockSyntax body)
        {
            if (body.ContainsDirectives)
                return;

            if (accessor.AttributeLists.Any())
                return;

            BodyStyle style = context.GetBodyStyle();

            if (style.IsDefault)
                return;

            bool isGetter = accessor.IsKind(SyntaxKind.GetAccessorDeclaration);

            BlockExpressionAnalysis analysis = BlockExpressionAnalysis.Create(body, allowExpressionStatement: !isGetter);

            ExpressionSyntax expression = analysis.Expression;

            if (expression == null)
                return;

            if (!style.UseExpression)
                return;

            if (style.UseBlockWhenExpressionIsMultiLine == true
                && expression.IsMultiLine())
            {
                return;
            }

            if (isGetter
                && accessor.Parent is AccessorListSyntax accessorList
                && accessorList.Accessors.Count == 1)
            {
                if (!SyntaxTriviaAnalysis.IsExteriorTriviaEmptyOrWhitespace(accessorList.OpenBraceToken))
                    return;

                if (!SyntaxTriviaAnalysis.IsExteriorTriviaEmptyOrWhitespace(accessor.Keyword))
                    return;

                if (!SyntaxTriviaAnalysis.IsExteriorTriviaEmptyOrWhitespace(body.OpenBraceToken))
                    return;

                if (style.UseBlockWhenDeclarationIsMultiLine == true)
                {
                    switch (accessorList.Parent.Kind())
                    {
                        case SyntaxKind.PropertyDeclaration:
                            {
                                if (accessor.SyntaxTree.IsMultiLineSpan(((PropertyDeclarationSyntax)accessorList.Parent).HeaderSpan()))
                                    return;

                                break;
                            }
                        case SyntaxKind.IndexerDeclaration:
                            {
                                if (accessor.SyntaxTree.IsMultiLineSpan(((IndexerDeclarationSyntax)accessorList.Parent).HeaderSpan()))
                                    return;

                                break;
                            }
                        default:
                            {
                                SyntaxDebug.Fail(accessorList.Parent);
                                break;
                            }
                    }

                    return;
                }

                ReportDiagnostic(context, accessorList);
                return;
            }

            if (!accessor.Keyword.TrailingTrivia.IsEmptyOrWhitespace())
                return;

            if (!SyntaxTriviaAnalysis.IsExteriorTriviaEmptyOrWhitespace(body.OpenBraceToken))
                return;

            if (!accessor.Keyword.LeadingTrivia.IsEmptyOrWhitespace())
                return;

            ReportDiagnostic(context, body);
        }
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            if (!TryFindToken(root, context.Span.Start, out SyntaxToken token))
            {
                return;
            }

            Document   document   = context.Document;
            Diagnostic diagnostic = context.Diagnostics[0];

            switch (diagnostic.Id)
            {
            case DiagnosticIdentifiers.AddEmptyLineBetweenBlockAndStatement:
            {
                CodeAction codeAction = CodeAction.Create(
                    CodeFixTitles.AddEmptyLine,
                    ct => CodeFixHelpers.AppendEndOfLineAsync(document, token, ct),
                    GetEquivalenceKey(diagnostic));

                context.RegisterCodeFix(codeAction, diagnostic);
                break;
            }

            case DiagnosticIdentifiers.AddNewLineBeforeConditionalOperatorInsteadOfAfterItOrViceVersa:
            {
                if (DiagnosticProperties.ContainsInvert(diagnostic.Properties))
                {
                    var conditionalExpression = (ConditionalExpressionSyntax)token.Parent;

                    string title = null;
                    if (token.IsKind(SyntaxKind.QuestionToken))
                    {
                        title = (SyntaxTriviaAnalysis.IsTokenFollowedWithNewLineAndNotPrecededWithNewLine(conditionalExpression.WhenTrue, conditionalExpression.ColonToken, conditionalExpression.WhenFalse))
                                    ? "Add newline after '?' and ':' instead of before it"
                                    : "Add newline after '?' instead of before it";
                    }
                    else
                    {
                        title = "Add newline after ':' instead of before it";
                    }

                    CodeAction codeAction = CodeAction.Create(
                        title,
                        ct => AddNewLineAfterConditionalOperatorInsteadOfBeforeItAsync(document, conditionalExpression, ct),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                }
                else
                {
                    var conditionalExpression = (ConditionalExpressionSyntax)token.Parent;

                    string title = null;
                    if (token.IsKind(SyntaxKind.QuestionToken))
                    {
                        title = (SyntaxTriviaAnalysis.IsTokenFollowedWithNewLineAndNotPrecededWithNewLine(conditionalExpression.WhenTrue, conditionalExpression.ColonToken, conditionalExpression.WhenFalse))
                                    ? "Add newline before '?' and ':' instead of after it"
                                    : "Add newline before '?' instead of after it";
                    }
                    else
                    {
                        title = "Add newline before ':' instead of after it";
                    }

                    CodeAction codeAction = CodeAction.Create(
                        title,
                        ct => AddNewLineBeforeConditionalOperatorInsteadOfAfterItAsync(document, conditionalExpression, ct),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                }

                break;
            }

            case DiagnosticIdentifiers.AddNewLineBeforeExpressionBodyArrowInsteadOfAfterItOrViceVersa:
            case DiagnosticIdentifiers.AddNewLineBeforeEqualsSignInsteadOfAfterItOrViceVersa:
            {
                AddNewLineBeforeOrAfter();
                break;
            }

            case DiagnosticIdentifiers.AddNewLineAfterAttributeList:
            {
                CodeAction codeAction = CodeAction.Create(
                    CodeFixTitles.AddNewLine,
                    ct => CodeFixHelpers.AddNewLineBeforeAsync(document, token, ct),
                    GetEquivalenceKey(diagnostic));

                context.RegisterCodeFix(codeAction, diagnostic);
                break;
            }

            case DiagnosticIdentifiers.AddNewLineBetweenClosingBraceAndWhileKeywordOrViceVersa:
            {
                if (DiagnosticProperties.ContainsInvert(diagnostic.Properties))
                {
                    CodeAction codeAction = CodeAction.Create(
                        CodeFixTitles.RemoveNewLine,
                        ct => CodeFixHelpers.ReplaceTriviaBetweenAsync(document, token, token.GetNextToken(), cancellationToken: ct),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                }
                else
                {
                    CodeAction codeAction = CodeAction.Create(
                        CodeFixTitles.AddNewLine,
                        ct => CodeFixHelpers.AddNewLineBeforeAsync(document, token, ct),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                }

                break;
            }
            }

            void AddNewLineBeforeOrAfter()
            {
                if (DiagnosticProperties.ContainsInvert(diagnostic.Properties))
                {
                    CodeAction codeAction = CodeAction.Create(
                        $"Add newline after '{token}' instead of before it",
                        ct => CodeFixHelpers.AddNewLineAfterInsteadOfBeforeAsync(document, token, ct),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                }
                else
                {
                    CodeAction codeAction = CodeAction.Create(
                        $"Add newline before '{token}' instead of after it",
                        ct => CodeFixHelpers.AddNewLineBeforeInsteadOfAfterAsync(document, token, ct),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                }
            }
        }
        private static void AnalyzeFinallyClause(SyntaxNodeAnalysisContext context)
        {
            var finallyClause = (FinallyClauseSyntax)context.Node;

            if (finallyClause.Parent is not TryStatementSyntax tryStatement)
            {
                return;
            }

            BlockSyntax finallyBlock = finallyClause.Block;

            if (finallyBlock?.Statements.Any() != false)
            {
                return;
            }

            if (!finallyClause.FinallyKeyword.TrailingTrivia.IsEmptyOrWhitespace())
            {
                return;
            }

            if (!SyntaxTriviaAnalysis.IsExteriorTriviaEmptyOrWhitespace(finallyBlock.OpenBraceToken))
            {
                return;
            }

            if (!finallyBlock.CloseBraceToken.LeadingTrivia.IsEmptyOrWhitespace())
            {
                return;
            }

            if (tryStatement.Catches.Any())
            {
                DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.RemoveEmptyFinallyClause, finallyClause);
            }
            else
            {
                BlockSyntax tryBlock = tryStatement.Block;

                if (tryBlock?.Statements.Any() != true)
                {
                    return;
                }

                if (!SyntaxTriviaAnalysis.IsExteriorTriviaEmptyOrWhitespace(tryStatement.TryKeyword))
                {
                    return;
                }

                if (!SyntaxTriviaAnalysis.IsExteriorTriviaEmptyOrWhitespace(tryBlock.OpenBraceToken))
                {
                    return;
                }

                if (!SyntaxTriviaAnalysis.IsExteriorTriviaEmptyOrWhitespace(tryBlock.CloseBraceToken))
                {
                    return;
                }

                if (!finallyClause.FinallyKeyword.LeadingTrivia.IsEmptyOrWhitespace())
                {
                    return;
                }

                DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.RemoveEmptyFinallyClause, finallyClause);

                DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.RemoveEmptyFinallyClauseFadeOut, tryStatement.TryKeyword);
                DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.RemoveEmptyFinallyClauseFadeOut, tryBlock.OpenBraceToken);
                DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.RemoveEmptyFinallyClauseFadeOut, tryBlock.CloseBraceToken);
            }
        }
Пример #29
0
        private static void AnalyzeAccessorDeclarationBlock(
            SyntaxNodeAnalysisContext context,
            AccessorDeclarationSyntax accessor,
            BlockSyntax body)
        {
            if (body.ContainsDirectives)
            {
                return;
            }

            if (accessor.AttributeLists.Any())
            {
                return;
            }

            bool isGetter = accessor.IsKind(SyntaxKind.GetAccessorDeclaration);

            BlockExpressionAnalysis analysis = BlockExpressionAnalysis.Create(body, allowExpressionStatement: !isGetter);

            ExpressionSyntax expression = analysis.Expression;

            if (expression == null)
            {
                return;
            }

            if (AnalyzerOptions.ConvertExpressionBodyToBlockBody.IsEnabled(context))
            {
                return;
            }

            if (AnalyzerOptions.ConvertExpressionBodyToBlockBodyWhenExpressionIsMultiLine.IsEnabled(context) &&
                expression.IsMultiLine())
            {
                return;
            }

            if (isGetter &&
                accessor.Parent is AccessorListSyntax accessorList &&
                accessorList.Accessors.Count == 1)
            {
                if (!SyntaxTriviaAnalysis.IsExteriorTriviaEmptyOrWhitespace(accessorList.OpenBraceToken))
                {
                    return;
                }

                if (!SyntaxTriviaAnalysis.IsExteriorTriviaEmptyOrWhitespace(accessor.Keyword))
                {
                    return;
                }

                if (!SyntaxTriviaAnalysis.IsExteriorTriviaEmptyOrWhitespace(body.OpenBraceToken))
                {
                    return;
                }

                if (AnalyzerOptions.ConvertExpressionBodyToBlockBodyWhenDeclarationIsMultiLine.IsEnabled(context))
                {
                    switch (accessorList.Parent.Kind())
                    {
                    case SyntaxKind.PropertyDeclaration:
                    {
                        if (accessor.SyntaxTree.IsMultiLineSpan(((PropertyDeclarationSyntax)accessorList.Parent).HeaderSpan()))
                        {
                            return;
                        }

                        break;
                    }

                    case SyntaxKind.IndexerDeclaration:
                    {
                        if (accessor.SyntaxTree.IsMultiLineSpan(((IndexerDeclarationSyntax)accessorList.Parent).HeaderSpan()))
                        {
                            return;
                        }

                        break;
                    }

                    default:
                    {
                        Debug.Fail(accessorList.Parent.Kind().ToString());
                        break;
                    }
                    }

                    return;
                }

                ReportDiagnostic(context, accessorList, expression);
                ReportFadeOut(context, accessor.Keyword, body);
                return;
            }

            if (!accessor.Keyword.TrailingTrivia.IsEmptyOrWhitespace())
            {
                return;
            }

            if (!SyntaxTriviaAnalysis.IsExteriorTriviaEmptyOrWhitespace(body.OpenBraceToken))
            {
                return;
            }

            if (!accessor.Keyword.LeadingTrivia.IsEmptyOrWhitespace())
            {
                return;
            }

            ReportDiagnostic(context, body, expression);
        }
Пример #30
0
        private static Task <Document> RefactorAsync(
            Document document,
            XmlElementSyntax xmlElement,
            CancellationToken cancellationToken)
        {
            SyntaxList <XmlNodeSyntax> nodes = xmlElement.Content;

            (TextSpan span1, TextSpan span2, List <TextSpan> spans) = AddParagraphToDocumentationCommentAnalyzer.FindFixableSpan(nodes, stopOnFirstMatch: false, cancellationToken: cancellationToken);

            var textChanges = new List <TextChange>();

            string newLine = nodes
                             .OfType <XmlTextSyntax>()
                             .SelectMany(f => f.TextTokens)
                             .First(f => f.IsKind(SyntaxKind.XmlTextLiteralNewLineToken))
                             .ValueText;

            string indentation = SyntaxTriviaAnalysis.DetermineIndentation(xmlElement, cancellationToken).ToString();

            string s = $"{newLine}{indentation}/// ";

            int prevEnd = -1;

            foreach (TextSpan span in spans)
            {
                cancellationToken.ThrowIfCancellationRequested();

                if (prevEnd != -1)
                {
                    textChanges.Add(TextSpan.FromBounds(prevEnd, span.Start), s);
                }

                SyntaxToken token    = xmlElement.FindToken(span.Start);
                SyntaxToken endToken = xmlElement.FindToken(span.End - 1);

                bool isMultiline = xmlElement.SyntaxTree.IsMultiLineSpan(span, cancellationToken);

                var text = "<para>";

                if (isMultiline)
                {
                    text += s;
                }

                int start  = token.SpanStart;
                int length = 0;

                if (token.IsKind(SyntaxKind.XmlTextLiteralToken) &&
                    token.ValueText[0] == ' ')
                {
                    if (prevEnd == -1)
                    {
                        start++;
                    }
                    else
                    {
                        length++;
                    }
                }

                textChanges.Add(new TextSpan(start, length), text);

                text = "";

                if (isMultiline)
                {
                    text += s;
                }

                text += "</para>";

                textChanges.Add(new TextSpan(span.End, 0), text);

                prevEnd = endToken.Span.End;
            }

            cancellationToken.ThrowIfCancellationRequested();

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