Exemple #1
0
        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);
        }