protected override Task <CodeActionOperation?> UpdateProjectAsync(
                Project project,
                bool isPreview,
                CancellationToken cancellationToken
                )
            {
                if (!ShouldAddProjectReference())
                {
                    return(SpecializedTasks.Null <CodeActionOperation>());
                }

                var projectWithAddedReference = project.AddProjectReference(
                    new ProjectReference(FixData.ProjectReferenceToAdd)
                    );
                var applyOperation = new ApplyChangesOperation(projectWithAddedReference.Solution);

                if (isPreview)
                {
                    return(Task.FromResult <CodeActionOperation?>(applyOperation));
                }

                return(Task.FromResult <CodeActionOperation?>(
                           new AddProjectReferenceCodeActionOperation(
                               OriginalDocument.Project.Id,
                               FixData.ProjectReferenceToAdd,
                               applyOperation
                               )
                           ));
            }
예제 #2
0
        protected void Test(
            string markup,
            string expected,
            int actionIndex    = 0,
            bool compareTokens = false)
        {
            if (!markup.Contains('\r'))
            {
                markup = markup.Replace("\n", "\r\n");
            }

            if (!expected.Contains('\r'))
            {
                expected = expected.Replace("\n", "\r\n");
            }

            MarkupTestFile.GetSpan(markup, out string code, out TextSpan span);

            Document document = CreateDocument(code);
            IEnumerable <CodeAction> actions = GetRefactoring(document, span);

            Assert.NotNull(actions);

            CodeAction action = actions.ElementAt(actionIndex);

            Assert.NotNull(action);

            ApplyChangesOperation edit = action.GetOperationsAsync(CancellationToken.None).Result.OfType <ApplyChangesOperation>().First();

            VerifyDocument(expected, compareTokens, edit.ChangedSolution.GetDocument(document.Id));
        }
예제 #3
0
            static async Task AddTextDocumentEdits <T>(
                ArrayBuilder <TextDocumentEdit> textDocumentEdits,
                ApplyChangesOperation applyChangesOperation,
                Solution solution,
                IEnumerable <DocumentId> changedDocuments,
                Func <DocumentId, T?> getNewDocumentFunc,
                Func <DocumentId, T?> getOldDocumentFunc,
                CancellationToken cancellationToken)
                where T : TextDocument
            {
                foreach (var docId in changedDocuments)
                {
                    var newDoc = getNewDocumentFunc(docId);
                    var oldDoc = getOldDocumentFunc(docId);

                    Contract.ThrowIfNull(oldDoc);
                    Contract.ThrowIfNull(newDoc);

                    var oldText = await oldDoc.GetTextAsync(cancellationToken).ConfigureAwait(false);

                    var newText = await newDoc.GetTextAsync(cancellationToken).ConfigureAwait(false);

                    var textChanges = newText.GetTextChanges(oldText);

                    var edits = textChanges.Select(tc => ProtocolConversions.TextChangeToTextEdit(tc, oldText)).ToArray();
                    var documentIdentifier = new VersionedTextDocumentIdentifier {
                        Uri = newDoc.GetURI()
                    };
                    textDocumentEdits.Add(new TextDocumentEdit {
                        TextDocument = documentIdentifier, Edits = edits.ToArray()
                    });
                }
            }
                protected override async Task <IEnumerable <CodeActionOperation> > ComputeOperationsAsync(CancellationToken cancellationToken)
                {
                    var service      = _document.Project.Solution.Workspace.Services.GetService <IMetadataService>();
                    var resolvedPath = _lazyResolvedPath.Value;
                    var reference    = service.GetReference(resolvedPath, MetadataReferenceProperties.Assembly);

                    // First add the "using/import" directive in the code.
                    var node     = _node;
                    var document = _document;

                    _reference.ReplaceNameNode(ref node, ref document, cancellationToken);

                    var newDocument = await _reference.provider.AddImportAsync(
                        node, _reference.SearchResult.NameParts, document, _placeSystemNamespaceFirst, cancellationToken).ConfigureAwait(false);

                    // Now add the actual assembly reference.
                    var newProject = newDocument.Project;

                    newProject = newProject.WithMetadataReferences(
                        newProject.MetadataReferences.Concat(reference));

                    var operation = new ApplyChangesOperation(newProject.Solution);

                    return(SpecializedCollections.SingletonEnumerable <CodeActionOperation>(operation));
                }
