Example #1
0
        private async Task <Tuple <IEnumerable <ReferencedSymbol>, Solution> > FindReferencedSymbolsAsync(
            Document document, int position, IWaitContext waitContext)
        {
            var cancellationToken = waitContext.CancellationToken;

            var symbolAndProject = await FindUsagesHelpers.GetRelevantSymbolAndProjectAtPositionAsync(
                document, position, cancellationToken).ConfigureAwait(false);

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

            var symbol  = symbolAndProject?.symbol;
            var project = symbolAndProject?.project;

            var displayName = FindUsagesHelpers.GetDisplayName(symbol);

            waitContext.Message = string.Format(
                EditorFeaturesResources.Finding_references_of_0, displayName);

            var result = await SymbolFinder.FindReferencesAsync(symbol, project.Solution, cancellationToken).ConfigureAwait(false);

            return(Tuple.Create(result, project.Solution));
        }
Example #2
0
        public static bool TryGoToDefinition(
            ISymbol symbol,
            Solution solution,
            IThreadingContext threadingContext,
            IStreamingFindUsagesPresenter streamingPresenter,
            CancellationToken cancellationToken,
            bool thirdPartyNavigationAllowed = true
        )
        {
            var definitions = GetDefinitions(
                symbol,
                solution,
                thirdPartyNavigationAllowed,
                cancellationToken
            );

            var title = string.Format(
                EditorFeaturesResources._0_declarations,
                FindUsagesHelpers.GetDisplayName(symbol)
            );

            return threadingContext.JoinableTaskFactory.Run(
                () =>
                    streamingPresenter.TryNavigateToOrPresentItemsAsync(
                        threadingContext,
                        solution.Workspace,
                        title,
                        definitions,
                        cancellationToken
                    )
            );
        }
Example #3
0
        public async Task FindBasesAsync(Document document, int position, IFindUsagesContext context)
        {
            var cancellationToken   = context.CancellationToken;
            var symbolAndProjectOpt = await FindUsagesHelpers.GetRelevantSymbolAndProjectAtPositionAsync(
                document, position, cancellationToken).ConfigureAwait(false);

            if (symbolAndProjectOpt == null)
            {
                await context.ReportMessageAsync(
                    EditorFeaturesResources.Cannot_navigate_to_the_symbol_under_the_caret).ConfigureAwait(false);

                return;
            }

            var(symbol, project) = symbolAndProjectOpt.Value;

            var bases = FindBaseHelpers.FindBases(
                symbol, project, cancellationToken);

            await context.SetSearchTitleAsync(
                string.Format(EditorFeaturesResources._0_bases,
                              FindUsagesHelpers.GetDisplayName(symbol))).ConfigureAwait(false);

            var found = false;

            // For each potential base, try to find its definition in sources.
            // If found, add it's definitionItem to the context.
            // If not found but the symbol is from metadata, create it's definition item from metadata and add to the context.
            foreach (var baseSymbol in bases)
            {
                var sourceDefinition = await SymbolFinder.FindSourceDefinitionAsync(
                    SymbolAndProjectId.Create(baseSymbol, project.Id), project.Solution, cancellationToken).ConfigureAwait(false);

                if (sourceDefinition.Symbol != null)
                {
                    var definitionItem = await sourceDefinition.Symbol.ToClassifiedDefinitionItemAsync(
                        project.Solution.GetProject(sourceDefinition.ProjectId), includeHiddenLocations : false,
                        FindReferencesSearchOptions.Default, cancellationToken : cancellationToken)
                                         .ConfigureAwait(false);

                    await context.OnDefinitionFoundAsync(definitionItem).ConfigureAwait(false);

                    found = true;
                }
                else if (baseSymbol.Locations.Any(l => l.IsInMetadata))
                {
                    var definitionItem = baseSymbol.ToNonClassifiedDefinitionItem(
                        project, includeHiddenLocations: true);
                    await context.OnDefinitionFoundAsync(definitionItem).ConfigureAwait(false);

                    found = true;
                }
            }

            if (!found)
            {
                await context.ReportMessageAsync(EditorFeaturesResources.The_symbol_has_no_base)
                .ConfigureAwait(false);
            }
        }
