public async Task <bool> AdjustAsync() { var subjectDocument = _workspace.GetDocument(_subjectFilePath); if (subjectDocument == null) { return(false); } var subjectSemanticModel = await subjectDocument.GetSemanticModelAsync(); if (subjectSemanticModel == null) { return(false); } var subjectSyntaxRoot = await subjectDocument.GetSyntaxRootAsync(); if (subjectSyntaxRoot == null) { return(false); } var namespaceInfos = subjectSyntaxRoot.GetAllNamespaceInfos(_targetNamespace); if (namespaceInfos.Count == 0) { return(false); } var namespaceRenameDict = namespaceInfos.BuildRenameDict(); #region fix refs (adding a new using namespace clauses) var toProcess = new Dictionary <string, List <IFixer> >(); var processedTypes = new HashSet <INamedTypeSymbol>(SymbolEqualityComparer.Default); var foundSyntaxes = ( from snode in subjectSyntaxRoot.DescendantNodes() where snode is TypeDeclarationSyntax || snode is EnumDeclarationSyntax || snode is DelegateDeclarationSyntax select snode ).ToList(); foreach (var foundTypeSyntax in foundSyntaxes) { var symbolInfo = (INamedTypeSymbol?)subjectSemanticModel.GetDeclaredSymbol(foundTypeSyntax); if (symbolInfo == null) { //skip this type continue; } if (processedTypes.Contains(symbolInfo)) { //already processed continue; } var symbolNamespace = symbolInfo.ContainingNamespace.ToDisplayString(); var targetNamespaceInfo = namespaceRenameDict[symbolNamespace]; if (symbolNamespace == targetNamespaceInfo.ModifiedName) { //current symbol is in target namespace already continue; } var foundReferences = (await SymbolFinder.FindReferencesAsync(symbolInfo, _workspace.CurrentSolution)) .Select(r => (Reference: r, IsClass: true)) .ToList(); if (symbolInfo.TypeKind == TypeKind.Class && symbolInfo.IsStatic) { var extensionMethodSymbols = ( from member in symbolInfo.GetMembers() where member is IMethodSymbol let method = member as IMethodSymbol where method.IsStatic where method.IsExtensionMethod select method ) .ToList(); foreach (var extensionMethodSymbol in extensionMethodSymbols) { var methodFoundReferences = await SymbolFinder.FindReferencesAsync(extensionMethodSymbol, _workspace.CurrentSolution); foundReferences.AddRange( methodFoundReferences.Select(r => (Reference: r, IsClass: false) )); } } foreach (var foundReferencePair in foundReferences) { var foundReference = foundReferencePair.Reference; var isClass = foundReferencePair.IsClass; if (foundReference.Definition.ContainingNamespace.ToDisplayString() == targetNamespaceInfo.ModifiedName) { //referenced symbols is in target namespace already continue; } foreach (var location in foundReference.Locations) { if (location.Document.FilePath == null) { //skip this location continue; } if (location.Location.Kind != LocationKind.SourceFile) { //skip this location continue; } if (location.Location.SourceTree == null) { //skip this location continue; } var refDocument = _workspace.GetDocument(location.Location.SourceTree.FilePath); if (refDocument == null) { continue; } var refRoot = await refDocument.GetSyntaxRootAsync(); if (refRoot == null) { //skip this location continue; } var refSyntax = refRoot.FindNode(location.Location.SourceSpan); if (refSyntax == null) { //skip this location continue; } if (refSyntax is TypeConstraintSyntax tcs) { refSyntax = tcs.Type; } if (refSyntax is SimpleBaseTypeSyntax sbts) { refSyntax = sbts.Type; } if (refSyntax is ArgumentSyntax args) { refSyntax = args.Expression; } var refSemanticModel = await refDocument.GetSemanticModelAsync(); if (refSemanticModel == null) { continue; } var refSymbol = refSemanticModel.GetSymbolInfo(refSyntax).Symbol; if (refSymbol == null) { continue; } if (!toProcess.ContainsKey(location.Document.FilePath)) { toProcess[location.Document.FilePath] = new List <IFixer> { new QualifiedNameFixer(_workspace), new NamespaceFixer(_workspace) }; } if (refSyntax.Parent is QualifiedNameSyntax qns) { //replace QualifiedNameSyntax var mqns = qns .WithLeft(SyntaxFactory.ParseName((qns.IsGlobal() ? "global::" : "") + " " + targetNamespaceInfo.ModifiedName)) .WithLeadingTrivia(qns.GetLeadingTrivia()) .WithTrailingTrivia(qns.GetTrailingTrivia()) ; toProcess[location.Document.FilePath].First(f => f.GetType() == typeof(QualifiedNameFixer)) .AddSubject( new QualifiedNameFixer.QualifiedNameFixerArgument( qns, mqns ) ); } else if (refSyntax.Parent is MemberAccessExpressionSyntax maes) { var maesr = maes.UpTo <MemberAccessExpressionSyntax>() !; if (refSymbol.Kind.NotIn(SymbolKind.Property, SymbolKind.Field, SymbolKind.Method)) { var isGlobal = maesr.IsGlobal(); var inss = ( from desc in maesr.DescendantNodes() where desc is IdentifierNameSyntax || desc is GenericNameSyntax select desc ).ToList(); var withoutNamespaceNodes = inss .SkipWhile(s => !ReferenceEquals(s, refSyntax)) .ToList(); var withoutNamespacesText = string.Join(".", withoutNamespaceNodes); if (inss.IndexOf(refSyntax) > 0) //namespace clauses exists { var modifiedMaesr = SyntaxFactory.ParseExpression( (isGlobal ? "global::" : "") + targetNamespaceInfo.ModifiedName + "." + withoutNamespacesText ); toProcess[location.Document.FilePath].First(f => f.GetType() == typeof(QualifiedNameFixer)) .AddSubject( new QualifiedNameFixer.QualifiedNameFixerArgument( maesr, modifiedMaesr ) ); } else { toProcess[location.Document.FilePath].First(f => f.GetType() == typeof(NamespaceFixer)) .AddSubject(targetNamespaceInfo.ModifiedName); } } else { toProcess[location.Document.FilePath].First(f => f.GetType() == typeof(NamespaceFixer)) .AddSubject(targetNamespaceInfo.ModifiedName); } } else { //i don't know why we are here //add a new using clause toProcess[location.Document.FilePath].First(f => f.GetType() == typeof(NamespaceFixer)) .AddSubject(targetNamespaceInfo.ModifiedName); } } } processedTypes.Add(symbolInfo); _namespaceCenter.TypeRemoved(symbolInfo); } foreach (var group in toProcess) { var targetFilePath = group.Key; Debug.WriteLine($"Fix references in {targetFilePath}"); var qnf = group.Value.First(f => f.GetType() == typeof(QualifiedNameFixer)); await qnf.FixAsync(targetFilePath); var nsf = group.Value.First(f => f.GetType() == typeof(NamespaceFixer)); await nsf.FixAsync(targetFilePath); } #endregion await FixSubjectFileNamespacesAsync( subjectDocument, namespaceInfos ); FixReferenceInXamlFiles( namespaceRenameDict, processedTypes ); await RemoveEmptyUsingStatementsAsync(); return(true); }