checker.src.org.checkerframework.checker.formatter.FormatterVisitor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of checker Show documentation
Show all versions of checker Show documentation
The Checker Framework enhances Java’s type system to
make it more powerful and useful. This lets software developers
detect and prevent errors in their Java programs.
The Checker Framework includes compiler plug-ins ("checkers")
that find bugs or verify their absence. It also permits you to
write your own compiler plug-ins.
package org.checkerframework.checker.formatter;
/*>>>
import org.checkerframework.checker.compilermsgs.qual.CompilerMessageKey;
*/
import org.checkerframework.checker.formatter.FormatterTreeUtil.FormatCall;
import org.checkerframework.checker.formatter.FormatterTreeUtil.InvocationType;
import org.checkerframework.checker.formatter.FormatterTreeUtil.Result;
import org.checkerframework.checker.formatter.qual.ConversionCategory;
import org.checkerframework.common.basetype.BaseTypeChecker;
import org.checkerframework.common.basetype.BaseTypeVisitor;
import org.checkerframework.framework.type.AnnotatedTypeMirror;
import org.checkerframework.javacutil.AnnotationUtils;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.type.TypeMirror;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.source.tree.Tree;
/**
* Whenever a format method invocation is found in the syntax tree,
* the following checks happen, read the code, seriously! (otherwise see manual 12.2)
*
* @author Konstantin Weitz
*/
public class FormatterVisitor extends BaseTypeVisitor {
public FormatterVisitor(BaseTypeChecker checker) {
super(checker);
}
@Override
public Void visitMethodInvocation(MethodInvocationTree node, Void p) {
FormatterTreeUtil tu = atypeFactory.treeUtil;
if (tu.isFormatCall(node, atypeFactory)) {
FormatCall fc = atypeFactory.treeUtil.new FormatCall(node, atypeFactory);
Result sat = fc.isIllegalFormat();
if (sat.value() != null) {
// I.1
tu.failure(sat, "format.string.invalid", sat.value());
} else {
Result invc = fc.getInvocationType();
ConversionCategory[] formatCats = fc.getFormatCategories();
switch (invc.value()) {
case VARARG:
Result[] paramTypes = fc.getParamTypes();
int paraml = paramTypes.length;
int formatl = formatCats.length;
if (paraml < formatl) {
// For assignments, format.missing.arguments is issued
// from commonAssignmentCheck.
// II.1
tu.failure(invc, "format.missing.arguments", formatl, paraml);
} else {
if (paraml > formatl) {
// II.2
tu.warning(invc, "format.excess.arguments", formatl, paraml);
}
for (int i = 0; i < formatl; ++i) {
ConversionCategory formatCat = formatCats[i];
Result param = paramTypes[i];
TypeMirror paramType = param.value();
switch (formatCat) {
case UNUSED:
// I.2
tu.warning(param, "format.argument.unused"," "+(1+i));
break;
case NULL:
// I.3
tu.failure(param, "format.specifier.null"," "+(1+i));
break;
case GENERAL:
break;
default:
if (!fc.isValidParameter(formatCat, paramType)) {
// II.3
tu.failure(param, "argument.type.incompatible", paramType,
formatCat);
}
break;
}
}
}
break;
case NULLARRAY:
/* continue */
case ARRAY:
for (ConversionCategory cat : formatCats) {
if (cat == ConversionCategory.NULL) {
// I.3
tu.failure(invc, "format.specifier.null","");
}
if (cat == ConversionCategory.UNUSED) {
// I.2
tu.warning(invc, "format.argument.unused","");
}
}
// III
tu.warning(invc, "format.indirect.arguments");
break;
}
}
}
return super.visitMethodInvocation(node, p);
}
@Override
protected void commonAssignmentCheck(AnnotatedTypeMirror varType,
AnnotatedTypeMirror valueType, Tree valueTree, /*@CompilerMessageKey*/ String errorKey) {
super.commonAssignmentCheck(varType, valueType, valueTree, errorKey);
AnnotationMirror rhs = valueType.getAnnotationInHierarchy(atypeFactory.UNKNOWNFORMAT);
AnnotationMirror lhs = varType.getAnnotationInHierarchy(atypeFactory.UNKNOWNFORMAT);
// From the manual:
// It is legal to use a format string with fewer format specifiers
// than required, but a warning is issued.
// The format.missing.arguments warning is issued here for assignments.
// For method calls, it is issued in visitMethodInvocation.
if (AnnotationUtils.areSameIgnoringValues(rhs, atypeFactory.FORMAT) &&
AnnotationUtils.areSameIgnoringValues(lhs, atypeFactory.FORMAT)) {
ConversionCategory[] rhsArgTypes =
atypeFactory.treeUtil.formatAnnotationToCategories(rhs);
ConversionCategory[] lhsArgTypes =
atypeFactory.treeUtil.formatAnnotationToCategories(lhs);
if (rhsArgTypes.length < lhsArgTypes.length) {
checker.report(org.checkerframework.framework.source.Result.warning("format.missing.arguments",
varType.toString(), valueType.toString()), valueTree);
}
}
}
}