Example #4
0
        private async Task StreamingFindBaseSymbolsAsync(
            Document document, int caretPosition,
            IStreamingFindUsagesPresenter presenter)
        {
            try
            {
                using (var token = _asyncListener.BeginAsyncOperation(nameof(StreamingFindBaseSymbolsAsync)))
                {
                    // Let the presented know we're starting a search.
                    var context = presenter.StartSearch(
                        EditorFeaturesResources.Navigating, supportsReferences: true);

                    using (Logger.LogBlock(
                               FunctionId.CommandHandler_FindAllReference,
                               KeyValueLogMessage.Create(LogType.UserAction, m => m["type"] = "streaming"),
                               context.CancellationToken))
                    {
                        try
                        {
#pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task
                            var relevantSymbol = await FindUsagesHelpers.GetRelevantSymbolAndProjectAtPositionAsync(document, caretPosition, context.CancellationToken);

#pragma warning restore CA2007 // Consider calling ConfigureAwait on the awaited task

                            var overriddenSymbol = relevantSymbol?.symbol.GetOverriddenMember();

                            while (overriddenSymbol != null)
                            {
                                if (context.CancellationToken.IsCancellationRequested)
                                {
                                    return;
                                }

                                var definitionItem = overriddenSymbol.ToNonClassifiedDefinitionItem(document.Project.Solution, true);
#pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task
                                await context.OnDefinitionFoundAsync(definitionItem);

#pragma warning restore CA2007 // Consider calling ConfigureAwait on the awaited task

                                // try getting the next one
                                overriddenSymbol = overriddenSymbol.GetOverriddenMember();
                            }
                        }
                        finally
                        {
                            await context.OnCompletedAsync().ConfigureAwait(false);
                        }
                    }
                }
            }
            catch (OperationCanceledException)
            {
            }
            catch (Exception e) when(FatalError.ReportAndCatch(e))
            {
            }
        }
        private async Task FindMemberOverloadsAsync(
            Document document, int caretPosition,
            IStreamingFindUsagesPresenter presenter)
        {
            try
            {
                using (var token = _asyncListener.BeginAsyncOperation(nameof(FindMemberOverloadsAsync)))
                {
                    // Let the presented know we're starting a search.
                    var context = presenter.StartSearch(
                        EditorFeaturesResources.Navigating, supportsReferences: true);

                    using (Logger.LogBlock(
                               FunctionId.CommandHandler_FindAllReference,
                               KeyValueLogMessage.Create(LogType.UserAction, m => m["type"] = "streaming"),
                               context.CancellationToken))
                    {
                        try
                        {
#pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task
                            var candidateSymbolProjectPair = await FindUsagesHelpers.GetRelevantSymbolAndProjectAtPositionAsync(document, caretPosition, context.CancellationToken);

#pragma warning restore CA2007 // Consider calling ConfigureAwait on the awaited task

                            // we need to get the containing type (i.e. class)
                            var symbol = candidateSymbolProjectPair?.symbol;

                            // if we didn't get any symbol, that's it
                            if (symbol == null || symbol.ContainingType == null)
                            {
                                return;
                            }

                            foreach (var curSymbol in symbol.ContainingType.GetMembers()
                                     .Where(m => m.Kind == symbol.Kind && m.Name == symbol.Name))
                            {
                                var definitionItem = curSymbol.ToNonClassifiedDefinitionItem(document.Project.Solution, true);
#pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task
                                await context.OnDefinitionFoundAsync(definitionItem);

#pragma warning restore CA2007 // Consider calling ConfigureAwait on the awaited task
                            }
                        }
                        finally
                        {
                            await context.OnCompletedAsync().ConfigureAwait(false);
                        }
                    }
                }
            }
            catch (OperationCanceledException)
            {
            }
            catch (Exception e) when(FatalError.ReportAndCatch(e))
            {
            }
        }
