예제 #1
0
        public static async Task <Document> RefactorAsync(
            Document document,
            BinaryExpressionSyntax binaryExpression,
            CancellationToken cancellationToken)
        {
            SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            StringConcatenationExpression concatenation;

            if (StringConcatenationExpression.TryCreate(binaryExpression, semanticModel, out concatenation))
            {
                ExpressionSyntax newNode = null;

                if (concatenation.ContainsLiteralExpression)
                {
                    if (concatenation.ContainsVerbatim &&
                        ContainsMultiLine(concatenation, cancellationToken))
                    {
                        newNode = concatenation.ToMultilineStringLiteral();
                    }
                    else
                    {
                        newNode = concatenation.ToStringLiteral();
                    }
                }
                else
                {
                    newNode = concatenation.ToInterpolatedString();
                }

                newNode = newNode.WithTriviaFrom(binaryExpression);

                return(await document.ReplaceNodeAsync(binaryExpression, newNode, cancellationToken).ConfigureAwait(false));
            }

            Debug.Fail(binaryExpression.ToString());

            return(document);
        }
예제 #2
0
        private static async Task <Document> RefactorAsync(
            Document document,
            StringConcatenationExpression concatenation,
            StatementSyntax statement,
            CancellationToken cancellationToken)
        {
            SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            string name = NameGenerator.Default.EnsureUniqueLocalName(DefaultNames.StringBuilderVariable, semanticModel, statement.SpanStart, cancellationToken: cancellationToken);

            IdentifierNameSyntax stringBuilderName = IdentifierName(name);

            TypeSyntax type = semanticModel.GetTypeByMetadataName(MetadataNames.System_Text_StringBuilder).ToMinimalTypeSyntax(semanticModel, statement.SpanStart);

            var statements = new List <StatementSyntax>()
            {
                LocalDeclarationStatement(VarType(), Identifier(name).WithRenameAnnotation(), ObjectCreationExpression(type, ArgumentList())).WithLeadingTrivia(statement.GetLeadingTrivia())
            };

            ImmutableArray <ExpressionSyntax> expressions = concatenation.Expressions;

            ExpressionSyntax newInvocation = null;

            for (int i = 0; i < expressions.Length; i++)
            {
                if (expressions[i].IsKind(SyntaxKind.InterpolatedStringExpression))
                {
                    var interpolatedString = (InterpolatedStringExpressionSyntax)expressions[i];

                    bool isVerbatim = interpolatedString.IsVerbatim();

                    SyntaxList <InterpolatedStringContentSyntax> contents = interpolatedString.Contents;

                    for (int j = 0; j < contents.Count; j++)
                    {
                        InterpolatedStringContentConversion conversion = InterpolatedStringContentConversion.Create(contents[j], isVerbatim);

                        newInvocation = SimpleMemberInvocationExpression(
                            newInvocation ?? stringBuilderName,
                            IdentifierName(conversion.Name),
                            ArgumentList(conversion.Arguments));
                    }
                }
                else
                {
                    newInvocation = SimpleMemberInvocationExpression(
                        newInvocation ?? stringBuilderName,
                        IdentifierName("Append"),
                        Argument(expressions[i].WithoutTrivia()));
                }
            }

            statements.Add(ExpressionStatement(newInvocation));

            statements.Add(statement
                           .ReplaceNode(concatenation.OriginalExpression, SimpleMemberInvocationExpression(stringBuilderName, IdentifierName("ToString")))
                           .WithTrailingTrivia(statement.GetTrailingTrivia())
                           .WithoutLeadingTrivia());

            if (EmbeddedStatementHelper.IsEmbeddedStatement(statement))
            {
                BlockSyntax block = Block(statements).WithFormatterAnnotation();

                return(await document.ReplaceNodeAsync(statement, block, cancellationToken).ConfigureAwait(false));
            }
            else
            {
                for (int i = 0; i < statements.Count; i++)
                {
                    statements[i] = statements[i].WithFormatterAnnotation();
                }

                return(await document.ReplaceNodeAsync(statement, statements, cancellationToken).ConfigureAwait(false));
            }
        }
예제 #3
0
 private static void RegisterRefactoring(RefactoringContext context, StringConcatenationExpression concatenation, StatementSyntax statement)
 {
     context.RegisterRefactoring(
         "Use StringBuilder instead of concatenation",
         cancellationToken => RefactorAsync(context.Document, concatenation, statement, cancellationToken));
 }