예제 #5
0
            protected override async Task <IEnumerable <CodeActionOperation> > ComputeOperationsAsync(
                CancellationToken cancellationToken
                )
            {
                var newSolution = await _createChangedSolutionAsync(cancellationToken)
                                  .ConfigureAwait(false);

                var codeAction = new ApplyChangesOperation(newSolution);

#if CODE_STYLE  // https://github.com/dotnet/roslyn/issues/42218 tracks removing this conditional code.
                return(SpecializedCollections.SingletonEnumerable(codeAction));
#else
                var factory =
                    _startingSolution.Workspace.Services.GetRequiredService <ISymbolRenamedCodeActionOperationFactoryWorkspaceService>();
                return(new CodeActionOperation[]
                {
                    codeAction,
                    factory.CreateSymbolRenamedOperation(
                        _symbol,
                        _newName,
                        _startingSolution,
                        newSolution
                        )
                }.AsEnumerable());
#endif
            }
                private async Task <ImmutableArray <CodeActionOperation> > GetOperationsAsync(
                    string versionOpt,
                    bool isLocal,
                    Document document,
                    SyntaxNode node,
                    bool placeSystemNamespaceFirst,
                    CancellationToken cancellationToken)
                {
                    _reference.ReplaceNameNode(ref node, ref document, cancellationToken);

                    var newDocument = await _reference.provider.AddImportAsync(
                        node, _reference.SearchResult.NameParts, document, placeSystemNamespaceFirst, cancellationToken).ConfigureAwait(false);

                    var newSolution = newDocument.Project.Solution;

                    var operation1 = new ApplyChangesOperation(newSolution);

                    var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);

                    var operation2 = new InstallNugetPackageOperation(
                        _reference._installerService, document, _reference._source, _reference._packageName, versionOpt, isLocal);

                    var operations = ImmutableArray.Create <CodeActionOperation>(operation1, operation2);

                    return(operations);
                }
예제 #7
0
            private async Task <IEnumerable <CodeActionOperation> > ComputeOperationsAsync(
                bool isPreview,
                CancellationToken cancellationToken
                )
            {
                var newDocument = await GetUpdatedDocumentAsync(cancellationToken)
                                  .ConfigureAwait(false);

                var newProject = newDocument.Project;

                if (isPreview)
                {
                    // If this is a preview, just return an ApplyChangesOperation for the updated document
                    var operation = new ApplyChangesOperation(newProject.Solution);
                    return(SpecializedCollections.SingletonEnumerable <CodeActionOperation>(
                               operation
                               ));
                }
                else
                {
                    // Otherwise return an operation that can apply the text changes and add the reference
                    var operation = new AddAssemblyReferenceCodeActionOperation(
                        FixData.AssemblyReferenceAssemblyName,
                        FixData.AssemblyReferenceFullyQualifiedTypeName,
                        newProject
                        );
                    return(SpecializedCollections.SingletonEnumerable <CodeActionOperation>(
                               operation
                               ));
                }
            }
예제 #8
0
            private async Task <ImmutableArray <CodeActionOperation> > GetOperationsAsync(
                Document document, SyntaxNode node, bool placeSystemNamespaceFirst, CancellationToken cancellationToken)
            {
                var newSolution = await UpdateSolutionAsync(document, node, placeSystemNamespaceFirst, cancellationToken).ConfigureAwait(false);

                var operation = new ApplyChangesOperation(newSolution);

                return(ImmutableArray.Create <CodeActionOperation>(operation));
            }
 public AddProjectReferenceCodeActionOperation(
     ProjectId referencingProject,
     ProjectId referencedProject,
     ApplyChangesOperation applyOperation
     )
 {
     _referencingProject = referencingProject;
     _referencedProject  = referencedProject;
     _applyOperation     = applyOperation;
 }