Example #6
0
        private async Task <INavigableLocation?> GetAlternativeLocationIfAlreadyOnDefinitionAsync(
            Document document, int position, ISymbol symbol, CancellationToken cancellationToken)
        {
            var project  = document.Project;
            var solution = project.Solution;

            var sourceLocations = symbol.Locations.WhereAsArray(loc => loc.IsInSource);

            if (sourceLocations.Length != 1)
            {
                return(null);
            }

            var definitionLocation = sourceLocations[0];

            if (!definitionLocation.SourceSpan.IntersectsWith(position))
            {
                return(null);
            }

            var definitionTree     = definitionLocation.SourceTree;
            var definitionDocument = solution.GetDocument(definitionTree);

            if (definitionDocument != document)
            {
                return(null);
            }

            // Ok, we were already on the definition. Look for better symbols we could show results
            // for instead. For now, just see if we're on an interface member impl. If so, we can
            // instead navigate to the actual interface member.
            //
            // In the future we can expand this with other mappings if appropriate.
            var interfaceImpls = symbol.ExplicitOrImplicitInterfaceImplementations();

            if (interfaceImpls.Length == 0)
            {
                return(null);
            }

            var title = string.Format(EditorFeaturesResources._0_implemented_members,
                                      FindUsagesHelpers.GetDisplayName(symbol));

            using var _ = ArrayBuilder <DefinitionItem> .GetInstance(out var builder);

            foreach (var impl in interfaceImpls)
            {
                builder.AddRange(await GoToDefinitionHelpers.GetDefinitionsAsync(
                                     impl, solution, thirdPartyNavigationAllowed: false, cancellationToken).ConfigureAwait(false));
            }

            var definitions = builder.ToImmutable();

            return(await _streamingPresenter.GetStreamingLocationAsync(
                       _threadingContext, solution.Workspace, title, definitions, cancellationToken).ConfigureAwait(false));
        }
Example #7
0
        private bool TryGoToAlternativeLocationIfAlreadyOnDefinition(
            Document document, int position,
            ISymbol symbol, CancellationToken cancellationToken)
        {
            var project  = document.Project;
            var solution = project.Solution;

            var sourceLocations = symbol.Locations.WhereAsArray(loc => loc.IsInSource);

            if (sourceLocations.Length != 1)
            {
                return(false);
            }

            var definitionLocation = sourceLocations[0];

            if (!definitionLocation.SourceSpan.IntersectsWith(position))
            {
                return(false);
            }

            var definitionTree     = definitionLocation.SourceTree;
            var definitionDocument = solution.GetDocument(definitionTree);

            if (definitionDocument != document)
            {
                return(false);
            }

            // Ok, we were already on the definition. Look for better symbols we could show results
            // for instead. For now, just see if we're on an interface member impl. If so, we can
            // instead navigate to the actual interface member.
            //
            // In the future we can expand this with other mappings if appropriate.
            var interfaceImpls = symbol.ExplicitOrImplicitInterfaceImplementations();

            if (interfaceImpls.Length == 0)
            {
                return(false);
            }

            var definitions = interfaceImpls.SelectMany(
                i => GoToDefinitionHelpers.GetDefinitions(
                    i, solution, thirdPartyNavigationAllowed: false, cancellationToken)).ToImmutableArray();

            var title = string.Format(EditorFeaturesResources._0_implemented_members,
                                      FindUsagesHelpers.GetDisplayName(symbol));

            return(_threadingContext.JoinableTaskFactory.Run(() =>
                                                             _streamingPresenter.TryNavigateToOrPresentItemsAsync(
                                                                 _threadingContext, solution.Workspace, title, definitions, cancellationToken)));
        }
        public static bool TryGoToDefinition(
            ISymbol symbol,
            Solution solution,
            IStreamingFindUsagesPresenter streamingPresenter,
            CancellationToken cancellationToken,
            bool thirdPartyNavigationAllowed = true)
        {
            var definitions = GetDefinitions(symbol, solution, thirdPartyNavigationAllowed, cancellationToken);

            var title = string.Format(EditorFeaturesResources._0_declarations,
                                      FindUsagesHelpers.GetDisplayName(symbol));

            return(streamingPresenter.TryNavigateToOrPresentItemsAsync(
                       solution.Workspace, title, definitions).WaitAndGetResult(cancellationToken));
        }
Example #9
0
        public static async Task <bool> TryGoToDefinitionAsync(
            ISymbol symbol,
            Solution solution,
            IThreadingContext threadingContext,
            IStreamingFindUsagesPresenter streamingPresenter,
            CancellationToken cancellationToken,
            bool thirdPartyNavigationAllowed = true)
        {
            var title = string.Format(EditorFeaturesResources._0_declarations,
                                      FindUsagesHelpers.GetDisplayName(symbol));

            var definitions = await GetDefinitionsAsync(symbol, solution, thirdPartyNavigationAllowed, cancellationToken).ConfigureAwait(false);

            return(await streamingPresenter.TryNavigateToOrPresentItemsAsync(
                       threadingContext, solution.Workspace, title, definitions, cancellationToken).ConfigureAwait(false));
        }
