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 ) )); }
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)); }
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)); }
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); }
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 )); } }
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; }
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)); }
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); }
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); }