fix compile time check for private member access

This commit is contained in:
金戟 2021-01-31 18:37:27 +08:00
parent 39c788cd02
commit ab8a0b32e5
4 changed files with 31 additions and 7 deletions

View File

@ -6,7 +6,16 @@ package com.alibaba.testable.processor.exception;
public class MemberNotExistException extends RuntimeException {
public MemberNotExistException(String type, String className, String target) {
super(type + " \"" + target + "\" not exist in class \"" + className + "\"");
super(String.format("%s \"%s\" not exist in class \"%s\"", type, target, className));
}
public MemberNotExistException(String type, String className, String target, int count) {
super(String.format("%s \"%s\" with %d %s not exist in class \"%s\"",
type, target, count, parameters(count), className));
}
private static String parameters(int count) {
return count > 1 ? "parameters" : "parameter";
}
}

View File

@ -146,13 +146,13 @@ public class EnablePrivateAccessTranslator extends BaseTranslator {
// check is invoking a private method of source class
if (expr instanceof JCMethodInvocation) {
JCMethodInvocation invocation = (JCMethodInvocation)expr;
privateAccessChecker.validate(invocation);
MemberType memberType = checkInvokeType(invocation);
if (memberType.equals(MemberType.PRIVATE_OR_FINAL)) {
expr = privateAccessStatementGenerator.fetchInvokeStatement(invocation);
} else if (memberType.equals(MemberType.STATIC_PRIVATE)) {
expr = privateAccessStatementGenerator.fetchStaticInvokeStatement(invocation);
}
privateAccessChecker.validate((JCMethodInvocation)expr);
}
// check the casted expression
if (expr instanceof JCTypeCast) {

View File

@ -17,6 +17,7 @@ import java.util.Map;
public class PrivateAccessChecker {
private static final String CLASS_NAME_PRIVATE_ACCESSOR = "PrivateAccessor";
private static final String CLASS_NAME_PRIVATE_ACCESSOR_FULL = "com.alibaba.testable.core.accessor.PrivateAccessor";
private static final List<String> FIELD_ACCESS_METHOD = Arrays.asList(new String[]
{ "get", "set", "getStatic", "setStatic" }.clone());
private static final List<String> FIELD_INVOKE_METHOD = Arrays.asList(new String[]
@ -37,8 +38,7 @@ public class PrivateAccessChecker {
public void validate(JCTree.JCMethodInvocation invocation) {
if (invocation.meth instanceof JCTree.JCFieldAccess && invocation.args.length() >= 2) {
JCTree.JCFieldAccess fieldAccess = (JCTree.JCFieldAccess)invocation.meth;
if (fieldAccess.selected instanceof JCTree.JCIdent && invocation.args.get(1) instanceof JCTree.JCLiteral &&
((JCTree.JCIdent)fieldAccess.selected).name.toString().equals(CLASS_NAME_PRIVATE_ACCESSOR)) {
if (invocation.args.get(1) instanceof JCTree.JCLiteral && isPrivateAccessor(fieldAccess)) {
Object target = ((JCTree.JCLiteral)invocation.args.get(1)).getValue();
if (target instanceof String) {
String methodName = fieldAccess.name.toString();
@ -55,10 +55,10 @@ public class PrivateAccessChecker {
checkParameterCount(sourceMembers.privateMethods, (String)target, parameterCount)) {
// Let it go
} else if (sourceMembers.nonPrivateMethods.containsKey(target) &&
checkParameterCount(sourceMembers.privateMethods, (String)target, parameterCount)) {
checkParameterCount(sourceMembers.nonPrivateMethods, (String)target, parameterCount)) {
cx.logger.warn("Method " + className + "::" + target + " is not private.");
} else {
throw new MemberNotExistException(TYPE_METHOD, className, (String)target);
throw new MemberNotExistException(TYPE_METHOD, className, (String)target, parameterCount);
}
}
}
@ -66,6 +66,20 @@ public class PrivateAccessChecker {
}
}
private boolean isPrivateAccessor(JCTree.JCFieldAccess fieldAccess) {
return isPrivateAccessorWithShortRef(fieldAccess) || isPrivateAccessorWithFullRef(fieldAccess);
}
private boolean isPrivateAccessorWithShortRef(JCTree.JCFieldAccess fieldAccess) {
return fieldAccess.selected instanceof JCTree.JCIdent &&
((JCTree.JCIdent)fieldAccess.selected).name.toString().equals(CLASS_NAME_PRIVATE_ACCESSOR);
}
private boolean isPrivateAccessorWithFullRef(JCTree.JCFieldAccess fieldAccess) {
return fieldAccess.selected instanceof JCTree.JCFieldAccess &&
fieldAccess.selected.toString().equals(CLASS_NAME_PRIVATE_ACCESSOR_FULL);
}
private boolean checkParameterCount(Map<String, List<Integer>> methods, String target, int parameterCount) {
for (Integer expectCount : methods.get(target)) {
if (countMatch(parameterCount, expectCount)) {

View File

@ -22,7 +22,8 @@ public class TestableLogger {
}
public void warn(String msg) {
messager.printMessage(Diagnostic.Kind.WARNING, msg);
// Message level WARNING won't show, use MANDATORY_WARNING instead
messager.printMessage(Diagnostic.Kind.MANDATORY_WARNING, msg);
}
public void error(String msg) {