private static ISymbol GetEnclosingMethodOrPropertyOrField(
            SemanticModel semanticModel,
            ReferenceLocation reference)
        {
            var enclosingSymbol = semanticModel.GetEnclosingSymbol(reference.Location.SourceSpan.Start);

            for (var current = enclosingSymbol; current != null; current = current.ContainingSymbol)
            {
                if (current.Kind == SymbolKind.Field)
                {
                    return current;
                }

                if (current.Kind == SymbolKind.Property)
                {
                    return current;
                }

                if (current.Kind == SymbolKind.Method)
                {
                    var method = (IMethodSymbol)current;
                    if (method.IsAccessor())
                    {
                        return method.AssociatedSymbol;
                    }

                    if (method.MethodKind != MethodKind.AnonymousFunction)
                    {
                        return method;
                    }
                }
            }

            return null;
        }
        private bool TryGetMethodReturnType(SyntaxNode node, SemanticModel model, CancellationToken cancellationToken, out ITypeSymbol methodReturnType)
        {
            methodReturnType = null;
            var symbol = model.GetEnclosingSymbol(node.Span.Start, cancellationToken);
            var method = symbol as IMethodSymbol;
            if (method == null || method.ReturnsVoid)
            {
                return false;
            }

            methodReturnType = method.ReturnType;
            return methodReturnType != null;
        }
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            if (!Settings.IsAnyCodeFixEnabled(
                    CodeFixIdentifiers.ReplaceStringLiteralWithCharacterLiteral,
                    CodeFixIdentifiers.UseYieldReturnInsteadOfReturn))
            {
                return;
            }

            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            SyntaxNode node = root.FindNode(context.Span, getInnermostNodeForTie: true);

            foreach (Diagnostic diagnostic in context.Diagnostics)
            {
                switch (diagnostic.Id)
                {
                case CompilerDiagnosticIdentifiers.CannotImplicitlyConvertType:
                {
                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.ReplaceStringLiteralWithCharacterLiteral) &&
                        node?.IsKind(SyntaxKind.StringLiteralExpression) == true)
                    {
                        var literalExpression = (LiteralExpressionSyntax)node;

                        if (literalExpression.Token.ValueText.Length == 1)
                        {
                            SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                            if (semanticModel.GetTypeInfo(node, context.CancellationToken).ConvertedType?.IsChar() == true)
                            {
                                CodeAction codeAction = CodeAction.Create(
                                    "Replace string literal with character literal",
                                    cancellationToken => ReplaceStringLiteralWithCharacterLiteralRefactoring.RefactorAsync(context.Document, literalExpression, cancellationToken),
                                    GetEquivalenceKey(diagnostic));

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

                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.UseYieldReturnInsteadOfReturn) &&
                        node.IsParentKind(SyntaxKind.ReturnStatement))
                    {
                        var returnStatement = (ReturnStatementSyntax)node.Parent;

                        SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                        ISymbol containingSymbol = semanticModel.GetEnclosingSymbol(returnStatement.SpanStart, context.CancellationToken);

                        if (containingSymbol?.IsKind(SymbolKind.Method) == true &&
                            ((IMethodSymbol)containingSymbol).ReturnType?.IsIEnumerableOrConstructedFromIEnumerableOfT() == true)
                        {
                            CodeAction codeAction = CodeAction.Create(
                                "Use yield return instead of return",
                                cancellationToken => UseYieldReturnInsteadOfReturnRefactoring.RefactorAsync(context.Document, returnStatement, SyntaxKind.YieldReturnStatement, semanticModel, cancellationToken),
                                GetEquivalenceKey(diagnostic));

                            context.RegisterCodeFix(codeAction, diagnostic);
                        }
                    }

                    break;
                }
                }
            }
        }
Esempio n. 4
0
 private static bool IsCalledInsideDispose(InvocationExpressionSyntax invocation, SemanticModel semanticModel) =>
 semanticModel.GetEnclosingSymbol(invocation.SpanStart) is IMethodSymbol enclosingMethodSymbol &&
            private bool TryDetermineOverridableMembers(
                SemanticModel semanticModel, SyntaxToken startToken, Accessibility seenAccessibility, out ISet<ISymbol> overridableMembers)
            {
                var result = new HashSet<ISymbol>();

                var containingType = semanticModel.GetEnclosingSymbol<INamedTypeSymbol>(startToken.SpanStart, _cancellationToken);
                if (containingType != null && !containingType.IsScriptClass && !containingType.IsImplicitClass)
                {
                    if (containingType.TypeKind == TypeKind.Class || containingType.TypeKind == TypeKind.Struct)
                    {
                        var baseTypes = containingType.GetBaseTypes().Reverse();
                        foreach (var type in baseTypes)
                        {
                            _cancellationToken.ThrowIfCancellationRequested();

                            // Prefer overrides in derived classes
                            RemoveOverriddenMembers(result, type);

                            // Retain overridable methods
                            AddOverridableMembers(result, containingType, type);
                        }

                        // Don't suggest already overridden members
                        RemoveOverriddenMembers(result, containingType);
                    }
                }

                // Filter based on accessibility
                if (seenAccessibility != Accessibility.NotApplicable)
                {
                    result.RemoveWhere(m => m.DeclaredAccessibility != seenAccessibility);
                }

                overridableMembers = result;
                return overridableMembers.Count > 0;
            }
        protected override bool TryBuildSpecificConverter(
            ForEachInfo <ForEachStatementSyntax, StatementSyntax> forEachInfo,
            SemanticModel semanticModel,
            StatementSyntax statementCannotBeConverted,
            CancellationToken cancellationToken,
            out IConverter <ForEachStatementSyntax, StatementSyntax> converter)
        {
            switch (statementCannotBeConverted.Kind())
            {
            case SyntaxKind.ExpressionStatement:
                var expresisonStatement = (ExpressionStatementSyntax)statementCannotBeConverted;
                var expression          = expresisonStatement.Expression;
                switch (expression.Kind())
                {
                case SyntaxKind.PostIncrementExpression:
                    // Input:
                    // foreach (var x in a)
                    // {
                    //     ...
                    //     c++;
                    // }
                    // Output:
                    // (from x in a ... select x).Count();
                    // Here we put SyntaxFactory.IdentifierName(forEachStatement.Identifier) ('x' in the example)
                    // into the select clause.
                    var postfixUnaryExpression = (PostfixUnaryExpressionSyntax)expression;
                    var operand = postfixUnaryExpression.Operand;
                    converter = new ToCountConverter(
                        forEachInfo,
                        selectExpression: SyntaxFactory.IdentifierName(forEachInfo.ForEachStatement.Identifier),
                        modifyingExpression: operand,
                        trivia: SyntaxNodeOrTokenExtensions.GetTrivia(
                            operand, postfixUnaryExpression.OperatorToken, expresisonStatement.SemicolonToken));
                    return(true);

                case SyntaxKind.InvocationExpression:
                    var invocationExpression = (InvocationExpressionSyntax)expression;
                    // Check that there is 'list.Add(item)'.
                    if (invocationExpression.Expression is MemberAccessExpressionSyntax memberAccessExpression &&
                        semanticModel.GetSymbolInfo(memberAccessExpression, cancellationToken).Symbol is IMethodSymbol methodSymbol &&
                        TypeSymbolOptIsList(methodSymbol.ContainingType, semanticModel) &&
                        methodSymbol.Name == nameof(IList.Add) &&
                        methodSymbol.Parameters.Length == 1 &&
                        invocationExpression.ArgumentList.Arguments.Count == 1)
                    {
                        // Input:
                        // foreach (var x in a)
                        // {
                        //     ...
                        //     list.Add(...);
                        // }
                        // Output:
                        // (from x in a ... select x).ToList();
                        var selectExpression = invocationExpression.ArgumentList.Arguments.Single().Expression;
                        converter = new ToToListConverter(
                            forEachInfo,
                            selectExpression,
                            modifyingExpression: memberAccessExpression.Expression,
                            trivia: SyntaxNodeOrTokenExtensions.GetTrivia(
                                memberAccessExpression,
                                invocationExpression.ArgumentList.OpenParenToken,
                                invocationExpression.ArgumentList.CloseParenToken,
                                expresisonStatement.SemicolonToken));
                        return(true);
                    }

                    break;
                }

                break;

            case SyntaxKind.YieldReturnStatement:
                var memberDeclarationSymbol = semanticModel.GetEnclosingSymbol(
                    forEachInfo.ForEachStatement.SpanStart, cancellationToken);

                // Using Single() is valid even for partial methods.
                var memberDeclarationSyntax = memberDeclarationSymbol.DeclaringSyntaxReferences.Single().GetSyntax();

                var yieldStatementsCount = memberDeclarationSyntax.DescendantNodes().OfType <YieldStatementSyntax>()
                                           // Exclude yield statements from nested local functions.
                                           .Where(statement => semanticModel.GetEnclosingSymbol(
                                                      statement.SpanStart, cancellationToken) == memberDeclarationSymbol).Count();

                if (forEachInfo.ForEachStatement.IsParentKind(SyntaxKind.Block) &&
                    forEachInfo.ForEachStatement.Parent.Parent == memberDeclarationSyntax)
                {
                    // Check that
                    // a. There are either just a single 'yield return' or 'yield return' with 'yield break' just after.
                    // b. Those foreach and 'yield break' (if exists) are last statements in the method (do not count local function declaration statements).
                    var statementsOnBlockWithForEach = ((BlockSyntax)forEachInfo.ForEachStatement.Parent).Statements
                                                       .Where(statement => statement.Kind() != SyntaxKind.LocalFunctionStatement).ToArray();
                    var lastNonLocalFunctionStatement = statementsOnBlockWithForEach.Last();
                    if (yieldStatementsCount == 1 && lastNonLocalFunctionStatement == forEachInfo.ForEachStatement)
                    {
                        converter = new YieldReturnConverter(
                            forEachInfo,
                            (YieldStatementSyntax)statementCannotBeConverted,
                            yieldBreakStatement: null);
                        return(true);
                    }

                    // foreach()
                    // {
                    //    yield return ...;
                    // }
                    // yield break;
                    // end of member
                    if (yieldStatementsCount == 2 &&
                        lastNonLocalFunctionStatement.Kind() == SyntaxKind.YieldBreakStatement &&
                        !lastNonLocalFunctionStatement.ContainsDirectives &&
                        statementsOnBlockWithForEach[statementsOnBlockWithForEach.Length - 2] == forEachInfo.ForEachStatement)
                    {
                        // This removes the yield break.
                        converter = new YieldReturnConverter(
                            forEachInfo,
                            (YieldStatementSyntax)statementCannotBeConverted,
                            yieldBreakStatement: (YieldStatementSyntax)lastNonLocalFunctionStatement);
                        return(true);
                    }
                }

                break;
            }

            converter = default;
            return(false);
        }
