|
|
@ -20,17 +20,17 @@ |
|
|
|
package jode.expr; |
|
|
|
package jode.expr; |
|
|
|
import java.lang.reflect.Modifier; |
|
|
|
import java.lang.reflect.Modifier; |
|
|
|
|
|
|
|
|
|
|
|
import jode.Decompiler; |
|
|
|
|
|
|
|
import jode.decompiler.MethodAnalyzer; |
|
|
|
import jode.decompiler.MethodAnalyzer; |
|
|
|
import jode.decompiler.MethodAnalyzer; |
|
|
|
import jode.decompiler.MethodAnalyzer; |
|
|
|
import jode.decompiler.ClassAnalyzer; |
|
|
|
import jode.decompiler.ClassAnalyzer; |
|
|
|
import jode.decompiler.TabbedPrintWriter; |
|
|
|
import jode.decompiler.TabbedPrintWriter; |
|
|
|
|
|
|
|
import jode.decompiler.Options; |
|
|
|
import jode.decompiler.OuterValues; |
|
|
|
import jode.decompiler.OuterValues; |
|
|
|
|
|
|
|
import jode.decompiler.Scope; |
|
|
|
import jode.GlobalOptions; |
|
|
|
import jode.GlobalOptions; |
|
|
|
import jode.bytecode.*; |
|
|
|
import jode.bytecode.*; |
|
|
|
import jode.jvm.*; |
|
|
|
import jode.jvm.*; |
|
|
|
import jode.type.*; |
|
|
|
import jode.type.*; |
|
|
|
import jode.decompiler.Scope; |
|
|
|
|
|
|
|
import jode.util.SimpleMap; |
|
|
|
import jode.util.SimpleMap; |
|
|
|
|
|
|
|
|
|
|
|
import java.lang.reflect.InvocationTargetException; |
|
|
|
import java.lang.reflect.InvocationTargetException; |
|
|
@ -39,6 +39,7 @@ import @COLLECTIONS@.Collections; |
|
|
|
import @COLLECTIONS@.Collection; |
|
|
|
import @COLLECTIONS@.Collection; |
|
|
|
import @COLLECTIONS@.Map; |
|
|
|
import @COLLECTIONS@.Map; |
|
|
|
import @COLLECTIONS@.Iterator; |
|
|
|
import @COLLECTIONS@.Iterator; |
|
|
|
|
|
|
|
import @COLLECTIONS@.Set; |
|
|
|
|
|
|
|
|
|
|
|
public final class InvokeOperator extends Operator |
|
|
|
public final class InvokeOperator extends Operator |
|
|
|
implements MatchableOperator { |
|
|
|
implements MatchableOperator { |
|
|
@ -175,7 +176,7 @@ public final class InvokeOperator extends Operator |
|
|
|
|
|
|
|
|
|
|
|
public void checkAnonymousClasses() { |
|
|
|
public void checkAnonymousClasses() { |
|
|
|
if (methodFlag != CONSTRUCTOR |
|
|
|
if (methodFlag != CONSTRUCTOR |
|
|
|
|| (Decompiler.options & Decompiler.OPTION_ANON) == 0) |
|
|
|
|| (Options.options & Options.OPTION_ANON) == 0) |
|
|
|
return; |
|
|
|
return; |
|
|
|
InnerClassInfo outer = getOuterClassInfo(getClassInfo()); |
|
|
|
InnerClassInfo outer = getOuterClassInfo(getClassInfo()); |
|
|
|
if (outer != null && (outer.outer == null || outer.name == null)) { |
|
|
|
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. |
|
|
|
* inside the same base class as the caller class, null otherwise. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public ClassAnalyzer getClassAnalyzer() { |
|
|
|
public ClassAnalyzer getClassAnalyzer() { |
|
|
|
if ((Decompiler.options & |
|
|
|
if ((Options.options & |
|
|
|
(Decompiler.OPTION_ANON | Decompiler.OPTION_INNER)) == 0) |
|
|
|
(Options.OPTION_ANON | Options.OPTION_INNER)) == 0) |
|
|
|
return null; |
|
|
|
return null; |
|
|
|
|
|
|
|
|
|
|
|
ClassInfo callee = getClassInfo(); |
|
|
|
ClassInfo callee = getClassInfo(); |
|
|
@ -261,7 +262,7 @@ public final class InvokeOperator extends Operator |
|
|
|
|
|
|
|
|
|
|
|
int nested = 0; |
|
|
|
int nested = 0; |
|
|
|
InnerClassInfo[] outers = callee.getOuterClasses(); |
|
|
|
InnerClassInfo[] outers = callee.getOuterClasses(); |
|
|
|
if ((Decompiler.options & Decompiler.OPTION_INNER) != 0 |
|
|
|
if ((Options.options & Options.OPTION_INNER) != 0 |
|
|
|
&& outers != null) { |
|
|
|
&& outers != null) { |
|
|
|
/* If the callee class is an inner class we take its |
|
|
|
/* If the callee class is an inner class we take its |
|
|
|
* (outermost) parent instead. This will assure that we |
|
|
|
* (outermost) parent instead. This will assure that we |
|
|
@ -288,12 +289,12 @@ public final class InvokeOperator extends Operator |
|
|
|
if (ana.getParent() == null) |
|
|
|
if (ana.getParent() == null) |
|
|
|
return null; |
|
|
|
return null; |
|
|
|
if (ana.getParent() instanceof MethodAnalyzer |
|
|
|
if (ana.getParent() instanceof MethodAnalyzer |
|
|
|
&& (Decompiler.options & Decompiler.OPTION_ANON) != 0) |
|
|
|
&& (Options.options & Options.OPTION_ANON) != 0) |
|
|
|
ana = ((MethodAnalyzer) ana.getParent()) |
|
|
|
ana = ((MethodAnalyzer) ana.getParent()) |
|
|
|
.getClassAnalyzer(); |
|
|
|
.getClassAnalyzer(); |
|
|
|
else if (ana.getParent() instanceof ClassAnalyzer |
|
|
|
else if (ana.getParent() instanceof ClassAnalyzer |
|
|
|
&& (Decompiler.options |
|
|
|
&& (Options.options |
|
|
|
& Decompiler.OPTION_INNER) != 0) |
|
|
|
& Options.OPTION_INNER) != 0) |
|
|
|
ana = (ClassAnalyzer) ana.getParent(); |
|
|
|
ana = (ClassAnalyzer) ana.getParent(); |
|
|
|
else |
|
|
|
else |
|
|
|
throw new jode.AssertError |
|
|
|
throw new jode.AssertError |
|
|
@ -325,12 +326,12 @@ public final class InvokeOperator extends Operator |
|
|
|
if (ana.getParent() == null) |
|
|
|
if (ana.getParent() == null) |
|
|
|
break; |
|
|
|
break; |
|
|
|
if (ana.getParent() instanceof MethodAnalyzer |
|
|
|
if (ana.getParent() instanceof MethodAnalyzer |
|
|
|
&& (Decompiler.options & Decompiler.OPTION_ANON) != 0) |
|
|
|
&& (Options.options & Options.OPTION_ANON) != 0) |
|
|
|
ana = ((MethodAnalyzer) ana.getParent()) |
|
|
|
ana = ((MethodAnalyzer) ana.getParent()) |
|
|
|
.getClassAnalyzer(); |
|
|
|
.getClassAnalyzer(); |
|
|
|
else if (ana.getParent() instanceof ClassAnalyzer |
|
|
|
else if (ana.getParent() instanceof ClassAnalyzer |
|
|
|
&& (Decompiler.options |
|
|
|
&& (Options.options |
|
|
|
& Decompiler.OPTION_INNER) != 0) |
|
|
|
& Options.OPTION_INNER) != 0) |
|
|
|
ana = (ClassAnalyzer) ana.getParent(); |
|
|
|
ana = (ClassAnalyzer) ana.getParent(); |
|
|
|
else |
|
|
|
else |
|
|
|
throw new jode.AssertError |
|
|
|
throw new jode.AssertError |
|
|
@ -367,7 +368,7 @@ public final class InvokeOperator extends Operator |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public boolean isConstant() { |
|
|
|
public boolean isConstant() { |
|
|
|
if ((Decompiler.options & Decompiler.OPTION_ANON) == 0) |
|
|
|
if ((Options.options & Options.OPTION_ANON) == 0) |
|
|
|
return super.isConstant(); |
|
|
|
return super.isConstant(); |
|
|
|
|
|
|
|
|
|
|
|
ClassInfo clazz = getClassInfo(); |
|
|
|
ClassInfo clazz = getClassInfo(); |
|
|
@ -545,7 +546,7 @@ public final class InvokeOperator extends Operator |
|
|
|
result.addOperand(right); |
|
|
|
result.addOperand(right); |
|
|
|
result.addOperand(subExpressions[0].simplify()); |
|
|
|
result.addOperand(subExpressions[0].simplify()); |
|
|
|
} |
|
|
|
} |
|
|
|
else if ((Decompiler.options & Decompiler.OPTION_DECRYPT) != 0 |
|
|
|
else if ((Options.options & Options.OPTION_DECRYPT) != 0 |
|
|
|
&& isThis() && isStatic() |
|
|
|
&& isThis() && isStatic() |
|
|
|
&& methodType.getParameterTypes().length == 1 |
|
|
|
&& methodType.getParameterTypes().length == 1 |
|
|
|
&& methodType.getParameterTypes()[0].equals(Type.tString) |
|
|
|
&& methodType.getParameterTypes()[0].equals(Type.tString) |
|
|
@ -700,63 +701,68 @@ public final class InvokeOperator extends Operator |
|
|
|
InnerClassInfo outer = getOuterClassInfo(clazz); |
|
|
|
InnerClassInfo outer = getOuterClassInfo(clazz); |
|
|
|
ClassAnalyzer clazzAna = methodAnalyzer.getClassAnalyzer(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 arg = 1; |
|
|
|
int length = subExpressions.length; |
|
|
|
int length = subExpressions.length; |
|
|
|
boolean jikesAnonymousInner = false; |
|
|
|
boolean jikesAnonymousInner = false; |
|
|
|
|
|
|
|
|
|
|
|
if ((Decompiler.options & Decompiler.OPTION_ANON) != 0 |
|
|
|
if ((Options.options & Options.OPTION_ANON) != 0 |
|
|
|
&& clazzAna != null |
|
|
|
&& clazzAna != null |
|
|
|
&& outer != null && (outer.outer == null || outer.name == 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++) { |
|
|
|
OuterValues ov = clazzAna.getOuterValues(); |
|
|
|
Expression expr = subExpressions[i]; |
|
|
|
arg += ov.getCount(); |
|
|
|
if (expr instanceof CheckNullOperator) { |
|
|
|
jikesAnonymousInner = ov.isJikesAnonymousInner(); |
|
|
|
CheckNullOperator cno = (CheckNullOperator) expr; |
|
|
|
|
|
|
|
|
|
|
|
for (int i=1; i< arg; i++) { |
|
|
|
|
|
|
|
Expression expr = subExpressions[i]; |
|
|
|
|
|
|
|
if (expr instanceof CheckNullOperator) { |
|
|
|
|
|
|
|
CheckNullOperator cno = (CheckNullOperator) expr; |
|
|
|
expr = cno.subExpressions[0]; |
|
|
|
expr = cno.subExpressions[0]; |
|
|
|
} |
|
|
|
|
|
|
|
expr.fillDeclarables(used); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
expr.fillDeclarables(used); |
|
|
|
if (outer.name == null) { |
|
|
|
} |
|
|
|
/* This is an anonymous class */ |
|
|
|
|
|
|
|
ClassInfo superClazz = clazz.getSuperclass(); |
|
|
|
if (outer.name == null) { |
|
|
|
ClassInfo[] interfaces = clazz.getInterfaces(); |
|
|
|
/* This is an anonymous class */ |
|
|
|
if (interfaces.length == 1 |
|
|
|
ClassInfo superClazz = clazz.getSuperclass(); |
|
|
|
&& (superClazz == null |
|
|
|
ClassInfo[] interfaces = clazz.getInterfaces(); |
|
|
|
|| superClazz == ClassInfo.javaLangObject)) { |
|
|
|
if (interfaces.length == 1 |
|
|
|
clazz = interfaces[0]; |
|
|
|
&& (superClazz == null |
|
|
|
} else { |
|
|
|
|| superClazz == ClassInfo.javaLangObject)) { |
|
|
|
clazz = (superClazz != null |
|
|
|
clazz = interfaces[0]; |
|
|
|
? superClazz : ClassInfo.javaLangObject); |
|
|
|
} else { |
|
|
|
} |
|
|
|
clazz = (superClazz != null |
|
|
|
outer = getOuterClassInfo(clazz); |
|
|
|
? 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 |
|
|
|
&& outer != null && outer.outer != null && outer.name != null |
|
|
|
&& !Modifier.isStatic(outer.modifiers)) { |
|
|
|
&& !Modifier.isStatic(outer.modifiers)) { |
|
|
|
|
|
|
|
|
|
|
|
Expression outerExpr = jikesAnonymousInner |
|
|
|
Expression outerExpr = jikesAnonymousInner |
|
|
|
? subExpressions[--length] |
|
|
|
? subExpressions[--length] |
|
|
|
: subExpressions[arg++]; |
|
|
|
: subExpressions[arg++]; |
|
|
|
if (outerExpr instanceof CheckNullOperator) { |
|
|
|
if (outerExpr instanceof CheckNullOperator) { |
|
|
|
CheckNullOperator cno = (CheckNullOperator) outerExpr; |
|
|
|
CheckNullOperator cno = (CheckNullOperator) outerExpr; |
|
|
|
outerExpr = cno.subExpressions[0]; |
|
|
|
outerExpr = cno.subExpressions[0]; |
|
|
@ -767,6 +773,27 @@ public final class InvokeOperator extends Operator |
|
|
|
subExpressions[i].fillDeclarables(used); |
|
|
|
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 |
|
|
|
/* Invokes never equals: they may return different values even if |
|
|
|
* they have the same parameters. |
|
|
|
* they have the same parameters. |
|
|
|
*/ |
|
|
|
*/ |
|
|
@ -798,8 +825,8 @@ public final class InvokeOperator extends Operator |
|
|
|
if (outer != null && outer.name == null) |
|
|
|
if (outer != null && outer.name == null) |
|
|
|
anonymousNew = true; |
|
|
|
anonymousNew = true; |
|
|
|
clazzAna = methodAnalyzer.getClassAnalyzer(clazz); |
|
|
|
clazzAna = methodAnalyzer.getClassAnalyzer(clazz); |
|
|
|
if ((~Decompiler.options & |
|
|
|
if ((~Options.options & |
|
|
|
(Decompiler.OPTION_ANON | Decompiler.OPTION_CONTRAFO)) == 0 |
|
|
|
(Options.OPTION_ANON | Options.OPTION_CONTRAFO)) == 0 |
|
|
|
&& clazzAna != null |
|
|
|
&& clazzAna != null |
|
|
|
&& outer != null |
|
|
|
&& outer != null |
|
|
|
&& (outer.outer == null || outer.name == 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 |
|
|
|
if (outer != null && outer.outer != null && outer.name != null |
|
|
|
&& !Modifier.isStatic(outer.modifiers) |
|
|
|
&& !Modifier.isStatic(outer.modifiers) |
|
|
|
&& (~Decompiler.options & |
|
|
|
&& (~Options.options & |
|
|
|
(Decompiler.OPTION_INNER |
|
|
|
(Options.OPTION_INNER |
|
|
|
| Decompiler.OPTION_CONTRAFO)) == 0) { |
|
|
|
| Options.OPTION_CONTRAFO)) == 0) { |
|
|
|
|
|
|
|
|
|
|
|
Expression outerExpr = jikesAnonymousInner |
|
|
|
Expression outerExpr = jikesAnonymousInner |
|
|
|
? subExpressions[--length] |
|
|
|
? subExpressions[--length] |
|
|
@ -914,10 +941,7 @@ public final class InvokeOperator extends Operator |
|
|
|
break; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
case SPECIAL: |
|
|
|
case SPECIAL: |
|
|
|
if (subExpressions[0] instanceof ThisOperator |
|
|
|
if (isSuperOrThis()) { |
|
|
|
&& (((ThisOperator)subExpressions[0]).getClassInfo() |
|
|
|
|
|
|
|
== methodAnalyzer.getClazz())) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!isThis()) { |
|
|
|
if (!isThis()) { |
|
|
|
/* We don't have to check if this is the real super |
|
|
|
/* We don't have to check if this is the real super |
|
|
|
* class, as long as ACC_SUPER is set. |
|
|
|
* class, as long as ACC_SUPER is set. |
|
|
|