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 rootClasses = new ArrayList(); private List rootInterfaces = new ArrayList(); private HashMap> interfaceNameMaps = new HashMap>(); 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 lstClasses = getReversePostOrderListIterative(rootClasses); HashMap> classNameMaps = new HashMap>(); for(ClassWrapperNode node : lstClasses) { StructClass cl = node.getClassStruct(); HashMap names = new HashMap(); // merge informations on super class if(cl.superClass != null) { HashMap mapClass = classNameMaps.get(cl.superClass.getString()); if(mapClass != null) { names.putAll(mapClass); } } // merge informations on interfaces for(String intrName : cl.getInterfaceNames()) { HashMap 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 processExternalInterface(StructClass cl) { HashMap names = new HashMap(); for(String intrName : cl.getInterfaceNames()) { HashMap 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 lstInterfaces = getReversePostOrderListIterative(rootInterfaces); HashMap> interfaceNameMaps = new HashMap>(); // rename methods and fields for(ClassWrapperNode node : lstInterfaces) { StructClass cl = node.getClassStruct(); HashMap names = new HashMap(); // merge informations on super interfaces for(String intrName : cl.getInterfaceNames()) { HashMap 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 lstAllClasses = new ArrayList(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 names) { // all classes are already renamed String classOldFullName = cl.qualifiedName; String classNewFullName = interceptor.getName(classOldFullName); if(classNewFullName == null) { classNewFullName = classOldFullName; } // methods HashSet setMethodNames = new HashSet(); for(StructMethod md : cl.getMethods()) { setMethodNames.add(md.getName()); } VBStyleCollection methods = cl.getMethods(); for(int i=0;i setFieldNames = new HashSet(); 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 getReversePostOrderListIterative(List roots) { List res = new ArrayList(); LinkedList stackNode = new LinkedList(); LinkedList stackIndex = new LinkedList(); HashSet setVisited = new HashSet(); 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 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 nodes = new HashMap(); HashMap classes = context.getClasses(); List rootClasses = new ArrayList(); List rootInterfaces = new ArrayList(); for(StructClass cl : classes.values()) { if(!cl.isOwn()) { continue; } LinkedList stack = new LinkedList(); LinkedList stackSubnodes = new LinkedList(); 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; } }