提交 b5386dea 编写于 作者: C CyrusNajmabadi

Merge branch 'findRefsRQNames1' into findRefsOOPWork

......@@ -77,7 +77,7 @@ public FindReferencesProgressAdapter(Solution solution, IFindUsagesContext conte
public Task OnFindInDocumentCompletedAsync(Document document) => SpecializedTasks.EmptyTask;
// Simple context forwarding functions.
public Task ReportProgressAsync(int current, int maximum) =>
public Task ReportProgressAsync(int current, int maximum) =>
_context.ReportProgressAsync(current, maximum);
// More complicated forwarding functions. These need to map from the symbols
......@@ -129,7 +129,7 @@ public async Task OnReferenceFoundAsync(SymbolAndProjectId definition, Reference
public async Task CallThirdPartyExtensionsAsync(CancellationToken cancellationToken)
{
var factory = _solution.Workspace.Services.GetService<IDefinitionsAndReferencesFactory>();
foreach (var definition in _definitionToItem.Keys)
foreach (var definition in _definitionToItem.Values)
{
var item = factory.GetThirdPartyDefinitionItem(
_solution, definition, cancellationToken);
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Composition;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Completion;
using Microsoft.CodeAnalysis.Features.RQName;
using Microsoft.CodeAnalysis.FindSymbols;
using Microsoft.CodeAnalysis.FindUsages;
using Microsoft.CodeAnalysis.Host;
......@@ -18,7 +18,7 @@ namespace Microsoft.CodeAnalysis.Editor.FindUsages
internal interface IDefinitionsAndReferencesFactory : IWorkspaceService
{
DefinitionItem GetThirdPartyDefinitionItem(
Solution solution, ISymbol definition, CancellationToken cancellationToken);
Solution solution, DefinitionItem definitionItem, CancellationToken cancellationToken);
}
[ExportWorkspaceService(typeof(IDefinitionsAndReferencesFactory)), Shared]
......@@ -29,7 +29,7 @@ internal class DefaultDefinitionsAndReferencesFactory : IDefinitionsAndReference
/// results to the results found by the FindReferences engine.
/// </summary>
public virtual DefinitionItem GetThirdPartyDefinitionItem(
Solution solution, ISymbol definition, CancellationToken cancellationToken)
Solution solution, DefinitionItem definitionItem, CancellationToken cancellationToken)
{
return null;
}
......@@ -59,7 +59,8 @@ internal static class DefinitionItemExtensions
showMetadataSymbolsWithoutReferences: false);
var sourceLocations = ArrayBuilder<DocumentSpan>.GetInstance();
ImmutableDictionary<string, string> properties = null;
var properties = GetProperties(definition);
// If it's a namespace, don't create any normal location. Namespaces
// come from many different sources, but we'll only show a single
......@@ -109,6 +110,30 @@ internal static class DefinitionItemExtensions
nameDisplayParts, properties, displayIfNoReferences);
}
private static ImmutableDictionary<string, string> GetProperties(ISymbol definition)
{
var properties = ImmutableDictionary<string, string>.Empty;
var rqName = RQNameInternal.From(definition);
if (rqName != null)
{
properties = properties.Add(DefinitionItem.RQNameKey1, rqName);
}
if (definition?.IsConstructor() == true)
{
// If the symbol being considered is a constructor include the containing type in case
// a third party wants to navigate to that.
rqName = RQNameInternal.From(definition.ContainingType);
if (rqName != null)
{
properties = properties.Add(DefinitionItem.RQNameKey2, rqName);
}
}
return properties;
}
public static async Task<SourceReferenceItem> TryCreateSourceReferenceItemAsync(
this ReferenceLocation referenceLocation,
DefinitionItem definitionItem,
......
......@@ -53,14 +53,6 @@ internal static class GoToDefinitionHelpers
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)
......@@ -68,40 +60,25 @@ internal static class GoToDefinitionHelpers
symbol = method.PartialImplementationPart ?? symbol;
}
var options = project.Solution.Options;
var definitions = ArrayBuilder<DefinitionItem>.GetInstance();
var definitionItem = symbol.ToDefinitionItemAsync(
solution, includeHiddenLocations: true, cancellationToken: cancellationToken).WaitAndGetResult(cancellationToken);
if (thirdPartyNavigationAllowed)
{
var factory = solution.Workspace.Services.GetService<IDefinitionsAndReferencesFactory>();
var thirdPartyItem = factory?.GetThirdPartyDefinitionItem(solution, definitionItem, cancellationToken);
definitions.AddIfNotNull(thirdPartyItem);
}
definitions.Add(definitionItem);
var presenter = GetFindUsagesPresenter(streamingPresenters);
var presenter = streamingPresenters.FirstOrDefault()?.Value;
var title = string.Format(EditorFeaturesResources._0_declarations,
FindUsagesHelpers.GetDisplayName(symbol));
return presenter.TryNavigateToOrPresentItemsAsync(
title, definitions.ToImmutableAndFree()).WaitAndGetResult(cancellationToken);
}
private static IStreamingFindUsagesPresenter GetFindUsagesPresenter(
IEnumerable<Lazy<IStreamingFindUsagesPresenter>> streamingPresenters)
{
try
{
return streamingPresenters.FirstOrDefault()?.Value;
}
catch
{
return null;
}
}
private static bool TryThirdPartyNavigation(
ISymbol symbol, Solution solution, CancellationToken cancellationToken)
{
var symbolNavigationService = solution.Workspace.Services.GetService<ISymbolNavigationService>();
// Notify of navigation so third parties can intercept the navigation
return symbolNavigationService.TrySymbolNavigationNotify(symbol, solution, cancellationToken);
}
}
}
\ No newline at end of file
......@@ -6,6 +6,7 @@
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Editor.FindUsages;
using Microsoft.CodeAnalysis.Editor.Peek;
using Microsoft.CodeAnalysis.FindSymbols;
using Microsoft.CodeAnalysis.Navigation;
......@@ -59,9 +60,11 @@ private PeekableItemFactory(IMetadataAsSourceFileService metadataAsSourceFileSer
}
var symbolNavigationService = solution.Workspace.Services.GetService<ISymbolNavigationService>();
var definitionItem = await symbol.ToDefinitionItemAsync(
solution, includeHiddenLocations: true, cancellationToken: cancellationToken).ConfigureAwait(false);
if (symbolNavigationService.WouldNavigateToSymbol(
symbol, solution, cancellationToken,
definitionItem, solution, cancellationToken,
out var filePath, out var lineNumber, out var charOffset))
{
var position = new LinePosition(lineNumber, charOffset);
......
......@@ -2,6 +2,7 @@
Imports System.Composition
Imports System.Threading
Imports Microsoft.CodeAnalysis.FindUsages
Imports Microsoft.CodeAnalysis.Host
Imports Microsoft.CodeAnalysis.Host.Mef
Imports Microsoft.CodeAnalysis.Navigation
......@@ -31,7 +32,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Utilities
Public TrySymbolNavigationNotifyProvidedSolution As Solution
Public TrySymbolNavigationNotifyReturnValue As Boolean = False
Public WouldNavigateToSymbolProvidedSymbol As ISymbol
Public WouldNavigateToSymbolProvidedDefinitionItem As DefinitionItem
Public WouldNavigateToSymbolProvidedSolution As Solution
Public WouldNavigateToSymbolReturnValue As Boolean = False
Public NavigationFilePathReturnValue As String = String.Empty
......@@ -54,11 +55,11 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Utilities
Return TrySymbolNavigationNotifyReturnValue
End Function
Public Function WouldNavigateToSymbol(symbol As ISymbol,
Public Function WouldNavigateToSymbol(definitionItem As DefinitionItem,
solution As Solution,
cancellationToken As CancellationToken,
ByRef filePath As String, ByRef lineNumber As Integer, ByRef charOffset As Integer) As Boolean Implements ISymbolNavigationService.WouldNavigateToSymbol
Me.WouldNavigateToSymbolProvidedSymbol = symbol
Me.WouldNavigateToSymbolProvidedDefinitionItem = definitionItem
Me.WouldNavigateToSymbolProvidedSolution = solution
filePath = Me.NavigationFilePathReturnValue
......
......@@ -18,6 +18,13 @@ namespace Microsoft.CodeAnalysis.FindUsages
/// </summary>
internal abstract partial class DefinitionItem
{
// Existing behavior is to do up to two lookups for 3rd party navigation for FAR. One
// for the symbol itself and one for a 'fallback' symbol. For example, if we're FARing
// on a constructor, then the fallback symbol will be the actual type that the constructor
// is contained within.
internal const string RQNameKey1 = nameof(RQNameKey1);
internal const string RQNameKey2 = nameof(RQNameKey2);
/// <summary>
/// Descriptive tags from <see cref="CompletionTags"/>. These tags may influence how the
/// item is displayed.
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Threading;
using Microsoft.CodeAnalysis.FindUsages;
using Microsoft.CodeAnalysis.Options;
namespace Microsoft.CodeAnalysis.Navigation
......@@ -8,17 +9,13 @@ namespace Microsoft.CodeAnalysis.Navigation
internal class DefaultSymbolNavigationService : ISymbolNavigationService
{
public bool TryNavigateToSymbol(ISymbol symbol, Project project, OptionSet options = null, CancellationToken cancellationToken = default(CancellationToken))
{
return false;
}
=> false;
public bool TrySymbolNavigationNotify(ISymbol symbol, Solution solution, CancellationToken cancellationToken)
{
return false;
}
=> false;
public bool WouldNavigateToSymbol(
ISymbol symbol, Solution solution, CancellationToken cancellationToken,
DefinitionItem definitionItem, Solution solution, CancellationToken cancellationToken,
out string filePath, out int lineNumber, out int charOffset)
{
filePath = null;
......@@ -28,4 +25,4 @@ public bool TrySymbolNavigationNotify(ISymbol symbol, Solution solution, Cancell
return false;
}
}
}
}
\ No newline at end of file
......@@ -3,6 +3,7 @@
using Microsoft.CodeAnalysis.Host;
using System.Threading;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.FindUsages;
namespace Microsoft.CodeAnalysis.Navigation
{
......@@ -25,7 +26,7 @@ internal interface ISymbolNavigationService : IWorkspaceService
/// <returns>True if the navigation would be handled.</returns>
bool WouldNavigateToSymbol(
ISymbol symbol, Solution solution, CancellationToken cancellationToken,
DefinitionItem definitionItem, Solution solution, CancellationToken cancellationToken,
out string filePath, out int lineNumber, out int charOffset);
}
}
......@@ -32,11 +32,11 @@ public VisualStudioDefinitionsAndReferencesFactory(SVsServiceProvider servicePro
}
public override DefinitionItem GetThirdPartyDefinitionItem(
Solution solution, ISymbol definition, CancellationToken cancellationToken)
Solution solution, DefinitionItem definitionItem, CancellationToken cancellationToken)
{
var symbolNavigationService = solution.Workspace.Services.GetService<ISymbolNavigationService>();
if (!symbolNavigationService.WouldNavigateToSymbol(
definition, solution, cancellationToken,
definitionItem, solution, cancellationToken,
out var filePath, out var lineNumber, out var charOffset))
{
return null;
......@@ -44,7 +44,7 @@ public VisualStudioDefinitionsAndReferencesFactory(SVsServiceProvider servicePro
var displayParts = GetDisplayParts(filePath, lineNumber, charOffset);
return new ExternalDefinitionItem(
GlyphTags.GetTags(definition.GetGlyph()), displayParts,
definitionItem.Tags, displayParts,
_serviceProvider, filePath, lineNumber, charOffset);
}
......
......@@ -6,8 +6,10 @@
using System.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Editor;
using Microsoft.CodeAnalysis.Editor.FindUsages;
using Microsoft.CodeAnalysis.Editor.Implementation.Structure;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.FindUsages;
using Microsoft.CodeAnalysis.Navigation;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Shared.Extensions;
......@@ -156,9 +158,14 @@ public bool TrySymbolNavigationNotify(ISymbol symbol, Solution solution, Cancell
ISymbol symbol, Solution solution, CancellationToken cancellationToken)
{
AssertIsForeground();
var definitionItem = symbol.ToDefinitionItemAsync(
solution, includeHiddenLocations: true, cancellationToken: cancellationToken).WaitAndGetResult(cancellationToken);
definitionItem.Properties.TryGetValue(DefinitionItem.RQNameKey1, out var rqName);
if (!TryGetNavigationAPIRequiredArguments(
symbol, solution, cancellationToken,
out var hierarchy, out var itemID, out var navigationNotify, out var rqname))
definitionItem, rqName, solution, cancellationToken,
out var hierarchy, out var itemID, out var navigationNotify))
{
return false;
}
......@@ -166,30 +173,21 @@ public bool TrySymbolNavigationNotify(ISymbol symbol, Solution solution, Cancell
int returnCode = navigationNotify.OnBeforeNavigateToSymbol(
hierarchy,
itemID,
rqname,
rqName,
out var navigationHandled);
if (returnCode == VSConstants.S_OK && navigationHandled == 1)
{
return true;
}
return false;
return returnCode == VSConstants.S_OK && navigationHandled == 1;
}
public bool WouldNavigateToSymbol(
ISymbol symbol, Solution solution, CancellationToken cancellationToken,
DefinitionItem definitionItem, Solution solution, CancellationToken cancellationToken,
out string filePath, out int lineNumber, out int charOffset)
{
if (WouldNotifyToSpecificSymbol(symbol, solution, cancellationToken, out filePath, out lineNumber, out charOffset))
{
return true;
}
definitionItem.Properties.TryGetValue(DefinitionItem.RQNameKey1, out var rqName1);
definitionItem.Properties.TryGetValue(DefinitionItem.RQNameKey2, out var rqName2);
// If the symbol being considered is a constructor and no third parties choose to
// navigate to the constructor, then try the constructor's containing type.
if (symbol.IsConstructor() && WouldNotifyToSpecificSymbol(
symbol.ContainingType, solution, cancellationToken, out filePath, out lineNumber, out charOffset))
if (WouldNotifyToSpecificSymbol(definitionItem, rqName1, solution, cancellationToken, out filePath, out lineNumber, out charOffset) ||
WouldNotifyToSpecificSymbol(definitionItem, rqName2, solution, cancellationToken, out filePath, out lineNumber, out charOffset))
{
return true;
}
......@@ -201,7 +199,7 @@ public bool TrySymbolNavigationNotify(ISymbol symbol, Solution solution, Cancell
}
public bool WouldNotifyToSpecificSymbol(
ISymbol symbol, Solution solution, CancellationToken cancellationToken,
DefinitionItem definitionItem, string rqName, Solution solution, CancellationToken cancellationToken,
out string filePath, out int lineNumber, out int charOffset)
{
AssertIsForeground();
......@@ -209,9 +207,15 @@ public bool TrySymbolNavigationNotify(ISymbol symbol, Solution solution, Cancell
filePath = null;
lineNumber = 0;
charOffset = 0;
if (rqName == null)
{
return false;
}
if (!TryGetNavigationAPIRequiredArguments(
symbol, solution, cancellationToken,
out var hierarchy, out var itemID, out var navigationNotify, out var rqname))
definitionItem, rqName, solution, cancellationToken,
out var hierarchy, out var itemID, out var navigationNotify))
{
return false;
}
......@@ -221,7 +225,7 @@ public bool TrySymbolNavigationNotify(ISymbol symbol, Solution solution, Cancell
int queryNavigateStatusCode = navigationNotify.QueryNavigateToSymbol(
hierarchy,
itemID,
rqname,
rqName,
out var navigateToHierarchy,
out var navigateToItem,
navigateToTextSpan,
......@@ -239,43 +243,38 @@ public bool TrySymbolNavigationNotify(ISymbol symbol, Solution solution, Cancell
}
private bool TryGetNavigationAPIRequiredArguments(
ISymbol symbol,
DefinitionItem definitionItem,
string rqName,
Solution solution,
CancellationToken cancellationToken,
out IVsHierarchy hierarchy,
out uint itemID,
out IVsSymbolicNavigationNotify navigationNotify,
out string rqname)
out IVsSymbolicNavigationNotify navigationNotify)
{
AssertIsForeground();
hierarchy = null;
navigationNotify = null;
rqname = null;
itemID = (uint)VSConstants.VSITEMID.Nil;
if (!symbol.Locations.Any())
if (rqName == null)
{
return false;
}
var sourceLocations = symbol.Locations.Where(loc => loc.IsInSource);
var sourceLocations = definitionItem.SourceSpans;
if (!sourceLocations.Any())
{
return false;
}
var documents = sourceLocations.Select(loc => solution.GetDocument(loc.SourceTree)).WhereNotNull();
if (!documents.Any())
{
return false;
}
var documents = sourceLocations.SelectAsArray(loc => loc.Document);
// We can only pass one itemid to IVsSymbolicNavigationNotify, so prefer itemids from
// documents we consider to be "generated" to give external language services the best
// chance of participating.
var generatedDocuments = documents.Where(d => d.IsGeneratedCode(cancellationToken));
var generatedDocuments = documents.WhereAsArray(d => d.IsGeneratedCode(cancellationToken));
var documentToUse = generatedDocuments.FirstOrDefault() ?? documents.First();
if (!TryGetVsHierarchyAndItemId(documentToUse, out hierarchy, out itemID))
......@@ -289,8 +288,7 @@ public bool TrySymbolNavigationNotify(ISymbol symbol, Solution solution, Cancell
return false;
}
rqname = LanguageServices.RQName.From(symbol);
return rqname != null;
return true;
}
private bool TryGetVsHierarchyAndItemId(Document document, out IVsHierarchy hierarchy, out uint itemID)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册