Beispiel #1
0
        public static async Task <Document> ConvertToTopLevelStatementsAsync(
            Document document, MethodDeclarationSyntax methodDeclaration, CodeCleanupOptionsProvider fallbackOptions, CancellationToken cancellationToken)
        {
            var typeDeclaration = (TypeDeclarationSyntax?)methodDeclaration.Parent;

            Contract.ThrowIfNull(typeDeclaration); // checked by analyzer

            var generator = document.GetRequiredLanguageService <SyntaxGenerator>();
            var root      = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

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

            var rootWithGlobalStatements = GetRootWithGlobalStatements(
                semanticModel, generator, root, typeDeclaration, methodDeclaration, cancellationToken);

            // simple case.  we were in a top level type to begin with.  Nothing we need to do now.
            if (typeDeclaration.Parent is not BaseNamespaceDeclarationSyntax namespaceDeclaration)
            {
                return(document.WithSyntaxRoot(rootWithGlobalStatements));
            }

            // We were parented by a namespace.  Add using statements to bring in all the symbols that were
            // previously visible within the namespace.  Then remove any that we don't need once we've done that.
            var cleanupOptions = await document.GetCodeCleanupOptionsAsync(fallbackOptions, cancellationToken).ConfigureAwait(false);

            document = await AddUsingDirectivesAsync(
                document, rootWithGlobalStatements, namespaceDeclaration, cleanupOptions, cancellationToken).ConfigureAwait(false);

            // if we have a file scoped namespace after converting to top-level-statements, then convert it to a
            // block-namespace.  Top level statements and file-scoped-namespaces are not allowed together.
            document = await ConvertFileScopedNamespaceAsync(document, cancellationToken).ConfigureAwait(false);

            return(document);
        }
            public SymbolInlineRenameInfo(
                IEnumerable <IRefactorNotifyService> refactorNotifyServices,
                Document document,
                TextSpan triggerSpan,
                string triggerText,
                ISymbol renameSymbol,
                bool forceRenameOverloads,
                ImmutableArray <DocumentSpan> definitionLocations,
                CodeCleanupOptionsProvider fallbackOptions,
                CancellationToken cancellationToken)
            {
                this.CanRename = true;

                _refactorNotifyServices = refactorNotifyServices;
                _document         = document;
                _fallbackOptions  = fallbackOptions;
                this.RenameSymbol = renameSymbol;

                this.HasOverloads        = RenameLocations.GetOverloadedSymbols(this.RenameSymbol).Any();
                this.MustRenameOverloads = forceRenameOverloads;

                _isRenamingAttributePrefix = CanRenameAttributePrefix(triggerText);
                this.TriggerSpan           = GetReferenceEditSpan(new InlineRenameLocation(document, triggerSpan), triggerText, cancellationToken);

                this.DefinitionLocations = definitionLocations;
            }
 public ChangeSignatureAnalysisSucceededContext(
     Document document, int positionForTypeBinding, ISymbol symbol, ParameterConfiguration parameterConfiguration, CodeCleanupOptionsProvider fallbackOptions)
 {
     Document = document;
     Symbol   = symbol;
     ParameterConfiguration = parameterConfiguration;
     PositionForTypeBinding = positionForTypeBinding;
     FallbackOptions        = fallbackOptions;
 }
        private static async Task <RenameLocations> FindLocationsInCurrentProcessAsync(
            ISymbol symbol, Solution solution, SymbolRenameOptions options, CodeCleanupOptionsProvider cleanupOptions, CancellationToken cancellationToken)
        {
            Contract.ThrowIfNull(symbol);
            using (Logger.LogBlock(FunctionId.Rename_AllRenameLocations, cancellationToken))
            {
                symbol = await ReferenceProcessing.FindDefinitionSymbolAsync(symbol, solution, cancellationToken).ConfigureAwait(false);

                // First, find the direct references just to the symbol being renamed.
                var originalSymbolResult = await AddLocationsReferenceSymbolsAsync(symbol, solution, cancellationToken).ConfigureAwait(false);

                // Next, find references to overloads, if the user has asked to rename those as well.
                var overloadsResult = options.RenameOverloads ? await GetOverloadsAsync(symbol, solution, cancellationToken).ConfigureAwait(false) :
                                      ImmutableArray <SearchResult> .Empty;

                // Finally, include strings/comments if that's what the user wants.
                var(strings, comments) = await ReferenceProcessing.GetRenamableLocationsInStringsAndCommentsAsync(
                    symbol,
                    solution,
                    originalSymbolResult.Locations,
                    options.RenameInStrings,
                    options.RenameInComments,
                    cancellationToken).ConfigureAwait(false);

                var mergedLocations = ImmutableHashSet.CreateBuilder <RenameLocation>();

                using var _1 = ArrayBuilder <ISymbol> .GetInstance(out var mergedReferencedSymbols);

                using var _2 = ArrayBuilder <ReferenceLocation> .GetInstance(out var mergedImplicitLocations);

                var renameMethodGroupReferences = options.RenameOverloads || !GetOverloadedSymbols(symbol).Any();
                foreach (var result in overloadsResult.Concat(originalSymbolResult))
                {
                    mergedLocations.AddRange(renameMethodGroupReferences
                        ? result.Locations
                        : result.Locations.Where(x => x.CandidateReason != CandidateReason.MemberGroup));

                    mergedImplicitLocations.AddRange(result.ImplicitLocations);
                    mergedReferencedSymbols.AddRange(result.ReferencedSymbols);
                }

                // Add string and comment locations to the merged hashset
                // after adding in reference symbols. This allows any references
                // in comments to be resolved as proper references rather than
                // comment resolutions. See https://github.com/dotnet/roslyn/issues/54294
                mergedLocations.AddRange(strings.NullToEmpty());
                mergedLocations.AddRange(comments.NullToEmpty());

                return(new RenameLocations(
                           symbol, solution, options, cleanupOptions,
                           new SearchResult(
                               mergedLocations.ToImmutable(),
                               mergedImplicitLocations.ToImmutable(),
                               mergedReferencedSymbols.ToImmutable())));
            }
        }
 internal static RenameLocations Create(
     ImmutableHashSet <RenameLocation> locations,
     ISymbol symbol,
     Solution solution,
     ImmutableArray <ISymbol> referencedSymbols,
     ImmutableArray <ReferenceLocation> implicitLocations,
     SymbolRenameOptions options,
     CodeCleanupOptionsProvider fallbackOptions)
 {
     return(new RenameLocations(
                symbol, solution, options, fallbackOptions,
                new SearchResult(locations, implicitLocations, referencedSymbols)));
 }
 private RenameLocations(
     ISymbol symbol,
     Solution solution,
     SymbolRenameOptions options,
     CodeCleanupOptionsProvider fallbackOptions,
     SearchResult result)
 {
     Solution        = solution;
     Symbol          = symbol;
     Options         = options;
     FallbackOptions = fallbackOptions;
     _result         = result;
 }
