fit kotlin companion object as static method

This commit is contained in:
金戟 2020-10-27 11:54:00 +08:00
parent 0ef13a8e95
commit 36136e878e
3 changed files with 41 additions and 4 deletions

View File

@ -84,7 +84,8 @@ public class SourceClassHandler extends BaseClassHandler {
private String getMemberInjectMethodName(List<MethodInfo> memberInjectMethodList, MethodInsnNode node) {
for (MethodInfo m : memberInjectMethodList) {
if (m.getClazz().equals(node.owner) && m.getName().equals(node.name) && m.getDesc().equals(node.desc)) {
String nodeOwner = ClassUtil.fitCompanionClassName(node.owner);
if (m.getClazz().equals(nodeOwner) && m.getName().equals(node.name) && m.getDesc().equals(node.desc)) {
return m.getMockName();
}
}
@ -166,16 +167,24 @@ public class SourceClassHandler extends BaseClassHandler {
String testClassName = ClassUtil.getTestClassName(cn.name);
mn.instructions.insertBefore(instructions[start], new FieldInsnNode(GETSTATIC, testClassName,
ConstPool.TESTABLE_INJECT_REF, ClassUtil.toByteCodeClassName(testClassName)));
if (Opcodes.INVOKESTATIC == opcode) {
// append a null value if it was a static invoke
if (Opcodes.INVOKESTATIC == opcode || isCompanionMethod(ownerClass, opcode)) {
// append a null value if it was a static invoke or in kotlin companion class
mn.instructions.insertBefore(instructions[start], new InsnNode(ACONST_NULL));
if (ClassUtil.isCompanionClassName(ownerClass)) {
// for kotlin companion class, remove the byte code of reference to "companion" static field
mn.instructions.remove(instructions[end - 1]);
}
}
mn.instructions.insertBefore(instructions[end], new MethodInsnNode(INVOKEVIRTUAL, testClassName,
substitutionMethod, addFirstParameter(method.desc, ownerClass), false));
substitutionMethod, addFirstParameter(method.desc, ClassUtil.fitCompanionClassName(ownerClass)), false));
mn.instructions.remove(instructions[end]);
return mn.instructions.toArray();
}
private boolean isCompanionMethod(String ownerClass, int opcode) {
return Opcodes.INVOKEVIRTUAL == opcode && ClassUtil.isCompanionClassName(ownerClass);
}
private String addFirstParameter(String desc, String ownerClass) {
return "(" + ClassUtil.toByteCodeClassName(ownerClass) + desc.substring(1);
}

View File

@ -72,6 +72,22 @@ public class ClassUtil {
return false;
}
/**
* fit kotlin companion class name to original name
* @param name a class name (which could be a companion class)
*/
public static boolean isCompanionClassName(String name) {
return name.endsWith("$Companion");
}
/**
* fit kotlin companion class name to original name
* @param name a class name (which could be a companion class)
*/
public static String fitCompanionClassName(String name) {
return name.replaceAll("\\$Companion$", "");
}
/**
* get test class name from source class name
* @param sourceClassName source class name

View File

@ -40,5 +40,17 @@ class ClassUtilTest {
assertEquals("Ljava/lang/String;", ClassUtil.toByteCodeClassName("java.lang.String"));
}
@Test
void should_able_to_fit_companion_class_name() {
assertEquals("com/intellij/rt/debugger/agent/CaptureAgent$ParamKeyProvider",
ClassUtil.fitCompanionClassName("com/intellij/rt/debugger/agent/CaptureAgent$ParamKeyProvider"));
assertEquals("com/alibaba/testable/demo/BlackBox",
ClassUtil.fitCompanionClassName("com/alibaba/testable/demo/BlackBox"));
assertEquals("com/alibaba/testable/demo/BlackBox$Companion",
ClassUtil.fitCompanionClassName("com/alibaba/testable/demo/BlackBox$Companion$Companion"));
assertEquals("com/alibaba/testable/demo/BlackBox",
ClassUtil.fitCompanionClassName("com/alibaba/testable/demo/BlackBox$Companion"));
}
}