Esempio n. 7
0
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            if (!Settings.IsEnabled(CodeFixIdentifiers.AddArgumentList) &&
                !Settings.IsEnabled(CodeFixIdentifiers.OrderModifiers) &&
                !Settings.IsEnabled(CodeFixIdentifiers.ReplaceNullLiteralExpressionWithDefaultValue) &&
                !Settings.IsEnabled(CodeFixIdentifiers.ReturnDefaultValue) &&
                !Settings.IsEnabled(CodeFixIdentifiers.AddMissingType) &&
                !Settings.IsEnabled(CodeFixIdentifiers.RemoveSemicolon) &&
                !Settings.IsEnabled(CodeFixIdentifiers.RemoveConditionalAccess) &&
                !Settings.IsEnabled(CodeFixIdentifiers.ChangeForEachType) &&
                !Settings.IsEnabled(CodeFixIdentifiers.AddDefaultValueToParameter) &&
                !Settings.IsEnabled(CodeFixIdentifiers.ChangeParameterType))
            {
                return;
            }

            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

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

            SyntaxKind kind = token.Kind();

            foreach (Diagnostic diagnostic in context.Diagnostics)
            {
                switch (diagnostic.Id)
                {
                case CompilerDiagnosticIdentifiers.OperatorCannotBeAppliedToOperand:
                {
                    if (kind == SyntaxKind.QuestionToken &&
                        token.Parent is ConditionalAccessExpressionSyntax conditionalAccess)
                    {
                        SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

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

                        if (typeSymbol?.IsErrorType() == false &&
                            !typeSymbol.IsNullableType())
                        {
                            if (typeSymbol.IsValueType)
                            {
                                if (Settings.IsEnabled(CodeFixIdentifiers.RemoveConditionalAccess))
                                {
                                    CodeAction codeAction = CodeAction.Create(
                                        "Remove '?' operator",
                                        cancellationToken =>
                                        {
                                            var textChange = new TextChange(token.Span, "");
                                            return(context.Document.WithTextChangeAsync(textChange, cancellationToken));
                                        },
                                        GetEquivalenceKey(diagnostic));

                                    context.RegisterCodeFix(codeAction, diagnostic);
                                }
                            }
                            else if (typeSymbol.IsReferenceType)
                            {
                                if (Settings.IsEnabled(CodeFixIdentifiers.AddArgumentList) &&
                                    conditionalAccess.WhenNotNull is MemberBindingExpressionSyntax memberBindingExpression)
                                {
                                    ConditionalAccessExpressionSyntax newNode = conditionalAccess.WithWhenNotNull(
                                        InvocationExpression(
                                            memberBindingExpression.WithoutTrailingTrivia(),
                                            ArgumentList().WithTrailingTrivia(memberBindingExpression.GetTrailingTrivia())));

                                    CodeAction codeAction = CodeAction.Create(
                                        "Add argument list",
                                        cancellationToken => context.Document.ReplaceNodeAsync(conditionalAccess, newNode, cancellationToken),
                                        GetEquivalenceKey(diagnostic));

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

                    break;
                }

                case CompilerDiagnosticIdentifiers.PartialModifierCanOnlyAppearImmediatelyBeforeClassStructInterfaceOrVoid:
                {
                    if (!Settings.IsEnabled(CodeFixIdentifiers.OrderModifiers))
                    {
                        break;
                    }

                    ModifiersCodeFixRegistrator.MoveModifier(context, diagnostic, token.Parent, token);
                    break;
                }

                case CompilerDiagnosticIdentifiers.ValueCannotBeUsedAsDefaultParameter:
                {
                    if (!Settings.IsAnyEnabled(CodeFixIdentifiers.ReplaceNullLiteralExpressionWithDefaultValue, CodeFixIdentifiers.ChangeParameterType))
                    {
                        break;
                    }

                    if (!(token.Parent is ParameterSyntax parameter))
                    {
                        break;
                    }

                    ExpressionSyntax value = parameter.Default?.Value;

                    if (value == null)
                    {
                        break;
                    }

                    if (value.IsKind(SyntaxKind.NullLiteralExpression))
                    {
                        if (Settings.IsEnabled(CodeFixIdentifiers.ReplaceNullLiteralExpressionWithDefaultValue))
                        {
                            SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                            CodeFixRegistrator.ReplaceNullWithDefaultValue(context, diagnostic, value, semanticModel);
                        }
                    }
                    else if (!value.IsKind(SyntaxKind.DefaultExpression, SyntaxKind.DefaultLiteralExpression))
                    {
                        if (Settings.IsEnabled(CodeFixIdentifiers.ChangeParameterType))
                        {
                            SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

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

                            if (!typeSymbol.IsKind(SymbolKind.ErrorType))
                            {
                                CodeFixRegistrator.ChangeType(context, diagnostic, parameter.Type, typeSymbol, semanticModel);
                            }
                        }
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.ObjectOfTypeConvertibleToTypeIsRequired:
                {
                    if (!Settings.IsEnabled(CodeFixIdentifiers.ReturnDefaultValue))
                    {
                        break;
                    }

                    if (token.Kind() != SyntaxKind.ReturnKeyword)
                    {
                        break;
                    }

                    if (!token.IsParentKind(SyntaxKind.ReturnStatement))
                    {
                        break;
                    }

                    SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                    ISymbol symbol = semanticModel.GetEnclosingSymbol(token.SpanStart, context.CancellationToken);

                    if (symbol == null)
                    {
                        break;
                    }

                    SymbolKind symbolKind = symbol.Kind;

                    ITypeSymbol typeSymbol = null;

                    if (symbolKind == SymbolKind.Method)
                    {
                        var methodSymbol = (IMethodSymbol)symbol;

                        typeSymbol = methodSymbol.ReturnType;

                        if (methodSymbol.IsAsync &&
                            (typeSymbol is INamedTypeSymbol namedTypeSymbol))
                        {
                            ImmutableArray <ITypeSymbol> typeArguments = namedTypeSymbol.TypeArguments;

                            if (typeArguments.Any())
                            {
                                typeSymbol = typeArguments[0];
                            }
                        }
                    }
                    else if (symbolKind == SymbolKind.Property)
                    {
                        typeSymbol = ((IPropertySymbol)symbol).Type;
                    }
                    else
                    {
                        Debug.Fail(symbolKind.ToString());
                    }

                    if (typeSymbol == null)
                    {
                        break;
                    }

                    if (typeSymbol.Kind == SymbolKind.ErrorType)
                    {
                        break;
                    }

                    if (!typeSymbol.SupportsExplicitDeclaration())
                    {
                        break;
                    }

                    var returnStatement = (ReturnStatementSyntax)token.Parent;

                    CodeAction codeAction = CodeAction.Create(
                        "Return default value",
                        cancellationToken =>
                        {
                            ExpressionSyntax expression = typeSymbol.GetDefaultValueSyntax(context.Document.GetDefaultSyntaxOptions());

                            if (expression.IsKind(SyntaxKind.DefaultExpression) &&
                                context.Document.SupportsLanguageFeature(CSharpLanguageFeature.DefaultLiteral))
                            {
                                expression = CSharpFactory.DefaultLiteralExpression().WithTriviaFrom(expression);
                            }

                            ReturnStatementSyntax newNode = returnStatement.WithExpression(expression);

                            return(context.Document.ReplaceNodeAsync(returnStatement, newNode, cancellationToken));
                        },
                        GetEquivalenceKey(diagnostic));

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

                case CompilerDiagnosticIdentifiers.TypeExpected:
                {
                    if (!Settings.IsEnabled(CodeFixIdentifiers.AddMissingType))
                    {
                        break;
                    }

                    if (token.Kind() != SyntaxKind.CloseParenToken)
                    {
                        break;
                    }

                    if (!(token.Parent is DefaultExpressionSyntax defaultExpression))
                    {
                        break;
                    }

                    if (!(defaultExpression.Type is IdentifierNameSyntax identifierName))
                    {
                        break;
                    }

                    if (!identifierName.IsMissing)
                    {
                        break;
                    }

                    SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                    TypeInfo typeInfo = semanticModel.GetTypeInfo(defaultExpression, context.CancellationToken);

                    ITypeSymbol convertedType = typeInfo.ConvertedType;

                    if (convertedType?.SupportsExplicitDeclaration() != true)
                    {
                        break;
                    }

                    CodeAction codeAction = CodeAction.Create(
                        $"Add type '{SymbolDisplay.ToMinimalDisplayString(convertedType, semanticModel, defaultExpression.SpanStart, SymbolDisplayFormats.Default)}'",
                        cancellationToken =>
                        {
                            TypeSyntax newNode = convertedType.ToMinimalTypeSyntax(semanticModel, defaultExpression.SpanStart);

                            newNode = newNode
                                      .WithTriviaFrom(identifierName)
                                      .WithFormatterAnnotation();

                            return(context.Document.ReplaceNodeAsync(identifierName, newNode, cancellationToken));
                        },
                        GetEquivalenceKey(diagnostic));

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

                case CompilerDiagnosticIdentifiers.SemicolonAfterMethodOrAccessorBlockIsNotValid:
                {
                    if (!Settings.IsEnabled(CodeFixIdentifiers.RemoveSemicolon))
                    {
                        break;
                    }

                    if (token.Kind() != SyntaxKind.SemicolonToken)
                    {
                        break;
                    }

                    switch (token.Parent)
                    {
                    case MethodDeclarationSyntax methodDeclaration:
                    {
                        BlockSyntax body = methodDeclaration.Body;

                        if (body == null)
                        {
                            break;
                        }

                        CodeAction codeAction = CodeAction.Create(
                            "Remove semicolon",
                            cancellationToken =>
                                {
                                    SyntaxTriviaList trivia = body
                                                              .GetTrailingTrivia()
                                                              .EmptyIfWhitespace()
                                                              .AddRange(token.LeadingTrivia.EmptyIfWhitespace())
                                                              .AddRange(token.TrailingTrivia);

                                    MethodDeclarationSyntax newNode = methodDeclaration
                                                                      .WithBody(body.WithTrailingTrivia(trivia))
                                                                      .WithSemicolonToken(default(SyntaxToken));

                                    return(context.Document.ReplaceNodeAsync(methodDeclaration, newNode, cancellationToken));
                                },
                            GetEquivalenceKey(diagnostic));

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

                    case PropertyDeclarationSyntax propertyDeclaration:
                    {
                        AccessorListSyntax accessorList = propertyDeclaration.AccessorList;

                        if (accessorList == null)
                        {
                            break;
                        }

                        CodeAction codeAction = CodeAction.Create(
                            "Remove semicolon",
                            cancellationToken =>
                                {
                                    SyntaxTriviaList trivia = accessorList
                                                              .GetTrailingTrivia()
                                                              .EmptyIfWhitespace()
                                                              .AddRange(token.LeadingTrivia.EmptyIfWhitespace())
                                                              .AddRange(token.TrailingTrivia);

                                    PropertyDeclarationSyntax newNode = propertyDeclaration
                                                                        .WithAccessorList(accessorList.WithTrailingTrivia(trivia))
                                                                        .WithSemicolonToken(default(SyntaxToken));

                                    return(context.Document.ReplaceNodeAsync(propertyDeclaration, newNode, cancellationToken));
                                },
                            GetEquivalenceKey(diagnostic));

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

                    case AccessorDeclarationSyntax accessorDeclaration:
                    {
                        BlockSyntax body = accessorDeclaration.Body;

                        if (body == null)
                        {
                            break;
                        }

                        CodeAction codeAction = CodeAction.Create(
                            "Remove semicolon",
                            cancellationToken =>
                                {
                                    SyntaxTriviaList trivia = body
                                                              .GetTrailingTrivia()
                                                              .EmptyIfWhitespace()
                                                              .AddRange(token.LeadingTrivia.EmptyIfWhitespace())
                                                              .AddRange(token.TrailingTrivia);

                                    AccessorDeclarationSyntax newNode = accessorDeclaration
                                                                        .WithBody(body.WithTrailingTrivia(trivia))
                                                                        .WithSemicolonToken(default(SyntaxToken));

                                    return(context.Document.ReplaceNodeAsync(accessorDeclaration, newNode, cancellationToken));
                                },
                            GetEquivalenceKey(diagnostic));

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

                    break;
                }

                case CompilerDiagnosticIdentifiers.CannotConvertType:
                {
                    if (!Settings.IsEnabled(CodeFixIdentifiers.ChangeForEachType))
                    {
                        break;
                    }

                    if (token.Kind() != SyntaxKind.ForEachKeyword)
                    {
                        break;
                    }

                    if (!(token.Parent is ForEachStatementSyntax forEachStatement))
                    {
                        break;
                    }

                    SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                    ForEachStatementInfo info = semanticModel.GetForEachStatementInfo(forEachStatement);

                    ITypeSymbol typeSymbol = info.ElementType;

                    if (typeSymbol.SupportsExplicitDeclaration())
                    {
                        CodeFixRegistrator.ChangeType(context, diagnostic, forEachStatement.Type, typeSymbol, semanticModel, CodeFixIdentifiers.ChangeForEachType);
                    }

                    CodeFixRegistrator.ChangeTypeToVar(context, diagnostic, forEachStatement.Type, CodeFixIdentifiers.ChangeTypeToVar);
                    break;
                }

                case CompilerDiagnosticIdentifiers.OptionalParametersMustAppearAfterAllRequiredParameters:
                {
                    if (!Settings.IsEnabled(CodeFixIdentifiers.AddDefaultValueToParameter))
                    {
                        break;
                    }

                    if (!(token.Parent is BaseParameterListSyntax parameterList))
                    {
                        break;
                    }

                    SeparatedSyntaxList <ParameterSyntax> parameters = parameterList.Parameters;

                    ParameterSyntax parameter = null;

                    for (int i = 0; i < parameters.Count; i++)
                    {
                        ParameterSyntax p = parameters[i];

                        if (p.FullSpan.End <= token.SpanStart)
                        {
                            parameter = p;
                        }
                        else
                        {
                            break;
                        }
                    }

                    SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                    IParameterSymbol parameterSymbol = semanticModel.GetDeclaredSymbol(parameter, context.CancellationToken);

                    ITypeSymbol typeSymbol = parameterSymbol.Type;

                    if (typeSymbol.Kind == SymbolKind.ErrorType)
                    {
                        break;
                    }

                    CodeAction codeAction = CodeAction.Create(
                        "Add default value",
                        cancellationToken =>
                        {
                            ExpressionSyntax defaultValue = typeSymbol.GetDefaultValueSyntax(context.Document.GetDefaultSyntaxOptions());

                            ParameterSyntax newParameter = parameter
                                                           .WithDefault(EqualsValueClause(defaultValue).WithTrailingTrivia(parameter.GetTrailingTrivia()))
                                                           .WithoutTrailingTrivia()
                                                           .WithFormatterAnnotation();

                            return(context.Document.ReplaceNodeAsync(parameter, newParameter, cancellationToken));
                        },
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }
                }
            }
        }
Esempio n. 8
0
        public static void ComputeCodeFix(
            CodeFixContext context,
            Diagnostic diagnostic,
            ExpressionSyntax expression,
            SemanticModel semanticModel)
        {
            if (!(expression.Parent is EqualsValueClauseSyntax equalsValueClause))
            {
                return;
            }

            if (equalsValueClause.Parent is VariableDeclaratorSyntax variableDeclarator)
            {
                if (!(variableDeclarator.Parent is VariableDeclarationSyntax variableDeclaration))
                {
                    return;
                }

                TypeSyntax type = variableDeclaration.Type;

                if (type != null)
                {
                    ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(expression, context.CancellationToken);

                    if (typeSymbol?.SupportsExplicitDeclaration() == true)
                    {
                        CodeFixRegistrator.ChangeType(context, diagnostic, type, typeSymbol, semanticModel, CodeFixIdentifiers.ChangeTypeAccordingToInitializer);

                        if (typeSymbol.IsConstructedFromTaskOfT(semanticModel))
                        {
                            ISymbol enclosingSymbol = semanticModel.GetEnclosingSymbol(variableDeclaration.SpanStart, context.CancellationToken);

                            if (enclosingSymbol.IsAsyncMethod())
                            {
                                ITypeSymbol typeArgument = ((INamedTypeSymbol)typeSymbol).TypeArguments[0];

                                ChangeTypeAndAddAwait(context, diagnostic, expression, variableDeclaration, type, typeArgument, semanticModel);
                            }
                        }
                    }

                    if (variableDeclaration.IsParentKind(SyntaxKind.LocalDeclarationStatement, SyntaxKind.UsingStatement))
                    {
                        CodeFixRegistrator.ChangeTypeToVar(context, diagnostic, type, CodeFixIdentifiers.ChangeTypeToVar);
                    }
                }
            }
            else if (equalsValueClause.Parent is PropertyDeclarationSyntax propertyDeclaration)
            {
                TypeSyntax type = propertyDeclaration.Type;

                if (type != null)
                {
                    ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(expression, context.CancellationToken);

                    if (typeSymbol?.SupportsExplicitDeclaration() == true)
                    {
                        ISymbol symbol = semanticModel.GetDeclaredSymbol(propertyDeclaration, context.CancellationToken);

                        if (symbol?.IsOverride == false &&
                            !symbol.ImplementsInterfaceMember())
                        {
                            CodeFixRegistrator.ChangeType(context, diagnostic, type, typeSymbol, semanticModel, CodeFixIdentifiers.ChangeTypeAccordingToInitializer);
                        }
                    }
                }
            }
            else
            {
                Debug.Fail(equalsValueClause.Parent.Kind().ToString());
            }
        }
Esempio n. 9
0
        public static async Task ComputeRefactoringAsync(RefactoringContext context, LocalDeclarationStatementSyntax localDeclaration)
        {
            SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

            ISymbol symbol = semanticModel.GetEnclosingSymbol(localDeclaration.SpanStart, context.CancellationToken);

            if (symbol?.IsMethod() == true)
            {
                var methodsymbol = (IMethodSymbol)symbol;

                if (methodsymbol.MethodKind == MethodKind.Ordinary)
                {
                    if (methodsymbol.PartialImplementationPart != null)
                    {
                        symbol = methodsymbol.PartialImplementationPart;
                    }

                    SyntaxNode node = await symbol
                                      .DeclaringSyntaxReferences[0]
                                      .GetSyntaxAsync(context.CancellationToken)
                                      .ConfigureAwait(false);

                    var method = node as MethodDeclarationSyntax;

                    if (method != null)
                    {
                        VariableDeclarationSyntax declaration = localDeclaration.Declaration;

                        if (declaration != null)
                        {
                            VariableDeclaratorSyntax variable = declaration
                                                                .Variables
                                                                .FirstOrDefault(f => !f.IsMissing && f.Identifier.Span.Contains(context.Span));

                            if (variable != null)
                            {
                                TypeSyntax type = declaration.Type;

                                if (type != null)
                                {
                                    if (type.IsVar)
                                    {
                                        ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(type, context.CancellationToken);

                                        if (typeSymbol?.SupportsExplicitDeclaration() == true)
                                        {
                                            type = typeSymbol.ToTypeSyntax();
                                        }
                                        else
                                        {
                                            type = null;
                                        }
                                    }

                                    if (type != null)
                                    {
                                        context.RegisterRefactoring(
                                            $"Promote '{variable.Identifier.ValueText}' to parameter",
                                            cancellationToken =>
                                        {
                                            return(RefactorAsync(
                                                       context.Document,
                                                       method,
                                                       localDeclaration,
                                                       type.WithoutTrivia().WithSimplifierAnnotation(),
                                                       variable,
                                                       cancellationToken));
                                        });
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
Esempio n. 10
0
        ParameterHintingResult HandleInvocationExpression(SemanticModel semanticModel, InvocationExpressionSyntax node, CancellationToken cancellationToken)
        {
            var info   = semanticModel.GetSymbolInfo(node, cancellationToken);
            var result = new ParameterHintingResult(node.SpanStart);

            var targetTypeInfo = semanticModel.GetTypeInfo(node.Expression);

            if (targetTypeInfo.Type != null && targetTypeInfo.Type.TypeKind == TypeKind.Delegate)
            {
                result.AddData(factory.CreateMethodDataProvider(targetTypeInfo.Type.GetDelegateInvokeMethod()));
                return(result);
            }

            var         within = semanticModel.GetEnclosingNamedTypeOrAssembly(node.SpanStart, cancellationToken);
            ITypeSymbol type;
            string      name         = null;
            bool        staticLookup = false;
            var         ma           = node.Expression as MemberAccessExpressionSyntax;
            var         mb           = node.Expression as MemberBindingExpressionSyntax;

            if (mb != null)
            {
                info = semanticModel.GetSymbolInfo(mb, cancellationToken);
                type = (info.Symbol ?? info.CandidateSymbols.FirstOrDefault())?.ContainingType;
                name = mb.Name.Identifier.ValueText;
            }
            else if (ma != null)
            {
                staticLookup = semanticModel.GetSymbolInfo(ma.Expression).Symbol is ITypeSymbol;
                type         = semanticModel.GetTypeInfo(ma.Expression).Type;
                name         = info.Symbol?.Name ?? ma.Name.Identifier.ValueText;
            }
            else
            {
                type = within as ITypeSymbol;
                name = info.Symbol?.Name ?? node.Expression.ToString();
                var sym = semanticModel.GetEnclosingSymbol(node.SpanStart, cancellationToken);
                staticLookup = sym.IsStatic;
            }
            var addedMethods = new List <IMethodSymbol> ();
            var filterMethod = new HashSet <IMethodSymbol> ();

            for (; type != null; type = type.BaseType)
            {
                foreach (var method in type.GetMembers().OfType <IMethodSymbol> ().Concat(GetExtensionMethods(semanticModel, type, node, cancellationToken)).Where(m => m.Name == name))
                {
                    if (staticLookup && !method.IsStatic)
                    {
                        continue;
                    }
                    if (method.OverriddenMethod != null)
                    {
                        filterMethod.Add(method.OverriddenMethod);
                    }
                    if (filterMethod.Contains(method))
                    {
                        continue;
                    }
                    if (addedMethods.Any(added => SignatureComparer.HaveSameSignature(method, added, true)))
                    {
                        continue;
                    }
                    if (method.IsAccessibleWithin(within))
                    {
                        if (info.Symbol != null)
                        {
                            var smethod = (IMethodSymbol)info.Symbol;
                            if (smethod != null && smethod.OriginalDefinition == method)
                            {
                                continue;
                            }
                        }
                        addedMethods.Add(method);
                        result.AddData(factory.CreateMethodDataProvider(method));
                    }
                }
            }
            if (info.Symbol != null && !addedMethods.Contains(info.Symbol))
            {
                if (!staticLookup || info.Symbol.IsStatic)
                {
                    result.AddData(factory.CreateMethodDataProvider((IMethodSymbol)info.Symbol));
                }
            }
            return(result);
        }
 public static ISymbol GetEnclosingNamedTypeOrAssembly(this SemanticModel semanticModel, int position, CancellationToken cancellationToken)
 {
     return(semanticModel.GetEnclosingSymbol <INamedTypeSymbol>(position, cancellationToken) ??
            (ISymbol)semanticModel.Compilation.Assembly);
 }
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddComparisonWithBooleanLiteral) &&
                !Settings.IsCodeFixEnabled(CodeFixIdentifiers.CreateSingletonArray) &&
                !Settings.IsCodeFixEnabled(CodeFixIdentifiers.UseUncheckedExpression) &&
                !Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveConstModifier) &&
                !Settings.IsCodeFixEnabled(CodeFixIdentifiers.ReplaceNullLiteralExpressionWithDefaultValue) &&
                !Settings.IsCodeFixEnabled(CodeFixIdentifiers.UseCoalesceExpression) &&
                !Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveConditionThatIsAlwaysEqualToTrueOrFalse) &&
                !Settings.IsCodeFixEnabled(CodeFixIdentifiers.IntroduceLocalVariable) &&
                !Settings.IsCodeFixEnabled(CodeFixIdentifiers.IntroduceField) &&
                !Settings.IsCodeFixEnabled(CodeFixIdentifiers.ReplaceStringLiteralWithCharacterLiteral) &&
                !Settings.IsCodeFixEnabled(CodeFixIdentifiers.UseYieldReturnInsteadOfReturn) &&
                !Settings.IsCodeFixEnabled(CodeFixIdentifiers.ChangeMemberTypeAccordingToReturnExpression) &&
                !Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddArgumentList) &&
                !Settings.IsCodeFixEnabled(CodeFixIdentifiers.ReplaceConditionalExpressionWithIfElse) &&
                !Settings.IsCodeFixEnabled(CodeFixIdentifiers.ReplaceConstantWithField) &&
                !Settings.IsCodeFixEnabled(CodeFixIdentifiers.ChangeTypeAccordingToInitializer) &&
                !Settings.IsCodeFixEnabled(CodeFixIdentifiers.ReplaceYieldReturnWithForEach) &&
                !Settings.IsCodeFixEnabled(CodeFixIdentifiers.ReplaceComparisonWithAssignment) &&
                !Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveParentheses))
            {
                return;
            }

            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            if (!TryFindNode(root, context.Span, out ExpressionSyntax expression))
            {
                return;
            }

            foreach (Diagnostic diagnostic in context.Diagnostics)
            {
                switch (diagnostic.Id)
                {
                case CompilerDiagnosticIdentifiers.CannotImplicitlyConvertTypeExplicitConversionExists:
                {
                    SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                    TypeInfo typeInfo = semanticModel.GetTypeInfo(expression, context.CancellationToken);

                    ITypeSymbol type          = typeInfo.Type;
                    ITypeSymbol convertedType = typeInfo.ConvertedType;

                    if ((type is INamedTypeSymbol namedType) &&
                        namedType.IsNullableType())
                    {
                        if (convertedType?.SpecialType == SpecialType.System_Boolean ||
                            AddComparisonWithBooleanLiteralRefactoring.IsCondition(expression))
                        {
                            if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddComparisonWithBooleanLiteral))
                            {
                                CodeAction codeAction = CodeAction.Create(
                                    AddComparisonWithBooleanLiteralRefactoring.GetTitle(expression),
                                    cancellationToken => AddComparisonWithBooleanLiteralRefactoring.RefactorAsync(context.Document, expression, cancellationToken),
                                    GetEquivalenceKey(diagnostic, CodeFixIdentifiers.AddComparisonWithBooleanLiteral));

                                context.RegisterCodeFix(codeAction, diagnostic);
                            }
                        }
                        else if (namedType.TypeArguments[0].Equals(convertedType))
                        {
                            if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.UseCoalesceExpression))
                            {
                                CodeAction codeAction = CodeAction.Create(
                                    "Use coalesce expression",
                                    cancellationToken =>
                                    {
                                        ExpressionSyntax defaultValue = (context.Document.SupportsLanguageFeature(CSharpLanguageFeature.DefaultLiteral))
                                                    ? DefaultLiteralExpression()
                                                    : convertedType.GetDefaultValueSyntax(semanticModel, expression.SpanStart);

                                        ExpressionSyntax newNode = CoalesceExpression(expression.WithoutTrivia(), defaultValue)
                                                                   .WithTriviaFrom(expression)
                                                                   .Parenthesize()
                                                                   .WithFormatterAnnotation();

                                        return(context.Document.ReplaceNodeAsync(expression, newNode, cancellationToken));
                                    },
                                    GetEquivalenceKey(diagnostic, CodeFixIdentifiers.UseCoalesceExpression));

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

                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.ChangeMemberTypeAccordingToReturnExpression) &&
                        expression.IsParentKind(SyntaxKind.ReturnStatement, SyntaxKind.YieldReturnStatement))
                    {
                        ChangeMemberTypeRefactoring.ComputeCodeFix(context, diagnostic, expression, semanticModel);
                    }

                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddCastExpression))
                    {
                        CodeFixRegistrator.AddCastExpression(context, diagnostic, expression, convertedType, semanticModel);
                    }

                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.ChangeTypeAccordingToInitializer))
                    {
                        ChangeTypeAccordingToInitializerRefactoring.ComputeCodeFix(context, diagnostic, expression, semanticModel);
                    }

                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.CreateSingletonArray) &&
                        type?.IsErrorType() == false &&
                        !type.Equals(convertedType) &&
                        (convertedType is IArrayTypeSymbol arrayType) &&
                        semanticModel.IsImplicitConversion(expression, arrayType.ElementType))
                    {
                        CodeAction codeAction = CodeAction.Create(
                            "Create singleton array",
                            cancellationToken => CreateSingletonArrayRefactoring.RefactorAsync(context.Document, expression, arrayType.ElementType, semanticModel, cancellationToken),
                            GetEquivalenceKey(diagnostic, CodeFixIdentifiers.CreateSingletonArray));

                        context.RegisterCodeFix(codeAction, diagnostic);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.ConstantValueCannotBeConverted:
                {
                    if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.UseUncheckedExpression))
                    {
                        break;
                    }

                    CodeAction codeAction = CodeAction.Create(
                        "Use 'unchecked'",
                        cancellationToken =>
                        {
                            CheckedExpressionSyntax newNode = CSharpFactory.UncheckedExpression(expression.WithoutTrivia());

                            newNode = newNode.WithTriviaFrom(expression);

                            return(context.Document.ReplaceNodeAsync(expression, newNode, cancellationToken));
                        },
                        GetEquivalenceKey(diagnostic));

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

                case CompilerDiagnosticIdentifiers.ExpressionBeingAssignedMustBeConstant:
                {
                    SyntaxNode parent = expression.Parent;

                    if (parent?.IsKind(SyntaxKind.EqualsValueClause) != true)
                    {
                        break;
                    }

                    parent = parent.Parent;

                    if (parent?.IsKind(SyntaxKind.VariableDeclarator) != true)
                    {
                        break;
                    }

                    parent = parent.Parent;

                    if (!(parent is VariableDeclarationSyntax variableDeclaration))
                    {
                        break;
                    }

                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveConstModifier) &&
                        variableDeclaration.Parent is LocalDeclarationStatementSyntax localDeclarationStatement)
                    {
                        SyntaxTokenList modifiers = localDeclarationStatement.Modifiers;

                        if (!modifiers.Contains(SyntaxKind.ConstKeyword))
                        {
                            break;
                        }

                        ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, localDeclarationStatement, SyntaxKind.ConstKeyword);
                    }
                    else if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.ReplaceConstantWithField) &&
                             variableDeclaration.Variables.Count == 1 &&
                             (variableDeclaration.Parent is FieldDeclarationSyntax fieldDeclaration) &&
                             fieldDeclaration.Modifiers.Contains(SyntaxKind.ConstKeyword))
                    {
                        CodeAction codeAction = CodeAction.Create(
                            ReplaceConstantWithFieldRefactoring.Title,
                            cancellationToken => ReplaceConstantWithFieldRefactoring.RefactorAsync(context.Document, fieldDeclaration, cancellationToken),
                            GetEquivalenceKey(diagnostic));

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

                    break;
                }

                case CompilerDiagnosticIdentifiers.CannotConvertNullToTypeBecauseItIsNonNullableValueType:
                case CompilerDiagnosticIdentifiers.CannotConvertNullToTypeParameterBecauseItCouldBeNonNullableValueType:
                {
                    if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.ReplaceNullLiteralExpressionWithDefaultValue))
                    {
                        break;
                    }

                    SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                    CodeFixRegistrator.ReplaceNullWithDefaultValue(context, diagnostic, expression, semanticModel);
                    break;
                }

                case CompilerDiagnosticIdentifiers.ResultOfExpressionIsAlwaysConstantSinceValueIsNeverEqualToNull:
                {
                    if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveConditionThatIsAlwaysEqualToTrueOrFalse))
                    {
                        break;
                    }

                    NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(expression, allowedStyles: NullCheckStyles.ComparisonToNull);

                    if (!nullCheck.Success)
                    {
                        break;
                    }

                    CodeAction codeAction = CodeAction.Create(
                        "Remove condition",
                        cancellationToken =>
                        {
                            cancellationToken.ThrowIfCancellationRequested();

                            SyntaxNode newRoot = RemoveCondition(root, expression, nullCheck.Style == NullCheckStyles.NotEqualsToNull);

                            cancellationToken.ThrowIfCancellationRequested();

                            return(Task.FromResult(context.Document.WithSyntaxRoot(newRoot)));
                        },
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);

                    break;
                }

                case CompilerDiagnosticIdentifiers.OnlyAssignmentCallIncrementDecrementAndNewObjectExpressionsCanBeUsedAsStatement:
                {
                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveParentheses) &&
                        expression is ParenthesizedExpressionSyntax parenthesizedExpression &&
                        parenthesizedExpression?.IsMissing == false)
                    {
                        CodeAction codeAction = CodeAction.Create(
                            "Remove parentheses",
                            cancellationToken => RemoveRedundantParenthesesRefactoring.RefactorAsync(context.Document, parenthesizedExpression, cancellationToken),
                            GetEquivalenceKey(diagnostic));

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

                    SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                    if (expression.Parent is ArrowExpressionClauseSyntax arrowExpresssionClause)
                    {
                        if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.ChangeMemberTypeAccordingToReturnExpression))
                        {
                            break;
                        }

                        ChangeMemberTypeRefactoring.ComputeCodeFix(context, diagnostic, expression, semanticModel);
                    }
                    else if (expression.Parent is ExpressionStatementSyntax expressionStatement)
                    {
                        if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddArgumentList) &&
                            expression.IsKind(
                                SyntaxKind.IdentifierName,
                                SyntaxKind.SimpleMemberAccessExpression))
                        {
                            SyntaxNode invocationExpression = InvocationExpression(expression);

                            if (semanticModel.GetSpeculativeMethodSymbol(expression.SpanStart, invocationExpression) != null)
                            {
                                CodeAction codeAction = CodeAction.Create(
                                    "Add argument list",
                                    cancellationToken => context.Document.ReplaceNodeAsync(expression, invocationExpression, cancellationToken),
                                    GetEquivalenceKey(diagnostic, CodeFixIdentifiers.AddArgumentList));

                                context.RegisterCodeFix(codeAction, diagnostic);
                            }
                        }

                        if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.ReplaceComparisonWithAssignment) &&
                            expression.IsKind(SyntaxKind.EqualsExpression))
                        {
                            BinaryExpressionInfo info = SyntaxInfo.BinaryExpressionInfo(expression);

                            if (!info.Success)
                            {
                                break;
                            }

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

                            if (typeSymbol?.IsErrorType() != false)
                            {
                                break;
                            }

                            if (!semanticModel.IsImplicitConversion(info.Right, typeSymbol))
                            {
                                break;
                            }

                            CodeAction codeAction = CodeAction.Create(
                                "Replace comparison with assignment",
                                cancellationToken =>
                                {
                                    AssignmentExpressionSyntax simpleAssignment = SimpleAssignmentExpression(info.Left, info.Right).WithTriviaFrom(expression);
                                    return(context.Document.ReplaceNodeAsync(expression, simpleAssignment, cancellationToken));
                                },
                                GetEquivalenceKey(diagnostic, CodeFixIdentifiers.ReplaceComparisonWithAssignment));

                            context.RegisterCodeFix(codeAction, diagnostic);
                        }

                        if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.ReplaceConditionalExpressionWithIfElse) &&
                            (expression is ConditionalExpressionSyntax conditionalExpression) &&
                            conditionalExpression.Condition != null)
                        {
                            ExpressionSyntax whenTrue  = conditionalExpression.WhenTrue;
                            ExpressionSyntax whenFalse = conditionalExpression.WhenFalse;

                            if (whenTrue != null &&
                                whenFalse != null &&
                                semanticModel.GetTypeSymbol(whenTrue, context.CancellationToken)?.SpecialType == SpecialType.System_Void &&
                                semanticModel.GetTypeSymbol(whenFalse, context.CancellationToken)?.SpecialType == SpecialType.System_Void)
                            {
                                CodeAction codeAction = CodeAction.Create(
                                    "Replace ?: with if-else",
                                    cancellationToken =>
                                    {
                                        IfStatementSyntax newNode = IfStatement(
                                            conditionalExpression.Condition.WalkDownParentheses(),
                                            Block(ExpressionStatement(whenTrue)),
                                            ElseClause(Block(ExpressionStatement(whenFalse))));

                                        newNode = newNode
                                                  .WithTriviaFrom(expressionStatement)
                                                  .WithFormatterAnnotation();

                                        return(context.Document.ReplaceNodeAsync(expressionStatement, newNode, cancellationToken));
                                    },
                                    GetEquivalenceKey(diagnostic, CodeFixIdentifiers.ReplaceConditionalExpressionWithIfElse));

                                context.RegisterCodeFix(codeAction, diagnostic);
                            }
                        }

                        if (Settings.IsAnyCodeFixEnabled(
                                CodeFixIdentifiers.IntroduceLocalVariable,
                                CodeFixIdentifiers.IntroduceField))
                        {
                            if (semanticModel.GetSymbol(expression, context.CancellationToken)?.IsErrorType() != false)
                            {
                                break;
                            }

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

                            if (typeSymbol?.IsErrorType() != false)
                            {
                                break;
                            }

                            if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.IntroduceLocalVariable) &&
                                !expressionStatement.IsEmbedded())
                            {
                                bool addAwait = typeSymbol.OriginalDefinition.EqualsOrInheritsFromTaskOfT() &&
                                                semanticModel.GetEnclosingSymbol(expressionStatement.SpanStart, context.CancellationToken).IsAsyncMethod();

                                CodeAction codeAction = CodeAction.Create(
                                    IntroduceLocalVariableRefactoring.GetTitle(expression),
                                    cancellationToken => IntroduceLocalVariableRefactoring.RefactorAsync(context.Document, expressionStatement, typeSymbol, addAwait, semanticModel, cancellationToken),
                                    GetEquivalenceKey(diagnostic, CodeFixIdentifiers.IntroduceLocalVariable));

                                context.RegisterCodeFix(codeAction, diagnostic);
                            }

                            if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.IntroduceField))
                            {
                                CodeAction codeAction = CodeAction.Create(
                                    $"Introduce field for '{expression}'",
                                    cancellationToken => IntroduceFieldRefactoring.RefactorAsync(context.Document, expressionStatement, typeSymbol, semanticModel, cancellationToken),
                                    GetEquivalenceKey(diagnostic, CodeFixIdentifiers.IntroduceField));

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

                    break;
                }

                case CompilerDiagnosticIdentifiers.CannotImplicitlyConvertType:
                {
                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.ReplaceYieldReturnWithForEach) &&
                        expression.IsParentKind(SyntaxKind.YieldReturnStatement))
                    {
                        SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                        ReplaceYieldReturnWithForEachRefactoring.ComputeCodeFix(context, diagnostic, expression, semanticModel);
                        break;
                    }

                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.ChangeMemberTypeAccordingToReturnExpression) &&
                        expression.IsParentKind(SyntaxKind.ReturnStatement, SyntaxKind.YieldReturnStatement))
                    {
                        SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                        ChangeMemberTypeRefactoring.ComputeCodeFix(context, diagnostic, expression, semanticModel);
                        break;
                    }

                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.ChangeTypeAccordingToInitializer))
                    {
                        SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                        ChangeTypeAccordingToInitializerRefactoring.ComputeCodeFix(context, diagnostic, expression, semanticModel);
                        break;
                    }

                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.ReplaceStringLiteralWithCharacterLiteral) &&
                        expression?.Kind() == SyntaxKind.StringLiteralExpression)
                    {
                        var literalExpression = (LiteralExpressionSyntax)expression;

                        if (literalExpression.Token.ValueText.Length == 1)
                        {
                            SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                            if (semanticModel.GetTypeInfo(expression, context.CancellationToken).ConvertedType?.SpecialType == SpecialType.System_Char)
                            {
                                CodeAction codeAction = CodeAction.Create(
                                    "Replace string literal with character literal",
                                    cancellationToken => ReplaceStringLiteralWithCharacterLiteralRefactoring.RefactorAsync(context.Document, literalExpression, cancellationToken),
                                    GetEquivalenceKey(diagnostic, CodeFixIdentifiers.ReplaceStringLiteralWithCharacterLiteral));

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

                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.UseYieldReturnInsteadOfReturn) &&
                        expression.IsParentKind(SyntaxKind.ReturnStatement))
                    {
                        var returnStatement = (ReturnStatementSyntax)expression.Parent;

                        SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                        ISymbol containingSymbol = semanticModel.GetEnclosingSymbol(returnStatement.SpanStart, context.CancellationToken);

                        if (containingSymbol?.Kind == SymbolKind.Method &&
                            ((IMethodSymbol)containingSymbol).ReturnType.OriginalDefinition.IsIEnumerableOrIEnumerableOfT())
                        {
                            CodeAction codeAction = CodeAction.Create(
                                "Use yield return instead of return",
                                cancellationToken => UseYieldReturnInsteadOfReturnRefactoring.RefactorAsync(context.Document, returnStatement, SyntaxKind.YieldReturnStatement, semanticModel, cancellationToken),
                                GetEquivalenceKey(diagnostic, CodeFixIdentifiers.UseYieldReturnInsteadOfReturn));

                            context.RegisterCodeFix(codeAction, diagnostic);
                        }
                    }

                    break;
                }
                }
            }
        }
        public static void ComputeRefactoring(
            RefactoringContext context,
            LocalDeclarationStatementSyntax localDeclaration,
            SemanticModel semanticModel)
        {
            if (semanticModel.GetEnclosingSymbol(localDeclaration.SpanStart, context.CancellationToken) is not IMethodSymbol methodSymbol)
                return;

            if (methodSymbol.IsImplicitlyDeclared)
                return;

            if (!methodSymbol.MethodKind.Is(MethodKind.Ordinary, MethodKind.LocalFunction))
                return;

            if (methodSymbol.PartialImplementationPart != null)
                methodSymbol = methodSymbol.PartialImplementationPart;

            SyntaxNode methodOrLocalFunction = methodSymbol.GetSyntax(context.CancellationToken);

            if (!methodOrLocalFunction.IsKind(SyntaxKind.MethodDeclaration, SyntaxKind.LocalFunctionStatement))
                return;

            VariableDeclarationSyntax declaration = localDeclaration.Declaration;

            if (declaration == null)
                return;

            VariableDeclaratorSyntax variable = declaration
                .Variables
                .FirstOrDefault(f => !f.IsMissing && f.Identifier.Span.Contains(context.Span));

            if (variable == null)
                return;

            TypeSyntax type = declaration.Type;

            if (type == null)
                return;

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

                if (typeSymbol?.SupportsExplicitDeclaration() == true)
                {
                    type = typeSymbol.ToTypeSyntax();
                }
                else
                {
                    return;
                }
            }

            context.RegisterRefactoring(
                $"Promote '{variable.Identifier.ValueText}' to parameter",
                ct =>
                {
                    return RefactorAsync(
                        context.Document,
                        methodOrLocalFunction,
                        localDeclaration,
                        type.WithoutTrivia().WithSimplifierAnnotation(),
                        variable,
                        ct);
                },
                RefactoringDescriptors.PromoteLocalVariableToParameter);
        }
