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

org.checkerframework.framework.flow.CFTreeBuilder 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.framework.flow;

import com.sun.source.tree.Tree;
import com.sun.tools.javac.code.Attribute;
import com.sun.tools.javac.code.BoundKind;
import com.sun.tools.javac.code.Symbol.TypeSymbol;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.code.TypeTag;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.JCTree.JCAnnotatedType;
import com.sun.tools.javac.tree.JCTree.JCAnnotation;
import com.sun.tools.javac.tree.JCTree.JCExpression;
import com.sun.tools.javac.tree.JCTree.JCTypeApply;
import com.sun.tools.javac.util.List;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.type.ArrayType;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.IntersectionType;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.TypeVariable;
import javax.lang.model.type.WildcardType;
import org.checkerframework.javacutil.TypeAnnotationUtils;
import org.checkerframework.javacutil.trees.TreeBuilder;

/**
 * The TreeBuilder permits the creation of new AST Trees using the non-public Java compiler API
 * TreeMaker. Initially, it will support construction of desugared Trees required by the CFGBuilder,
 * e.g. the pieces of a desugared enhanced for loop.
 */
public class CFTreeBuilder extends TreeBuilder {

  /**
   * To avoid infinite recursions, record each wildcard that has been converted to a tree. This set
   * is cleared each time {@link #buildAnnotatedType(TypeMirror)} is called.
   */
  private final Set visitedWildcards = new HashSet<>();

  /**
   * Creates a {@code CFTreeBuilder}.
   *
   * @param env environment
   */
  public CFTreeBuilder(ProcessingEnvironment env) {
    super(env);
  }

  /**
   * Builds an AST Tree representing a type, including AnnotationTrees for its annotations.
   *
   * @param type the type
   * @return a Tree representing the type
   */
  public Tree buildAnnotatedType(TypeMirror type) {
    visitedWildcards.clear();
    return createAnnotatedType(type);
  }

  /**
   * Converts a list of AnnotationMirrors to the a corresponding list of new AnnotationTrees.
   *
   * @param annotations the annotations
   * @return new annotation trees representing the annotations
   */
  private List convertAnnotationMirrorsToAnnotationTrees(
      Collection annotations) {
    List annotationTrees = List.nil();

    for (AnnotationMirror am : annotations) {
      // TODO: what TypeAnnotationPosition should be used?
      Attribute.TypeCompound typeCompound =
          TypeAnnotationUtils.createTypeCompoundFromAnnotationMirror(
              am, TypeAnnotationUtils.unknownTAPosition(), env);
      JCAnnotation annotationTree = maker.Annotation(typeCompound);
      JCAnnotation typeAnnotationTree =
          maker.TypeAnnotation(annotationTree.getAnnotationType(), annotationTree.getArguments());

      typeAnnotationTree.attribute = typeCompound;

      annotationTrees = annotationTrees.append(typeAnnotationTree);
    }
    return annotationTrees;
  }

  /**
   * Builds an AST Tree representing a type, including AnnotationTrees for its annotations. This
   * internal method differs from the public {@link #buildAnnotatedType(TypeMirror)} only in that it
   * does not reset the list of visited wildcards.
   *
   * @param type the type for which to create a tree
   * @return a Tree representing the type
   */
  private Tree createAnnotatedType(TypeMirror type) {
    // Implementation based on com.sun.tools.javac.tree.TreeMaker.Type

    // Convert the annotations from a set of AnnotationMirrors
    // to a list of AnnotationTrees.
    java.util.List annotations = type.getAnnotationMirrors();
    List annotationTrees = convertAnnotationMirrorsToAnnotationTrees(annotations);

    // Convert the underlying type from a TypeMirror to an ExpressionTree and combine with the
    // AnnotationTrees to form a ClassTree of kind ANNOTATION_TYPE.
    JCExpression typeTree;
    switch (type.getKind()) {
      case BYTE:
        typeTree = maker.TypeIdent(TypeTag.BYTE);
        break;
      case CHAR:
        typeTree = maker.TypeIdent(TypeTag.CHAR);
        break;
      case SHORT:
        typeTree = maker.TypeIdent(TypeTag.SHORT);
        break;
      case INT:
        typeTree = maker.TypeIdent(TypeTag.INT);
        break;
      case LONG:
        typeTree = maker.TypeIdent(TypeTag.LONG);
        break;
      case FLOAT:
        typeTree = maker.TypeIdent(TypeTag.FLOAT);
        break;
      case DOUBLE:
        typeTree = maker.TypeIdent(TypeTag.DOUBLE);
        break;
      case BOOLEAN:
        typeTree = maker.TypeIdent(TypeTag.BOOLEAN);
        break;
      case VOID:
        typeTree = maker.TypeIdent(TypeTag.VOID);
        break;
      case TYPEVAR:
        // No recursive annotations.
        TypeVariable underlyingTypeVar = (TypeVariable) type;
        typeTree = maker.Ident((TypeSymbol) underlyingTypeVar.asElement());
        break;
      case WILDCARD:
        WildcardType wildcardType = (WildcardType) type;
        boolean visitedBefore = !visitedWildcards.add(wildcardType);
        if (!visitedBefore && wildcardType.getExtendsBound() != null) {
          Tree annotatedExtendsBound = createAnnotatedType(wildcardType.getExtendsBound());
          typeTree =
              maker.Wildcard(
                  maker.TypeBoundKind(BoundKind.EXTENDS), (JCTree) annotatedExtendsBound);
        } else if (!visitedBefore && wildcardType.getSuperBound() != null) {
          Tree annotatedSuperBound = createAnnotatedType(wildcardType.getSuperBound());
          typeTree =
              maker.Wildcard(maker.TypeBoundKind(BoundKind.SUPER), (JCTree) annotatedSuperBound);
        } else {
          typeTree = maker.Wildcard(maker.TypeBoundKind(BoundKind.UNBOUND), null);
        }
        break;
      case INTERSECTION:
        IntersectionType intersectionType = (IntersectionType) type;
        List components = List.nil();
        for (TypeMirror bound : intersectionType.getBounds()) {
          components = components.append((JCExpression) createAnnotatedType(bound));
        }
        typeTree = maker.TypeIntersection(components);
        break;
        // case UNION:
        // TODO: case UNION similar to INTERSECTION, but write test first.
      case DECLARED:
        typeTree = maker.Type((Type) type);

        if (typeTree instanceof JCTypeApply) {
          // Replace the type parameters with annotated versions.
          DeclaredType annotatedDeclaredType = (DeclaredType) type;
          List typeArgTrees = List.nil();
          for (TypeMirror arg : annotatedDeclaredType.getTypeArguments()) {
            typeArgTrees = typeArgTrees.append((JCExpression) createAnnotatedType(arg));
          }
          JCExpression clazz = (JCExpression) ((JCTypeApply) typeTree).getType();
          typeTree = maker.TypeApply(clazz, typeArgTrees);
        }
        break;
      case ARRAY:
        ArrayType arrayType = (ArrayType) type;
        Tree componentTree = createAnnotatedType(arrayType.getComponentType());
        typeTree = maker.TypeArray((JCExpression) componentTree);
        break;
      case ERROR:
        typeTree = maker.TypeIdent(TypeTag.ERROR);
        break;
      default:
        assert false : "unexpected type: " + type;
        typeTree = null;
        break;
    }

    typeTree.setType((Type) type);

    if (annotationTrees.isEmpty()) {
      return typeTree;
    }

    JCAnnotatedType annotatedTypeTree = maker.AnnotatedType(annotationTrees, typeTree);
    annotatedTypeTree.setType((Type) type);

    return annotatedTypeTree;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy