private bool TryCreateUpdatedSolution(ChangeSignatureAnalyzedContext context, ChangeSignatureOptionsResult options, CancellationToken cancellationToken, out Solution updatedSolution) { updatedSolution = context.Solution; var declaredSymbol = context.Symbol; var nodesToUpdate = new Dictionary<DocumentId, List<SyntaxNode>>(); var definitionToUse = new Dictionary<SyntaxNode, ISymbol>(); bool hasLocationsInMetadata = false; var symbols = FindChangeSignatureReferencesAsync(declaredSymbol, context.Solution, cancellationToken).WaitAndGetResult(cancellationToken); foreach (var symbol in symbols) { if (symbol.Definition.Kind == SymbolKind.Method && ((symbol.Definition as IMethodSymbol).MethodKind == MethodKind.PropertyGet || (symbol.Definition as IMethodSymbol).MethodKind == MethodKind.PropertySet)) { continue; } if (symbol.Definition.Kind == SymbolKind.NamedType) { continue; } if (symbol.Definition.Locations.Any(loc => loc.IsInMetadata)) { hasLocationsInMetadata = true; continue; } var symbolWithSyntacticParameters = symbol.Definition; var symbolWithSemanticParameters = symbol.Definition; var includeDefinitionLocations = true; if (symbol.Definition.Kind == SymbolKind.Field) { includeDefinitionLocations = false; } if (symbolWithSyntacticParameters.Kind == SymbolKind.Event) { var eventSymbol = symbolWithSyntacticParameters as IEventSymbol; var type = eventSymbol.Type as INamedTypeSymbol; if (type != null && type.DelegateInvokeMethod != null) { symbolWithSemanticParameters = type.DelegateInvokeMethod; } else { continue; } } if (symbolWithSyntacticParameters.Kind == SymbolKind.Method) { var methodSymbol = symbolWithSyntacticParameters as IMethodSymbol; if (methodSymbol.MethodKind == MethodKind.DelegateInvoke) { symbolWithSyntacticParameters = methodSymbol.ContainingType; } if (methodSymbol.Name == WellKnownMemberNames.DelegateBeginInvokeName && methodSymbol.ContainingType != null && methodSymbol.ContainingType.IsDelegateType()) { includeDefinitionLocations = false; } } // Find and annotate all the relevant definitions if (includeDefinitionLocations) { foreach (var def in symbolWithSyntacticParameters.Locations) { DocumentId documentId; SyntaxNode nodeToUpdate; if (!TryGetNodeWithEditableSignatureOrAttributes(def, updatedSolution, out nodeToUpdate, out documentId)) { continue; } if (!nodesToUpdate.ContainsKey(documentId)) { nodesToUpdate.Add(documentId, new List<SyntaxNode>()); } AddUpdatableNodeToDictionaries(nodesToUpdate, documentId, nodeToUpdate, definitionToUse, symbolWithSemanticParameters); } } // Find and annotate all the relevant references foreach (var location in symbol.Locations) { if (location.Location.IsInMetadata) { hasLocationsInMetadata = true; continue; } DocumentId documentId2; SyntaxNode nodeToUpdate2; if (!TryGetNodeWithEditableSignatureOrAttributes(location.Location, updatedSolution, out nodeToUpdate2, out documentId2)) { continue; } if (!nodesToUpdate.ContainsKey(documentId2)) { nodesToUpdate.Add(documentId2, new List<SyntaxNode>()); } AddUpdatableNodeToDictionaries(nodesToUpdate, documentId2, nodeToUpdate2, definitionToUse, symbolWithSemanticParameters); } } if (hasLocationsInMetadata) { var notificationService = context.Solution.Workspace.Services.GetService<INotificationService>(); if (!notificationService.ConfirmMessageBox(FeaturesResources.ThisSymbolHasRelatedDefinitionsOrReferencesInMetadata, severity: NotificationSeverity.Warning)) { return false; } } // Construct all the relevant syntax trees from the base solution var updatedRoots = new Dictionary<DocumentId, SyntaxNode>(); foreach (var docId in nodesToUpdate.Keys) { var doc = updatedSolution.GetDocument(docId); var updater = doc.Project.LanguageServices.GetService<AbstractChangeSignatureService>(); var root = doc.GetSyntaxRootAsync(CancellationToken.None).WaitAndGetResult(CancellationToken.None); var nodes = nodesToUpdate[docId]; var newRoot = root.ReplaceNodes(nodes, (originalNode, potentiallyUpdatedNode) => { return updater.ChangeSignature(doc, definitionToUse[originalNode], potentiallyUpdatedNode, originalNode, CreateCompensatingSignatureChange(definitionToUse[originalNode], options.UpdatedSignature), cancellationToken); }); var annotatedNodes = newRoot.GetAnnotatedNodes<SyntaxNode>(syntaxAnnotation: changeSignatureFormattingAnnotation); var formattedRoot = Formatter.Format( newRoot, changeSignatureFormattingAnnotation, doc.Project.Solution.Workspace, options: null, rules: GetFormattingRules(doc), cancellationToken: CancellationToken.None); updatedRoots[docId] = formattedRoot; } // Update the documents using the updated syntax trees foreach (var docId in nodesToUpdate.Keys) { updatedSolution = updatedSolution.WithDocumentSyntaxRoot(docId, updatedRoots[docId]); } return true; }
internal ChangeSignatureResult ChangeSignatureWithContext(ChangeSignatureAnalysisSucceededContext context, ChangeSignatureOptionsResult options, CancellationToken cancellationToken) { var succeeded = TryCreateUpdatedSolution(context, options, cancellationToken, out var updatedSolution); return(new ChangeSignatureResult(succeeded, updatedSolution, context.Symbol.ToDisplayString(), context.Symbol.GetGlyph(), options.PreviewChanges)); }
internal ChangeSignatureResult ChangeSignatureWithContext(ChangeSignatureAnalyzedContext context, ChangeSignatureOptionsResult options, CancellationToken cancellationToken) { Solution updatedSolution; var succeeded = TryCreateUpdatedSolution(context, options, cancellationToken, out updatedSolution); return new ChangeSignatureResult(succeeded, updatedSolution, context.Symbol.ToDisplayString(), context.Symbol.GetGlyph(), options.PreviewChanges); }
private bool TryCreateUpdatedSolution( ChangeSignatureAnalyzedContext context, ChangeSignatureOptionsResult options, CancellationToken cancellationToken, out Solution updatedSolution) { updatedSolution = context.Solution; var declaredSymbol = context.Symbol; var nodesToUpdate = new Dictionary <DocumentId, List <SyntaxNode> >(); var definitionToUse = new Dictionary <SyntaxNode, ISymbol>(); bool hasLocationsInMetadata = false; var symbols = FindChangeSignatureReferencesAsync( SymbolAndProjectId.Create(declaredSymbol, context.Project.Id), context.Solution, cancellationToken).WaitAndGetResult(cancellationToken); foreach (var symbol in symbols) { if (symbol.Definition.Kind == SymbolKind.Method && ((symbol.Definition as IMethodSymbol).MethodKind == MethodKind.PropertyGet || (symbol.Definition as IMethodSymbol).MethodKind == MethodKind.PropertySet)) { continue; } if (symbol.Definition.Kind == SymbolKind.NamedType) { continue; } if (symbol.Definition.Locations.Any(loc => loc.IsInMetadata)) { hasLocationsInMetadata = true; continue; } var symbolWithSyntacticParameters = symbol.Definition; var symbolWithSemanticParameters = symbol.Definition; var includeDefinitionLocations = true; if (symbol.Definition.Kind == SymbolKind.Field) { includeDefinitionLocations = false; } if (symbolWithSyntacticParameters.Kind == SymbolKind.Event) { var eventSymbol = symbolWithSyntacticParameters as IEventSymbol; var type = eventSymbol.Type as INamedTypeSymbol; if (type != null && type.DelegateInvokeMethod != null) { symbolWithSemanticParameters = type.DelegateInvokeMethod; } else { continue; } } if (symbolWithSyntacticParameters.Kind == SymbolKind.Method) { var methodSymbol = symbolWithSyntacticParameters as IMethodSymbol; if (methodSymbol.MethodKind == MethodKind.DelegateInvoke) { symbolWithSyntacticParameters = methodSymbol.ContainingType; } if (methodSymbol.Name == WellKnownMemberNames.DelegateBeginInvokeName && methodSymbol.ContainingType != null && methodSymbol.ContainingType.IsDelegateType()) { includeDefinitionLocations = false; } } // Find and annotate all the relevant definitions if (includeDefinitionLocations) { foreach (var def in symbolWithSyntacticParameters.Locations) { if (!TryGetNodeWithEditableSignatureOrAttributes(def, updatedSolution, out var nodeToUpdate, out var documentId)) { continue; } if (!nodesToUpdate.ContainsKey(documentId)) { nodesToUpdate.Add(documentId, new List <SyntaxNode>()); } AddUpdatableNodeToDictionaries(nodesToUpdate, documentId, nodeToUpdate, definitionToUse, symbolWithSemanticParameters); } } // Find and annotate all the relevant references foreach (var location in symbol.Locations) { if (location.Location.IsInMetadata) { hasLocationsInMetadata = true; continue; } if (!TryGetNodeWithEditableSignatureOrAttributes(location.Location, updatedSolution, out var nodeToUpdate2, out var documentId2)) { continue; } if (!nodesToUpdate.ContainsKey(documentId2)) { nodesToUpdate.Add(documentId2, new List <SyntaxNode>()); } AddUpdatableNodeToDictionaries(nodesToUpdate, documentId2, nodeToUpdate2, definitionToUse, symbolWithSemanticParameters); } } if (hasLocationsInMetadata) { var notificationService = context.Solution.Workspace.Services.GetService <INotificationService>(); if (!notificationService.ConfirmMessageBox(FeaturesResources.This_symbol_has_related_definitions_or_references_in_metadata_Changing_its_signature_may_result_in_build_errors_Do_you_want_to_continue, severity: NotificationSeverity.Warning)) { return(false); } } // Construct all the relevant syntax trees from the base solution var updatedRoots = new Dictionary <DocumentId, SyntaxNode>(); foreach (var docId in nodesToUpdate.Keys) { var doc = updatedSolution.GetDocument(docId); var updater = doc.Project.LanguageServices.GetService <AbstractChangeSignatureService>(); var root = doc.GetSyntaxRootSynchronously(CancellationToken.None); var nodes = nodesToUpdate[docId]; var newRoot = root.ReplaceNodes(nodes, (originalNode, potentiallyUpdatedNode) => { return(updater.ChangeSignature(doc, definitionToUse[originalNode], potentiallyUpdatedNode, originalNode, CreateCompensatingSignatureChange(definitionToUse[originalNode], options.UpdatedSignature), cancellationToken)); }); var annotatedNodes = newRoot.GetAnnotatedNodes <SyntaxNode>(syntaxAnnotation: changeSignatureFormattingAnnotation); var formattedRoot = Formatter.FormatAsync( newRoot, changeSignatureFormattingAnnotation, doc.Project.Solution.Workspace, options: null, rules: GetFormattingRules(doc), cancellationToken: CancellationToken.None).WaitAndGetResult(CancellationToken.None); updatedRoots[docId] = formattedRoot; } // Update the documents using the updated syntax trees foreach (var docId in nodesToUpdate.Keys) { updatedSolution = updatedSolution.WithDocumentSyntaxRoot(docId, updatedRoots[docId]); } return(true); }