Esempio n. 14
0
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            if (!Settings.IsAnyCodeFixEnabled(
                    CodeFixIdentifiers.RemoveUnreachableCode,
                    CodeFixIdentifiers.RemoveEmptySwitchStatement,
                    CodeFixIdentifiers.IntroduceLocalVariable,
                    CodeFixIdentifiers.RemoveJumpStatement))
            {
                return;
            }

            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            if (!TryFindFirstAncestorOrSelf(root, context.Span, out StatementSyntax statement))
            {
                return;
            }

            foreach (Diagnostic diagnostic in context.Diagnostics)
            {
                switch (diagnostic.Id)
                {
                case CompilerDiagnosticIdentifiers.UnreachableCodeDetected:
                {
                    if (context.Span.Start == statement.SpanStart)
                    {
                        StatementContainer container;
                        if (StatementContainer.TryCreate(statement, out container))
                        {
                            CodeAction codeAction = CodeAction.Create(
                                "Remove unreachable code",
                                cancellationToken =>
                                {
                                    SyntaxList <StatementSyntax> statements = container.Statements;

                                    int index = statements.IndexOf(statement);

                                    if (index == statements.Count - 1)
                                    {
                                        return(context.Document.RemoveStatementAsync(statement, context.CancellationToken));
                                    }
                                    else
                                    {
                                        SyntaxRemoveOptions removeOptions = RemoveHelper.DefaultRemoveOptions;

                                        if (statement.GetLeadingTrivia().IsEmptyOrWhitespace())
                                        {
                                            removeOptions &= ~SyntaxRemoveOptions.KeepLeadingTrivia;
                                        }

                                        if (statements.Last().GetTrailingTrivia().IsEmptyOrWhitespace())
                                        {
                                            removeOptions &= ~SyntaxRemoveOptions.KeepTrailingTrivia;
                                        }

                                        return(context.Document.RemoveNodesAsync(statements.Skip(index), removeOptions, context.CancellationToken));
                                    }
                                },
                                GetEquivalenceKey(diagnostic));

                            context.RegisterCodeFix(codeAction, diagnostic);
                        }
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.EmptySwitchBlock:
                {
                    if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveEmptySwitchStatement))
                    {
                        break;
                    }

                    if (!statement.IsKind(SyntaxKind.SwitchStatement))
                    {
                        break;
                    }

                    var switchStatement = (SwitchStatementSyntax)statement;

                    CodeAction codeAction = CodeAction.Create(
                        "Remove switch statement",
                        cancellationToken => context.Document.RemoveStatementAsync(switchStatement, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

                case CompilerDiagnosticIdentifiers.OnlyAssignmentCallIncrementDecrementAndNewObjectExpressionsCanBeUsedAsStatement:
                {
                    if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.IntroduceLocalVariable))
                    {
                        break;
                    }

                    if (!statement.IsKind(SyntaxKind.ExpressionStatement))
                    {
                        break;
                    }

                    var expressionStatement = (ExpressionStatementSyntax)statement;

                    ExpressionSyntax expression = expressionStatement.Expression;

                    SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                    if (semanticModel.GetSymbol(expression, context.CancellationToken)?.IsErrorType() == false)
                    {
                        ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(expression, context.CancellationToken);

                        if (typeSymbol?.IsErrorType() == false)
                        {
                            bool addAwait = typeSymbol.IsConstructedFromTaskOfT(semanticModel) &&
                                            semanticModel.GetEnclosingSymbol(expressionStatement.SpanStart, context.CancellationToken).IsAsyncMethod();

                            CodeAction codeAction = CodeAction.Create(
                                IntroduceLocalVariableRefactoring.GetTitle(expression),
                                cancellationToken => IntroduceLocalVariableRefactoring.RefactorAsync(context.Document, expressionStatement, typeSymbol, addAwait, semanticModel, cancellationToken),
                                GetEquivalenceKey(diagnostic));

                            context.RegisterCodeFix(codeAction, diagnostic);
                        }
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.NoEnclosingLoopOutOfWhichToBreakOrContinue:
                {
                    if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveJumpStatement))
                    {
                        break;
                    }

                    CodeAction codeAction = CodeAction.Create(
                        $"Remove {statement.GetTitle()}",
                        cancellationToken => context.Document.RemoveStatementAsync(statement, cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }
                }
            }
        }
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            if (!Settings.IsAnyCodeFixEnabled(
                    CodeFixIdentifiers.UseYieldReturnInsteadOfReturn,
                    CodeFixIdentifiers.RemoveReturnKeyword,
                    CodeFixIdentifiers.RemoveReturnExpression))
            {
                return;
            }

            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            ReturnStatementSyntax returnStatement = root
                                                    .FindNode(context.Span, getInnermostNodeForTie: true)?
                                                    .FirstAncestorOrSelf <ReturnStatementSyntax>();

            Debug.Assert(returnStatement != null, $"{nameof(returnStatement)} is null");

            if (returnStatement == null)
            {
                return;
            }

            foreach (Diagnostic diagnostic in context.Diagnostics)
            {
                switch (diagnostic.Id)
                {
                case CompilerDiagnosticIdentifiers.CannotReturnValueFromIterator:
                {
                    if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.UseYieldReturnInsteadOfReturn))
                    {
                        break;
                    }

                    ExpressionSyntax expression = returnStatement.Expression;

                    if (expression != null)
                    {
                        SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                        ISymbol containingSymbol = semanticModel.GetEnclosingSymbol(returnStatement.SpanStart, context.CancellationToken);

                        if (containingSymbol?.IsKind(SymbolKind.Method) == true)
                        {
                            var methodSymbol = (IMethodSymbol)containingSymbol;

                            ITypeSymbol returnType = methodSymbol.ReturnType;

                            var replacementKind = SyntaxKind.None;

                            if (returnType.SpecialType == SpecialType.System_Collections_IEnumerable)
                            {
                                if (semanticModel
                                    .GetTypeSymbol(expression, context.CancellationToken)
                                    .IsIEnumerableOrConstructedFromIEnumerableOfT())
                                {
                                    replacementKind = SyntaxKind.ForEachStatement;
                                }
                                else
                                {
                                    replacementKind = SyntaxKind.YieldReturnStatement;
                                }
                            }
                            else if (returnType.IsNamedType())
                            {
                                var namedTypeSymbol = (INamedTypeSymbol)returnType;

                                if (namedTypeSymbol.IsConstructedFromIEnumerableOfT())
                                {
                                    if (semanticModel.IsImplicitConversion(expression, namedTypeSymbol.TypeArguments[0]))
                                    {
                                        replacementKind = SyntaxKind.YieldReturnStatement;
                                    }
                                    else
                                    {
                                        replacementKind = SyntaxKind.ForEachStatement;
                                    }
                                }
                            }

                            if (replacementKind == SyntaxKind.YieldReturnStatement ||
                                (replacementKind == SyntaxKind.ForEachStatement && !returnStatement.SpanContainsDirectives()))
                            {
                                CodeAction codeAction = CodeAction.Create(
                                    "Use yield return instead of return",
                                    cancellationToken => UseYieldReturnInsteadOfReturnRefactoring.RefactorAsync(context.Document, returnStatement, replacementKind, semanticModel, cancellationToken),
                                    GetEquivalenceKey(diagnostic));

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

                    break;
                }

                case CompilerDiagnosticIdentifiers.SinceMethodReturnsVoidReturnKeywordMustNotBeFollowedByObjectExpression:
                case CompilerDiagnosticIdentifiers.SinceMethodIsAsyncMethodThatReturnsTaskReturnKeywordMustNotBeFollowedByObjectExpression:
                {
                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveReturnExpression))
                    {
                        SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                        ISymbol symbol = semanticModel.GetEnclosingSymbol(returnStatement.SpanStart, context.CancellationToken);

                        if (symbol?.IsMethod() == true)
                        {
                            var methodSymbol = (IMethodSymbol)symbol;

                            if (methodSymbol.ReturnsVoid ||
                                methodSymbol.ReturnType.Equals(semanticModel.GetTypeByMetadataName(MetadataNames.System_Threading_Tasks_Task)))
                            {
                                CodeAction codeAction = CodeAction.Create(
                                    "Remove return expression",
                                    cancellationToken =>
                                    {
                                        ReturnStatementSyntax newNode = returnStatement
                                                                        .WithExpression(null)
                                                                        .WithFormatterAnnotation();

                                        return(context.Document.ReplaceNodeAsync(returnStatement, newNode, cancellationToken));
                                    },
                                    GetEquivalenceKey(diagnostic, CodeFixIdentifiers.RemoveReturnExpression));

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

                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveReturnKeyword))
                    {
                        ExpressionSyntax expression = returnStatement.Expression;

                        if (expression.IsKind(
                                SyntaxKind.InvocationExpression,
                                SyntaxKind.ObjectCreationExpression,
                                SyntaxKind.PreDecrementExpression,
                                SyntaxKind.PreIncrementExpression,
                                SyntaxKind.PostDecrementExpression,
                                SyntaxKind.PostIncrementExpression) ||
                            expression is AssignmentExpressionSyntax)
                        {
                            CodeAction codeAction = CodeAction.Create(
                                "Remove 'return'",
                                cancellationToken =>
                                {
                                    SyntaxTriviaList leadingTrivia = returnStatement
                                                                     .GetLeadingTrivia()
                                                                     .AddRange(returnStatement.ReturnKeyword.TrailingTrivia.EmptyIfWhitespace())
                                                                     .AddRange(expression.GetLeadingTrivia().EmptyIfWhitespace());

                                    ExpressionStatementSyntax newNode = SyntaxFactory.ExpressionStatement(
                                        expression.WithLeadingTrivia(leadingTrivia),
                                        returnStatement.SemicolonToken);

                                    return(context.Document.ReplaceNodeAsync(returnStatement, newNode, cancellationToken));
                                },
                                GetEquivalenceKey(diagnostic, CodeFixIdentifiers.RemoveReturnKeyword));

                            context.RegisterCodeFix(codeAction, diagnostic);
                        }
                    }

                    break;
                }
                }
            }
        }
Esempio n. 16
0
        public override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

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

            SyntaxKind kind       = token.Kind();
            Diagnostic diagnostic = context.Diagnostics[0];
            Document   document   = context.Document;

            switch (diagnostic.Id)
            {
            case CompilerDiagnosticIdentifiers.CS0023_OperatorCannotBeAppliedToOperand:
            {
                if (kind == SyntaxKind.QuestionToken &&
                    token.Parent is ConditionalAccessExpressionSyntax conditionalAccess)
                {
                    SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

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

                    if (typeSymbol?.IsErrorType() == false &&
                        !typeSymbol.IsNullableType())
                    {
                        if (typeSymbol.IsValueType)
                        {
                            if (IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveConditionalAccess, document, root.SyntaxTree))
                            {
                                CodeAction codeAction = CodeAction.Create(
                                    "Remove '?' operator",
                                    ct => document.WithTextChangeAsync(token.Span, "", ct),
                                    GetEquivalenceKey(diagnostic));

                                context.RegisterCodeFix(codeAction, diagnostic);
                            }
                        }
                        else if (typeSymbol.IsReferenceType)
                        {
                            if (IsEnabled(diagnostic.Id, CodeFixIdentifiers.AddArgumentList, document, root.SyntaxTree) &&
                                conditionalAccess.WhenNotNull is MemberBindingExpressionSyntax memberBindingExpression)
                            {
                                ConditionalAccessExpressionSyntax newNode = conditionalAccess.WithWhenNotNull(
                                    InvocationExpression(
                                        memberBindingExpression.WithoutTrailingTrivia(),
                                        ArgumentList().WithTrailingTrivia(memberBindingExpression.GetTrailingTrivia())));

                                CodeAction codeAction = CodeAction.Create(
                                    "Add argument list",
                                    ct => document.ReplaceNodeAsync(conditionalAccess, newNode, ct),
                                    GetEquivalenceKey(diagnostic));

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

                break;
            }

            case CompilerDiagnosticIdentifiers.CS0267_PartialModifierCanOnlyAppearImmediatelyBeforeClassStructInterfaceOrVoid:
            {
                if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.OrderModifiers, document, root.SyntaxTree))
                {
                    break;
                }

                ModifiersCodeFixRegistrator.MoveModifier(context, diagnostic, token.Parent, token);
                break;
            }

            case CompilerDiagnosticIdentifiers.CS1750_ValueCannotBeUsedAsDefaultParameter:
            {
                if (token.Parent is not ParameterSyntax parameter)
                {
                    break;
                }

                ExpressionSyntax value = parameter.Default?.Value;

                if (value == null)
                {
                    break;
                }

                if (value.IsKind(SyntaxKind.NullLiteralExpression))
                {
                    if (IsEnabled(diagnostic.Id, CodeFixIdentifiers.ReplaceNullLiteralExpressionWithDefaultValue, document, root.SyntaxTree))
                    {
                        SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                        CodeFixRegistrator.ReplaceNullWithDefaultValue(context, diagnostic, value, semanticModel);
                    }
                }
                else if (!value.IsKind(SyntaxKind.DefaultExpression, SyntaxKind.DefaultLiteralExpression))
                {
                    if (IsEnabled(diagnostic.Id, CodeFixIdentifiers.ChangeParameterType, document, root.SyntaxTree))
                    {
                        SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

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

                        if (!typeSymbol.IsKind(SymbolKind.ErrorType))
                        {
                            CodeFixRegistrator.ChangeType(context, diagnostic, parameter.Type, typeSymbol, semanticModel);
                        }
                    }
                }

                break;
            }

            case CompilerDiagnosticIdentifiers.CS0126_ObjectOfTypeConvertibleToTypeIsRequired:
            {
                if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.ReturnDefaultValue, document, root.SyntaxTree))
                {
                    break;
                }

                if (!token.IsKind(SyntaxKind.ReturnKeyword))
                {
                    break;
                }

                if (!token.IsParentKind(SyntaxKind.ReturnStatement))
                {
                    break;
                }

                SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                ISymbol symbol = semanticModel.GetEnclosingSymbol(token.SpanStart, context.CancellationToken);

                if (symbol == null)
                {
                    break;
                }

                SymbolKind symbolKind = symbol.Kind;

                ITypeSymbol typeSymbol = null;

                if (symbolKind == SymbolKind.Method)
                {
                    var methodSymbol = (IMethodSymbol)symbol;

                    typeSymbol = methodSymbol.ReturnType;

                    if (methodSymbol.IsAsync &&
                        (typeSymbol is INamedTypeSymbol namedTypeSymbol))
                    {
                        ImmutableArray <ITypeSymbol> typeArguments = namedTypeSymbol.TypeArguments;

                        if (typeArguments.Any())
                        {
                            typeSymbol = typeArguments[0];
                        }
                    }
                }
                else if (symbolKind == SymbolKind.Property)
                {
                    typeSymbol = ((IPropertySymbol)symbol).Type;
                }
                else
                {
                    Debug.Fail(symbolKind.ToString());
                }

                if (typeSymbol == null)
                {
                    break;
                }

                if (typeSymbol.Kind == SymbolKind.ErrorType)
                {
                    break;
                }

                if (!typeSymbol.SupportsExplicitDeclaration())
                {
                    break;
                }

                var returnStatement = (ReturnStatementSyntax)token.Parent;

                CodeAction codeAction = CodeAction.Create(
                    "Return default value",
                    ct =>
                    {
                        ExpressionSyntax expression = typeSymbol.GetDefaultValueSyntax(document.GetDefaultSyntaxOptions());

                        if (expression.IsKind(SyntaxKind.DefaultExpression) &&
                            document.SupportsLanguageFeature(CSharpLanguageFeature.DefaultLiteral))
                        {
                            expression = CSharpFactory.DefaultLiteralExpression().WithTriviaFrom(expression);
                        }

                        ReturnStatementSyntax newNode = returnStatement.WithExpression(expression);

                        return(document.ReplaceNodeAsync(returnStatement, newNode, ct));
                    },
                    GetEquivalenceKey(diagnostic));

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

            case CompilerDiagnosticIdentifiers.CS1031_TypeExpected:
            {
                if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.AddMissingType, document, root.SyntaxTree))
                {
                    break;
                }

                if (!token.IsKind(SyntaxKind.CloseParenToken))
                {
                    break;
                }

                if (token.Parent is not DefaultExpressionSyntax defaultExpression)
                {
                    break;
                }

                if (defaultExpression.Type is not IdentifierNameSyntax identifierName)
                {
                    break;
                }

                if (!identifierName.IsMissing)
                {
                    break;
                }

                SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                TypeInfo typeInfo = semanticModel.GetTypeInfo(defaultExpression, context.CancellationToken);

                ITypeSymbol convertedType = typeInfo.ConvertedType;

                if (convertedType?.SupportsExplicitDeclaration() != true)
                {
                    break;
                }

                CodeAction codeAction = CodeAction.Create(
                    $"Add type '{SymbolDisplay.ToMinimalDisplayString(convertedType, semanticModel, defaultExpression.SpanStart, SymbolDisplayFormats.DisplayName)}'",
                    ct =>
                    {
                        TypeSyntax newType = convertedType.ToTypeSyntax()
                                             .WithTriviaFrom(identifierName)
                                             .WithFormatterAndSimplifierAnnotation();

                        return(document.ReplaceNodeAsync(identifierName, newType, ct));
                    },
                    GetEquivalenceKey(diagnostic));

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

            case CompilerDiagnosticIdentifiers.CS1597_SemicolonAfterMethodOrAccessorBlockIsNotValid:
            {
                if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveSemicolon, document, root.SyntaxTree))
                {
                    break;
                }

                if (!token.IsKind(SyntaxKind.SemicolonToken))
                {
                    break;
                }

                switch (token.Parent)
                {
                case MethodDeclarationSyntax methodDeclaration:
                {
                    BlockSyntax body = methodDeclaration.Body;

                    if (body == null)
                    {
                        break;
                    }

                    CodeAction codeAction = CodeAction.Create(
                        "Remove semicolon",
                        ct =>
                            {
                                SyntaxTriviaList trivia = body
                                                          .GetTrailingTrivia()
                                                          .EmptyIfWhitespace()
                                                          .AddRange(token.LeadingTrivia.EmptyIfWhitespace())
                                                          .AddRange(token.TrailingTrivia);

                                MethodDeclarationSyntax newNode = methodDeclaration
                                                                  .WithBody(body.WithTrailingTrivia(trivia))
                                                                  .WithSemicolonToken(default(SyntaxToken));

                                return(document.ReplaceNodeAsync(methodDeclaration, newNode, ct));
                            },
                        GetEquivalenceKey(diagnostic));

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

                case PropertyDeclarationSyntax propertyDeclaration:
                {
                    AccessorListSyntax accessorList = propertyDeclaration.AccessorList;

                    if (accessorList == null)
                    {
                        break;
                    }

                    CodeAction codeAction = CodeAction.Create(
                        "Remove semicolon",
                        ct =>
                            {
                                SyntaxTriviaList trivia = accessorList
                                                          .GetTrailingTrivia()
                                                          .EmptyIfWhitespace()
                                                          .AddRange(token.LeadingTrivia.EmptyIfWhitespace())
                                                          .AddRange(token.TrailingTrivia);

                                PropertyDeclarationSyntax newNode = propertyDeclaration
                                                                    .WithAccessorList(accessorList.WithTrailingTrivia(trivia))
                                                                    .WithSemicolonToken(default(SyntaxToken));

                                return(document.ReplaceNodeAsync(propertyDeclaration, newNode, ct));
                            },
                        GetEquivalenceKey(diagnostic));

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

                case AccessorDeclarationSyntax accessorDeclaration:
                {
                    BlockSyntax body = accessorDeclaration.Body;

                    if (body == null)
                    {
                        break;
                    }

                    CodeAction codeAction = CodeAction.Create(
                        "Remove semicolon",
                        ct =>
                            {
                                SyntaxTriviaList trivia = body
                                                          .GetTrailingTrivia()
                                                          .EmptyIfWhitespace()
                                                          .AddRange(token.LeadingTrivia.EmptyIfWhitespace())
                                                          .AddRange(token.TrailingTrivia);

                                AccessorDeclarationSyntax newNode = accessorDeclaration
                                                                    .WithBody(body.WithTrailingTrivia(trivia))
                                                                    .WithSemicolonToken(default(SyntaxToken));

                                return(document.ReplaceNodeAsync(accessorDeclaration, newNode, ct));
                            },
                        GetEquivalenceKey(diagnostic));

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

                break;
            }

            case CompilerDiagnosticIdentifiers.CS0030_CannotConvertType:
            {
                if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.ChangeForEachType, document, root.SyntaxTree))
                {
                    break;
                }

                if (!token.IsKind(SyntaxKind.ForEachKeyword))
                {
                    break;
                }

                if (token.Parent is not ForEachStatementSyntax forEachStatement)
                {
                    break;
                }

                SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                ForEachStatementInfo info = semanticModel.GetForEachStatementInfo(forEachStatement);

                ITypeSymbol typeSymbol = info.ElementType;

                if (typeSymbol.SupportsExplicitDeclaration())
                {
                    CodeFixRegistrator.ChangeType(context, diagnostic, forEachStatement.Type, typeSymbol, semanticModel, CodeFixIdentifiers.ChangeForEachType);
                }

                CodeFixRegistrator.ChangeTypeToVar(context, diagnostic, forEachStatement.Type, CodeFixIdentifiers.ChangeTypeToVar);
                break;
            }

            case CompilerDiagnosticIdentifiers.CS1737_OptionalParametersMustAppearAfterAllRequiredParameters:
            {
                if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.AddDefaultValueToParameter, document, root.SyntaxTree))
                {
                    break;
                }

                if (token.Parent is not BaseParameterListSyntax parameterList)
                {
                    break;
                }

                SeparatedSyntaxList <ParameterSyntax> parameters = parameterList.Parameters;

                ParameterSyntax parameter = null;

                for (int i = 0; i < parameters.Count; i++)
                {
                    ParameterSyntax p = parameters[i];

                    if (p.FullSpan.End <= token.SpanStart)
                    {
                        parameter = p;
                    }
                    else
                    {
                        break;
                    }
                }

                SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                IParameterSymbol parameterSymbol = semanticModel.GetDeclaredSymbol(parameter, context.CancellationToken);

                ITypeSymbol typeSymbol = parameterSymbol.Type;

                if (typeSymbol.Kind == SymbolKind.ErrorType)
                {
                    break;
                }

                CodeAction codeAction = CodeAction.Create(
                    "Add default value",
                    ct =>
                    {
                        ExpressionSyntax defaultValue = typeSymbol.GetDefaultValueSyntax(document.GetDefaultSyntaxOptions());

                        ParameterSyntax newParameter = parameter
                                                       .WithDefault(EqualsValueClause(defaultValue).WithTrailingTrivia(parameter.GetTrailingTrivia()))
                                                       .WithoutTrailingTrivia()
                                                       .WithFormatterAnnotation();

                        return(document.ReplaceNodeAsync(parameter, newParameter, ct));
                    },
                    GetEquivalenceKey(diagnostic));

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

            case CompilerDiagnosticIdentifiers.CS8632_AnnotationForNullableReferenceTypesShouldOnlyBeUsedWithinNullableAnnotationsContext:
            {
                if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveAnnotationForNullableReferenceTypes, document, root.SyntaxTree))
                {
                    break;
                }

                if (!token.IsKind(SyntaxKind.QuestionToken))
                {
                    return;
                }

                CodeAction codeAction = CodeAction.Create(
                    "Remove 'nullable' annotation",
                    ct =>
                    {
                        var textChange = new TextChange(token.Span, "");

                        return(document.WithTextChangeAsync(textChange, ct));
                    },
                    GetEquivalenceKey(diagnostic));

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

            case CompilerDiagnosticIdentifiers.CS8602_DereferenceOfPossiblyNullReference:
            {
                if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.UseNullForgivingOperator, document, root.SyntaxTree))
                {
                    break;
                }

                Debug.Assert(token.IsKind(SyntaxKind.IdentifierToken), token.Kind().ToString());

                if (!token.IsKind(SyntaxKind.IdentifierToken))
                {
                    return;
                }

                if (!token.IsParentKind(SyntaxKind.IdentifierName))
                {
                    return;
                }

                SyntaxNode node = token.Parent
                                  .WalkUp(f => f.IsKind(SyntaxKind.SimpleMemberAccessExpression, SyntaxKind.InvocationExpression, SyntaxKind.ElementAccessExpression))
                                  .Parent;

                if (node.IsKind(SyntaxKind.ExpressionStatement) &&
                    token.SpanStart == node.SpanStart)
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Use null propagation operator",
                        ct =>
                        {
                            var textChange = new TextChange(new TextSpan(token.Span.End, 0), "?");

                            return(document.WithTextChangeAsync(textChange, ct));
                        },
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                }

                return;
            }

            case CompilerDiagnosticIdentifiers.CS8604_PossibleNullReferenceArgumentForParameter:
            {
                if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.UseNullForgivingOperator, document, root.SyntaxTree))
                {
                    break;
                }

                Debug.Assert(token.IsKind(SyntaxKind.IdentifierToken), token.Kind().ToString());

                if (!token.IsKind(SyntaxKind.IdentifierToken))
                {
                    return;
                }

                if (!token.IsParentKind(SyntaxKind.IdentifierName))
                {
                    return;
                }

                CodeAction codeAction = CodeAction.Create(
                    "Use null-forgiving operator",
                    ct =>
                    {
                        var identifierName = (IdentifierNameSyntax)token.Parent;

                        PostfixUnaryExpressionSyntax newExpression = SuppressNullableWarningExpression(identifierName.WithoutTrivia())
                                                                     .WithTriviaFrom(identifierName);

                        return(document.ReplaceNodeAsync(identifierName, newExpression, ct));
                    },
                    GetEquivalenceKey(diagnostic));

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

            case CompilerDiagnosticIdentifiers.CS8618_NonNullableMemberIsUninitialized:
            {
                if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.UseNullForgivingOperator, document, root.SyntaxTree))
                {
                    break;
                }

                Debug.Assert(token.IsKind(SyntaxKind.IdentifierToken), token.Kind().ToString());

                if (!token.IsKind(SyntaxKind.IdentifierToken))
                {
                    return;
                }

                if (token.IsParentKind(SyntaxKind.PropertyDeclaration))
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Use null-forgiving operator",
                        ct =>
                        {
                            var property = (PropertyDeclarationSyntax)token.Parent;

                            PropertyDeclarationSyntax newProperty = property
                                                                    .WithoutTrailingTrivia()
                                                                    .WithInitializer(EqualsValueClause(SuppressNullableWarningExpression(NullLiteralExpression())))
                                                                    .WithSemicolonToken(SemicolonToken().WithTrailingTrivia(property.GetTrailingTrivia()));

                            return(document.ReplaceNodeAsync(property, newProperty, ct));
                        },
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                }
                else
                {
                    SyntaxDebug.Assert(
                        (token.IsParentKind(SyntaxKind.VariableDeclarator) &&
                         token.Parent.IsParentKind(SyntaxKind.VariableDeclaration) &&
                         token.Parent.Parent.IsParentKind(SyntaxKind.FieldDeclaration, SyntaxKind.EventFieldDeclaration)) ||
                        token.IsParentKind(SyntaxKind.ConstructorDeclaration),
                        token);

                    if (token.IsParentKind(SyntaxKind.VariableDeclarator) &&
                        token.Parent.IsParentKind(SyntaxKind.VariableDeclaration) &&
                        token.Parent.Parent.IsParentKind(SyntaxKind.FieldDeclaration))
                    {
                        CodeAction codeAction = CodeAction.Create(
                            "Use null-forgiving operator",
                            ct =>
                            {
                                var declarator = (VariableDeclaratorSyntax)token.Parent;

                                VariableDeclaratorSyntax newDeclarator = declarator
                                                                         .WithoutTrailingTrivia()
                                                                         .WithInitializer(
                                    EqualsValueClause(SuppressNullableWarningExpression(NullLiteralExpression()))
                                    .WithTrailingTrivia(declarator.GetTrailingTrivia()));

                                return(document.ReplaceNodeAsync(declarator, newDeclarator, ct));
                            },
                            GetEquivalenceKey(diagnostic));

                        context.RegisterCodeFix(codeAction, diagnostic);
                    }
                }

                break;
            }

            case CompilerDiagnosticIdentifiers.CS8403_MethodWithIteratorBlockMustBeAsyncToReturnIAsyncEnumerableOfT:
            {
                if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.AddAsyncModifier, document, root.SyntaxTree))
                {
                    break;
                }

                SyntaxDebug.Assert(token.IsKind(SyntaxKind.IdentifierToken), token);
                SyntaxDebug.Assert(token.IsParentKind(SyntaxKind.MethodDeclaration, SyntaxKind.LocalFunctionStatement), token.Parent);

                if (token.IsParentKind(SyntaxKind.MethodDeclaration, SyntaxKind.LocalFunctionStatement))
                {
                    ModifiersCodeFixRegistrator.AddModifier(
                        context,
                        diagnostic,
                        token.Parent,
                        SyntaxKind.AsyncKeyword,
                        additionalKey: CodeFixIdentifiers.AddAsyncModifier);
                }

                break;
            }
            }
        }
