public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
    {
        var(document, _, cancellationToken) = context;

        // First, see if we're inside a conditional.  If so, attempt to use that to offer fixes on.
        var conditionalExpression = await context.TryGetRelevantNodeAsync <TConditionalExpressionSyntax>().ConfigureAwait(false);

        if (conditionalExpression is not null)
        {
            TryHandleConditionalExpression(context, conditionalExpression);
            return;
        }

        // If not, see if we're on an supported statement.  If so, see if it has an applicable conditional within it
        // that we could support this on.
        var syntaxFacts = document.GetRequiredLanguageService <ISyntaxFactsService>();
        var statement   = await context.TryGetRelevantNodeAsync <TStatementSyntax>().ConfigureAwait(false);

        if (IsSupportedSimpleStatement(syntaxFacts, statement))
        {
            TryHandleConditionalExpression(context, TryFindConditional(statement, cancellationToken));
            return;
        }

        if (statement is TLocalDeclarationStatementSyntax localDeclarationStatement)
        {
            var variables = syntaxFacts.GetVariablesOfLocalDeclarationStatement(localDeclarationStatement);
            if (variables.Count == 1)
            {
                TryHandleConditionalExpression(
                    context, TryFindConditional(syntaxFacts.GetInitializerOfVariableDeclarator(variables[0]), cancellationToken));
                return;
            }
        }
    }
 protected override async Task <SyntaxNode> GetSelectedNodeAsync(CodeRefactoringContext context)
 {
     // Consider:
     // MemberDeclaration: member that can be declared in type (those are the ones we can pull up)
     // VariableDeclaratorSyntax: for fields the MemberDeclaration can actually represent multiple declarations, e.g. `int a = 0, b = 1;`.
     // ..Since the user might want to select & pull up only one of them (e.g. `int a = 0, [|b = 1|];` we also look for closest VariableDeclaratorSyntax.
     return(await context.TryGetRelevantNodeAsync <MemberDeclarationSyntax>().ConfigureAwait(false) as SyntaxNode ??
            await context.TryGetRelevantNodeAsync <VariableDeclaratorSyntax>().ConfigureAwait(false));
 }
        private static async Task <SyntaxNode> GetDeclarationAsync(CodeRefactoringContext context)
        {
            // We want to provide refactoring for changing the Type of newly introduced variables in following cases:
            // - DeclarationExpressionSyntax: `"42".TryParseInt32(out var number)`
            // - VariableDeclarationSyntax: General field / variable declaration statement `var number = 42`
            // - ForEachStatementSyntax: The variable that gets introduced by foreach `foreach(var number in numbers)`
            //
            // In addition to providing the refactoring when the whole node (i.e. the node that introduces the new variable) in question is selected
            // we also want to enable it when only the type node is selected because this refactoring changes the type. We still have to make sure
            // we're only working on TypeNodes for in above-mentioned situations.
            //
            // For foreach we need to guard against selecting just the expression because it is also of type `TypeSyntax`.

            var declNode = await context.TryGetRelevantNodeAsync <DeclarationExpressionSyntax>().ConfigureAwait(false);

            if (declNode != null)
            {
                return(declNode);
            }

            var variableNode = await context.TryGetRelevantNodeAsync <VariableDeclarationSyntax>().ConfigureAwait(false);

            if (variableNode != null)
            {
                return(variableNode);
            }

            var foreachStatement = await context.TryGetRelevantNodeAsync <ForEachStatementSyntax>().ConfigureAwait(false);

            if (foreachStatement != null)
            {
                return(foreachStatement);
            }

            var syntaxFacts = context.Document.GetLanguageService <ISyntaxFactsService>();

            var typeNode = await context.TryGetRelevantNodeAsync <TypeSyntax>().ConfigureAwait(false);

            var typeNodeParent = typeNode?.Parent;

            if (typeNodeParent != null &&
                (typeNodeParent.IsKind(SyntaxKind.DeclarationExpression, SyntaxKind.VariableDeclaration) ||
                 (typeNodeParent.IsKind(SyntaxKind.ForEachStatement) && !syntaxFacts.IsExpressionOfForeach(typeNode))))
            {
                return(typeNodeParent);
            }

            return(null);
        }
