public async Task <GeneratedCode> GenerateAsync(CancellationToken cancellationToken)
            {
                var root = SemanticDocument.Root;

                // should I check venus hidden position check here as well?
                root = root.ReplaceNode(GetOutermostCallSiteContainerToProcess(cancellationToken), await GenerateBodyForCallSiteContainerAsync(cancellationToken).ConfigureAwait(false));
                var callSiteDocument = await SemanticDocument.WithSyntaxRootAsync(root, cancellationToken).ConfigureAwait(false);

                var newCallSiteRoot    = callSiteDocument.Root;
                var previousMemberNode = GetPreviousMember(callSiteDocument);

                // it is possible in a script file case where there is no previous member. in that case, insert new text into top level script
                var destination = (previousMemberNode.Parent == null) ? previousMemberNode : previousMemberNode.Parent;

                var codeGenerationService = SemanticDocument.Document.GetLanguageService <ICodeGenerationService>();

                var result       = GenerateMethodDefinition(cancellationToken);
                var newContainer = codeGenerationService.AddMethod(
                    destination, result.Data,
                    new CodeGenerationOptions(afterThisLocation: previousMemberNode.GetLocation(), generateDefaultAccessibility: true, generateMethodBodies: true),
                    cancellationToken);

                var newDocument = callSiteDocument.Document.WithSyntaxRoot(newCallSiteRoot.ReplaceNode(destination, newContainer));

                newDocument = await Simplifier.ReduceAsync(newDocument, Simplifier.Annotation, null, cancellationToken).ConfigureAwait(false);

                var finalDocument = await SemanticDocument.CreateAsync(newDocument, cancellationToken).ConfigureAwait(false);

                var finalRoot = finalDocument.Root;

                var methodDefinition = finalRoot.GetAnnotatedNodesAndTokens(MethodDefinitionAnnotation).FirstOrDefault();

                if (!methodDefinition.IsNode || methodDefinition.AsNode() == null)
                {
                    return(await CreateGeneratedCodeAsync(
                               result.Status.With(OperationStatus.FailedWithUnknownReason), finalDocument, cancellationToken).ConfigureAwait(false));
                }

                if (methodDefinition.SyntaxTree.IsHiddenPosition(methodDefinition.AsNode().SpanStart, cancellationToken) ||
                    methodDefinition.SyntaxTree.IsHiddenPosition(methodDefinition.AsNode().Span.End, cancellationToken))
                {
                    return(await CreateGeneratedCodeAsync(
                               result.Status.With(OperationStatus.OverlapsHiddenPosition), finalDocument, cancellationToken).ConfigureAwait(false));
                }

                return(await CreateGeneratedCodeAsync(result.Status, finalDocument, cancellationToken).ConfigureAwait(false));
            }
Exemple #2
0
        public async Task <ImmutableArray <CodeAction> > GenerateDeconstructMethodAsync(
            Document document,
            SyntaxNode leftSide,
            INamedTypeSymbol typeToGenerateIn,
            CodeAndImportGenerationOptionsProvider fallbackOptions,
            CancellationToken cancellationToken)
        {
            using (Logger.LogBlock(FunctionId.Refactoring_GenerateMember_GenerateMethod, cancellationToken))
            {
                var semanticDocument = await SemanticDocument.CreateAsync(document, cancellationToken).ConfigureAwait(false);

                var state = await State.GenerateDeconstructMethodStateAsync(
                    (TService)this, semanticDocument, leftSide, typeToGenerateIn, cancellationToken).ConfigureAwait(false);

                return(state != null ? await GetActionsAsync(document, state, fallbackOptions, cancellationToken).ConfigureAwait(false) : ImmutableArray <CodeAction> .Empty);
            }
        }
Exemple #3
0
        protected static async Task <SyntaxNode> ExtractMethodAsync(
            TestWorkspace workspace,
            TestHostDocument testDocument,
            bool succeed = true,
            bool dontPutOutOrRefOnStruct = true,
            bool allowBestEffort         = false)
        {
            var document = workspace.CurrentSolution.GetDocument(testDocument.Id);

            Assert.NotNull(document);

            var options = new ExtractMethodGenerationOptions(
                ExtractOptions: new ExtractMethodOptions(dontPutOutOrRefOnStruct),
                CodeGenerationOptions: CodeGenerationOptions.GetDefault(document.Project.LanguageServices),
                AddImportOptions: AddImportPlacementOptions.Default,
                NamingPreferences: _ => NamingStylePreferences.Default);

            var semanticDocument = await SemanticDocument.CreateAsync(document, CancellationToken.None);

            var validator = new CSharpSelectionValidator(semanticDocument, testDocument.SelectedSpans.Single(), options.ExtractOptions, localFunction: false);

            var selectedCode = await validator.GetValidSelectionAsync(CancellationToken.None);

            if (!succeed && selectedCode.Status.FailedWithNoBestEffortSuggestion())
            {
                return(null);
            }

            Assert.True(selectedCode.ContainsValidContext);

            // extract method
            var extractor = new CSharpMethodExtractor((CSharpSelectionResult)selectedCode, options, localFunction: false);
            var result    = await extractor.ExtractMethodAsync(CancellationToken.None);

            Assert.NotNull(result);
            Assert.Equal(succeed,
                         result.Succeeded ||
                         result.SucceededWithSuggestion ||
                         (allowBestEffort && result.Status.HasBestEffort()));

            var(doc, _) = await result.GetFormattedDocumentAsync(CodeCleanupOptions.GetDefault(document.Project.LanguageServices), CancellationToken.None);

            return(doc == null
                ? null
                : await doc.GetSyntaxRootAsync());
        }