Esempio n. 17
0
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            if (!TryFindFirstAncestorOrSelf(root, context.Span, out StatementSyntax statement))
            {
                return;
            }

            foreach (Diagnostic diagnostic in context.Diagnostics)
            {
                switch (diagnostic.Id)
                {
                case CompilerDiagnosticIdentifiers.EmptySwitchBlock:
                {
                    if (!Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveEmptySwitchStatement))
                    {
                        break;
                    }

                    if (!(statement is SwitchStatementSyntax switchStatement))
                    {
                        break;
                    }

                    CodeFixRegistrator.RemoveStatement(context, diagnostic, switchStatement);
                    break;
                }

                case CompilerDiagnosticIdentifiers.NoEnclosingLoopOutOfWhichToBreakOrContinue:
                {
                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveJumpStatement))
                    {
                        CodeFixRegistrator.RemoveStatement(context, diagnostic, statement);
                    }

                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.ReplaceBreakWithContinue) &&
                        statement.Kind() == SyntaxKind.BreakStatement)
                    {
                        SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                        if (semanticModel.GetEnclosingSymbol(statement.SpanStart, context.CancellationToken) is IMethodSymbol methodSymbol)
                        {
                            if (methodSymbol.ReturnsVoid ||
                                (methodSymbol.IsAsync && methodSymbol.ReturnType.HasMetadataName(MetadataNames.System_Threading_Tasks_Task)))
                            {
                                CodeAction codeAction = CodeAction.Create(
                                    "Replace 'break' with 'return'",
                                    cancellationToken =>
                                    {
                                        var breakStatement       = (BreakStatementSyntax)statement;
                                        SyntaxToken breakKeyword = breakStatement.BreakKeyword;

                                        ReturnStatementSyntax newStatement = SyntaxFactory.ReturnStatement(
                                            SyntaxFactory.Token(breakKeyword.LeadingTrivia, SyntaxKind.ReturnKeyword, breakKeyword.TrailingTrivia),
                                            null,
                                            breakStatement.SemicolonToken);

                                        return(context.Document.ReplaceNodeAsync(statement, newStatement, cancellationToken));
                                    },
                                    GetEquivalenceKey(diagnostic, CodeFixIdentifiers.ReplaceBreakWithContinue));

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

                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveJumpStatement))
                    {
                        CodeFixRegistrator.RemoveStatement(context, diagnostic, statement);
                    }

                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.ReplaceBreakWithContinue) &&
                        statement.Kind() == SyntaxKind.BreakStatement)
                    {
                        SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                        if (semanticModel.GetEnclosingSymbol(statement.SpanStart, context.CancellationToken) is IMethodSymbol methodSymbol)
                        {
                            if (methodSymbol.ReturnsVoid ||
                                (methodSymbol.IsAsync && methodSymbol.ReturnType.HasMetadataName(MetadataNames.System_Threading_Tasks_Task)))
                            {
                                CodeAction codeAction = CodeAction.Create(
                                    "Replace 'break' with 'return'",
                                    cancellationToken =>
                                    {
                                        var breakStatement       = (BreakStatementSyntax)statement;
                                        SyntaxToken breakKeyword = breakStatement.BreakKeyword;

                                        ReturnStatementSyntax newStatement = SyntaxFactory.ReturnStatement(
                                            SyntaxFactory.Token(breakKeyword.LeadingTrivia, SyntaxKind.ReturnKeyword, breakKeyword.TrailingTrivia),
                                            null,
                                            breakStatement.SemicolonToken);

                                        return(context.Document.ReplaceNodeAsync(statement, newStatement, cancellationToken));
                                    },
                                    GetEquivalenceKey(diagnostic, CodeFixIdentifiers.ReplaceBreakWithContinue));

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

                    break;
                }
                }
            }
        }
 public static INamedTypeSymbol GetEnclosingNamedType(this SemanticModel semanticModel, int position, CancellationToken cancellationToken)
 {
     return(semanticModel.GetEnclosingSymbol <INamedTypeSymbol>(position, cancellationToken));
 }
        public static IMethodSymbol TryGetContainingMethod([NotNull] this IOperation operation, [NotNull] Compilation compilation)
        {
            SemanticModel model = compilation.GetSemanticModel(operation.Syntax.SyntaxTree);

            return(model.GetEnclosingSymbol(operation.Syntax.GetLocation().SourceSpan.Start) as IMethodSymbol);
        }
