| package org.checkerframework.framework.type; |
| |
| import com.sun.source.tree.AnnotatedTypeTree; |
| import com.sun.source.tree.ArrayAccessTree; |
| import com.sun.source.tree.ArrayTypeTree; |
| import com.sun.source.tree.AssignmentTree; |
| import com.sun.source.tree.BinaryTree; |
| import com.sun.source.tree.CompoundAssignmentTree; |
| import com.sun.source.tree.ConditionalExpressionTree; |
| import com.sun.source.tree.IdentifierTree; |
| import com.sun.source.tree.InstanceOfTree; |
| import com.sun.source.tree.IntersectionTypeTree; |
| import com.sun.source.tree.LambdaExpressionTree; |
| import com.sun.source.tree.LiteralTree; |
| import com.sun.source.tree.MemberReferenceTree; |
| import com.sun.source.tree.MemberSelectTree; |
| import com.sun.source.tree.MethodInvocationTree; |
| import com.sun.source.tree.NewArrayTree; |
| import com.sun.source.tree.NewClassTree; |
| import com.sun.source.tree.ParameterizedTypeTree; |
| import com.sun.source.tree.ParenthesizedTree; |
| import com.sun.source.tree.PrimitiveTypeTree; |
| import com.sun.source.tree.Tree; |
| import com.sun.source.tree.TypeCastTree; |
| import com.sun.source.tree.UnaryTree; |
| import com.sun.source.tree.WildcardTree; |
| import java.util.List; |
| import javax.lang.model.element.AnnotationMirror; |
| import javax.lang.model.element.Element; |
| import javax.lang.model.type.TypeKind; |
| import javax.lang.model.type.TypeMirror; |
| import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedArrayType; |
| import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType; |
| import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType; |
| import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedWildcardType; |
| import org.checkerframework.framework.util.AnnotatedTypes; |
| import org.checkerframework.javacutil.BugInCF; |
| import org.checkerframework.javacutil.Pair; |
| import org.checkerframework.javacutil.TreeUtils; |
| import org.checkerframework.javacutil.TypesUtils; |
| |
| /** |
| * Converts ExpressionTrees into AnnotatedTypeMirrors. |
| * |
| * <p>The type of some expressions depends on the checker, so for these expressions, a checker |
| * should add annotations in a {@link |
| * org.checkerframework.framework.type.treeannotator.TreeAnnotator} and/or the {@link |
| * org.checkerframework.framework.type.treeannotator.PropagationTreeAnnotator}. These trees are: |
| * |
| * <ul> |
| * <li>{@code BinaryTree} |
| * <li>{@code CompoundAssignmentTree} |
| * <li>{@code InstanceOfTree} |
| * <li>{@code LiteralTree} |
| * <li>{@code UnaryTree} |
| * </ul> |
| * |
| * Other expressions are in fact type trees and their annotataed type mirrors are computed as type |
| * trees: |
| * |
| * <ul> |
| * <li>{@code AnnotatedTypeTree} |
| * <li>{@code TypeCastTree} |
| * <li>{@code PrimitiveTypeTree} |
| * <li>{@code ArrayTypeTree} |
| * <li>{@code ParameterizedTypeTree} |
| * <li>{@code IntersectionTypeTree} |
| * </ul> |
| */ |
| class TypeFromExpressionVisitor extends TypeFromTreeVisitor { |
| |
| @Override |
| public AnnotatedTypeMirror visitBinary(BinaryTree node, AnnotatedTypeFactory f) { |
| return f.type(node); |
| } |
| |
| @Override |
| public AnnotatedTypeMirror visitCompoundAssignment( |
| CompoundAssignmentTree node, AnnotatedTypeFactory f) { |
| return f.type(node); |
| } |
| |
| @Override |
| public AnnotatedTypeMirror visitInstanceOf(InstanceOfTree node, AnnotatedTypeFactory f) { |
| return f.type(node); |
| } |
| |
| @Override |
| public AnnotatedTypeMirror visitLiteral(LiteralTree node, AnnotatedTypeFactory f) { |
| return f.type(node); |
| } |
| |
| @Override |
| public AnnotatedTypeMirror visitUnary(UnaryTree node, AnnotatedTypeFactory f) { |
| return f.type(node); |
| } |
| |
| @Override |
| public AnnotatedTypeMirror visitAnnotatedType(AnnotatedTypeTree node, AnnotatedTypeFactory f) { |
| return f.fromTypeTree(node); |
| } |
| |
| @Override |
| public AnnotatedTypeMirror visitTypeCast(TypeCastTree node, AnnotatedTypeFactory f) { |
| |
| // Use the annotated type of the type in the cast. |
| return f.fromTypeTree(node.getType()); |
| } |
| |
| @Override |
| public AnnotatedTypeMirror visitPrimitiveType(PrimitiveTypeTree node, AnnotatedTypeFactory f) { |
| // for e.g. "int.class" |
| return f.fromTypeTree(node); |
| } |
| |
| @Override |
| public AnnotatedTypeMirror visitArrayType(ArrayTypeTree node, AnnotatedTypeFactory f) { |
| // for e.g. "int[].class" |
| return f.fromTypeTree(node); |
| } |
| |
| @Override |
| public AnnotatedTypeMirror visitParameterizedType( |
| ParameterizedTypeTree node, AnnotatedTypeFactory f) { |
| return f.fromTypeTree(node); |
| } |
| |
| @Override |
| public AnnotatedTypeMirror visitIntersectionType( |
| IntersectionTypeTree node, AnnotatedTypeFactory f) { |
| return f.fromTypeTree(node); |
| } |
| |
| @Override |
| public AnnotatedTypeMirror visitMemberReference( |
| MemberReferenceTree node, AnnotatedTypeFactory f) { |
| return f.toAnnotatedType(TreeUtils.typeOf(node), false); |
| } |
| |
| @Override |
| public AnnotatedTypeMirror visitLambdaExpression( |
| LambdaExpressionTree node, AnnotatedTypeFactory f) { |
| return f.toAnnotatedType(TreeUtils.typeOf(node), false); |
| } |
| |
| @Override |
| public AnnotatedTypeMirror visitAssignment(AssignmentTree node, AnnotatedTypeFactory f) { |
| |
| // Recurse on the type of the variable. |
| return visit(node.getVariable(), f); |
| } |
| |
| @Override |
| public AnnotatedTypeMirror visitConditionalExpression( |
| ConditionalExpressionTree node, AnnotatedTypeFactory f) { |
| // The Java type of a conditional expression is generally the LUB of the boxed types |
| // of the true and false expressions, but with a few exceptions. See JLS 15.25. |
| // So, use the type of the ConditionalExpressionTree instead of |
| // InternalUtils#leastUpperBound |
| TypeMirror alub = TreeUtils.typeOf(node); |
| |
| AnnotatedTypeMirror trueType = f.getAnnotatedType(node.getTrueExpression()); |
| AnnotatedTypeMirror falseType = f.getAnnotatedType(node.getFalseExpression()); |
| |
| return AnnotatedTypes.leastUpperBound(f, trueType, falseType, alub); |
| } |
| |
| @Override |
| public AnnotatedTypeMirror visitIdentifier(IdentifierTree node, AnnotatedTypeFactory f) { |
| if (node.getName().contentEquals("this") || node.getName().contentEquals("super")) { |
| AnnotatedDeclaredType res = f.getSelfType(node); |
| return res; |
| } |
| |
| Element elt = TreeUtils.elementFromUse(node); |
| AnnotatedTypeMirror selfType = f.getImplicitReceiverType(node); |
| if (selfType != null) { |
| return AnnotatedTypes.asMemberOf(f.types, f, selfType, elt).asUse(); |
| } |
| |
| return f.getAnnotatedType(elt); |
| } |
| |
| @Override |
| public AnnotatedTypeMirror visitMemberSelect(MemberSelectTree node, AnnotatedTypeFactory f) { |
| Element elt = TreeUtils.elementFromUse(node); |
| |
| if (TreeUtils.isClassLiteral(node)) { |
| // the type of a class literal is the type of the "class" element. |
| return f.getAnnotatedType(elt); |
| } |
| switch (elt.getKind()) { |
| case METHOD: |
| case PACKAGE: // "java.lang" in new java.lang.Short("2") |
| case CLASS: // o instanceof MyClass.InnerClass |
| case ENUM: |
| case INTERFACE: // o instanceof MyClass.InnerInterface |
| case ANNOTATION_TYPE: |
| return f.fromElement(elt); |
| default: |
| // Fall-through. |
| } |
| |
| if (node.getIdentifier().contentEquals("this")) { |
| // Node is "MyClass.this", where "MyClass" may be the innermost enclosing type or any |
| // outer type. |
| return f.getEnclosingType(TypesUtils.getTypeElement(TreeUtils.typeOf(node)), node); |
| } else { |
| // node must be a field access, so get the type of the expression, and then call asMemberOf. |
| AnnotatedTypeMirror t = f.getAnnotatedType(node.getExpression()); |
| return AnnotatedTypes.asMemberOf(f.types, f, t, elt).asUse(); |
| } |
| } |
| |
| @Override |
| public AnnotatedTypeMirror visitArrayAccess(ArrayAccessTree node, AnnotatedTypeFactory f) { |
| |
| Pair<Tree, AnnotatedTypeMirror> preAssignmentContext = f.visitorState.getAssignmentContext(); |
| try { |
| // TODO: what other trees shouldn't maintain the context? |
| f.visitorState.setAssignmentContext(null); |
| |
| AnnotatedTypeMirror type = f.getAnnotatedType(node.getExpression()); |
| if (type.getKind() == TypeKind.ARRAY) { |
| return ((AnnotatedArrayType) type).getComponentType(); |
| } else if (type.getKind() == TypeKind.WILDCARD |
| && ((AnnotatedWildcardType) type).isUninferredTypeArgument()) { |
| // Clean-up after Issue #979. |
| AnnotatedTypeMirror wcbound = ((AnnotatedWildcardType) type).getExtendsBound(); |
| if (wcbound instanceof AnnotatedArrayType) { |
| return ((AnnotatedArrayType) wcbound).getComponentType(); |
| } |
| } |
| throw new BugInCF("Unexpected type: " + type); |
| } finally { |
| f.visitorState.setAssignmentContext(preAssignmentContext); |
| } |
| } |
| |
| @Override |
| public AnnotatedTypeMirror visitNewArray(NewArrayTree node, AnnotatedTypeFactory f) { |
| |
| // Don't use fromTypeTree here, because node.getType() is not an array type! |
| AnnotatedArrayType result = (AnnotatedArrayType) f.type(node); |
| |
| if (node.getType() == null) { // e.g., byte[] b = {(byte)1, (byte)2}; |
| return result; |
| } |
| |
| annotateArrayAsArray(result, node, f); |
| |
| return result; |
| } |
| |
| private AnnotatedTypeMirror descendBy(AnnotatedTypeMirror type, int depth) { |
| AnnotatedTypeMirror result = type; |
| while (depth > 0) { |
| result = ((AnnotatedArrayType) result).getComponentType(); |
| depth--; |
| } |
| return result; |
| } |
| |
| private void annotateArrayAsArray( |
| AnnotatedArrayType result, NewArrayTree node, AnnotatedTypeFactory f) { |
| // Copy annotations from the type. |
| AnnotatedTypeMirror treeElem = f.fromTypeTree(node.getType()); |
| boolean hasInit = node.getInitializers() != null; |
| AnnotatedTypeMirror typeElem = descendBy(result, hasInit ? 1 : node.getDimensions().size()); |
| while (true) { |
| typeElem.addAnnotations(treeElem.getAnnotations()); |
| if (!(treeElem instanceof AnnotatedArrayType)) { |
| break; |
| } |
| assert typeElem instanceof AnnotatedArrayType; |
| treeElem = ((AnnotatedArrayType) treeElem).getComponentType(); |
| typeElem = ((AnnotatedArrayType) typeElem).getComponentType(); |
| } |
| // Add all dimension annotations. |
| int idx = 0; |
| AnnotatedTypeMirror level = result; |
| while (level.getKind() == TypeKind.ARRAY) { |
| AnnotatedArrayType array = (AnnotatedArrayType) level; |
| List<? extends AnnotationMirror> annos = TreeUtils.annotationsFromArrayCreation(node, idx++); |
| array.addAnnotations(annos); |
| level = array.getComponentType(); |
| } |
| |
| // Add top-level annotations. |
| result.addAnnotations(TreeUtils.annotationsFromArrayCreation(node, -1)); |
| } |
| |
| /** |
| * Creates an AnnotatedDeclaredType for the NewClassTree and adds, for each hierarchy, one of: |
| * |
| * <ul> |
| * <li>an explicit annotation on the new class expression ({@code new @HERE MyClass()}), or |
| * <li>an explicit annotation on the declaration of the class ({@code @HERE class MyClass {}}), |
| * or |
| * <li>an explicit or default annotation on the declaration of the constructor ({@code @HERE |
| * public MyClass() {}}). |
| * </ul> |
| * |
| * @param node NewClassTree |
| * @param f the type factory |
| * @return AnnotatedDeclaredType of {@code node} |
| */ |
| @Override |
| public AnnotatedTypeMirror visitNewClass(NewClassTree node, AnnotatedTypeFactory f) { |
| // constructorFromUse return type has default annotations |
| // so use fromNewClass which does diamond inference and only |
| // contains explicit annotations. |
| AnnotatedDeclaredType type = f.fromNewClass(node); |
| |
| // Add annotations that are on the constructor declaration. |
| AnnotatedExecutableType ex = f.constructorFromUse(node).executableType; |
| type.addMissingAnnotations(ex.getReturnType().getAnnotations()); |
| |
| return type; |
| } |
| |
| @Override |
| public AnnotatedTypeMirror visitMethodInvocation( |
| MethodInvocationTree node, AnnotatedTypeFactory f) { |
| AnnotatedExecutableType ex = f.methodFromUse(node).executableType; |
| return ex.getReturnType().asUse(); |
| } |
| |
| @Override |
| public AnnotatedTypeMirror visitParenthesized(ParenthesizedTree node, AnnotatedTypeFactory f) { |
| |
| // Recurse on the expression inside the parens. |
| return visit(node.getExpression(), f); |
| } |
| |
| @Override |
| public AnnotatedTypeMirror visitWildcard(WildcardTree node, AnnotatedTypeFactory f) { |
| |
| AnnotatedTypeMirror bound = visit(node.getBound(), f); |
| |
| AnnotatedTypeMirror result = f.type(node); |
| assert result instanceof AnnotatedWildcardType; |
| |
| // Instead of directly overwriting the bound, replace each annotation |
| // to ensure that the structure of the wildcard will match that created by |
| // BoundsInitializer/createType. |
| if (node.getKind() == Tree.Kind.SUPER_WILDCARD) { |
| f.replaceAnnotations(bound, ((AnnotatedWildcardType) result).getSuperBound()); |
| |
| } else if (node.getKind() == Tree.Kind.EXTENDS_WILDCARD) { |
| f.replaceAnnotations(bound, ((AnnotatedWildcardType) result).getExtendsBound()); |
| } |
| return result; |
| } |
| } |