blob: d6cf1736d8037040f8f61f283798510fc43f437b [file] [log] [blame]
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.BugInCF;
/**
* 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();
/**
* Returns an AnnotatedTypeMirror representing the input expression tree.
*
* @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;
try {
type = expressionVisitor.visit(tree, typeFactory);
} catch (Throwable t) {
throw new BugInCF(
t,
"Error in AnnotatedTypeMirror.fromExpression(%s, %s): %s",
typeFactory.getClass().getSimpleName(),
tree,
t.getMessage());
}
ifExecutableCheckElement(typeFactory, tree, type);
return type;
}
/**
* Returns an AnnotatedTypeMirror representing the input tree.
*
* @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;
}
/**
* Returns an AnnotatedTypeMirror representing the input type tree.
*
* @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;
}
/**
* Returns an AnnotatedDeclaredType representing the input ClassTree.
*
* @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) {
throw new BugInCF("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) {
throw new BugInCF("Executable has no element:%n%s", summarize(typeFactory, tree, type));
}
}
}
protected static void abortIfTypeIsExecutable(
final AnnotatedTypeFactory typeFactory, final Tree tree, final AnnotatedTypeMirror type) {
if (type.getKind() == TypeKind.EXECUTABLE) {
throw new BugInCF("Unexpected Executable typekind:%n%s", summarize(typeFactory, tree, type));
}
}
/**
* Return a string with the two arguments, for diagnostics.
*
* @param typeFactory a type factory
* @param tree a tree
* @return a string with the two arguments
*/
protected static String summarize(final AnnotatedTypeFactory typeFactory, final Tree tree) {
return String.format("tree=%s%ntypeFactory=%s", tree, typeFactory.getClass().getSimpleName());
}
protected static String summarize(
final AnnotatedTypeFactory typeFactory, final Tree tree, final AnnotatedTypeMirror type) {
return "type=" + type + System.lineSeparator() + summarize(typeFactory, tree);
}
}