diff options
Diffstat (limited to 'src/org/jetbrains/java/decompiler/modules/renamer/IdentifierConverter.java')
-rw-r--r-- | src/org/jetbrains/java/decompiler/modules/renamer/IdentifierConverter.java | 447 |
1 files changed, 447 insertions, 0 deletions
diff --git a/src/org/jetbrains/java/decompiler/modules/renamer/IdentifierConverter.java b/src/org/jetbrains/java/decompiler/modules/renamer/IdentifierConverter.java new file mode 100644 index 0000000..634dc59 --- /dev/null +++ b/src/org/jetbrains/java/decompiler/modules/renamer/IdentifierConverter.java @@ -0,0 +1,447 @@ +package org.jetbrains.java.decompiler.modules.renamer; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; + +import org.jetbrains.java.decompiler.code.CodeConstants; +import org.jetbrains.java.decompiler.main.DecompilerContext; +import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences; +import org.jetbrains.java.decompiler.main.extern.IIdentifierRenamer; +import org.jetbrains.java.decompiler.struct.StructClass; +import org.jetbrains.java.decompiler.struct.StructContext; +import org.jetbrains.java.decompiler.struct.StructField; +import org.jetbrains.java.decompiler.struct.StructMethod; +import org.jetbrains.java.decompiler.struct.gen.FieldDescriptor; +import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor; +import org.jetbrains.java.decompiler.struct.gen.VarType; +import org.jetbrains.java.decompiler.util.VBStyleCollection; + +public class IdentifierConverter { + + private StructContext context; + + private IIdentifierRenamer helper; + + private PoolInterceptor interceptor; + + private List<ClassWrapperNode> rootClasses = new ArrayList<ClassWrapperNode>(); + + private List<ClassWrapperNode> rootInterfaces = new ArrayList<ClassWrapperNode>(); + + private HashMap<String, HashMap<String, String>> interfaceNameMaps = new HashMap<String, HashMap<String, String>>(); + + public void rename(StructContext context) { + + try { + this.context = context; + + String user_class = (String)DecompilerContext.getProperty(IFernflowerPreferences.USER_RENAMER_CLASS); + if(user_class != null) { + try { + helper = (IIdentifierRenamer)IdentifierConverter.class.getClassLoader().loadClass(user_class).newInstance(); + } catch(Exception ex) { + ; // ignore errors + } + } + + if(helper == null) { + helper = new ConverterHelper(); + } + + interceptor = new PoolInterceptor(helper); + + buildInheritanceTree(); + + renameAllClasses(); + + renameInterfaces(); + + renameClasses(); + + DecompilerContext.setPoolInterceptor(interceptor); + context.reloadContext(); + + } catch(IOException ex){ + throw new RuntimeException("Renaming failed!"); + } + + } + + private void renameClasses() { + + List<ClassWrapperNode> lstClasses = getReversePostOrderListIterative(rootClasses); + + HashMap<String, HashMap<String, String>> classNameMaps = new HashMap<String, HashMap<String, String>>(); + + for(ClassWrapperNode node : lstClasses) { + + StructClass cl = node.getClassStruct(); + HashMap<String, String> names = new HashMap<String, String>(); + + // merge informations on super class + if(cl.superClass != null) { + HashMap<String, String> mapClass = classNameMaps.get(cl.superClass.getString()); + if(mapClass != null) { + names.putAll(mapClass); + } + } + + // merge informations on interfaces + for(String intrName : cl.getInterfaceNames()) { + HashMap<String, String> mapInt = interfaceNameMaps.get(intrName); + if(mapInt != null) { + names.putAll(mapInt); + } else { + StructClass clintr = context.getClass(intrName); + if(clintr!=null) { + names.putAll(processExternalInterface(clintr)); + } + } + } + + renameClassIdentifiers(cl, names); + + if(!node.getSubclasses().isEmpty()) { + classNameMaps.put(cl.qualifiedName, names); + } + } + + } + + private HashMap<String, String> processExternalInterface(StructClass cl) { + + HashMap<String, String> names = new HashMap<String, String>(); + + for(String intrName : cl.getInterfaceNames()) { + + HashMap<String, String> mapInt = interfaceNameMaps.get(intrName); + if(mapInt != null) { + names.putAll(mapInt); + } else { + StructClass clintr = context.getClass(intrName); + if(clintr!=null) { + names.putAll(processExternalInterface(clintr)); + } + } + } + + renameClassIdentifiers(cl, names); + + return names; + } + + private void renameInterfaces() { + + List<ClassWrapperNode> lstInterfaces = getReversePostOrderListIterative(rootInterfaces); + + HashMap<String, HashMap<String, String>> interfaceNameMaps = new HashMap<String, HashMap<String, String>>(); + + // rename methods and fields + for(ClassWrapperNode node : lstInterfaces) { + + StructClass cl = node.getClassStruct(); + HashMap<String, String> names = new HashMap<String, String>(); + + // merge informations on super interfaces + for(String intrName : cl.getInterfaceNames()) { + HashMap<String, String> mapInt = interfaceNameMaps.get(intrName); + if(mapInt != null) { + names.putAll(mapInt); + } + } + + renameClassIdentifiers(cl, names); + + interfaceNameMaps.put(cl.qualifiedName, names); + } + + this.interfaceNameMaps = interfaceNameMaps; + } + + private void renameAllClasses() { + + // order not important + List<ClassWrapperNode> lstAllClasses = new ArrayList<ClassWrapperNode>(getReversePostOrderListIterative(rootInterfaces)); + lstAllClasses.addAll(getReversePostOrderListIterative(rootClasses)); + + // rename all interfaces and classes + for(ClassWrapperNode node : lstAllClasses) { + renameClass(node.getClassStruct()); + } + } + + private void renameClass(StructClass cl) { + + if(!cl.isOwn()) { + return; + } + + String classOldFullName = cl.qualifiedName; + String classNewFullName = classOldFullName; + + // TODO: rename packages + String clsimplename = ConverterHelper.getSimpleClassName(classOldFullName); + if(helper.toBeRenamed(IIdentifierRenamer.ELEMENT_CLASS, clsimplename, null, null)) { + do { + classNewFullName = ConverterHelper.replaceSimpleClassName(classOldFullName, + helper.getNextClassname(classOldFullName, ConverterHelper.getSimpleClassName(classOldFullName))); + } while(context.getClasses().containsKey(classNewFullName)); + + interceptor.addName(classOldFullName, classNewFullName); + } + + } + + private void renameClassIdentifiers(StructClass cl, HashMap<String, String> names) { + + // all classes are already renamed + String classOldFullName = cl.qualifiedName; + String classNewFullName = interceptor.getName(classOldFullName); + + if(classNewFullName == null) { + classNewFullName = classOldFullName; + } + + // methods + HashSet<String> setMethodNames = new HashSet<String>(); + for(StructMethod md : cl.getMethods()) { + setMethodNames.add(md.getName()); + } + + VBStyleCollection<StructMethod, String> methods = cl.getMethods(); + for(int i=0;i<methods.size();i++) { + + StructMethod mt = methods.get(i); + String key = methods.getKey(i); + + int access_flags = mt.getAccessFlags(); + boolean isPrivate = ((access_flags & CodeConstants.ACC_PRIVATE) != 0); + + String name = mt.getName(); + if(!cl.isOwn() || (access_flags & CodeConstants.ACC_NATIVE) != 0) { + // external and native methods must not be renamed + if(!isPrivate) { + names.put(key, name); + } + } else if(helper.toBeRenamed(IIdentifierRenamer.ELEMENT_METHOD, classOldFullName, name, mt.getDescriptor())) { + if(isPrivate || !names.containsKey(key)) { + do { + name = helper.getNextMethodname(classOldFullName, name, mt.getDescriptor()); + } while(setMethodNames.contains(name)); + + if(!isPrivate) { + names.put(key, name); + } + } else { + name = names.get(key); + } + + interceptor.addName(classOldFullName+" "+mt.getName()+" "+mt.getDescriptor(), + classNewFullName+" "+name+" "+buildNewDescriptor(false, mt.getDescriptor())); + } + } + + // external fields are not being renamed + if(!cl.isOwn()) { + return; + } + + // fields + // FIXME: should overloaded fields become the same name? + HashSet<String> setFieldNames = new HashSet<String>(); + for(StructField fd : cl.getFields()) { + setFieldNames.add(fd.getName()); + } + + for(StructField fd : cl.getFields()) { + if(helper.toBeRenamed(IIdentifierRenamer.ELEMENT_FIELD, classOldFullName, fd.getName(), fd.getDescriptor())) { + String newname; + + do { + newname = helper.getNextFieldname(classOldFullName, fd.getName(), fd.getDescriptor()); + } while(setFieldNames.contains(newname)); + + interceptor.addName(classOldFullName+" "+fd.getName()+" "+fd.getDescriptor(), + classNewFullName+" "+newname+" "+buildNewDescriptor(true, fd.getDescriptor())); + } + } + + } + + private String buildNewDescriptor(boolean isField, String descriptor) { + + boolean updated = false; + + if(isField) { + FieldDescriptor fd = FieldDescriptor.parseDescriptor(descriptor); + + VarType ftype = fd.type; + if(ftype.type == CodeConstants.TYPE_OBJECT) { + String newclname = interceptor.getName(ftype.value); + if(newclname != null) { + ftype.value = newclname; + updated = true; + } + } + + if(updated) { + return fd.getDescriptor(); + } + + } else { + + MethodDescriptor md = MethodDescriptor.parseDescriptor(descriptor); + // params + for(VarType partype : md.params) { + if(partype.type == CodeConstants.TYPE_OBJECT) { + String newclname = interceptor.getName(partype.value); + if(newclname != null) { + partype.value = newclname; + updated = true; + } + } + } + + // return value + if(md.ret.type == CodeConstants.TYPE_OBJECT) { + String newclname = interceptor.getName(md.ret.value); + if(newclname!=null) { + md.ret.value = newclname; + updated = true; + } + } + + if(updated) { + return md.getDescriptor(); + } + } + + return descriptor; + } + + private List<ClassWrapperNode> getReversePostOrderListIterative(List<ClassWrapperNode> roots) { + + List<ClassWrapperNode> res = new ArrayList<ClassWrapperNode>(); + + LinkedList<ClassWrapperNode> stackNode = new LinkedList<ClassWrapperNode>(); + LinkedList<Integer> stackIndex = new LinkedList<Integer>(); + + HashSet<ClassWrapperNode> setVisited = new HashSet<ClassWrapperNode>(); + + for(ClassWrapperNode root : roots) { + stackNode.add(root); + stackIndex.add(0); + } + + while(!stackNode.isEmpty()) { + + ClassWrapperNode node = stackNode.getLast(); + int index = stackIndex.removeLast(); + + setVisited.add(node); + + List<ClassWrapperNode> lstSubs = node.getSubclasses(); + + for(; index < lstSubs.size(); index++) { + ClassWrapperNode sub = lstSubs.get(index); + if(!setVisited.contains(sub)) { + stackIndex.add(index+1); + + stackNode.add(sub); + stackIndex.add(0); + + break; + } + } + + if(index == lstSubs.size()) { + res.add(0, node); + + stackNode.removeLast(); + } + } + + return res; + } + + + private void buildInheritanceTree() { + + HashMap<String, ClassWrapperNode> nodes = new HashMap<String, ClassWrapperNode>(); + HashMap<String, StructClass> classes = context.getClasses(); + + List<ClassWrapperNode> rootClasses = new ArrayList<ClassWrapperNode>(); + List<ClassWrapperNode> rootInterfaces = new ArrayList<ClassWrapperNode>(); + + for(StructClass cl : classes.values()) { + + if(!cl.isOwn()) { + continue; + } + + LinkedList<StructClass> stack = new LinkedList<StructClass>(); + LinkedList<ClassWrapperNode> stackSubnodes = new LinkedList<ClassWrapperNode>(); + + stack.add(cl); + stackSubnodes.add(null); + + while(!stack.isEmpty()) { + + StructClass clstr = stack.removeFirst(); + ClassWrapperNode child = stackSubnodes.removeFirst(); + + ClassWrapperNode node = nodes.get(clstr.qualifiedName); + boolean isNewNode = (node == null); + + if(isNewNode) { + nodes.put(clstr.qualifiedName, node = new ClassWrapperNode(clstr)); + } + + if(child!=null) { + node.addSubclass(child); + } + + if(!isNewNode) { + break; + } else { + + boolean isInterface = ((clstr.access_flags & CodeConstants.ACC_INTERFACE) != 0); + boolean found_parent = false; + + if(isInterface) { + for(String intrName : clstr.getInterfaceNames()) { + StructClass clparent = classes.get(intrName); + if(clparent != null) { + stack.add(clparent); + stackSubnodes.add(node); + found_parent = true; + } + } + } else { + if(clstr.superClass != null) { // null iff java/lang/Object + StructClass clparent = classes.get(clstr.superClass.getString()); + + if(clparent != null) { + stack.add(clparent); + stackSubnodes.add(node); + found_parent = true; + } + } + } + + if(!found_parent) { // no super class or interface + (isInterface?rootInterfaces:rootClasses).add(node); + } + } + } + } + + this.rootClasses = rootClasses; + this.rootInterfaces = rootInterfaces; + } + +} |