예제 #4
0
        public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            var(document, textSpan, cancellationToken) = context;
            if (document.Project.Solution.Workspace.Kind == WorkspaceKind.MiscellaneousFiles)
            {
                return;
            }

            var localFunction = await context.TryGetRelevantNodeAsync <LocalFunctionStatementSyntax>().ConfigureAwait(false);

            if (localFunction == null)
            {
                return;
            }

            if (!localFunction.Parent.IsKind(SyntaxKind.Block, out BlockSyntax parentBlock))
            {
                return;
            }

            var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            context.RegisterRefactoring(
                new MyCodeAction(
                    CSharpFeaturesResources.Convert_to_method,
                    c => UpdateDocumentAsync(root, document, parentBlock, localFunction, c)),
                localFunction.Span);
        }
        public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            var(document, _, cancellationToken) = context;

            var ifNode = await context.TryGetRelevantNodeAsync <TIfStatementSyntax>().ConfigureAwait(false);

            if (ifNode == null)
            {
                return;
            }

            if (!CanInvert(ifNode))
            {
                return;
            }

            var title = GetTitle();

            context.RegisterRefactoring(
                CodeAction.Create(
                    title,
                    c => InvertIfAsync(document, ifNode, c),
                    title),
                ifNode.Span);
        }
예제 #6
0
        public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            var(document, textSpan, cancellationToken) = context;

            var syntaxTree = (await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false)) !;

            if (!MakeLocalFunctionStaticHelper.IsStaticLocalFunctionSupported(((CSharpParseOptions)syntaxTree.Options).LanguageVersion))
            {
                return;
            }

            var localFunction = await context.TryGetRelevantNodeAsync <LocalFunctionStatementSyntax>().ConfigureAwait(false);

            if (localFunction == null)
            {
                return;
            }

            if (localFunction.Modifiers.Any(SyntaxKind.StaticKeyword))
            {
                return;
            }

            var semanticModel = (await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false)) !;

            if (MakeLocalFunctionStaticHelper.CanMakeLocalFunctionStaticByRefactoringCaptures(localFunction, semanticModel, out var captures))
            {
                context.RegisterRefactoring(new MyCodeAction(
                                                c => MakeLocalFunctionStaticCodeFixHelper.MakeLocalFunctionStaticAsync(document, localFunction, captures, c)));
            }
        }
        public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            var(document, span, cancellationToken) = context;

            var expression = await context.TryGetRelevantNodeAsync <TBinaryExpressionSyntax>().ConfigureAwait(false) as SyntaxNode;

            var syntaxFacts = document.GetLanguageService <ISyntaxFactsService>();

            if (expression == null ||
                (!syntaxFacts.IsLogicalAndExpression(expression) &&
                 !syntaxFacts.IsLogicalOrExpression(expression)))
            {
                return;
            }

            if (span.IsEmpty)
            {
                // Walk up to the topmost binary of the same type.  When converting || to && (or vice versa)
                // we want to grab the entire set.  i.e.  `!a && !b && !c` should become `!(a || b || c)` not
                // `!(a || b) && !c`
                while (expression.Parent?.RawKind == expression.RawKind)
                {
                    expression = expression.Parent;
                }
            }

            context.RegisterRefactoring(
                new MyCodeAction(
                    GetTitle(GetKind(expression.RawKind)),
                    c => InvertLogicalAsync(document, expression, c)),
                expression.Span);
        }
