示例#1
0
        //
        // A true result indicates that a type can never be a value type. This is important when testing variance-compatibility.
        //
        private static bool ProvablyAGcReferenceType(this Type t, CoreTypes coreTypes)
        {
            if (t.IsGenericParameter)
            {
                GenericParameterAttributes attributes = t.GenericParameterAttributes;
                if ((attributes & GenericParameterAttributes.ReferenceTypeConstraint) != 0)
                {
                    return(true);   // generic parameter with a "class" constraint.
                }
            }

            return(t.ProvablyAGcReferenceTypeHelper(coreTypes));
        }
        // Keep this separate from the other TypeClassification computations as it locks in the core assembly name.
        protected sealed override bool IsPrimitiveImpl()
        {
            CoreTypes coreTypes = Loader.GetAllFoundCoreTypes();

            foreach (CoreType primitiveType in s_primitiveTypes)
            {
                if (this == coreTypes[primitiveType])
                {
                    return(true);
                }
            }
            return(false);
        }
示例#3
0
        private CustomAttributeData ComputeDllImportCustomAttributeDataIfAny()
        {
            if ((Attributes & MethodAttributes.PinvokeImpl) == 0)
            {
                return(null);
            }

            // Make sure all the necessary framework types exist in this MetadataLoadContext's core assembly. If one doesn't, skip.
            CoreTypes ct = Loader.GetAllFoundCoreTypes();

            if (ct[CoreType.String] == null ||
                ct[CoreType.Boolean] == null ||
                ct[CoreType.DllImportAttribute] == null ||
                ct[CoreType.CharSet] == null ||
                ct[CoreType.CallingConvention] == null)
            {
                return(null);
            }
            ConstructorInfo ctor = Loader.TryGetDllImportCtor();

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

            Func <CustomAttributeArguments> argumentsPromise =
                () =>
            {
                // The expensive work goes in here.

                Type attributeType     = ctor.DeclaringType;
                DllImportAttribute dia = _decoder.ComputeDllImportAttribute();

                CustomAttributeTypedArgument[] cats = { new CustomAttributeTypedArgument(ct[CoreType.String], dia.Value) };
                CustomAttributeNamedArgument[] cans =
                {
                    attributeType.ToCustomAttributeNamedArgument(nameof(DllImportAttribute.EntryPoint),            ct[CoreType.String],            dia.EntryPoint),
                    attributeType.ToCustomAttributeNamedArgument(nameof(DllImportAttribute.CharSet),               ct[CoreType.CharSet],           (int)dia.CharSet),
                    attributeType.ToCustomAttributeNamedArgument(nameof(DllImportAttribute.CallingConvention),     ct[CoreType.CallingConvention], (int)dia.CallingConvention),
                    attributeType.ToCustomAttributeNamedArgument(nameof(DllImportAttribute.ExactSpelling),         ct[CoreType.Boolean],           dia.ExactSpelling),
                    attributeType.ToCustomAttributeNamedArgument(nameof(DllImportAttribute.PreserveSig),           ct[CoreType.Boolean],           dia.PreserveSig),
                    attributeType.ToCustomAttributeNamedArgument(nameof(DllImportAttribute.SetLastError),          ct[CoreType.Boolean],           dia.SetLastError),
                    attributeType.ToCustomAttributeNamedArgument(nameof(DllImportAttribute.BestFitMapping),        ct[CoreType.Boolean],           dia.BestFitMapping),
                    attributeType.ToCustomAttributeNamedArgument(nameof(DllImportAttribute.ThrowOnUnmappableChar), ct[CoreType.Boolean],           dia.ThrowOnUnmappableChar),
                };

                return(new CustomAttributeArguments(cats, cans));
            };

            return(new RoPseudoCustomAttributeData(ctor, argumentsPromise));
        }
