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