Exemple #4
0
        protected static async Task <SyntaxNode> ExtractMethodAsync(
            TestWorkspace workspace,
            TestHostDocument testDocument,
            bool succeed = true,
            bool allowMovingDeclaration  = true,
            bool dontPutOutOrRefOnStruct = true,
            bool allowBestEffort         = false)
        {
            var document = workspace.CurrentSolution.GetDocument(testDocument.Id);

            Assert.NotNull(document);

            var originalOptions = await document.GetOptionsAsync();

            var options = originalOptions.WithChangedOption(ExtractMethodOptions.AllowMovingDeclaration, document.Project.Language, allowMovingDeclaration)
                          .WithChangedOption(ExtractMethodOptions.DontPutOutOrRefOnStruct, document.Project.Language, dontPutOutOrRefOnStruct);

            var semanticDocument = await SemanticDocument.CreateAsync(document, CancellationToken.None);

            var validator = new CSharpSelectionValidator(semanticDocument, testDocument.SelectedSpans.Single(), options);

            var selectedCode = await validator.GetValidSelectionAsync(CancellationToken.None);

            if (!succeed && selectedCode.Status.FailedWithNoBestEffortSuggestion())
            {
                return(null);
            }

            Assert.True(selectedCode.ContainsValidContext);

            // extract method
            var extractor = new CSharpMethodExtractor((CSharpSelectionResult)selectedCode, localFunction: false);
            var result    = await extractor.ExtractMethodAsync(CancellationToken.None);

            Assert.NotNull(result);
            Assert.Equal(succeed,
                         result.Succeeded ||
                         result.SucceededWithSuggestion ||
                         (allowBestEffort && result.Status.HasBestEffort()));

            var doc = result.Document;

            return(doc == null
                ? null
                : await doc.GetSyntaxRootAsync());
        }
Exemple #5
0
        private static async Task <Tuple <SemanticDocument, ISet <ExpressionSyntax> > > ComplexifyParentingStatements(
            SemanticDocument semanticDocument,
            ISet <ExpressionSyntax> matches,
            CancellationToken cancellationToken)
        {
            // First, track the matches so that we can get back to them later.
            var newRoot             = semanticDocument.Root.TrackNodes(matches);
            var newDocument         = semanticDocument.Document.WithSyntaxRoot(newRoot);
            var newSemanticDocument = await SemanticDocument.CreateAsync(newDocument, cancellationToken).ConfigureAwait(false);

            var newMatches = newSemanticDocument.Root.GetCurrentNodes(matches.AsEnumerable()).ToSet();

            // Next, expand the topmost parenting expression of each match, being careful
            // not to expand the matches themselves.
            var topMostExpressions = newMatches
                                     .Select(m => m.AncestorsAndSelf().OfType <ExpressionSyntax>().Last())
                                     .Distinct();

            newRoot = await newSemanticDocument.Root
                      .ReplaceNodesAsync(
                topMostExpressions,
                computeReplacementAsync : async(oldNode, newNode, ct) =>
            {
                return(await Simplifier
                       .ExpandAsync(
                           oldNode,
                           newSemanticDocument.Document,
                           expandInsideNode: node =>
                {
                    var expression = node as ExpressionSyntax;
                    return expression == null ||
                    !newMatches.Contains(expression);
                },
                           cancellationToken: ct)
                       .ConfigureAwait(false));
            },
                cancellationToken : cancellationToken)
                      .ConfigureAwait(false);

            newDocument         = newSemanticDocument.Document.WithSyntaxRoot(newRoot);
            newSemanticDocument = await SemanticDocument.CreateAsync(newDocument, cancellationToken).ConfigureAwait(false);

            newMatches = newSemanticDocument.Root.GetCurrentNodes(matches.AsEnumerable()).ToSet();

            return(Tuple.Create(newSemanticDocument, newMatches));
        }
