コード例 #1
0
        public async Task <CodeAction> IntroduceVariableAsync(
            Document document,
            TextSpan textSpan,
            CodeCleanupOptions options,
            CancellationToken cancellationToken)
        {
            using (Logger.LogBlock(FunctionId.Refactoring_IntroduceVariable, cancellationToken))
            {
                var semanticDocument = await SemanticDocument.CreateAsync(document, cancellationToken).ConfigureAwait(false);

                var state = await State.GenerateAsync((TService)this, semanticDocument, options, textSpan, cancellationToken).ConfigureAwait(false);

                if (state != null)
                {
                    var(title, actions) = CreateActions(state, cancellationToken);
                    if (actions.Length > 0)
                    {
                        // We may end up creating a lot of viable code actions for the selected
                        // piece of code.  Create a top level code action so that we don't overwhelm
                        // the light bulb if there are a lot of other options in the list.  Set
                        // the code action as 'inlinable' so that if the lightbulb is not cluttered
                        // then the nested items can just be lifted into it, giving the user fast
                        // access to them.
                        return(CodeActionWithNestedActions.Create(title, actions, isInlinable: true));
                    }
                }

                return(null);
            }
        }
コード例 #2
0
ファイル: CodeAction.cs プロジェクト: josh-127/roslyn
        /// <summary>
        /// Creates a <see cref="CodeAction"/> representing a group of code actions.
        /// </summary>
        /// <param name="title">Title of the <see cref="CodeAction"/> group.</param>
        /// <param name="nestedActions">The code actions within the group.</param>
        /// <param name="isInlinable"><see langword="true"/> to allow inlining the members of the group into the parent;
        /// otherwise, <see langword="false"/> to require that this group appear as a group with nested actions.</param>
        public static CodeAction Create(string title, ImmutableArray <CodeAction> nestedActions, bool isInlinable)
        {
            if (title is null)
            {
                throw new ArgumentNullException(nameof(title));
            }

            if (nestedActions == null)
            {
                throw new ArgumentNullException(nameof(nestedActions));
            }

            return(CodeActionWithNestedActions.Create(title, nestedActions, isInlinable));
        }
コード例 #3
0
        public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            var(document, textSpan, cancellationToken) = context;
            if (document.Project.Solution.Workspace.Kind == WorkspaceKind.MiscellaneousFiles)
            {
                return;
            }

            var expression = await document.TryGetRelevantNodeAsync <TExpressionSyntax>(textSpan, cancellationToken).ConfigureAwait(false);

            if (expression == null || CodeRefactoringHelpers.IsNodeUnderselected(expression, textSpan))
            {
                return;
            }

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

            var expressionType = semanticModel.GetTypeInfo(expression, cancellationToken).Type;

            if (expressionType is null or IErrorTypeSymbol)
            {
                return;
            }

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

            // Need to special case for expressions that are contained within a parameter
            // because it is technically "contained" within a method, but an expression in a parameter does not make
            // sense to introduce.
            var parameterNode = expression.FirstAncestorOrSelf <SyntaxNode>(node => syntaxFacts.IsParameter(node));

            if (parameterNode is not null)
            {
                return;
            }

            // Need to special case for highlighting of method types because they are also "contained" within a method,
            // but it does not make sense to introduce a parameter in that case.
            if (syntaxFacts.IsInNamespaceOrTypeContext(expression))
            {
                return;
            }

            // Need to special case for expressions whose direct parent is a MemberAccessExpression since they will
            // never introduce a parameter that makes sense in that case.
            if (syntaxFacts.IsNameOfAnyMemberAccessExpression(expression))
            {
                return;
            }

            var generator        = SyntaxGenerator.GetGenerator(document);
            var containingMethod = expression.FirstAncestorOrSelf <SyntaxNode>(node => generator.GetParameterListNode(node) is not null);

            if (containingMethod is null)
            {
                return;
            }

            var containingSymbol = semanticModel.GetDeclaredSymbol(containingMethod, cancellationToken);

            if (containingSymbol is not IMethodSymbol methodSymbol)
            {
                return;
            }

            var expressionSymbol = semanticModel.GetSymbolInfo(expression, cancellationToken).Symbol;

            if (expressionSymbol is IParameterSymbol parameterSymbol && parameterSymbol.ContainingSymbol.Equals(containingSymbol))
            {
                return;
            }

            // Code actions for trampoline and overloads will not be offered if the method is a constructor.
            // Code actions for overloads will not be offered if the method if the method is a local function.
            var methodKind = methodSymbol.MethodKind;

            if (methodKind is not(MethodKind.Ordinary or MethodKind.LocalFunction or MethodKind.Constructor))
            {
                return;
            }

            if (IsDestructor(methodSymbol))
            {
                return;
            }

            var actions = await GetActionsAsync(document, expression, methodSymbol, containingMethod, context.Options, cancellationToken).ConfigureAwait(false);

            if (actions is null)
            {
                return;
            }

            var singleLineExpression = syntaxFacts.ConvertToSingleLine(expression);
            var nodeString           = singleLineExpression.ToString();

            if (actions.Value.actions.Length > 0)
            {
                context.RegisterRefactoring(CodeActionWithNestedActions.Create(
                                                string.Format(FeaturesResources.Introduce_parameter_for_0, nodeString), actions.Value.actions, isInlinable: false, priority: CodeActionPriority.Low), textSpan);
            }

            if (actions.Value.actionsAllOccurrences.Length > 0)
            {
                context.RegisterRefactoring(CodeActionWithNestedActions.Create(
                                                string.Format(FeaturesResources.Introduce_parameter_for_all_occurrences_of_0, nodeString), actions.Value.actionsAllOccurrences, isInlinable: false,
                                                priority: CodeActionPriority.Low), textSpan);
            }
        }