예제 #10
0
            private async Task <CodeActionOperation> GetOperationAsync(
                Document document, SyntaxNode node, bool placeSystemNamespaceFirst,
                CancellationToken cancellationToken)
            {
                var newDocument = await UpdateDocumentAsync(document, node, placeSystemNamespaceFirst, cancellationToken).ConfigureAwait(false);

                var updatedSolution = GetUpdatedSolution(newDocument);

                var operation = new ApplyChangesOperation(updatedSolution);

                return(operation);
            }
        private bool ApplyWorker(Workspace workspace, Solution originalSolution, IProgressTracker progressTracker, CancellationToken cancellationToken)
        {
            if (ConfirmationMessage != null)
            {
                var notificationService = workspace.Services.GetRequiredService <INotificationService>();
                if (!notificationService.ConfirmMessageBox(ConfirmationMessage, severity: NotificationSeverity.Warning))
                {
                    return(false);
                }
            }

            return(ApplyChangesOperation.ApplyOrMergeChanges(workspace, originalSolution, ChangedSolution, progressTracker, cancellationToken));
        }
                protected override async Task<IEnumerable<CodeActionOperation>> ComputeOperationsAsync(CancellationToken cancellationToken)
                {
                    var service = OriginalDocument.Project.Solution.Workspace.Services.GetService<IMetadataService>();
                    var resolvedPath = _lazyResolvedPath.Value;
                    var reference = service.GetReference(resolvedPath, MetadataReferenceProperties.Assembly);
    
                    var newDocument = await GetUpdatedDocumentAsync(cancellationToken).ConfigureAwait(false);

                    // Now add the actual assembly reference.
                    var newProject = newDocument.Project;
                    newProject = newProject.WithMetadataReferences(
                        newProject.MetadataReferences.Concat(reference));

                    var operation = new ApplyChangesOperation(newProject.Solution);
                    return SpecializedCollections.SingletonEnumerable<CodeActionOperation>(operation);
                }
        private async Task <SourceText> GetUpdatedApiAsync(string source, int diagnosticIndex, CancellationToken cancellationToken)
        {
            var fixes = await this.GetOfferedCSharpFixesAsync(source, diagnosticIndex, cancellationToken).ConfigureAwait(false);

            Assert.Equal(1, fixes.Item2.Length);

            var operations = await fixes.Item2[0].GetOperationsAsync(CancellationToken.None).ConfigureAwait(false);

            Assert.Equal(1, operations.Length);
            ApplyChangesOperation operation = operations[0] as ApplyChangesOperation;

            Assert.NotNull(operation);

            var oldSolution       = fixes.Item1;
            var newSolution       = operation.ChangedSolution;
            var solutionChanges   = newSolution.GetChanges(oldSolution);
            var projectChanges    = solutionChanges.GetProjectChanges().Single();
            var changedDocumentId = projectChanges.GetChangedAdditionalDocuments().Single();
            var newDocument       = projectChanges.NewProject.GetAdditionalDocument(changedDocumentId);
            var newText           = await newDocument.GetTextAsync(CancellationToken.None).ConfigureAwait(false);

            return(newText);
        }
        public async Task Test_Reverse()
        {
            string method =
                @"public static void Foo(stirng s{caret}tr) {}";

            var doc = await ClassTemplate.FromMethodAsync(method);

            var actions  = new List <CodeAction>();
            var context  = new CodeRefactoringContext(doc.Document, doc.SelectedNode.Span, (a) => actions.Add(a), CancellationToken.None);
            var provider = new CodeContractor.Refactorings.AddRequiresRefactoringProvider();

            provider.ComputeRefactoringsAsync(context).Wait();

            if (actions.Count != 0)
            {
                var operations = await actions[0].GetOperationsAsync(CancellationToken.None);

                Assert.IsNotEmpty(operations);
                ApplyChangesOperation operation = operations.First() as ApplyChangesOperation;

                var changedSolution = operation.ChangedSolution;
            }
        }
            private async Task <IEnumerable <CodeActionOperation> > ComputeOperationsAsync(bool isPreview, CancellationToken cancellationToken)
            {
                var newDocument = await GetUpdatedDocumentAsync(cancellationToken).ConfigureAwait(false);

                var newProject = newDocument.Project;

                // Now add the actual assembly reference.
                if (!isPreview)
                {
                    var resolvedPath = await ResolvePathAsync(cancellationToken).ConfigureAwait(false);

                    if (!string.IsNullOrWhiteSpace(resolvedPath))
                    {
                        var service   = OriginalDocument.Project.Solution.Workspace.Services.GetRequiredService <IMetadataService>();
                        var reference = service.GetReference(resolvedPath, MetadataReferenceProperties.Assembly);
                        newProject = newProject.WithMetadataReferences(
                            newProject.MetadataReferences.Concat(reference));
                    }
                }

                var operation = new ApplyChangesOperation(newProject.Solution);

                return(SpecializedCollections.SingletonEnumerable <CodeActionOperation>(operation));
            }