Beispiel #7
0
            internal static State Generate(
                SemanticDocument document, TTypeDeclarationSyntax typeDeclaration, CodeCleanupOptionsProvider fallbackOptions,
                CancellationToken cancellationToken)
            {
                var state = new State(document, fallbackOptions);

                if (!state.TryInitialize(typeDeclaration, cancellationToken))
                {
                    return(null);
                }

                return(state);
            }
 public ExtractInterfaceTypeAnalysisResult(
     Document documentToExtractFrom,
     SyntaxNode typeNode,
     INamedTypeSymbol typeToExtractFrom,
     IEnumerable <ISymbol> extractableMembers,
     CodeCleanupOptionsProvider fallbackOptions)
 {
     CanExtractInterface   = true;
     DocumentToExtractFrom = documentToExtractFrom;
     TypeNode           = typeNode;
     TypeToExtractFrom  = typeToExtractFrom;
     ExtractableMembers = extractableMembers;
     FallbackOptions    = fallbackOptions;
 }
        public override async Task <ImmutableArray <CodeAction> > GetRefactoringAsync(
            Document document, TextSpan textSpan, CodeCleanupOptionsProvider fallbackOptions, CancellationToken cancellationToken)
        {
            var state = await CreateStateAsync(document, textSpan, fallbackOptions, cancellationToken).ConfigureAwait(false);

            if (state == null)
            {
                return(ImmutableArray <CodeAction> .Empty);
            }

            var actions = CreateActions(state, cancellationToken);

            return(actions);
        }
        /// <summary>
        /// Find the locations that need to be renamed.  Can cross process boundaries efficiently to do this.
        /// </summary>
        public static async Task <LightweightRenameLocations> FindRenameLocationsAsync(
            ISymbol symbol, Solution solution, SymbolRenameOptions options, CodeCleanupOptionsProvider fallbackOptions, CancellationToken cancellationToken)
        {
            Contract.ThrowIfNull(solution);
            Contract.ThrowIfNull(symbol);

            cancellationToken.ThrowIfCancellationRequested();

            using (Logger.LogBlock(FunctionId.Renamer_FindRenameLocationsAsync, cancellationToken))
            {
                if (SerializableSymbolAndProjectId.TryCreate(symbol, solution, cancellationToken, out var serializedSymbol))
                {
                    var client = await RemoteHostClient.TryGetClientAsync(solution.Workspace, cancellationToken).ConfigureAwait(false);

                    if (client != null)
                    {
                        var result = await client.TryInvokeAsync <IRemoteRenamerService, SerializableRenameLocations?>(
                            solution,
                            (service, solutionInfo, callbackId, cancellationToken) => service.FindRenameLocationsAsync(solutionInfo, callbackId, serializedSymbol, options, cancellationToken),
                            callbackTarget : new RemoteOptionsProvider <CodeCleanupOptions>(solution.Workspace.Services, fallbackOptions),
                            cancellationToken).ConfigureAwait(false);

                        if (result.HasValue && result.Value != null)
                        {
                            var rehydrated = await TryRehydrateAsync(
                                solution, symbol, fallbackOptions, result.Value, cancellationToken).ConfigureAwait(false);

                            if (rehydrated != null)
                            {
                                return(rehydrated);
                            }
                        }

                        // TODO: do not fall back to in-proc if client is available (https://github.com/dotnet/roslyn/issues/47557)
                    }
                }
            }

            // Couldn't effectively search in OOP. Perform the search in-proc.
            var renameLocations = await HeavyweightRenameLocations.FindLocationsInCurrentProcessAsync(
                symbol, solution, options, fallbackOptions, cancellationToken).ConfigureAwait(false);

            return(new LightweightRenameLocations(
                       symbol, solution, options, fallbackOptions, renameLocations.Locations,
                       renameLocations.ImplicitLocations.IsDefault ? null : renameLocations.ImplicitLocations.Select(loc => SerializableReferenceLocation.Dehydrate(loc, cancellationToken)).ToArray(),
                       renameLocations.ReferencedSymbols.IsDefault ? null : renameLocations.ReferencedSymbols.Select(sym => SerializableSymbolAndProjectId.Dehydrate(solution, sym, cancellationToken)).ToArray()));
        }
 private LightweightRenameLocations(
     ISymbol symbol,
     Solution solution,
     SymbolRenameOptions options,
     CodeCleanupOptionsProvider fallbackOptions,
     ImmutableHashSet <RenameLocation> locations,
     SerializableReferenceLocation[]?implicitLocations,
     SerializableSymbolAndProjectId[]?referencedSymbols)
 {
     Symbol          = symbol;
     Solution        = solution;
     Options         = options;
     FallbackOptions = fallbackOptions;
     Contract.ThrowIfNull(locations);
     Locations          = locations;
     _implicitLocations = implicitLocations;
     _referencedSymbols = referencedSymbols;
 }
 public HeavyweightRenameLocations(
     ISymbol symbol,
     Solution solution,
     SymbolRenameOptions options,
     CodeCleanupOptionsProvider fallbackOptions,
     ImmutableHashSet <RenameLocation> locations,
     ImmutableArray <ReferenceLocation> implicitLocations,
     ImmutableArray <ISymbol> referencedSymbols)
 {
     Solution        = solution;
     Symbol          = symbol;
     Options         = options;
     FallbackOptions = fallbackOptions;
     Contract.ThrowIfNull(locations);
     Locations         = locations;
     ReferencedSymbols = referencedSymbols;
     ImplicitLocations = implicitLocations;
 }
