コード例 #1
0
        internal static ISymbol ResolveSymbol(ISymbol originalSymbol, Compilation targetCompilation, SymbolKeyComparison comparison)
        {
            var sid     = SymbolKey.Create(originalSymbol, CancellationToken.None);
            var symInfo = sid.Resolve(targetCompilation, (comparison & SymbolKeyComparison.IgnoreAssemblyIds) == SymbolKeyComparison.IgnoreAssemblyIds);

            return(symInfo.Symbol);
        }
コード例 #2
0
        private static bool IsCompatible <TExpressionSyntax>(
            ISemanticFactsService semanticFacts,
            SemanticModel semanticModel,
            IMethodSymbol constructor,
            ImmutableArray <TExpressionSyntax> expressions)
            where TExpressionSyntax : SyntaxNode
        {
            Debug.Assert(constructor.Parameters.Length == expressions.Length);

            // Resolve the constructor into our semantic model's compilation; if the constructor we're looking at is from
            // another project with a different language.
            var constructorInCompilation = (IMethodSymbol?)SymbolKey.Create(constructor).Resolve(semanticModel.Compilation).Symbol;

            Contract.ThrowIfNull(constructorInCompilation);

            for (var i = 0; i < constructorInCompilation.Parameters.Length; i++)
            {
                var constructorParameter = constructorInCompilation.Parameters[i];
                if (constructorParameter == null)
                {
                    return(false);
                }

                var conversion = semanticFacts.ClassifyConversion(semanticModel, expressions[i], constructorParameter.Type);
                if (!conversion.IsIdentity && !conversion.IsImplicit)
                {
                    return(false);
                }
            }

            return(true);
        }
コード例 #3
0
        public void TestGenericMethodTypeParameterMissing1()
        {
            var source1 = @"
public class C
{
    void M<T>(T t) { }
}
";

            var source2 = @"
public class C
{
}
";

            var compilation1 = GetCompilation(source1, LanguageNames.CSharp);
            var compilation2 = GetCompilation(source2, LanguageNames.CSharp);

            var methods = GetDeclaredSymbols(compilation1).OfType <IMethodSymbol>();

            foreach (var method in methods)
            {
                var key = SymbolKey.Create(method);
                key.Resolve(compilation2);
            }
        }
コード例 #4
0
        private static bool TryResolveSymbol(ISymbol symbol, Project project, CancellationToken cancellationToken, out ISymbol resolvedSymbol, out Project resolvedProject)
        {
            resolvedSymbol  = null;
            resolvedProject = null;

            var currentProject = project.Solution.Workspace.CurrentSolution.GetProject(project.Id);

            if (currentProject == null)
            {
                return(false);
            }

            var originalCompilation = project.GetCompilationAsync(cancellationToken).WaitAndGetResult(cancellationToken);
            var symbolId            = SymbolKey.Create(symbol, cancellationToken);
            var currentCompilation  = currentProject.GetCompilationAsync(cancellationToken).WaitAndGetResult(cancellationToken);
            var symbolInfo          = symbolId.Resolve(currentCompilation, cancellationToken: cancellationToken);

            if (symbolInfo.Symbol == null)
            {
                return(false);
            }

            resolvedSymbol  = symbolInfo.Symbol;
            resolvedProject = currentProject;

            return(true);
        }
コード例 #5
0
        internal static void AssertSymbolKeysEqual(ISymbol symbol1, ISymbol symbol2, SymbolKeyComparison comparison, bool expectEqual = true)
        {
            var sid1 = SymbolKey.Create(symbol1, CancellationToken.None);
            var sid2 = SymbolKey.Create(symbol2, CancellationToken.None);

            // default is Insensitive
            var ignoreCase = (comparison & SymbolKeyComparison.IgnoreCase) == SymbolKeyComparison.IgnoreCase;

            // default is NOT ignore
            var ignoreAssemblyIds = (comparison & SymbolKeyComparison.IgnoreAssemblyIds) == SymbolKeyComparison.IgnoreAssemblyIds;
            var message           = string.Concat(
                ignoreCase ? "SymbolID IgnoreCase" : "SymbolID",
                ignoreAssemblyIds ? " IgnoreAssemblyIds " : " ",
                "Compare");

            var ret = CodeAnalysis.SymbolKey.GetComparer(ignoreCase, ignoreAssemblyIds).Equals(sid2, sid1);

            if (expectEqual)
            {
                Assert.True(ret, message);
            }
            else
            {
                Assert.False(ret, message);
            }
        }