예제 #8
0
        public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            var(document, _, cancellationToken) = context;
            if (document.Project.Solution.Workspace.Kind == WorkspaceKind.MiscellaneousFiles)
            {
                return;
            }

            var ifStatement = await context
                              .TryGetRelevantNodeAsync <TIfStatementSyntax>()
                              .ConfigureAwait(false);

            if (
                ifStatement == null ||
                ifStatement.GetDiagnostics().Any(d => d.Severity == DiagnosticSeverity.Error)
                )
            {
                return;
            }

            var semanticModel = await document
                                .GetRequiredSemanticModelAsync(cancellationToken)
                                .ConfigureAwait(false);

            var ifOperation = semanticModel.GetOperation(ifStatement);

            if (!(ifOperation is IConditionalOperation {
                Parent : IBlockOperation parentBlock
            }))
        public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            var(document, _, cancellationToken) = context;
            var declaration = await context.TryGetRelevantNodeAsync <TLocalDeclaration>().ConfigureAwait(false);

            if (declaration == null)
            {
                return;
            }

            var syntaxFacts = document.GetRequiredLanguageService <ISyntaxFactsService>();
            var variables   = syntaxFacts.GetVariablesOfLocalDeclarationStatement(declaration);

            if (variables.Count != 1)
            {
                return;
            }

            var service = document.GetRequiredLanguageService <IMoveDeclarationNearReferenceService>();

            if (!await service.CanMoveDeclarationNearReferenceAsync(document, declaration, cancellationToken).ConfigureAwait(false))
            {
                return;
            }

            context.RegisterRefactoring(
                CodeAction.CreateWithPriority(
                    CodeActionPriority.Low,
                    FeaturesResources.Move_declaration_near_reference,
                    c => MoveDeclarationNearReferenceAsync(document, declaration, c),
                    nameof(FeaturesResources.Move_declaration_near_reference)),
                declaration.Span);
        }
예제 #10
0
        public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            var(document, _, cancellationToken) = context;
            var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            var forEachStatement = await context.TryGetRelevantNodeAsync <TForEachStatement>().ConfigureAwait(false);

            if (forEachStatement == null)
            {
                return;
            }

            if (forEachStatement.ContainsDiagnostics)
            {
                return;
            }

            // Do not try to refactor queries with conditional compilation in them.
            if (forEachStatement.ContainsDirectives)
            {
                return;
            }

            var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            if (!TryBuildConverter(forEachStatement, semanticModel, convertLocalDeclarations: true, cancellationToken, out var queryConverter))
            {
                return;
            }

            if (semanticModel.GetDiagnostics(forEachStatement.Span, cancellationToken)
                .Any(static diagnostic => diagnostic.DefaultSeverity == DiagnosticSeverity.Error))
        public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            var(document, _, cancellationToken) = context;

            var model = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            var syntaxFacts = document.GetLanguageService <ISyntaxFactsService>();

            var awaitable = await context.TryGetRelevantNodeAsync <TInvocationExpressionSyntax>().ConfigureAwait(false);

            if (awaitable == null || !IsValidAwaitableExpression(awaitable, model, syntaxFacts))
            {
                return;
            }

            context.RegisterRefactoring(
                new MyCodeAction(
                    GetTitle(),
                    c => AddAwaitAsync(document, awaitable, withConfigureAwait: false, c)),
                awaitable.Span);

            context.RegisterRefactoring(
                new MyCodeAction(
                    GetTitleWithConfigureAwait(),
                    c => AddAwaitAsync(document, awaitable, withConfigureAwait: true, c)),
                awaitable.Span);
        }
예제 #12
0
        public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            var(document, textSpan, cancellationToken) = context;
            var foreachStatement = await context.TryGetRelevantNodeAsync <TForEachStatement>().ConfigureAwait(false);

            if (foreachStatement == null || !IsValid(foreachStatement))
            {
                return;
            }

            var model = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            var semanticFact = document.GetLanguageService <ISemanticFactsService>();
            var options      = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false);

            var foreachInfo = GetForeachInfo(semanticFact, options, model, foreachStatement, cancellationToken);

            if (foreachInfo == null || !ValidLocation(foreachInfo))
            {
                return;
            }

            context.RegisterRefactoring(
                new ForEachToForCodeAction(
                    Title,
                    c => ConvertForeachToForAsync(document, foreachInfo, c)));
        }
        public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            var(document, textSpan, cancellationToken) = context;

            var syntaxTree = (await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false)) !;

            if (!MakeLocalFunctionStaticHelper.IsStaticLocalFunctionSupported(syntaxTree))
            {
                return;
            }

            var localFunction = await context.TryGetRelevantNodeAsync <LocalFunctionStatementSyntax>().ConfigureAwait(false);

            if (localFunction == null)
            {
                return;
            }

            if (localFunction.Modifiers.Any(SyntaxKind.StaticKeyword))
            {
                return;
            }

            var semanticModel = (await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false)) !;

            if (MakeLocalFunctionStaticHelper.TryGetCaputuredSymbolsAndCheckApplicability(localFunction, semanticModel, out var captures))
            {
                context.RegisterRefactoring(new MyCodeAction(
                                                FeaturesResources.Make_local_function_static,
                                                c => MakeLocalFunctionStaticHelper.MakeLocalFunctionStaticAsync(document, localFunction, captures, c)));
            }
        }
예제 #14
0
        public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            var(document, _, cancellationToken) = context;
            var declaration = await context.TryGetRelevantNodeAsync <TLocalDeclaration>().ConfigureAwait(false);

            if (declaration == null)
            {
                return;
            }

            var syntaxFacts = document.GetLanguageService <ISyntaxFactsService>();
            var variables   = syntaxFacts.GetVariablesOfLocalDeclarationStatement(declaration);

            if (variables.Count != 1)
            {
                return;
            }

            var service = document.GetLanguageService <IMoveDeclarationNearReferenceService>();

            if (!await service.CanMoveDeclarationNearReferenceAsync(document, declaration, cancellationToken).ConfigureAwait(false))
            {
                return;
            }

            context.RegisterRefactoring(
                new MyCodeAction(c => MoveDeclarationNearReferenceAsync(document, declaration, c)),
                declaration.Span);
        }
예제 #15
0
        private static async Task <(TTypeDeclarationSyntax type, CodeActionPriority priority)?> GetRelevantTypeFromMethodAsync(CodeRefactoringContext context)
        {
            var(document, _, cancellationToken) = context;
            var method = await context.TryGetRelevantNodeAsync <TMethodDeclarationSyntax>().ConfigureAwait(false);

            if (method == null)
            {
                return(null);
            }

            var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            var methodSymbol = (IMethodSymbol)semanticModel.GetRequiredDeclaredSymbol(method, cancellationToken);

            var isDebuggerDisplayMethod = IsDebuggerDisplayMethod(methodSymbol);

            if (!isDebuggerDisplayMethod && !IsToStringMethod(methodSymbol))
            {
                return(null);
            }

            // Show the feature if we're on a ToString or GetDebuggerDisplay method. For the former,
            // have this be low-pri so we don't override more important light-bulb options.
            var typeDecl = method.FirstAncestorOrSelf <TTypeDeclarationSyntax>();

            if (typeDecl == null)
            {
                return(null);
            }

            var priority = isDebuggerDisplayMethod ? CodeActionPriority.Medium : CodeActionPriority.Low;

            return(typeDecl, priority);
        }
