void instantiateVirtualMembers(MethodNameScopes scopes) { if (!TypeDefinition.IsInterface) { if (baseType != null) virtualMethodInstances.initializeFrom(baseType.typeDef.virtualMethodInstances, baseType.typeReference as GenericInstanceType); // Figure out which methods we override in the base class foreach (var methodDef in methods.getValues()) { if (!methodDef.isVirtual() || methodDef.isNewSlot()) continue; var methodInstList = virtualMethodInstances.lookup(methodDef.MethodDefinition); if (methodInstList == null) continue; foreach (var methodInst in methodInstList) scopes.same(methodDef, methodInst.origMethodDef); } } foreach (var methodDef in methods.getValues()) { if (!methodDef.isVirtual()) continue; virtualMethodInstances.add(new MethodInst(methodDef, methodDef.MethodDefinition)); } }
public void initializeVirtualMembers(MethodNameScopes scopes, IResolver resolver) { if (initializeVirtualMembersCalled) return; initializeVirtualMembersCalled = true; foreach (var iface in interfaces) iface.typeDef.initializeVirtualMembers(scopes, resolver); if (baseType != null) baseType.typeDef.initializeVirtualMembers(scopes, resolver); foreach (var methodDef in methods.getValues()) { if (methodDef.isVirtual()) scopes.add(methodDef); } instantiateVirtualMembers(scopes); initializeInterfaceMethods(scopes); }
void initializeInterfaceMethods(MethodNameScopes scopes) { if (baseType != null) overrideMethods = new Dictionary<MethodDef, bool>(baseType.typeDef.overrideMethods); else overrideMethods = new Dictionary<MethodDef, bool>(); initializeAllInterfaces(); if (TypeDefinition.IsInterface) return; //--- Partition II 12.2 Implementing virtual methods on interfaces: //--- The VES shall use the following algorithm to determine the appropriate //--- implementation of an interface's virtual abstract methods: //--- //--- * If the base class implements the interface, start with the same virtual methods //--- that it provides; otherwise, create an interface that has empty slots for all //--- virtual functions. // Done. See initializeAllInterfaces(). var methodsDict = new Dictionary<MethodReferenceKey, MethodDef>(); //--- * If this class explicitly specifies that it implements the interface (i.e., the //--- interfaces that appear in this class‘ InterfaceImpl table, §22.23) //--- * If the class defines any public virtual newslot methods whose name and //--- signature match a virtual method on the interface, then use these new virtual //--- methods to implement the corresponding interface method. if (interfaces.Count > 0) { methodsDict.Clear(); foreach (var method in methods.getValues()) { if (!method.isPublic() || !method.isVirtual() || !method.isNewSlot()) continue; methodsDict[new MethodReferenceKey(method.MethodDefinition)] = method; } foreach (var ifaceInfo in interfaces) { foreach (var methodsList in ifaceInfo.typeDef.virtualMethodInstances.getMethods()) { if (methodsList.Count != 1) // Never happens throw new ApplicationException("Interface with more than one method in the list"); var methodInst = methodsList[0]; var ifaceMethod = methodInst.origMethodDef; if (!ifaceMethod.isVirtual()) continue; var ifaceMethodReference = MethodReferenceInstance.make(methodInst.methodReference, ifaceInfo.typeReference as GenericInstanceType); MethodDef classMethod; var key = new MethodReferenceKey(ifaceMethodReference); if (!methodsDict.TryGetValue(key, out classMethod)) continue; interfaceMethodInfos.addMethod(ifaceInfo, ifaceMethod, classMethod); } } } //--- * If there are any virtual methods in the interface that still have empty slots, //--- see if there are any public virtual methods, but not public virtual newslot //--- methods, available on this class (directly or inherited) having the same name //--- and signature, then use these to implement the corresponding methods on the //--- interface. methodsDict.Clear(); foreach (var methodInstList in virtualMethodInstances.getMethods()) { // This class' method is at the end for (int i = methodInstList.Count - 1; i >= 0; i--) { var classMethod = methodInstList[i]; // These methods are guaranteed to be virtual. // We should allow newslot methods, despite what the official doc says. if (!classMethod.origMethodDef.isPublic()) continue; methodsDict[new MethodReferenceKey(classMethod.methodReference)] = classMethod.origMethodDef; break; } } foreach (var ifaceInfo in allImplementedInterfaces.Keys) { foreach (var methodsList in ifaceInfo.typeDef.virtualMethodInstances.getMethods()) { if (methodsList.Count != 1) // Never happens throw new ApplicationException("Interface with more than one method in the list"); var ifaceMethod = methodsList[0].origMethodDef; if (!ifaceMethod.isVirtual()) continue; var ifaceMethodRef = MethodReferenceInstance.make(ifaceMethod.MethodDefinition, ifaceInfo.typeReference as GenericInstanceType); MethodDef classMethod; var key = new MethodReferenceKey(ifaceMethodRef); if (!methodsDict.TryGetValue(key, out classMethod)) continue; interfaceMethodInfos.addMethodIfEmpty(ifaceInfo, ifaceMethod, classMethod); } } //--- * Apply all MethodImpls that are specified for this class, thereby placing //--- explicitly specified virtual methods into the interface in preference to those //--- inherited or chosen by name matching. methodsDict.Clear(); var ifaceMethodsDict = new Dictionary<MethodReferenceAndDeclaringTypeKey, MethodDef>(); foreach (var ifaceInfo in allImplementedInterfaces.Keys) { var git = ifaceInfo.typeReference as GenericInstanceType; foreach (var ifaceMethod in ifaceInfo.typeDef.methods.getValues()) { MethodReference ifaceMethodReference = ifaceMethod.MethodDefinition; if (git != null) ifaceMethodReference = simpleClone(ifaceMethod.MethodDefinition, git); ifaceMethodsDict[new MethodReferenceAndDeclaringTypeKey(ifaceMethodReference)] = ifaceMethod; } } foreach (var classMethod in methods.getValues()) { if (!classMethod.isVirtual()) continue; foreach (var overrideMethod in classMethod.MethodDefinition.Overrides) { MethodDef ifaceMethod; var key = new MethodReferenceAndDeclaringTypeKey(overrideMethod); if (!ifaceMethodsDict.TryGetValue(key, out ifaceMethod)) { // We couldn't find the interface method (eg. interface not resolved) or // it overrides a base class method, and not an interface method. continue; } var oldMethod = interfaceMethodInfos.addMethod(overrideMethod.DeclaringType, ifaceMethod, classMethod); if (oldMethod != classMethod) overrideMethods[classMethod] = true; } } //--- * If the current class is not abstract and there are any interface methods that //--- still have empty slots, then the program is invalid. // Check it anyway. C# requires a method, even if it's abstract. I don't think anyone // writes pure CIL assemblies. foreach (var info in interfaceMethodInfos.AllInfos) { foreach (var pair in info.IfaceMethodToClassMethod) { if (pair.Value != null) continue; if (!resolvedAllInterfaces() || !resolvedBaseClasses()) continue; // Ignore if COM class if (!TypeDefinition.IsImport && !hasAttribute("System.Runtime.InteropServices.ComImportAttribute") && !hasAttribute("System.Runtime.InteropServices.TypeLibTypeAttribute")) { Log.w("Could not find interface method {0} ({1:X8}). Type: {2} ({3:X8})", Utils.removeNewlines(pair.Key.MethodDefinition), pair.Key.MethodDefinition.MetadataToken.ToInt32(), Utils.removeNewlines(TypeDefinition), TypeDefinition.MetadataToken.ToInt32()); } } } foreach (var info in interfaceMethodInfos.AllInfos) { foreach (var pair in info.IfaceMethodToClassMethod) { if (pair.Value == null) continue; if (overrideMethods.ContainsKey(pair.Value)) continue; scopes.same(pair.Key, pair.Value); } } }
void prepareRenameMemberDefinitions(MethodNameScopes scopes) { Log.v("Renaming member definitions #1"); prepareRenameEntryPoints(); var virtualMethods = new ScopeHelper(memberInfos, modules.AllTypes); var ifaceMethods = new ScopeHelper(memberInfos, modules.AllTypes); var propMethods = new ScopeHelper(memberInfos, modules.AllTypes); var eventMethods = new ScopeHelper(memberInfos, modules.AllTypes); foreach (var scope in getSorted(scopes)) { if (scope.hasNonRenamableMethod()) continue; else if (scope.hasGetterOrSetterPropertyMethod() && getPropertyMethodType(scope.Methods[0]) != PropertyMethodType.Other) propMethods.add(scope); else if (scope.hasAddRemoveOrRaiseEventMethod()) eventMethods.add(scope); else if (scope.hasInterfaceMethod()) ifaceMethods.add(scope); else virtualMethods.add(scope); } var prepareHelper = new PrepareHelper(memberInfos, modules.AllTypes); prepareHelper.prepare((info) => info.prepareRenameMembers()); prepareHelper.prepare((info) => info.prepareRenamePropsAndEvents()); propMethods.visitAll((scope) => prepareRenameProperty(scope, false)); eventMethods.visitAll((scope) => prepareRenameEvent(scope, false)); propMethods.visitAll((scope) => prepareRenameProperty(scope, true)); eventMethods.visitAll((scope) => prepareRenameEvent(scope, true)); foreach (var typeDef in modules.AllTypes) memberInfos.type(typeDef).initializeEventHandlerNames(); prepareHelper.prepare((info) => info.prepareRenameMethods()); ifaceMethods.visitAll((scope) => prepareRenameVirtualMethods(scope, "imethod_", false)); virtualMethods.visitAll((scope) => prepareRenameVirtualMethods(scope, "vmethod_", false)); ifaceMethods.visitAll((scope) => prepareRenameVirtualMethods(scope, "imethod_", true)); virtualMethods.visitAll((scope) => prepareRenameVirtualMethods(scope, "vmethod_", true)); restoreMethodArgs(scopes); foreach (var typeDef in modules.AllTypes) memberInfos.type(typeDef).prepareRenameMethods2(); }
static List<MethodNameScope> getSorted(MethodNameScopes scopes) { var allScopes = new List<MethodNameScope>(scopes.getAllScopes()); allScopes.Sort((a, b) => Utils.compareInt32(b.Count, a.Count)); return allScopes; }
void restorePropertiesAndEvents(MethodNameScopes scopes) { var allScopes = scopes.getAllScopes(); restoreVirtualProperties(allScopes); restorePropertiesFromNames(allScopes); restoreVirtualEvents(allScopes); restoreEventsFromNames(allScopes); }
void restoreMethodArgs(MethodNameScopes scopes) { foreach (var scope in scopes.getAllScopes()) { if (scope.Methods[0].ParamDefs.Count == 0) continue; var argNames = getValidArgNames(scope); foreach (var method in scope.Methods) { if (!method.Owner.HasModule) continue; var nameChecker = method.Owner.Module.ObfuscatedFile.NameChecker; for (int i = 0; i < argNames.Length; i++) { var argName = argNames[i]; if (argName == null || !nameChecker.isValidMethodArgName(argName)) continue; var info = memberInfos.param(method.ParamDefs[i]); if (nameChecker.isValidMethodArgName(info.oldName)) continue; info.newName = argName; } } } }
void removeUselessOverrides(MethodNameScopes scopes) { foreach (var scope in scopes.getAllScopes()) { foreach (var method in scope.Methods) { if (!method.Owner.HasModule) continue; if (!method.isPublic()) continue; var overrides = method.MethodDefinition.Overrides; for (int i = 0; i < overrides.Count; i++) { var overrideMethod = overrides[i]; if (method.MethodDefinition.Name != overrideMethod.Name) continue; Log.v("Removed useless override from method {0} ({1:X8}), override: {2:X8}", Utils.removeNewlines(method.MethodDefinition), method.MethodDefinition.MetadataToken.ToInt32(), overrideMethod.MetadataToken.ToInt32()); overrides.RemoveAt(i); i--; } } } }