handling setter exchange

This commit is contained in:
金戟 2020-05-16 23:39:02 +08:00
parent cbb3a62fff
commit bc49fda272
5 changed files with 92 additions and 19 deletions

View File

@ -7,6 +7,7 @@ import com.alibaba.testable.generator.statement.FieldSetterStatementGenerator;
import com.alibaba.testable.generator.statement.FieldStatementGenerator;
import com.alibaba.testable.translator.TestableClassDevRoleTranslator;
import com.alibaba.testable.util.ConstPool;
import com.alibaba.testable.util.StringUtil;
import com.squareup.javapoet.*;
import com.sun.tools.javac.api.JavacTrees;
import com.sun.tools.javac.code.Type;
@ -51,10 +52,11 @@ public class TestableClassDevRoleGenerator {
methodSpecs.add(buildMemberMethod(clazz, method));
}
}
for (JCTree.JCVariableDecl field : translator.getPrivateFields()) {
for (JCTree.JCVariableDecl field : translator.getFields()) {
methodSpecs.add(buildFieldGetter(clazz, field));
methodSpecs.add(buildFieldSetter(clazz, field));
}
methodSpecs.add(buildStubbornFieldMethod(translator.getFields()));
TypeSpec.Builder builder = TypeSpec.classBuilder(className)
.addModifiers(Modifier.PUBLIC, Modifier.FINAL)
@ -67,9 +69,21 @@ public class TestableClassDevRoleGenerator {
return javaFile.toString();
}
private MethodSpec buildStubbornFieldMethod(List<JCTree.JCVariableDecl> fields) {
List<String> fieldNames = new ArrayList<>();
for (JCTree.JCVariableDecl f : fields) {
fieldNames.add("\"" + f.name.toString() + "\"");
}
return MethodSpec.methodBuilder(ConstPool.STUBBORN_FIELD_METHOD)
.addModifiers(Modifier.PUBLIC).addModifiers(Modifier.STATIC)
.addStatement("return new $T[]{" + StringUtil.join(fieldNames, ",") + "}", String.class)
.returns(ArrayTypeName.of(String.class))
.build();
}
private MethodSpec buildFieldGetter(Element classElement, JCTree.JCVariableDecl field) {
return buildFieldAccessor(classElement, field, "TestableGet",
TypeName.get(((Type.MethodType)field.type).restype), new FieldGetterStatementGenerator());
TypeName.get(field.vartype.type), new FieldGetterStatementGenerator());
}
private MethodSpec buildFieldSetter(Element classElement, JCTree.JCVariableDecl field) {

View File

@ -5,6 +5,7 @@ import com.alibaba.testable.generator.StaticNewClassGenerator;
import com.alibaba.testable.generator.TestableClassDevRoleGenerator;
import com.alibaba.testable.translator.TestableClassTestRoleTranslator;
import com.alibaba.testable.util.ConstPool;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.tree.JCTree;
import javax.annotation.processing.FilerException;
@ -40,9 +41,9 @@ public class TestableProcessor extends BaseProcessor {
for (Element element : elements) {
if (element.getKind().isClass()) {
if (isTestClass(element.getSimpleName())) {
processTestRoleClassElement(element);
processTestRoleClassElement((Symbol.ClassSymbol)element);
} else {
processDevRoleClassElement(element);
processDevRoleClassElement((Symbol.ClassSymbol)element);
}
}
}
@ -79,7 +80,7 @@ public class TestableProcessor extends BaseProcessor {
return staticNewClassFile.getName().contains(GENERATED_TEST_SOURCES);
}
private void processDevRoleClassElement(Element clazz) {
private void processDevRoleClassElement(Symbol.ClassSymbol clazz) {
String packageName = elementUtils.getPackageOf(clazz).getQualifiedName().toString();
String testableTypeName = getTestableClassName(clazz.getSimpleName());
String fullQualityTypeName = packageName + "." + testableTypeName;
@ -91,12 +92,16 @@ public class TestableProcessor extends BaseProcessor {
}
}
private void processTestRoleClassElement(Element clazz) {
private void processTestRoleClassElement(Symbol.ClassSymbol clazz) {
JCTree tree = trees.getTree(clazz);
tree.accept(new TestableClassTestRoleTranslator(getOriginClassName(clazz), treeMaker));
tree.accept(new TestableClassTestRoleTranslator(getPkgName(clazz), getOriginClassName(clazz), treeMaker));
}
private String getOriginClassName(Element clazz) {
private String getPkgName(Symbol.ClassSymbol clazz) {
return ((Symbol.PackageSymbol)clazz.owner).fullname.toString();
}
private String getOriginClassName(Symbol.ClassSymbol clazz) {
String testClassName = clazz.getSimpleName().toString();
return testClassName.substring(0, testClassName.length() - "Test".length());
}

View File

@ -28,7 +28,7 @@ public class TestableClassDevRoleTranslator extends TreeTranslator {
private List<JCMethodDecl> methods = List.nil();
/**
* Private field to mock
* Fields to wrap
*/
private List<JCTree.JCVariableDecl> fields = List.nil();
@ -36,7 +36,7 @@ public class TestableClassDevRoleTranslator extends TreeTranslator {
return methods;
}
public List<JCTree.JCVariableDecl> getPrivateFields() {
public List<JCTree.JCVariableDecl> getFields() {
return fields;
}
@ -51,7 +51,7 @@ public class TestableClassDevRoleTranslator extends TreeTranslator {
}
/**
* record all methods
* Record all methods
*/
@Override
public void visitMethodDef(JCMethodDecl jcMethodDecl) {
@ -60,7 +60,7 @@ public class TestableClassDevRoleTranslator extends TreeTranslator {
}
/**
* case: new Demo()
* Case: new Demo()
*/
@Override
public void visitExec(JCTree.JCExpressionStatement jcExpressionStatement) {
@ -69,7 +69,7 @@ public class TestableClassDevRoleTranslator extends TreeTranslator {
}
/**
* case: call(new Demo())
* Case: call(new Demo())
*/
@Override
public void visitApply(JCTree.JCMethodInvocation tree) {
@ -78,20 +78,20 @@ public class TestableClassDevRoleTranslator extends TreeTranslator {
}
/**
* record all private fields
* case: Demo d = new Demo()
* Record all private fields
* Case: Demo d = new Demo()
*/
@Override
public void visitVarDef(JCTree.JCVariableDecl jcVariableDecl) {
if (jcVariableDecl.mods.getFlags().contains(javax.lang.model.element.Modifier.PRIVATE)) {
fields.append(jcVariableDecl);
if (isStubbornField(jcVariableDecl.mods)) {
fields = fields.append(jcVariableDecl);
}
jcVariableDecl.init = checkAndExchangeNewOperation(jcVariableDecl.init);
super.visitVarDef(jcVariableDecl);
}
/**
* case: new Demo().call()
* Case: new Demo().call()
*/
@Override
public void visitSelect(JCTree.JCFieldAccess jcFieldAccess) {
@ -99,16 +99,27 @@ public class TestableClassDevRoleTranslator extends TreeTranslator {
super.visitSelect(jcFieldAccess);
}
/**
* For break point
*/
@Override
public void visitNewClass(JCTree.JCNewClass jcNewClass) {
super.visitNewClass(jcNewClass);
}
/**
* For break point
*/
@Override
public void visitNewArray(JCTree.JCNewArray jcNewArray) {
super.visitNewArray(jcNewArray);
}
private boolean isStubbornField(JCTree.JCModifiers mods) {
return mods.getFlags().contains(javax.lang.model.element.Modifier.PRIVATE) ||
mods.getFlags().contains(javax.lang.model.element.Modifier.FINAL);
}
private List<JCTree.JCExpression> checkAndExchangeNewOperation(List<JCTree.JCExpression> args) {
if (args != null) {
JCTree.JCExpression[] es = new JCTree.JCExpression[args.length()];

View File

@ -7,6 +7,7 @@ import com.sun.tools.javac.tree.TreeTranslator;
import com.sun.tools.javac.util.Name;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
@ -19,10 +20,19 @@ public class TestableClassTestRoleTranslator extends TreeTranslator {
private TreeMaker treeMaker;
private String sourceClassName;
private List<Name> sourceClassIns = new ArrayList<>();
private List<String> stubbornFields = new ArrayList<>();
public TestableClassTestRoleTranslator(String className, TreeMaker treeMaker) {
public TestableClassTestRoleTranslator(String pkgName, String className, TreeMaker treeMaker) {
this.sourceClassName = className;
this.treeMaker = treeMaker;
try {
stubbornFields = Arrays.asList(
(String[])Class.forName(pkgName + "." + className + ConstPool.TESTABLE)
.getMethod(ConstPool.STUBBORN_FIELD_METHOD)
.invoke(null));
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
@ -42,6 +52,37 @@ public class TestableClassTestRoleTranslator extends TreeTranslator {
}
}
/**
* For break point
*/
@Override
public void visitAssign(JCTree.JCAssign jcAssign) {
super.visitAssign(jcAssign);
}
/**
* For break point
*/
@Override
public void visitSelect(JCTree.JCFieldAccess jcFieldAccess) {
super.visitSelect(jcFieldAccess);
}
@Override
public void visitExec(JCTree.JCExpressionStatement jcExpressionStatement) {
if (jcExpressionStatement.expr.getClass().equals(JCTree.JCAssign.class) &&
isAssignStubbornField((JCTree.JCAssign)jcExpressionStatement.expr)) {
//jcExpressionStatement.expr =
}
super.visitExec(jcExpressionStatement);
}
private boolean isAssignStubbornField(JCTree.JCAssign expr) {
return expr.lhs.getClass().equals(JCTree.JCFieldAccess.class) &&
sourceClassIns.contains(((JCTree.JCIdent)((JCTree.JCFieldAccess)(expr).lhs).selected).name) &&
stubbornFields.contains(((JCTree.JCFieldAccess)(expr).lhs).name.toString());
}
private JCTree.JCIdent getTestableClassIdent(JCTree.JCExpression clazz) {
Name className = ((JCTree.JCIdent)clazz).name;
return treeMaker.Ident(className.table.fromString(className + ConstPool.TESTABLE));

View File

@ -12,4 +12,6 @@ public final class ConstPool {
public static final String SN_CLS = "e";
public static final String SN_METHOD = "w";
public static final String SN_PKG_CLS = "n.e";
public static final String STUBBORN_FIELD_METHOD = "stubbornField";
}