Esempio n. 20
0
        void AddDelegateHandlers(List <CompletionData> completionList, SyntaxNode parent, SemanticModel semanticModel, CompletionEngine engine, CompletionResult result, ITypeSymbol delegateType, int position, string optDelegateName, CancellationToken cancellationToken)
        {
            var delegateMethod = delegateType.GetDelegateInvokeMethod();

            result.PossibleDelegates.Add(delegateMethod);

            var    thisLineIndent = "";
            string EolMarker      = "\n";
            bool   addSemicolon   = true;
            bool   addDefault     = true;

            string delegateEndString = EolMarker + thisLineIndent + "}" + (addSemicolon ? ";" : "");
            //bool containsDelegateData = completionList.Result.Any(d => d.DisplayText.StartsWith("delegate("));
            CompletionData item;

            if (addDefault)
            {
                item = engine.Factory.CreateAnonymousMethod(
                    this,
                    "delegate",
                    "Creates anonymous delegate.",
                    "delegate {" + EolMarker + thisLineIndent,
                    delegateEndString
                    );
                if (!completionList.Any(i => i.DisplayText == item.DisplayText))
                {
                    completionList.Add(item);
                }

                //if (LanguageVersion.Major >= 5)

                item = engine.Factory.CreateAnonymousMethod(
                    this,
                    "async delegate",
                    "Creates anonymous async delegate.",
                    "async delegate {" + EolMarker + thisLineIndent,
                    delegateEndString
                    );
                if (!completionList.Any(i => i.DisplayText == item.DisplayText))
                {
                    completionList.Add(item);
                }
            }

            var sb             = new StringBuilder("(");
            var sbWithoutTypes = new StringBuilder("(");

            for (int k = 0; k < delegateMethod.Parameters.Length; k++)
            {
                if (k > 0)
                {
                    sb.Append(", ");
                    sbWithoutTypes.Append(", ");
                }
                sb.Append(RoslynCompletionData.SafeMinimalDisplayString(delegateMethod.Parameters [k], semanticModel, position, overrideNameFormat));
                sbWithoutTypes.Append(delegateMethod.Parameters [k].Name);
            }

            sb.Append(")");
            sbWithoutTypes.Append(")");
            var signature = sb.ToString()
                            .Replace(", params ", ", ")
                            .Replace("(params ", "(");

            if (completionList.All(data => data.DisplayText != signature))
            {
                item = engine.Factory.CreateAnonymousMethod(
                    this,
                    signature + " =>",
                    "Creates typed lambda expression.",
                    signature + " => ",
                    (addSemicolon ? ";" : "")
                    );
                if (!completionList.Any(i => i.DisplayText == item.DisplayText))
                {
                    completionList.Add(item);
                }

                // if (LanguageVersion.Major >= 5) {

                item = engine.Factory.CreateAnonymousMethod(
                    this,
                    "async " + signature + " =>",
                    "Creates typed async lambda expression.",
                    "async " + signature + " => ",
                    (addSemicolon ? ";" : "")
                    );
                if (!completionList.Any(i => i.DisplayText == item.DisplayText))
                {
                    completionList.Add(item);
                }

                var signatureWithoutTypes = sbWithoutTypes.ToString();
                if (!delegateMethod.Parameters.Any(p => p.RefKind != RefKind.None) && completionList.All(data => data.DisplayText != signatureWithoutTypes))
                {
                    item = engine.Factory.CreateAnonymousMethod(
                        this,
                        signatureWithoutTypes + " =>",
                        "Creates typed lambda expression.",
                        signatureWithoutTypes + " => ",
                        (addSemicolon ? ";" : "")
                        );
                    if (!completionList.Any(i => i.DisplayText == item.DisplayText))
                    {
                        completionList.Add(item);
                    }

                    //if (LanguageVersion.Major >= 5) {
                    item = engine.Factory.CreateAnonymousMethod(
                        this,
                        "async " + signatureWithoutTypes + " =>",
                        "Creates typed async lambda expression.",
                        "async " + signatureWithoutTypes + " => ",
                        (addSemicolon ? ";" : "")
                        );
                    if (!completionList.Any(i => i.DisplayText == item.DisplayText))
                    {
                        completionList.Add(item);
                    }

                    //}
                }
            }
            string varName = optDelegateName ?? "Handle" + delegateType.Name;


            var curType    = semanticModel.GetEnclosingSymbol <INamedTypeSymbol> (position, cancellationToken);
            var uniqueName = new UniqueNameGenerator(semanticModel).CreateUniqueMethodName(parent, varName);

            item = engine.Factory.CreateNewMethodDelegate(this, delegateType, uniqueName, curType);
            if (!completionList.Any(i => i.DisplayText == item.DisplayText))
            {
                completionList.Add(item);
            }
        }