예제 #16
0
        public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            var(document, _, cancellationToken) = context;
            if (document.Project.Solution.Workspace.Kind == WorkspaceKind.MiscellaneousFiles)
            {
                return;
            }

            var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            var variableDeclarator = await context.TryGetRelevantNodeAsync <VariableDeclaratorSyntax>().ConfigureAwait(false);

            if (variableDeclarator == null)
            {
                return;
            }

            if (!variableDeclarator.IsParentKind(SyntaxKind.VariableDeclaration) ||
                !variableDeclarator.Parent.IsParentKind(SyntaxKind.LocalDeclarationStatement))
            {
                return;
            }

            var variableDeclaration = (VariableDeclarationSyntax)variableDeclarator.Parent;

            if (variableDeclarator.Initializer == null ||
                variableDeclarator.Initializer.Value.IsMissing ||
                variableDeclarator.Initializer.Value.IsKind(SyntaxKind.StackAllocArrayCreationExpression))
            {
                return;
            }

            if (variableDeclaration.Type.Kind() == SyntaxKind.RefType)
            {
                // TODO: inlining ref returns:
                // https://github.com/dotnet/roslyn/issues/17132
                return;
            }

            var localDeclarationStatement = (LocalDeclarationStatementSyntax)variableDeclaration.Parent;

            if (localDeclarationStatement.ContainsDiagnostics ||
                localDeclarationStatement.UsingKeyword != default)
            {
                return;
            }

            var references = await GetReferencesAsync(document, variableDeclarator, cancellationToken).ConfigureAwait(false);

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

            context.RegisterRefactoring(
                new MyCodeAction(
                    CSharpFeaturesResources.Inline_temporary_variable,
                    c => this.InlineTemporaryAsync(document, variableDeclarator, c)),
                variableDeclarator.Span);
        }
        protected async Task <TExpressionStatementSyntax> GetExpressionStatementAsync(CodeRefactoringContext context)
        {
            var expressionStatement = await context.TryGetRelevantNodeAsync <TExpressionStatementSyntax>().ConfigureAwait(false);

            if (expressionStatement == null)
            {
                // If an expression-statement wasn't selected, see if they're selecting
                // an expression belonging to an expression-statement instead.
                var expression = await context.TryGetRelevantNodeAsync <TExpressionSyntax>().ConfigureAwait(false);

                expressionStatement = expression?.Parent as TExpressionStatementSyntax;
            }

            return(expressionStatement != null && IsValid(expressionStatement, context.Span)
                ? expressionStatement
                : null);
        }
예제 #18
0
        protected async Task <TExpressionStatementSyntax> GetExpressionStatementAsync(CodeRefactoringContext context)
        {
            var expressionStatement = await context.TryGetRelevantNodeAsync <TExpressionStatementSyntax>().ConfigureAwait(false);

            return(expressionStatement != null && IsValid(expressionStatement, context.Span)
                ? expressionStatement
                : null);
        }
예제 #19
0
        public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            var forStatement = await context.TryGetRelevantNodeAsync <ForStatementSyntax>().ConfigureAwait(false);

            if (forStatement == null)
            {
                return;
            }

            // We support the following cases
            //
            //  for (var x = start; x < end ; x++)
            //  for (...          ; ...     ; ++x)
            //  for (...          ; x <= end; ...)
            //  for (...          ; ...     ; x += 1)
            //
            //  for (var x = end    ; x >= start; x--)
            //  for (...            ; ...       ; --x)
            //  for (...            ; ...       ; x -= 1)

            var declaration = forStatement.Declaration;

            if (declaration == null ||
                declaration.Variables.Count != 1 ||
                forStatement.Incrementors.Count != 1)
            {
                return;
            }

            var variable = declaration.Variables[0];
            var after    = forStatement.Incrementors[0];

            if (forStatement.Condition is not BinaryExpressionSyntax condition)
            {
                return;
            }

            var(document, _, cancellationToken) = context;
            if (MatchesIncrementPattern(variable, condition, after, out var start, out var equals, out var end) ||
                MatchesDecrementPattern(variable, condition, after, out end, out start))
            {
                var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false);

                if (IsUnsignedBoundary(semanticModel, variable, start, end, cancellationToken))
                {
                    // Don't allow reversing when you have unsigned types and are on the start/end
                    // of the legal values for that type.  i.e. `for (byte i = 0; i < 10; i++)` it's
                    // not trivial to reverse this.
                    return;
                }

                context.RegisterRefactoring(
                    CodeAction.Create(
                        CSharpFeaturesResources.Reverse_for_statement,
                        c => ReverseForStatementAsync(document, forStatement, c),
                        nameof(CSharpFeaturesResources.Reverse_for_statement)));
            }
        }
        public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            var(document, textSpan, cancellationToken) = context;
            if (cancellationToken.IsCancellationRequested)
            {
                return;
            }

            if (document.Project.Solution.Workspace.Kind == WorkspaceKind.MiscellaneousFiles)
            {
                return;
            }

            var semanticDocument = await SemanticDocument
                                   .CreateAsync(document, cancellationToken)
                                   .ConfigureAwait(false);

            var lambda = await context
                         .TryGetRelevantNodeAsync <LambdaExpressionSyntax>()
                         .ConfigureAwait(false);

            if (lambda == null)
            {
                return;
            }

            if (
                !CanSimplify(
                    semanticDocument,
                    lambda as SimpleLambdaExpressionSyntax,
                    cancellationToken
                    ) &&
                !CanSimplify(
                    semanticDocument,
                    lambda as ParenthesizedLambdaExpressionSyntax,
                    cancellationToken
                    )
                )
            {
                return;
            }

            context.RegisterRefactoring(
                new MyCodeAction(
                    CSharpFeaturesResources.Simplify_lambda_expression,
                    c => SimplifyLambdaAsync(document, lambda, c)
                    ),
                lambda.Span
                );

            context.RegisterRefactoring(
                new MyCodeAction(
                    CSharpFeaturesResources.Simplify_all_occurrences,
                    c => SimplifyAllLambdasAsync(document, c)
                    ),
                lambda.Span
                );
        }
        private static async Task<SyntaxNode?> GetPropertyAsync(CodeRefactoringContext context)
        {
            var containingProperty = await context.TryGetRelevantNodeAsync<TPropertyDeclarationNode>().ConfigureAwait(false);
            if (containingProperty?.Parent is not TTypeDeclarationNode)
            {
                return null;
            }

            return containingProperty;
        }
        private async Task <SyntaxNode> GetPropertyAsync(CodeRefactoringContext context)
        {
            var containingProperty = await context.TryGetRelevantNodeAsync <TPropertyDeclarationNode>().ConfigureAwait(false);

            if (!(containingProperty?.Parent is TTypeDeclarationNode))
            {
                return(null);
            }

            return(containingProperty);
        }
예제 #23
0
        private static async Task <(TTypeDeclarationSyntax type, CodeActionPriority priority)?> GetRelevantTypeFromHeaderAsync(CodeRefactoringContext context)
        {
            var type = await context.TryGetRelevantNodeAsync <TTypeDeclarationSyntax>().ConfigureAwait(false);

            if (type is null)
            {
                return(null);
            }

            return(type, CodeActionPriority.Low);
        }
        private async Task <TTypeDeclarationSyntax?> GetRelevantTypeFromHeaderAsync(CodeRefactoringContext context)
        {
            var type = await context.TryGetRelevantNodeAsync <TTypeDeclarationSyntax>(RefactoringHelpers).ConfigureAwait(false);

            if (type is null)
            {
                return(null);
            }

            return(type);
        }
        public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            var(document, textSpan, cancellationToken) = context;
            var syntaxTree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);

            var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            var parameterNode = await context.TryGetRelevantNodeAsync <TParameterSyntax>().ConfigureAwait(false);

            if (parameterNode == null)
            {
                return;
            }

            var functionDeclaration = parameterNode.FirstAncestorOrSelf <SyntaxNode>(IsFunctionDeclaration);

            if (functionDeclaration == null)
            {
                return;
            }

            var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            // we can't just call GetDeclaredSymbol on functionDeclaration because it could an anonymous function,
            // so first we have to get the parameter symbol and then its containing method symbol
            var parameter = (IParameterSymbol)semanticModel.GetDeclaredSymbol(parameterNode, cancellationToken);

            if (parameter == null || parameter.Name == "")
            {
                return;
            }

            var method = (IMethodSymbol)parameter.ContainingSymbol;

            if (method.IsAbstract ||
                method.IsExtern ||
                method.PartialImplementationPart != null ||
                method.ContainingType.TypeKind == TypeKind.Interface)
            {
                return;
            }

            var syntaxFacts = document.GetLanguageService <ISyntaxFactsService>();

            if (CanOfferRefactoring(functionDeclaration, semanticModel, syntaxFacts, cancellationToken, out var blockStatementOpt))
            {
                // Ok.  Looks like a reasonable parameter to analyze.  Defer to subclass to
                // actually determine if there are any viable refactorings here.
                context.RegisterRefactorings(await GetRefactoringsAsync(
                                                 document, parameter, functionDeclaration, method, blockStatementOpt, cancellationToken).ConfigureAwait(false));
            }
        }
        internal virtual async Task <SyntaxToken> GetNumericTokenAsync(CodeRefactoringContext context)
        {
            var syntaxFacts = context.Document.GetRequiredLanguageService <ISyntaxFactsService>();

            var literalNode = await context.TryGetRelevantNodeAsync <TNumericLiteralExpression>().ConfigureAwait(false);

            var numericLiteralExpressionNode = syntaxFacts.IsNumericLiteralExpression(literalNode)
                ? literalNode
                : null;

            return(numericLiteralExpressionNode != null
                ? numericLiteralExpressionNode.GetFirstToken()    // We know that TNumericLiteralExpression has always only one token: NumericLiteralToken
                : default);
        public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            var literalExpression = await context
                                    .TryGetRelevantNodeAsync <TStringExpressionSyntax>()
                                    .ConfigureAwait(false);

            if (literalExpression == null || !IsAppropriateLiteralKind(literalExpression))
            {
                return;
            }

            var(document, _, cancellationToken) = context;

            var charService = document.GetRequiredLanguageService <IVirtualCharLanguageService>();

            using var _ = ArrayBuilder <SyntaxToken> .GetInstance(out var subStringTokens);

            // First, ensure that we understand all text parts of the interpolation.
            AddSubStringTokens(literalExpression, subStringTokens);
            foreach (var subToken in subStringTokens)
            {
                var chars = charService.TryConvertToVirtualChars(subToken);
                if (chars.IsDefault)
                {
                    return;
                }
            }

            if (IsVerbatim(literalExpression))
            {
                // always offer to convert from verbatim string to normal string.
                context.RegisterRefactoring(
                    new MyCodeAction(
                        CSharpFeaturesResources.Convert_to_regular_string,
                        c => ConvertToRegularStringAsync(document, literalExpression, c)
                        )
                    );
            }
            else if (ContainsSimpleEscape(charService, subStringTokens))
            {
                // Offer to convert to a verbatim string if the normal string contains simple
                // escapes that can be directly embedded in the verbatim string.
                context.RegisterRefactoring(
                    new MyCodeAction(
                        CSharpFeaturesResources.Convert_to_verbatim_string,
                        c => ConvertToVerbatimStringAsync(document, literalExpression, c)
                        )
                    );
            }
        }
        public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            var literalExpression = await context.TryGetRelevantNodeAsync <TStringExpressionSyntax>().ConfigureAwait(false);

            if (literalExpression == null || !IsAppropriateLiteralKind(literalExpression))
            {
                return;
            }

            var(document, _, cancellationToken) = context;

            var charService = document.GetRequiredLanguageService <IVirtualCharLanguageService>();

            using var _ = ArrayBuilder <SyntaxToken> .GetInstance(out var subStringTokens);

            // First, ensure that we understand all text parts of the interpolation.
            AddSubStringTokens(literalExpression, subStringTokens);
            foreach (var subToken in subStringTokens)
            {
                var chars = charService.TryConvertToVirtualChars(subToken);
                if (chars.IsDefault)
                {
                    return;
                }
            }

            // Note: This is a generally useful feature on strings.  But it's not likely to be something
            // people want to use a lot.  Make low priority so it doesn't interfere with more
            // commonly useful refactorings.

            if (IsVerbatim(literalExpression))
            {
                // always offer to convert from verbatim string to normal string.
                context.RegisterRefactoring(CodeAction.CreateWithPriority(
                                                CodeActionPriority.Low,
                                                CSharpFeaturesResources.Convert_to_regular_string,
                                                c => ConvertToRegularStringAsync(document, literalExpression, c),
                                                nameof(CSharpFeaturesResources.Convert_to_regular_string)));
            }
            else if (ContainsSimpleEscape(charService, subStringTokens))
            {
                // Offer to convert to a verbatim string if the normal string contains simple
                // escapes that can be directly embedded in the verbatim string.
                context.RegisterRefactoring(CodeAction.CreateWithPriority(
                                                CodeActionPriority.Low,
                                                CSharpFeaturesResources.Convert_to_verbatim_string,
                                                c => ConvertToVerbatimStringAsync(document, literalExpression, c),
                                                nameof(CSharpFeaturesResources.Convert_to_verbatim_string)));
            }
        }
예제 #29
0
        public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            var(document, span, cancellationToken) = context;

            var expression = (SyntaxNode?)await context.TryGetRelevantNodeAsync <TBinaryExpressionSyntax>().ConfigureAwait(false);

            var syntaxFacts = document.GetRequiredLanguageService <ISyntaxFactsService>();
            var syntaxKinds = document.GetRequiredLanguageService <ISyntaxKindsService>();

            if (expression == null ||
                (!syntaxFacts.IsLogicalAndExpression(expression) &&
                 !syntaxFacts.IsLogicalOrExpression(expression)))
            {
                return;
            }

            if (span.IsEmpty)
            {
                // Walk up to the topmost binary of the same type.  When converting || to && (or vice versa)
                // we want to grab the entire set.  i.e.  `!a && !b && !c` should become `!(a || b || c)` not
                // `!(a || b) && !c`
                while (expression.Parent?.RawKind == expression.RawKind)
                {
                    expression = expression.Parent;
                }
            }
            else
            {
                // When selection is non-empty -> allow only top-level full selections.
                // Currently the refactoring can't handle invert of arbitrary nodes but only whole subtrees
                // and allowing it just for selection of those nodes that - by chance - form a full subtree
                // would produce only confusion.
                if (CodeRefactoringHelpers.IsNodeUnderselected(expression, span) ||
                    syntaxFacts.IsLogicalAndExpression(expression.Parent) || syntaxFacts.IsLogicalOrExpression(expression.Parent))
                {
                    return;
                }
            }

            context.RegisterRefactoring(
                new MyCodeAction(
                    GetTitle(syntaxKinds, expression.RawKind),
                    c => InvertLogicalAsync(document, expression, c)),
                expression.Span);
        }
예제 #30
0
        public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            var literal = await context.TryGetRelevantNodeAsync <LiteralExpressionSyntax>(CSharpRefactoringHelpers.Instance).ConfigureAwait(false);

            if (literal is null)
            {
                return;
            }

            if (literal.Kind() == SyntaxKind.StringLiteralExpression &&
                !IsProperlyNumbered(literal.Token.ValueText))
            {
                var action = CodeAction.Create(
                    RoslynDiagnosticsAnalyzersResources.FixNumberedComments,
                    c => FixCommentsAsync(context.Document, literal, c));
                context.RegisterRefactoring(action);
            }
        }