org.checkerframework.checker.fenum.FenumVisitor 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.fenum;
import com.sun.source.tree.BinaryTree;
import com.sun.source.tree.CaseTree;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.NewClassTree;
import com.sun.source.tree.SwitchTree;
import com.sun.source.tree.Tree;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.ExecutableElement;
import org.checkerframework.common.basetype.BaseTypeChecker;
import org.checkerframework.common.basetype.BaseTypeVisitor;
import org.checkerframework.framework.type.AnnotatedTypeMirror;
import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType;
import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType;
import org.checkerframework.framework.type.QualifierHierarchy;
import org.checkerframework.javacutil.TreeUtils;
public class FenumVisitor extends BaseTypeVisitor {
public FenumVisitor(BaseTypeChecker checker) {
super(checker);
}
@Override
public Void visitBinary(BinaryTree node, Void p) {
if (!TreeUtils.isStringConcatenation(node)) {
// TODO: ignore string concatenations
// The Fenum Checker is only concerned with primitive types, so just check that
// the primary annotations are equivalent.
AnnotatedTypeMirror lhsAtm = atypeFactory.getAnnotatedType(node.getLeftOperand());
AnnotatedTypeMirror rhsAtm = atypeFactory.getAnnotatedType(node.getRightOperand());
Set lhs = lhsAtm.getEffectiveAnnotations();
Set rhs = rhsAtm.getEffectiveAnnotations();
QualifierHierarchy qualHierarchy = atypeFactory.getQualifierHierarchy();
if (!(qualHierarchy.isSubtype(lhs, rhs) || qualHierarchy.isSubtype(rhs, lhs))) {
checker.reportError(node, "binary", lhsAtm, rhsAtm);
}
}
return super.visitBinary(node, p);
}
@Override
public Void visitSwitch(SwitchTree node, Void p) {
ExpressionTree expr = node.getExpression();
AnnotatedTypeMirror exprType = atypeFactory.getAnnotatedType(expr);
for (CaseTree caseExpr : node.getCases()) {
List realCaseExprs = TreeUtils.caseTreeGetExpressions(caseExpr);
// Check all the case options against the switch expression type:
for (ExpressionTree realCaseExpr : realCaseExprs) {
AnnotatedTypeMirror caseType = atypeFactory.getAnnotatedType(realCaseExpr);
// There is currently no "switch" message key, so it is treated
// identically to "type.incompatible".
this.commonAssignmentCheck(exprType, caseType, caseExpr, "type.incompatible");
}
}
return super.visitSwitch(node, p);
}
@Override
protected void checkConstructorInvocation(
AnnotatedDeclaredType dt, AnnotatedExecutableType constructor, NewClassTree src) {
// Ignore the default annotation on the constructor
}
@Override
protected void checkConstructorResult(
AnnotatedExecutableType constructorType, ExecutableElement constructorElement) {
// Skip this check
}
@Override
protected Set getExceptionParameterLowerBoundAnnotations() {
return Collections.singleton(atypeFactory.FENUM_UNQUALIFIED);
}
// TODO: should we require a match between switch expression and cases?
@Override
public boolean isValidUse(
AnnotatedDeclaredType declarationType, AnnotatedDeclaredType useType, Tree tree) {
// The checker calls this method to compare the annotation used in a type to the modifier it
// adds to the class declaration. As our default modifier is FenumBottom, this results in an
// error when a non-subtype is used. Can we use FenumTop as default instead?
return true;
}
}