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

org.checkerframework.dataflow.cfg.UnderlyingAST 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.dataflow.cfg;

import com.sun.source.tree.ClassTree;
import com.sun.source.tree.LambdaExpressionTree;
import com.sun.source.tree.MethodTree;
import com.sun.source.tree.Tree;
import java.util.concurrent.atomic.AtomicLong;
import org.checkerframework.checker.initialization.qual.UnknownInitialization;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.plumelib.util.StringsPlume;
import org.plumelib.util.UniqueId;

/**
 * Represents an abstract syntax tree of type {@link Tree} that underlies a given control flow
 * graph.
 */
public abstract class UnderlyingAST implements UniqueId {
  /** The kinds of underlying ASTs. */
  public enum Kind {
    /** The underlying code is a whole method. */
    METHOD,
    /** The underlying code is a lambda expression. */
    LAMBDA,

    /** The underlying code is an arbitrary Java statement or expression. */
    ARBITRARY_CODE,
  }

  /** The kind of the underlying AST. */
  protected final Kind kind;

  /** The unique ID for the next-created object. */
  private static final AtomicLong nextUid = new AtomicLong(0);

  /** The unique ID of this object. */
  private final transient long uid = nextUid.getAndIncrement();

  @Override
  public long getUid(@UnknownInitialization UnderlyingAST this) {
    return uid;
  }

  /**
   * Creates an UnderlyingAST.
   *
   * @param kind the kind of the AST
   */
  protected UnderlyingAST(Kind kind) {
    this.kind = kind;
  }

  /**
   * Returns the code that corresponds to the CFG. For a method or lamdda, this returns the body.
   * For other constructs, it returns the tree itself (a statement or expression).
   *
   * @return the code that corresponds to the CFG
   */
  public abstract Tree getCode();

  public Kind getKind() {
    return kind;
  }

  /** If the underlying AST is a method. */
  public static class CFGMethod extends UnderlyingAST {

    /** The method declaration. */
    protected final MethodTree method;

    /** The class tree this method belongs to. */
    protected final ClassTree classTree;

    public CFGMethod(MethodTree method, ClassTree classTree) {
      super(Kind.METHOD);
      this.method = method;
      this.classTree = classTree;
    }

    @Override
    public Tree getCode() {
      return method.getBody();
    }

    public MethodTree getMethod() {
      return method;
    }

    /**
     * Returns the name of the method.
     *
     * @return the name of the method
     */
    public String getMethodName() {
      return method.getName().toString();
    }

    /**
     * Returns the class tree this method belongs to.
     *
     * @return the class tree this method belongs to
     */
    public ClassTree getClassTree() {
      return classTree;
    }

    /**
     * Returns the simple name of the enclosing class.
     *
     * @return the simple name of the enclosing class
     */
    public String getSimpleClassName() {
      return classTree.getSimpleName().toString();
    }

    @Override
    public String toString() {
      return StringsPlume.joinLines("CFGMethod(", method, ")");
    }
  }

  /** If the underlying AST is a lambda. */
  public static class CFGLambda extends UnderlyingAST {

    /** The lambda expression. */
    private final LambdaExpressionTree lambda;

    /** The enclosing class of the lambda. */
    private final ClassTree classTree;

    /** The enclosing method of the lambda. */
    private final @Nullable MethodTree enclosingMethod;

    /**
     * Create a new CFGLambda.
     *
     * @param lambda the lambda expression
     * @param classTree the enclosing class of the lambda
     * @param enclosingMethod the enclosing method of the lambda
     */
    public CFGLambda(
        LambdaExpressionTree lambda, ClassTree classTree, @Nullable MethodTree enclosingMethod) {
      super(Kind.LAMBDA);
      this.lambda = lambda;
      this.enclosingMethod = enclosingMethod;
      this.classTree = classTree;
    }

    @Override
    public Tree getCode() {
      return lambda.getBody();
    }

    /**
     * Returns the lambda expression tree.
     *
     * @return the lambda expression tree
     */
    public LambdaExpressionTree getLambdaTree() {
      return lambda;
    }

    /**
     * Returns the enclosing class of the lambda.
     *
     * @return the enclosing class of the lambda
     */
    public ClassTree getClassTree() {
      return classTree;
    }

    /**
     * Returns the simple name of the enclosing class.
     *
     * @return the simple name of the enclosing class
     */
    public String getSimpleClassName() {
      return classTree.getSimpleName().toString();
    }

    /**
     * Returns the enclosing method of the lambda.
     *
     * @return the enclosing method of the lambda, or {@code null} if there is no enclosing method
     * @deprecated use #getEnclosingMethod()
     */
    @Deprecated // 2022-01-23
    public @Nullable MethodTree getMethod() {
      return enclosingMethod;
    }

    /**
     * Returns the enclosing method of the lambda.
     *
     * @return the enclosing method of the lambda, or {@code null} if there is no enclosing method
     */
    public @Nullable MethodTree getEnclosingMethod() {
      return enclosingMethod;
    }

    /**
     * Returns the name of the enclosing method of the lambda.
     *
     * @return the name of the enclosing method of the lambda, or {@code null} if there is no
     *     enclosing method
     * @deprecated use #getEnclosingMethodName()
     */
    @Deprecated // 2022-01-23
    public @Nullable String getMethodName() {
      return enclosingMethod == null ? null : enclosingMethod.getName().toString();
    }

    /**
     * Returns the name of the enclosing method of the lambda.
     *
     * @return the name of the enclosing method of the lambda, or {@code null} if there is no
     *     enclosing method
     */
    public @Nullable String getEnclosingMethodName() {
      return enclosingMethod == null ? null : enclosingMethod.getName().toString();
    }

    @Override
    public String toString() {
      return StringsPlume.joinLines("CFGLambda(", lambda, ")");
    }
  }

  /**
   * If the underlying AST is a statement or expression. This is for field definitions (with
   * initializers) and initializer blocks.
   */
  public static class CFGStatement extends UnderlyingAST {

    protected final Tree code;

    /** The class tree this method belongs to. */
    protected final ClassTree classTree;

    public CFGStatement(Tree code, ClassTree classTree) {
      super(Kind.ARBITRARY_CODE);
      this.code = code;
      this.classTree = classTree;
    }

    @Override
    public Tree getCode() {
      return code;
    }

    public ClassTree getClassTree() {
      return classTree;
    }

    /**
     * Returns the simple name of the enclosing class.
     *
     * @return the simple name of the enclosing class
     */
    public String getSimpleClassName() {
      return classTree.getSimpleName().toString();
    }

    @Override
    public String toString() {
      return StringsPlume.joinLines("CFGStatement(", code, ")");
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy