提交 c9f3dd33 编写于 作者: C CyrusNajmabadi

Merge remote-tracking branch 'upstream/master' into findRefsRQNames1

......@@ -77,7 +77,7 @@ internal static class GoToDefinitionHelpers
FindUsagesHelpers.GetDisplayName(symbol));
return presenter.TryNavigateToOrPresentItemsAsync(
title, definitions.ToImmutableAndFree()).WaitAndGetResult(cancellationToken);
project.Solution.Workspace, title, definitions.ToImmutableAndFree()).WaitAndGetResult(cancellationToken);
}
private static IStreamingFindUsagesPresenter GetFindUsagesPresenter(
......
......@@ -136,7 +136,7 @@ public void ExecuteCommand(GoToImplementationCommandArgs args, Action nextHandle
var definitionItems = goToImplContext.GetDefinitions();
streamingPresenter.TryNavigateToOrPresentItemsAsync(
goToImplContext.SearchTitle, definitionItems).Wait(cancellationToken);
document.Project.Solution.Workspace, goToImplContext.SearchTitle, definitionItems).Wait(cancellationToken);
}
private IStreamingFindUsagesPresenter GetStreamingPresenter()
......
......@@ -43,17 +43,17 @@ internal static class IStreamingFindUsagesPresenterExtensions
/// </summary>
public static async Task<bool> TryNavigateToOrPresentItemsAsync(
this IStreamingFindUsagesPresenter presenter,
string title, ImmutableArray<DefinitionItem> items)
Workspace workspace, string title, ImmutableArray<DefinitionItem> items)
{
// Ignore any definitions that we can't navigate to.
var definitions = items.WhereAsArray(d => d.CanNavigateTo());
var definitions = items.WhereAsArray(d => d.CanNavigateTo(workspace));
// See if there's a third party external item we can navigate to. If so, defer
// to that item and finish.
var externalItems = definitions.WhereAsArray(d => d.IsExternal);
foreach (var item in externalItems)
{
if (item.TryNavigateTo())
if (item.TryNavigateTo(workspace))
{
return true;
}
......@@ -69,7 +69,7 @@ internal static class IStreamingFindUsagesPresenterExtensions
nonExternalItems[0].SourceSpans.Length <= 1)
{
// There was only one location to navigate to. Just directly go to that location.
return nonExternalItems[0].TryNavigateTo();
return nonExternalItems[0].TryNavigateTo(workspace);
}
if (presenter != null)
......
......@@ -396,8 +396,6 @@
<Compile Include="DocumentSpan.cs" />
<Compile Include="FindUsages\DefinitionItem.cs" />
<Compile Include="FindUsages\DefinitionItem.DocumentLocationDefinitionItem.cs" />
<Compile Include="FindUsages\DefinitionItem.NonNavigatingDefinitionItem.cs" />
<Compile Include="FindUsages\DefinitionItem.SymbolDefinitionItem.cs" />
<Compile Include="FindUsages\DefinitionsAndReferences.cs" />
<Compile Include="FindUsages\SourceReferenceItem.cs" />
<Compile Include="Diagnostics\EngineV2\DiagnosticAnalyzerExecutor.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;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis.FindSymbols;
using Microsoft.CodeAnalysis.Navigation;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.FindUsages
{
......@@ -11,25 +17,111 @@ internal partial class DefinitionItem
/// <see cref="DocumentSpan"/>.
/// </summary>
// internal for testing purposes.
internal sealed class DocumentLocationDefinitionItem : DefinitionItem
internal sealed class DefaultDefinitionItem : DefinitionItem
{
internal override bool IsExternal => false;
public DocumentLocationDefinitionItem(
public DefaultDefinitionItem(
ImmutableArray<string> tags,
ImmutableArray<TaggedText> displayParts,
ImmutableArray<TaggedText> nameDisplayParts,
ImmutableArray<TaggedText> originationParts,
ImmutableArray<DocumentSpan> sourceSpans,
ImmutableDictionary<string, string> properties,
bool displayIfNoReferences)
: base(tags, displayParts, nameDisplayParts,
ImmutableArray.Create(new TaggedText(TextTags.Text, sourceSpans[0].Document.Project.Name)),
: base(tags, displayParts, nameDisplayParts, originationParts,
sourceSpans, properties, displayIfNoReferences)
{
}
public override bool CanNavigateTo() => SourceSpans[0].CanNavigateTo();
public override bool TryNavigateTo() => SourceSpans[0].TryNavigateTo();
public override bool CanNavigateTo(Workspace workspace)
{
if (this.Properties.ContainsKey(NonNavigable))
{
return false;
}
if (this.Properties.TryGetValue(MetadataSymbolKey, out var symbolKey))
{
return CanNavigateToMetadataSymbol(workspace, symbolKey);
}
return SourceSpans[0].CanNavigateTo();
}
public override bool TryNavigateTo(Workspace workspace)
{
if (this.Properties.ContainsKey(NonNavigable))
{
return false;
}
if (this.Properties.TryGetValue(MetadataSymbolKey, out var symbolKey))
{
return TryNavigateToMetadataSymbol(workspace, symbolKey);
}
return SourceSpans[0].TryNavigateTo();
}
private bool CanNavigateToMetadataSymbol(Workspace workspace, string symbolKey)
=> TryNavigateToMetadataSymbol(workspace, symbolKey, action: (symbol, project, service) => true);
private bool TryNavigateToMetadataSymbol(Workspace workspace, string symbolKey)
{
return TryNavigateToMetadataSymbol(workspace, symbolKey,
action: (symbol, project, service) =>
{
return service.TryNavigateToSymbol(
symbol, project, project.Solution.Options.WithChangedOption(NavigationOptions.PreferProvisionalTab, true));
});
}
private bool TryNavigateToMetadataSymbol(
Workspace workspace, string symbolKey, Func<ISymbol, Project, ISymbolNavigationService, bool> action)
{
var projectAndSymbol = TryResolveSymbolInCurrentSolution(workspace, symbolKey);
var project = projectAndSymbol.project;
var symbol = projectAndSymbol.symbol;
if (symbol == null || project == null)
{
return false;
}
if (symbol.Kind == SymbolKind.Namespace)
{
return false;
}
var navigationService = workspace.Services.GetService<ISymbolNavigationService>();
return action(symbol, project, navigationService);
}
private (Project project, ISymbol symbol) TryResolveSymbolInCurrentSolution(
Workspace workspace, string symbolKey)
{
if (!this.Properties.TryGetValue(MetadataAssemblyIdentityDisplayName, out var identityDisplayName) ||
!AssemblyIdentity.TryParseDisplayName(identityDisplayName, out var identity))
{
return (null, null);
}
var project = workspace.CurrentSolution
.ProjectsWithReferenceToAssembly(identity)
.FirstOrDefault();
if (project == null)
{
return (null, null);
}
var compilation = project.GetCompilationAsync(CancellationToken.None)
.WaitAndGetResult(CancellationToken.None);
var symbol = SymbolKey.Resolve(symbolKey, compilation).Symbol;
return (project, symbol);
}
}
}
}
\ 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;
namespace Microsoft.CodeAnalysis.FindUsages
{
internal partial class DefinitionItem
{
/// <summary>
/// Implementation of a <see cref="DefinitionItem"/> used for definitions
/// that cannot be navigated to. For example, C# and VB namespaces cannot be
/// navigated to.
/// </summary>
private sealed class NonNavigatingDefinitionItem : DefinitionItem
{
internal override bool IsExternal => false;
public NonNavigatingDefinitionItem(
ImmutableArray<string> tags,
ImmutableArray<TaggedText> displayParts,
ImmutableArray<TaggedText> originationParts,
ImmutableDictionary<string, string> properties,
bool displayIfNoReferences)
: base(tags, displayParts, ImmutableArray<TaggedText>.Empty,
originationParts, ImmutableArray<DocumentSpan>.Empty,
properties, displayIfNoReferences)
{
}
public override bool CanNavigateTo() => false;
public override bool TryNavigateTo() => false;
}
}
}
\ 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;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis.FindSymbols;
using Microsoft.CodeAnalysis.Navigation;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.FindUsages
{
internal partial class DefinitionItem
{
/// <summary>
/// Implementation of a <see cref="DefinitionItem"/> that sits on top of an
/// <see cref="ISymbol"/>. In order to not keep anything alive too long, we only
/// hold onto IDs and Keys. When the user tries to navigate to an item we will
/// attempt to find the symbol again in the current solution snapshot and
/// navigate to it there.
/// </summary>
private sealed class MetadataDefinitionItem : DefinitionItem
{
private readonly Workspace _workspace;
private readonly SymbolKey _symbolKey;
private readonly AssemblyIdentity _symbolAssemblyIdentity;
internal override bool IsExternal => false;
public MetadataDefinitionItem(
ImmutableArray<string> tags,
ImmutableArray<TaggedText> displayParts,
ImmutableArray<TaggedText> nameDisplayParts,
ImmutableDictionary<string, string> properties,
bool displayIfNoReferences,
Solution solution, ISymbol definition)
: base(tags, displayParts, nameDisplayParts,
GetOriginationParts(definition),
ImmutableArray<DocumentSpan>.Empty,
properties,
displayIfNoReferences)
{
_workspace = solution.Workspace;
_symbolKey = definition.GetSymbolKey();
_symbolAssemblyIdentity = definition.ContainingAssembly?.Identity;
}
public override bool CanNavigateTo()
=> TryNavigateTo((symbol, project, service) => true);
public override bool TryNavigateTo()
{
return TryNavigateTo((symbol, project, service) =>
service.TryNavigateToSymbol(
symbol, project, project.Solution.Options.WithChangedOption(NavigationOptions.PreferProvisionalTab, true)));
}
private bool TryNavigateTo(Func<ISymbol, Project, ISymbolNavigationService, bool> action)
{
var projectAndSymbol = ResolveSymbolInCurrentSolution();
if (projectAndSymbol == null)
{
return false;
}
var project = projectAndSymbol?.project;
var symbol = projectAndSymbol?.symbol;
if (symbol == null || project == null)
{
return false;
}
if (symbol.Kind == SymbolKind.Namespace)
{
return false;
}
var navigationService = _workspace.Services.GetService<ISymbolNavigationService>();
return action(symbol, project, navigationService);
}
private (Project project, ISymbol symbol)? ResolveSymbolInCurrentSolution()
{
var project = _workspace.CurrentSolution
.ProjectsWithReferenceToAssembly(_symbolAssemblyIdentity)
.FirstOrDefault();
if (project == null)
{
return null;
}
var compilation = project.GetCompilationAsync(CancellationToken.None)
.WaitAndGetResult(CancellationToken.None);
return (project, _symbolKey.Resolve(compilation).Symbol);
}
}
}
}
\ No newline at end of file
......@@ -3,6 +3,7 @@
using System;
using System.Collections.Immutable;
using Microsoft.CodeAnalysis.Completion;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.FindUsages
{
......@@ -25,6 +26,22 @@ internal abstract partial class DefinitionItem
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
/// metadata-as-source for metadata symbols. We need to store the <see cref="SymbolKey"/>
/// for the symbol and the name we get back from <see cref="AssemblyIdentity.GetDisplayName"/>
/// for. With these we can effetively recover the symbol.
/// </summary>
private const string MetadataSymbolKey = nameof(MetadataSymbolKey);
private const string MetadataAssemblyIdentityDisplayName = nameof(MetadataAssemblyIdentityDisplayName);
/// <summary>
/// If this item is something that cannot be navigated to. We store this in our
/// <see cref="Properties"/> to act as an explicit marker that navigation is not possible.
/// </summary>
private const string NonNavigable = nameof(NonNavigable);
/// <summary>
/// Descriptive tags from <see cref="CompletionTags"/>. These tags may influence how the
/// item is displayed.
......@@ -89,12 +106,17 @@ internal abstract partial class DefinitionItem
NameDisplayParts = nameDisplayParts.IsDefaultOrEmpty ? displayParts : nameDisplayParts;
OriginationParts = originationParts.NullToEmpty();
SourceSpans = sourceSpans.NullToEmpty();
Properties = properties;
Properties = properties ?? ImmutableDictionary<string, string>.Empty;
DisplayIfNoReferences = displayIfNoReferences;
if (Properties.ContainsKey(MetadataSymbolKey))
{
Contract.ThrowIfFalse(Properties.ContainsKey(MetadataAssemblyIdentityDisplayName));
}
}
public abstract bool CanNavigateTo();
public abstract bool TryNavigateTo();
public abstract bool CanNavigateTo(Workspace workspace);
public abstract bool TryNavigateTo(Workspace workspace);
public static DefinitionItem Create(
ImmutableArray<string> tags,
......@@ -134,8 +156,13 @@ internal abstract partial class DefinitionItem
throw new ArgumentException($"{nameof(sourceSpans)} cannot be empty.");
}
return new DocumentLocationDefinitionItem(
tags, displayParts, nameDisplayParts, sourceSpans, properties, displayIfNoReferences);
var firstDocument = sourceSpans[0].Document;
var originationParts = ImmutableArray.Create(
new TaggedText(TextTags.Text, firstDocument.Project.Name));
return new DefaultDefinitionItem(
tags, displayParts, nameDisplayParts, originationParts,
sourceSpans, properties, displayIfNoReferences);
}
internal static DefinitionItem CreateMetadataDefinition(
......@@ -146,9 +173,20 @@ internal abstract partial class DefinitionItem
ImmutableDictionary<string, string> properties = null,
bool displayIfNoReferences = true)
{
return new MetadataDefinitionItem(
tags, displayParts, nameDisplayParts, properties,
displayIfNoReferences, solution, symbol);
properties = properties ?? ImmutableDictionary<string, string>.Empty;
var symbolKey = symbol.GetSymbolKey().ToString();
var assemblyIdentityDisplayName = symbol.ContainingAssembly?.Identity.GetDisplayName();
properties = properties.Add(MetadataSymbolKey, symbolKey)
.Add(MetadataAssemblyIdentityDisplayName, assemblyIdentityDisplayName);
var originationParts = GetOriginationParts(symbol);
return new DefaultDefinitionItem(
tags, displayParts, nameDisplayParts, originationParts,
sourceSpans: ImmutableArray<DocumentSpan>.Empty,
properties: properties,
displayIfNoReferences: displayIfNoReferences);
}
// Kept around for binary compat with F#/TypeScript.
......@@ -170,8 +208,17 @@ internal abstract partial class DefinitionItem
ImmutableDictionary<string, string> properties = null,
bool displayIfNoReferences = true)
{
return new NonNavigatingDefinitionItem(
tags, displayParts, originationParts, properties, displayIfNoReferences);
properties = properties ?? ImmutableDictionary<string, string>.Empty;
properties = properties.Add(NonNavigable, "");
return new DefaultDefinitionItem(
tags: tags,
displayParts: displayParts,
nameDisplayParts: ImmutableArray<TaggedText>.Empty,
originationParts: originationParts,
sourceSpans: ImmutableArray<DocumentSpan>.Empty,
properties: properties,
displayIfNoReferences: displayIfNoReferences);
}
internal static ImmutableArray<TaggedText> GetOriginationParts(ISymbol symbol)
......
// 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;
namespace Microsoft.CodeAnalysis.FindReferences
{
internal partial class DefinitionLocation
{
/// <summary>
/// Implementation of a <see cref="DefinitionLocation"/> that sits on top of a
/// <see cref="DocumentLocation"/>.
/// </summary>
// Internal for testing purposes only.
internal sealed class DocumentDefinitionLocation : DefinitionLocation
{
public readonly DocumentLocation Location;
public DocumentDefinitionLocation(DocumentLocation location)
{
Location = location;
}
/// <summary>
/// Show the project that this <see cref="DocumentLocation"/> is contained in as the
/// Origination of this <see cref="DefinitionLocation"/>.
/// </summary>
public override ImmutableArray<TaggedText> OriginationParts =>
ImmutableArray.Create(new TaggedText(TextTags.Text, Location.Document.Project.Name));
public override bool CanNavigateTo() => true;
public override bool TryNavigateTo() => Location.TryNavigateTo();
}
}
}
\ No newline at end of file
......@@ -106,9 +106,9 @@ private class ExternalDefinitionItem : DefinitionItem
_charOffset = charOffset;
}
public override bool CanNavigateTo() => true;
public override bool CanNavigateTo(Workspace workspace) => true;
public override bool TryNavigateTo()
public override bool TryNavigateTo(Workspace workspace)
{
return TryOpenFile() && TryNavigateToPosition();
}
......
......@@ -12,9 +12,12 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.Library.FindRes
[Guid(Guids.RoslynLibraryIdString)]
internal partial class LibraryManager : AbstractLibraryManager
{
public LibraryManager(IServiceProvider serviceProvider)
private readonly Workspace _workspace;
public LibraryManager(Workspace workspace, IServiceProvider serviceProvider)
: base(Guids.RoslynLibraryId, serviceProvider)
{
_workspace = workspace;
}
public override uint GetLibraryFlags()
......
......@@ -40,7 +40,7 @@ public void PresentDefinitionsAndReferences(DefinitionsAndReferences definitions
var query =
from d in definitionsAndReferences.Definitions
let referenceItems = CreateReferenceItems(d, definitionsAndReferences, commonPathElements)
select new DefinitionTreeItem(d, referenceItems);
select new DefinitionTreeItem(_workspace, d, referenceItems);
return query.ToList<AbstractTreeItem>();
}
......
......@@ -12,13 +12,16 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.Library.FindRes
{
internal class DefinitionTreeItem : AbstractTreeItem
{
private readonly Workspace _workspace;
private readonly DefinitionItem _definitionItem;
public DefinitionTreeItem(
Workspace workspace,
DefinitionItem definitionItem,
ImmutableArray<SourceReferenceTreeItem> referenceItems)
: base(definitionItem.Tags.GetGlyph().GetGlyphIndex())
{
_workspace = workspace;
_definitionItem = definitionItem;
this.Children.AddRange(referenceItems);
......@@ -49,14 +52,14 @@ private string CreateDisplayText()
public override int GoToSource()
{
return _definitionItem.TryNavigateTo()
return _definitionItem.TryNavigateTo(_workspace)
? VSConstants.S_OK
: VSConstants.E_FAIL;
}
public override bool CanGoToDefinition()
{
return _definitionItem.CanNavigateTo();
return _definitionItem.CanNavigateTo(_workspace);
}
}
}
\ No newline at end of file
......@@ -62,11 +62,11 @@ protected override void Initialize()
var method = compilerFailFast.GetMethod(nameof(FailFast.OnFatalException), BindingFlags.Static | BindingFlags.NonPublic);
property.SetValue(null, Delegate.CreateDelegate(property.PropertyType, method));
RegisterFindResultsLibraryManager();
var componentModel = (IComponentModel)this.GetService(typeof(SComponentModel));
_workspace = componentModel.GetService<VisualStudioWorkspace>();
RegisterFindResultsLibraryManager();
// Ensure the options persisters are loaded since we have to fetch options from the shell
componentModel.GetExtensions<IOptionPersister>();
......@@ -186,7 +186,7 @@ private void RegisterFindResultsLibraryManager()
var objectManager = this.GetService(typeof(SVsObjectManager)) as IVsObjectManager2;
if (objectManager != null)
{
_libraryManager = new LibraryManager(this);
_libraryManager = new LibraryManager(_workspace, this);
if (ErrorHandler.Failed(objectManager.RegisterSimpleLibrary(_libraryManager, out _libraryManagerCookie)))
{
......
......@@ -35,9 +35,7 @@ private class RoslynDefinitionBucket : DefinitionBucket, ISupportsNavigation
}
public bool TryNavigateTo()
{
return DefinitionItem.TryNavigateTo();
}
=> DefinitionItem.TryNavigateTo(_presenter._workspace);
public override bool TryGetValue(string key, out object content)
{
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册