예제 #1
0
            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);
            }
예제 #2
0
            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);
            }
예제 #3
0
            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;
예제 #7
0
                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);
                    }
                }