blob: e64cc77fdf0b313f240dac423a8c6e0be6c3762d [file] [log] [blame]
package org.checkerframework.checker.index.inequality;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.IdentifierTree;
import com.sun.source.tree.Tree;
import java.util.List;
import javax.lang.model.element.AnnotationMirror;
import org.checkerframework.checker.compilermsgs.qual.CompilerMessageKey;
import org.checkerframework.checker.index.Subsequence;
import org.checkerframework.checker.index.upperbound.OffsetEquation;
import org.checkerframework.common.basetype.BaseTypeChecker;
import org.checkerframework.common.basetype.BaseTypeVisitor;
import org.checkerframework.framework.type.AnnotatedTypeMirror;
import org.checkerframework.framework.util.JavaExpressionParseUtil;
import org.plumelib.util.CollectionsPlume;
/** The visitor for the Less Than Checker. */
public class LessThanVisitor extends BaseTypeVisitor<LessThanAnnotatedTypeFactory> {
private static final @CompilerMessageKey String FROM_GT_TO = "from.gt.to";
public LessThanVisitor(BaseTypeChecker checker) {
super(checker);
}
@Override
protected void commonAssignmentCheck(
Tree varTree,
ExpressionTree valueTree,
@CompilerMessageKey String errorKey,
Object... extraArgs) {
// check that when an assignment to a variable declared as @HasSubsequence(a, from, to)
// occurs, from <= to.
Subsequence subSeq = Subsequence.getSubsequenceFromTree(varTree, atypeFactory);
if (subSeq != null) {
AnnotationMirror anm;
try {
anm =
atypeFactory.getAnnotationMirrorFromJavaExpressionString(
subSeq.from, varTree, getCurrentPath());
} catch (JavaExpressionParseUtil.JavaExpressionParseException e) {
anm = null;
}
LessThanAnnotatedTypeFactory factory = getTypeFactory();
if (anm == null || !factory.isLessThanOrEqual(anm, subSeq.to)) {
// issue an error
checker.reportError(
valueTree,
FROM_GT_TO,
subSeq.from,
subSeq.to,
anm == null ? "@LessThanUnknown" : anm,
subSeq.to,
subSeq.to);
}
}
super.commonAssignmentCheck(varTree, valueTree, errorKey, extraArgs);
}
@Override
protected void commonAssignmentCheck(
AnnotatedTypeMirror varType,
AnnotatedTypeMirror valueType,
Tree valueTree,
@CompilerMessageKey String errorKey,
Object... extraArgs) {
// If value is less than all expressions in the annotation in varType,
// using the Value Checker, then skip the common assignment check.
// Also skip the check if the only expression is "a + 1" and the valueTree is "a".
List<String> expressions =
getTypeFactory()
.getLessThanExpressions(
varType.getEffectiveAnnotationInHierarchy(atypeFactory.LESS_THAN_UNKNOWN));
if (expressions != null) {
boolean isLessThan = true;
for (String expression : expressions) {
if (!atypeFactory.isLessThanByValue(valueTree, expression, getCurrentPath())) {
isLessThan = false;
}
}
if (!isLessThan && expressions.size() == 1) {
String expression = expressions.get(0);
if (expression.endsWith(" + 1")) {
String value = expression.substring(0, expression.length() - 4);
if (valueTree.getKind() == Tree.Kind.IDENTIFIER) {
String id = ((IdentifierTree) valueTree).getName().toString();
if (id.equals(value)) {
isLessThan = true;
}
}
}
}
if (isLessThan) {
// Print the messages because super isn't called.
commonAssignmentCheckStartDiagnostic(varType, valueType, valueTree);
commonAssignmentCheckEndDiagnostic(true, "isLessThan", varType, valueType, valueTree);
// skip call to super, everything is OK.
return;
}
}
super.commonAssignmentCheck(varType, valueType, valueTree, errorKey, extraArgs);
}
@Override
protected boolean isTypeCastSafe(AnnotatedTypeMirror castType, AnnotatedTypeMirror exprType) {
AnnotationMirror exprLTAnno =
exprType.getEffectiveAnnotationInHierarchy(atypeFactory.LESS_THAN_UNKNOWN);
if (exprLTAnno != null) {
LessThanAnnotatedTypeFactory factory = getTypeFactory();
List<String> initialAnnotations = factory.getLessThanExpressions(exprLTAnno);
if (initialAnnotations != null) {
List<String> updatedAnnotations =
CollectionsPlume.mapList(
annotation -> OffsetEquation.createOffsetFromJavaExpression(annotation).toString(),
initialAnnotations);
exprType.replaceAnnotation(atypeFactory.createLessThanQualifier(updatedAnnotations));
}
}
return super.isTypeCastSafe(castType, exprType);
}
}