summaryrefslogtreecommitdiffstats
path: root/src/org/jetbrains/java/decompiler/modules/renamer/IdentifierConverter.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/org/jetbrains/java/decompiler/modules/renamer/IdentifierConverter.java')
-rw-r--r--src/org/jetbrains/java/decompiler/modules/renamer/IdentifierConverter.java447
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;
+ }
+
+}