Exemple #6
0
        public async Task <IEnumerable <CodeAction> > GenerateVariableAsync(
            Document document,
            SyntaxNode node,
            CancellationToken cancellationToken)
        {
            var semanticDocument = await SemanticDocument.CreateAsync(document, cancellationToken).ConfigureAwait(false);

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

            if (state == null)
            {
                return(SpecializedCollections.EmptyEnumerable <CodeAction>());
            }

            var result = new List <CodeAction>();

            var canGenerateMember = ICSharpCode.NRefactory6.CSharp.CodeGenerator.CanAdd(document.Project.Solution, state.TypeToGenerateIn, cancellationToken);

            // prefer fields over properties (and vice versa) depending on the casing of the member.
            // lowercase -> fields.  title case -> properties.
            var name = state.IdentifierToken.ValueText;

            if (char.IsUpper(name.FirstOrDefault()))
            {
                if (canGenerateMember)
                {
                    AddPropertyCodeActions(result, document, state);
                    AddFieldCodeActions(result, document, state);
                }

                AddLocalCodeActions(result, document, state);
            }
            else
            {
                if (canGenerateMember)
                {
                    AddFieldCodeActions(result, document, state);
                    AddPropertyCodeActions(result, document, state);
                }

                AddLocalCodeActions(result, document, state);
            }

            return(result);
        }
        public async Task <GenerateDefaultConstructorsResult> GenerateDefaultConstructorsAsync(
            Document document,
            TextSpan textSpan,
            CancellationToken cancellationToken)
        {
            var semanticDocument = await SemanticDocument.CreateAsync(document, cancellationToken).ConfigureAwait(false);

            if (textSpan.IsEmpty)
            {
                var state = State.Generate((TService)this, semanticDocument, textSpan, cancellationToken);
                if (state != null)
                {
                    return(new GenerateDefaultConstructorsResult(new CodeRefactoring(null, GetActions(document, state))));
                }
            }

            return(GenerateDefaultConstructorsResult.Failure);
        }
        private async Task <IEnumerable <SnapshotSpan> > GetExecutableSyntaxTreeNodeSelectionAsync(
            TextSpan selectionSpan,
            EditorCommandArgs args,
            ITextSnapshot snapshot,
            CancellationToken cancellationToken
            )
        {
            var doc =
                args.SubjectBuffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges();
            var semanticDocument = await SemanticDocument
                                   .CreateAsync(doc, cancellationToken)
                                   .ConfigureAwait(false);

            var root = semanticDocument.Root;

            return(GetExecutableSyntaxTreeNodeSelection(selectionSpan, root)
                   .Select(span => new SnapshotSpan(snapshot, span.Start, span.Length)));
        }
        public async Task <IEnumerable <CodeAction> > GenerateTypeAsync(
            Document document,
            SyntaxNode node,
            CancellationToken cancellationToken)
        {
            using (Logger.LogBlock(FunctionId.Refactoring_GenerateType, cancellationToken))
            {
                var semanticDocument = await SemanticDocument.CreateAsync(document, cancellationToken).ConfigureAwait(false);

                var state = State.Generate((TService)this, semanticDocument, node, cancellationToken);
                if (state != null)
                {
                    return(GetActions(semanticDocument, node, state, cancellationToken));
                }

                return(SpecializedCollections.EmptyEnumerable <CodeAction>());
            }
        }
Exemple #10
0
        public async Task <ImmutableArray <CodeAction> > GenerateConstructorAsync(Document document, SyntaxNode node, CodeAndImportGenerationOptionsProvider fallbackOptions, CancellationToken cancellationToken)
        {
            using (Logger.LogBlock(FunctionId.Refactoring_GenerateMember_GenerateConstructor, cancellationToken))
            {
                var semanticDocument = await SemanticDocument.CreateAsync(document, cancellationToken).ConfigureAwait(false);

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

                if (state != null)
                {
                    Contract.ThrowIfNull(state.TypeToGenerateIn);

                    using var _ = ArrayBuilder <CodeAction> .GetInstance(out var result);

                    // If we have any fields we'd like to generate, offer a code action to do that.
                    if (state.ParameterToNewFieldMap.Count > 0)
                    {
                        result.Add(CodeAction.Create(
                                       string.Format(FeaturesResources.Generate_constructor_in_0_with_fields, state.TypeToGenerateIn.Name),
                                       c => state.GetChangedDocumentAsync(document, withFields: true, withProperties: false, c),
                                       nameof(FeaturesResources.Generate_constructor_in_0_with_fields) + "_" + state.TypeToGenerateIn.Name));
                    }

                    // Same with a version that generates properties instead.
                    if (state.ParameterToNewPropertyMap.Count > 0)
                    {
                        result.Add(CodeAction.Create(
                                       string.Format(FeaturesResources.Generate_constructor_in_0_with_properties, state.TypeToGenerateIn.Name),
                                       c => state.GetChangedDocumentAsync(document, withFields: false, withProperties: true, c),
                                       nameof(FeaturesResources.Generate_constructor_in_0_with_properties) + "_" + state.TypeToGenerateIn.Name));
                    }

                    // Always offer to just generate the constructor and nothing else.
                    result.Add(CodeAction.Create(
                                   string.Format(FeaturesResources.Generate_constructor_in_0, state.TypeToGenerateIn.Name),
                                   c => state.GetChangedDocumentAsync(document, withFields: false, withProperties: false, c),
                                   nameof(FeaturesResources.Generate_constructor_in_0) + "_" + state.TypeToGenerateIn.Name));

                    return(result.ToImmutable());
                }
            }

            return(ImmutableArray <CodeAction> .Empty);
        }