Example #10
0
        internal static bool TryGoToDefinition(
            ISymbol symbol,
            Project project,
            IEnumerable <Lazy <IStreamingFindUsagesPresenter> > streamingPresenters,
            CancellationToken cancellationToken,
            bool thirdPartyNavigationAllowed = true,
            bool throwOnHiddenDefinition     = false)
        {
            var definitions = GetDefinitions(symbol, project, thirdPartyNavigationAllowed, cancellationToken);

            var presenter = streamingPresenters.FirstOrDefault()?.Value;
            var title     = string.Format("_0_declarations",
                                          FindUsagesHelpers.GetDisplayName(symbol));

            return(presenter.TryNavigateToOrPresentItemsAsync(
                       project.Solution.Workspace, title, definitions).WaitAndGetResult(cancellationToken));
        }
        public bool TryGoToImplementation(Document document, int position, CancellationToken cancellationToken, out string message)
        {
            var result = FindUsagesHelpers.FindImplementationsAsync(document, position, cancellationToken).WaitAndGetResult(cancellationToken);

            if (result == null)
            {
                message = EditorFeaturesResources.Cannot_navigate_to_the_symbol_under_the_caret;
                return(false);
            }

            if (result.Value.message != null)
            {
                message = result.Value.message;
                return(false);
            }

            return(TryGoToImplementations(
                       result.Value.symbol, result.Value.project,
                       result.Value.implementations, cancellationToken, out message));
        }
Example #12
0
        public static async Task <(ISymbol symbol, ImmutableArray <SymbolAndProjectId> implementations, string message)?> FindBasesAsync(Document document, int position, CancellationToken cancellationToken)
        {
            var symbolAndProject = await FindUsagesHelpers.GetRelevantSymbolAndProjectAtPositionAsync(
                document, position, cancellationToken).ConfigureAwait(false);

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

            var symbol  = symbolAndProject.Value.symbol;
            var project = symbolAndProject.Value.project;

            var bases = await FindBasesWorkerAsync(symbol, project, cancellationToken).ConfigureAwait(false);

            var filteredSymbols = bases.WhereAsArray(s => s.Symbol.Locations.Any(l => l.IsInSource));

            return(filteredSymbols.Length == 0
                ? (symbol, filteredSymbols, EditorFeaturesResources.The_symbol_has_no_base)
                : (symbol, filteredSymbols, null));
        }
Example #13
0
        public async Task FindBasesAsync(Document document, int position, IFindUsagesContext context)
        {
            var cancellationToken = context.CancellationToken;
            var tuple             = await FindBaseHelpers.FindBasesAsync(document, position, cancellationToken).ConfigureAwait(false);

            if (tuple == null)
            {
                await context.ReportMessageAsync(
                    EditorFeaturesResources.Cannot_navigate_to_the_symbol_under_the_caret).ConfigureAwait(false);

                return;
            }

            var(symbol, implementations, message) = tuple.Value;

            if (message != null)
            {
                await context.ReportMessageAsync(message).ConfigureAwait(false);

                return;
            }

            await context.SetSearchTitleAsync(
                string.Format(EditorFeaturesResources._0_bases,
                              FindUsagesHelpers.GetDisplayName(symbol))).ConfigureAwait(false);

            var solution = document.Project.Solution;

            foreach (var implementation in implementations)
            {
                var definitionItem = await implementation.Symbol.ToClassifiedDefinitionItemAsync(
                    solution.GetProject(implementation.ProjectId), includeHiddenLocations : false,
                    FindReferencesSearchOptions.Default, cancellationToken : cancellationToken).ConfigureAwait(false);

                await context.OnDefinitionFoundAsync(definitionItem).ConfigureAwait(false);
            }
        }
        private async Task FindExtensionMethodsAsync(
            Document document,
            int caretPosition,
            IStreamingFindUsagesPresenter presenter,
            CancellationToken cancellationToken
            )
        {
            try
            {
                using var token = _asyncListener.BeginAsyncOperation(
                          nameof(FindExtensionMethodsAsync)
                          );

                var context = presenter.StartSearch(
                    EditorFeaturesResources.Navigating,
                    supportsReferences: true,
                    cancellationToken
                    );

                using (
                    Logger.LogBlock(
                        FunctionId.CommandHandler_FindAllReference,
                        KeyValueLogMessage.Create(LogType.UserAction, m => m["type"] = "streaming"),
                        context.CancellationToken
                        )
                    )
                {
#pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task
                    var candidateSymbolProjectPair =
                        await FindUsagesHelpers.GetRelevantSymbolAndProjectAtPositionAsync(
                            document,
                            caretPosition,
                            context.CancellationToken
                            );

#pragma warning restore CA2007 // Consider calling ConfigureAwait on the awaited task

                    var symbol = candidateSymbolProjectPair?.symbol as INamedTypeSymbol;

                    // if we didn't get the right symbol, just abort
                    if (symbol == null)
                    {
                        await context.OnCompletedAsync().ConfigureAwait(false);

                        return;
                    }

                    Compilation compilation;
                    if (!document.Project.TryGetCompilation(out compilation))
                    {
                        await context.OnCompletedAsync().ConfigureAwait(false);

                        return;
                    }

                    var solution = document.Project.Solution;

                    foreach (
                        var type in compilation.Assembly.GlobalNamespace.GetAllTypes(
                            context.CancellationToken
                            )
                        )
                    {
                        if (!type.MightContainExtensionMethods)
                        {
                            continue;
                        }

                        foreach (
                            var extMethod in type.GetMembers()
                            .OfType <IMethodSymbol>()
                            .Where(method => method.IsExtensionMethod)
                            )
                        {
                            if (context.CancellationToken.IsCancellationRequested)
                            {
                                break;
                            }

                            var reducedMethod = extMethod.ReduceExtensionMethod(symbol);
                            if (reducedMethod != null)
                            {
                                var loc = extMethod.Locations.First();

                                var sourceDefinition = await SymbolFinder
                                                       .FindSourceDefinitionAsync(
                                    reducedMethod,
                                    solution,
                                    context.CancellationToken
                                    )
                                                       .ConfigureAwait(false);

                                // And if our definition actually is from source, then let's re-figure out what project it came from
                                if (sourceDefinition != null)
                                {
                                    var originatingProject = solution.GetProject(
                                        sourceDefinition.ContainingAssembly,
                                        context.CancellationToken
                                        );

                                    var definitionItem =
                                        reducedMethod.ToNonClassifiedDefinitionItem(solution, true);

#pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task
                                    await context.OnDefinitionFoundAsync(definitionItem);

#pragma warning restore CA2007 // Consider calling ConfigureAwait on the awaited task
                                }
                            }
                        }
                    }

                    await context.OnCompletedAsync().ConfigureAwait(false);
                }
            }
            catch (OperationCanceledException) { }
            catch (Exception e) when(FatalError.ReportAndCatch(e))
            {
            }
        }