コード例 #6
0
        public async Task <IEnumerable <IPeekableItem> > GetPeekableItemsAsync(ISymbol symbol, Project project, IPeekResultFactory peekResultFactory, CancellationToken cancellationToken)
        {
            if (symbol == null)
            {
                throw new ArgumentNullException(nameof(symbol));
            }

            if (project == null)
            {
                throw new ArgumentNullException(nameof(project));
            }

            if (peekResultFactory == null)
            {
                throw new ArgumentNullException(nameof(peekResultFactory));
            }

            var results = new List <IPeekableItem>();

            var solution         = project.Solution;
            var sourceDefinition = await SymbolFinder.FindSourceDefinitionAsync(symbol, solution, cancellationToken).ConfigureAwait(false);

            // And if our definition actually is from source, then let's re-figure out what project it came from
            if (sourceDefinition != null)
            {
                var originatingProject = solution.GetProject(sourceDefinition.ContainingAssembly, cancellationToken);

                project = originatingProject ?? project;
            }

            string filePath;
            int    lineNumber;
            int    charOffset;

            var symbolNavigationService = solution.Workspace.Services.GetService <ISymbolNavigationService>();

            if (symbolNavigationService.WouldNavigateToSymbol(symbol, solution, out filePath, out lineNumber, out charOffset))
            {
                var position = new LinePosition(lineNumber, charOffset);
                results.Add(new ExternalFilePeekableItem(new FileLinePositionSpan(filePath, position, position), PredefinedPeekRelationships.Definitions, peekResultFactory));
            }
            else
            {
                var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);

                var symbolKey = SymbolKey.Create(symbol, compilation, cancellationToken);

                var firstLocation = symbol.Locations.FirstOrDefault();
                if (firstLocation != null)
                {
                    if (firstLocation.IsInSource || _metadataAsSourceFileService.IsNavigableMetadataSymbol(symbol))
                    {
                        results.Add(new DefinitionPeekableItem(solution.Workspace, project.Id, symbolKey, peekResultFactory, _metadataAsSourceFileService));
                    }
                }
            }

            return(results);
        }
コード例 #7
0
        public async Task <IEnumerable <IPeekableItem> > GetPeekableItemsAsync(
            ISymbol symbol, Project project,
            IPeekResultFactory peekResultFactory,
            CancellationToken cancellationToken)
        {
            if (symbol == null)
            {
                throw new ArgumentNullException(nameof(symbol));
            }

            if (project == null)
            {
                throw new ArgumentNullException(nameof(project));
            }

            if (peekResultFactory == null)
            {
                throw new ArgumentNullException(nameof(peekResultFactory));
            }

            var results = new List <IPeekableItem>();

            var solution         = project.Solution;
            var sourceDefinition = await SymbolFinder.FindSourceDefinitionAsync(symbol, solution, cancellationToken).ConfigureAwait(false);

            // And if our definition actually is from source, then let's re-figure out what project it came from
            if (sourceDefinition != null)
            {
                var originatingProject = solution.GetProject(sourceDefinition.ContainingAssembly, cancellationToken);

                project = originatingProject ?? project;
            }

            var symbolNavigationService = solution.Workspace.Services.GetService <ISymbolNavigationService>();
            var definitionItem          = symbol.ToNonClassifiedDefinitionItem(solution, includeHiddenLocations: true);

            var result = await symbolNavigationService.GetExternalNavigationSymbolLocationAsync(definitionItem, cancellationToken).ConfigureAwait(false);

            if (result is var(filePath, linePosition))
            {
                results.Add(new ExternalFilePeekableItem(new FileLinePositionSpan(filePath, linePosition, linePosition), PredefinedPeekRelationships.Definitions, peekResultFactory));
            }
            else
            {
                var symbolKey = SymbolKey.Create(symbol, cancellationToken);

                var firstLocation = symbol.Locations.FirstOrDefault();
                if (firstLocation != null)
                {
                    if (firstLocation.IsInSource || _metadataAsSourceFileService.IsNavigableMetadataSymbol(symbol))
                    {
                        results.Add(new DefinitionPeekableItem(solution.Workspace, project.Id, symbolKey, peekResultFactory, _metadataAsSourceFileService, _globalOptions));
                    }
                }
            }

            return(results);
        }
コード例 #8
0
            private bool CanResolveSymbolKey(ISymbol m, Compilation compilation)
            {
                // SymbolKey doesn't guarantee roundtrip-ability, which we need in order to generate overrides.
                // Preemptively filter out those methods whose SymbolKeys we won't be able to round trip.
                var key    = SymbolKey.Create(m, _cancellationToken);
                var result = key.Resolve(compilation, cancellationToken: _cancellationToken);

                return(result.Symbol != null);
            }
コード例 #9
0
        private static bool IsCompatible <TExpressionSyntax>(
            ISemanticFactsService semanticFacts,
            SemanticModel semanticModel,
            IMethodSymbol constructor,
            ImmutableArray <TExpressionSyntax?> expressions)
            where TExpressionSyntax : SyntaxNode
        {
            Debug.Assert(constructor.Parameters.Length == expressions.Length);

            // Resolve the constructor into our semantic model's compilation; if the constructor we're looking at is from
            // another project with a different language.
            var constructorInCompilation = (IMethodSymbol?)SymbolKey.Create(constructor).Resolve(semanticModel.Compilation).Symbol;

            if (constructorInCompilation == null)
            {
                // If the constructor can't be mapped into our invocation project, we'll just bail.
                // Note the logic in this method doesn't handle a complicated case where:
                //
                // 1. Project A has some public type.
                // 2. Project B references A, and has one constructor that uses the public type from A.
                // 3. Project C, which references B but not A, has an invocation of B's constructor passing some
                //    parameters.
                //
                // The algorithm of this class tries to map the constructor in B (that we might delegate to) into
                // C, but that constructor might not be mappable if the public type from A is not available.
                // However, theoretically the public type from A could have a user-defined conversion.
                // The alternative approach might be to map the type of the parameters back into B, and then
                // classify the conversions in Project B, but that'll run into other issues if the experssions
                // don't have a natural type (like default). We choose to ignore all complicated cases here.
                return(false);
            }

            for (var i = 0; i < constructorInCompilation.Parameters.Length; i++)
            {
                var constructorParameter = constructorInCompilation.Parameters[i];
                if (constructorParameter == null)
                {
                    return(false);
                }

                // In VB the argument may not have been specified at all if the parameter is optional
                if (expressions[i] is null && constructorParameter.IsOptional)
                {
                    continue;
                }

                var conversion = semanticFacts.ClassifyConversion(semanticModel, expressions[i], constructorParameter.Type);
                if (!conversion.IsIdentity && !conversion.IsImplicit)
                {
                    return(false);
                }
            }

            return(true);
        }
コード例 #10
0
 public async Task <SymbolMappingResult?> MapSymbolAsync(
     Document document,
     ISymbol symbol,
     CancellationToken cancellationToken
     )
 {
     return(await MapSymbolAsync(
                document,
                SymbolKey.Create(symbol, cancellationToken),
                cancellationToken
                )
            .ConfigureAwait(false));
 }
コード例 #11
0
        public async Task TestGetInteriorSymbolsDoesNotCrashOnSpeculativeSemanticModel()
        {
            var    markup = @"
class C
{
    void foo()
    {
        System.Func<int> lambda = () => 
        {
        int x;
        $$
        }
    }
}";
            int    position;
            string text;

            MarkupTestFile.GetPosition(markup, out text, out position);

            var sourceText = SourceText.From(text);
            var workspace  = new AdhocWorkspace();
            var project    = workspace.AddProject("Test", LanguageNames.CSharp);
            var document   = workspace.AddDocument(project.Id, "testdocument", sourceText);

            var firstModel = await document.GetSemanticModelAsync();

            var tree1 = await document.GetSyntaxTreeAsync();

            var basemethod1 = tree1.FindTokenOnLeftOfPosition(position, CancellationToken.None).GetAncestor <CSharp.Syntax.BaseMethodDeclarationSyntax>();

            // Modify the document so we can use the old semantic model as a base.
            var updated = sourceText.WithChanges(new TextChange(new TextSpan(position, 0), "insertion"));

            workspace.TryApplyChanges(document.WithText(updated).Project.Solution);

            document = workspace.CurrentSolution.GetDocument(document.Id);
            var tree2 = await document.GetSyntaxTreeAsync();

            var basemethod2 = tree2.FindTokenOnLeftOfPosition(position, CancellationToken.None).GetAncestor <CSharp.Syntax.BaseMethodDeclarationSyntax>();

            var           service = new CSharp.CSharpSemanticFactsService();
            SemanticModel testModel;
            var           m = service.TryGetSpeculativeSemanticModel(firstModel, basemethod1, basemethod2, out testModel);

            var xSymbol = testModel.LookupSymbols(position).First(s => s.Name == "x");

            // This should not throw an exception.
            Assert.NotNull(SymbolKey.Create(xSymbol));
        }