Exemple #11
0
        public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            var document          = context.Document;
            var textSpan          = context.Span;
            var cancellationToken = context.CancellationToken;

            if (!textSpan.IsEmpty)
            {
                return;
            }

            if (cancellationToken.IsCancellationRequested)
            {
                return;
            }

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

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

            var statement = root.FindToken(textSpan.Start).GetAncestor <LocalDeclarationStatementSyntax>();

            if (statement == null || !statement.Span.IntersectsWith(textSpan.Start))
            {
                return;
            }

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

            var state = await State.GenerateAsync(semanticDocument, statement, cancellationToken).ConfigureAwait(false);

            if (state == null)
            {
                return;
            }

            context.RegisterRefactoring(
                new MyCodeAction(
                    CSharpFeaturesResources.Move_declaration_near_reference,
                    c => MoveDeclarationNearReferenceAsync(document, state, c)));
        }
Exemple #12
0
        public async Task <ImmutableArray <CodeAction> > GenerateMethodAsync(
            Document document,
            SyntaxNode node,
            CancellationToken cancellationToken)
        {
            using (Logger.LogBlock(FunctionId.Refactoring_GenerateMember_GenerateMethod, cancellationToken))
            {
                var semanticDocument = await SemanticDocument.CreateAsync(document, cancellationToken).ConfigureAwait(false);

                var state = await State.GenerateMethodStateAsync((TService)this, semanticDocument, node, cancellationToken).ConfigureAwait(false);

                if (state == null)
                {
                    return(ImmutableArray <CodeAction> .Empty);
                }

                return(GetActions(document, state, cancellationToken));
            }
        }
            protected override async Task <IEnumerable <CodeActionOperation> > ComputeOperationsAsync(
                CancellationToken cancellationToken
                )
            {
                var semanticDocument = await SemanticDocument
                                       .CreateAsync(_document, cancellationToken)
                                       .ConfigureAwait(false);

                var editor = new Editor(
                    _service,
                    semanticDocument,
                    _state,
                    _intoNamespace,
                    _inNewFile,
                    cancellationToken: cancellationToken
                    );

                return(await editor.GetOperationsAsync().ConfigureAwait(false));
            }
        public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            var document          = context.Document;
            var textSpan          = context.Span;
            var cancellationToken = context.CancellationToken;

            if (cancellationToken.IsCancellationRequested)
            {
                return;
            }

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

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

            var refactoringHelperService = document.GetLanguageService <IRefactoringHelpersService>();
            var lambda = await refactoringHelperService.TryGetSelectedNodeAsync <LambdaExpressionSyntax>(document, context.Span, cancellationToken).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)));

            context.RegisterRefactoring(
                new MyCodeAction(
                    CSharpFeaturesResources.Simplify_all_occurrences,
                    c => SimplifyAllLambdasAsync(document, c)));
        }
Exemple #15
0
        protected static async Task TestSelectionAsync(
            string codeWithMarker,
            bool expectedFail = false,
            CSharpParseOptions parseOptions = null,
            TextSpan?textSpanOverride       = null
            )
        {
            using var workspace = TestWorkspace.CreateCSharp(
                      codeWithMarker,
                      parseOptions: parseOptions
                      );
            var testDocument = workspace.Documents.Single();
            var namedSpans   = testDocument.AnnotatedSpans;

            var document = workspace.CurrentSolution.GetDocument(testDocument.Id);

            Assert.NotNull(document);

            var options = await document.GetOptionsAsync(CancellationToken.None);

            var semanticDocument = await SemanticDocument.CreateAsync(
                document,
                CancellationToken.None
                );

            var validator = new CSharpSelectionValidator(
                semanticDocument,
                textSpanOverride ?? namedSpans["b"].Single(),
                options
                );
            var result = await validator.GetValidSelectionAsync(CancellationToken.None);

            Assert.True(expectedFail ? result.Status.Failed() : result.Status.Succeeded());

            if (
                (result.Status.Succeeded() || result.Status.Flag.HasBestEffort()) &&
                result.Status.Flag.HasSuggestion()
                )
            {
                Assert.Equal(namedSpans["r"].Single(), result.FinalSpan);
            }
        }