Example #15
0
        private async Task FindImplementingMembersAsync(
            Document document,
            int caretPosition,
            IStreamingFindUsagesPresenter presenter,
            CancellationToken cancellationToken
            )
        {
            try
            {
                using var token = _asyncListener.BeginAsyncOperation(
                          nameof(FindImplementingMembersAsync)
                          );

                // Let the presented know we're starting a search.  We pass in no cancellation token here as this
                // operation itself is fire-and-forget and the user won't cancel the operation through us (though
                // the window itself can cancel the operation if it is taken over for another find operation.
                var context = presenter.StartSearch(
                    EditorFeaturesResources.Navigating,
                    supportsReferences: true,
                    cancellationToken
                    );

                using (
                    Logger.LogBlock(
                        FunctionId.CommandHandler_FindAllReference,
                        KeyValueLogMessage.Create(LogType.UserAction, m => m["type"] = "streaming"),
                        context.CancellationToken
                        )
                    )
                {
                    try
                    {
#pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task
                        var relevantSymbol =
                            await FindUsagesHelpers.GetRelevantSymbolAndProjectAtPositionAsync(
                                document,
                                caretPosition,
                                context.CancellationToken
                                );

#pragma warning restore CA2007 // Consider calling ConfigureAwait on the awaited task

                        var interfaceSymbol = relevantSymbol?.symbol as INamedTypeSymbol;

                        if (
                            interfaceSymbol == null ||
                            interfaceSymbol.TypeKind != TypeKind.Interface
                            )
                        {
                            //looks like it's not a relevant symbol
                            return;
                        }

                        // we now need to find the class that implements this particular interface, at the
                        // caret position, or somewhere around it
                        SyntaxNode nodeRoot;
                        if (!document.TryGetSyntaxRoot(out nodeRoot))
                        {
                            return;
                        }

#pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task
                        var syntaxTree = await document.GetSyntaxTreeAsync(cancellationToken);

#pragma warning restore CA2007 // Consider calling ConfigureAwait on the awaited task
                        var documentToken = nodeRoot.FindToken(caretPosition);

                        if (!documentToken.Span.IntersectsWith(caretPosition))
                        {
                            return; // looks like it's not relevant
                        }
                        // the parents should bring us to the class definition
                        var parentTypeNode = documentToken.Parent?.Parent?.Parent?.Parent;
#pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task
                        var compilation = await document.Project.GetCompilationAsync(
                            cancellationToken
                            );

#pragma warning restore CA2007 // Consider calling ConfigureAwait on the awaited task

                        // let's finally get our implementing type
                        var namedTypeSymbol =
                            compilation
                            .GetSemanticModel(syntaxTree)
                            .GetDeclaredSymbol(
                                parentTypeNode,
                                cancellationToken: cancellationToken
                                ) as INamedTypeSymbol;
                        // unless something went wrong, and we got an empty symbol,
                        if (namedTypeSymbol == null)
                        {
                            return;
                        }

                        // we can search for implementations of the interface, within this type
#pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task
                        await InspectInterfaceAsync(
                            context,
                            interfaceSymbol,
                            namedTypeSymbol,
                            document.Project
                            );

#pragma warning restore CA2007 // Consider calling ConfigureAwait on the awaited task

                        // now, we iterate on interfaces of our interfaces
                        foreach (var iFace in interfaceSymbol.AllInterfaces)
                        {
#pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task
                            await InspectInterfaceAsync(
                                context,
                                iFace,
                                namedTypeSymbol,
                                document.Project
                                );

#pragma warning restore CA2007 // Consider calling ConfigureAwait on the awaited task
                        }
                    }
                    finally
                    {
                        await context.OnCompletedAsync().ConfigureAwait(false);
                    }
                }
            }
            catch (OperationCanceledException) { }
            catch (Exception e) when(FatalError.ReportAndCatch(e))
            {
            }
        }