コード例 #12
0
        public void C2CTypeSymbolChanged02()
        {
            var src1 =
                @"using System;
namespace NS
{
    public class C1 
    {
        public void M() {}
    }
}
";

            var src2 =
                @"
namespace NS
{
    internal class C1 // add new C1
    {
        public string P { get; set; }
    }

    public class C2  // rename C1 to C2
    {
        public void M() {}
    }
}
";
            var comp1 = (Compilation)CreateCompilation(src1, assemblyName: "Test");
            var comp2 = (Compilation)CreateCompilation(src2, assemblyName: "Test");

            var namespace1 =
                comp1.SourceModule.GlobalNamespace.GetMembers("NS").Single() as INamespaceSymbol;
            var typeSym00 = namespace1.GetTypeMembers("C1").FirstOrDefault() as INamedTypeSymbol;

            var namespace2 =
                comp2.SourceModule.GlobalNamespace.GetMembers("NS").Single() as INamespaceSymbol;
            var typeSym01 = namespace2.GetTypeMembers("C1").FirstOrDefault() as INamedTypeSymbol;
            var typeSym02 = namespace2.GetTypeMembers("C2").Single() as INamedTypeSymbol;

            // new C1 resolve to old C1
            ResolveAndVerifySymbol(typeSym01, typeSym00, comp1);

            // old C1 (new C2) NOT resolve to old C1
            var symkey  = SymbolKey.Create(typeSym02, CancellationToken.None);
            var syminfo = symkey.Resolve(comp1);

            Assert.Null(syminfo.Symbol);
        }
コード例 #13
0
        internal static ISymbol ResolveSymbol(ISymbol originalSymbol, Compilation targetCompilation, SymbolKeyComparison comparison)
        {
            var sid = SymbolKey.Create(originalSymbol, CancellationToken.None);

            // Verify that serialization works.
            var serialized   = sid.ToString();
            var deserialized = new SymbolKey(serialized);
            var comparer     = SymbolKey.GetComparer(ignoreCase: false, ignoreAssemblyKeys: false);

            Assert.True(comparer.Equals(sid, deserialized));

            var symInfo = sid.Resolve(targetCompilation, (comparison & SymbolKeyComparison.IgnoreAssemblyIds) == SymbolKeyComparison.IgnoreAssemblyIds);

            return(symInfo.Symbol);
        }
コード例 #14
0
        public static async ValueTask <ValueTrackedItem?> TryCreateAsync(Solution solution, Location location, ISymbol symbol, ValueTrackedItem?parent = null, CancellationToken cancellationToken = default)
        {
            Contract.ThrowIfNull(location.SourceTree);

            var document   = solution.GetRequiredDocument(location.SourceTree);
            var syntaxTree = await document.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);

            var sourceText = await syntaxTree.GetTextAsync(cancellationToken).ConfigureAwait(false);

            return(new ValueTrackedItem(
                       SymbolKey.Create(symbol, cancellationToken),
                       sourceText,
                       location.SourceSpan,
                       document.Id,
                       symbol.GetGlyph(),
                       parent));
        }
