summaryrefslogtreecommitdiffstats
path: root/src/org/jetbrains/java/decompiler/main/ClassReference14Processor.java
diff options
context:
space:
mode:
authorRoman Shevchenko <roman.shevchenko@jetbrains.com>2014-08-28 20:52:43 +0400
committerRoman Shevchenko <roman.shevchenko@jetbrains.com>2014-08-28 20:52:43 +0400
commit663631f0456fcc245dd835889f86541d75161c53 (patch)
treee183fa9777242e2900ff3648a726f05b190bc51b /src/org/jetbrains/java/decompiler/main/ClassReference14Processor.java
parentf864084061806fda5510e50bfd2e69bf1dea406b (diff)
downloadfernflower-663631f0456fcc245dd835889f86541d75161c53.tar
fernflower-663631f0456fcc245dd835889f86541d75161c53.tar.gz
fernflower-663631f0456fcc245dd835889f86541d75161c53.tar.lz
fernflower-663631f0456fcc245dd835889f86541d75161c53.tar.xz
fernflower-663631f0456fcc245dd835889f86541d75161c53.zip
java-decompiler: post-import cleanup (classes moved)
Diffstat (limited to 'src/org/jetbrains/java/decompiler/main/ClassReference14Processor.java')
-rw-r--r--src/org/jetbrains/java/decompiler/main/ClassReference14Processor.java309
1 files changed, 309 insertions, 0 deletions
diff --git a/src/org/jetbrains/java/decompiler/main/ClassReference14Processor.java b/src/org/jetbrains/java/decompiler/main/ClassReference14Processor.java
new file mode 100644
index 0000000..cdad6ca
--- /dev/null
+++ b/src/org/jetbrains/java/decompiler/main/ClassReference14Processor.java
@@ -0,0 +1,309 @@
+/*
+ * Fernflower - The Analytical Java Decompiler
+ * http://www.reversed-java.com
+ *
+ * (C) 2008 - 2010, Stiver
+ *
+ * This software is NEITHER public domain NOR free software
+ * as per GNU License. See license.txt for more details.
+ *
+ * This software is distributed WITHOUT ANY WARRANTY; without
+ * even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE.
+ */
+
+package org.jetbrains.java.decompiler.main;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map.Entry;
+
+import org.jetbrains.java.decompiler.code.CodeConstants;
+import org.jetbrains.java.decompiler.main.ClassesProcessor.ClassNode;
+import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences;
+import org.jetbrains.java.decompiler.main.rels.ClassWrapper;
+import org.jetbrains.java.decompiler.main.rels.MethodWrapper;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.AssignmentExprent;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.ConstExprent;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.ExitExprent;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.FieldExprent;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.FunctionExprent;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.InvocationExprent;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.NewExprent;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.VarExprent;
+import org.jetbrains.java.decompiler.modules.decompiler.sforms.DirectGraph;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.BasicBlockStatement;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.CatchStatement;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.RootStatement;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
+import org.jetbrains.java.decompiler.struct.StructField;
+import org.jetbrains.java.decompiler.struct.StructMethod;
+import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor;
+import org.jetbrains.java.decompiler.struct.gen.VarType;
+import org.jetbrains.java.decompiler.util.InterpreterUtil;
+import org.jetbrains.java.decompiler.util.VBStyleCollection;
+
+public class ClassReference14Processor {
+
+ public ExitExprent bodyexprent;
+
+ public ExitExprent handlerexprent;
+
+
+ public ClassReference14Processor() {
+
+ InvocationExprent invfor = new InvocationExprent();
+ invfor.setName("forName");
+ invfor.setClassname("java/lang/Class");
+ invfor.setStringDescriptor("(Ljava/lang/String;)Ljava/lang/Class;");
+ invfor.setDescriptor(MethodDescriptor.parseDescriptor("(Ljava/lang/String;)Ljava/lang/Class;"));
+ invfor.setStatic(true);
+ invfor.setLstParameters(Arrays.asList(new Exprent[] {new VarExprent(0, VarType.VARTYPE_STRING, null)}));
+
+ bodyexprent = new ExitExprent(ExitExprent.EXIT_RETURN,
+ invfor,
+ VarType.VARTYPE_CLASS);
+
+ InvocationExprent constr = new InvocationExprent();
+ constr.setName("<init>");
+ constr.setClassname("java/lang/NoClassDefFoundError");
+ constr.setStringDescriptor("()V");
+ constr.setFunctype(InvocationExprent.TYP_INIT);
+ constr.setDescriptor(MethodDescriptor.parseDescriptor("()V"));
+
+ NewExprent newexpr = new NewExprent(new VarType(CodeConstants.TYPE_OBJECT,0,"java/lang/NoClassDefFoundError"), new ArrayList<Exprent>());
+ newexpr.setConstructor(constr);
+
+ InvocationExprent invcause = new InvocationExprent();
+ invcause.setName("initCause");
+ invcause.setClassname("java/lang/NoClassDefFoundError");
+ invcause.setStringDescriptor("(Ljava/lang/Throwable;)Ljava/lang/Throwable;");
+ invcause.setDescriptor(MethodDescriptor.parseDescriptor("(Ljava/lang/Throwable;)Ljava/lang/Throwable;"));
+ invcause.setInstance(newexpr);
+ invcause.setLstParameters(Arrays.asList(new Exprent[] {new VarExprent(2, new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/ClassNotFoundException"), null)}));
+
+ handlerexprent = new ExitExprent(ExitExprent.EXIT_THROW,
+ invcause,
+ null);
+ }
+
+
+ public void processClassReferences(ClassNode node) {
+
+ ClassWrapper wrapper = node.wrapper;
+
+// int major_version = wrapper.getClassStruct().major_version;
+// int minor_version = wrapper.getClassStruct().minor_version;
+//
+// if(major_version > 48 || (major_version == 48 && minor_version > 0)) {
+// // version 1.5 or above
+// return;
+// }
+
+ if(wrapper.getClassStruct().isVersionGE_1_5()) {
+ // version 1.5 or above
+ return;
+ }
+
+ // find the synthetic method Class class$(String) if present
+ HashMap<ClassWrapper, MethodWrapper> mapClassMeths = new HashMap<ClassWrapper, MethodWrapper>();
+ findClassMethod(node, mapClassMeths);
+
+ if(mapClassMeths.isEmpty()) {
+ return;
+ }
+
+ HashSet<ClassWrapper> setFound = new HashSet<ClassWrapper>();
+ processClassRec(node, mapClassMeths, setFound);
+
+ if(!setFound.isEmpty()) {
+ for(ClassWrapper wrp : setFound) {
+ StructMethod mt = mapClassMeths.get(wrp).methodStruct;
+ wrp.getHideMembers().add(InterpreterUtil.makeUniqueKey(mt.getName(), mt.getDescriptor()));
+ }
+ }
+
+ }
+
+ private void processClassRec(ClassNode node, final HashMap<ClassWrapper, MethodWrapper> mapClassMeths, final HashSet<ClassWrapper> setFound) {
+
+ final ClassWrapper wrapper = node.wrapper;
+
+ // search code
+ for(MethodWrapper meth : wrapper.getMethods()) {
+
+ RootStatement root = meth.root;
+ if(root != null) {
+
+ DirectGraph graph = meth.getOrBuildGraph();
+
+ graph.iterateExprents(new DirectGraph.ExprentIterator() {
+ public int processExprent(Exprent exprent) {
+ for(Entry<ClassWrapper, MethodWrapper> ent : mapClassMeths.entrySet()) {
+ if(replaceInvocations(exprent, ent.getKey(), ent.getValue())) {
+ setFound.add(ent.getKey());
+ }
+ }
+ return 0;
+ }
+ });
+
+ }
+ }
+
+ // search initializers
+ for(int j=0;j<2;j++) {
+ VBStyleCollection<Exprent, String> initializers = j==0?wrapper.getStaticFieldInitializers():wrapper.getDynamicFieldInitializers();
+
+ for(int i=0; i<initializers.size();i++) {
+ for(Entry<ClassWrapper, MethodWrapper> ent : mapClassMeths.entrySet()) {
+ Exprent exprent = initializers.get(i);
+ if(replaceInvocations(exprent, ent.getKey(), ent.getValue())) {
+ setFound.add(ent.getKey());
+ }
+
+ String cl = isClass14Invocation(exprent, ent.getKey(), ent.getValue());
+ if(cl != null) {
+ initializers.set(i, new ConstExprent(VarType.VARTYPE_CLASS, cl.replace('.', '/')));
+ setFound.add(ent.getKey());
+ }
+ }
+ }
+ }
+
+ // iterate nested classes
+ for(ClassNode nd : node.nested) {
+ processClassRec(nd, mapClassMeths, setFound);
+ }
+
+ }
+
+ private void findClassMethod(ClassNode node, HashMap<ClassWrapper, MethodWrapper> mapClassMeths) {
+
+ boolean nosynthflag = DecompilerContext.getOption(IFernflowerPreferences.SYNTHETIC_NOT_SET);
+
+ ClassWrapper wrapper = node.wrapper;
+
+ for(MethodWrapper meth : wrapper.getMethods()) {
+ StructMethod mt = meth.methodStruct;
+
+ if(((mt.getAccessFlags() & CodeConstants.ACC_SYNTHETIC) != 0 || mt.getAttributes().containsKey("Synthetic")
+ || nosynthflag) &&
+ mt.getDescriptor().equals("(Ljava/lang/String;)Ljava/lang/Class;") &&
+ (mt.getAccessFlags() & CodeConstants.ACC_STATIC) != 0) {
+
+ RootStatement root = meth.root;
+ if(root != null) {
+ if(root.getFirst().type == Statement.TYPE_TRYCATCH) {
+ CatchStatement cst = (CatchStatement)root.getFirst();
+ if(cst.getStats().size() == 2 && cst.getFirst().type == Statement.TYPE_BASICBLOCK &&
+ cst.getStats().get(1).type == Statement.TYPE_BASICBLOCK &&
+ cst.getVars().get(0).getVartype().equals(new VarType(CodeConstants.TYPE_OBJECT,0,"java/lang/ClassNotFoundException"))) {
+
+ BasicBlockStatement body = (BasicBlockStatement)cst.getFirst();
+ BasicBlockStatement handler = (BasicBlockStatement)cst.getStats().get(1);
+
+ if(body.getExprents().size() == 1 && handler.getExprents().size() == 1) {
+ if(bodyexprent.equals(body.getExprents().get(0)) &&
+ handlerexprent.equals(handler.getExprents().get(0))) {
+ mapClassMeths.put(wrapper, meth);
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // iterate nested classes
+ for(ClassNode nd : node.nested) {
+ findClassMethod(nd, mapClassMeths);
+ }
+
+ }
+
+
+ private boolean replaceInvocations(Exprent exprent, ClassWrapper wrapper, MethodWrapper meth) {
+
+ boolean res = false;
+
+ for(;;) {
+
+ boolean found = false;
+
+ for(Exprent expr : exprent.getAllExprents()) {
+ String cl = isClass14Invocation(expr, wrapper, meth);
+ if(cl != null) {
+ exprent.replaceExprent(expr, new ConstExprent(VarType.VARTYPE_CLASS, cl.replace('.', '/')));
+ found = true;
+ res = true;
+ break;
+ }
+
+ res |= replaceInvocations(expr, wrapper, meth);
+ }
+
+ if(!found) {
+ break;
+ }
+ }
+
+ return res;
+ }
+
+
+
+ private String isClass14Invocation(Exprent exprent, ClassWrapper wrapper, MethodWrapper meth) {
+
+ if(exprent.type == Exprent.EXPRENT_FUNCTION) {
+ FunctionExprent fexpr = (FunctionExprent)exprent;
+ if(fexpr.getFunctype() == FunctionExprent.FUNCTION_IIF) {
+ if(fexpr.getLstOperands().get(0).type == Exprent.EXPRENT_FUNCTION) {
+ FunctionExprent headexpr = (FunctionExprent)fexpr.getLstOperands().get(0);
+ if(headexpr.getFunctype() == FunctionExprent.FUNCTION_EQ) {
+ if(headexpr.getLstOperands().get(0).type == Exprent.EXPRENT_FIELD &&
+ headexpr.getLstOperands().get(1).type == Exprent.EXPRENT_CONST &&
+ ((ConstExprent)headexpr.getLstOperands().get(1)).getConsttype().equals(VarType.VARTYPE_NULL)) {
+
+ FieldExprent field = (FieldExprent)headexpr.getLstOperands().get(0);
+ ClassNode fieldnode = DecompilerContext.getClassprocessor().getMapRootClasses().get(field.getClassname());
+
+ if(fieldnode != null && fieldnode.classStruct.qualifiedName.equals(wrapper.getClassStruct().qualifiedName)) { // source class
+ StructField fd = wrapper.getClassStruct().getField(field.getName(), field.getDescriptor().descriptorString); // FIXME: can be null! why??
+
+ if(fd != null && (fd.access_flags & CodeConstants.ACC_STATIC) != 0 &&
+ ((fd.access_flags & CodeConstants.ACC_SYNTHETIC) != 0 || fd.getAttributes().containsKey("Synthetic")
+ || DecompilerContext.getOption(IFernflowerPreferences.SYNTHETIC_NOT_SET))) {
+
+ if(fexpr.getLstOperands().get(1).type == Exprent.EXPRENT_ASSIGNMENT && fexpr.getLstOperands().get(2).equals(field)) {
+ AssignmentExprent asexpr = (AssignmentExprent)fexpr.getLstOperands().get(1);
+
+ if(asexpr.getLeft().equals(field) && asexpr.getRight().type == Exprent.EXPRENT_INVOCATION) {
+ InvocationExprent invexpr = (InvocationExprent)asexpr.getRight();
+
+ if(invexpr.getClassname().equals(wrapper.getClassStruct().qualifiedName) &&
+ invexpr.getName().equals(meth.methodStruct.getName()) &&
+ invexpr.getStringDescriptor().equals(meth.methodStruct.getDescriptor())) {
+
+ if(invexpr.getLstParameters().get(0).type == Exprent.EXPRENT_CONST) {
+ wrapper.getHideMembers().add(InterpreterUtil.makeUniqueKey(fd.getName(), fd.getDescriptor())); // hide synthetic field
+ return ((ConstExprent)invexpr.getLstParameters().get(0)).getValue().toString();
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+}