Esempio n. 21
0
        public override SyntaxNode VisitInvocationExpression(InvocationExpressionSyntax node)
        {
            IInvocationExpression invocation = semanticModel.GetOperation(node, cancellationToken) as IInvocationExpression;

            if (invocation == null)
            {
                return(base.VisitInvocationExpression(node));
            }

            bool IsMacroMethod(ISymbol methodSymbol, out string error)
            {
                foreach (var attr in methodSymbol.GetAttributes())
                {
                    if (attr.AttributeClass.MetadataName != nameof(ExpandAttribute))
                    {
                        continue;
                    }

                    if (!methodSymbol.IsStatic)
                    {
                        error = "The target method must be static.";
                    }
                    else
                    {
                        error = null;
                    }

                    return(true);
                }

                error = null;
                return(false);
            }

            // Check if it's a call to a macro method
            var target = invocation.TargetMethod;

            if (!IsMacroMethod(target, out string err))
            {
                return(base.VisitInvocationExpression(node));
            }

            // Make sure it's valid
            if (err != null)
            {
                throw new DiagnosticException($"Cannot call the specified method as a macro method: {err}.",
                                              invocation.Syntax.GetLocation());
            }

            // It is a method, find it
            MethodInfo method = target.GetCorrespondingMethod() as MethodInfo;

            if (method == null)
            {
                throw new DiagnosticException("Cannot find corresponding method.", invocation.Syntax.GetLocation());
            }

            // Found it, make the arguments
            ParameterInfo[] parameters = method.GetParameters();
            object[]        arguments  = new object[parameters.Length];

            for (int i = 0; i < arguments.Length; i++)
            {
                ParameterInfo param     = parameters[i];
                Type          paramType = param.ParameterType;

                if (param.HasDefaultValue)
                {
                    arguments[i] = param.DefaultValue;
                }
                else
                {
                    arguments[i] = paramType.GetTypeInfo().IsValueType
                        ? Activator.CreateInstance(paramType)
                        : null;
                }
            }

            // Set up the context
            var statementSyntax = node.FirstAncestorOrSelf <StatementSyntax>();
            var statementSymbol = new Lazy <IOperation>(() => semanticModel.GetOperation(statementSyntax, cancellationToken));

            var callerSymbol = new Lazy <IMethodSymbol>(() => semanticModel.GetEnclosingSymbol(statementSyntax.SpanStart, cancellationToken) as IMethodSymbol);
            var callerInfo   = new Lazy <MethodInfo>(() => callerSymbol.Value?.GetCorrespondingMethod() as MethodInfo);

            ExpressionSyntax expr;
            StatementSyntax  stmt;

            using (CallBinder.EnterContext(invocation, statementSymbol, node, statementSyntax, method, target, callerInfo, callerSymbol))
            {
                // Invoke the method
                try
                {
                    method.Invoke(null, arguments);
                }
                catch (Exception e)
                {
                    throw new DiagnosticException($"Exception thrown when expanding the '{method}' macro.", e, invocation.Syntax.GetLocation());
                }

                (expr, stmt) = CallBinder.Result;
            }

            // Edit the node accordingly
            if (stmt != statementSyntax)
            {
                // Return the new statement
                changes.Add(statementSyntax, stmt.WithTriviaFrom(statementSyntax).Accept(this) as StatementSyntax);
                return(node);
            }

            return(base.Visit(expr == node ? expr : expr.WithTriviaFrom(node)));
        }
