All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.checkerframework.checker.index.lowerbound.LowerBoundVisitor Maven / Gradle / Ivy

Go to download

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.

There is a newer version: 3.43.0
Show newest version
package org.checkerframework.checker.index.lowerbound;

import com.sun.source.tree.ArrayAccessTree;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.NewArrayTree;
import com.sun.source.tree.Tree;
import javax.lang.model.element.AnnotationMirror;
import org.checkerframework.checker.compilermsgs.qual.CompilerMessageKey;
import org.checkerframework.checker.index.Subsequence;
import org.checkerframework.checker.index.qual.NonNegative;
import org.checkerframework.checker.index.qual.Positive;
import org.checkerframework.common.basetype.BaseTypeChecker;
import org.checkerframework.common.basetype.BaseTypeVisitor;
import org.checkerframework.framework.type.AnnotatedTypeMirror;
import org.checkerframework.framework.util.JavaExpressionParseUtil;

/**
 * Implements the actual checks to make sure that array accesses aren't too low. Will issue a
 * warning if a variable that can't be proved to be either "NonNegative" (i.e. ≥ 0) or "Positive"
 * (i.e. ≥ 1) is used as an array index.
 */
public class LowerBoundVisitor extends BaseTypeVisitor {

  /* This is a key into the messages.properties file in the same
   * directory, which includes the actual text of the warning.
   */
  private static final @CompilerMessageKey String LOWER_BOUND = "array.access.unsafe.low";
  private static final @CompilerMessageKey String NEGATIVE_ARRAY = "array.length.negative";
  private static final @CompilerMessageKey String FROM_NOT_NN = "from.not.nonnegative";

  public LowerBoundVisitor(BaseTypeChecker checker) {
    super(checker);
  }

  @Override
  public Void visitArrayAccess(ArrayAccessTree tree, Void type) {
    ExpressionTree index = tree.getIndex();
    String arrName = tree.getExpression().toString();
    AnnotatedTypeMirror indexType = atypeFactory.getAnnotatedType(index);
    if (!(indexType.hasPrimaryAnnotation(NonNegative.class)
        || indexType.hasPrimaryAnnotation(Positive.class))) {
      checker.reportError(index, LOWER_BOUND, indexType.toString(), arrName);
    }

    return super.visitArrayAccess(tree, type);
  }

  @Override
  public Void visitNewArray(NewArrayTree tree, Void type) {
    if (!tree.getDimensions().isEmpty()) {
      for (ExpressionTree dim : tree.getDimensions()) {
        AnnotatedTypeMirror dimType = atypeFactory.getAnnotatedType(dim);
        if (!(dimType.hasPrimaryAnnotation(NonNegative.class)
            || dimType.hasPrimaryAnnotation(Positive.class))) {
          checker.reportError(dim, NEGATIVE_ARRAY, dimType.toString());
        }
      }
    }

    return super.visitNewArray(tree, type);
  }

  @Override
  protected boolean 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 is non-negative.

    boolean result = true;

    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;
      }
      if (anm == null
          || !(atypeFactory.areSameByClass(anm, NonNegative.class)
              || atypeFactory.areSameByClass(anm, Positive.class))) {
        checker.reportError(
            valueTree, FROM_NOT_NN, subSeq.from, anm == null ? "@LowerBoundUnknown" : anm);
        result = false;
      }
    }

    result = super.commonAssignmentCheck(varTree, valueTree, errorKey, extraArgs) && result;
    return result;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy