Skip to content

Commit

Permalink
Add baseline support for records (#3017)
Browse files Browse the repository at this point in the history
Treat records as regular classes.  Avoid throwing exceptions when records
are encountered in source code.  Keep backwards compatibility with Java 8
and 11.

Co-authored-by: Michael Ernst <mernst@alum.mit.edu>
Co-authored-by: Werner Dietl <wdietl@gmail.com>
  • Loading branch information
3 people committed Dec 31, 2019
1 parent 47f0907 commit e2874e7
Show file tree
Hide file tree
Showing 7 changed files with 97 additions and 96 deletions.
Expand Up @@ -287,6 +287,10 @@ public static Receiver internalReprOf(
assert TreeUtils.isUseOfElement(identifierTree)
: "@AssumeAssertion(nullness): tree kind";
Element ele = TreeUtils.elementFromUse(identifierTree);
if (ElementUtils.isClassElement(ele)) {
receiver = new ClassName(ele.asType());
break;
}
switch (ele.getKind()) {
case LOCAL_VARIABLE:
case RESOURCE_VARIABLE:
Expand All @@ -307,12 +311,6 @@ public static Receiver internalReprOf(
new FieldAccess(
fieldAccessExpression, typeOfId, (VariableElement) ele);
break;
case CLASS:
case ENUM:
case ANNOTATION_TYPE:
case INTERFACE:
receiver = new ClassName(ele.asType());
break;
default:
receiver = null;
}
Expand Down Expand Up @@ -372,16 +370,16 @@ private static Receiver internalReprOfMemberSelect(
}
assert TreeUtils.isUseOfElement(memberSelectTree) : "@AssumeAssertion(nullness): tree kind";
Element ele = TreeUtils.elementFromUse(memberSelectTree);
if (ElementUtils.isClassElement(ele)) {
// o instanceof MyClass.InnerClass
// o instanceof MyClass.InnerInterface
TypeMirror selectType = TreeUtils.typeOf(memberSelectTree);
return new ClassName(selectType);
}
switch (ele.getKind()) {
case METHOD:
case CONSTRUCTOR:
return internalReprOf(provider, memberSelectTree.getExpression());
case CLASS: // o instanceof MyClass.InnerClass
case ENUM:
case INTERFACE: // o instanceof MyClass.InnerInterface
case ANNOTATION_TYPE:
TypeMirror selectType = TreeUtils.typeOf(memberSelectTree);
return new ClassName(selectType);
case ENUM_CONSTANT:
case FIELD:
TypeMirror fieldType = TreeUtils.typeOf(memberSelectTree);
Expand Down
Expand Up @@ -75,6 +75,7 @@
import java.util.Set;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Name;
import javax.lang.model.element.TypeElement;
Expand Down Expand Up @@ -3889,13 +3890,6 @@ public Node visitIdentifier(IdentifierTree tree, Void p) {
} else {
Element element = TreeUtils.elementFromUse(tree);
switch (element.getKind()) {
case ANNOTATION_TYPE:
case CLASS:
case ENUM:
case INTERFACE:
case TYPE_PARAMETER:
node = new ClassNameNode(tree);
break;
case FIELD:
// Note that "this"/"super" is a field, but not a field access.
if (element.getSimpleName().contentEquals("this")) {
Expand All @@ -3914,6 +3908,10 @@ public Node visitIdentifier(IdentifierTree tree, Void p) {
node = new PackageNameNode(tree);
break;
default:
if (ElementUtils.isTypeDeclaration(element)) {
node = new ClassNameNode(tree);
break;
}
throw new BugInCF("bad element kind " + element.getKind());
}
}
Expand Down Expand Up @@ -4173,23 +4171,15 @@ public Node visitMemberSelect(MemberSelectTree tree, Void p) {
Node expr = scan(tree.getExpression(), p);
if (!TreeUtils.isFieldAccess(tree)) {
// Could be a selector of a class or package
Node result = null;
Element element = TreeUtils.elementFromUse(tree);
switch (element.getKind()) {
case ANNOTATION_TYPE:
case CLASS:
case ENUM:
case INTERFACE:
result = extendWithNode(new ClassNameNode(tree, expr));
break;
case PACKAGE:
result = extendWithNode(new PackageNameNode(tree, (PackageNameNode) expr));
break;
default:
assert false : "Unexpected element kind: " + element.getKind();
return null;
if (ElementUtils.isClassElement(element)) {
return extendWithNode(new ClassNameNode(tree, expr));
} else if (element.getKind() == ElementKind.PACKAGE) {
return extendWithNode(new PackageNameNode(tree, (PackageNameNode) expr));
} else {
assert false : "Unexpected element kind: " + element.getKind();
return null;
}
return result;
}

Node node = new FieldAccessNode(tree, expr);
Expand Down
Expand Up @@ -37,12 +37,13 @@ public ClassNameNode(IdentifierTree tree) {
this.parent = null;
}

/**
* Create a new ClassNameNode.
*
* @param tree the class tree for this node
*/
public ClassNameNode(ClassTree tree) {
super(TreeUtils.typeOf(tree));
assert tree.getKind() == Tree.Kind.CLASS
|| tree.getKind() == Tree.Kind.ENUM
|| tree.getKind() == Tree.Kind.INTERFACE
|| tree.getKind() == Tree.Kind.ANNOTATION_TYPE;
this.tree = tree;
this.element = TreeUtils.elementFromDeclaration(tree);
this.parent = null;
Expand Down
Expand Up @@ -526,11 +526,7 @@ public static EnumSet<ElementKind> getElementKindsForTarget(@Nullable Target tar
public static EnumSet<ElementKind> getElementKindsForElementType(ElementType elementType) {
switch (elementType) {
case TYPE:
return EnumSet.of(
ElementKind.CLASS,
ElementKind.INTERFACE,
ElementKind.ANNOTATION_TYPE,
ElementKind.ENUM);
return EnumSet.copyOf(ElementUtils.classElementKinds());
case FIELD:
return EnumSet.of(ElementKind.FIELD, ElementKind.ENUM_CONSTANT);
case METHOD:
Expand Down Expand Up @@ -558,6 +554,9 @@ public static EnumSet<ElementKind> getElementKindsForElementType(ElementType ele
if (elementType.name().contentEquals("MODULE")) {
return EnumSet.noneOf(ElementKind.class);
}
if (elementType.name().equals("RECORD_COMPONENT")) {
return EnumSet.of(ElementKind.valueOf("RECORD_COMPONENT"));
}
throw new BugInCF("Unrecognized ElementType: " + elementType);
}
}
Expand Down
Expand Up @@ -7,6 +7,7 @@
import java.util.Collection;
import java.util.Collections;
import java.util.Deque;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
Expand Down Expand Up @@ -45,7 +46,7 @@ private ElementUtils() {
*/
public static TypeElement enclosingClass(final Element elem) {
Element result = elem;
while (result != null && !result.getKind().isClass() && !result.getKind().isInterface()) {
while (result != null && !isClassElement(result)) {
@Nullable Element encl = result.getEnclosingElement();
result = encl;
}
Expand Down Expand Up @@ -171,9 +172,7 @@ public static String getVerboseName(Element elt) {
if (n == null) {
return "Unexpected element: " + elt;
}
if (elt.getKind() == ElementKind.PACKAGE
|| elt.getKind().isClass()
|| elt.getKind().isInterface()) {
if (elt.getKind() == ElementKind.PACKAGE || isClassElement(elt)) {
return n.toString();
} else {
return n + "." + elt;
Expand Down Expand Up @@ -492,22 +491,47 @@ public static List<TypeElement> getAllTypeElementsIn(TypeElement type) {
return types;
}

public static boolean isTypeDeclaration(Element elt) {
switch (elt.getKind()) {
// These tree kinds are always declarations. Uses of the declared
// types have tree kind IDENTIFIER.
case ANNOTATION_TYPE:
case CLASS:
case ENUM:
case INTERFACE:
case TYPE_PARAMETER:
return true;
/** The set of kinds that represent classes. */
private static final Set<ElementKind> classElementKinds;

default:
return false;
static {
classElementKinds = EnumSet.noneOf(ElementKind.class);
for (ElementKind kind : ElementKind.values()) {
if (kind.isClass() || kind.isInterface()) {
classElementKinds.add(kind);
}
}
}

/**
* Return the set of kinds that represent classes.
*
* @return the set of kinds that represent classes
*/
public static Set<ElementKind> classElementKinds() {
return classElementKinds;
}

/**
* Is the given element kind a class, i.e. a class, enum, interface, or annotation type.
*
* @param element the element to test
* @return true, iff the given kind is a class kind
*/
public static boolean isClassElement(Element element) {
return classElementKinds().contains(element.getKind());
}

/**
* Return true if the element is a type declaration.
*
* @param elt the element to test
* @return true if the argument is a type declaration
*/
public static boolean isTypeDeclaration(Element elt) {
return isClassElement(elt) || elt.getKind() == ElementKind.TYPE_PARAMETER;
}

/**
* Check that a method Element matches a signature.
*
Expand Down
Expand Up @@ -456,15 +456,6 @@ public static Pair<Tree, Tree> enclosingNonParen(final TreePath path) {
}

switch (tree.getKind()) {
case VARIABLE:
case METHOD:
case CLASS:
case ENUM:
case INTERFACE:
case ANNOTATION_TYPE:
case TYPE_PARAMETER:
return TreeInfo.symbolFor((JCTree) tree);

// symbol() only works on MethodSelects, so we need to get it manually
// for method invocations.
case METHOD_INVOCATION:
Expand All @@ -485,6 +476,11 @@ public static Pair<Tree, Tree> enclosingNonParen(final TreePath path) {
return ((JCMemberReference) tree).sym;

default:
if (isTypeDeclaration(tree)
|| tree.getKind() == Tree.Kind.VARIABLE
|| tree.getKind() == Tree.Kind.METHOD) {
return TreeInfo.symbolFor((JCTree) tree);
}
return TreeInfo.symbol((JCTree) tree);
}
}
Expand Down Expand Up @@ -806,13 +802,23 @@ public static boolean isCompileTimeString(ExpressionTree node) {
// Adding Tree.Kind.NEW_CLASS here doesn't work, because then a
// tree gets cast to ClassTree when it is actually a NewClassTree,
// for example in enclosingClass above.
private static final Set<Tree.Kind> classTreeKinds =
EnumSet.of(
Tree.Kind.CLASS,
Tree.Kind.ENUM,
Tree.Kind.INTERFACE,
Tree.Kind.ANNOTATION_TYPE);
/** The set of kinds that represent classes. */
private static final Set<Tree.Kind> classTreeKinds;

static {
classTreeKinds = EnumSet.noneOf(Tree.Kind.class);
for (Tree.Kind kind : Tree.Kind.values()) {
if (kind.asInterface() == ClassTree.class) {
classTreeKinds.add(kind);
}
}
}

/**
* Return the set of kinds that represent classes.
*
* @return the set of kinds that represent classes
*/
public static Set<Tree.Kind> classTreeKinds() {
return classTreeKinds;
}
Expand Down Expand Up @@ -1174,19 +1180,7 @@ public static boolean isEnumSuper(MethodInvocationTree node) {
* @return true if the tree is a type declaration
*/
public static boolean isTypeDeclaration(Tree node) {
switch (node.getKind()) {
// These tree kinds are always declarations. Uses of the declared
// types have tree kind IDENTIFIER.
case ANNOTATION_TYPE:
case CLASS:
case ENUM:
case INTERFACE:
case TYPE_PARAMETER:
return true;

default:
return false;
}
return isClassTree(node) || node.getKind() == Tree.Kind.TYPE_PARAMETER;
}

/**
Expand Down
Expand Up @@ -351,7 +351,7 @@ public static Type wildUpperBound(TypeMirror tm, ProcessingEnvironment env) {
if (w.isSuperBound()) { // returns true if w is unbound
Symtab syms = Symtab.instance(context);
// w.bound is null if the wildcard is from bytecode.
return w.bound == null ? syms.objectType : w.bound.bound;
return w.bound == null ? syms.objectType : w.bound.getUpperBound();
} else {
return wildUpperBound(w.type, env);
}
Expand Down Expand Up @@ -643,15 +643,10 @@ public static TypeMirror substituteMethodReturnType(
*/
public static @Nullable TypeElement getTypeElement(TypeMirror type) {
Element element = ((Type) type).asElement();
switch (element.getKind()) {
case ANNOTATION_TYPE:
case CLASS:
case ENUM:
case INTERFACE:
return (TypeElement) element;
default:
return null;
if (ElementUtils.isClassElement(element)) {
return (TypeElement) element;
}
return null;
}

/**
Expand Down

0 comments on commit e2874e7

Please sign in to comment.