|
|
@ -18,9 +18,12 @@ |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
package jode.decompiler; |
|
|
|
package jode.decompiler; |
|
|
|
|
|
|
|
import jode.bytecode.ClassInfo; |
|
|
|
import jode.bytecode.MethodInfo; |
|
|
|
import jode.bytecode.MethodInfo; |
|
|
|
import jode.jvm.SyntheticAnalyzer; |
|
|
|
import jode.jvm.SyntheticAnalyzer; |
|
|
|
import jode.type.*; |
|
|
|
import jode.type.*; |
|
|
|
|
|
|
|
import jode.expr.Expression; |
|
|
|
|
|
|
|
import jode.expr.ThisOperator; |
|
|
|
import jode.AssertError; |
|
|
|
import jode.AssertError; |
|
|
|
import jode.Decompiler; |
|
|
|
import jode.Decompiler; |
|
|
|
import jode.GlobalOptions; |
|
|
|
import jode.GlobalOptions; |
|
|
@ -41,7 +44,10 @@ public class MethodAnalyzer implements Analyzer { |
|
|
|
Type[] exceptions; |
|
|
|
Type[] exceptions; |
|
|
|
|
|
|
|
|
|
|
|
SyntheticAnalyzer synth; |
|
|
|
SyntheticAnalyzer synth; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
boolean isJikesConstructor; |
|
|
|
|
|
|
|
boolean isImplicitAnonymousConstructor; |
|
|
|
|
|
|
|
|
|
|
|
public MethodAnalyzer(ClassAnalyzer cla, MethodInfo minfo, |
|
|
|
public MethodAnalyzer(ClassAnalyzer cla, MethodInfo minfo, |
|
|
|
ImportHandler imports) { |
|
|
|
ImportHandler imports) { |
|
|
|
this.classAnalyzer = cla; |
|
|
|
this.classAnalyzer = cla; |
|
|
@ -95,6 +101,14 @@ public class MethodAnalyzer implements Analyzer { |
|
|
|
return minfo.isSynthetic(); |
|
|
|
return minfo.isSynthetic(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public final void setJikesConstructor(boolean value) { |
|
|
|
|
|
|
|
isJikesConstructor = value; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public final void setAnonymousConstructor(boolean value) { |
|
|
|
|
|
|
|
isImplicitAnonymousConstructor = value; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public final SyntheticAnalyzer getSynthetic() { |
|
|
|
public final SyntheticAnalyzer getSynthetic() { |
|
|
|
return synth; |
|
|
|
return synth; |
|
|
|
} |
|
|
|
} |
|
|
@ -111,19 +125,19 @@ public class MethodAnalyzer implements Analyzer { |
|
|
|
|
|
|
|
|
|
|
|
int offset = 0; |
|
|
|
int offset = 0; |
|
|
|
if (!isStatic()) { |
|
|
|
if (!isStatic()) { |
|
|
|
LocalInfo clazz = code.getParamInfo(0); |
|
|
|
ClassInfo classInfo = classAnalyzer.getClazz(); |
|
|
|
clazz.setType(Type.tClass(classAnalyzer.getClazz())); |
|
|
|
LocalInfo thisLocal = code.getParamInfo(0); |
|
|
|
clazz.setName("this"); |
|
|
|
thisLocal.setExpression(new ThisOperator(classInfo, true)); |
|
|
|
offset++; |
|
|
|
offset++; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (isConstructor() |
|
|
|
if (isConstructor() && !isStatic() |
|
|
|
&& classAnalyzer.getParent() instanceof ClassAnalyzer |
|
|
|
&& classAnalyzer.outerValues != null) { |
|
|
|
&& !classAnalyzer.isStatic()) { |
|
|
|
Expression[] outerValues = classAnalyzer.outerValues; |
|
|
|
ClassAnalyzer parent = (ClassAnalyzer) classAnalyzer.getParent(); |
|
|
|
for (int i=0; i< outerValues.length; i++) { |
|
|
|
LocalInfo clazz = code.getParamInfo(1); |
|
|
|
LocalInfo local = code.getParamInfo(offset+i); |
|
|
|
clazz.setType(Type.tClass(parent.getClazz())); |
|
|
|
local.setExpression(outerValues[i]); |
|
|
|
clazz.setName("this$-1"); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Type[] paramTypes = methodType.getParameterTypes(); |
|
|
|
Type[] paramTypes = methodType.getParameterTypes(); |
|
|
@ -146,31 +160,85 @@ public class MethodAnalyzer implements Analyzer { |
|
|
|
GlobalOptions.err.println(""); |
|
|
|
GlobalOptions.err.println(""); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public void dumpSource(TabbedPrintWriter writer) |
|
|
|
public LocalInfo getParamInfo(int i) { |
|
|
|
throws IOException |
|
|
|
if (code == null) |
|
|
|
|
|
|
|
return null; |
|
|
|
|
|
|
|
return code.getParamInfo(i); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void analyzeAnonymousClasses() |
|
|
|
|
|
|
|
throws ClassFormatError |
|
|
|
{ |
|
|
|
{ |
|
|
|
|
|
|
|
if (code == null) |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
code.analyzeAnonymousClasses(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public boolean skipWriting() { |
|
|
|
if (synth != null) { |
|
|
|
if (synth != null) { |
|
|
|
// We don't need this class anymore (hopefully?)
|
|
|
|
// We don't need this class anymore (hopefully?)
|
|
|
|
if (synth.getKind() == synth.GETCLASS) |
|
|
|
if (synth.getKind() == synth.GETCLASS) |
|
|
|
return; |
|
|
|
return true; |
|
|
|
if (synth.getKind() >= synth.ACCESSGETFIELD |
|
|
|
if (synth.getKind() >= synth.ACCESSGETFIELD |
|
|
|
&& synth.getKind() <= synth.ACCESSSTATICMETHOD |
|
|
|
&& synth.getKind() <= synth.ACCESSSTATICMETHOD |
|
|
|
&& (Decompiler.options & Decompiler.OPTION_INNER) != 0 |
|
|
|
&& (Decompiler.options & Decompiler.OPTION_INNER) != 0 |
|
|
|
&& (Decompiler.options & Decompiler.OPTION_ANON) != 0) |
|
|
|
&& (Decompiler.options & Decompiler.OPTION_ANON) != 0) |
|
|
|
return; |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (isConstructor && classAnalyzer.constructors.length == 1 |
|
|
|
if (isConstructor && isJikesConstructor) { |
|
|
|
&& (methodType.getParameterTypes().length == 0 |
|
|
|
// This is the first empty part of a jikes constructor
|
|
|
|
|| (methodType.getParameterTypes().length == 1 |
|
|
|
return true; |
|
|
|
&& classAnalyzer.parent instanceof ClassAnalyzer)) |
|
|
|
} |
|
|
|
&& getMethodHeader() != null |
|
|
|
|
|
|
|
&& getMethodHeader().getBlock() instanceof jode.flow.EmptyBlock |
|
|
|
boolean declareAsConstructor = isConstructor; |
|
|
|
&& getMethodHeader().hasNoJumps()) |
|
|
|
int skipParams = 0; |
|
|
|
|
|
|
|
if (isConstructor() && !isStatic() |
|
|
|
|
|
|
|
&& classAnalyzer.outerValues != null) |
|
|
|
|
|
|
|
skipParams = classAnalyzer.outerValues.length; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (isJikesConstructor) { |
|
|
|
|
|
|
|
// This is the real part of a jikes constructor
|
|
|
|
|
|
|
|
declareAsConstructor = true; |
|
|
|
|
|
|
|
skipParams = 1; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (declareAsConstructor |
|
|
|
|
|
|
|
&& classAnalyzer.constructors.length == 1) { |
|
|
|
|
|
|
|
|
|
|
|
// If this is the only constructor and it is empty and
|
|
|
|
// If this is the only constructor and it is empty and
|
|
|
|
// takes no parameters, this is the default constructor.
|
|
|
|
// takes no parameters, this is the default constructor.
|
|
|
|
return; |
|
|
|
if (methodType.getParameterTypes().length == skipParams |
|
|
|
|
|
|
|
&& getMethodHeader() != null |
|
|
|
|
|
|
|
&& getMethodHeader().getBlock() instanceof jode.flow.EmptyBlock |
|
|
|
|
|
|
|
&& getMethodHeader().hasNoJumps()) |
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// if this is an anonymous class and this is the only
|
|
|
|
|
|
|
|
// constructor and it only does a super call with the given
|
|
|
|
|
|
|
|
// parameters, this is constructor is implicit.
|
|
|
|
|
|
|
|
if (isImplicitAnonymousConstructor) |
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void dumpSource(TabbedPrintWriter writer) |
|
|
|
|
|
|
|
throws IOException |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
boolean declareAsConstructor = isConstructor; |
|
|
|
|
|
|
|
int skipParams = 0; |
|
|
|
|
|
|
|
if (isConstructor() && !isStatic() |
|
|
|
|
|
|
|
&& classAnalyzer.outerValues != null) |
|
|
|
|
|
|
|
skipParams = classAnalyzer.outerValues.length; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (isJikesConstructor) { |
|
|
|
|
|
|
|
// This is the real part of a jikes constructor
|
|
|
|
|
|
|
|
declareAsConstructor = true; |
|
|
|
|
|
|
|
skipParams = 1; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if ((Decompiler.options & Decompiler.OPTION_IMMEDIATE) != 0 |
|
|
|
if ((Decompiler.options & Decompiler.OPTION_IMMEDIATE) != 0 |
|
|
|
&& code != null) { |
|
|
|
&& code != null) { |
|
|
@ -188,8 +256,6 @@ public class MethodAnalyzer implements Analyzer { |
|
|
|
&& getMethodHeader().getBlock() instanceof jode.flow.EmptyBlock) |
|
|
|
&& getMethodHeader().getBlock() instanceof jode.flow.EmptyBlock) |
|
|
|
return; |
|
|
|
return; |
|
|
|
|
|
|
|
|
|
|
|
writer.println(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (minfo.isDeprecated()) { |
|
|
|
if (minfo.isDeprecated()) { |
|
|
|
writer.println("/**"); |
|
|
|
writer.println("/**"); |
|
|
|
writer.println(" * @deprecated"); |
|
|
|
writer.println(" * @deprecated"); |
|
|
@ -203,7 +269,7 @@ public class MethodAnalyzer implements Analyzer { |
|
|
|
if (isConstructor && isStatic()) |
|
|
|
if (isConstructor && isStatic()) |
|
|
|
writer.print(""); /* static block */ |
|
|
|
writer.print(""); /* static block */ |
|
|
|
else { |
|
|
|
else { |
|
|
|
if (isConstructor) |
|
|
|
if (declareAsConstructor) |
|
|
|
writer.print(classAnalyzer.getName()); |
|
|
|
writer.print(classAnalyzer.getName()); |
|
|
|
else { |
|
|
|
else { |
|
|
|
writer.printType(getReturnType()); |
|
|
|
writer.printType(getReturnType()); |
|
|
@ -211,14 +277,8 @@ public class MethodAnalyzer implements Analyzer { |
|
|
|
} |
|
|
|
} |
|
|
|
writer.print("("); |
|
|
|
writer.print("("); |
|
|
|
Type[] paramTypes = methodType.getParameterTypes(); |
|
|
|
Type[] paramTypes = methodType.getParameterTypes(); |
|
|
|
int offset = isStatic()?0:1; |
|
|
|
int offset = skipParams + (isStatic() ? 0 : 1); |
|
|
|
|
|
|
|
int start = skipParams; |
|
|
|
int start = 0; |
|
|
|
|
|
|
|
if (isConstructor() |
|
|
|
|
|
|
|
&& classAnalyzer.getParent() instanceof ClassAnalyzer) { |
|
|
|
|
|
|
|
start++; |
|
|
|
|
|
|
|
offset++; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
LocalInfo[] param = new LocalInfo[paramTypes.length]; |
|
|
|
LocalInfo[] param = new LocalInfo[paramTypes.length]; |
|
|
|
for (int i=start; i<paramTypes.length; i++) { |
|
|
|
for (int i=start; i<paramTypes.length; i++) { |
|
|
|