Ejemplo n.º 1
0
        private static async Task <GraphNodeId> GetPartialForNamedTypeAsync(INamedTypeSymbol namedType, GraphNodeIdName nodeName, Solution solution, CancellationToken cancellationToken, bool isInGenericArguments = false)
        {
            // If this is a simple type, then we don't have much to do
            if (namedType.ContainingType == null && namedType.ConstructedFrom == namedType && namedType.Arity == 0)
            {
                return(GraphNodeId.GetPartial(nodeName, namedType.Name));
            }
            else
            {
                // For a generic type, we need to populate "type" property with the following form:
                //
                //      Type = (Name =...GenericParameterCount = GenericArguments =...ParentType =...)
                //
                //  where "Name" contains a symbol name
                //    and "GenericParameterCount" contains the number of type parameters,
                //    and "GenericArguments" contains its type parameters' node information.
                //    and "ParentType" contains its containing type's node information.

                var partials = new List <GraphNodeId>();

                partials.Add(GraphNodeId.GetPartial(CodeQualifiedName.Name, namedType.Name));

                if (namedType.Arity > 0)
                {
                    partials.Add(GraphNodeId.GetPartial(CodeGraphNodeIdName.GenericParameterCountIdentifier, namedType.Arity.ToString()));
                }

                // For the property "GenericArguments", we only populate them
                // when type parameters are constructed using instance types (i.e., namedType.ConstructedFrom != namedType).
                // However, there is a case where we need to populate "GenericArguments" even though arguments are not marked as "constructed"
                // because a symbol is not marked as "constructed" when a type is constructed using its own type parameters.
                // To distinguish this case, we use "isInGenericArguments" flag which we pass either to populate arguments recursively or to populate "ParentType".

                bool hasGenericArguments = (namedType.ConstructedFrom != namedType || isInGenericArguments) && namedType.TypeArguments != null && namedType.TypeArguments.Any();

                if (hasGenericArguments)
                {
                    var genericArguments = new List <GraphNodeId>();
                    foreach (var arg in namedType.TypeArguments)
                    {
                        var nodes = await GetPartialsForNamespaceAndTypeAsync(arg, includeNamespace : true, solution : solution, cancellationToken : cancellationToken, isInGenericArguments : true).ConfigureAwait(false);

                        genericArguments.Add(GraphNodeId.GetNested(nodes.ToArray()));
                    }

                    partials.Add(GraphNodeId.GetArray(
                                     CodeGraphNodeIdName.GenericArgumentsIdentifier,
                                     genericArguments.ToArray()));
                }

                if (namedType.ContainingType != null)
                {
                    partials.Add(await GetPartialForTypeAsync(namedType.ContainingType, CodeGraphNodeIdName.ParentType, solution, cancellationToken, hasGenericArguments).ConfigureAwait(false));
                }

                return(GraphNodeId.GetPartial(nodeName, MakeCollectionIfNecessary(false, partials.ToArray())));
            }
        }
Ejemplo n.º 2
0
        public static async Task <GraphNodeId> GetIdForMemberAsync(ISymbol member, Solution solution, CancellationToken cancellationToken)
        {
            var partials = new List <GraphNodeId>();

            partials.AddRange(await GetPartialsForNamespaceAndTypeAsync(member.ContainingType, true, solution, cancellationToken).ConfigureAwait(false));

            var parameters = member.GetParameters();

            if (parameters.Any() || member.GetArity() > 0)
            {
                var memberPartials = new List <GraphNodeId>();

                memberPartials.Add(GraphNodeId.GetPartial(CodeQualifiedName.Name, member.MetadataName));

                if (member.GetArity() > 0)
                {
                    memberPartials.Add(GraphNodeId.GetPartial(CodeGraphNodeIdName.GenericParameterCountIdentifier, member.GetArity().ToString()));
                }

                if (parameters.Any())
                {
                    var parameterTypeIds = new List <GraphNodeId>();
                    foreach (var p in parameters)
                    {
                        var parameterIds = await GetPartialsForNamespaceAndTypeAsync(p.Type, true, solution, cancellationToken).ConfigureAwait(false);

                        var nodes = parameterIds.ToList();
                        if (p.IsRefOrOut())
                        {
                            nodes.Add(GraphNodeId.GetPartial(CodeGraphNodeIdName.ParamKind, ParamKind.Ref));
                        }

                        parameterTypeIds.Add(GraphNodeId.GetNested(nodes.ToArray()));
                    }

                    if (member is IMethodSymbol methodSymbol && methodSymbol.MethodKind == MethodKind.Conversion)
                    {
                        // For explicit/implicit conversion operators, we need to include the return type in the method Id,
                        // because there can be several conversion operators with same parameters and only differ by return type.
                        // For example,
                        //
                        //     public class Class1
                        //     {
                        //         public static explicit (explicit) operator int(Class1 c) { ... }
                        //         public static explicit (explicit) operator double(Class1 c) { ... }
                        //     }

                        var nodes = await GetPartialsForNamespaceAndTypeAsync(methodSymbol.ReturnType, true, solution, cancellationToken).ConfigureAwait(false);

                        List <GraphNodeId> returnTypePartial = nodes.ToList();
                        returnTypePartial.Add(GraphNodeId.GetPartial(CodeGraphNodeIdName.ParamKind, Microsoft.VisualStudio.GraphModel.CodeSchema.ParamKind.Return));

                        GraphNodeId returnCollection = GraphNodeId.GetNested(returnTypePartial.ToArray());
                        parameterTypeIds.Add(returnCollection);
                    }

                    memberPartials.Add(GraphNodeId.GetArray(
                                           CodeGraphNodeIdName.OverloadingParameters,
                                           parameterTypeIds.ToArray()));
                }

                partials.Add(GraphNodeId.GetPartial(
                                 CodeGraphNodeIdName.Member,
                                 MakeCollectionIfNecessary(false, memberPartials.ToArray())));
            }
            else
            {
                partials.Add(GraphNodeId.GetPartial(CodeGraphNodeIdName.Member, member.MetadataName));
            }

            return(GraphNodeId.GetNested(partials.ToArray()));
        }