private static async Task <AnalysisResult?> AnalyzeAsync(Document document, string newDocumentName, CancellationToken cancellationToken)
            {
                // TODO: Detect naming conflicts ahead of time
                var documentWithNewName = document.WithName(newDocumentName);
                var originalSymbolName  = WorkspacePathUtilities.GetTypeNameFromDocumentName(document);
                var newTypeName         = WorkspacePathUtilities.GetTypeNameFromDocumentName(documentWithNewName);

                if (originalSymbolName is null || newTypeName is null)
                {
                    return(null);
                }

                var matchingDeclaration = await GetMatchingTypeDeclarationAsync(document, originalSymbolName, cancellationToken).ConfigureAwait(false);

                if (matchingDeclaration is null)
                {
                    return(null);
                }

                var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false);

                var symbol = semanticModel.GetDeclaredSymbol(matchingDeclaration, cancellationToken);

                if (symbol is null || WorkspacePathUtilities.TypeNameMatchesDocumentName(documentWithNewName, symbol.Name))
                {
                    return(null);
                }

                return(new AnalysisResult(
                           document,
                           newDocumentName,
                           newTypeName,
                           symbol.Name));
            }
            private static async Task <SyntaxNode?> GetMatchingTypeDeclarationAsync(Document document, string name, CancellationToken cancellationToken)
            {
                var syntaxRoot = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

                var syntaxFacts = document.GetRequiredLanguageService <ISyntaxFactsService>();

                var typeDeclarations = syntaxRoot.DescendantNodesAndSelf(n => !syntaxFacts.IsMethodBody(n)).Where(syntaxFacts.IsTypeDeclaration);

                return(typeDeclarations.FirstOrDefault(d => WorkspacePathUtilities.TypeNameMatchesDocumentName(document, d, syntaxFacts)));
            }
            private static AnalysisResult?Analyze(Document document, IReadOnlyCollection <string> newFolders)
            {
                // https://github.com/dotnet/roslyn/issues/41841
                // VB implementation is incomplete for sync namespace
                if (document.Project.Language == LanguageNames.CSharp)
                {
                    var syntaxFacts     = document.GetRequiredLanguageService <ISyntaxFactsService>();
                    var targetNamespace = WorkspacePathUtilities.TryBuildNamespaceFromFolders(newFolders, syntaxFacts);

                    if (targetNamespace is null)
                    {
                        return(null);
                    }

                    return(new AnalysisResult(targetNamespace));
                }
                else
                {
                    return(null);
                }
            }
            public InlineRenameFileRenameInfo GetFileRenameInfo()
            {
                if (RenameSymbol.Kind == SymbolKind.NamedType &&
                    _document.Project.Solution.Workspace.CanApplyChange(ApplyChangesKind.ChangeDocumentInfo))
                {
                    if (RenameSymbol.Locations.Length > 1)
                    {
                        return(InlineRenameFileRenameInfo.TypeWithMultipleLocations);
                    }

                    // Get the document that the symbol is defined in to compare
                    // the name with the symbol name. If they match allow
                    // rename file rename as part of the symbol rename
                    var symbolSourceDocument = _document.Project.Solution.GetDocument(RenameSymbol.Locations.Single().SourceTree);
                    if (symbolSourceDocument != null && WorkspacePathUtilities.TypeNameMatchesDocumentName(symbolSourceDocument, RenameSymbol.Name))
                    {
                        return(InlineRenameFileRenameInfo.Allowed);
                    }

                    return(InlineRenameFileRenameInfo.TypeDoesNotMatchFileName);
                }

                return(InlineRenameFileRenameInfo.NotAllowed);
            }
            public static async Task <State> CreateAsync(
                AbstractSyncNamespaceCodeRefactoringProvider <TNamespaceDeclarationSyntax, TCompilationUnitSyntax, TMemberDeclarationSyntax> provider,
                Document document,
                TextSpan textSpan,
                CancellationToken cancellationToken)
            {
                // User must put cursor on one of the nodes described below to trigger the refactoring.
                // For each scenario, all requirements must be met. Some of them are checked by `TryGetApplicableInvocationNodeAsync`,
                // rest by `IChangeNamespaceService.CanChangeNamespaceAsync`.
                //
                // - A namespace declaration node that is the only namespace declaration in the document and all types are declared in it:
                //    1. No nested namespace declarations (even it's empty).
                //    2. The cursor is on the name of the namespace declaration.
                //    3. The name of the namespace is valid (i.e. no errors).
                //    4. No partial type declared in the namespace. Otherwise its multiple declaration will
                //       end up in different namespace.
                //
                // - A compilation unit node that contains no namespace declaration:
                //    1. The cursor is on the name of first declared type.
                //    2. No partial type declared in the document. Otherwise its multiple declaration will
                //       end up in different namespace.

                var applicableNode = await provider.TryGetApplicableInvocationNodeAsync(document, textSpan, cancellationToken).ConfigureAwait(false);

                if (applicableNode == null)
                {
                    return(null);
                }

                var changeNamespaceService = document.GetLanguageService <IChangeNamespaceService>();
                var canChange = await changeNamespaceService.CanChangeNamespaceAsync(document, applicableNode, cancellationToken).ConfigureAwait(false);

                if (!canChange || !IsDocumentPathRootedInProjectFolder(document))
                {
                    return(null);
                }

                var syntaxFacts = document.GetLanguageService <ISyntaxFactsService>();

                // We can't determine what the expected namespace would be without knowing the default namespace.
                var defaultNamespace = GetDefaultNamespace(document, syntaxFacts);

                if (defaultNamespace == null)
                {
                    return(null);
                }

                string declaredNamespace;

                if (applicableNode is TCompilationUnitSyntax)
                {
                    declaredNamespace = string.Empty;
                }
                else if (applicableNode is TNamespaceDeclarationSyntax)
                {
                    var syntaxGenerator = SyntaxGenerator.GetGenerator(document);
                    declaredNamespace = syntaxGenerator.GetName(applicableNode);
                }
                else
                {
                    throw ExceptionUtilities.Unreachable;
                }

                // Namespace can't be changed if we can't construct a valid qualified identifier from folder names.
                // In this case, we might still be able to provide refactoring to move file to new location.
                var namespaceFromFolders = WorkspacePathUtilities.TryBuildNamespaceFromFolders(document.Folders, syntaxFacts);
                var targetNamespace      = namespaceFromFolders == null
                    ? null
                    : ConcatNamespace(defaultNamespace, namespaceFromFolders);

                // No action required if namespace already matches folders.
                if (syntaxFacts.StringComparer.Equals(targetNamespace, declaredNamespace))
                {
                    return(null);
                }

                // Only provide "move file" action if default namespace contains declared namespace.
                // For example, if the default namespace is `Microsoft.CodeAnalysis`, and declared
                // namespace is `System.Diagnostics`, it's very likely this document is an outlier
                // in the project and user probably has some special rule for it.
                var relativeNamespace = GetRelativeNamespace(defaultNamespace, declaredNamespace, syntaxFacts);

                return(new State(document, applicableNode, targetNamespace, relativeNamespace));
            }