diff --git a/jode/jode/expr/Expression.java.in b/jode/jode/expr/Expression.java.in index 0bd54ae..9749201 100644 --- a/jode/jode/expr/Expression.java.in +++ b/jode/jode/expr/Expression.java.in @@ -23,6 +23,7 @@ import jode.GlobalOptions; import jode.decompiler.TabbedPrintWriter; import @COLLECTIONS@.Collection; +import @COLLECTIONS@.Set; public abstract class Expression { protected Type type; @@ -230,6 +231,9 @@ public abstract class Expression { public void fillDeclarables(Collection used) { } + public void makeDeclaration(Set done) { + } + public abstract void dumpExpression(TabbedPrintWriter writer) throws java.io.IOException; diff --git a/jode/jode/expr/FieldOperator.java.in b/jode/jode/expr/FieldOperator.java.in index e23becb..6384981 100644 --- a/jode/jode/expr/FieldOperator.java.in +++ b/jode/jode/expr/FieldOperator.java.in @@ -29,9 +29,9 @@ import jode.decompiler.MethodAnalyzer; import jode.decompiler.ClassAnalyzer; import jode.decompiler.MethodAnalyzer; import jode.decompiler.FieldAnalyzer; +import jode.decompiler.Options; import jode.decompiler.TabbedPrintWriter; import jode.decompiler.Scope; -import jode.Decompiler; import @COLLECTIONS@.Collection; @@ -157,21 +157,19 @@ public abstract class FieldOperator extends Operator { InnerClassInfo outer = getOuterClassInfo(clazz); ClassAnalyzer clazzAna = methodAnalyzer.getClassAnalyzer(clazz); - if ((Decompiler.options & Decompiler.OPTION_ANON) != 0 + if ((Options.options & Options.OPTION_ANON) != 0 + && outer != null && outer.outer == null && outer.name != null && clazzAna != null - && outer != null && (outer.outer == null || outer.name == null)) { - - if (outer.name != null) { - if (clazzAna.getParent() == methodAnalyzer) { - /* This is a named method scope class, declare it. - * But first declare all method scoped classes, - * that are used inside; order does matter. - */ - clazzAna.fillDeclarables(used); - used.add(clazzAna); - } - } + && clazzAna.getParent() == methodAnalyzer) { + + /* This is a named method scope class, declare it. + * But first declare all method scoped classes, + * that are used inside; order does matter. + */ + clazzAna.fillDeclarables(used); + used.add(clazzAna); } + super.fillDeclarables(used); } public void dumpExpression(TabbedPrintWriter writer) diff --git a/jode/jode/expr/InvokeOperator.java.in b/jode/jode/expr/InvokeOperator.java.in index f1fcb0c..d0d13c4 100644 --- a/jode/jode/expr/InvokeOperator.java.in +++ b/jode/jode/expr/InvokeOperator.java.in @@ -20,17 +20,17 @@ package jode.expr; import java.lang.reflect.Modifier; -import jode.Decompiler; import jode.decompiler.MethodAnalyzer; import jode.decompiler.MethodAnalyzer; import jode.decompiler.ClassAnalyzer; import jode.decompiler.TabbedPrintWriter; +import jode.decompiler.Options; import jode.decompiler.OuterValues; +import jode.decompiler.Scope; import jode.GlobalOptions; import jode.bytecode.*; import jode.jvm.*; import jode.type.*; -import jode.decompiler.Scope; import jode.util.SimpleMap; import java.lang.reflect.InvocationTargetException; @@ -39,6 +39,7 @@ import @COLLECTIONS@.Collections; import @COLLECTIONS@.Collection; import @COLLECTIONS@.Map; import @COLLECTIONS@.Iterator; +import @COLLECTIONS@.Set; public final class InvokeOperator extends Operator implements MatchableOperator { @@ -175,7 +176,7 @@ public final class InvokeOperator extends Operator public void checkAnonymousClasses() { if (methodFlag != CONSTRUCTOR - || (Decompiler.options & Decompiler.OPTION_ANON) == 0) + || (Options.options & Options.OPTION_ANON) == 0) return; InnerClassInfo outer = getOuterClassInfo(getClassInfo()); if (outer != null && (outer.outer == null || outer.name == null)) { @@ -251,8 +252,8 @@ public final class InvokeOperator extends Operator * inside the same base class as the caller class, null otherwise. */ public ClassAnalyzer getClassAnalyzer() { - if ((Decompiler.options & - (Decompiler.OPTION_ANON | Decompiler.OPTION_INNER)) == 0) + if ((Options.options & + (Options.OPTION_ANON | Options.OPTION_INNER)) == 0) return null; ClassInfo callee = getClassInfo(); @@ -261,7 +262,7 @@ public final class InvokeOperator extends Operator int nested = 0; InnerClassInfo[] outers = callee.getOuterClasses(); - if ((Decompiler.options & Decompiler.OPTION_INNER) != 0 + if ((Options.options & Options.OPTION_INNER) != 0 && outers != null) { /* If the callee class is an inner class we take its * (outermost) parent instead. This will assure that we @@ -288,12 +289,12 @@ public final class InvokeOperator extends Operator if (ana.getParent() == null) return null; if (ana.getParent() instanceof MethodAnalyzer - && (Decompiler.options & Decompiler.OPTION_ANON) != 0) + && (Options.options & Options.OPTION_ANON) != 0) ana = ((MethodAnalyzer) ana.getParent()) .getClassAnalyzer(); else if (ana.getParent() instanceof ClassAnalyzer - && (Decompiler.options - & Decompiler.OPTION_INNER) != 0) + && (Options.options + & Options.OPTION_INNER) != 0) ana = (ClassAnalyzer) ana.getParent(); else throw new jode.AssertError @@ -325,12 +326,12 @@ public final class InvokeOperator extends Operator if (ana.getParent() == null) break; if (ana.getParent() instanceof MethodAnalyzer - && (Decompiler.options & Decompiler.OPTION_ANON) != 0) + && (Options.options & Options.OPTION_ANON) != 0) ana = ((MethodAnalyzer) ana.getParent()) .getClassAnalyzer(); else if (ana.getParent() instanceof ClassAnalyzer - && (Decompiler.options - & Decompiler.OPTION_INNER) != 0) + && (Options.options + & Options.OPTION_INNER) != 0) ana = (ClassAnalyzer) ana.getParent(); else throw new jode.AssertError @@ -367,7 +368,7 @@ public final class InvokeOperator extends Operator } public boolean isConstant() { - if ((Decompiler.options & Decompiler.OPTION_ANON) == 0) + if ((Options.options & Options.OPTION_ANON) == 0) return super.isConstant(); ClassInfo clazz = getClassInfo(); @@ -545,7 +546,7 @@ public final class InvokeOperator extends Operator result.addOperand(right); result.addOperand(subExpressions[0].simplify()); } - else if ((Decompiler.options & Decompiler.OPTION_DECRYPT) != 0 + else if ((Options.options & Options.OPTION_DECRYPT) != 0 && isThis() && isStatic() && methodType.getParameterTypes().length == 1 && methodType.getParameterTypes()[0].equals(Type.tString) @@ -700,63 +701,68 @@ public final class InvokeOperator extends Operator InnerClassInfo outer = getOuterClassInfo(clazz); ClassAnalyzer clazzAna = methodAnalyzer.getClassAnalyzer(clazz); + if ((Options.options & Options.OPTION_ANON) != 0 + && outer != null && outer.outer == null && outer.name != null + && clazzAna != null + && clazzAna.getParent() == methodAnalyzer) { + + /* This is a named method scope class, declare it. + * But first declare all method scoped classes, + * that are used inside; order does matter. + */ + clazzAna.fillDeclarables(used); + used.add(clazzAna); + } + + if (!isConstructor() || isStatic()) { + super.fillDeclarables(used); + return; + } int arg = 1; int length = subExpressions.length; boolean jikesAnonymousInner = false; - if ((Decompiler.options & Decompiler.OPTION_ANON) != 0 + if ((Options.options & Options.OPTION_ANON) != 0 && clazzAna != null && outer != null && (outer.outer == null || outer.name == null)) { - - if (outer.name != null) { - if (clazzAna.getParent() == methodAnalyzer) { - /* This is a named method scope class, declare it. - * But first declare all method scoped classes, - * that are used inside; order does matter. - */ - clazzAna.fillDeclarables(used); - used.add(clazzAna); - } - } - if (isConstructor()) { - OuterValues ov = clazzAna.getOuterValues(); - arg += ov.getCount(); - jikesAnonymousInner = ov.isJikesAnonymousInner(); - for (int i=1; i< arg; i++) { - Expression expr = subExpressions[i]; - if (expr instanceof CheckNullOperator) { - CheckNullOperator cno = (CheckNullOperator) expr; + OuterValues ov = clazzAna.getOuterValues(); + arg += ov.getCount(); + jikesAnonymousInner = ov.isJikesAnonymousInner(); + + for (int i=1; i< arg; i++) { + Expression expr = subExpressions[i]; + if (expr instanceof CheckNullOperator) { + CheckNullOperator cno = (CheckNullOperator) expr; expr = cno.subExpressions[0]; - } - expr.fillDeclarables(used); } - - if (outer.name == null) { - /* This is an anonymous class */ - ClassInfo superClazz = clazz.getSuperclass(); - ClassInfo[] interfaces = clazz.getInterfaces(); - if (interfaces.length == 1 - && (superClazz == null - || superClazz == ClassInfo.javaLangObject)) { - clazz = interfaces[0]; - } else { - clazz = (superClazz != null - ? superClazz : ClassInfo.javaLangObject); - } - outer = getOuterClassInfo(clazz); - + expr.fillDeclarables(used); + } + + if (outer.name == null) { + /* This is an anonymous class */ + ClassInfo superClazz = clazz.getSuperclass(); + ClassInfo[] interfaces = clazz.getInterfaces(); + if (interfaces.length == 1 + && (superClazz == null + || superClazz == ClassInfo.javaLangObject)) { + clazz = interfaces[0]; + } else { + clazz = (superClazz != null + ? superClazz : ClassInfo.javaLangObject); } + outer = getOuterClassInfo(clazz); + } } - if (isConstructor() - && (Decompiler.options & Decompiler.OPTION_INNER) != 0 + + if ((Options.options & Options.OPTION_INNER) != 0 && outer != null && outer.outer != null && outer.name != null && !Modifier.isStatic(outer.modifiers)) { - + Expression outerExpr = jikesAnonymousInner - ? subExpressions[--length] - : subExpressions[arg++]; + ? subExpressions[--length] + : subExpressions[arg++]; if (outerExpr instanceof CheckNullOperator) { CheckNullOperator cno = (CheckNullOperator) outerExpr; outerExpr = cno.subExpressions[0]; @@ -767,6 +773,27 @@ public final class InvokeOperator extends Operator subExpressions[i].fillDeclarables(used); } + /** + * We add the named method scoped classes to the declarables, and + * only fillDeclarables on the parameters we will print. + */ + public void makeDeclaration(Set done) { + super.makeDeclaration(done); + + if (isConstructor() && !isStatic() + && (Options.options & Options.OPTION_ANON) != 0) { + ClassInfo clazz = getClassInfo(); + InnerClassInfo outer = getOuterClassInfo(clazz); + ClassAnalyzer clazzAna = methodAnalyzer.getClassAnalyzer(clazz); + if (clazzAna != null && outer != null && outer.name == null) { + + /* call makeDeclaration on the anonymous class, since + * _we_ will declare the anonymous class. */ + clazzAna.makeDeclaration(done); + } + } + } + /* Invokes never equals: they may return different values even if * they have the same parameters. */ @@ -798,8 +825,8 @@ public final class InvokeOperator extends Operator if (outer != null && outer.name == null) anonymousNew = true; clazzAna = methodAnalyzer.getClassAnalyzer(clazz); - if ((~Decompiler.options & - (Decompiler.OPTION_ANON | Decompiler.OPTION_CONTRAFO)) == 0 + if ((~Options.options & + (Options.OPTION_ANON | Options.OPTION_CONTRAFO)) == 0 && clazzAna != null && outer != null && (outer.outer == null || outer.name == null)) { @@ -846,9 +873,9 @@ public final class InvokeOperator extends Operator */ if (outer != null && outer.outer != null && outer.name != null && !Modifier.isStatic(outer.modifiers) - && (~Decompiler.options & - (Decompiler.OPTION_INNER - | Decompiler.OPTION_CONTRAFO)) == 0) { + && (~Options.options & + (Options.OPTION_INNER + | Options.OPTION_CONTRAFO)) == 0) { Expression outerExpr = jikesAnonymousInner ? subExpressions[--length] @@ -914,10 +941,7 @@ public final class InvokeOperator extends Operator break; } case SPECIAL: - if (subExpressions[0] instanceof ThisOperator - && (((ThisOperator)subExpressions[0]).getClassInfo() - == methodAnalyzer.getClazz())) { - + if (isSuperOrThis()) { if (!isThis()) { /* We don't have to check if this is the real super * class, as long as ACC_SUPER is set. diff --git a/jode/jode/expr/Operator.java.in b/jode/jode/expr/Operator.java.in index de19bb9..3d77e90 100644 --- a/jode/jode/expr/Operator.java.in +++ b/jode/jode/expr/Operator.java.in @@ -23,6 +23,7 @@ import jode.GlobalOptions; import jode.decompiler.TabbedPrintWriter; import @COLLECTIONS@.Collection; +import @COLLECTIONS@.Set; public abstract class Operator extends Expression { /* Don't reorder these constants unless you know what you are doing! */ @@ -172,13 +173,16 @@ public abstract class Operator extends Expression { } public void fillDeclarables(Collection used) { - if (this instanceof LocalVarOperator) { - used.add(((LocalVarOperator) this).getLocalInfo()); - } for (int i=0; i< subExpressions.length; i++) subExpressions[i].fillDeclarables(used); } + public void makeDeclaration(Set done) { + for (int i=0; i< subExpressions.length; i++) + subExpressions[i].makeDeclaration(done); + } + + /** * Checks if the value of the given expression can change, due to * side effects in this expression. If this returns false, the diff --git a/jode/jode/expr/StoreInstruction.java b/jode/jode/expr/StoreInstruction.java index 5531f06..5f5a39d 100644 --- a/jode/jode/expr/StoreInstruction.java +++ b/jode/jode/expr/StoreInstruction.java @@ -89,8 +89,9 @@ public class StoreInstruction extends Operator ConstOperator one = (ConstOperator) subExpressions[1]; if ((getOperatorIndex() == OPASSIGN_OP+ADD_OP || - getOperatorIndex() == OPASSIGN_OP+SUB_OP) && - ((Number)one.getValue()).doubleValue() == 1.0) { + getOperatorIndex() == OPASSIGN_OP+SUB_OP) + && one.getValue() instanceof Number + && ((Number)one.getValue()).doubleValue() == 1.0) { int op = (getOperatorIndex() == OPASSIGN_OP+ADD_OP) ? INC_OP : DEC_OP; diff --git a/jode/jode/flow/FlowBlock.java.in b/jode/jode/flow/FlowBlock.java.in index b60b777..c42983b 100644 --- a/jode/jode/flow/FlowBlock.java.in +++ b/jode/jode/flow/FlowBlock.java.in @@ -1612,23 +1612,13 @@ public class FlowBlock { /** * Make declarations. It will determine, where in each block the - * + * variables and method scoped classes must be declared. */ - public void makeDeclaration() { + public void makeDeclaration(Set done) { block.propagateUsage(); - Set done = new SimpleSet(); - done.addAll(in); block.makeDeclaration(done); if (nextByAddr != null) - nextByAddr.makeDeclaration(); - } - - /** - * Make declarations. It will determine, where in each block the - * - */ - public void makeDeclaration(LocalInfo[] param) { - makeDeclaration(); + nextByAddr.makeDeclaration(done); } /** diff --git a/jode/jode/flow/IfThenElseBlock.java.in b/jode/jode/flow/IfThenElseBlock.java.in index 96a6b6c..e91260a 100644 --- a/jode/jode/flow/IfThenElseBlock.java.in +++ b/jode/jode/flow/IfThenElseBlock.java.in @@ -140,6 +140,21 @@ public class IfThenElseBlock extends StructuredBlock { return used; } + /** + * Make the declarations, i.e. initialize the declare variable + * to correct values. This will declare every variable that + * is marked as used, but not done.
+ * + * This will now also combine locals, that use the same slot, have + * compatible types and are declared in the same block.
+ * + * @param done The set of the already declare variables. + */ + public void makeDeclaration(Set done) { + cond.makeDeclaration(done); + super.makeDeclaration(done); + } + /** * Print the source code for this structured block. This may be * called only once, because it remembers which local variables diff --git a/jode/jode/flow/InstructionContainer.java.in b/jode/jode/flow/InstructionContainer.java.in index 472afac..1925843 100644 --- a/jode/jode/flow/InstructionContainer.java.in +++ b/jode/jode/flow/InstructionContainer.java.in @@ -44,6 +44,22 @@ public abstract class InstructionContainer extends StructuredBlock { setJump(jump); } + /** + * Make the declarations, i.e. initialize the declare variable + * to correct values. This will declare every variable that + * is marked as used, but not done.
+ * + * This will now also combine locals, that use the same slot, have + * compatible types and are declared in the same block.
+ * + * @param done The set of the already declare variables. + */ + public void makeDeclaration(Set done) { + if (instr != null) + instr.makeDeclaration(done); + super.makeDeclaration(done); + } + /** * This method should remove local variables that are only written * and read one time directly after another.
diff --git a/jode/jode/flow/LoopBlock.java.in b/jode/jode/flow/LoopBlock.java.in index 29d1340..c602bd3 100644 --- a/jode/jode/flow/LoopBlock.java.in +++ b/jode/jode/flow/LoopBlock.java.in @@ -199,6 +199,28 @@ public class LoopBlock extends StructuredBlock implements BreakableBlock { this.type = type; } + /** + * Replaces the given sub block with a new block. + * @param oldBlock the old sub block. + * @param newBlock the new sub block. + * @return false, if oldBlock wasn't a direct sub block. + */ + public boolean replaceSubBlock(StructuredBlock oldBlock, + StructuredBlock newBlock) { + if (bodyBlock == oldBlock) + bodyBlock = newBlock; + else + return false; + return true; + } + + /** + * Returns all sub block of this structured block. + */ + public StructuredBlock[] getSubBlocks() { + return new StructuredBlock[] { bodyBlock }; + } + /** * Remove all variables from set, that we can declare inside the * loop-block. This is the initializer for for-blocks. @@ -225,28 +247,6 @@ public class LoopBlock extends StructuredBlock implements BreakableBlock { return used; } - /** - * Replaces the given sub block with a new block. - * @param oldBlock the old sub block. - * @param newBlock the new sub block. - * @return false, if oldBlock wasn't a direct sub block. - */ - public boolean replaceSubBlock(StructuredBlock oldBlock, - StructuredBlock newBlock) { - if (bodyBlock == oldBlock) - bodyBlock = newBlock; - else - return false; - return true; - } - - /** - * Returns all sub block of this structured block. - */ - public StructuredBlock[] getSubBlocks() { - return new StructuredBlock[] { bodyBlock }; - } - /** * Check if this is an local store instruction to a not yet declared * variable. In that case mark this as declaration and return the @@ -278,6 +278,12 @@ public class LoopBlock extends StructuredBlock implements BreakableBlock { * @param done The set of the already declare variables. */ public void makeDeclaration(Set done) { + if (type == FOR) { + if (initInstr != null) + initInstr.makeDeclaration(done); + incrInstr.makeDeclaration(done); + } + cond.makeDeclaration(done); super.makeDeclaration(done); if (type == FOR && initInstr != null) checkDeclaration(declare); diff --git a/jode/jode/flow/SpecialBlock.java b/jode/jode/flow/SpecialBlock.java index 67e2c3e..fc7916b 100644 --- a/jode/jode/flow/SpecialBlock.java +++ b/jode/jode/flow/SpecialBlock.java @@ -19,7 +19,6 @@ package jode.flow; import jode.decompiler.TabbedPrintWriter; -import jode.Decompiler; import jode.expr.*; /** diff --git a/jode/jode/flow/StructuredBlock.java.in b/jode/jode/flow/StructuredBlock.java.in index 8d92da9..c46e1ea 100644 --- a/jode/jode/flow/StructuredBlock.java.in +++ b/jode/jode/flow/StructuredBlock.java.in @@ -23,6 +23,7 @@ import jode.GlobalOptions; import jode.decompiler.TabbedPrintWriter; import jode.decompiler.LocalInfo; import jode.decompiler.Declarable; +import jode.decompiler.ClassAnalyzer; import jode.util.SimpleSet; import @COLLECTIONS@.Collections; @@ -464,31 +465,27 @@ public abstract class StructuredBlock { if (!(previous instanceof LocalInfo)) continue; LocalInfo prevLocal = (LocalInfo) previous; - if (prevLocal.getSlot() == local.getSlot()) { - - /* XXX - I have to think about this... - * there may be a case where this leads to type errors. - * TODO: Give a formal proof ;-) - * One bad thing that may happen is that the name - * of prevLocal (it has already a name) doesn't match - * the intersected type. - * - * We don't want to merge variables, whose names - * are not generated by us and differ. And we - * don't want to merge special locals that have a - * constant expression, e.g. this. - */ - if (prevLocal.getType().isOfType(local.getType()) - && (prevLocal.isNameGenerated() - || local.isNameGenerated() - || localName.equals(prevLocal.getName())) - && !prevLocal.isFinal() - && !local.isFinal() - && prevLocal.getExpression() == null - && local.getExpression() == null) { - local.combineWith(prevLocal); - continue next_used; - } + /* We only merge locals living in the same + * method and having the same slot. + * + * We don't want to merge variables, whose names + * are not generated by us and differ. And we + * don't want to merge special locals that have a + * constant expression, e.g. this. + */ + if (prevLocal.getMethodAnalyzer() + == local.getMethodAnalyzer() + && prevLocal.getSlot() == local.getSlot() + && prevLocal.getType().isOfType(local.getType()) + && (prevLocal.isNameGenerated() + || local.isNameGenerated() + || localName.equals(prevLocal.getName())) + && !prevLocal.isFinal() + && !local.isFinal() + && prevLocal.getExpression() == null + && local.getExpression() == null) { + local.combineWith(prevLocal); + continue next_used; } } } @@ -500,11 +497,14 @@ public abstract class StructuredBlock { if (declarable.getName().equals(previous.getName())) { /* A name conflict happened. */ declarable.makeNameUnique(); + break; } } } done.add(declarable); declare.add(declarable); + if (declare instanceof ClassAnalyzer) + ((ClassAnalyzer) declare).makeDeclaration(done); } StructuredBlock[] subs = getSubBlocks(); for (int i=0; i