Example #16
0
        private bool TryGoToAlternativeLocationIfAlreadyOnDefinition(
            Document document, int position,
            ISymbol symbol, CancellationToken cancellationToken)
        {
            var project  = document.Project;
            var solution = project.Solution;

            var sourceLocations = symbol.Locations.WhereAsArray(loc => loc.IsInSource);

            if (sourceLocations.Length != 1)
            {
                return(false);
            }

            var definitionLocation = sourceLocations[0];

            if (!definitionLocation.SourceSpan.IntersectsWith(position))
            {
                return(false);
            }

            var definitionTree     = definitionLocation.SourceTree;
            var definitionDocument = solution.GetDocument(definitionTree);

            if (definitionDocument != document)
            {
                return(false);
            }

            // Ok, we were already on the definition. Look for better symbols we could show results
            // for instead. For now, just see if we're on an interface member impl. If so, we can
            // instead navigate to the actual interface member.
            //
            // In the future we can expand this with other mappings if appropriate.
            var interfaceImpls = symbol.ExplicitOrImplicitInterfaceImplementations();

            if (interfaceImpls.Length == 0)
            {
                return(false);
            }

            var title = string.Format(EditorFeaturesResources._0_implemented_members,
                                      FindUsagesHelpers.GetDisplayName(symbol));

            return(_threadingContext.JoinableTaskFactory.Run(async() =>
            {
                using var _ = ArrayBuilder <DefinitionItem> .GetInstance(out var definitions);
                foreach (var impl in interfaceImpls)
                {
                    // Use ConfigureAwait(true) here.  Not for a correctness requirements, but because we're
                    // already blocking the UI thread by being in a JTF.Run call.  So we might as well try to
                    // continue to use the blocking UI thread to do as much work as possible instead of making
                    // it wait for threadpool threads to be available to process the work.
                    definitions.AddRange(await GoToDefinitionHelpers.GetDefinitionsAsync(
                                             impl, solution, thirdPartyNavigationAllowed: false, cancellationToken).ConfigureAwait(true));
                }

                return await _streamingPresenter.TryNavigateToOrPresentItemsAsync(
                    _threadingContext, solution.Workspace, title, definitions.ToImmutable(), cancellationToken).ConfigureAwait(true);
            }));
        }
        private async Task StreamingFindReferencesAsync(
            Document document, int caretPosition, IStreamingFindUsagesPresenter presenter)
        {
            try
            {
                // first, let's see if we even have a comment, otherwise there's no use in starting a search
                var relevantSymbol = await FindUsagesHelpers.GetRelevantSymbolAndProjectAtPositionAsync(document, caretPosition, new CancellationToken()).ConfigureAwait(false);
                var symbol = relevantSymbol?.symbol;
                if (symbol == null)
                    return; // would be useful if we could notify the user why we didn't do anything
                            // maybe using something like an info bar?

                var findUsagesService = document.GetLanguageService<IFindUsagesService>();

                using var token = _asyncListener.BeginAsyncOperation(nameof(StreamingFindReferencesAsync));

                var (context, cancellationToken) = presenter.StartSearch(EditorFeaturesResources.Find_References, supportsReferences: true);

                using (Logger.LogBlock(
                    FunctionId.CommandHandler_FindAllReference,
                    KeyValueLogMessage.Create(LogType.UserAction, m => m["type"] = "streaming"),
                    cancellationToken))
                {
                    var symbolsToLookup = new List<ISymbol>();

                    foreach (var curSymbol in symbol.ContainingType.GetMembers()
                                                    .Where(m => m.Kind == symbol.Kind && m.Name == symbol.Name))
                    {
                        if (!document.Project.TryGetCompilation(out var compilation))
                        {
                            // TODO: should we do anything more here?
                            continue;
                        }

                        foreach (var sym in SymbolFinder.FindSimilarSymbols(curSymbol, compilation, cancellationToken))
                        {
                            // assumption here is, that FindSimilarSymbols returns symbols inside same project
                            var symbolsToAdd = await GatherSymbolsAsync(sym, document.Project.Solution, cancellationToken).ConfigureAwait(false);
                            symbolsToLookup.AddRange(symbolsToAdd);
                        }
                    }

                    foreach (var candidate in symbolsToLookup)
                    {
                        await AbstractFindUsagesService.FindSymbolReferencesAsync(context, candidate, document.Project, cancellationToken).ConfigureAwait(false);
                    }

                    // Note: we don't need to put this in a finally.  The only time we might not hit
                    // this is if cancellation or another error gets thrown.  In the former case,
                    // that means that a new search has started.  We don't care about telling the
                    // context it has completed.  In the latter case something wrong has happened
                    // and we don't want to run any more code in this particular context.
                    await context.OnCompletedAsync(cancellationToken).ConfigureAwait(false);
                }
            }
            catch (OperationCanceledException)
            {
            }
            catch (Exception e) when (FatalError.ReportAndCatch(e))
            {
            }
        }
        public static bool TryGoToDefinition(
            ISymbol symbol,
            Project project,
            IEnumerable <Lazy <IStreamingFindUsagesPresenter> > streamingPresenters,
            CancellationToken cancellationToken,
            bool thirdPartyNavigationAllowed = true,
            bool throwOnHiddenDefinition     = false)
        {
            var alias = symbol as IAliasSymbol;

            if (alias != null)
            {
                var ns = alias.Target as INamespaceSymbol;
                if (ns != null && ns.IsGlobalNamespace)
                {
                    return(false);
                }
            }

            // VB global import aliases have a synthesized SyntaxTree.
            // We can't go to the definition of the alias, so use the target type.

            var solution = project.Solution;

            if (alias != null)
            {
                var sourceLocations = NavigableItemFactory.GetPreferredSourceLocations(
                    solution, symbol, cancellationToken);

                if (sourceLocations.All(l => project.Solution.GetDocument(l.SourceTree) == null))
                {
                    symbol = alias.Target;
                }
            }

            var definition = SymbolFinder.FindSourceDefinitionAsync(symbol, solution, cancellationToken).WaitAndGetResult(cancellationToken);

            cancellationToken.ThrowIfCancellationRequested();

            symbol = definition ?? symbol;

            var definitions = ArrayBuilder <DefinitionItem> .GetInstance();

            if (thirdPartyNavigationAllowed)
            {
                var factory        = solution.Workspace.Services.GetService <IDefinitionsAndReferencesFactory>();
                var thirdPartyItem = factory?.GetThirdPartyDefinitionItem(solution, symbol, cancellationToken);
                definitions.AddIfNotNull(thirdPartyItem);
            }

            // If it is a partial method declaration with no body, choose to go to the implementation
            // that has a method body.
            if (symbol is IMethodSymbol method)
            {
                symbol = method.PartialImplementationPart ?? symbol;
            }

            var options = project.Solution.Options;

            definitions.Add(symbol.ToDefinitionItem(solution, includeHiddenLocations: true));

            var presenter = GetFindUsagesPresenter(streamingPresenters);
            var title     = string.Format(EditorFeaturesResources._0_declarations,
                                          FindUsagesHelpers.GetDisplayName(symbol));

            return(presenter.TryNavigateToOrPresentItemsAsync(
                       title, definitions.ToImmutableAndFree()).WaitAndGetResult(cancellationToken));
        }
