package org.checkerframework.checker.index.searchindex; import java.util.List; import javax.lang.model.element.AnnotationMirror; import org.checkerframework.checker.index.IndexAbstractTransfer; import org.checkerframework.checker.index.IndexUtil; import org.checkerframework.checker.index.qual.NegativeIndexFor; import org.checkerframework.checker.index.qual.SearchIndexFor; import org.checkerframework.dataflow.analysis.FlowExpressions; import org.checkerframework.dataflow.analysis.TransferInput; import org.checkerframework.dataflow.cfg.node.Node; import org.checkerframework.framework.flow.CFAnalysis; import org.checkerframework.framework.flow.CFStore; import org.checkerframework.framework.flow.CFValue; /** * The transfer function for the SearchIndexFor checker. Allows {@link SearchIndexFor} to be refined * to {@link NegativeIndexFor}. */ public class SearchIndexTransfer extends IndexAbstractTransfer { // The ATF (Annotated Type Factory). private SearchIndexAnnotatedTypeFactory aTypeFactory; public SearchIndexTransfer(CFAnalysis analysis) { super(analysis); aTypeFactory = (SearchIndexAnnotatedTypeFactory) analysis.getTypeFactory(); } /** * If a {@link SearchIndexFor} value is negative, then refine it to {@link NegativeIndexFor}. * This method is called by refinement rules for binary comparison operators. * * <p>If the left value (in a greater-than or greater-than-or-equal binary comparison) is * exactly the value of {@code valueToCompareTo}, and the right side has type {@link * SearchIndexFor}, then the right side's new value in the store should become {@link * NegativeIndexFor}. * * <p>For example, this allows the following code to typecheck: * * <pre> * <code> * {@literal @}SearchIndexFor("a") int index = Arrays.binarySearch(a, y); * if (index < 0) { * {@literal @}NegativeIndexFor("a") int negInsertionPoint = index; * } * </code> * </pre> * * @param valueToCompareTo This value must be 0 (for greater than or less than) or -1 (for * greater than or equal or less than or equal). */ private void refineSearchIndexToNegativeIndexFor( Node left, Node right, CFStore store, int valueToCompareTo) { assert valueToCompareTo == 0 || valueToCompareTo == -1; Long leftValue = IndexUtil.getExactValue( left.getTree(), aTypeFactory.getValueAnnotatedTypeFactory()); if (leftValue != null && leftValue == valueToCompareTo) { AnnotationMirror rightSI = aTypeFactory.getAnnotationMirror(right.getTree(), SearchIndexFor.class); if (rightSI != null) { List<String> arrays = IndexUtil.getValueOfAnnotationWithStringArgument(rightSI); AnnotationMirror nif = aTypeFactory.createNegativeIndexFor(arrays); store.insertValue( FlowExpressions.internalReprOf(analysis.getTypeFactory(), right), nif); } } } @Override protected void refineGT( Node left, AnnotationMirror leftAnno, Node right, AnnotationMirror rightAnno, CFStore store, TransferInput<CFValue, CFStore> in) { refineSearchIndexToNegativeIndexFor(left, right, store, 0); } @Override protected void refineGTE( Node left, AnnotationMirror leftAnno, Node right, AnnotationMirror rightAnno, CFStore store, TransferInput<CFValue, CFStore> in) { refineSearchIndexToNegativeIndexFor(left, right, store, -1); } }