Beispiel #13
0
        private static async Task <Solution> RenameAsync(
            Solution solution,
            IFieldSymbol field,
            string finalName,
            Func <DocumentId, TextSpan, bool> filter,
            CodeCleanupOptionsProvider fallbackOptions,
            CancellationToken cancellationToken)
        {
            var options = new SymbolRenameOptions(
                RenameOverloads: false,
                RenameInStrings: false,
                RenameInComments: false,
                RenameFile: false);

            var initialLocations = await Renamer.FindRenameLocationsAsync(
                solution, field, options, fallbackOptions, cancellationToken).ConfigureAwait(false);

            var resolution = await initialLocations.Filter(filter).ResolveConflictsAsync(
                field, finalName, nonConflictSymbolKeys: default, cancellationToken).ConfigureAwait(false);
        public async Task <ExtractInterfaceTypeAnalysisResult> AnalyzeTypeAtPositionAsync(
            Document document,
            int position,
            TypeDiscoveryRule typeDiscoveryRule,
            CodeCleanupOptionsProvider fallbackOptions,
            CancellationToken cancellationToken)
        {
            var typeNode = await GetTypeDeclarationAsync(document, position, typeDiscoveryRule, cancellationToken).ConfigureAwait(false);

            if (typeNode == null)
            {
                var errorMessage = FeaturesResources.Could_not_extract_interface_colon_The_selection_is_not_inside_a_class_interface_struct;
                return(new ExtractInterfaceTypeAnalysisResult(errorMessage));
            }

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

            var type = semanticModel.GetDeclaredSymbol(typeNode, cancellationToken);

            if (type == null || type.Kind != SymbolKind.NamedType)
            {
                var errorMessage = FeaturesResources.Could_not_extract_interface_colon_The_selection_is_not_inside_a_class_interface_struct;
                return(new ExtractInterfaceTypeAnalysisResult(errorMessage));
            }

            var typeToExtractFrom  = type as INamedTypeSymbol;
            var extractableMembers = typeToExtractFrom.GetMembers().Where(IsExtractableMember);

            if (!extractableMembers.Any())
            {
                var errorMessage = FeaturesResources.Could_not_extract_interface_colon_The_type_does_not_contain_any_member_that_can_be_extracted_to_an_interface;
                return(new ExtractInterfaceTypeAnalysisResult(errorMessage));
            }

            return(new ExtractInterfaceTypeAnalysisResult(document, typeNode, typeToExtractFrom, extractableMembers, fallbackOptions));
        }
Beispiel #15
0
        private static async Task <Solution> RenameAsync(
            Solution solution,
            IFieldSymbol field,
            string finalName,
            Func <Location, bool> filter,
            CodeCleanupOptionsProvider fallbackOptions,
            CancellationToken cancellationToken)
        {
            var options = new SymbolRenameOptions(
                RenameOverloads: false,
                RenameInStrings: false,
                RenameInComments: false,
                RenameFile: false);

            var initialLocations = await Renamer.FindRenameLocationsAsync(
                solution, field, options, fallbackOptions, cancellationToken).ConfigureAwait(false);

            var resolution = await initialLocations.Filter(filter).ResolveConflictsAsync(
                finalName, nonConflictSymbols: null, cancellationToken).ConfigureAwait(false);

            Contract.ThrowIfTrue(resolution.ErrorMessage != null);

            return(resolution.NewSolution);
        }
Beispiel #16
0
 public static AbstractMoveToNamespaceCodeAction Generate(IMoveToNamespaceService changeNamespaceService, MoveToNamespaceAnalysisResult analysisResult, CodeCleanupOptionsProvider cleanupOptions)
 => analysisResult.Container switch
 {
        public override async Task <Solution> GetModifiedSolutionAsync(Document document, TextSpan textSpan, MoveTypeOperationKind operationKind, CodeCleanupOptionsProvider fallbackOptions, CancellationToken cancellationToken)
        {
            var state = await CreateStateAsync(document, textSpan, fallbackOptions, cancellationToken).ConfigureAwait(false);

            if (state == null)
            {
                return(document.Project.Solution);
            }

            var suggestedFileNames = GetSuggestedFileNames(
                state.TypeNode,
                IsNestedType(state.TypeNode),
                state.TypeName,
                state.SemanticDocument.Document.Name,
                state.SemanticDocument.SemanticModel,
                cancellationToken);

            var editor           = Editor.GetEditor(operationKind, (TService)this, state, suggestedFileNames.FirstOrDefault(), cancellationToken);
            var modifiedSolution = await editor.GetModifiedSolutionAsync().ConfigureAwait(false);

            return(modifiedSolution ?? document.Project.Solution);
        }
            public static SyncNamespaceDocumentAction?TryCreate(Document document, IReadOnlyList <string> newFolders, CodeCleanupOptionsProvider fallbackOptions)
            {
                var analysisResult = Analyze(document, newFolders);

                if (analysisResult.HasValue)
                {
                    return(new SyncNamespaceDocumentAction(analysisResult.Value, fallbackOptions));
                }

                return(null);
            }
Beispiel #19
0
 public AbstractMoveToNamespaceCodeAction(IMoveToNamespaceService moveToNamespaceService, MoveToNamespaceAnalysisResult analysisResult, CodeCleanupOptionsProvider cleanupOptions)
 {
     _moveToNamespaceService        = moveToNamespaceService;
     _moveToNamespaceAnalysisResult = analysisResult;
     _cleanupOptions = cleanupOptions;
 }
Beispiel #20
0
 public MoveTypeToNamespaceCodeAction(IMoveToNamespaceService changeNamespaceService, MoveToNamespaceAnalysisResult analysisResult, CodeCleanupOptionsProvider cleanupOptions)
     : base(changeNamespaceService, analysisResult, cleanupOptions)
 {
 }
 public static async ValueTask <CodeCleanupOptions> GetCodeCleanupOptionsAsync(this Document document, CodeCleanupOptionsProvider fallbackOptionsProvider, CancellationToken cancellationToken)
 => await document.GetCodeCleanupOptionsAsync(await ((OptionsProvider <CodeCleanupOptions>)fallbackOptionsProvider).GetOptionsAsync(document.Project.LanguageServices, cancellationToken).ConfigureAwait(false), cancellationToken).ConfigureAwait(false);
        public async Task <ImmutableArray <ExtractInterfaceCodeAction> > GetExtractInterfaceCodeActionAsync(Document document, TextSpan span, CodeCleanupOptionsProvider fallbackOptions, CancellationToken cancellationToken)
        {
            var typeAnalysisResult = await AnalyzeTypeAtPositionAsync(document, span.Start, TypeDiscoveryRule.TypeNameOnly, fallbackOptions, cancellationToken).ConfigureAwait(false);

            return(typeAnalysisResult.CanExtractInterface
                ? ImmutableArray.Create(new ExtractInterfaceCodeAction(this, typeAnalysisResult))
                : ImmutableArray <ExtractInterfaceCodeAction> .Empty);
        }
Beispiel #23
0
        private async Task <Solution> UpdateReferencesAsync(
            bool updateReferences, Solution solution, Document document, IFieldSymbol field, string finalFieldName, string generatedPropertyName, CodeCleanupOptionsProvider fallbackOptions, CancellationToken cancellationToken)
        {
            if (!updateReferences)
            {
                return(solution);
            }

            var projectId = document.Project.Id;

            if (field.IsReadOnly)
            {
                // Inside the constructor we want to rename references the field to the final field name.
                var constructorLocations = GetConstructorLocations(solution, field.ContainingType);
                if (finalFieldName != field.Name && constructorLocations.Count > 0)
                {
                    solution = await RenameAsync(
                        solution, field, finalFieldName,
                        (docId, span) => IntersectsWithAny(docId, span, constructorLocations),
                        fallbackOptions,
                        cancellationToken).ConfigureAwait(false);

                    document = solution.GetDocument(document.Id);
                    var compilation = await document.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);

                    field = field.GetSymbolKey(cancellationToken).Resolve(compilation, cancellationToken: cancellationToken).Symbol as IFieldSymbol;
                    constructorLocations = GetConstructorLocations(solution, field.ContainingType);
                }

                // Outside the constructor we want to rename references to the field to final property name.
                return(await RenameAsync(
                           solution, field, generatedPropertyName,
                           (documentId, span) => !IntersectsWithAny(documentId, span, constructorLocations),
                           fallbackOptions,
                           cancellationToken).ConfigureAwait(false));
            }
            else
            {
                // Just rename everything.
                return(await Renamer.RenameSymbolAsync(
                           solution, field, new SymbolRenameOptions(), generatedPropertyName, cancellationToken).ConfigureAwait(false));
            }
        }
        private async Task <State> CreateStateAsync(Document document, TextSpan textSpan, CodeCleanupOptionsProvider fallbackOptions, CancellationToken cancellationToken)
        {
            var nodeToAnalyze = await GetRelevantNodeAsync(document, textSpan, cancellationToken).ConfigureAwait(false);

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

            var semanticDocument = await SemanticDocument.CreateAsync(document, cancellationToken).ConfigureAwait(false);

            return(State.Generate(semanticDocument, nodeToAnalyze, fallbackOptions, cancellationToken));
        }
Beispiel #25
0
 private State(SemanticDocument document, CodeCleanupOptionsProvider fallbackOptions)
 {
     SemanticDocument = document;
     FallbackOptions  = fallbackOptions;
 }
 private SyncNamespaceDocumentAction(AnalysisResult analysis, CodeCleanupOptionsProvider fallbackOptions)
     : base(ImmutableArray <ErrorResource> .Empty)
 {
     _analysis        = analysis;
     _fallbackOptions = fallbackOptions;
 }
 public abstract Task <Solution?> TryChangeTopLevelNamespacesAsync(Document document, string targetNamespace, CodeCleanupOptionsProvider fallbackOptions, CancellationToken cancellationToken);
 public abstract Task <Solution> ChangeNamespaceAsync(Document document, SyntaxNode container, string targetNamespace, CodeCleanupOptionsProvider fallbackOptions, CancellationToken cancellationToken);