/// <summary> /// Mark all base types and externally visible members reachable /// </summary> private static void Walk(ReachableContext context, TypeReference type) { if (type == null) return; if (type.IsArray) { var aType = (ArrayTypeReference)type; Walk(context, aType.ElementType); } else if (type.IsObjectType) { var oType = (ObjectTypeReference)type; foreach (var typeArg in oType.Arguments) { Walk(context, typeArg.Signature); } ClassFile classFile; if (context.TryLoadClass(oType.ClassName, out classFile)) { classFile.MarkReachable(context); } } else if (type.IsBaseType || type.IsVoid || type.IsTypeVariable) { // Not need to mark anything } else { throw new ArgumentException("Unknown type: " + type); } }
/// <summary> /// Mark all base types and externally visible members reachable /// </summary> private static void Walk(ReachableContext context, TypeReference type) { if (type == null) { return; } if (type.IsArray) { var aType = (ArrayTypeReference)type; Walk(context, aType.ElementType); } else if (type.IsObjectType) { var oType = (ObjectTypeReference)type; foreach (var typeArg in oType.Arguments) { Walk(context, typeArg.Signature); } ClassFile classFile; if (context.TryLoadClass(oType.ClassName, out classFile)) { classFile.MarkReachable(context); } } else if (type.IsBaseType || type.IsVoid || type.IsTypeVariable) { // Not need to mark anything } else { throw new ArgumentException("Unknown type: " + type); } }
/// <summary> /// Mark all eachable items in argument as such. /// </summary> private static void Walk(ReachableContext context, FieldReference field) { // Field type field.FieldType.MarkReachable(context); var fieldDef = field as FieldDefinition; if (fieldDef != null) { // Custom attributes Walk(context, (ICustomAttributeProvider)fieldDef); // Walk imported java classes CustomAttribute javaImportAttr; if ((javaImportAttr = fieldDef.GetJavaImportAttribute()) != null) { string className; string memberName; string descriptor; javaImportAttr.GetDexOrJavaImportNames(fieldDef, out memberName, out descriptor, out className); ClassFile javaClass; if (context.TryLoadClass(className, out javaClass)) { var javaField = javaClass.Fields.FirstOrDefault(x => (x.Name == memberName) && (x.Descriptor == descriptor)); javaClass.MarkReachable(context); javaField.MarkReachable(context); } } } else { // Try to resolve field.Resolve(context).MarkReachable(context); } }
/// <summary> /// Mark all base types and externally visible members reachable /// </summary> private static void Walk(ReachableContext context, TypeReference type) { // Generic parameters Walk(context, (IGenericParameterProvider)type); TypeDefinition typeDef; TypeSpecification typeSpec; GenericParameter genericParam; if ((typeDef = type as TypeDefinition) != null) { var isUsedInSerialization = typeDef.IsUsedInSerialization && !type.IsPrimitive && !typeDef.IsEnum && !type.Namespace.StartsWith("System"); // Mark base type reachable typeDef.BaseType.MarkReachable(context, isUsedInSerialization); // Mark declaring type reachable typeDef.DeclaringType.MarkReachable(context); // Mark implemented interfaces reachable if (typeDef.HasInterfaces) { foreach (var intf in typeDef.Interfaces.Select(x => x.Interface)) { intf.MarkReachable(context); } } // If this is an attribute, include related types if (typeDef.IsAttribute()) { GetDot42InternalType(context, "IAttribute").MarkReachable(context); GetDot42InternalType(context, "IAttributes").MarkReachable(context); } else if (typeDef.IsEnum) { var boxingType = GetDot42InternalType(context, "Boxing"); boxingType.Methods.Where(x => (x.Name == "UnboxInteger" || x.Name == "UnboxLong")).ForEach(x => x.MarkReachable(context)); } // Default & class ctor typeDef.FindDefaultCtor().MarkReachable(context); typeDef.GetClassCtor().MarkReachable(context); // Visit externally visible members if (typeDef.HasEvents) { foreach (var evt in typeDef.Events) { if ((!evt.IsReachable) && context.Include(evt)) { evt.MarkReachable(context); } } } if (typeDef.HasFields) { foreach (var field in typeDef.Fields) { // only public fields, so we don't pull any compiler generated stuff. var isSerializable = isUsedInSerialization && !field.IsStatic && field.IsPublic; if ((!field.IsReachable && context.Include(field)) || (!field.IsUsedInSerialization && isSerializable)) { field.MarkReachable(context, isUsedInSerialization); } } } if (typeDef.HasMethods) { foreach (var method in typeDef.Methods) { if ((!method.IsReachable) && context.Include(method)) { method.MarkReachable(context); } } } if (typeDef.HasProperties) { foreach (var prop in typeDef.Properties) { var isSerializable = isUsedInSerialization && prop.HasThis; if ((!prop.IsReachable && context.Include(prop) || (!prop.IsUsedInSerialization && isSerializable))) { prop.MarkReachable(context, isUsedInSerialization); } } } // Custom attributes Walk(context, (ICustomAttributeProvider)typeDef); // Walk imported java classes CustomAttribute javaImportAttr; if ((javaImportAttr = typeDef.GetJavaImportAttribute()) != null) { var javaClassName = (string)javaImportAttr.ConstructorArguments[0].Value; ClassFile javaClass; if (context.TryLoadClass(javaClassName, out javaClass)) { javaClass.MarkReachable(context); } } // Dex imported interfaces should have all their methods marked reachable. if (typeDef.IsInterface && typeDef.HasDexImportAttribute()) { typeDef.Methods.ForEach(x => x.MarkReachable(context)); } // Record in context context.RecordReachableType(typeDef); } else if ((typeSpec = type as TypeSpecification) != null) { // Element typeSpec.ElementType.MarkReachable(context, typeSpec.IsUsedInSerialization); // Generic instance GenericInstanceType git; FunctionPointerType fpt; RequiredModifierType reqModType; OptionalModifierType optModType; if ((git = typeSpec as GenericInstanceType) != null) { if (git.ElementType.IsNullableT()) { var typeofT = git.GenericArguments[0].Resolve(context); if (typeofT != null && !typeofT.UsedInNullableT) { typeofT.UsedInNullableT = true; DLog.Debug(DContext.CompilerAssemblyResolver, "found System.Nullable<{0}>", typeofT.FullName); } } Walk(context, (IGenericInstance)git); } else if ((fpt = typeSpec as FunctionPointerType) != null) { Walk(context, fpt.ReturnType); } else if ((reqModType = typeSpec as RequiredModifierType) != null) { reqModType.ModifierType.MarkReachable(context); } else if ((optModType = typeSpec as OptionalModifierType) != null) { optModType.ModifierType.MarkReachable(context); } } else if ((genericParam = type as GenericParameter) != null) { genericParam.IsSerializedParameter = genericParam.HasSerializedParameterAttribute(); // Owner var owner = (MemberReference)genericParam.Owner; owner.MarkReachable(context); // Constraints if (genericParam.HasConstraints) { foreach (TypeReference constraint in genericParam.Constraints) { constraint.MarkReachable(context); } } } else { // Try to resolve type.Resolve(context).MarkReachable(context, type.IsUsedInSerialization); } }
/// <summary> /// Mark all reachable items in argument as such. /// </summary> private static void Walk(ReachableContext context, MethodReference method) { method.ReturnType.MarkReachable(context); // All parameters if (method.HasParameters) { foreach (ParameterDefinition param in method.Parameters) { Walk(context, (ParameterReference)param); } } // Generic parameters Walk(context, (IGenericParameterProvider)method); // Method definition? MethodDefinition methodDef; MethodSpecification methodSpec; if ((methodDef = method as MethodDefinition) != null) { // Code Walk(context, methodDef.Body); // Overrides foreach (MethodReference methodRef in methodDef.Overrides) { methodRef.MarkReachable(context); } // Base methods if (methodDef.IsVirtual) { MethodDefinition baseMethod; if ((baseMethod = methodDef.GetBaseMethod()) != null) { if (context.Contains(baseMethod.DeclaringType)) { baseMethod.MarkReachable(context); } } } // Custom attributes Walk(context, (ICustomAttributeProvider)methodDef); // Walk imported java classes CustomAttribute javaImportAttr; if ((javaImportAttr = methodDef.GetJavaImportAttribute()) != null) { string className; string memberName; string descriptor; javaImportAttr.GetDexOrJavaImportNames(methodDef, out memberName, out descriptor, out className); ClassFile javaClass; if (context.TryLoadClass(className, out javaClass)) { var javaMethod = javaClass.Methods.FirstOrDefault(x => (x.Name == memberName) && (x.Descriptor == descriptor)); javaClass.MarkReachable(context); javaMethod.MarkReachable(context); } } // If this method is a property accessor, include the property also if (methodDef.SemanticsAttributes.HasFlag(MethodSemanticsAttributes.Getter)) { var prop = methodDef.DeclaringType.Properties.FirstOrDefault(x => x.GetMethod == methodDef); prop.MarkReachable(context); } if (methodDef.SemanticsAttributes.HasFlag(MethodSemanticsAttributes.Setter)) { var prop = methodDef.DeclaringType.Properties.FirstOrDefault(x => x.SetMethod == methodDef); prop.MarkReachable(context); } } else if ((methodSpec = method as MethodSpecification) != null) { // Method var elementRef = methodSpec.ElementMethod; elementRef.MarkReachable(context); // Generic arguments var gim = methodSpec as GenericInstanceMethod; if (gim != null) { var elementDef = elementRef.Resolve(); for (int i = 0; i < gim.GenericArguments.Count; ++i) { bool isSerialized = elementDef.GenericParameters[i].IsSerializedParameter; gim.GenericArguments[i].MarkReachable(context, isSerialized); } } } else { // Try to resolve method.Resolve(context).MarkReachable(context); } }
/// <summary> /// Mark all reachable items in argument as such. /// </summary> private static void Walk(ReachableContext context, FieldReference field) { // Field type field.FieldType.MarkReachable(context, field.IsUsedInSerialization); var fieldDef = field as FieldDefinition; if (fieldDef != null) { // Custom attributes Walk(context, (ICustomAttributeProvider)fieldDef); // Walk imported java classes CustomAttribute javaImportAttr; if ((javaImportAttr = fieldDef.GetJavaImportAttribute()) != null) { string className; string memberName; string descriptor; javaImportAttr.GetDexOrJavaImportNames(fieldDef, out memberName, out descriptor, out className); ClassFile javaClass; if (context.TryLoadClass(className, out javaClass)) { var javaField = javaClass.Fields.FirstOrDefault(x => (x.Name == memberName) && (x.Descriptor == descriptor)); javaClass.MarkReachable(context); javaField.MarkReachable(context); } } } else { // Try to resolve field.Resolve(context).MarkReachable(context, field.IsUsedInSerialization); } }
/// <summary> /// Is our <see cref="instanceOfCondition"/> an interface implemented by the given type (or one of it's base types)? /// </summary> private bool Implements(ReachableContext context, ClassFile javaClass) { while (javaClass != null) { if (javaClass.ClassName == className) return true; if (javaClass.Interfaces != null) { foreach (var intfRef in javaClass.Interfaces) { ClassFile intf; if (context.TryLoadClass(intfRef.ClassName, out intf)) { if (Implements(context, intf)) return true; } } } ClassFile superClass; if (!javaClass.TryGetSuperClass(out superClass)) return false; javaClass = superClass; } return false; }
/// <summary> /// Mark all base types and externally visible members reachable /// </summary> private static void Walk(ReachableContext context, TypeReference type) { // Generic parameters Walk(context, (IGenericParameterProvider)type); TypeDefinition typeDef; TypeSpecification typeSpec; GenericParameter genericParam; if ((typeDef = type as TypeDefinition) != null) { // Mark base type reachable typeDef.BaseType.MarkReachable(context); // Mark declaring type reachable typeDef.DeclaringType.MarkReachable(context); // Mark implemented interfaces reachable if (typeDef.HasInterfaces) { foreach (var intf in typeDef.Interfaces.Select(x => x.Interface)) { intf.MarkReachable(context); } } // If is an an attribute include related types if (typeDef.IsAttribute()) { GetDot42InternalType(context, "IAttribute").MarkReachable(context); GetDot42InternalType(context, "IAttributes").MarkReachable(context); GetDot42InternalType(context, "IAnnotationType").MarkReachable(context); } else if (typeDef.IsEnum) { var boxingType = GetDot42InternalType(context, "Boxing"); boxingType.Methods.Where(x => (x.Name == "UnboxInteger" || x.Name == "UnboxLong")).ForEach(x => x.MarkReachable(context)); } // Default & class ctor typeDef.FindDefaultCtor().MarkReachable(context); typeDef.GetClassCtor().MarkReachable(context); // Visit externally visible members if (typeDef.HasEvents) { foreach (var evt in typeDef.Events) { if ((!evt.IsReachable) && context.Include(evt)) { evt.MarkReachable(context); } } } if (typeDef.HasFields) { foreach (var field in typeDef.Fields) { if ((!field.IsReachable) && context.Include(field)) { field.MarkReachable(context); } } } if (typeDef.HasMethods) { foreach (var method in typeDef.Methods) { if ((!method.IsReachable) && context.Include(method)) { method.MarkReachable(context); } } } if (typeDef.HasProperties) { foreach (var prop in typeDef.Properties) { if ((!prop.IsReachable) && context.Include(prop)) { prop.MarkReachable(context); } } } // Custom attributes Walk(context, (ICustomAttributeProvider)typeDef); // Walk imported java classes CustomAttribute javaImportAttr; if ((javaImportAttr = typeDef.GetJavaImportAttribute()) != null) { var javaClassName = (string)javaImportAttr.ConstructorArguments[0].Value; ClassFile javaClass; if (context.TryLoadClass(javaClassName, out javaClass)) { javaClass.MarkReachable(context); } } // Dex imported interfaces should have all their methods marked reachable. if (typeDef.IsInterface && typeDef.HasDexImportAttribute()) { typeDef.Methods.ForEach(x => x.MarkReachable(context)); } // Record in context and create class builder context.RecordReachableType(typeDef); } else if ((typeSpec = type as TypeSpecification) != null) { // Element typeSpec.ElementType.MarkReachable(context); // Generic instance GenericInstanceType git; FunctionPointerType fpt; RequiredModifierType reqModType; OptionalModifierType optModType; if ((git = typeSpec as GenericInstanceType) != null) { if (git.ElementType.IsNullableT()) { var typeofT = git.GenericArguments[0].Resolve(context); if (typeofT != null) { typeofT.UsedInNullableT = true; } } Walk(context, (IGenericInstance)git); } else if ((fpt = typeSpec as FunctionPointerType) != null) { Walk(context, fpt.ReturnType); } else if ((reqModType = typeSpec as RequiredModifierType) != null) { reqModType.ModifierType.MarkReachable(context); } else if ((optModType = typeSpec as OptionalModifierType) != null) { optModType.ModifierType.MarkReachable(context); } } else if ((genericParam = type as GenericParameter) != null) { // Owner var owner = (MemberReference)genericParam.Owner; owner.MarkReachable(context); // Constraints if (genericParam.HasConstraints) { foreach (TypeReference constraint in genericParam.Constraints) { constraint.MarkReachable(context); } } } else { // Try to resolve type.Resolve(context).MarkReachable(context); } }
/// <summary> /// Mark all eachable items in argument as such. /// </summary> private static void Walk(ReachableContext context, MethodReference method) { method.ReturnType.MarkReachable(context); // All parameters if (method.HasParameters) { foreach (ParameterDefinition param in method.Parameters) { Walk(context, (ParameterReference)param); } } // Generic parameters Walk(context, (IGenericParameterProvider)method); // Method definition? MethodDefinition methodDef; MethodSpecification methodSpec; if ((methodDef = method as MethodDefinition) != null) { // Code Walk(context, methodDef.Body); // Overrides foreach (MethodReference methodRef in methodDef.Overrides) { methodRef.MarkReachable(context); } // Base methods if (methodDef.IsVirtual) { MethodDefinition baseMethod; if ((baseMethod = methodDef.GetBaseMethod()) != null) { if (context.Contains(baseMethod.DeclaringType)) { baseMethod.MarkReachable(context); } } } // Custom attributes Walk(context, (ICustomAttributeProvider)methodDef); // Walk imported java classes CustomAttribute javaImportAttr; if ((javaImportAttr = methodDef.GetJavaImportAttribute()) != null) { string className; string memberName; string descriptor; javaImportAttr.GetDexOrJavaImportNames(methodDef, out memberName, out descriptor, out className); ClassFile javaClass; if (context.TryLoadClass(className, out javaClass)) { var javaMethod = javaClass.Methods.FirstOrDefault(x => (x.Name == memberName) && (x.Descriptor == descriptor)); javaClass.MarkReachable(context); javaMethod.MarkReachable(context); } } // If this method is a property accessor, include the property also if (methodDef.SemanticsAttributes.HasFlag(MethodSemanticsAttributes.Getter)) { var prop = methodDef.DeclaringType.Properties.FirstOrDefault(x => x.GetMethod == methodDef); prop.MarkReachable(context); } if (methodDef.SemanticsAttributes.HasFlag(MethodSemanticsAttributes.Setter)) { var prop = methodDef.DeclaringType.Properties.FirstOrDefault(x => x.SetMethod == methodDef); prop.MarkReachable(context); } } else if ((methodSpec = method as MethodSpecification) != null) { // Method methodSpec.ElementMethod.MarkReachable(context); // Generic arguments var gim = methodSpec as GenericInstanceMethod; if (gim != null) { Walk(context, (IGenericInstance)gim); } } else { // Try to resolve method.Resolve(context).MarkReachable(context); } }
/// <summary> /// Mark all base types and externally visible members reachable /// </summary> private static void Walk(ReachableContext context, TypeReference type) { // Generic parameters Walk(context, (IGenericParameterProvider)type); TypeDefinition typeDef; TypeSpecification typeSpec; GenericParameter genericParam; if ((typeDef = type as TypeDefinition) != null) { var isUsedInSerialization = typeDef.IsUsedInSerialization && !type.IsPrimitive && !typeDef.IsEnum && !type.Namespace.StartsWith("System"); // Mark base type reachable typeDef.BaseType.MarkReachable(context, isUsedInSerialization); // Mark declaring type reachable typeDef.DeclaringType.MarkReachable(context); // Mark implemented interfaces reachable if (typeDef.HasInterfaces) { foreach (var intf in typeDef.Interfaces.Select(x => x.InterfaceType)) { intf.MarkReachable(context); } } // If this is an attribute, include related types if (typeDef.IsAttribute()) { GetDot42InternalType(context, "IAttribute").MarkReachable(context); GetDot42InternalType(context, "IAttributes").MarkReachable(context); } else if (typeDef.IsEnum) { var boxingType = GetDot42InternalType(context, "Boxing"); boxingType.Methods.Where(x => (x.Name == "UnboxInteger" || x.Name == "UnboxLong")).ForEach(x => x.MarkReachable(context)); } // Default & class ctor typeDef.FindDefaultCtor().MarkReachable(context); typeDef.GetClassCtor().MarkReachable(context); // Visit externally visible members if (typeDef.HasEvents) { foreach (var evt in typeDef.Events) { if ((!evt.IsReachable) && context.Include(evt)) { evt.MarkReachable(context); } } } if (typeDef.HasFields) { foreach (var field in typeDef.Fields) { // only public fields, so we don't pull any compiler generated stuff. var isSerializable = isUsedInSerialization && !field.IsStatic && field.IsPublic; if ((!field.IsReachable && context.Include(field)) || (!field.IsUsedInSerialization && isSerializable)) { field.MarkReachable(context, isUsedInSerialization); } } } if (typeDef.HasMethods) { foreach (var method in typeDef.Methods) { if ((!method.IsReachable) && context.Include(method)) { method.MarkReachable(context); } } } if (typeDef.HasProperties) { foreach (var prop in typeDef.Properties) { var isSerializable = isUsedInSerialization && prop.HasThis; if ((!prop.IsReachable && context.Include(prop) || (!prop.IsUsedInSerialization && isSerializable))) { prop.MarkReachable(context, isUsedInSerialization); } } } // Custom attributes Walk(context, (ICustomAttributeProvider)typeDef); // Walk imported java classes CustomAttribute javaImportAttr; if ((javaImportAttr = typeDef.GetJavaImportAttribute()) != null) { var javaClassName = (string)javaImportAttr.ConstructorArguments[0].Value; ClassFile javaClass; if (context.TryLoadClass(javaClassName, out javaClass)) { javaClass.MarkReachable(context); } } // Dex imported interfaces should have all their methods marked reachable. if (typeDef.IsInterface && typeDef.HasDexImportAttribute()) { typeDef.Methods.ForEach(x => x.MarkReachable(context)); } // Record in context context.RecordReachableType(typeDef); } else if ((typeSpec = type as TypeSpecification) != null) { // Element typeSpec.ElementType.MarkReachable(context, typeSpec.IsUsedInSerialization); // Generic instance GenericInstanceType git; FunctionPointerType fpt; RequiredModifierType reqModType; OptionalModifierType optModType; if ((git = typeSpec as GenericInstanceType) != null) { if (git.ElementType.IsNullableT()) { var typeofT = git.GenericArguments[0].Resolve(context); if (typeofT != null && !typeofT.UsedInNullableT) { typeofT.UsedInNullableT = true; DLog.Debug(DContext.CompilerAssemblyResolver, "found System.Nullable<{0}>", typeofT.FullName); } } Walk(context, (IGenericInstance)git); } else if ((fpt = typeSpec as FunctionPointerType) != null) { Walk(context, fpt.ReturnType); } else if ((reqModType = typeSpec as RequiredModifierType) != null) { reqModType.ModifierType.MarkReachable(context); } else if ((optModType = typeSpec as OptionalModifierType) != null) { optModType.ModifierType.MarkReachable(context); } } else if ((genericParam = type as GenericParameter) != null) { genericParam.IsSerializedParameter = genericParam.HasSerializedParameterAttribute(); // Owner var owner = (MemberReference)genericParam.Owner; owner.MarkReachable(context); // Constraints if (genericParam.HasConstraints) { foreach (TypeReference constraint in genericParam.Constraints) { constraint.MarkReachable(context); } } } else { // Try to resolve type.Resolve(context).MarkReachable(context, type.IsUsedInSerialization); } }