コード例 #15
0
ファイル: ValueTrackedItem.cs プロジェクト: Forgind/roslyn
        public static async Task <ValueTrackedItem?> TryCreateAsync(Document document, TextSpan textSpan, ISymbol symbol, ValueTrackedItem?parent = null, CancellationToken cancellationToken = default)
        {
            var        excerptService = document.Services.GetService <IDocumentExcerptService>();
            SourceText?sourceText     = null;
            ImmutableArray <ClassifiedSpan> classifiedSpans = default;

            if (excerptService != null)
            {
                var result = await excerptService.TryExcerptAsync(document, textSpan, ExcerptMode.SingleLine, cancellationToken).ConfigureAwait(false);

                if (result.HasValue)
                {
                    var value = result.Value;
                    sourceText = value.Content;
                }
            }

            if (sourceText is null)
            {
                var options      = ClassificationOptions.From(document.Project);
                var documentSpan = await ClassifiedSpansAndHighlightSpanFactory.GetClassifiedDocumentSpanAsync(document, textSpan, options, cancellationToken).ConfigureAwait(false);

                var classificationResult = await ClassifiedSpansAndHighlightSpanFactory.ClassifyAsync(documentSpan, options, cancellationToken).ConfigureAwait(false);

                classifiedSpans = classificationResult.ClassifiedSpans;
                var syntaxTree = await document.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);

                sourceText = await syntaxTree.GetTextAsync(cancellationToken).ConfigureAwait(false);
            }

            return(new ValueTrackedItem(
                       SymbolKey.Create(symbol, cancellationToken),
                       sourceText,
                       classifiedSpans,
                       textSpan,
                       document.Id,
                       symbol.GetGlyph(),
                       parent: parent));
        }
コード例 #16
0
        public override async Task <bool> TryGoToDefinitionAsync(
            ISymbol symbol, Project project, CancellationToken cancellationToken)
        {
            var currentProject = project.Solution.Workspace.CurrentSolution.GetProject(project.Id);

            if (currentProject == null)
            {
                return(false);
            }

            var symbolId           = SymbolKey.Create(symbol, cancellationToken);
            var currentCompilation = await currentProject.GetRequiredCompilationAsync(cancellationToken).ConfigureAwait(false);

            var symbolInfo = symbolId.Resolve(currentCompilation, cancellationToken: cancellationToken);

            if (symbolInfo.Symbol == null)
            {
                return(false);
            }

            return(await GoToDefinitionHelpers.TryNavigateToLocationAsync(
                       symbolInfo.Symbol, currentProject.Solution,
                       _threadingContext, _streamingPresenter.Value, cancellationToken).ConfigureAwait(false));
        }