Esempio n. 22
0
        private static ImmutableArray <string> GetMemberReturnTypeArgumentList(SemanticModel semanticModel, AnonymousMethodExpressionSyntax anonymousMethod)
        {
            var enclosingSymbol = semanticModel.GetEnclosingSymbol(anonymousMethod.Parent.SpanStart);

            return(!(((IMethodSymbol)enclosingSymbol).ReturnType is INamedTypeSymbol returnType) ? ImmutableArray <string> .Empty : returnType.DelegateInvokeMethod.Parameters.Select(ps => ps.Name).ToImmutableArray());
        }
Esempio n. 23
0
 private static bool IsUserDefinedOperator(TBinaryExpression expression, SemanticModel semanticModel) =>
 semanticModel.GetEnclosingSymbol(expression.SpanStart) is IMethodSymbol enclosingSymbol &&
        private IMethodSymbol TryGetContainingMethod([NotNull] IInvocationExpression invocation, OperationAnalysisContext context)
        {
            SemanticModel model = context.Compilation.GetSemanticModel(invocation.Syntax.SyntaxTree);

            return(model.GetEnclosingSymbol(invocation.Syntax.GetLocation().SourceSpan.Start) as IMethodSymbol);
        }
Esempio n. 25
0
        // Note: The caller needs to verify that replacement doesn't change semantics of the original expression.
        private static bool TrySimplifyMemberAccessOrQualifiedName(
            ExpressionSyntax left,
            ExpressionSyntax right,
            SemanticModel semanticModel,
            out ExpressionSyntax replacementNode,
            out TextSpan issueSpan)
        {
            replacementNode = null;
            issueSpan       = default;

            if (left != null && right != null)
            {
                var leftSymbol = SimplificationHelpers.GetOriginalSymbolInfo(semanticModel, left);
                if (leftSymbol != null && leftSymbol.Kind == SymbolKind.NamedType)
                {
                    var rightSymbol = SimplificationHelpers.GetOriginalSymbolInfo(semanticModel, right);
                    if (rightSymbol != null && (rightSymbol.IsStatic || rightSymbol.Kind == SymbolKind.NamedType))
                    {
                        // Static member access or nested type member access.
                        var containingType = rightSymbol.ContainingType;

                        var enclosingSymbol = semanticModel.GetEnclosingSymbol(left.SpanStart);
                        var enclosingTypeParametersInsideOut = new List <ISymbol>();

                        while (enclosingSymbol != null)
                        {
                            if (enclosingSymbol is IMethodSymbol methodSymbol)
                            {
                                if (methodSymbol.TypeArguments.Length != 0)
                                {
                                    enclosingTypeParametersInsideOut.AddRange(methodSymbol.TypeArguments);
                                }
                            }

                            if (enclosingSymbol is INamedTypeSymbol namedTypeSymbol)
                            {
                                if (namedTypeSymbol.TypeArguments.Length != 0)
                                {
                                    enclosingTypeParametersInsideOut.AddRange(namedTypeSymbol.TypeArguments);
                                }
                            }

                            enclosingSymbol = enclosingSymbol.ContainingSymbol;
                        }

                        if (containingType != null && !containingType.Equals(leftSymbol))
                        {
                            if (leftSymbol is INamedTypeSymbol namedType &&
                                containingType.TypeArguments.Length != 0)
                            {
                                return(false);
                            }

                            // We have a static member access or a nested type member access using a more derived type.
                            // Simplify syntax so as to use accessed member's most immediate containing type instead of the derived type.
                            replacementNode = containingType.GenerateTypeSyntax()
                                              .WithLeadingTrivia(left.GetLeadingTrivia())
                                              .WithTrailingTrivia(left.GetTrailingTrivia());
                            issueSpan = left.Span;
                            return(true);
                        }
                    }
                }
            }

            return(false);
        }
        // Note: The caller needs to verify that replacement doesn't change semantics of the original expression.
        private static bool TrySimplifyMemberAccessOrQualifiedName(
        ExpressionSyntax left,
            ExpressionSyntax right,
            SemanticModel semanticModel,
            OptionSet optionSet,
            out ExpressionSyntax replacementNode,
            out TextSpan issueSpan)
        {
            replacementNode = null;
            issueSpan = default(TextSpan);

            if (left != null && right != null)
            {
                var leftSymbol = SimplificationHelpers.GetOriginalSymbolInfo(semanticModel, left);
                if (leftSymbol != null && (leftSymbol.Kind == SymbolKind.NamedType))
                {
                    var rightSymbol = SimplificationHelpers.GetOriginalSymbolInfo(semanticModel, right);
                    if (rightSymbol != null && (rightSymbol.IsStatic || rightSymbol.Kind == SymbolKind.NamedType))
                    {
                        // Static member access or nested type member access.
                        INamedTypeSymbol containingType = rightSymbol.ContainingType;

                        var enclosingSymbol = semanticModel.GetEnclosingSymbol(left.SpanStart);
                        List<ISymbol> enclosingTypeParametersInsideOut = new List<ISymbol>();

                        while (enclosingSymbol != null)
                        {
                            if (enclosingSymbol is IMethodSymbol)
                            {
                                var methodSymbol = (IMethodSymbol)enclosingSymbol;
                                if (methodSymbol.TypeArguments.Length != 0)
                                {
                                    enclosingTypeParametersInsideOut.AddRange(methodSymbol.TypeArguments);
                                }
                            }

                            if (enclosingSymbol is INamedTypeSymbol)
                            {
                                var namedTypeSymbol = (INamedTypeSymbol)enclosingSymbol;
                                if (namedTypeSymbol.TypeArguments.Length != 0)
                                {
                                    enclosingTypeParametersInsideOut.AddRange(namedTypeSymbol.TypeArguments);
                                }
                            }

                            enclosingSymbol = enclosingSymbol.ContainingSymbol;
                        }

                        if (containingType != null && !containingType.Equals(leftSymbol))
                        {
                            var namedType = leftSymbol as INamedTypeSymbol;
                            if (namedType != null)
                            {
                                if ((namedType.GetBaseTypes().Contains(containingType) &&
                                    !optionSet.GetOption(SimplificationOptions.AllowSimplificationToBaseType)) ||
                                    (!optionSet.GetOption(SimplificationOptions.AllowSimplificationToGenericType) &&
                                    containingType.TypeArguments.Length != 0))
                                {
                                    return false;
                                }
                            }

                            // We have a static member access or a nested type member access using a more derived type.
                            // Simplify syntax so as to use accessed member's most immediate containing type instead of the derived type.
                            replacementNode = containingType.GenerateTypeSyntax()
                                .WithLeadingTrivia(left.GetLeadingTrivia())
                                .WithTrailingTrivia(left.GetTrailingTrivia());
                            issueSpan = left.Span;
                            return true;
                        }
                    }
                }
            }

            return false;
        }