示例#4
0
        private static bool CanCastTo(this Type fromTypeInfo, Type toTypeInfo, CoreTypes coreTypes)
        {
            if (fromTypeInfo.Equals(toTypeInfo))
            {
                return(true);
            }

            if (fromTypeInfo.IsArray)
            {
                if (toTypeInfo.IsInterface)
                {
                    return(fromTypeInfo.CanCastArrayToInterface(toTypeInfo, coreTypes));
                }

                if (fromTypeInfo.IsSubclassOf(toTypeInfo))
                {
                    return(true);  // T[] is castable to Array or Object.
                }
                if (!toTypeInfo.IsArray)
                {
                    return(false);
                }

                int rank = fromTypeInfo.GetArrayRank();
                if (rank != toTypeInfo.GetArrayRank())
                {
                    return(false);
                }

                bool fromTypeIsSzArray = fromTypeInfo.IsSZArray();
                bool toTypeIsSzArray   = toTypeInfo.IsSZArray();
                if (fromTypeIsSzArray != toTypeIsSzArray)
                {
                    // T[] is assignable to T[*] but not vice-versa.
                    if (!(rank == 1 && !toTypeIsSzArray))
                    {
                        return(false); // T[*] is not castable to T[]
                    }
                }

                Type toElementTypeInfo   = toTypeInfo.GetElementType();
                Type fromElementTypeInfo = fromTypeInfo.GetElementType();
                return(fromElementTypeInfo.IsElementTypeCompatibleWith(toElementTypeInfo, coreTypes));
            }

            if (fromTypeInfo.IsByRef)
            {
                if (!toTypeInfo.IsByRef)
                {
                    return(false);
                }

                Type toElementTypeInfo   = toTypeInfo.GetElementType();
                Type fromElementTypeInfo = fromTypeInfo.GetElementType();
                return(fromElementTypeInfo.IsElementTypeCompatibleWith(toElementTypeInfo, coreTypes));
            }

            if (fromTypeInfo.IsPointer)
            {
                if (toTypeInfo.Equals(coreTypes[CoreType.Object]))
                {
                    return(true);  // T* is castable to Object.
                }
                if (toTypeInfo.Equals(coreTypes[CoreType.UIntPtr]))
                {
                    return(true);  // T* is castable to UIntPtr (but not IntPtr)
                }
                if (!toTypeInfo.IsPointer)
                {
                    return(false);
                }

                Type toElementTypeInfo   = toTypeInfo.GetElementType();
                Type fromElementTypeInfo = fromTypeInfo.GetElementType();
                return(fromElementTypeInfo.IsElementTypeCompatibleWith(toElementTypeInfo, coreTypes));
            }

            if (fromTypeInfo.IsGenericParameter)
            {
                //
                // A generic parameter can be cast to any of its constraints, or object, if none are specified, or ValueType if the "struct" constraint is
                // specified.
                //
                // This has to be coded as its own case as TypeInfo.BaseType on a generic parameter doesn't always return what you'd expect.
                //
                if (toTypeInfo.Equals(coreTypes[CoreType.Object]))
                {
                    return(true);
                }

                if (toTypeInfo.Equals(coreTypes[CoreType.ValueType]))
                {
                    GenericParameterAttributes attributes = fromTypeInfo.GenericParameterAttributes;
                    if ((attributes & GenericParameterAttributes.NotNullableValueTypeConstraint) != 0)
                    {
                        return(true);
                    }
                }

                foreach (Type constraintType in fromTypeInfo.GetGenericParameterConstraints())
                {
                    if (constraintType.CanCastTo(toTypeInfo, coreTypes))
                    {
                        return(true);
                    }
                }

                return(false);
            }

            if (toTypeInfo.IsArray || toTypeInfo.IsByRef || toTypeInfo.IsPointer || toTypeInfo.IsGenericParameter)
            {
                return(false);
            }

            if (fromTypeInfo.MatchesWithVariance(toTypeInfo, coreTypes))
            {
                return(true);
            }

            if (toTypeInfo.IsInterface)
            {
                foreach (Type ifc in fromTypeInfo.GetInterfaces())
                {
                    if (ifc.MatchesWithVariance(toTypeInfo, coreTypes))
                    {
                        return(true);
                    }
                }
                return(false);
            }
            else
            {
                // Interfaces are always castable to System.Object. The code below will not catch this as interfaces report their BaseType as null.
                if (toTypeInfo.Equals(coreTypes[CoreType.Object]) && fromTypeInfo.IsInterface)
                {
                    return(true);
                }

                Type walk = fromTypeInfo;
                for (;;)
                {
                    Type baseType = walk.BaseType;
                    if (baseType == null)
                    {
                        return(false);
                    }
                    walk = baseType;
                    if (walk.MatchesWithVariance(toTypeInfo, coreTypes))
                    {
                        return(true);
                    }
                }
            }
        }
