private async Task UpdateReferenceAsync( Project project, PortableExecutableReference reference, CancellationToken cancellationToken) { var key = GetReferenceKey(reference); if (key == null) { return; } var checksum = SymbolTreeInfo.GetMetadataChecksum(project.Solution, reference, cancellationToken); if (!_metadataPathToInfo.TryGetValue(key, out var metadataInfo) || metadataInfo.SymbolTreeInfo.Checksum != checksum) { var info = await SymbolTreeInfo.TryGetInfoForMetadataReferenceAsync( project.Solution, reference, checksum, loadOnly : false, cancellationToken : cancellationToken).ConfigureAwait(false); // Note, getting the info may fail (for example, bogus metadata). That's ok. // We still want to cache that result so that don't try to continuously produce // this info over and over again. metadataInfo = new MetadataInfo(info, metadataInfo.ReferencingProjects ?? new HashSet <ProjectId>()); _metadataPathToInfo.AddOrUpdate(key, metadataInfo, (_1, _2) => metadataInfo); } // Keep track that this dll is referenced by this project. metadataInfo.ReferencingProjects.Add(project.Id); }
public async ValueTask <SymbolTreeInfo> TryGetMetadataSymbolTreeInfoAsync( Solution solution, PortableExecutableReference reference, CancellationToken cancellationToken) { var metadataId = SymbolTreeInfo.GetMetadataIdNoThrow(reference); if (metadataId == null) { return(null); } var checksum = SymbolTreeInfo.GetMetadataChecksum(solution, reference, cancellationToken); // See if the last value produced matches what the caller is asking for. If so, return that. if (_metadataIdToInfo.TryGetValue(metadataId, out var metadataInfo) && metadataInfo.SymbolTreeInfo.Checksum == checksum) { return(metadataInfo.SymbolTreeInfo); } // If we didn't have it in our cache, see if we can load it from disk. // Note: pass 'loadOnly' so we only attempt to load from disk, not to actually // try to create the metadata. var info = await SymbolTreeInfo.GetInfoForMetadataReferenceAsync( solution, reference, checksum, loadOnly : true, cancellationToken).ConfigureAwait(false); return(info); }
public async Task <SymbolTreeInfo> TryGetMetadataSymbolTreeInfoAsync( Solution solution, PortableExecutableReference reference, CancellationToken cancellationToken) { var checksum = SymbolTreeInfo.GetMetadataChecksum(solution, reference, cancellationToken); var key = GetReferenceKey(reference); if (key != null) { if (_metadataPathToInfo.TryGetValue(key, out var metadataInfo) && metadataInfo.SymbolTreeInfo.Checksum == checksum) { return(metadataInfo.SymbolTreeInfo); } } // If we didn't have it in our cache, see if we can load it from disk. // Note: pass 'loadOnly' so we only attempt to load from disk, not to actually // try to create the metadata. var info = await SymbolTreeInfo.TryGetInfoForMetadataReferenceAsync( solution, reference, checksum, loadOnly : true, cancellationToken : cancellationToken).ConfigureAwait(false); return(info); }
private async Task UpdateReferenceAsync( Project project, PortableExecutableReference reference, CancellationToken cancellationToken) { var metadataId = SymbolTreeInfo.GetMetadataIdNoThrow(reference); if (metadataId == null) { return; } var checksum = SymbolTreeInfo.GetMetadataChecksum(project.Solution, reference, cancellationToken); if (!_metadataIdToInfo.TryGetValue(metadataId, out var metadataInfo) || metadataInfo.SymbolTreeInfo.Checksum != checksum) { var info = await SymbolTreeInfo.GetInfoForMetadataReferenceAsync( project.Solution, reference, checksum, loadOnly : false, cancellationToken : cancellationToken).ConfigureAwait(false); Contract.ThrowIfNull(info); Contract.ThrowIfTrue(info.Checksum != checksum, "If we computed a SymbolTreeInfo, then its checksum much match our checksum."); // Note, getting the info may fail (for example, bogus metadata). That's ok. // We still want to cache that result so that don't try to continuously produce // this info over and over again. metadataInfo = new MetadataInfo(info, metadataInfo.ReferencingProjects ?? new HashSet <ProjectId>()); _metadataIdToInfo[metadataId] = metadataInfo; } // Keep track that this dll is referenced by this project. metadataInfo.ReferencingProjects.Add(project.Id); }
public ImmutableArray <CompletionItem> GetTopLevelTypesFromPEReference( Solution solution, Compilation compilation, PortableExecutableReference peReference, SyntaxContext syntaxContext, bool isInternalsVisible, CancellationToken cancellationToken) { var key = GetReferenceKey(peReference); if (key == null) { // Can't cache items for reference with null key. We don't want risk potential perf regression by // making those items repeatedly, so simply not returning anything from this assembly, until // we have a better understanding on this sceanrio. // TODO: Add telemetry return(ImmutableArray <CompletionItem> .Empty); } if (!(compilation.GetAssemblyOrModuleSymbol(peReference) is IAssemblySymbol assemblySymbol)) { return(ImmutableArray <CompletionItem> .Empty); } var checksum = SymbolTreeInfo.GetMetadataChecksum(solution, peReference, cancellationToken); return(GetAccessibleTopLevelTypesWorker( key, assemblySymbol, checksum, syntaxContext, isInternalsVisible, CacheService.PEItemsCache, cancellationToken));
public void GetTopLevelTypesFromPEReference( Solution solution, Compilation compilation, PortableExecutableReference peReference, Action <TypeImportCompletionItemInfo> handleItem, CancellationToken cancellationToken) { var key = GetReferenceKey(peReference); if (key == null) { // Can't cache items for reference with null key. We don't want risk potential perf regression by // making those items repeatedly, so simply not returning anything from this assembly, until // we have a better understanding on this sceanrio. // TODO: Add telemetry return; } if (!(compilation.GetAssemblyOrModuleSymbol(peReference) is IAssemblySymbol assemblySymbol)) { return; } var checksum = SymbolTreeInfo.GetMetadataChecksum(solution, peReference, cancellationToken); GetAccessibleTopLevelTypesWorker( key, assemblySymbol, checksum, handleItem, _peItemsCache, cancellationToken); return;
static async Task UpdateReferenceAsync( ConcurrentDictionary <MetadataId, MetadataInfo> metadataIdToInfo, Project project, PortableExecutableReference reference, CancellationToken cancellationToken ) { var metadataId = SymbolTreeInfo.GetMetadataIdNoThrow(reference); if (metadataId == null) { return; } // 🐉 PERF: GetMetadataChecksum indirectly uses a ConditionalWeakTable. This call is intentionally // placed before the first 'await' of this asynchronous method to ensure it executes in the // synchronous portion of the caller. https://dev.azure.com/devdiv/DevDiv/_workitems/edit/1270250 var checksum = SymbolTreeInfo.GetMetadataChecksum( project.Solution, reference, cancellationToken ); if ( !metadataIdToInfo.TryGetValue(metadataId, out var metadataInfo) || metadataInfo.SymbolTreeInfo.Checksum != checksum ) { var info = await SymbolTreeInfo .GetInfoForMetadataReferenceAsync( project.Solution, reference, checksum, loadOnly : false, cancellationToken : cancellationToken ) .ConfigureAwait(false); Contract.ThrowIfNull(info); Contract.ThrowIfTrue( info.Checksum != checksum, "If we computed a SymbolTreeInfo, then its checksum much match our checksum." ); // Note, getting the info may fail (for example, bogus metadata). That's ok. // We still want to cache that result so that don't try to continuously produce // this info over and over again. metadataInfo = new MetadataInfo( info, metadataInfo.ReferencingProjects ?? new HashSet <ProjectId>() ); metadataIdToInfo[metadataId] = metadataInfo; } // Keep track that this dll is referenced by this project. lock (metadataInfo.ReferencingProjects) { metadataInfo.ReferencingProjects.Add(project.Id); } }