コード例 #17
0
        public async Task <MetadataAsSourceFile> GetGeneratedFileAsync(Project project, ISymbol symbol, bool allowDecompilation, CancellationToken cancellationToken = default)
        {
            if (project == null)
            {
                throw new ArgumentNullException(nameof(project));
            }

            if (symbol == null)
            {
                throw new ArgumentNullException(nameof(symbol));
            }

            if (symbol.Kind == SymbolKind.Namespace)
            {
                throw new ArgumentException(EditorFeaturesResources.symbol_cannot_be_a_namespace, nameof(symbol));
            }

            symbol = symbol.GetOriginalUnreducedDefinition();

            MetadataAsSourceGeneratedFileInfo fileInfo;
            Location navigateLocation  = null;
            var      topLevelNamedType = MetadataAsSourceHelpers.GetTopLevelContainingNamedType(symbol);
            var      symbolId          = SymbolKey.Create(symbol, cancellationToken);

            using (await _gate.DisposableWaitAsync(cancellationToken).ConfigureAwait(false))
            {
                InitializeWorkspace(project);

                var infoKey = await GetUniqueDocumentKey(project, topLevelNamedType, cancellationToken).ConfigureAwait(false);

                fileInfo = _keyToInformation.GetOrAdd(infoKey, _ => new MetadataAsSourceGeneratedFileInfo(GetRootPathWithGuid_NoLock(), project, topLevelNamedType));

                _generatedFilenameToInformation[fileInfo.TemporaryFilePath] = fileInfo;

                if (!File.Exists(fileInfo.TemporaryFilePath))
                {
                    // We need to generate this. First, we'll need a temporary project to do the generation into. We
                    // avoid loading the actual file from disk since it doesn't exist yet.
                    var temporaryProjectInfoAndDocumentId = fileInfo.GetProjectInfoAndDocumentId(_workspace, loadFileFromDisk: false);
                    var temporaryDocument = _workspace.CurrentSolution.AddProject(temporaryProjectInfoAndDocumentId.Item1)
                                            .GetDocument(temporaryProjectInfoAndDocumentId.Item2);

                    var useDecompiler = allowDecompilation;
                    if (useDecompiler)
                    {
                        try
                        {
                            temporaryDocument = await DecompileSymbolAsync(temporaryDocument, symbol, cancellationToken).ConfigureAwait(false);
                        }
                        catch (Exception e) when(FatalError.ReportWithoutCrashUnlessCanceled(e))
                        {
                            useDecompiler = false;
                        }
                    }

                    if (!useDecompiler)
                    {
                        var sourceFromMetadataService = temporaryDocument.Project.LanguageServices.GetService <IMetadataAsSourceService>();
                        temporaryDocument = await sourceFromMetadataService.AddSourceToAsync(temporaryDocument, symbol, cancellationToken).ConfigureAwait(false);
                    }

                    // We have the content, so write it out to disk
                    var text = await temporaryDocument.GetTextAsync(cancellationToken).ConfigureAwait(false);

                    // Create the directory. It's possible a parallel deletion is happening in another process, so we may have
                    // to retry this a few times.
                    var directoryToCreate = Path.GetDirectoryName(fileInfo.TemporaryFilePath);
                    while (!Directory.Exists(directoryToCreate))
                    {
                        try
                        {
                            Directory.CreateDirectory(directoryToCreate);
                        }
                        catch (DirectoryNotFoundException)
                        {
                        }
                        catch (UnauthorizedAccessException)
                        {
                        }
                    }

                    using (var textWriter = new StreamWriter(fileInfo.TemporaryFilePath, append: false, encoding: fileInfo.Encoding))
                    {
                        text.Write(textWriter);
                    }

                    // Mark read-only
                    new FileInfo(fileInfo.TemporaryFilePath).IsReadOnly = true;

                    // Locate the target in the thing we just created
                    navigateLocation = await MetadataAsSourceHelpers.GetLocationInGeneratedSourceAsync(symbolId, temporaryDocument, cancellationToken).ConfigureAwait(false);
                }

                // If we don't have a location yet, then that means we're re-using an existing file. In this case, we'll want to relocate the symbol.
                if (navigateLocation == null)
                {
                    navigateLocation = await RelocateSymbol_NoLock(fileInfo, symbolId, cancellationToken).ConfigureAwait(false);
                }
            }

            var documentName = string.Format(
                "{0} [{1}]",
                topLevelNamedType.Name,
                EditorFeaturesResources.from_metadata);

            var documentTooltip = topLevelNamedType.ToDisplayString(new SymbolDisplayFormat(typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces));

            return(new MetadataAsSourceFile(fileInfo.TemporaryFilePath, navigateLocation, documentName, documentTooltip));
        }
コード例 #18
0
        private async Task <UniqueDocumentKey> GetUniqueDocumentKey(Project project, INamedTypeSymbol topLevelNamedType, CancellationToken cancellationToken)
        {
            var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);

            var peMetadataReference = compilation.GetMetadataReference(topLevelNamedType.ContainingAssembly) as PortableExecutableReference;

            if (peMetadataReference.FilePath != null)
            {
                return(new UniqueDocumentKey(peMetadataReference.FilePath, project.Language, SymbolKey.Create(topLevelNamedType, cancellationToken)));
            }
            else
            {
                return(new UniqueDocumentKey(topLevelNamedType.ContainingAssembly.Identity, project.Language, SymbolKey.Create(topLevelNamedType, cancellationToken)));
            }
        }
コード例 #19
0
            public async Task <SymbolMappingResult> MapSymbolAsync(Document document, ISymbol symbol, CancellationToken cancellationToken)
            {
                var compilation = await document.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);

                return(await MapSymbolAsync(document, SymbolKey.Create(symbol, cancellationToken), cancellationToken).ConfigureAwait(false));
            }
