| 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); |
| } |
| } |