in nullaway/src/main/java/com/uber/nullaway/handlers/AbstractFieldContractHandler.java [110:240]
protected abstract void validateOverridingRules(
Set<String> fieldNames,
NullAway analysis,
VisitorState state,
MethodTree tree,
Symbol.MethodSymbol overriddenMethod);
/**
* Validates that a method implementation matches the semantics of the annotation.
*
* @return Returns true, if the annotation conforms to the semantic rules.
* @param methodAnalysisContext The MethodAnalysisContext object
*/
protected abstract boolean validateAnnotationSemantics(
MethodTree tree, MethodAnalysisContext methodAnalysisContext);
/**
* Validates whether the parameter inside annotation conforms to the syntax rules. Parameters must
* conform to the following rules:
*
* <p>
*
* <ul>
* <li>Cannot annotate a method with empty param set.
* <li>The receiver of selected fields in annotation can only be the receiver of the method.
* <li>All parameters given in the annotation must be one of the fields of the class or its
* super classes.
* </ul>
*
* <p>
*
* @return Returns true, if the annotation conforms to the syntax rules.
* @param methodAnalysisContext The MethodAnalysisContext object
*/
protected boolean validateAnnotationSyntax(
Set<String> content, MethodTree tree, MethodAnalysisContext methodAnalysisContext) {
String message;
VisitorState state = methodAnalysisContext.state();
NullAway analysis = methodAnalysisContext.analysis();
if (content.isEmpty()) {
// we should not allow useless annotations.
message =
"empty @"
+ annotName
+ " is the default precondition for every method, please remove it.";
state.reportMatch(
analysis
.getErrorBuilder()
.createErrorDescription(
new ErrorMessage(ErrorMessage.MessageTypes.ANNOTATION_VALUE_INVALID, message),
tree,
analysis.buildDescription(tree),
state,
null));
return false;
} else {
Symbol.ClassSymbol classSymbol =
castToNonNull(ASTHelpers.enclosingClass(methodAnalysisContext.methodSymbol()));
for (String fieldName : content) {
if (isThisDotStaticField(classSymbol, fieldName)) {
message =
"Cannot refer to static field "
+ fieldName.substring(THIS_NOTATION.length())
+ " using this.";
state.reportMatch(
analysis
.getErrorBuilder()
.createErrorDescription(
new ErrorMessage(ErrorMessage.MessageTypes.ANNOTATION_VALUE_INVALID, message),
tree,
analysis.buildDescription(tree),
state,
null));
return false;
}
VariableElement field = getFieldOfClass(classSymbol, fieldName);
if (field != null) {
if (field.getModifiers().contains(Modifier.STATIC)) {
continue;
}
}
if (fieldName.contains(".")) {
if (!fieldName.startsWith(THIS_NOTATION)) {
message =
"currently @"
+ annotName
+ " supports only class fields of the method receiver: "
+ fieldName
+ " is not supported";
state.reportMatch(
analysis
.getErrorBuilder()
.createErrorDescription(
new ErrorMessage(
ErrorMessage.MessageTypes.ANNOTATION_VALUE_INVALID, message),
tree,
analysis.buildDescription(tree),
state,
null));
return false;
} else {
fieldName = fieldName.substring(fieldName.lastIndexOf(".") + 1);
}
}
field = getFieldOfClass(classSymbol, fieldName);
if (field == null) {
message =
"For @"
+ annotName
+ " annotation, cannot find instance field "
+ fieldName
+ " in class "
+ classSymbol.getSimpleName();
state.reportMatch(
analysis
.getErrorBuilder()
.createErrorDescription(
new ErrorMessage(ErrorMessage.MessageTypes.ANNOTATION_VALUE_INVALID, message),
tree,
analysis.buildDescription(tree),
state,
null));
return false;
}
}
}
return true;
}