提交 a540462b 编写于 作者: C CyrusNajmabadi

Allow navigation back to metadata symbols without needing to know a reference to that symbol first.

上级 2317ddee
......@@ -2,7 +2,9 @@
using System;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis.FindSymbols;
using Microsoft.CodeAnalysis.Navigation;
using Roslyn.Utilities;
......@@ -20,15 +22,15 @@ internal partial class DefinitionLocation
private sealed class SymbolDefinitionLocation : DefinitionLocation
{
private readonly Workspace _workspace;
private readonly ProjectId _referencingProjectId;
private readonly SymbolKey _symbolKey;
private readonly string _symbolAssemblyName;
private readonly ImmutableArray<TaggedText> _originationParts;
public SymbolDefinitionLocation(ISymbol definition, Project project)
public SymbolDefinitionLocation(Solution solution, ISymbol definition)
{
_workspace = project.Solution.Workspace;
_referencingProjectId = project.Id;
_workspace = solution.Workspace;
_symbolKey = definition.GetSymbolKey();
_symbolAssemblyName = definition.ContainingAssembly?.Name;
_originationParts = GetOriginationParts(definition);
}
......@@ -47,9 +49,15 @@ public override bool TryNavigateTo()
private bool TryNavigateTo(Func<ISymbol, Project, ISymbolNavigationService, bool> action)
{
var symbol = ResolveSymbolInCurrentSolution();
var referencingProject = _workspace.CurrentSolution.GetProject(_referencingProjectId);
if (symbol == null || referencingProject == null)
var projectAndSymbol = ResolveSymbolInCurrentSolution();
if (projectAndSymbol == null)
{
return false;
}
var project = projectAndSymbol.Value.Item1;
var symbol = projectAndSymbol.Value.Item2;
if (symbol == null || project == null)
{
return false;
}
......@@ -60,15 +68,23 @@ private bool TryNavigateTo(Func<ISymbol, Project, ISymbolNavigationService, bool
}
var navigationService = _workspace.Services.GetService<ISymbolNavigationService>();
return action(symbol, referencingProject, navigationService);
return action(symbol, project, navigationService);
}
private ISymbol ResolveSymbolInCurrentSolution()
private ValueTuple<Project, ISymbol>? ResolveSymbolInCurrentSolution()
{
var compilation = _workspace.CurrentSolution.GetProject(_referencingProjectId)
.GetCompilationAsync(CancellationToken.None)
.WaitAndGetResult(CancellationToken.None);
return _symbolKey.Resolve(compilation).Symbol;
var project = _workspace.CurrentSolution
.Projects
.FirstOrDefault(p => p.HasReferenceToAssembly(_symbolAssemblyName));
if (project == null)
{
return null;
}
var compilation = project.GetCompilationAsync(CancellationToken.None)
.WaitAndGetResult(CancellationToken.None);
return ValueTuple.Create(project, _symbolKey.Resolve(compilation).Symbol);
}
}
}
......
......@@ -34,9 +34,9 @@ public static DefinitionLocation CreateDocumentLocation(DocumentLocation locatio
return new DocumentDefinitionLocation(location);
}
public static DefinitionLocation CreateSymbolLocation(ISymbol symbol, Project referencingProject)
public static DefinitionLocation CreateSymbolLocation(Solution solution, ISymbol symbol)
{
return new SymbolDefinitionLocation(symbol, referencingProject);
return new SymbolDefinitionLocation(solution, symbol);
}
public static DefinitionLocation CreateNonNavigatingLocation(
......
......@@ -132,7 +132,7 @@ private static int GetPrecedence(ReferencedSymbol referencedSymbol)
{
var definition = referencedSymbol.Definition;
var definitionLocations = ConvertLocations(solution, referencedSymbol);
var definitionLocations = ConvertDefinitionLocations(solution, definition);
var displayParts = definition.ToDisplayParts(s_definitionDisplayFormat).ToTaggedText();
return new DefinitionItem(
......@@ -142,10 +142,9 @@ private static int GetPrecedence(ReferencedSymbol referencedSymbol)
definition.ShouldShowWithNoReferenceLocations());
}
private static ImmutableArray<DefinitionLocation> ConvertLocations(
Solution solution, ReferencedSymbol referencedSymbol)
private static ImmutableArray<DefinitionLocation> ConvertDefinitionLocations(
Solution solution, ISymbol definition)
{
var definition = referencedSymbol.Definition;
var result = ImmutableArray.CreateBuilder<DefinitionLocation>();
// If it's a namespace, don't create any normal lcoation. Namespaces
......@@ -157,12 +156,7 @@ private static int GetPrecedence(ReferencedSymbol referencedSymbol)
{
if (location.IsInMetadata)
{
var firstSourceReferenceLocation = referencedSymbol.Locations.FirstOrNullable();
if (firstSourceReferenceLocation != null)
{
result.Add(DefinitionLocation.CreateSymbolLocation(
definition, firstSourceReferenceLocation.Value.Document.Project));
}
result.Add(DefinitionLocation.CreateSymbolLocation(solution, definition));
}
else if (location.IsInSource)
{
......
......@@ -399,6 +399,16 @@ private static bool HasReferenceTo(IAssemblySymbol containingAssembly, Project s
return project.ProjectReferences.Any(p => p.ProjectId == sourceProject.Id);
}
return project.HasReferenceToAssembly(containingAssembly);
}
public static bool HasReferenceToAssembly(this Project project, IAssemblySymbol assemblySymbol)
{
return project.HasReferenceToAssembly(assemblySymbol.Name);
}
public static bool HasReferenceToAssembly(this Project project, string assemblyName)
{
// If the project we're looking at doesn't even support compilations, then there's no
// way for it to have an IAssemblySymbol. And without that, there is no way for it
// to have any sort of 'ReferenceTo' the provided 'containingAssembly' symbol.
......@@ -408,18 +418,20 @@ private static bool HasReferenceTo(IAssemblySymbol containingAssembly, Project s
}
// WORKAROUND:
// perf check metadata reference using newly created empty compilation with only metadata references.
// perf check metadata reference using newly created empty compilation with only metadata references.
//
// TODO(cyrusn): Why don't we call project.TryGetCompilation first?
// wouldn't we want to use that compilation if it's available?
var compilation = project.LanguageServices.CompilationFactory.CreateCompilation(
project.AssemblyName,
project.CompilationOptions);
project.AssemblyName, project.CompilationOptions);
compilation = compilation.AddReferences(project.MetadataReferences);
return project.MetadataReferences.Any(m =>
{
var symbol = compilation.GetAssemblyOrModuleSymbol(m) as IAssemblySymbol;
return symbol != null && symbol.Name == containingAssembly.Name;
return symbol != null && symbol.Name == assemblyName;
});
}
}
}
}
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册