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; 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.util.List; import java.util.Set; import javax.annotation.processing.ProcessingEnvironment; import javax.lang.model.element.AnnotationMirror; import javax.lang.model.type.TypeVariable; import org.checkerframework.framework.type.AnnotatedTypeMirror; 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 { public CFTreeBuilder(ProcessingEnvironment env) { super(env); } /** * Builds an AST Tree representing an AnnotatedTypeMirror. * * @param annotatedType the annotated type * @return a Tree representing the annotated type */ public Tree buildAnnotatedType(AnnotatedTypeMirror annotatedType) { return createAnnotatedType(annotatedType); } private Tree createAnnotatedType(AnnotatedTypeMirror annotatedType) { // Implementation based on com.sun.tools.javac.tree.TreeMaker.Type // Convert the annotations from a set of AnnotationMirrors // to a list of AnnotationTrees. Set<AnnotationMirror> annotations = annotatedType.getAnnotations(); List<JCTree.JCAnnotation> annotationTrees = List.nil(); for (AnnotationMirror am : annotations) { // TODO: what TypeAnnotationPosition should be used? Attribute.TypeCompound typeCompound = TypeAnnotationUtils.createTypeCompoundFromAnnotationMirror( env, am, TypeAnnotationUtils.unknownTAPosition()); JCTree.JCAnnotation annotationTree = maker.Annotation(typeCompound); JCTree.JCAnnotation typeAnnotationTree = maker.TypeAnnotation( annotationTree.getAnnotationType(), annotationTree.getArguments()); typeAnnotationTree.attribute = typeCompound; annotationTrees = annotationTrees.append(typeAnnotationTree); } // Convert the underlying type from a TypeMirror to an // ExpressionTree and combine with the AnnotationTrees // to form a ClassTree of kind ANNOTATION_TYPE. Tree underlyingTypeTree; switch (annotatedType.getKind()) { case BYTE: underlyingTypeTree = maker.TypeIdent(TypeTag.BYTE); break; case CHAR: underlyingTypeTree = maker.TypeIdent(TypeTag.BYTE); break; case SHORT: underlyingTypeTree = maker.TypeIdent(TypeTag.SHORT); break; case INT: underlyingTypeTree = maker.TypeIdent(TypeTag.INT); break; case LONG: underlyingTypeTree = maker.TypeIdent(TypeTag.LONG); break; case FLOAT: underlyingTypeTree = maker.TypeIdent(TypeTag.FLOAT); break; case DOUBLE: underlyingTypeTree = maker.TypeIdent(TypeTag.DOUBLE); break; case BOOLEAN: underlyingTypeTree = maker.TypeIdent(TypeTag.BOOLEAN); break; case VOID: underlyingTypeTree = maker.TypeIdent(TypeTag.VOID); break; case TYPEVAR: { // No recursive annotations. AnnotatedTypeMirror.AnnotatedTypeVariable variable = (AnnotatedTypeMirror.AnnotatedTypeVariable) annotatedType; TypeVariable underlyingTypeVar = variable.getUnderlyingType(); underlyingTypeTree = maker.Ident((Symbol.TypeSymbol) (underlyingTypeVar).asElement()); break; } case WILDCARD: { AnnotatedTypeMirror.AnnotatedWildcardType wildcard = (AnnotatedTypeMirror.AnnotatedWildcardType) annotatedType; if (wildcard.getExtendsBound() != null) { Tree annotatedExtendsBound = createAnnotatedType(wildcard.getExtendsBound()); underlyingTypeTree = maker.Wildcard( maker.TypeBoundKind(BoundKind.EXTENDS), (JCTree) annotatedExtendsBound); } else if (wildcard.getSuperBound() != null) { Tree annotatedSuperBound = createAnnotatedType(wildcard.getSuperBound()); underlyingTypeTree = maker.Wildcard( maker.TypeBoundKind(BoundKind.SUPER), (JCTree) annotatedSuperBound); } else { underlyingTypeTree = maker.Wildcard( maker.TypeBoundKind(BoundKind.UNBOUND), maker.TypeIdent(TypeTag.VOID)); } break; } case DECLARED: { underlyingTypeTree = maker.Type((Type) annotatedType.getUnderlyingType()); if (underlyingTypeTree instanceof JCTree.JCTypeApply) { // Replace the type parameters with annotated versions. AnnotatedTypeMirror.AnnotatedDeclaredType annotatedDeclaredType = (AnnotatedTypeMirror.AnnotatedDeclaredType) annotatedType; List<JCTree.JCExpression> typeArgTrees = List.nil(); for (AnnotatedTypeMirror arg : annotatedDeclaredType.getTypeArguments()) { typeArgTrees = typeArgTrees.append( (JCTree.JCExpression) createAnnotatedType(arg)); } JCTree.JCExpression clazz = (JCTree.JCExpression) ((JCTree.JCTypeApply) underlyingTypeTree).getType(); underlyingTypeTree = maker.TypeApply(clazz, typeArgTrees); } break; } case ARRAY: { AnnotatedTypeMirror.AnnotatedArrayType annotatedArrayType = (AnnotatedTypeMirror.AnnotatedArrayType) annotatedType; Tree annotatedComponentTree = createAnnotatedType(annotatedArrayType.getComponentType()); underlyingTypeTree = maker.TypeArray((JCTree.JCExpression) annotatedComponentTree); break; } case ERROR: underlyingTypeTree = maker.TypeIdent(TypeTag.ERROR); break; default: assert false : "unexpected type: " + annotatedType; underlyingTypeTree = null; break; } ((JCTree) underlyingTypeTree).setType((Type) annotatedType.getUnderlyingType()); if (annotationTrees.isEmpty()) { return underlyingTypeTree; } JCTree.JCAnnotatedType annotatedTypeTree = maker.AnnotatedType(annotationTrees, (JCTree.JCExpression) underlyingTypeTree); annotatedTypeTree.setType((Type) annotatedType.getUnderlyingType()); return annotatedTypeTree; } }