From c905acf44f3600aeead37b971f8d3e8f8bb8bd34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=87=91=E6=88=9F?= Date: Fri, 22 May 2020 21:24:34 +0800 Subject: [PATCH] use global invoke replace testable class method --- .../PrivateAccessStatementGenerator.java | 13 +++- .../testable/translator/BaseTranslator.java | 25 ++++++ .../EnableTestableInjectTranslator.java | 18 +---- .../translator/EnableTestableTranslator.java | 76 ++++++++++--------- 4 files changed, 81 insertions(+), 51 deletions(-) create mode 100644 src/main/java/com/alibaba/testable/translator/BaseTranslator.java diff --git a/src/main/java/com/alibaba/testable/generator/PrivateAccessStatementGenerator.java b/src/main/java/com/alibaba/testable/generator/PrivateAccessStatementGenerator.java index 1acd098..216eb54 100644 --- a/src/main/java/com/alibaba/testable/generator/PrivateAccessStatementGenerator.java +++ b/src/main/java/com/alibaba/testable/generator/PrivateAccessStatementGenerator.java @@ -4,6 +4,7 @@ import com.alibaba.testable.model.TestableContext; import com.alibaba.testable.util.ConstPool; import com.sun.tools.javac.tree.JCTree.*; import com.sun.tools.javac.util.List; +import com.sun.tools.javac.util.ListBuffer; /** * @author flin @@ -14,11 +15,19 @@ public class PrivateAccessStatementGenerator extends BaseGenerator { super(cx); } - public JCExpression fetchSetterStatement(JCExpressionStatement jcExpressionStatement) { - JCAssign assign = (JCAssign)jcExpressionStatement.expr; + public JCExpression fetchSetterStatement(JCAssign assign) { JCFieldAccess setter = cx.treeMaker.Select(nameToExpression(ConstPool.TESTABLE_PRIVATE_ACCESSOR), cx.names.fromString("set")); return cx.treeMaker.Apply(List.nil(), setter, List.of(((JCFieldAccess)assign.lhs).selected, cx.treeMaker.Literal(((JCFieldAccess)assign.lhs).name.toString()), assign.rhs)); } + + public JCExpression fetchInvokeStatement(JCMethodInvocation expr) { + JCFieldAccess invoker = cx.treeMaker.Select(nameToExpression(ConstPool.TESTABLE_PRIVATE_ACCESSOR), + cx.names.fromString("invoke")); + ListBuffer params = ListBuffer.of(((JCFieldAccess)expr.meth).selected); + params.add(cx.treeMaker.Literal(((JCFieldAccess)expr.meth).name.toString())); + params.addAll(expr.args); + return cx.treeMaker.Apply(List.nil(), invoker, params.toList()); + } } diff --git a/src/main/java/com/alibaba/testable/translator/BaseTranslator.java b/src/main/java/com/alibaba/testable/translator/BaseTranslator.java new file mode 100644 index 0000000..974727a --- /dev/null +++ b/src/main/java/com/alibaba/testable/translator/BaseTranslator.java @@ -0,0 +1,25 @@ +package com.alibaba.testable.translator; + +import com.sun.tools.javac.tree.JCTree.*; +import com.sun.tools.javac.tree.TreeTranslator; +import com.sun.tools.javac.util.List; + +/** + * @author flin + */ +public abstract class BaseTranslator extends TreeTranslator { + + protected List checkAndExchange(List args) { + if (args != null) { + JCExpression[] es = new JCExpression[args.length()]; + for (int i = 0; i < args.length(); i++) { + es[i] = checkAndExchange(args.get(i)); + } + return List.from(es); + } + return null; + } + + protected abstract JCExpression checkAndExchange(JCExpression expr); + +} diff --git a/src/main/java/com/alibaba/testable/translator/EnableTestableInjectTranslator.java b/src/main/java/com/alibaba/testable/translator/EnableTestableInjectTranslator.java index c17039f..bc72d1f 100644 --- a/src/main/java/com/alibaba/testable/translator/EnableTestableInjectTranslator.java +++ b/src/main/java/com/alibaba/testable/translator/EnableTestableInjectTranslator.java @@ -13,7 +13,7 @@ import com.sun.tools.javac.util.Name; * * @author flin */ -public class EnableTestableInjectTranslator extends TreeTranslator { +public class EnableTestableInjectTranslator extends BaseTranslator { private final TestableContext cx; @@ -123,18 +123,8 @@ public class EnableTestableInjectTranslator extends TreeTranslator { mods.getFlags().contains(javax.lang.model.element.Modifier.FINAL); } - private List checkAndExchange(List args) { - if (args != null) { - JCExpression[] es = new JCExpression[args.length()]; - for (int i = 0; i < args.length(); i++) { - es[i] = checkAndExchange(args.get(i)); - } - return List.from(es); - } - return null; - } - - private JCExpression checkAndExchange(JCExpression expr) { + @Override + protected JCExpression checkAndExchange(JCExpression expr) { if (isNewOperation(expr)) { JCNewClass newClassExpr = (JCNewClass)expr; Name className = ((JCIdent)newClassExpr.clazz).name; @@ -175,7 +165,7 @@ public class EnableTestableInjectTranslator extends TreeTranslator { JCFieldAccess snClass = cx.treeMaker.Select(cx.treeMaker.Ident(cx.names.fromString(ConstPool.NE_PKG)), cx.names.fromString(ConstPool.NE_CLS)); JCFieldAccess snMethod = cx.treeMaker.Select(snClass, cx.names.fromString(ConstPool.NE_FUN)); - ListBuffer args = new ListBuffer(); + ListBuffer args = new ListBuffer<>(); args.add(cx.treeMaker.Ident(cx.names.fromString(ConstPool.REF_THIS))); args.add(cx.treeMaker.Literal(methodName.toString())); args.addAll(param); diff --git a/src/main/java/com/alibaba/testable/translator/EnableTestableTranslator.java b/src/main/java/com/alibaba/testable/translator/EnableTestableTranslator.java index f866f59..9f3811c 100644 --- a/src/main/java/com/alibaba/testable/translator/EnableTestableTranslator.java +++ b/src/main/java/com/alibaba/testable/translator/EnableTestableTranslator.java @@ -7,13 +7,13 @@ import com.alibaba.testable.model.TestableContext; import com.alibaba.testable.util.ConstPool; import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.*; -import com.sun.tools.javac.tree.TreeTranslator; import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.ListBuffer; import com.sun.tools.javac.util.Name; import com.sun.tools.javac.util.Pair; import java.lang.reflect.Field; +import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Arrays; @@ -22,12 +22,13 @@ import java.util.Arrays; * * @author flin */ -public class EnableTestableTranslator extends TreeTranslator { +public class EnableTestableTranslator extends BaseTranslator { private final TestableContext cx; private String sourceClassName = ""; private final ListBuffer sourceClassIns = new ListBuffer<>(); - private final ListBuffer stubbornFields = new ListBuffer<>(); + private final ListBuffer privateOrFinalFields = new ListBuffer<>(); + private final ListBuffer privateMethods = new ListBuffer<>(); private final TestSetupMethodGenerator testSetupMethodGenerator; private final PrivateAccessStatementGenerator privateAccessStatementGenerator; @@ -41,7 +42,13 @@ public class EnableTestableTranslator extends TreeTranslator { Field[] fields = cls.getDeclaredFields(); for (Field f : fields) { if (Modifier.isFinal(f.getModifiers()) || Modifier.isPrivate(f.getModifiers())) { - stubbornFields.add(f.getName()); + privateOrFinalFields.add(f.getName()); + } + } + Method[] methods = cls.getDeclaredMethods(); + for (Method m : methods) { + if (Modifier.isPrivate(m.getModifiers())) { + privateMethods.add(m.getName()); } } testSetupMethodGenerator.memberMethods.addAll(Arrays.asList(cls.getDeclaredMethods())); @@ -50,39 +57,27 @@ public class EnableTestableTranslator extends TreeTranslator { } } - /** - * Demo d = new Demo() -> DemoTestable d = new Demo() - */ @Override public void visitVarDef(JCVariableDecl jcVariableDecl) { super.visitVarDef(jcVariableDecl); if (jcVariableDecl.vartype.getClass().equals(JCIdent.class) && ((JCIdent)jcVariableDecl.vartype).name.toString().equals(sourceClassName)) { - jcVariableDecl.vartype = getTestableClassIdent(jcVariableDecl.vartype); sourceClassIns.add(jcVariableDecl.name); } } - /** - * Demo d = new Demo() -> Demo d = new DemoTestable() - */ - @Override - public void visitNewClass(JCNewClass jcNewClass) { - super.visitNewClass(jcNewClass); - if (getSimpleClassName(jcNewClass).equals(sourceClassName)) { - jcNewClass.clazz = getTestableClassIdent(jcNewClass.clazz); - } - } - /** * d.privateField = val -> PrivateAccessor.set(d, "privateField", val) + * d.privateMethod(args) -> PrivateAccessor.invoke(d, "privateMethod", args) */ @Override public void visitExec(JCExpressionStatement jcExpressionStatement) { if (jcExpressionStatement.expr.getClass().equals(JCAssign.class) && - isAssignStubbornField((JCAssign)jcExpressionStatement.expr)) { - jcExpressionStatement.expr = privateAccessStatementGenerator.fetchSetterStatement(jcExpressionStatement); + isPrivateField((JCAssign)jcExpressionStatement.expr)) { + jcExpressionStatement.expr = privateAccessStatementGenerator.fetchSetterStatement( + (JCAssign)jcExpressionStatement.expr); } + jcExpressionStatement.expr = checkAndExchange(jcExpressionStatement.expr); super.visitExec(jcExpressionStatement); } @@ -129,7 +124,16 @@ public class EnableTestableTranslator extends TreeTranslator { } /** - * For setter break point + * For private invoke invocation break point + */ + @Override + public void visitApply(JCMethodInvocation tree) { + tree.args = checkAndExchange(tree.args); + super.visitApply(tree); + } + + /** + * For private setter break point */ @Override public void visitAssign(JCAssign jcAssign) { @@ -137,21 +141,20 @@ public class EnableTestableTranslator extends TreeTranslator { } /** - * For getter break point + * For private getter break point */ @Override public void visitSelect(JCFieldAccess jcFieldAccess) { super.visitSelect(jcFieldAccess); } - private String getSimpleClassName(JCNewClass jcNewClass) { - if (jcNewClass.clazz.getClass().equals(JCIdent.class)) { - return ((JCIdent)jcNewClass.clazz).name.toString(); - } else if (jcNewClass.clazz.getClass().equals(JCFieldAccess.class)) { - return ((JCFieldAccess)jcNewClass.clazz).name.toString(); - } else { - return ""; + @Override + protected JCExpression checkAndExchange(JCExpression expr) { + if (expr.getClass().equals(JCMethodInvocation.class) && + isPrivateMethod((JCMethodInvocation)expr)) { + expr = privateAccessStatementGenerator.fetchInvokeStatement((JCMethodInvocation)expr); } + return expr; } private List removeAnnotation(List annotations, String target) { @@ -164,15 +167,18 @@ public class EnableTestableTranslator extends TreeTranslator { return nb.toList(); } - private boolean isAssignStubbornField(JCAssign expr) { + private boolean isPrivateField(JCAssign expr) { return expr.lhs.getClass().equals(JCFieldAccess.class) && + ((JCFieldAccess)(expr).lhs).selected.getClass().equals(JCIdent.class) && sourceClassIns.contains(((JCIdent)((JCFieldAccess)(expr).lhs).selected).name) && - stubbornFields.contains(((JCFieldAccess)(expr).lhs).name.toString()); + privateOrFinalFields.contains(((JCFieldAccess)(expr).lhs).name.toString()); } - private JCIdent getTestableClassIdent(JCExpression clazz) { - Name className = ((JCIdent)clazz).name; - return cx.treeMaker.Ident(cx.names.fromString(className + ConstPool.TESTABLE)); + private boolean isPrivateMethod(JCMethodInvocation expr) { + return expr.meth.getClass().equals(JCFieldAccess.class) && + ((JCFieldAccess)(expr).meth).selected.getClass().equals(JCIdent.class) && + sourceClassIns.contains(((JCIdent)((JCFieldAccess)(expr).meth).selected).name) && + privateMethods.contains(((JCFieldAccess)(expr).meth).name.toString()); } }