private static Solution UpdateMainDocument(Document document, SyntaxNode root, MethodDeclarationSyntax method, IEnumerable<IGrouping<Document, ReferenceLocation>> documentGroups) { var mainDocGroup = documentGroups.FirstOrDefault(dg => dg.Key.Equals(document)); SyntaxNode newRoot; if (mainDocGroup == null) { newRoot = root.ReplaceNode(method, method.WithoutTrivia().AddModifiers(staticToken).WithTriviaFrom(method)); } else { var diagnosticNodes = mainDocGroup.Select(referenceLocation => root.FindNode(referenceLocation.Location.SourceSpan)).ToList(); newRoot = root.TrackNodes(diagnosticNodes.Union(new[] { method })); newRoot = newRoot.ReplaceNode(newRoot.GetCurrentNode(method), method.WithoutTrivia().AddModifiers(staticToken).WithTriviaFrom(method)); foreach (var diagnosticNode in diagnosticNodes) { var token = newRoot.FindToken(diagnosticNode.GetLocation().SourceSpan.Start); var tokenParent = token.Parent; if (token.Parent.IsKind(SyntaxKind.IdentifierName)) continue; var invocationExpression = newRoot.GetCurrentNode(diagnosticNode).FirstAncestorOrSelfOfType<InvocationExpressionSyntax>()?.Expression; if (invocationExpression == null || invocationExpression.IsKind(SyntaxKind.IdentifierName)) continue; var memberAccess = invocationExpression as MemberAccessExpressionSyntax; if (memberAccess == null) continue; var newMemberAccessParent = memberAccess.Parent.ReplaceNode(memberAccess, memberAccess.Name) .WithAdditionalAnnotations(Formatter.Annotation); newRoot = newRoot.ReplaceNode(memberAccess.Parent, newMemberAccessParent); } } var newSolution = document.Project.Solution.WithDocumentSyntaxRoot(document.Id, newRoot); return newSolution; }
private static async Task<Solution> UpdateMainDocumentAsync(Document document, string fullMethodName, SyntaxNode root, MethodDeclarationSyntax method, IEnumerable<IGrouping<Document, ReferenceLocation>> documentGroups, CancellationToken cancellationToken) { var mainDocGroup = documentGroups.FirstOrDefault(dg => dg.Key.Equals(document)); SyntaxNode newRoot; if (mainDocGroup == null) { newRoot = root.ReplaceNode(method, method.WithoutTrivia().AddModifiers(staticToken).WithTriviaFrom(method)); } else { var newMemberAccess = (MemberAccessExpressionSyntax)SyntaxFactory.ParseExpression(fullMethodName); newMemberAccess = newMemberAccess.WithExpression( newMemberAccess.Expression.WithAdditionalAnnotations(Simplifier.Annotation)); var diagnosticNodes = mainDocGroup.Select(referenceLocation => root.FindNode(referenceLocation.Location.SourceSpan)).ToList(); newRoot = root.TrackNodes(diagnosticNodes.Union(new[] { method })); var trackedMethod = newRoot.GetCurrentNode(method); var staticMethod = method.WithoutTrivia().AddModifiers(staticToken).WithTriviaFrom(method); newRoot = newRoot.ReplaceNode(trackedMethod, staticMethod); foreach (var diagnosticNode in diagnosticNodes) { var tempDoc = document.WithSyntaxRoot(newRoot); newRoot = await tempDoc.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var semanticModel = await tempDoc.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); var syntaxNode = newRoot.GetCurrentNode(diagnosticNode); var memberAccess = syntaxNode.FirstAncestorOrSelfOfType<MemberAccessExpressionSyntax>(); if (memberAccess?.Expression == null) continue; if (!syntaxNode.Equals(memberAccess.Name)) continue; var memberAccessExpressionSymbol = semanticModel.GetSymbolInfo(memberAccess.Expression).Symbol; var containingMember = memberAccess.FirstAncestorOrSelfThatIsAMember(); var memberSymbol = semanticModel.GetDeclaredSymbol(containingMember); var allContainingTypes = memberSymbol.GetAllContainingTypes().ToList(); var methodTypeSymbol = GetMethodTypeSymbol(memberAccessExpressionSymbol); var expressionToReplaceMemberAccess = allContainingTypes.Any(t => t.Equals(methodTypeSymbol)) // ideally we would check the symbols // but there is a bug on Roslyn 1.0, fixed on 1.1: // https://github.com/dotnet/roslyn/issues/3096 // so if we try to check the method symbol, it fails and always returns null // so if we find a name clash, whatever one, we fall back to the full name ? allContainingTypes.Count(t => t.MemberNames.Any(n => n == memberSymbol.Name)) > 1 ? (SyntaxNode)newMemberAccess : memberAccess.Name : newMemberAccess; var newMemberAccessParent = memberAccess.Parent.ReplaceNode(memberAccess, expressionToReplaceMemberAccess) .WithAdditionalAnnotations(Formatter.Annotation) .WithAdditionalAnnotations(Simplifier.Annotation); newRoot = newRoot.ReplaceNode(memberAccess.Parent, newMemberAccessParent); } } var newSolution = document.Project.Solution.WithDocumentSyntaxRoot(document.Id, newRoot); return newSolution; }