Esempio n. 27
0
        private static void ComputeChangeTypeAndAddAwait(
            CodeFixContext context,
            Diagnostic diagnostic,
            VariableDeclarationSyntax variableDeclaration,
            TypeSyntax type,
            ExpressionSyntax expression,
            ITypeSymbol typeSymbol,
            SemanticModel semanticModel)
        {
            if (!typeSymbol.OriginalDefinition.EqualsOrInheritsFromTaskOfT(semanticModel))
            {
                return;
            }

            if (!(semanticModel.GetEnclosingSymbol(variableDeclaration.SpanStart, context.CancellationToken) is IMethodSymbol methodSymbol))
            {
                return;
            }

            if (!methodSymbol.MethodKind.Is(MethodKind.Ordinary, MethodKind.LocalFunction))
            {
                return;
            }

            SyntaxNode node = GetSyntax();

            if (node == null)
            {
                return;
            }

            SyntaxNode bodyOrExpressionBody = GetBodyOrExpressionBody();

            if (bodyOrExpressionBody == null)
            {
                return;
            }

            foreach (SyntaxNode descendant in bodyOrExpressionBody.DescendantNodes())
            {
                if (descendant.IsKind(SyntaxKind.ReturnStatement))
                {
                    var returnStatement = (ReturnStatementSyntax)descendant;

                    if (returnStatement
                        .Expression?
                        .WalkDownParentheses()
                        .IsKind(SyntaxKind.AwaitExpression) == false)
                    {
                        return;
                    }
                }
            }

            ITypeSymbol typeArgument = ((INamedTypeSymbol)typeSymbol).TypeArguments[0];

            CodeAction codeAction = CodeAction.Create(
                $"Change type to '{SymbolDisplay.ToMinimalDisplayString(typeArgument, semanticModel, type.SpanStart, SymbolDisplayFormats.Default)}' and add await",
                cancellationToken => ChangeTypeAndAddAwait(context.Document, node, variableDeclaration, type, expression, typeArgument, semanticModel, cancellationToken),
                EquivalenceKey.Create(diagnostic, CodeFixIdentifiers.ChangeTypeAccordingToInitializer, "AddAwait"));

            context.RegisterCodeFix(codeAction, diagnostic);

            SyntaxNode GetSyntax()
            {
                foreach (SyntaxReference syntaxReference in methodSymbol.DeclaringSyntaxReferences)
                {
                    SyntaxNode syntax = syntaxReference.GetSyntax(context.CancellationToken);

                    if (syntax.Contains(variableDeclaration))
                    {
                        return(syntax);
                    }
                }

                return(null);
            }

            SyntaxNode GetBodyOrExpressionBody()
            {
                switch (node.Kind())
                {
                case SyntaxKind.MethodDeclaration:
                    return(((MethodDeclarationSyntax)node).BodyOrExpressionBody());

                case SyntaxKind.LocalFunctionStatement:
                    return(((LocalFunctionStatementSyntax)node).BodyOrExpressionBody());
                }

                Debug.Fail(node.Kind().ToString());

                return(null);
            }
        }