예제 #16
0
        public virtual async Task <Solution> TryMergeFixesAsync(Solution oldSolution, IEnumerable <CodeAction> codeActions, CancellationToken cancellationToken)
        {
            var changedDocumentsMap = new Dictionary <DocumentId, Document>();
            Dictionary <DocumentId, List <Document> > documentsToMergeMap = null;

            foreach (var codeAction in codeActions)
            {
                cancellationToken.ThrowIfCancellationRequested();

                // TODO: Parallelize GetChangedSolutionInternalAsync for codeActions
                var operations = await codeAction.GetPreviewOperationsAsync(cancellationToken).ConfigureAwait(false);

                ApplyChangesOperation singleApplyChangesOperation = null;
                foreach (var operation in operations)
                {
                    var applyChangesOperation = operation as ApplyChangesOperation;
                    if (applyChangesOperation == null)
                    {
                        continue;
                    }

                    if (singleApplyChangesOperation != null)
                    {
                        // Already had an ApplyChangesOperation; only one is supported.
                        singleApplyChangesOperation = null;
                        break;
                    }

                    singleApplyChangesOperation = applyChangesOperation;
                }

                if (singleApplyChangesOperation == null)
                {
                    continue;
                }

                var changedSolution = singleApplyChangesOperation.ChangedSolution;
                var solutionChanges = changedSolution.GetChanges(oldSolution);

                // TODO: Handle added/removed documents
                // TODO: Handle changed/added/removed additional documents
                var documentIdsWithChanges = solutionChanges
                                             .GetProjectChanges()
                                             .SelectMany(p => p.GetChangedDocuments());

                foreach (var documentId in documentIdsWithChanges)
                {
                    cancellationToken.ThrowIfCancellationRequested();
                    var document = changedSolution.GetDocument(documentId);

                    Document existingDocument;
                    if (changedDocumentsMap.TryGetValue(documentId, out existingDocument))
                    {
                        if (existingDocument != null)
                        {
                            changedDocumentsMap[documentId] = null;
                            var documentsToMerge = new List <Document>();
                            documentsToMerge.Add(existingDocument);
                            documentsToMerge.Add(document);
                            documentsToMergeMap             = documentsToMergeMap ?? new Dictionary <DocumentId, List <Document> >();
                            documentsToMergeMap[documentId] = documentsToMerge;
                        }
                        else
                        {
                            documentsToMergeMap[documentId].Add(document);
                        }
                    }
                    else
                    {
                        changedDocumentsMap[documentId] = document;
                    }
                }
            }

            var currentSolution = oldSolution;

            foreach (var kvp in changedDocumentsMap)
            {
                cancellationToken.ThrowIfCancellationRequested();
                var document = kvp.Value;
                if (document != null)
                {
                    var documentText = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);

                    currentSolution = currentSolution.WithDocumentText(kvp.Key, documentText);
                }
            }

            if (documentsToMergeMap != null)
            {
                var mergedDocuments       = new ConcurrentDictionary <DocumentId, SourceText>();
                var documentsToMergeArray = documentsToMergeMap.ToImmutableArray();
                var mergeTasks            = new Task[documentsToMergeArray.Length];
                for (var i = 0; i < documentsToMergeArray.Length; i++)
                {
                    cancellationToken.ThrowIfCancellationRequested();
                    var kvp              = documentsToMergeArray[i];
                    var documentId       = kvp.Key;
                    var documentsToMerge = kvp.Value;
                    var oldDocument      = oldSolution.GetDocument(documentId);

                    mergeTasks[i] = Task.Run(async() =>
                    {
                        var appliedChanges = (await documentsToMerge[0].GetTextChangesAsync(oldDocument, cancellationToken).ConfigureAwait(false)).ToList();

                        foreach (var document in documentsToMerge.Skip(1))
                        {
                            cancellationToken.ThrowIfCancellationRequested();
                            appliedChanges = await TryAddDocumentMergeChangesAsync(
                                oldDocument,
                                document,
                                appliedChanges,
                                cancellationToken).ConfigureAwait(false);
                        }

                        var oldText = await oldDocument.GetTextAsync(cancellationToken).ConfigureAwait(false);
                        var newText = oldText.WithChanges(appliedChanges);
                        mergedDocuments.TryAdd(documentId, newText);
                    });
                }

                await Task.WhenAll(mergeTasks).ConfigureAwait(false);

                foreach (var kvp in mergedDocuments)
                {
                    cancellationToken.ThrowIfCancellationRequested();
                    currentSolution = currentSolution.WithDocumentText(kvp.Key, kvp.Value);
                }
            }

            return(currentSolution);
        }
