/// <summary>
        /// Resolves a symbol.
        /// </summary>
        /// <remarks>
        /// * Types are resolved to their definition, as IType does not implement ISymbol.
        ///    * types without definition will resolve to <c>null</c>
        ///    * use ResolveType() to properly resolve types
        /// * When resolving methods, varargs signatures are not expanded.
        ///    * use ResolveMethod() instead to get an IMethod instance suitable for call-sites
        /// * May return specialized members, where generics are involved.
        /// * Other types of handles that don't correspond to TS entities, will return <c>null</c>.
        /// </remarks>
        public IEntity ResolveEntity(EntityHandle entityHandle, GenericContext context = default)
        {
            switch (entityHandle.Kind)
            {
            case HandleKind.TypeReference:
            case HandleKind.TypeDefinition:
            case HandleKind.TypeSpecification:
            case HandleKind.ExportedType:
                return(ResolveType(entityHandle, context).GetDefinition());

            case HandleKind.MemberReference:
                var memberReferenceHandle = (MemberReferenceHandle)entityHandle;
                switch (metadata.GetMemberReference(memberReferenceHandle).GetKind())
                {
                case MemberReferenceKind.Method:
                    // for consistency with the MethodDefinition case, never expand varargs
                    return(ResolveMethodReference(memberReferenceHandle, context, expandVarArgs: false));

                case MemberReferenceKind.Field:
                    return(ResolveFieldReference(memberReferenceHandle, context));

                default:
                    throw new BadImageFormatException("Unknown MemberReferenceKind");
                }

            case HandleKind.MethodDefinition:
                return(GetDefinition((MethodDefinitionHandle)entityHandle));

            case HandleKind.MethodSpecification:
                return(ResolveMethodSpecification((MethodSpecificationHandle)entityHandle, context, expandVarArgs: false));

            case HandleKind.FieldDefinition:
                return(GetDefinition((FieldDefinitionHandle)entityHandle));

            case HandleKind.EventDefinition:
                return(GetDefinition((EventDefinitionHandle)entityHandle));

            case HandleKind.PropertyDefinition:
                return(GetDefinition((PropertyDefinitionHandle)entityHandle));

            default:
                return(null);
            }
        }
        public IMethod ResolveMethod(EntityHandle methodReference, GenericContext context)
        {
            if (methodReference.IsNil)
            {
                throw new ArgumentNullException(nameof(methodReference));
            }
            switch (methodReference.Kind)
            {
            case HandleKind.MethodDefinition:
                return(ResolveMethodDefinition((MethodDefinitionHandle)methodReference, expandVarArgs: true));

            case HandleKind.MemberReference:
                return(ResolveMethodReference((MemberReferenceHandle)methodReference, context, expandVarArgs: true));

            case HandleKind.MethodSpecification:
                return(ResolveMethodSpecification((MethodSpecificationHandle)methodReference, context, expandVarArgs: true));

            default:
                throw new BadImageFormatException("Metadata token must be either a methoddef, memberref or methodspec");
            }
        }
        IField ResolveFieldReference(MemberReferenceHandle memberReferenceHandle, GenericContext context)
        {
            var    memberRef               = metadata.GetMemberReference(memberReferenceHandle);
            var    declaringType           = ResolveDeclaringType(memberRef.Parent, context);
            var    declaringTypeDefinition = declaringType.GetDefinition();
            string name = metadata.GetString(memberRef.Name);
            // field signature is for the definition, not the generic instance
            var signature = memberRef.DecodeFieldSignature(TypeProvider,
                                                           new GenericContext(declaringTypeDefinition?.TypeParameters));
            // 'f' in the predicate is also the definition, even if declaringType is a ParameterizedType
            var field = declaringType.GetFields(f => f.Name == name && CompareTypes(f.ReturnType, signature),
                                                GetMemberOptions.IgnoreInheritedMembers).FirstOrDefault();

            if (field == null)
            {
                field = new FakeField(Compilation)
                {
                    ReturnType    = signature,
                    Name          = name,
                    DeclaringType = declaringType,
                };
            }
            return(field);
        }
        public ImmutableArray <IType> DecodeLocalSignature(StandaloneSignatureHandle handle, GenericContext genericContext)
        {
            var standaloneSignature = metadata.GetStandaloneSignature(handle);

            if (standaloneSignature.GetKind() != StandaloneSignatureKind.LocalVariables)
            {
                throw new BadImageFormatException("Expected LocalVariables signature");
            }
            var types = standaloneSignature.DecodeLocalSignature(TypeProvider, genericContext);

            return(ImmutableArray.CreateRange(types, IntroduceTupleTypes));
        }
        public MethodSignature <IType> DecodeMethodSignature(StandaloneSignatureHandle handle, GenericContext genericContext)
        {
            var standaloneSignature = metadata.GetStandaloneSignature(handle);

            if (standaloneSignature.GetKind() != StandaloneSignatureKind.Method)
            {
                throw new BadImageFormatException("Expected Method signature");
            }
            var sig = standaloneSignature.DecodeMethodSignature(TypeProvider, genericContext);

            return(new MethodSignature <IType>(
                       sig.Header,
                       IntroduceTupleTypes(sig.ReturnType),
                       sig.RequiredParameterCount,
                       sig.GenericParameterCount,
                       ImmutableArray.CreateRange(
                           sig.ParameterTypes, IntroduceTupleTypes
                           )
                       ));
        }
        /// <summary>
        /// Resolves a method reference.
        /// </summary>
        /// <remarks>
        /// Class type arguments are provided by the declaring type stored in the memberRef.
        /// Method type arguments are provided by the caller.
        /// </remarks>
        IMethod ResolveMethodReference(MemberReferenceHandle memberRefHandle, GenericContext context, IReadOnlyList <IType> methodTypeArguments = null, bool expandVarArgs = true)
        {
            var memberRef = metadata.GetMemberReference(memberRefHandle);

            Debug.Assert(memberRef.GetKind() == MemberReferenceKind.Method);
            MethodSignature <IType> signature;
            IReadOnlyList <IType>   classTypeArguments = null;
            IMethod method;

            if (memberRef.Parent.Kind == HandleKind.MethodDefinition)
            {
                method    = ResolveMethodDefinition((MethodDefinitionHandle)memberRef.Parent, expandVarArgs: false);
                signature = memberRef.DecodeMethodSignature(TypeProvider, context);
            }
            else
            {
                var declaringType           = ResolveDeclaringType(memberRef.Parent, context);
                var declaringTypeDefinition = declaringType.GetDefinition();
                if (declaringType.TypeArguments.Count > 0)
                {
                    classTypeArguments = declaringType.TypeArguments;
                }
                // Note: declaringType might be parameterized, but the signature is for the original method definition.
                // We'll have to search the member directly on declaringTypeDefinition.
                string name = metadata.GetString(memberRef.Name);
                signature = memberRef.DecodeMethodSignature(TypeProvider,
                                                            new GenericContext(declaringTypeDefinition?.TypeParameters));
                if (declaringTypeDefinition != null)
                {
                    // Find the set of overloads to search:
                    IEnumerable <IMethod> methods;
                    if (name == ".ctor")
                    {
                        methods = declaringTypeDefinition.GetConstructors();
                    }
                    else if (name == ".cctor")
                    {
                        methods = declaringTypeDefinition.Methods.Where(m => m.IsConstructor && m.IsStatic);
                    }
                    else
                    {
                        methods = declaringTypeDefinition.GetMethods(m => m.Name == name, GetMemberOptions.IgnoreInheritedMembers)
                                  .Concat(declaringTypeDefinition.GetAccessors(m => m.Name == name, GetMemberOptions.IgnoreInheritedMembers));
                    }
                    // Determine the expected parameters from the signature:
                    ImmutableArray <IType> parameterTypes;
                    if (signature.Header.CallingConvention == SignatureCallingConvention.VarArgs)
                    {
                        parameterTypes = signature.ParameterTypes
                                         .Take(signature.RequiredParameterCount)
                                         .Concat(new[] { SpecialType.ArgList })
                                         .ToImmutableArray();
                    }
                    else
                    {
                        parameterTypes = signature.ParameterTypes;
                    }
                    // Search for the matching method:
                    method = null;
                    foreach (var m in methods)
                    {
                        if (m.TypeParameters.Count != signature.GenericParameterCount)
                        {
                            continue;
                        }
                        if (CompareSignatures(m.Parameters, parameterTypes) && CompareTypes(m.ReturnType, signature.ReturnType))
                        {
                            method = m;
                            break;
                        }
                    }
                }
                else
                {
                    method = null;
                }
                if (method == null)
                {
                    method = CreateFakeMethod(declaringType, name, signature);
                }
            }
            if (classTypeArguments != null || methodTypeArguments != null)
            {
                method = method.Specialize(new TypeParameterSubstitution(classTypeArguments, methodTypeArguments));
            }
            if (expandVarArgs && signature.Header.CallingConvention == SignatureCallingConvention.VarArgs)
            {
                method = new VarArgInstanceMethod(method, signature.ParameterTypes.Skip(signature.RequiredParameterCount));
            }
            return(method);
        }
        IMethod ResolveMethodSpecification(MethodSpecificationHandle methodSpecHandle, GenericContext context, bool expandVarArgs)
        {
            var methodSpec     = metadata.GetMethodSpecification(methodSpecHandle);
            var methodTypeArgs = methodSpec.DecodeSignature(TypeProvider, context)
                                 .SelectReadOnlyArray(IntroduceTupleTypes);
            IMethod method;

            if (methodSpec.Method.Kind == HandleKind.MethodDefinition)
            {
                // generic instance of a methoddef (=generic method in non-generic class in current assembly)
                method = ResolveMethodDefinition((MethodDefinitionHandle)methodSpec.Method, expandVarArgs);
                method = method.Specialize(new TypeParameterSubstitution(null, methodTypeArgs));
            }
            else
            {
                method = ResolveMethodReference((MemberReferenceHandle)methodSpec.Method, context, methodTypeArgs, expandVarArgs);
            }
            return(method);
        }
 public IType ResolveType(EntityHandle typeRefDefSpec, GenericContext context, CustomAttributeHandleCollection?typeAttributes = null)
 {
     return(ResolveType(typeRefDefSpec, context, options, typeAttributes));
 }