示例#5
0
        //
        // T[] casts to IList<T>. This could be handled by the normal ancestor-walking code
        // but for one complication: T[] also casts to IList<U> if T[] casts to U[].
        //
        private static bool CanCastArrayToInterface(this Type fromTypeInfo, Type toTypeInfo, CoreTypes coreTypes)
        {
            Debug.Assert(fromTypeInfo.IsArray);
            Debug.Assert(toTypeInfo.IsInterface);

            if (toTypeInfo.IsConstructedGenericType)
            {
                Type[] toTypeGenericTypeArguments = toTypeInfo.GenericTypeArguments;
                if (toTypeGenericTypeArguments.Length != 1)
                {
                    return(false);
                }
                Type toElementTypeInfo = toTypeGenericTypeArguments[0];

                Type toTypeGenericTypeDefinition = toTypeInfo.GetGenericTypeDefinition();
                Type fromElementTypeInfo         = fromTypeInfo.GetElementType();
                foreach (Type ifc in fromTypeInfo.GetInterfaces())
                {
                    if (ifc.IsConstructedGenericType)
                    {
                        Type ifcGenericTypeDefinition = ifc.GetGenericTypeDefinition();
                        if (ifcGenericTypeDefinition.Equals(toTypeGenericTypeDefinition))
                        {
                            if (fromElementTypeInfo.IsElementTypeCompatibleWith(toElementTypeInfo, coreTypes))
                            {
                                return(true);
                            }
                        }
                    }
                }
                return(false);
            }
            else
            {
                foreach (Type ifc in fromTypeInfo.GetInterfaces())
                {
                    if (ifc.Equals(toTypeInfo))
                    {
                        return(true);
                    }
                }
                return(false);
            }
        }
示例#6
0
        //
        // Contra/CoVariance.
        //
        // IEnumerable<D> can cast to IEnumerable<B> if D can cast to B and if there's no possibility that D is a value type.
        //
        private static bool IsGcReferenceTypeAndCastableTo(this Type fromTypeInfo, Type toTypeInfo, CoreTypes coreTypes)
        {
            if (fromTypeInfo.Equals(toTypeInfo))
            {
                return(true);
            }

            if (fromTypeInfo.ProvablyAGcReferenceType(coreTypes))
            {
                return(fromTypeInfo.CanCastTo(toTypeInfo, coreTypes));
            }

            return(false);
        }
示例#7
0
        //
        // A[] can cast to B[] if one of the following are true:
        //
        //    A can cast to B under variance rules.
        //
        //    A and B are both integers or enums and have the same reduced type (i.e. represent the same-sized integer, ignoring signed/unsigned differences.)
        //        "char" is not interchangable with short/ushort. "bool" is not interchangable with byte/sbyte.
        //
        // For desktop compat, A& and A* follow the same rules.
        //
        private static bool IsElementTypeCompatibleWith(this Type fromTypeInfo, Type toTypeInfo, CoreTypes coreTypes)
        {
            if (fromTypeInfo.IsGcReferenceTypeAndCastableTo(toTypeInfo, coreTypes))
            {
                return(true);
            }

            Type reducedFromType = fromTypeInfo.ReducedType(coreTypes);
            Type reducedToType   = toTypeInfo.ReducedType(coreTypes);

            if (reducedFromType.Equals(reducedToType))
            {
                return(true);
            }

            return(false);
        }