예제 #17
0
        public async Task <bool> IncludeCodeActionInRevisionsAsync(Solution oldSolution, CodeAction codeAction, RevisionsTracker revisionsTracker, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();

            ImmutableArray <CodeActionOperation> operations = await codeAction.GetPreviewOperationsAsync(cancellationToken).ConfigureAwait(false);

            ApplyChangesOperation singleApplyChangesOperation = null;

            foreach (var operation in operations)
            {
                if (!(operation is ApplyChangesOperation applyChangesOperation))
                {
                    continue;
                }

                if (singleApplyChangesOperation != null)
                {
                    // Already had an ApplyChangesOperation; only one is supported.
                    singleApplyChangesOperation = null;
                    break;
                }

                singleApplyChangesOperation = applyChangesOperation;
            }

            if (singleApplyChangesOperation == null)
            {
                return(false);
            }

            var changedSolution = singleApplyChangesOperation.ChangedSolution;

            if (await LazinatorCodeFixProvider.WhetherCodeFixFailed(changedSolution))
            {
                return(false);
            }

            var solutionChanges = changedSolution.GetChanges(oldSolution);

            foreach (var projectChange in solutionChanges.GetProjectChanges())
            {
                foreach (var removed in projectChange.GetRemovedDocuments())
                {
                    revisionsTracker.removedDocuments.Add(removed);
                }
            }

            var documentIdsForNew = solutionChanges
                                    .GetProjectChanges()
                                    .SelectMany(p => p.GetAddedDocuments());

            foreach (var documentId in documentIdsForNew)
            {
                if (revisionsTracker.newDocumentsMap.ContainsKey(documentId))
                {
                    throw new LazinatorCodeGenException("Internal exception. Did not expect multiple code fixes to produce same new document.");
                }
                revisionsTracker.newDocumentsMap[documentId] = changedSolution.GetDocument(documentId);
            }

            var documentIdsWithChanges = solutionChanges
                                         .GetProjectChanges()
                                         .SelectMany(p => p.GetChangedDocuments());

            foreach (var documentId in documentIdsWithChanges)
            {
                cancellationToken.ThrowIfCancellationRequested();
                var document = changedSolution.GetDocument(documentId);

                Document existingDocument;
                if (revisionsTracker.changedDocumentsMap.TryGetValue(documentId, out existingDocument))
                {
                    if (existingDocument != null)
                    {
                        revisionsTracker.changedDocumentsMap[documentId] = null;
                        var documentsToMerge = new List <Document>();
                        documentsToMerge.Add(existingDocument);
                        documentsToMerge.Add(document);
                        revisionsTracker.documentsToMergeMap             = revisionsTracker.documentsToMergeMap ?? new Dictionary <DocumentId, List <Document> >();
                        revisionsTracker.documentsToMergeMap[documentId] = documentsToMerge;
                    }
                    else
                    {
                        revisionsTracker.documentsToMergeMap[documentId].Add(document);
                    }
                }
                else
                {
                    revisionsTracker.changedDocumentsMap[documentId] = document;
                }
            }

            return(true);
        }