Пример #1
0
        public static async Task <DefinitionItem?> GetDefinitionAsync(Solution solution, StackFrameCompilationUnit compilationUnit, StackFrameSymbolPart symbolPart, CancellationToken cancellationToken)
        {
            // MemberAccessExpression is [Expression].[Identifier], and Identifier is the
            // method name.
            var typeExpression = compilationUnit.MethodDeclaration.MemberAccessExpression.Left;

            // typeExpression.ToString() returns the full expression (or identifier)
            // including arity for generic types.
            var fullyQualifiedTypeName = typeExpression.ToString();

            var typeName = typeExpression is StackFrameQualifiedNameNode qualifiedName
                ? qualifiedName.Right.ToString()
                : typeExpression.ToString();

            RoslynDebug.AssertNotNull(fullyQualifiedTypeName);

            var methodNode          = compilationUnit.MethodDeclaration.MemberAccessExpression.Right;
            var methodTypeArguments = compilationUnit.MethodDeclaration.TypeArguments;
            var methodArguments     = compilationUnit.MethodDeclaration.ArgumentList;

            //
            // Do a first pass to find projects with the type name to check first
            //
            using var _ = PooledObjects.ArrayBuilder <Project> .GetInstance(out var candidateProjects);

            foreach (var project in solution.Projects)
            {
                if (!project.SupportsCompilation)
                {
                    continue;
                }

                var containsSymbol = await project.ContainsSymbolsWithNameAsync(
                    typeName,
                    SymbolFilter.Type,
                    cancellationToken).ConfigureAwait(false);

                if (containsSymbol)
                {
                    var method = await TryGetBestMatchAsync(project, fullyQualifiedTypeName, methodNode, methodArguments, methodTypeArguments, cancellationToken).ConfigureAwait(false);

                    if (method is not null)
                    {
                        return(GetDefinition(method));
                    }
                }
                else
                {
                    candidateProjects.Add(project);
                }
            }

            //
            // Do a second pass to check the remaining compilations
            // for the symbol, which may be a metadata symbol in the compilation
            //
            foreach (var project in candidateProjects)
            {
                var method = await TryGetBestMatchAsync(project, fullyQualifiedTypeName, methodNode, methodArguments, methodTypeArguments, cancellationToken).ConfigureAwait(false);

                if (method is not null)
                {
                    return(GetDefinition(method));
                }
            }

            return(null);

            //
            // Local Functions
            //

            DefinitionItem GetDefinition(IMethodSymbol method)
            {
                ISymbol symbol = method;

                if (symbolPart == StackFrameSymbolPart.ContainingType)
                {
                    symbol = method.ContainingType;
                }

                return(symbol.ToNonClassifiedDefinitionItem(
                           solution,
                           FindReferencesSearchOptions.Default with {
                    UnidirectionalHierarchyCascade = true
                },
                           includeHiddenLocations: true));
            }
Пример #2
0
        public static async Task <DefinitionItem?> GetDefinitionAsync(Solution solution, StackFrameCompilationUnit compilationUnit, StackFrameSymbolPart symbolPart, CancellationToken cancellationToken)
        {
            // MemberAccessExpression is [Expression].[Identifier], and Identifier is the
            // method name.
            var typeExpression = compilationUnit.MethodDeclaration.MemberAccessExpression.Left;

            // typeExpression.ToString() returns the full expression (or identifier)
            // including arity for generic types.
            var fullyQualifiedTypeName = typeExpression.ToString();

            var typeName = typeExpression is StackFrameQualifiedNameNode qualifiedName
                ? qualifiedName.Right.ToString()
                : typeExpression.ToString();

            RoslynDebug.AssertNotNull(fullyQualifiedTypeName);

            var methodIdentifier    = compilationUnit.MethodDeclaration.MemberAccessExpression.Right;
            var methodTypeArguments = compilationUnit.MethodDeclaration.TypeArguments;
            var methodArguments     = compilationUnit.MethodDeclaration.ArgumentList;

            var methodName = methodIdentifier.ToString();

            //
            // Do a first pass to find projects with the type name to check first
            //
            using var _ = PooledObjects.ArrayBuilder <Project> .GetInstance(out var candidateProjects);

            foreach (var project in solution.Projects)
            {
                if (!project.SupportsCompilation)
                {
                    continue;
                }

                var containsSymbol = await project.ContainsSymbolsWithNameAsync(
                    typeName,
                    SymbolFilter.Type,
                    cancellationToken).ConfigureAwait(false);

                if (containsSymbol)
                {
                    var matchingMethods = await GetMatchingMembersFromCompilationAsync(project).ConfigureAwait(false);

                    if (matchingMethods.Any())
                    {
                        return(await GetDefinitionAsync(matchingMethods[0]).ConfigureAwait(false));
                    }
                }
                else
                {
                    candidateProjects.Add(project);
                }
            }

            //
            // Do a second pass to check the remaining compilations
            // for the symbol, which may be a metadata symbol in the compilation
            //
            foreach (var project in candidateProjects)
            {
                var matchingMethods = await GetMatchingMembersFromCompilationAsync(project).ConfigureAwait(false);

                if (matchingMethods.Any())
                {
                    return(await GetDefinitionAsync(matchingMethods[0]).ConfigureAwait(false));
                }
            }

            return(null);

            //
            // Local Functions
            //

            async Task <ImmutableArray <IMethodSymbol> > GetMatchingMembersFromCompilationAsync(Project project)
            {
                var compilation = await project.GetRequiredCompilationAsync(cancellationToken).ConfigureAwait(false);

                var type = compilation.GetTypeByMetadataName(fullyQualifiedTypeName);

                if (type is null)
                {
                    return(ImmutableArray <IMethodSymbol> .Empty);
                }

                var members = type.GetMembers();

                return(members
                       .OfType <IMethodSymbol>()
                       .Where(m => m.Name == methodName)
                       .Where(m => MatchTypeArguments(m.TypeArguments, methodTypeArguments))
                       .Where(m => MatchParameters(m.Parameters, methodArguments))
                       .ToImmutableArrayOrEmpty());
            }

            Task <DefinitionItem> GetDefinitionAsync(IMethodSymbol method)
            {
                ISymbol symbol = method;

                if (symbolPart == StackFrameSymbolPart.ContainingType)
                {
                    symbol = method.ContainingType;
                }

                return(symbol.ToNonClassifiedDefinitionItemAsync(solution, includeHiddenLocations: true, cancellationToken));
            }
        }