private void CreateDelegateDeclaration(Document document, FuncOrAction funcOrAction, IParameterSymbol parameterSymbol, out string newDelegateName, out DelegateDeclarationSyntax delegateDeclaration) { var syntaxGenerator = SyntaxGenerator.GetGenerator(document); var parameters = funcOrAction switch { FuncOrAction.Action action => action.Parameters, FuncOrAction.Func func => func.Parameters, _ => throw new System.NotImplementedException() }; newDelegateName = MakeFirstLetterUpperCase(parameterSymbol.Name); delegateDeclaration = (DelegateDeclarationSyntax)syntaxGenerator.DelegateDeclaration( newDelegateName, parameters .Select(p => syntaxGenerator.ParameterDeclaration( p.Name, syntaxGenerator.TypeExpression(p.Type))), accessibility: Accessibility.Public); if (funcOrAction is FuncOrAction.Func func1) { delegateDeclaration = delegateDeclaration .WithReturnType((TypeSyntax)syntaxGenerator.TypeExpression(func1.ReturnType)); } }
private async Task <Solution> UpdateSolutionToAddAndUseANewDelegate( Document document, FuncOrAction funcOrAction, ParameterSyntax parameterSyntax, IParameterSymbol parameterSymbol, SemanticModel semanticModel) { CreateDelegateDeclaration( document, funcOrAction, parameterSymbol, out var newDelegateName, out var delegateDeclaration); var method = (MethodDeclarationSyntax)parameterSyntax.Parent.Parent; var annotationForParameter = new SyntaxAnnotation(); var updatedMethod = method.ReplaceNode(parameterSyntax, parameterSyntax .WithType( SyntaxFactory.IdentifierName(newDelegateName)) .WithAdditionalAnnotations(annotationForParameter)); var root = await document.GetSyntaxRootAsync(); var containingType = (TypeDeclarationSyntax)method.Parent; var containingTypeSymbol = semanticModel.GetDeclaredSymbol(containingType); var syntaxGenerator = SyntaxGenerator.GetGenerator(document); var qualifiedDelegateType = SyntaxFactory.QualifiedName( (NameSyntax)syntaxGenerator.TypeExpression(containingTypeSymbol), SyntaxFactory.IdentifierName(newDelegateName)); var indexOfMethodWithinSiblingMembers = containingType.Members.IndexOf(method); var solution = document.Project.Solution; var updatedRoot = root.ReplaceNodes(new SyntaxNode[] { method, containingType }, (originalNode, possiblyChangedNode) => { if (originalNode == method) { return(updatedMethod); } else if (originalNode == containingType) { var possibleChangedContainingType = (TypeDeclarationSyntax)possiblyChangedNode; var newMembers = possibleChangedContainingType.Members.Insert( indexOfMethodWithinSiblingMembers, delegateDeclaration); return(possibleChangedContainingType .WithMembers(SyntaxFactory.List(newMembers)) .NormalizeWhitespace()); } throw new System.Exception("Unexpected: originalNode is not any of the nodes passed to ReplaceNodes"); }); solution = solution.WithDocumentSyntaxRoot(document.Id, updatedRoot); var newDocument = solution.GetDocument(document.Id); var newSemanticModel = await newDocument.GetSemanticModelAsync(); var newDocumentRootNode = await newDocument.GetSyntaxRootAsync(); var newParameterSyntax = (ParameterSyntax)newDocumentRootNode.GetAnnotatedNodes(annotationForParameter).Single(); var newParameterSymbol = newSemanticModel.GetDeclaredSymbol(newParameterSyntax); var parametersThatAreSourcesOfParameter = await FindSourceParameters( newParameterSymbol, solution); foreach (var callerParameterAndDocument in parametersThatAreSourcesOfParameter) { var callerDocument = callerParameterAndDocument.document; var callerDocumentRoot = await callerDocument.GetSyntaxRootAsync(); var callerParameterSyntax = (ParameterSyntax)callerDocumentRoot.FindNode( callerParameterAndDocument.parameter.Locations.Single().SourceSpan); var newParameterType = callerDocument.Id == document.Id ? (TypeSyntax)SyntaxFactory.IdentifierName(newDelegateName) : qualifiedDelegateType; var updatedCallerParameterSyntax = callerParameterSyntax.WithType(newParameterType); var updatedCallerDocumentRoot = callerDocumentRoot .ReplaceNode(callerParameterSyntax, updatedCallerParameterSyntax); solution = solution.WithDocumentSyntaxRoot(callerDocument.Id, updatedCallerDocumentRoot); } return(solution); }
private async Task <Solution> UpdateSolutionToAddAndUseANewDelegate( Document document, FuncOrAction funcOrAction, ParameterSyntax parameterSyntax, IParameterSymbol parameterSymbol, SemanticModel semanticModel) { var allChanges = new Dictionary <DocumentId, ChangesForDocument>(); void AddChange(DocumentId documentId, Change change) { if (allChanges.TryGetValue(documentId, out var changes)) { allChanges[documentId] = changes.Add(change); } else { allChanges[documentId] = new ChangesForDocument(documentId, ImmutableArray.Create(change)); } } CreateDelegateDeclaration( document, funcOrAction, parameterSymbol, out var newDelegateName, out var delegateDeclaration); var method = (MethodDeclarationSyntax)parameterSyntax.Parent.Parent; var containingType = (TypeDeclarationSyntax)method.Parent; var indexOfMethodWithinSiblingMembers = containingType.Members.IndexOf(method); var changeToAddDelegate = new Change(containingType, x => { var possibleChangedContainingType = (TypeDeclarationSyntax)x; var newMembers = possibleChangedContainingType.Members.Insert( indexOfMethodWithinSiblingMembers, delegateDeclaration); return(possibleChangedContainingType .WithMembers(SyntaxFactory.List(newMembers)) .NormalizeWhitespace()); }); AddChange(document.Id, changeToAddDelegate); var annotationForParameter = new SyntaxAnnotation(); var changeToParameter = new Change(parameterSyntax, x => { var potentiallyChangedParameter = (ParameterSyntax)x; return(potentiallyChangedParameter .WithType( SyntaxFactory.IdentifierName(newDelegateName))); }); AddChange(document.Id, changeToParameter); var containingTypeSymbol = semanticModel.GetDeclaredSymbol(containingType); var syntaxGenerator = SyntaxGenerator.GetGenerator(document); var qualifiedDelegateType = SyntaxFactory.QualifiedName( (NameSyntax)syntaxGenerator.TypeExpression(containingTypeSymbol), SyntaxFactory.IdentifierName(newDelegateName)); var parametersThatAreSourcesOfParameter = await FindSourceParameters( parameterSymbol, document.Project.Solution); foreach (var callerParameterAndDocument in parametersThatAreSourcesOfParameter) { var callerDocument = callerParameterAndDocument.document; var callerDocumentRoot = await callerDocument.GetSyntaxRootAsync(); var callerParameterSyntax = (ParameterSyntax)callerDocumentRoot.FindNode( callerParameterAndDocument.parameter.Locations.Single().SourceSpan); var newParameterType = callerDocument.Id == document.Id ? (TypeSyntax)SyntaxFactory.IdentifierName(newDelegateName) : qualifiedDelegateType; var change = new Change(callerParameterSyntax, x => { var potentiallyChangedParameterSyntax = (ParameterSyntax)x; return(potentiallyChangedParameterSyntax.WithType(newParameterType)); }); AddChange(callerDocument.Id, change); } var changes = allChanges.Values.ToImmutableArray(); return(await ApplyChanges(document.Project.Solution, changes)); }
private async Task <Document> UpdateDocumentToAddAndUseANewDelegate( Document document, FuncOrAction funcOrAction, ParameterSyntax parameterSyntax, IParameterSymbol parameterSymbol, SemanticModel semanticModel) { var syntaxGenerator = SyntaxGenerator.GetGenerator(document); var parameters = funcOrAction switch { FuncOrAction.Action action => action.Parameters, FuncOrAction.Func func => func.Parameters, _ => throw new System.NotImplementedException() }; var newDelegateName = MakeFirstLetterUpperCase(parameterSymbol.Name); var delegateDeclaration = (DelegateDeclarationSyntax)syntaxGenerator.DelegateDeclaration( newDelegateName, parameters .Select(p => syntaxGenerator.ParameterDeclaration( p.Name, syntaxGenerator.TypeExpression(p.Type))), accessibility: Accessibility.Public); if (funcOrAction is FuncOrAction.Func func1) { delegateDeclaration = delegateDeclaration .WithReturnType((TypeSyntax)syntaxGenerator.TypeExpression(func1.ReturnType)); } var method = (MethodDeclarationSyntax)parameterSyntax.Parent.Parent; var updatedMethod = method.ReplaceNode(parameterSyntax.Type, SyntaxFactory.IdentifierName(newDelegateName)); var root = await document.GetSyntaxRootAsync(); var containingType = (TypeDeclarationSyntax)method.Parent; var indexOfMethodWithinSiblingMembers = containingType.Members.IndexOf(method); var updatedRoot = root.ReplaceNodes(new SyntaxNode[] { method, containingType }, (originalNode, possiblyChangedNode) => { if (originalNode == method) { return(updatedMethod); } else if (originalNode == containingType) { var possibleChangedContainingType = (TypeDeclarationSyntax)possiblyChangedNode; var newMembers = possibleChangedContainingType.Members.Insert( indexOfMethodWithinSiblingMembers, delegateDeclaration); return(possibleChangedContainingType.WithMembers(SyntaxFactory.List(newMembers))); } throw new System.Exception("Unexpected: originalNode is not any of the nodes passed to ReplaceNodes"); }); return(document.WithSyntaxRoot(updatedRoot)); }