예제 #4
0
        public static async Task ComputeRefactoringsAsync(RefactoringContext context, BinaryExpressionSyntax binaryExpression)
        {
            if (context.IsRefactoringEnabled(RefactoringIdentifiers.NegateOperator))
            {
                SyntaxToken operatorToken = binaryExpression.OperatorToken;

                if (operatorToken.Span.Contains(context.Span) &&
                    NegateOperatorRefactoring.CanBeNegated(operatorToken))
                {
                    context.RegisterRefactoring(
                        "Negate operator",
                        cancellationToken => NegateOperatorRefactoring.RefactorAsync(context.Document, operatorToken, cancellationToken));
                }
            }

            if (context.IsRefactoringEnabled(RefactoringIdentifiers.FormatBinaryExpression))
            {
                FormatBinaryExpressionRefactoring.ComputeRefactorings(context, binaryExpression);
            }

            if (context.IsRefactoringEnabled(RefactoringIdentifiers.NegateBinaryExpression))
            {
                NegateBinaryExpressionRefactoring.ComputeRefactoring(context, binaryExpression);
            }

            if (context.IsRefactoringEnabled(RefactoringIdentifiers.ExpandCoalesceExpression) &&
                binaryExpression.OperatorToken.Span.Contains(context.Span))
            {
                ExpandCoalesceExpressionRefactoring.ComputeRefactoring(context, binaryExpression);
            }

            if (context.IsAnyRefactoringEnabled(
                    RefactoringIdentifiers.JoinStringExpressions,
                    RefactoringIdentifiers.UseStringBuilderInsteadOfConcatenation) &&
                context.Span.IsBetweenSpans(binaryExpression) &&
                binaryExpression.IsKind(SyntaxKind.AddExpression))
            {
                SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                StringConcatenationExpression concatenation;
                if (StringConcatenationExpression.TryCreate(binaryExpression, semanticModel, out concatenation, context.CancellationToken))
                {
                    if (context.IsRefactoringEnabled(RefactoringIdentifiers.JoinStringExpressions))
                    {
                        JoinStringExpressionsRefactoring.ComputeRefactoring(context, concatenation);
                    }

                    if (context.IsRefactoringEnabled(RefactoringIdentifiers.UseStringBuilderInsteadOfConcatenation))
                    {
                        UseStringBuilderInsteadOfConcatenationRefactoring.ComputeRefactoring(context, concatenation);
                    }
                }
            }

            if (context.IsRefactoringEnabled(RefactoringIdentifiers.SwapExpressionsInBinaryExpression) &&
                context.Span.IsBetweenSpans(binaryExpression))
            {
                SwapExpressionsInBinaryExpressionRefactoring.ComputeRefactoring(context, binaryExpression);
            }

            if (context.IsRefactoringEnabled(RefactoringIdentifiers.ReplaceAsWithCast) &&
                context.Span.IsEmptyAndContainedInSpanOrBetweenSpans(binaryExpression))
            {
                SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                if (ReplaceAsWithCastRefactoring.CanRefactor(binaryExpression, semanticModel, context.CancellationToken))
                {
                    context.RegisterRefactoring(
                        "Replace as with cast",
                        cancellationToken => ReplaceAsWithCastRefactoring.RefactorAsync(context.Document, binaryExpression, context.CancellationToken));
                }
            }

            if (context.IsRefactoringEnabled(RefactoringIdentifiers.NegateIsExpression))
            {
                NegateIsExpressionRefactoring.ComputeRefactoring(context, binaryExpression);
            }

            if (context.Span.IsContainedInSpanOrBetweenSpans(binaryExpression.OperatorToken))
            {
                if (context.IsRefactoringEnabled(RefactoringIdentifiers.ReplaceEqualsExpressionWithStringEquals))
                {
                    await ReplaceEqualsExpressionWithStringEqualsRefactoring.ComputeRefactoringAsync(context, binaryExpression).ConfigureAwait(false);
                }

                if (context.IsAnyRefactoringEnabled(
                        RefactoringIdentifiers.ReplaceEqualsExpressionWithStringIsNullOrEmpty,
                        RefactoringIdentifiers.ReplaceEqualsExpressionWithStringIsNullOrWhiteSpace))
                {
                    await ReplaceEqualsExpressionRefactoring.ComputeRefactoringsAsync(context, binaryExpression).ConfigureAwait(false);
                }
            }

            if (!context.Span.IsBetweenSpans(binaryExpression) &&
                context.IsAnyRefactoringEnabled(
                    RefactoringIdentifiers.ExtractExpressionFromCondition,
                    RefactoringIdentifiers.JoinStringExpressions))
            {
                BinaryExpressionSelection binaryExpressionSelection = BinaryExpressionSelection.Create(binaryExpression, context.Span);

                if (binaryExpressionSelection.Expressions.Length > 1)
                {
                    if (context.IsRefactoringEnabled(RefactoringIdentifiers.ExtractExpressionFromCondition))
                    {
                        ExtractConditionRefactoring.ComputeRefactoring(context, binaryExpressionSelection);
                    }

                    if (context.IsRefactoringEnabled(RefactoringIdentifiers.JoinStringExpressions) &&
                        binaryExpression.IsKind(SyntaxKind.AddExpression))
                    {
                        SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                        StringConcatenationExpression concatenation;
                        if (StringConcatenationExpression.TryCreate(binaryExpressionSelection, semanticModel, out concatenation, context.CancellationToken))
                        {
                            JoinStringExpressionsRefactoring.ComputeRefactoring(context, concatenation);
                        }
                    }
                }
            }
        }
        public static void Analyze(SyntaxNodeAnalysisContext context, MemberInvocationExpression memberInvocation)
        {
            INamedTypeSymbol stringBuilderSymbol = context.GetTypeByMetadataName(MetadataNames.System_Text_StringBuilder);

            if (stringBuilderSymbol != null)
            {
                InvocationExpressionSyntax invocationExpression = memberInvocation.InvocationExpression;
                MethodInfo methodInfo;
                if (context.SemanticModel.TryGetMethodInfo(invocationExpression, out methodInfo, context.CancellationToken) &&
                    !methodInfo.IsExtensionMethod &&
                    methodInfo.ContainingType?.Equals(stringBuilderSymbol) == true)
                {
                    ImmutableArray <IParameterSymbol>    parameters = methodInfo.Parameters;
                    SeparatedSyntaxList <ArgumentSyntax> arguments  = memberInvocation.ArgumentList.Arguments;

                    if (parameters.Length == 1 &&
                        arguments.Count == 1 &&
                        methodInfo.IsName("Append", "AppendLine"))
                    {
                        ArgumentSyntax argument = arguments.First();

                        ExpressionSyntax expression = argument.Expression;

                        SyntaxKind expressionKind = expression.Kind();

                        switch (expressionKind)
                        {
                        case SyntaxKind.InterpolatedStringExpression:
                        {
                            context.ReportDiagnostic(DiagnosticDescriptors.OptimizeStringBuilderAppendCall, argument, methodInfo.Name);
                            return;
                        }

                        case SyntaxKind.AddExpression:
                        {
                            StringConcatenationExpression concatenation;
                            if (StringConcatenationExpression.TryCreate((BinaryExpressionSyntax)expression, context.SemanticModel, out concatenation))
                            {
                                context.ReportDiagnostic(DiagnosticDescriptors.OptimizeStringBuilderAppendCall, argument, methodInfo.Name);
                                return;
                            }

                            break;
                        }

                        default:
                        {
                            if (expressionKind == SyntaxKind.InvocationExpression &&
                                IsFixable((InvocationExpressionSyntax)expression, context.SemanticModel, context.CancellationToken))
                            {
                                context.ReportDiagnostic(DiagnosticDescriptors.OptimizeStringBuilderAppendCall, argument, methodInfo.Name);
                                return;
                            }

                            if (methodInfo.IsName("Append") &&
                                parameters.Length == 1 &&
                                parameters[0].Type.IsObject() &&
                                context.SemanticModel.GetTypeSymbol(argument.Expression, context.CancellationToken).IsValueType)
                            {
                                context.ReportDiagnostic(DiagnosticDescriptors.AvoidBoxingOfValueType, argument);
                                return;
                            }

                            break;
                        }
                        }
                    }
                    else if (parameters.Length > 1 &&
                             methodInfo.IsName("Insert") &&
                             methodInfo.HasParameters(SpecialType.System_Int32, SpecialType.System_Object) &&
                             context.SemanticModel
                             .GetTypeSymbol(arguments[1].Expression, context.CancellationToken)
                             .IsValueType)
                    {
                        context.ReportDiagnostic(DiagnosticDescriptors.AvoidBoxingOfValueType, arguments[1]);
                    }
                }
            }
        }