private static void HandleCall(ref DependencyList list, NodeFactory factory, MethodIL methodIL, MethodDesc methodCalled, ref Tracker tracker) { switch (methodCalled.Name) { // Enum.GetValues(Type) needs array of that type case "GetValues" when methodCalled.OwningType == factory.TypeSystemContext.GetWellKnownType(WellKnownType.Enum): { TypeDesc type = tracker.GetLastType(); if (type != null && type.IsEnum && !type.IsGenericDefinition /* generic enums! */) { // Type could be something weird like MyEnum<object, __Canon> - normalize it type = type.NormalizeInstantiation(); list = list ?? new DependencyList(); list.Add(factory.ConstructedTypeSymbol(type.MakeArrayType()), "Enum.GetValues"); } } break; // Type.GetType(string...) needs the type with the given name case "GetType" when methodCalled.OwningType.IsSystemType() && methodCalled.Signature.Length > 0: { string name = tracker.GetLastString(); if (name != null && methodIL.OwningMethod.OwningType is MetadataType mdType && ResolveType(name, mdType.Module, out TypeDesc type, out ModuleDesc referenceModule) && !factory.MetadataManager.IsReflectionBlocked(type)) { const string reason = "Type.GetType"; list = list ?? new DependencyList(); list.Add(factory.MaximallyConstructableType(type), reason); // Also add module metadata in case this reference was through a type forward if (factory.MetadataManager.CanGenerateMetadata(referenceModule.GetGlobalModuleType())) { list.Add(factory.ModuleMetadata(referenceModule), reason); } // Opportunistically remember the type so that it flows to Type.GetMethod if needed. tracker.TrackType(type); } } break; // Type.GetMethod(string...) case "GetMethod" when methodCalled.OwningType.IsSystemType(): { string name = tracker.GetLastString(); TypeDesc type = tracker.GetLastType(); if (name != null && type != null && !factory.MetadataManager.IsReflectionBlocked(type)) { if (type.IsGenericDefinition) { Instantiation inst = TypeExtensions.GetInstantiationThatMeetsConstraints(type.Instantiation, allowCanon: false); if (inst.IsNull) { break; } type = ((MetadataType)type).MakeInstantiatedType(inst); list = list ?? new DependencyList(); list.Add(factory.MaximallyConstructableType(type), "Type.GetMethod"); } else { // Type could be something weird like SomeType<object, __Canon> - normalize it type = type.NormalizeInstantiation(); } MethodDesc reflectedMethod = type.GetMethod(name, null); if (reflectedMethod != null && !factory.MetadataManager.IsReflectionBlocked(reflectedMethod)) { if (reflectedMethod.HasInstantiation) { // Don't want to accidentally get Foo<__Canon>.Bar<object>() if (reflectedMethod.OwningType.IsCanonicalSubtype(CanonicalFormKind.Any)) { break; } Instantiation inst = TypeExtensions.GetInstantiationThatMeetsConstraints(reflectedMethod.Instantiation, allowCanon: false); if (inst.IsNull) { break; } reflectedMethod = reflectedMethod.MakeInstantiatedMethod(inst); } const string reason = "Type.GetMethod"; list = list ?? new DependencyList(); if (reflectedMethod.IsVirtual) { RootVirtualMethodForReflection(ref list, factory, reflectedMethod, reason); } if (!reflectedMethod.IsAbstract) { list.Add(factory.CanonicalEntrypoint(reflectedMethod), reason); if (reflectedMethod.HasInstantiation && reflectedMethod != reflectedMethod.GetCanonMethodTarget(CanonicalFormKind.Specific)) { list.Add(factory.MethodGenericDictionary(reflectedMethod), reason); } } } } } break; case "SizeOf" when IsMarshalSizeOf(methodCalled): { TypeDesc type = tracker.GetLastType(); if (IsTypeEligibleForMarshalSizeOfTracking(type)) { list = list ?? new DependencyList(); list.Add(factory.StructMarshallingData((DefType)type), "Marshal.SizeOf"); } } break; } }
private static void HandleCall(ref DependencyList list, NodeFactory factory, MethodIL methodIL, MethodDesc methodCalled, ref Tracker tracker) { switch (methodCalled.Name) { // Enum.GetValues(Type) needs array of that type case "GetValues" when methodCalled.OwningType == factory.TypeSystemContext.GetWellKnownType(WellKnownType.Enum): { TypeDesc type = tracker.GetLastType(); if (type != null && type.IsEnum && !type.IsGenericDefinition /* generic enums! */) { list = list ?? new DependencyList(); list.Add(factory.ConstructedTypeSymbol(type.MakeArrayType()), "Enum.GetValues"); } } break; // Type.GetType(string...) needs the type with the given name case "GetType" when methodCalled.OwningType.IsSystemType() && methodCalled.Signature.Length > 0: { string name = tracker.GetLastString(); if (name != null && methodIL.OwningMethod.OwningType is MetadataType mdType && ResolveType(name, mdType.Module, out TypeDesc type, out ModuleDesc referenceModule) && !factory.MetadataManager.IsReflectionBlocked(type)) { const string reason = "Type.GetType"; list = list ?? new DependencyList(); list.Add(factory.MaximallyConstructableType(type), reason); // Also add module metadata in case this reference was through a type forward if (factory.MetadataManager.CanGenerateMetadata(referenceModule.GetGlobalModuleType())) { list.Add(factory.ModuleMetadata(referenceModule), reason); } // Opportunistically remember the type so that it flows to Type.GetMethod if needed. tracker.TrackType(type); } } break; // Type.GetMethod(string...) case "GetMethod" when methodCalled.OwningType.IsSystemType(): { string name = tracker.GetLastString(); TypeDesc type = tracker.GetLastType(); if (name != null && type != null && !factory.MetadataManager.IsReflectionBlocked(type)) { if (type.IsGenericDefinition) { Instantiation inst = TypeExtensions.GetInstantiationThatMeetsConstraints(type.Instantiation, allowCanon: false); if (inst.IsNull) { break; } type = ((MetadataType)type).MakeInstantiatedType(inst); list = list ?? new DependencyList(); list.Add(factory.MaximallyConstructableType(type), "Type.GetMethod"); } MethodDesc reflectedMethod = type.GetMethod(name, null); if (reflectedMethod != null && !factory.MetadataManager.IsReflectionBlocked(reflectedMethod)) { if (reflectedMethod.HasInstantiation) { // Don't want to accidentally get Foo<__Canon>.Bar<object>() if (reflectedMethod.OwningType.IsCanonicalSubtype(CanonicalFormKind.Any)) { break; } Instantiation inst = TypeExtensions.GetInstantiationThatMeetsConstraints(reflectedMethod.Instantiation, allowCanon: false); if (inst.IsNull) { break; } reflectedMethod = reflectedMethod.MakeInstantiatedMethod(inst); } const string reason = "Type.GetMethod"; list = list ?? new DependencyList(); if (reflectedMethod.IsVirtual) { RootVirtualMethodForReflection(ref list, factory, reflectedMethod, reason); } if (!reflectedMethod.IsAbstract) { list.Add(factory.CanonicalEntrypoint(reflectedMethod), reason); if (reflectedMethod.HasInstantiation && reflectedMethod != reflectedMethod.GetCanonMethodTarget(CanonicalFormKind.Specific)) { list.Add(factory.MethodGenericDictionary(reflectedMethod), reason); } } } } } break; case "SizeOf" when methodCalled.OwningType.IsSystemRuntimeInteropServicesMarshal() && !methodCalled.HasInstantiation && methodCalled.Signature.Length == 1 && methodCalled.Signature[0].IsSystemType(): { TypeDesc type = tracker.GetLastType(); if (type != null && !type.IsGenericDefinition && !type.IsCanonicalSubtype(CanonicalFormKind.Any)) { list = list ?? new DependencyList(); MethodDesc marshalSizeOfGeneric = methodCalled.OwningType.GetKnownMethod( "SizeOf", new MethodSignature(MethodSignatureFlags.Static, 1, methodCalled.Context.GetWellKnownType(WellKnownType.Int32), TypeDesc.EmptyTypes)); marshalSizeOfGeneric = marshalSizeOfGeneric.MakeInstantiatedMethod(type); // InteropManager is looking for the following method bodies or dictionaries to decide marshalling info need. // We should ideally model these as separate entities in the dependency graph and add those entities instead. // Fixable after https://github.com/dotnet/corert/issues/6063 is fixed. if (marshalSizeOfGeneric.GetCanonMethodTarget(CanonicalFormKind.Specific) != marshalSizeOfGeneric) { list.Add(factory.MethodGenericDictionary(marshalSizeOfGeneric), "Marshal.SizeOf"); } else { list.Add(factory.MethodEntrypoint(marshalSizeOfGeneric), "Marshal.SizeOf"); } } } break; } }