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

org.checkerframework.checker.index.IndexMethodIdentifier 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.44.0
Show newest version
package org.checkerframework.checker.index;

import com.sun.source.tree.MethodInvocationTree;
import com.sun.source.tree.Tree;
import java.util.List;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.ExecutableElement;
import org.checkerframework.checker.index.qual.LengthOf;
import org.checkerframework.dataflow.cfg.node.MethodAccessNode;
import org.checkerframework.dataflow.cfg.node.MethodInvocationNode;
import org.checkerframework.dataflow.cfg.node.Node;
import org.checkerframework.framework.type.AnnotatedTypeFactory;
import org.checkerframework.javacutil.AnnotationUtils;
import org.checkerframework.javacutil.TreeUtils;

/**
 * Given a Tree or other construct, this class has methods to query whether it is a particular
 * method call.
 */
public class IndexMethodIdentifier {

  /** The {@code java.lang.Math#random()} method. */
  private final ExecutableElement mathRandom;
  /** The {@code java.util.Random#nextDouble()} method. */
  private final ExecutableElement randomNextDouble;
  /** The {@code java.util.Random#nextInt()} method. */
  private final ExecutableElement randomNextInt;
  /** The {@code java.lang.String#length()} method. */
  private final ExecutableElement stringLength;
  /** The {@code java.lang.Math#min()} methods. */
  private final List mathMinMethods;
  /** The {@code java.lang.Math#max()} methods. */
  private final List mathMaxMethods;

  /** The LengthOf.value argument/element. */
  private final ExecutableElement lengthOfValueElement;

  /** The type factory. */
  private final AnnotatedTypeFactory factory;

  public IndexMethodIdentifier(AnnotatedTypeFactory factory) {
    this.factory = factory;
    ProcessingEnvironment processingEnv = factory.getProcessingEnv();
    mathRandom = TreeUtils.getMethod("java.lang.Math", "random", 0, processingEnv);
    randomNextDouble = TreeUtils.getMethod("java.util.Random", "nextDouble", 0, processingEnv);
    randomNextInt = TreeUtils.getMethod("java.util.Random", "nextInt", 1, processingEnv);

    stringLength = TreeUtils.getMethod("java.lang.String", "length", 0, processingEnv);

    mathMinMethods = TreeUtils.getMethods("java.lang.Math", "min", 2, processingEnv);
    mathMaxMethods = TreeUtils.getMethods("java.lang.Math", "max", 2, processingEnv);

    lengthOfValueElement = TreeUtils.getMethod(LengthOf.class, "value", 0, processingEnv);
  }

  /** Returns true iff the argument is an invocation of Math.min. */
  public boolean isMathMin(Tree methodTree) {
    ProcessingEnvironment processingEnv = factory.getProcessingEnv();
    return TreeUtils.isMethodInvocation(methodTree, mathMinMethods, processingEnv);
  }

  /** Returns true iff the argument is an invocation of Math.max. */
  public boolean isMathMax(Tree methodTree) {
    ProcessingEnvironment processingEnv = factory.getProcessingEnv();
    return TreeUtils.isMethodInvocation(methodTree, mathMaxMethods, processingEnv);
  }

  /** Returns true iff the argument is an invocation of Math.random(). */
  public boolean isMathRandom(Tree tree, ProcessingEnvironment processingEnv) {
    return TreeUtils.isMethodInvocation(tree, mathRandom, processingEnv);
  }

  /** Returns true iff the argument is an invocation of Random.nextDouble(). */
  public boolean isRandomNextDouble(Tree tree, ProcessingEnvironment processingEnv) {
    return TreeUtils.isMethodInvocation(tree, randomNextDouble, processingEnv);
  }

  /** Returns true iff the argument is an invocation of Random.nextInt(). */
  public boolean isRandomNextInt(Tree tree, ProcessingEnvironment processingEnv) {
    return TreeUtils.isMethodInvocation(tree, randomNextInt, processingEnv);
  }

  /**
   * Returns true if {@code tree} is an invocation of a method that returns the length of "this"
   *
   * @param tree a tree
   * @return true if {@code tree} is an invocation of a method that returns the length of {@code
   *     this}
   */
  public boolean isLengthOfMethodInvocation(Tree tree) {
    if (tree.getKind() != Tree.Kind.METHOD_INVOCATION) {
      return false;
    }
    return isLengthOfMethodInvocation(TreeUtils.elementFromUse((MethodInvocationTree) tree));
  }

  /**
   * Returns true if {@code tree} evaluates to the length of "this". This might be a call to
   * String,length, or a method annotated with @LengthOf.
   *
   * @return true if {@code tree} evaluates to the length of "this"
   */
  public boolean isLengthOfMethodInvocation(ExecutableElement ele) {
    if (stringLength.equals(ele)) {
      // TODO: Why not just annotate String.length with @LengthOf and thus eliminate the
      // special case in this method's implementation?
      return true;
    }

    AnnotationMirror lengthOfAnno = factory.getDeclAnnotation(ele, LengthOf.class);
    if (lengthOfAnno == null) {
      return false;
    }
    AnnotationValue lengthOfValue = lengthOfAnno.getElementValues().get(lengthOfValueElement);
    return AnnotationUtils.annotationValueContains(lengthOfValue, "this");
  }

  /**
   * Returns true if {@code node} is an invocation of a method that returns the length of {@code
   * this}
   *
   * @param node a node
   * @return true if {@code node} is an invocation of a method that returns the length of {@code
   *     this}
   */
  public boolean isLengthOfMethodInvocation(Node node) {
    if (node instanceof MethodInvocationNode) {
      MethodInvocationNode methodInvocationNode = (MethodInvocationNode) node;
      MethodAccessNode methodAccessNode = methodInvocationNode.getTarget();
      ExecutableElement ele = methodAccessNode.getMethod();

      return isLengthOfMethodInvocation(ele);
    }
    return false;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy