diff --git a/jode/jode/expr/InvokeOperator.java b/jode/jode/expr/InvokeOperator.java index e3b4662..2c8b1d4 100644 --- a/jode/jode/expr/InvokeOperator.java +++ b/jode/jode/expr/InvokeOperator.java @@ -170,9 +170,9 @@ public final class InvokeOperator extends Operator } catch (IOException ex) { classInfo.guess(ClassInfo.OUTERCLASS); } + checkAnonymousClasses(); } } - checkAnonymousClasses(); } public final boolean isStatic() { @@ -200,8 +200,7 @@ public final class InvokeOperator extends Operator || (Options.options & Options.OPTION_ANON) == 0) return; if (classInfo != null - && classInfo.isMethodScoped() - && classInfo.getClassName() == null) + && classInfo.isMethodScoped()) methodAnalyzer.addAnonymousConstructor(this); } @@ -581,6 +580,7 @@ public final class InvokeOperator extends Operator if (getMethodAnalyzer() != null) { SyntheticAnalyzer synth = getMethodAnalyzer().getSynthetic(); if (synth != null) { + int unifyParam = synth.getUnifyParam(); Expression op = null; switch (synth.getKind()) { case SyntheticAnalyzer.ACCESSGETFIELD: @@ -610,9 +610,9 @@ public final class InvokeOperator extends Operator synth.getReference()); break; case SyntheticAnalyzer.ACCESSCONSTRUCTOR: - if (subExpressions[1] instanceof ConstOperator + if (subExpressions[unifyParam] instanceof ConstOperator && ((ConstOperator) - subExpressions[1]).getValue() == null) { + subExpressions[unifyParam]).getValue() == null) { op = new InvokeOperator(methodAnalyzer, CONSTRUCTOR, synth.getReference()); } @@ -622,8 +622,9 @@ public final class InvokeOperator extends Operator if (op != null) { if (subExpressions != null) { for (int i=subExpressions.length; i-- > 0; ) { - if (i == 1 && synth.getKind() - == SyntheticAnalyzer.ACCESSCONSTRUCTOR) + if (synth.getKind() + == SyntheticAnalyzer.ACCESSCONSTRUCTOR + && i == unifyParam) // skip the null param. continue; op = op.addOperand(subExpressions[i]); diff --git a/jode/jode/jvm/SyntheticAnalyzer.java b/jode/jode/jvm/SyntheticAnalyzer.java index b5c738a..2575792 100644 --- a/jode/jode/jvm/SyntheticAnalyzer.java +++ b/jode/jode/jvm/SyntheticAnalyzer.java @@ -28,6 +28,7 @@ import jode.bytecode.Instruction; import jode.bytecode.MethodInfo; import jode.bytecode.Opcodes; import jode.bytecode.Reference; +import jode.bytecode.TypeSignature; import jode.type.Type; import jode.type.MethodType; @@ -49,6 +50,8 @@ public class SyntheticAnalyzer implements Opcodes { public final static int ACCESSCONSTRUCTOR = 8; int kind = UNKNOWN; + + int unifyParam; Reference reference; ClassInfo classInfo; MethodInfo method; @@ -78,6 +81,14 @@ public class SyntheticAnalyzer implements Opcodes { return reference; } + /** + * Gets the index of the dummy parameter for an ACCESSCONSTRUCTOR. + * Normally the 1 but for inner classes it may be 2. + */ + public int getUnifyParam() { + return unifyParam; + } + private static final int[] getClassOpcodes = { opc_aload, opc_invokestatic, opc_areturn, opc_astore, opc_new, opc_dup, opc_aload, @@ -376,10 +387,11 @@ public class SyntheticAnalyzer implements Opcodes { public boolean checkConstructorAccess() { BasicBlocks bb = method.getBasicBlocks(); + String[] paramTypes + = TypeSignature.getParameterTypes(method.getType()); Handler[] excHandlers = bb.getExceptionHandlers(); if (excHandlers != null && excHandlers.length != 0) return false; - Block[] blocks = bb.getBlocks(); Block startBlock = bb.getStartBlock(); if (startBlock == null) return false; @@ -389,19 +401,22 @@ public class SyntheticAnalyzer implements Opcodes { Iterator iter = startBlock.getInstructions().iterator(); if (!iter.hasNext()) return false; - Instruction instr = (Instruction) iter.next(); - if (instr.getOpcode() != opc_aload || instr.getLocalSlot() != 0) - return false; - if (!iter.hasNext()) - return false; - instr = (Instruction) iter.next(); - // slot begins with 2. Slot 1 contains a dummy value, that - // is used so that the constructor has a different type signature. - int params = 0, slot = 2; + unifyParam = -1; + Instruction instr = (Instruction) iter.next(); + int params = 0, slot = 0; while (instr.getOpcode() >= opc_iload - && instr.getOpcode() <= opc_aload - && instr.getLocalSlot() == slot) { + && instr.getOpcode() <= opc_aload) { + if (instr.getLocalSlot() > slot + && unifyParam == -1 && params > 0 + && paramTypes[params-1].charAt(0) == 'L') { + unifyParam = params; + params++; + slot++; + } + if (instr.getLocalSlot() != slot) + return false; + params++; slot += (instr.getOpcode() == opc_lload || instr.getOpcode() == opc_dload) ? 2 : 1; @@ -409,6 +424,13 @@ public class SyntheticAnalyzer implements Opcodes { return false; instr = (Instruction) iter.next(); } + if (unifyParam == -1 + && params > 0 && params <= paramTypes.length + && paramTypes[params-1].charAt(0) == 'L') { + unifyParam = params; + params++; + slot++; + } if (instr.getOpcode() == opc_invokespecial) { Reference ref = instr.getReference(); String refClazz = ref.getClazz().substring(1); @@ -420,11 +442,15 @@ public class SyntheticAnalyzer implements Opcodes { MethodType refType = Type.tMethod(ref.getType()); if ((refMethod.getModifiers() & modifierMask) != Modifier.PRIVATE || !refMethod.getName().equals("") - || refType.getParameterTypes().length != params) - return false; + || unifyParam == -1 + || refType.getParameterTypes().length != params - 2) + return false; if (iter.hasNext()) return false; - /* For valid bytecode the types matches automatically */ + /* We don't check if types matches. No problem since we only + * need to make sure, this constructor doesn't do anything + * more than relay to the real one. + */ reference = ref; kind = ACCESSCONSTRUCTOR; return true;