提交 11ed85f5 编写于 作者: S Sam Harwell

Keep track of the original compilation when navigating to metadata

Fixes #6859
上级 5c4bd7a7
......@@ -38,14 +38,12 @@ public CSharpDecompiledSourceService(HostLanguageServices provider)
this.provider = provider;
}
public async Task<Document> AddSourceToAsync(Document document, ISymbol symbol, CancellationToken cancellationToken)
public async Task<Document> AddSourceToAsync(Document document, Compilation symbolCompilation, ISymbol symbol, CancellationToken cancellationToken)
{
// Get the name of the type the symbol is in
var containingOrThis = symbol.GetContainingTypeOrThis();
var fullName = GetFullReflectionName(containingOrThis);
var compilation = await document.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);
string assemblyLocation = null;
var isReferenceAssembly = symbol.ContainingAssembly.GetAttributes().Any(attribute => attribute.AttributeClass.Name == nameof(ReferenceAssemblyAttribute)
&& attribute.AttributeClass.ToNameDisplayString() == typeof(ReferenceAssemblyAttribute).FullName);
......@@ -63,7 +61,7 @@ public async Task<Document> AddSourceToAsync(Document document, ISymbol symbol,
if (assemblyLocation == null)
{
var reference = MetadataAsSourceHelpers.TryGetAssemblyReference(compilation, symbol.ContainingAssembly);
var reference = symbolCompilation.GetMetadataReference(symbol.ContainingAssembly);
assemblyLocation = (reference as PortableExecutableReference)?.FilePath;
if (assemblyLocation == null)
{
......@@ -72,7 +70,7 @@ public async Task<Document> AddSourceToAsync(Document document, ISymbol symbol,
}
// Decompile
document = PerformDecompilation(document, fullName, compilation, assemblyLocation);
document = PerformDecompilation(document, fullName, symbolCompilation, assemblyLocation);
document = await AddAssemblyInfoRegionAsync(document, symbol, cancellationToken).ConfigureAwait(false);
......
......@@ -14,9 +14,10 @@ internal interface IDecompiledSourceService : ILanguageService
/// into the given document
/// </summary>
/// <param name="document">The document to generate source into</param>
/// <param name="symbolCompilation">The <see cref="Compilation"/> in which symbol is resolved.</param>
/// <param name="symbol">The symbol to generate source for</param>
/// <param name="cancellationToken">To cancel document operations</param>
/// <returns>The updated document</returns>
Task<Document> AddSourceToAsync(Document document, ISymbol symbol, CancellationToken cancellationToken);
Task<Document> AddSourceToAsync(Document document, Compilation symbolCompilation, ISymbol symbol, CancellationToken cancellationToken);
}
}
......@@ -91,6 +91,7 @@ public async Task<MetadataAsSourceFile> GetGeneratedFileAsync(Project project, I
Location navigateLocation = null;
var topLevelNamedType = MetadataAsSourceHelpers.GetTopLevelContainingNamedType(symbol);
var symbolId = SymbolKey.Create(symbol, cancellationToken);
var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);
using (await _gate.DisposableWaitAsync(cancellationToken).ConfigureAwait(false))
{
......@@ -123,7 +124,7 @@ public async Task<MetadataAsSourceFile> GetGeneratedFileAsync(Project project, I
var decompiledSourceService = temporaryDocument.GetLanguageService<IDecompiledSourceService>();
if (decompiledSourceService != null)
{
temporaryDocument = await decompiledSourceService.AddSourceToAsync(temporaryDocument, symbol, cancellationToken).ConfigureAwait(false);
temporaryDocument = await decompiledSourceService.AddSourceToAsync(temporaryDocument, compilation, symbol, cancellationToken).ConfigureAwait(false);
}
else
{
......@@ -139,7 +140,7 @@ public async Task<MetadataAsSourceFile> GetGeneratedFileAsync(Project project, I
if (!useDecompiler)
{
var sourceFromMetadataService = temporaryDocument.Project.LanguageServices.GetService<IMetadataAsSourceService>();
temporaryDocument = await sourceFromMetadataService.AddSourceToAsync(temporaryDocument, symbol, cancellationToken).ConfigureAwait(false);
temporaryDocument = await sourceFromMetadataService.AddSourceToAsync(temporaryDocument, compilation, symbol, cancellationToken).ConfigureAwait(false);
}
// We have the content, so write it out to disk
......
......@@ -31,11 +31,10 @@ public CSharpMetadataAsSourceService(HostLanguageServices languageServices)
{
}
protected override async Task<Document> AddAssemblyInfoRegionAsync(Document document, ISymbol symbol, CancellationToken cancellationToken)
protected override async Task<Document> AddAssemblyInfoRegionAsync(Document document, Compilation symbolCompilation, ISymbol symbol, CancellationToken cancellationToken)
{
string assemblyInfo = MetadataAsSourceHelpers.GetAssemblyInfo(symbol.ContainingAssembly);
var compilation = await document.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);
string assemblyPath = MetadataAsSourceHelpers.GetAssemblyDisplay(compilation, symbol.ContainingAssembly);
string assemblyPath = MetadataAsSourceHelpers.GetAssemblyDisplay(symbolCompilation, symbol.ContainingAssembly);
var regionTrivia = SyntaxFactory.RegionDirectiveTrivia(true)
.WithTrailingTrivia(new[] { SyntaxFactory.Space, SyntaxFactory.PreprocessingMessage(assemblyInfo) });
......
......@@ -26,7 +26,7 @@ protected AbstractMetadataAsSourceService(ICodeGenerationService codeGenerationS
_codeGenerationService = codeGenerationService;
}
public async Task<Document> AddSourceToAsync(Document document, ISymbol symbol, CancellationToken cancellationToken)
public async Task<Document> AddSourceToAsync(Document document, Compilation symbolCompilation, ISymbol symbol, CancellationToken cancellationToken)
{
if (document == null)
{
......@@ -47,7 +47,7 @@ public async Task<Document> AddSourceToAsync(Document document, ISymbol symbol,
var docCommentFormattingService = document.GetLanguageService<IDocumentationCommentFormattingService>();
var docWithDocComments = await ConvertDocCommentsToRegularComments(document, docCommentFormattingService, cancellationToken).ConfigureAwait(false);
var docWithAssemblyInfo = await AddAssemblyInfoRegionAsync(docWithDocComments, symbol.GetOriginalUnreducedDefinition(), cancellationToken).ConfigureAwait(false);
var docWithAssemblyInfo = await AddAssemblyInfoRegionAsync(docWithDocComments, symbolCompilation, symbol.GetOriginalUnreducedDefinition(), cancellationToken).ConfigureAwait(false);
var node = await docWithAssemblyInfo.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var formattedDoc = await Formatter.FormatAsync(
docWithAssemblyInfo, SpecializedCollections.SingletonEnumerable(node.FullSpan), options: null, rules: GetFormattingRules(docWithAssemblyInfo), cancellationToken: cancellationToken).ConfigureAwait(false);
......@@ -68,7 +68,12 @@ public async Task<Document> AddSourceToAsync(Document document, ISymbol symbol,
/// a string similar to "location unknown" will be placed in the comment inside the region
/// instead of the path.
/// </summary>
protected abstract Task<Document> AddAssemblyInfoRegionAsync(Document document, ISymbol symbol, CancellationToken cancellationToken);
/// <param name="document">The document to generate source into</param>
/// <param name="symbolCompilation">The <see cref="Compilation"/> in which symbol is resolved.</param>
/// <param name="symbol">The symbol to generate source for</param>
/// <param name="cancellationToken">To cancel document operations</param>
/// <returns>The updated document</returns>
protected abstract Task<Document> AddAssemblyInfoRegionAsync(Document document, Compilation symbolCompilation, ISymbol symbol, CancellationToken cancellationToken);
protected abstract Task<Document> ConvertDocCommentsToRegularComments(Document document, IDocumentationCommentFormattingService docCommentFormattingService, CancellationToken cancellationToken);
......
......@@ -14,9 +14,10 @@ internal interface IMetadataAsSourceService : ILanguageService
/// which the given ISymbol is or is a part of into the given document
/// </summary>
/// <param name="document">The document to generate source into</param>
/// <param name="symbol">The symbol whose interface to generate source for</param>
/// <param name="symbolCompilation">The <see cref="Compilation"/> in which <paramref name="symbol"/> is resolved.</param>
/// <param name="symbol">The symbol to generate source for</param>
/// <param name="cancellationToken">To cancel document operations</param>
/// <returns>The updated document</returns>
Task<Document> AddSourceToAsync(Document document, ISymbol symbol, CancellationToken cancellationToken = default);
Task<Document> AddSourceToAsync(Document document, Compilation symbolCompilation, ISymbol symbol, CancellationToken cancellationToken = default);
}
}
......@@ -51,22 +51,10 @@ public static string GetAssemblyDisplay(Compilation compilation, IAssemblySymbol
// This method is only used to generate a comment at the top of Metadata-as-Source documents and
// previous submissions are never viewed as metadata (i.e. we always have compilations) so there's no
// need to consume compilation.ScriptCompilationInfo.PreviousScriptCompilation.
var assemblyReference = TryGetAssemblyReference(compilation, assemblySymbol);
var assemblyReference = compilation.GetMetadataReference(assemblySymbol);
return assemblyReference?.Display ?? FeaturesResources.location_unknown;
}
public static MetadataReference TryGetAssemblyReference(Compilation compilation, IAssemblySymbol assemblySymbol)
{
return compilation.References.Where(r =>
{
var referencedSymbol = compilation.GetAssemblyOrModuleSymbol(r) as IAssemblySymbol;
return
referencedSymbol != null &&
referencedSymbol.MetadataName == assemblySymbol.MetadataName;
})
.FirstOrDefault();
}
public static INamedTypeSymbol GetTopLevelContainingNamedType(ISymbol symbol)
{
// Traverse up until we find a named type that is parented by the namespace
......
......@@ -11,7 +11,6 @@ Imports Microsoft.CodeAnalysis.MetadataAsSource
Imports Microsoft.CodeAnalysis.Options
Imports Microsoft.CodeAnalysis.Simplification
Imports Microsoft.CodeAnalysis.VisualBasic
Imports Microsoft.CodeAnalysis.VisualBasic.DocumentationComments
Imports Microsoft.CodeAnalysis.VisualBasic.Simplification
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
......@@ -25,10 +24,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.MetadataAsSource
MyBase.New(languageServices.GetService(Of ICodeGenerationService)())
End Sub
Protected Overrides Async Function AddAssemblyInfoRegionAsync(document As Document, symbol As ISymbol, cancellationToken As CancellationToken) As Task(Of Document)
Protected Overrides Async Function AddAssemblyInfoRegionAsync(document As Document, symbolCompilation As Compilation, symbol As ISymbol, cancellationToken As CancellationToken) As Task(Of Document)
Dim assemblyInfo = MetadataAsSourceHelpers.GetAssemblyInfo(symbol.ContainingAssembly)
Dim compilation = Await document.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(False)
Dim assemblyPath = MetadataAsSourceHelpers.GetAssemblyDisplay(compilation, symbol.ContainingAssembly)
Dim assemblyPath = MetadataAsSourceHelpers.GetAssemblyDisplay(symbolCompilation, symbol.ContainingAssembly)
Dim regionTrivia = SyntaxFactory.RegionDirectiveTrivia(
SyntaxFactory.Token(SyntaxKind.HashToken),
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册