Example #19
0
        public async Task <ImmutableArray <INavigableItem> > FindDefinitionsAsync(
            Document document, int position, CancellationToken cancellationToken)
        {
            var symbolService = document.GetRequiredLanguageService <IGoToDefinitionSymbolService>();

            var(symbol, _) = await symbolService.GetSymbolAndBoundSpanAsync(document, position, includeType : true, cancellationToken).ConfigureAwait(false);

            symbol = await SymbolFinder.FindSourceDefinitionAsync(symbol, document.Project.Solution, cancellationToken).ConfigureAwait(false) ?? symbol;

            // Try to compute source definitions from symbol.
            return(symbol != null
                ? NavigableItemFactory.GetItemsFromPreferredSourceLocations(document.Project.Solution, symbol, displayTaggedParts : FindUsagesHelpers.GetDisplayParts(symbol), cancellationToken : cancellationToken)
                : ImmutableArray <INavigableItem> .Empty);
        }
Example #20
0
        public static bool TryGoToDefinition(
            ISymbol symbol,
            Project project,
            IEnumerable <Lazy <IStreamingFindUsagesPresenter> > streamingPresenters,
            CancellationToken cancellationToken,
            bool thirdPartyNavigationAllowed = true,
            bool throwOnHiddenDefinition     = false)
        {
            var alias = symbol as IAliasSymbol;

            if (alias != null)
            {
                var ns = alias.Target as INamespaceSymbol;
                if (ns != null && ns.IsGlobalNamespace)
                {
                    return(false);
                }
            }

            // VB global import aliases have a synthesized SyntaxTree.
            // We can't go to the definition of the alias, so use the target type.

            var solution = project.Solution;

            if (alias != null)
            {
                var sourceLocations = NavigableItemFactory.GetPreferredSourceLocations(
                    solution, symbol, cancellationToken);

                if (sourceLocations.All(l => project.Solution.GetDocument(l.SourceTree) == null))
                {
                    symbol = alias.Target;
                }
            }

            var definition = SymbolFinder.FindSourceDefinitionAsync(symbol, solution, cancellationToken).WaitAndGetResult(cancellationToken);

            cancellationToken.ThrowIfCancellationRequested();

            symbol = definition ?? symbol;

            // If it is a partial method declaration with no body, choose to go to the implementation
            // that has a method body.
            if (symbol is IMethodSymbol method)
            {
                symbol = method.PartialImplementationPart ?? symbol;
            }

            var definitions = ArrayBuilder <DefinitionItem> .GetInstance();

            // Going to a symbol may end up actually showing the symbol in the Find-Usages window.
            // This happens when there is more than one location for the symbol (i.e. for partial
            // symbols) and we don't know the best place to take you to.
            //
            // The FindUsages window supports showing the classified text for an item.  It does this
            // in two ways.  Either the item can pass along its classified text (and the window will
            // defer to that), or the item will have no classified text, and the window will compute
            // it in the BG.
            //
            // Passing along the classified information is valuable for OOP scenarios where we want
            // all that expensive computation done on the OOP side and not in the VS side.
            //
            // However, Go To Definition is all in-process, and is also synchronous.  So we do not
            // want to fetch the classifications here.  It slows down the command and leads to a
            // measurable delay in our perf tests.
            //
            // So, if we only have a single location to go to, this does no unnecessary work.  And,
            // if we do have multiple locations to show, it will just be done in the BG, unblocking
            // this command thread so it can return the user faster.
            var definitionItem = symbol.ToNonClassifiedDefinitionItem(solution, includeHiddenLocations: true);

            if (thirdPartyNavigationAllowed)
            {
                var factory        = solution.Workspace.Services.GetService <IDefinitionsAndReferencesFactory>();
                var thirdPartyItem = factory?.GetThirdPartyDefinitionItem(solution, definitionItem, cancellationToken);
                definitions.AddIfNotNull(thirdPartyItem);
            }

            definitions.Add(definitionItem);

            var presenter = streamingPresenters.FirstOrDefault()?.Value;
            var title     = string.Format(EditorFeaturesResources._0_declarations,
                                          FindUsagesHelpers.GetDisplayName(symbol));

            return(presenter.TryNavigateToOrPresentItemsAsync(
                       project.Solution.Workspace, title, definitions.ToImmutableAndFree()).WaitAndGetResult(cancellationToken));
        }