コード例 #20
0
        public async Task <SignatureHelpItems?> GetItemsAsync(
            Document document, int position, SignatureHelpTriggerInfo triggerInfo, SignatureHelpOptions options, CancellationToken cancellationToken)
        {
            var itemsForCurrentDocument = await GetItemsWorkerAsync(document, position, triggerInfo, options, cancellationToken).ConfigureAwait(false);

            if (itemsForCurrentDocument == null)
            {
                return(itemsForCurrentDocument);
            }

            var relatedDocuments = await FindActiveRelatedDocumentsAsync(position, document, cancellationToken).ConfigureAwait(false);

            if (relatedDocuments.IsEmpty)
            {
                return(itemsForCurrentDocument);
            }

            var totalProjects = relatedDocuments.Select(d => d.Project.Id).Concat(document.Project.Id);

            var semanticModel = await document.ReuseExistingSpeculativeModelAsync(position, cancellationToken).ConfigureAwait(false);

            var compilation = semanticModel.Compilation;

            var finalItems = new List <SignatureHelpItem>();

            foreach (var item in itemsForCurrentDocument.Items)
            {
                if (item is not SymbolKeySignatureHelpItem symbolKeyItem ||
                    symbolKeyItem.SymbolKey is not SymbolKey symbolKey ||
                    symbolKey.Resolve(compilation, ignoreAssemblyKey: true, cancellationToken).Symbol is not ISymbol symbol)
                {
                    finalItems.Add(item);
                    continue;
                }

                // If the symbol is an instantiated generic method, ensure we use its original
                // definition for symbol key resolution in related compilations.
                if (symbol is IMethodSymbol methodSymbol && methodSymbol.IsGenericMethod && methodSymbol != methodSymbol.OriginalDefinition)
                {
                    symbolKey = SymbolKey.Create(methodSymbol.OriginalDefinition, cancellationToken);
                }

                var invalidProjectsForCurrentSymbol = new List <ProjectId>();
                foreach (var relatedDocument in relatedDocuments)
                {
                    // Try to resolve symbolKey in each related compilation,
                    // unresolvable key means the symbol is unavailable in the corresponding project.
                    var relatedSemanticModel = await relatedDocument.ReuseExistingSpeculativeModelAsync(position, cancellationToken).ConfigureAwait(false);

                    if (symbolKey.Resolve(relatedSemanticModel.Compilation, ignoreAssemblyKey: true, cancellationToken).Symbol == null)
                    {
                        invalidProjectsForCurrentSymbol.Add(relatedDocument.Project.Id);
                    }
                }

                var platformData = new SupportedPlatformData(document.Project.Solution, invalidProjectsForCurrentSymbol, totalProjects);
                finalItems.Add(UpdateItem(item, platformData));
            }

            return(new SignatureHelpItems(
                       finalItems, itemsForCurrentDocument.ApplicableSpan,
                       itemsForCurrentDocument.ArgumentIndex,
                       itemsForCurrentDocument.ArgumentCount,
                       itemsForCurrentDocument.ArgumentName,
                       itemsForCurrentDocument.SelectedItemIndex));
        }
コード例 #21
0
        private async Task <UniqueDocumentKey> GetUniqueDocumentKeyAsync(Project project, INamedTypeSymbol topLevelNamedType, bool allowDecompilation, CancellationToken cancellationToken)
        {
            var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);

            Contract.ThrowIfNull(compilation, "We are trying to produce a key for a language that doesn't support compilations.");

            var peMetadataReference = compilation.GetMetadataReference(topLevelNamedType.ContainingAssembly) as PortableExecutableReference;

            if (peMetadataReference?.FilePath != null)
            {
                return(new UniqueDocumentKey(peMetadataReference.FilePath, peMetadataReference.GetMetadataId(), project.Language, SymbolKey.Create(topLevelNamedType, cancellationToken), allowDecompilation));
            }
            else
            {
                var containingAssembly = topLevelNamedType.ContainingAssembly;
                return(new UniqueDocumentKey(containingAssembly.Identity, containingAssembly.GetMetadata()?.Id, project.Language, SymbolKey.Create(topLevelNamedType, cancellationToken), allowDecompilation));
            }
        }
コード例 #22
0
        public static Task <Location> GetLocationInGeneratedSourceAsync(ISymbol symbol, Document generatedDocument, CancellationToken cancellationToken)
        {
            var symbolKey = SymbolKey.Create(symbol, cancellationToken);

            return(MetadataAsSourceHelpers.GetLocationInGeneratedSourceAsync(symbolKey, generatedDocument, cancellationToken));
        }
コード例 #23
0
 public static string GetSymbolKeyString(
     this ISymbol symbol,
     CancellationToken cancellationToken
     ) => SymbolKey.Create(symbol, cancellationToken).ToString();