示例#8
0
        //
        // Check a base type or implemented interface type for equivalence (taking into account variance for generic instantiations.)
        // Does not check ancestors recursively.
        //
        private static bool MatchesWithVariance(this Type fromTypeInfo, Type toTypeInfo, CoreTypes coreTypes)
        {
            Debug.Assert(!(fromTypeInfo.IsArray || fromTypeInfo.IsByRef || fromTypeInfo.IsPointer || fromTypeInfo.IsGenericParameter));
            Debug.Assert(!(toTypeInfo.IsArray || toTypeInfo.IsByRef || toTypeInfo.IsPointer || toTypeInfo.IsGenericParameter));

            if (fromTypeInfo.Equals(toTypeInfo))
            {
                return(true);
            }

            if (!(fromTypeInfo.IsConstructedGenericType && toTypeInfo.IsConstructedGenericType))
            {
                return(false);
            }

            Type genericTypeDefinition = fromTypeInfo.GetGenericTypeDefinition();

            if (!genericTypeDefinition.Equals(toTypeInfo.GetGenericTypeDefinition()))
            {
                return(false);
            }

            Type[] fromTypeArguments     = fromTypeInfo.GenericTypeArguments;
            Type[] toTypeArguments       = toTypeInfo.GenericTypeArguments;
            Type[] genericTypeParameters = genericTypeDefinition.GetGenericTypeParameters();
            for (int i = 0; i < genericTypeParameters.Length; i++)
            {
                Type fromTypeArgumentInfo = fromTypeArguments[i];
                Type toTypeArgumentInfo   = toTypeArguments[i];

                GenericParameterAttributes attributes = genericTypeParameters[i].GenericParameterAttributes;
                switch (attributes & GenericParameterAttributes.VarianceMask)
                {
                case GenericParameterAttributes.Covariant:
                    if (!(fromTypeArgumentInfo.IsGcReferenceTypeAndCastableTo(toTypeArgumentInfo, coreTypes)))
                    {
                        return(false);
                    }
                    break;

                case GenericParameterAttributes.Contravariant:
                    if (!(toTypeArgumentInfo.IsGcReferenceTypeAndCastableTo(fromTypeArgumentInfo, coreTypes)))
                    {
                        return(false);
                    }
                    break;

                case GenericParameterAttributes.None:
                    if (!(fromTypeArgumentInfo.Equals(toTypeArgumentInfo)))
                    {
                        return(false);
                    }
                    break;

                default:
                    throw new BadImageFormatException();      // Unexpected variance value in metadata.
                }
            }
            return(true);
        }
        /// <summary>
        /// Convert MarshalAsAttribute data into CustomAttributeData form. Returns null if the core assembly cannot be loaded or if the necessary
        /// types aren't in the core assembly.
        /// </summary>
        public static CustomAttributeData TryComputeMarshalAsCustomAttributeData(Func <MarshalAsAttribute> marshalAsAttributeComputer, TypeLoader loader)
        {
            // Make sure all the necessary framework types exist in this TypeLoader's core assembly. If one doesn't, skip.
            CoreTypes ct = loader.GetAllFoundCoreTypes();

            if (ct[CoreType.String] == null ||
                ct[CoreType.Boolean] == null ||
                ct[CoreType.UnmanagedType] == null ||
                ct[CoreType.VarEnum] == null ||
                ct[CoreType.Type] == null ||
                ct[CoreType.Int16] == null ||
                ct[CoreType.Int32] == null)
            {
                return(null);
            }
            ConstructorInfo ci = loader.TryGetMarshalAsCtor();

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

            Func <CustomAttributeArguments> argumentsPromise =
                () =>
            {
                // The expensive work goes in here. It will not execute unless someone invokes the Constructor/NamedArguments properties on
                // the CustomAttributeData.

                MarshalAsAttribute ma = marshalAsAttributeComputer();

                Type attributeType = ci.DeclaringType;

                CustomAttributeTypedArgument[]      cats = { new CustomAttributeTypedArgument(ct[CoreType.UnmanagedType], (int)(ma.Value)) };
                List <CustomAttributeNamedArgument> cans = new List <CustomAttributeNamedArgument>();
                cans.AddRange(new CustomAttributeNamedArgument[]
                {
                    attributeType.ToCustomAttributeNamedArgument(nameof(MarshalAsAttribute.ArraySubType), ct[CoreType.UnmanagedType], (int)ma.ArraySubType),
                    attributeType.ToCustomAttributeNamedArgument(nameof(MarshalAsAttribute.IidParameterIndex), ct[CoreType.Int32], ma.IidParameterIndex),
                    attributeType.ToCustomAttributeNamedArgument(nameof(MarshalAsAttribute.SafeArraySubType), ct[CoreType.VarEnum], (int)ma.SafeArraySubType),
                    attributeType.ToCustomAttributeNamedArgument(nameof(MarshalAsAttribute.SizeConst), ct[CoreType.Int32], ma.SizeConst),
                    attributeType.ToCustomAttributeNamedArgument(nameof(MarshalAsAttribute.SizeParamIndex), ct[CoreType.Int16], ma.SizeParamIndex),
                });

                if (ma.SafeArrayUserDefinedSubType != null)
                {
                    cans.Add(attributeType.ToCustomAttributeNamedArgument(nameof(MarshalAsAttribute.SafeArrayUserDefinedSubType), ct[CoreType.Type], ma.SafeArrayUserDefinedSubType));
                }

                if (ma.MarshalType != null)
                {
                    cans.Add(attributeType.ToCustomAttributeNamedArgument(nameof(MarshalAsAttribute.MarshalType), ct[CoreType.String], ma.MarshalType));
                }

                if (ma.MarshalTypeRef != null)
                {
                    cans.Add(attributeType.ToCustomAttributeNamedArgument(nameof(MarshalAsAttribute.MarshalTypeRef), ct[CoreType.Type], ma.MarshalTypeRef));
                }

                if (ma.MarshalCookie != null)
                {
                    cans.Add(attributeType.ToCustomAttributeNamedArgument(nameof(MarshalAsAttribute.MarshalCookie), ct[CoreType.String], ma.MarshalCookie));
                }

                return(new CustomAttributeArguments(cats, cans));
            };

            return(new RoPseudoCustomAttributeData(ci, argumentsPromise));
        }