package org.checkerframework.framework.type; import com.sun.source.tree.ClassTree; import com.sun.source.tree.ExpressionTree; import com.sun.source.tree.Tree; import javax.lang.model.type.TypeKind; import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType; import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType; import org.checkerframework.javacutil.ErrorReporter; /** * A utility class to convert trees into corresponding AnnotatedTypeMirrors. This class should be * used ONLY from AnnotatedTypeFactory. * * <p>For each method in TypeFromTree there is a corresponding TypeFromTreeVisitor that handles the * input tree. The list of methods implemented by these visitors outline which trees each method * will support. If a tree kind is not handled by the given visitor, then execution is halted and an * RuntimeException is thrown which includes a list of supported tree types. */ class TypeFromTree { private static final TypeFromTypeTreeVisitor typeTreeVisitor = new TypeFromTypeTreeVisitor(); private static final TypeFromMemberVisitor memberVisitor = new TypeFromMemberVisitor(); private static final TypeFromClassVisitor classVisitor = new TypeFromClassVisitor(); private static final TypeFromExpressionVisitor expressionVisitor = new TypeFromExpressionVisitor(); /** * @param tree must be an ExpressionTree * @return an AnnotatedTypeMirror representing the input expression tree */ public static AnnotatedTypeMirror fromExpression( final AnnotatedTypeFactory typeFactory, final ExpressionTree tree) { abortIfTreeIsNull(typeFactory, tree); final AnnotatedTypeMirror type = expressionVisitor.visit(tree, typeFactory); ifExecutableCheckElement(typeFactory, tree, type); return type; } /** * @param tree must represent a class member * @return an AnnotatedTypeMirror representing the input tree */ public static AnnotatedTypeMirror fromMember( final AnnotatedTypeFactory typeFactory, final Tree tree) { abortIfTreeIsNull(typeFactory, tree); final AnnotatedTypeMirror type = memberVisitor.visit(tree, typeFactory); ifExecutableCheckElement(typeFactory, tree, type); return type; } /** * @param tree must be a type tree * @return an AnnotatedTypeMirror representing the input type tree */ public static AnnotatedTypeMirror fromTypeTree( final AnnotatedTypeFactory typeFactory, final Tree tree) { abortIfTreeIsNull(typeFactory, tree); final AnnotatedTypeMirror type = typeTreeVisitor.visit(tree, typeFactory); abortIfTypeIsExecutable(typeFactory, tree, type); return type; } /** @return an AnnotatedDeclaredType representing the input ClassTree */ public static AnnotatedDeclaredType fromClassTree( final AnnotatedTypeFactory typeFactory, final ClassTree tree) { abortIfTreeIsNull(typeFactory, tree); final AnnotatedDeclaredType type = (AnnotatedDeclaredType) classVisitor.visit(tree, typeFactory); abortIfTypeIsExecutable(typeFactory, tree, type); return type; } protected static void abortIfTreeIsNull( final AnnotatedTypeFactory typeFactory, final Tree tree) { if (tree == null) { ErrorReporter.errorAbort("Encountered null tree" + summarize(typeFactory, tree)); } } protected static void ifExecutableCheckElement( final AnnotatedTypeFactory typeFactory, final Tree tree, final AnnotatedTypeMirror type) { if (type.getKind() == TypeKind.EXECUTABLE) { if (((AnnotatedExecutableType) type).getElement() == null) { ErrorReporter.errorAbort( "Executable has no element:\n" + summarize(typeFactory, tree, type)); } } } protected static void abortIfTypeIsExecutable( final AnnotatedTypeFactory typeFactory, final Tree tree, final AnnotatedTypeMirror type) { if (type.getKind() == TypeKind.EXECUTABLE) { ErrorReporter.errorAbort( "Unexpected Executable typekind:\n" + summarize(typeFactory, tree, type)); } } protected static String summarize(final AnnotatedTypeFactory typeFactory, final Tree tree) { return "tree=" + tree + "\n" + "typeFactory=" + typeFactory.getClass().getSimpleName(); } protected static String summarize( final AnnotatedTypeFactory typeFactory, final Tree tree, final AnnotatedTypeMirror type) { return "type=" + type + "\n" + summarize(typeFactory, tree); } }