Exemple #16
0
        public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            var document          = context.Document;
            var textSpan          = context.Span;
            var cancellationToken = context.CancellationToken;

            if (cancellationToken.IsCancellationRequested)
            {
                return;
            }

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

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

            var lambda = semanticDocument.Root.FindToken(textSpan.Start).GetAncestor(n =>
                                                                                     n is SimpleLambdaExpressionSyntax || n is ParenthesizedLambdaExpressionSyntax);

            if (lambda == null || !lambda.Span.IntersectsWith(textSpan.Start))
            {
                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)));

            context.RegisterRefactoring(
                new MyCodeAction(
                    CSharpFeaturesResources.Simplify_all_occurrences,
                    c => SimplifyAllLambdasAsync(document, c)));
        }
        private async Task <State> CreateStateAsync(
            Document document,
            TextSpan textSpan,
            CancellationToken cancellationToken
            )
        {
            var nodeToAnalyze = await GetRelevantNodeAsync(document, textSpan, cancellationToken)
                                .ConfigureAwait(false);

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

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

            return(State.Generate(semanticDocument, nodeToAnalyze, cancellationToken));
        }
        public async Task <ImmutableArray <CodeAction> > IntroduceVariableAsync(
            Document document,
            TextSpan textSpan,
            CancellationToken cancellationToken)
        {
            using (Logger.LogBlock(FunctionId.Refactoring_IntroduceVariable, cancellationToken))
            {
                var semanticDocument = await SemanticDocument.CreateAsync(document, cancellationToken).ConfigureAwait(false);

                var state = State.Generate((TService)this, semanticDocument, textSpan, cancellationToken);
                if (state != null)
                {
                    var actions = await CreateActionsAsync(state, cancellationToken).ConfigureAwait(false);

                    if (actions.Count > 0)
                    {
                        return(actions.AsImmutableOrNull());
                    }
                }

                return(default);
        public async Task <ImmutableArray <CodeAction> > GenerateDefaultConstructorsAsync(
            Document document,
            TextSpan textSpan,
            CancellationToken cancellationToken)
        {
            using (Logger.LogBlock(FunctionId.Refactoring_GenerateMember_GenerateDefaultConstructors, cancellationToken))
            {
                var semanticDocument = await SemanticDocument.CreateAsync(document, cancellationToken).ConfigureAwait(false);

                if (textSpan.IsEmpty)
                {
                    var state = State.Generate((TService)this, semanticDocument, textSpan, cancellationToken);
                    if (state != null)
                    {
                        return(GetActions(document, state).AsImmutableOrNull());
                    }
                }

                return(default(ImmutableArray <CodeAction>));
            }
        }
Exemple #20
0
        public static async Task <CSharpSelectionResult> CreateAsync(
            OperationStatus status,
            TextSpan originalSpan,
            TextSpan finalSpan,
            OptionSet options,
            bool selectionInExpression,
            SemanticDocument document,
            SyntaxToken firstToken,
            SyntaxToken lastToken,
            CancellationToken cancellationToken)
        {
            Contract.ThrowIfNull(status);
            Contract.ThrowIfNull(document);

            var firstTokenAnnotation = new SyntaxAnnotation();
            var lastTokenAnnotation  = new SyntaxAnnotation();

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

            var newDocument = await SemanticDocument.CreateAsync(document.Document.WithSyntaxRoot(root.AddAnnotations(
                                                                                                      new[]
            {
                Tuple.Create <SyntaxToken, SyntaxAnnotation>(firstToken, firstTokenAnnotation),
                Tuple.Create <SyntaxToken, SyntaxAnnotation>(lastToken, lastTokenAnnotation)
            })), cancellationToken).ConfigureAwait(false);

            if (selectionInExpression)
            {
                return(new ExpressionResult(
                           status, originalSpan, finalSpan, options, selectionInExpression,
                           newDocument, firstTokenAnnotation, lastTokenAnnotation));
            }
            else
            {
                return(new StatementResult(
                           status, originalSpan, finalSpan, options, selectionInExpression,
                           newDocument, firstTokenAnnotation, lastTokenAnnotation));
            }
        }
Exemple #21
0
        public async Task <ImmutableArray <CodeAction> > GenerateTypeAsync(
            Document document,
            SyntaxNode node,
            CancellationToken cancellationToken
            )
        {
            using (Logger.LogBlock(FunctionId.Refactoring_GenerateType, cancellationToken))
            {
                var semanticDocument = await SemanticDocument
                                       .CreateAsync(document, cancellationToken)
                                       .ConfigureAwait(false);

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

                if (state != null)
                {
                    var actions = GetActions(semanticDocument, node, state, cancellationToken);
                    if (actions.Length > 1)
                    {
                        // Wrap the generate type actions into a single top level suggestion
                        // so as to not clutter the list.
                        return(ImmutableArray.Create <CodeAction>(
                                   new MyCodeAction(
                                       string.Format(FeaturesResources.Generate_type_0, state.Name),
                                       actions.AsImmutable()
                                       )
                                   ));
                    }
                    else
                    {
                        return(actions);
                    }
                }

                return(ImmutableArray <CodeAction> .Empty);
            }
        }
        public async Task <ExtractMethodResult> ExtractMethodAsync(
            Document document,
            TextSpan textSpan,
            bool localFunction,
            OptionSet options,
            CancellationToken cancellationToken)
        {
            options ??= await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false);

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

            var validator = CreateSelectionValidator(semanticDocument, textSpan, options);

            var selectionResult = await validator.GetValidSelectionAsync(cancellationToken).ConfigureAwait(false);

            if (!selectionResult.ContainsValidContext)
            {
                return(new FailedExtractMethodResult(selectionResult.Status));
            }

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

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

            if (localFunction && syntaxFacts.ContainsGlobalStatement(root))
            {
                // ExtractLocalFunction doesn't yet support local functions in top-level statements
                // https://github.com/dotnet/roslyn/issues/44260
                return(new FailedExtractMethodResult(OperationStatus.FailedWithUnknownReason));
            }

            cancellationToken.ThrowIfCancellationRequested();

            // extract method
            var extractor = CreateMethodExtractor((TResult)selectionResult, localFunction);

            return(await extractor.ExtractMethodAsync(cancellationToken).ConfigureAwait(false));
        }
Exemple #23
0
        public async Task <IntroduceVariableResult> IntroduceVariableAsync(
            Document document,
            TextSpan textSpan,
            CancellationToken cancellationToken)
        {
            var semanticDocument = await SemanticDocument.CreateAsync(document, cancellationToken).ConfigureAwait(false);

            var state = State.Generate((TService)this, semanticDocument, textSpan, cancellationToken);

            if (state == null)
            {
                return(IntroduceVariableResult.Failure);
            }

            var actions = await CreateActionsAsync(state, cancellationToken).ConfigureAwait(false);

            if (actions.Count == 0)
            {
                return(IntroduceVariableResult.Failure);
            }

            return(new IntroduceVariableResult(new CodeRefactoring(null, actions)));
        }
Exemple #24
0
        public async Task <ImmutableArray <CodeAction> > GetRefactoringAsync(Document document, TextSpan textSpan, CancellationToken cancellationToken)
        {
            var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            if (!ShouldAnalyze(root, textSpan))
            {
                return(default(ImmutableArray <CodeAction>));
            }

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

            var state = State.Generate((TService)this, semanticDocument, textSpan, cancellationToken);

            if (state == null)
            {
                return(default(ImmutableArray <CodeAction>));
            }

            var actions = CreateActions(state, cancellationToken);

            Debug.Assert(actions.Count() != 0, "No code actions found for MoveType Refactoring");
            return(actions);
        }
Exemple #25
0
        protected static async Task IterateAllAsync(string code)
        {
            using var workspace = TestWorkspace.CreateCSharp(
                      code,
                      CodeAnalysis.CSharp.Test.Utilities.TestOptions.Regular
                      );
            var document = workspace.CurrentSolution.GetDocument(workspace.Documents.First().Id);

            Assert.NotNull(document);

            var semanticDocument = await SemanticDocument.CreateAsync(
                document,
                CancellationToken.None
                );

            var root = await document.GetSyntaxRootAsync();

            var iterator = root.DescendantNodesAndSelf().Cast <SyntaxNode>();

            var originalOptions = await document.GetOptionsAsync();

            foreach (var node in iterator)
            {
                var validator = new CSharpSelectionValidator(
                    semanticDocument,
                    node.Span,
                    originalOptions
                    );
                var result = await validator.GetValidSelectionAsync(CancellationToken.None);

                // check the obvious case
                if (!(node is ExpressionSyntax) && !node.UnderValidContext())
                {
                    Assert.True(result.Status.FailedWithNoBestEffortSuggestion());
                }
            }
        }
        private Solution CreateSolutionWithEventHandler(
            Document document,
            string eventHandlerMethodName,
            int position,
            out int plusEqualTokenEndPosition,
            IGlobalOptionService globalOptions,
            CancellationToken cancellationToken)
        {
            _threadingContext.ThrowIfNotOnUIThread();

            // Mark the += token with an annotation so we can find it after formatting
            var plusEqualsTokenAnnotation = new SyntaxAnnotation();

            var documentWithNameAndAnnotationsAdded = AddMethodNameAndAnnotationsToSolution(document, eventHandlerMethodName, position, plusEqualsTokenAnnotation, cancellationToken);
            var semanticDocument = SemanticDocument.CreateAsync(documentWithNameAndAnnotationsAdded, cancellationToken).WaitAndGetResult(cancellationToken);
            var options          = (CSharpCodeGenerationOptions)document.GetCodeGenerationOptionsAsync(globalOptions, cancellationToken).AsTask().WaitAndGetResult(cancellationToken);
            var updatedRoot      = AddGeneratedHandlerMethodToSolution(semanticDocument, options, eventHandlerMethodName, plusEqualsTokenAnnotation, cancellationToken);

            if (updatedRoot == null)
            {
                plusEqualTokenEndPosition = 0;
                return(null);
            }

            var cleanupOptions     = documentWithNameAndAnnotationsAdded.GetCodeCleanupOptionsAsync(globalOptions, cancellationToken).AsTask().WaitAndGetResult(cancellationToken);
            var simplifiedDocument = Simplifier.ReduceAsync(documentWithNameAndAnnotationsAdded.WithSyntaxRoot(updatedRoot), Simplifier.Annotation, cleanupOptions.SimplifierOptions, cancellationToken).WaitAndGetResult(cancellationToken);
            var formattedDocument  = Formatter.FormatAsync(simplifiedDocument, Formatter.Annotation, cleanupOptions.FormattingOptions, cancellationToken).WaitAndGetResult(cancellationToken);

            var newRoot = formattedDocument.GetSyntaxRootSynchronously(cancellationToken);

            plusEqualTokenEndPosition = newRoot.GetAnnotatedNodesAndTokens(plusEqualsTokenAnnotation)
                                        .Single().Span.End;

            return(document.Project.Solution.WithDocumentText(
                       formattedDocument.Id, formattedDocument.GetTextSynchronously(cancellationToken)));
        }
Exemple #27
0
        protected async Task IterateAllAsync(string code)
        {
            using (var workspace = await CSharpWorkspaceFactory.CreateWorkspaceFromLinesAsync(new string[] { code }, CodeAnalysis.CSharp.Test.Utilities.TestOptions.Regular))
            {
                var document = workspace.CurrentSolution.GetDocument(workspace.Documents.First().Id);
                Assert.NotNull(document);

                var semanticDocument = await SemanticDocument.CreateAsync(document, CancellationToken.None);

                var tree = await document.GetSyntaxTreeAsync();

                var iterator = tree.GetRoot().DescendantNodesAndSelf().Cast <SyntaxNode>();

                var options = document.Project.Solution.Workspace.Options
                              .WithChangedOption(ExtractMethodOptions.AllowMovingDeclaration, document.Project.Language, true);

                foreach (var node in iterator)
                {
                    try
                    {
                        var validator = new CSharpSelectionValidator(semanticDocument, node.Span, options);
                        var result    = await validator.GetValidSelectionAsync(CancellationToken.None);

                        // check the obvious case
                        if (!(node is ExpressionSyntax) && !node.UnderValidContext())
                        {
                            Assert.True(result.Status.FailedWithNoBestEffortSuggestion());
                        }
                    }
                    catch (ArgumentException)
                    {
                        // catch and ignore unknown issue. currently control flow analysis engine doesn't support field initializer.
                    }
                }
            }
        }
        protected static SyntaxNode ExtractMethod(
            TestWorkspace workspace,
            TestHostDocument testDocument,
            bool succeed = true,
            bool allowMovingDeclaration  = true,
            bool dontPutOutOrRefOnStruct = true)
        {
            var document = workspace.CurrentSolution.GetDocument(testDocument.Id);

            Assert.NotNull(document);

            var options = document.Project.Solution.Workspace.Options
                          .WithChangedOption(ExtractMethodOptions.AllowMovingDeclaration, document.Project.Language, allowMovingDeclaration)
                          .WithChangedOption(ExtractMethodOptions.DontPutOutOrRefOnStruct, document.Project.Language, dontPutOutOrRefOnStruct);

            var semanticDocument = SemanticDocument.CreateAsync(document, CancellationToken.None).Result;
            var validator        = new CSharpSelectionValidator(semanticDocument, testDocument.SelectedSpans.Single(), options);

            var selectedCode = validator.GetValidSelectionAsync(CancellationToken.None).Result;

            if (!succeed && selectedCode.Status.FailedWithNoBestEffortSuggestion())
            {
                return(null);
            }

            Assert.True(selectedCode.ContainsValidContext);

            // extract method
            var extractor = new CSharpMethodExtractor((CSharpSelectionResult)selectedCode);
            var result    = extractor.ExtractMethodAsync(CancellationToken.None).Result;

            Assert.NotNull(result);
            Assert.Equal(succeed, result.Succeeded || result.SucceededWithSuggestion);

            return((SyntaxNode)result.Document.GetSyntaxRootAsync().Result);
        }
            public async Task <GeneratedCode> GenerateAsync(CancellationToken cancellationToken)
            {
                var root = SemanticDocument.Root;

                // should I check venus hidden position check here as well?
                root = root.ReplaceNode(
                    GetOutermostCallSiteContainerToProcess(cancellationToken),
                    await GenerateBodyForCallSiteContainerAsync(cancellationToken)
                    .ConfigureAwait(false)
                    );
                var callSiteDocument = await SemanticDocument
                                       .WithSyntaxRootAsync(root, cancellationToken)
                                       .ConfigureAwait(false);

                var newCallSiteRoot = callSiteDocument.Root;

                var codeGenerationService =
                    SemanticDocument.Document.GetLanguageService <ICodeGenerationService>();
                var result = GenerateMethodDefinition(LocalFunction, cancellationToken);

                SyntaxNode destination,
                           newContainer;

                if (LocalFunction)
                {
                    destination = InsertionPoint.With(callSiteDocument).GetContext();

                    // No valid location to insert the new method call.
                    if (destination == null)
                    {
                        return(await CreateGeneratedCodeAsync(
                                   OperationStatus.NoValidLocationToInsertMethodCall,
                                   callSiteDocument,
                                   cancellationToken
                                   )
                               .ConfigureAwait(false));
                    }

                    var localMethod = codeGenerationService.CreateMethodDeclaration(
                        method: result.Data,
                        options: new CodeGenerationOptions(
                            generateDefaultAccessibility: false,
                            generateMethodBodies: true,
                            options: Options,
                            parseOptions: destination?.SyntaxTree.Options
                            )
                        );
                    newContainer = codeGenerationService.AddStatements(
                        destination,
                        new[] { localMethod },
                        cancellationToken: cancellationToken
                        );
                }
                else
                {
                    var previousMemberNode = GetPreviousMember(callSiteDocument);

                    // it is possible in a script file case where there is no previous member. in that case, insert new text into top level script
                    destination  = previousMemberNode.Parent ?? previousMemberNode;
                    newContainer = codeGenerationService.AddMethod(
                        destination,
                        result.Data,
                        new CodeGenerationOptions(
                            afterThisLocation: previousMemberNode.GetLocation(),
                            generateDefaultAccessibility: true,
                            generateMethodBodies: true,
                            options: Options
                            ),
                        cancellationToken
                        );
                }

                var newSyntaxRoot = newCallSiteRoot.ReplaceNode(destination, newContainer);
                var newDocument   = callSiteDocument.Document.WithSyntaxRoot(newSyntaxRoot);

                newDocument = await Simplifier
                              .ReduceAsync(newDocument, Simplifier.Annotation, null, cancellationToken)
                              .ConfigureAwait(false);

                var generatedDocument = await SemanticDocument
                                        .CreateAsync(newDocument, cancellationToken)
                                        .ConfigureAwait(false);

                // For nullable reference types, we can provide a better experience by reducing use
                // of nullable reference types after a method is done being generated. If we can
                // determine that the method never returns null, for example, then we can
                // make the signature into a non-null reference type even though
                // the original type was nullable. This allows our code generation to
                // follow our recommendation of only using nullable when necessary.
                // This is done after method generation instead of at analyzer time because it's purely
                // based on the resulting code, which the generator can modify as needed. If return statements
                // are added, the flow analysis could change to indicate something different. It's cleaner to rely
                // on flow analysis of the final resulting code than to try and predict from the analyzer what
                // will happen in the generator.
                var finalDocument = await UpdateMethodAfterGenerationAsync(
                    generatedDocument,
                    result,
                    cancellationToken
                    )
                                    .ConfigureAwait(false);

                var finalRoot = finalDocument.Root;

                var methodDefinition = finalRoot
                                       .GetAnnotatedNodesAndTokens(MethodDefinitionAnnotation)
                                       .FirstOrDefault();

                if (!methodDefinition.IsNode || methodDefinition.AsNode() == null)
                {
                    return(await CreateGeneratedCodeAsync(
                               result.Status.With(OperationStatus.FailedWithUnknownReason),
                               finalDocument,
                               cancellationToken
                               )
                           .ConfigureAwait(false));
                }

                if (
                    methodDefinition.SyntaxTree.IsHiddenPosition(
                        methodDefinition.AsNode().SpanStart,
                        cancellationToken
                        ) ||
                    methodDefinition.SyntaxTree.IsHiddenPosition(
                        methodDefinition.AsNode().Span.End,
                        cancellationToken
                        )
                    )
                {
                    return(await CreateGeneratedCodeAsync(
                               result.Status.With(OperationStatus.OverlapsHiddenPosition),
                               finalDocument,
                               cancellationToken
                               )
                           .ConfigureAwait(false));
                }

                return(await CreateGeneratedCodeAsync(
                           result.Status,
                           finalDocument,
                           cancellationToken
                           )
                       .ConfigureAwait(false));
            }
Exemple #30
0
 public static Task <SemanticDocument> WithSyntaxRootAsync(this SemanticDocument semanticDocument, SyntaxNode root, CancellationToken cancellationToken)
 {
     return(SemanticDocument.CreateAsync(semanticDocument.Document.WithSyntaxRoot(root), cancellationToken));
 }