mirror of
https://github.com/alibaba/testable-mock.git
synced 2025-03-14 03:40:25 +08:00
consider return type when calculating stack change
This commit is contained in:
parent
43cd4aeeec
commit
7d2dd83410
@ -122,21 +122,17 @@ public class SourceClassHandler extends BaseClassHandler {
|
||||
for (int i = rangeEnd - 1; i >= 0; i--) {
|
||||
switch (instructions[i].getOpcode()) {
|
||||
case Opcodes.INVOKESPECIAL:
|
||||
stackLevel += ClassUtil.getParameterTypes(((MethodInsnNode)instructions[i]).desc).size();
|
||||
case Opcodes.INVOKEVIRTUAL:
|
||||
case Opcodes.INVOKEINTERFACE:
|
||||
stackLevel += stackEffectOfInvocation(instructions[i]) + 1;
|
||||
if (((MethodInsnNode)instructions[i]).name.equals(ConstPool.CONSTRUCTOR)) {
|
||||
// constructor implicitly eat 2 more stack and return 1 value
|
||||
// constructor must be INVOKESPECIAL and implicitly pop 1 more stack
|
||||
stackLevel++;
|
||||
}
|
||||
break;
|
||||
case Opcodes.INVOKESTATIC:
|
||||
case Opcodes.INVOKEDYNAMIC:
|
||||
// static and dynamic invoke implicitly return 1 value
|
||||
stackLevel += (ClassUtil.getParameterTypes(((MethodInsnNode)instructions[i]).desc).size() - 1);
|
||||
break;
|
||||
case Opcodes.INVOKEVIRTUAL:
|
||||
case Opcodes.INVOKEINTERFACE:
|
||||
// virtual and interface invoke implicitly eat 1 more stack and return 1 value, deuce
|
||||
stackLevel += ClassUtil.getParameterTypes(((MethodInsnNode)instructions[i]).desc).size();
|
||||
stackLevel += stackEffectOfInvocation(instructions[i]);
|
||||
break;
|
||||
case -1:
|
||||
// reach LineNumberNode or LabelNode
|
||||
@ -151,6 +147,11 @@ public class SourceClassHandler extends BaseClassHandler {
|
||||
return -1;
|
||||
}
|
||||
|
||||
private int stackEffectOfInvocation(AbstractInsnNode instruction) {
|
||||
String desc = ((MethodInsnNode)instruction).desc;
|
||||
return ClassUtil.getParameterTypes(desc).size() - (ClassUtil.getReturnType(desc).isEmpty() ? 0 : 1);
|
||||
}
|
||||
|
||||
private AbstractInsnNode[] replaceNewOps(ClassNode cn, MethodNode mn, String newOperatorInjectMethodName,
|
||||
AbstractInsnNode[] instructions, int start, int end) {
|
||||
LogUtil.debug(" Using %s mock new operation in %s", newOperatorInjectMethodName, mn.name);
|
||||
|
@ -26,6 +26,7 @@ public class ClassUtil {
|
||||
public static final byte TYPE_CLASS = 'L';
|
||||
public static final byte TYPE_SHORT = 'S';
|
||||
public static final byte TYPE_BOOL = 'Z';
|
||||
public static final byte TYPE_VOID = 'V';
|
||||
private static final byte PARAM_END = ')';
|
||||
private static final byte CLASS_END = ';';
|
||||
private static final byte TYPE_ARRAY = '[';
|
||||
@ -39,6 +40,7 @@ public class ClassUtil {
|
||||
private static final String CLASS_LONG = "java/lang/Long";
|
||||
private static final String CLASS_SHORT = "java/lang/Short";
|
||||
private static final String CLASS_BOOLEAN = "java/lang/Boolean";
|
||||
private static final String EMPTY = "";
|
||||
private static final String METHOD_VALUE_OF = "valueOf";
|
||||
|
||||
private final static String JOINER = "::";
|
||||
@ -56,6 +58,7 @@ public class ClassUtil {
|
||||
TYPE_MAPPING.put(TYPE_LONG, CLASS_LONG);
|
||||
TYPE_MAPPING.put(TYPE_SHORT, CLASS_SHORT);
|
||||
TYPE_MAPPING.put(TYPE_BOOL, CLASS_BOOLEAN);
|
||||
TYPE_MAPPING.put(TYPE_VOID, EMPTY);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -159,7 +162,7 @@ public class ClassUtil {
|
||||
} else if (TYPE_MAPPING.containsKey((byte)typeChar)) {
|
||||
return TYPE_MAPPING.get((byte)typeChar);
|
||||
} else {
|
||||
return "";
|
||||
return EMPTY;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user