提交 40199132 编写于 作者: C CyrusNajmabadi 提交者: GitHub

Merge pull request #18925 from CyrusNajmabadi/findRefsRQNames1

Include RQNames in the property bag returned for definition items in FindAllReferences.
......@@ -105,6 +105,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="FindUsages\AbstractFindUsagesService.cs" />
<Compile Include="FindUsages\AbstractFindUsagesService.DefinitionTrackingContext.cs" />
<Compile Include="FindUsages\FindUsagesHelpers.cs" />
<Compile Include="FindUsages\FindUsagesContext.cs" />
<Compile Include="FindUsages\IDefinitionsAndReferencesFactory.cs" />
......
// 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.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.FindUsages;
namespace Microsoft.CodeAnalysis.Editor.FindUsages
{
internal abstract partial class AbstractFindUsagesService
{
/// <summary>
/// Forwards <see cref="IFindUsagesContext"/> notifications to an underlying <see cref="IFindUsagesContext"/>
/// while also keeping track of the <see cref="DefinitionItem"/> definitions reported.
///
/// These can then be used by <see cref="GetThirdPartyDefinitions"/> to report the
/// definitions found to third parties in case they want to add any additional definitions
/// to the results we present.
/// </summary>
private class DefinitionTrackingContext : IFindUsagesContext
{
private readonly IFindUsagesContext _underlyingContext;
private readonly object _gate = new object();
private readonly List<DefinitionItem> _definitions = new List<DefinitionItem>();
public DefinitionTrackingContext(IFindUsagesContext underlyingContext)
{
_underlyingContext = underlyingContext;
}
public CancellationToken CancellationToken
=> _underlyingContext.CancellationToken;
public void ReportMessage(string message)
=> _underlyingContext.ReportMessage(message);
public void SetSearchTitle(string title)
=> _underlyingContext.SetSearchTitle(title);
public Task OnReferenceFoundAsync(SourceReferenceItem reference)
=> _underlyingContext.OnReferenceFoundAsync(reference);
public Task ReportProgressAsync(int current, int maximum)
=> _underlyingContext.ReportProgressAsync(current, maximum);
public Task OnDefinitionFoundAsync(DefinitionItem definition)
{
lock (_gate)
{
_definitions.Add(definition);
}
return _underlyingContext.OnDefinitionFoundAsync(definition);
}
public ImmutableArray<DefinitionItem> GetDefinitions()
{
lock (_gate)
{
return _definitions.ToImmutableArray();
}
}
}
}
}
\ No newline at end of file
......@@ -2,7 +2,6 @@
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.FindSymbols;
......@@ -15,6 +14,10 @@ namespace Microsoft.CodeAnalysis.Editor.FindUsages
{
internal abstract partial class AbstractFindUsagesService
{
/// <summary>
/// Forwards <see cref="IStreamingFindLiteralReferencesProgress"/> calls to an
/// <see cref="IFindUsagesContext"/> instance.
/// </summary>
private class FindLiteralsProgressAdapter : IStreamingFindLiteralReferencesProgress
{
private readonly IFindUsagesContext _context;
......@@ -73,7 +76,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
......@@ -106,22 +109,6 @@ public async Task OnReferenceFoundAsync(SymbolAndProjectId definition, Reference
await _context.OnReferenceFoundAsync(referenceItem).ConfigureAwait(false);
}
}
public async Task CallThirdPartyExtensionsAsync(CancellationToken cancellationToken)
{
var factory = _solution.Workspace.Services.GetService<IDefinitionsAndReferencesFactory>();
foreach (var definition in _definitionToItem.Keys)
{
var item = factory.GetThirdPartyDefinitionItem(
_solution, definition, cancellationToken);
if (item != null)
{
// ConfigureAwait(true) because we want to come back on the
// same thread after calling into extensions.
await _context.OnDefinitionFoundAsync(item).ConfigureAwait(true);
}
}
}
}
}
}
\ No newline at end of file
// 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.Immutable;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.FindSymbols;
using Microsoft.CodeAnalysis.FindUsages;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Editor.FindUsages
{
......@@ -45,36 +47,60 @@ public async Task FindImplementationsAsync(Document document, int position, IFin
public async Task FindReferencesAsync(
Document document, int position, IFindUsagesContext context)
{
// NOTE: All ConFigureAwaits in this method need to pass 'true' so that
// we return to the caller's context. that's so the call to
// CallThirdPartyExtensionsAsync will happen on the UI thread. We need
// this to maintain the threading guarantee we had around that method
// from pre-Roslyn days.
var cancellationToken = context.CancellationToken;
cancellationToken.ThrowIfCancellationRequested();
var definitionTrackingContext = new DefinitionTrackingContext(context);
// Need ConfigureAwait(true) here so we get back to the UI thread before calling
// GetThirdPartyDefinitions. We need to call that on the UI thread to match behavior
// of how the language service always worked in the past.
//
// Any async calls before GetThirdPartyDefinitions must be ConfigureAwait(true).
await FindLiteralOrSymbolReferencesAsync(
document, position, definitionTrackingContext).ConfigureAwait(true);
// After the FAR engine is done call into any third party extensions to see
// if they want to add results.
var thirdPartyDefinitions = GetThirdPartyDefinitions(
document.Project.Solution, definitionTrackingContext.GetDefinitions(), context.CancellationToken);
// From this point on we can do ConfigureAwait(false) as we're not calling back
// into third parties anymore.
foreach (var definition in thirdPartyDefinitions)
{
// Don't need ConfigureAwait(true) here
await context.OnDefinitionFoundAsync(definition).ConfigureAwait(false);
}
}
private async Task FindLiteralOrSymbolReferencesAsync(
Document document, int position, IFindUsagesContext context)
{
// First, see if we're on a literal. If so search for literals in the solution with
// the same value.
var found = await TryFindLiteralReferencesAsync(document, position, context).ConfigureAwait(true);
var found = await TryFindLiteralReferencesAsync(
document, position, context).ConfigureAwait(false);
if (found)
{
return;
}
var findReferencesProgress = await FindSymbolReferencesAsync(
document, position, context).ConfigureAwait(true);
if (findReferencesProgress == null)
{
return;
}
// Wasn't a literal. Try again as a symbol.
await FindSymbolReferencesAsync(
document, position, context).ConfigureAwait(false);
}
// After the FAR engine is done call into any third party extensions to see
// if they want to add results.
await findReferencesProgress.CallThirdPartyExtensionsAsync(
context.CancellationToken).ConfigureAwait(true);
private ImmutableArray<DefinitionItem> GetThirdPartyDefinitions(
Solution solution,
ImmutableArray<DefinitionItem> definitions,
CancellationToken cancellationToken)
{
var factory = solution.Workspace.Services.GetService<IDefinitionsAndReferencesFactory>();
return definitions.Select(d => factory.GetThirdPartyDefinitionItem(solution, d, cancellationToken))
.WhereNotNull()
.ToImmutableArray();
}
private async Task<FindReferencesProgressAdapter> FindSymbolReferencesAsync(
private async Task FindSymbolReferencesAsync(
Document document, int position, IFindUsagesContext context)
{
var cancellationToken = context.CancellationToken;
......@@ -85,10 +111,10 @@ public async Task FindImplementationsAsync(Document document, int position, IFin
document, position, cancellationToken).ConfigureAwait(false);
if (symbolAndProject == null)
{
return null;
return;
}
return await FindSymbolReferencesWorkerAsync(
await FindSymbolReferencesAsync(
context, symbolAndProject?.symbol, symbolAndProject?.project, cancellationToken).ConfigureAwait(false);
}
......@@ -96,13 +122,7 @@ public async Task FindImplementationsAsync(Document document, int position, IFin
/// Public helper that we use from features like ObjectBrowser which start with a symbol
/// and want to push all the references to it into the Streaming-Find-References window.
/// </summary>
public static Task FindSymbolReferencesAsync(
IFindUsagesContext context, ISymbol symbol, Project project, CancellationToken cancellationToken)
{
return FindSymbolReferencesWorkerAsync(context, symbol, project, cancellationToken);
}
private static async Task<FindReferencesProgressAdapter> FindSymbolReferencesWorkerAsync(
public static async Task FindSymbolReferencesAsync(
IFindUsagesContext context, ISymbol symbol, Project project, CancellationToken cancellationToken)
{
context.SetSearchTitle(string.Format(EditorFeaturesResources._0_references,
......@@ -120,8 +140,6 @@ public async Task FindImplementationsAsync(Document document, int position, IFin
progressAdapter,
documents: null,
cancellationToken: cancellationToken).ConfigureAwait(false);
return progressAdapter;
}
private async Task<bool> TryFindLiteralReferencesAsync(
......
// 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 Microsoft.CodeAnalysis.Completion;
using Microsoft.CodeAnalysis.Features.RQName;
using Microsoft.CodeAnalysis.FindSymbols;
using Microsoft.CodeAnalysis.FindUsages;
using Microsoft.CodeAnalysis.Host;
......@@ -17,7 +17,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]
......@@ -28,7 +28,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;
}
......@@ -57,7 +57,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
......@@ -104,6 +105,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 SourceReferenceItem TryCreateSourceReferenceItem(
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,9 +60,17 @@ internal static class GoToDefinitionHelpers
symbol = method.PartialImplementationPart ?? symbol;
}
var options = project.Solution.Options;
var definitions = ArrayBuilder<DefinitionItem>.GetInstance();
var definitionItem = symbol.ToDefinitionItem(solution, includeHiddenLocations: true);
if (thirdPartyNavigationAllowed)
{
var factory = solution.Workspace.Services.GetService<IDefinitionsAndReferencesFactory>();
var thirdPartyItem = factory?.GetThirdPartyDefinitionItem(solution, definitionItem, cancellationToken);
definitions.AddIfNotNull(thirdPartyItem);
}
definitions.Add(symbol.ToDefinitionItem(solution, includeHiddenLocations: true));
definitions.Add(definitionItem);
var presenter = GetFindUsagesPresenter(streamingPresenters);
var title = string.Format(EditorFeaturesResources._0_declarations,
......
......@@ -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,10 @@ private PeekableItemFactory(IMetadataAsSourceFileService metadataAsSourceFileSer
}
var symbolNavigationService = solution.Workspace.Services.GetService<ISymbolNavigationService>();
var definitionItem = symbol.ToDefinitionItem(solution, includeHiddenLocations: true);
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
......
......@@ -19,6 +19,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>
/// For metadata symbols we encode information in the <see cref="Properties"/> so we can
/// retrieve the symbol later on when navigating. This is needed so that we can go to
......
// 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,13 @@ public bool TrySymbolNavigationNotify(ISymbol symbol, Solution solution, Cancell
ISymbol symbol, Solution solution, CancellationToken cancellationToken)
{
AssertIsForeground();
var definitionItem = symbol.ToDefinitionItem(solution, includeHiddenLocations: true);
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 +172,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 +198,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 +206,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 +224,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 +242,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 +287,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.
先完成此消息的编辑!
想要评论请 注册