8224687: Add clarifying overrides of Element.asType to more specific subinterfaces
authordarcy
Thu, 30 May 2019 16:21:08 -0700
changeset 55118 9ea55cb79d77
parent 55117 b6418e5aad70
child 55119 04ff1e00635a
8224687: Add clarifying overrides of Element.asType to more specific subinterfaces Reviewed-by: jjg
src/java.compiler/share/classes/javax/lang/model/element/Element.java
src/java.compiler/share/classes/javax/lang/model/element/ExecutableElement.java
src/java.compiler/share/classes/javax/lang/model/element/ModuleElement.java
src/java.compiler/share/classes/javax/lang/model/element/PackageElement.java
src/java.compiler/share/classes/javax/lang/model/element/TypeElement.java
src/java.compiler/share/classes/javax/lang/model/element/TypeParameterElement.java
src/java.compiler/share/classes/javax/lang/model/element/VariableElement.java
test/langtools/tools/javac/processing/model/element/TestElementAsType.java
--- a/src/java.compiler/share/classes/javax/lang/model/element/Element.java	Thu May 30 15:55:16 2019 -0700
+++ b/src/java.compiler/share/classes/javax/lang/model/element/Element.java	Thu May 30 16:21:08 2019 -0700
@@ -63,20 +63,15 @@
 public interface Element extends javax.lang.model.AnnotatedConstruct {
     /**
      * Returns the type defined by this element.
-     *
-     * <p> A generic element defines a family of types, not just one.
-     * If this is a generic element, a <i>prototypical</i> type is
-     * returned.  This is the element's invocation on the
-     * type variables corresponding to its own formal type parameters.
-     * For example,
-     * for the generic class element {@code C<N extends Number>},
-     * the parameterized type {@code C<N>} is returned.
-     * The {@link Types} utility interface has more general methods
-     * for obtaining the full range of types defined by an element.
+     * @return the type defined by this element
      *
      * @see Types
-     *
-     * @return the type defined by this element
+     * @see ExecutableElement#asType
+     * @see ModuleElement#asType
+     * @see PackageElement#asType
+     * @see TypeElement#asType
+     * @see TypeParameterElement#asType
+     * @see VariableElement#asType
      */
     TypeMirror asType();
 
--- a/src/java.compiler/share/classes/javax/lang/model/element/ExecutableElement.java	Thu May 30 15:55:16 2019 -0700
+++ b/src/java.compiler/share/classes/javax/lang/model/element/ExecutableElement.java	Thu May 30 16:21:08 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -41,6 +41,17 @@
  */
 public interface ExecutableElement extends Element, Parameterizable {
     /**
+     * Returns the {@linkplain ExecutableType executable type} defined
+     * by this executable element.
+     *
+     * @return the executable type defined by this executable element
+     *
+     * @see ExecutableType
+     */
+    @Override
+    TypeMirror asType();
+
+    /**
      * Returns the formal type parameters of this executable
      * in declaration order.
      *
--- a/src/java.compiler/share/classes/javax/lang/model/element/ModuleElement.java	Thu May 30 15:55:16 2019 -0700
+++ b/src/java.compiler/share/classes/javax/lang/model/element/ModuleElement.java	Thu May 30 16:21:08 2019 -0700
@@ -26,6 +26,7 @@
 package javax.lang.model.element;
 
 import java.util.List;
+import javax.lang.model.type.TypeMirror;
 
 /**
  * Represents a module program element.  Provides access to
@@ -37,6 +38,16 @@
  * @spec JPMS
  */
 public interface ModuleElement extends Element, QualifiedNameable {
+    /**
+     * Returns a {@linkplain javax.lang.model.type.NoType pseudo-type}
+     * for this module.
+     * @return a pseudo-type for this module
+     *
+     * @see javax.lang.model.type.NoType
+     * @see javax.lang.model.type.TypeKind#MODULE
+     */
+    @Override
+    TypeMirror asType();
 
     /**
      * Returns the fully qualified name of this module.  For an
--- a/src/java.compiler/share/classes/javax/lang/model/element/PackageElement.java	Thu May 30 15:55:16 2019 -0700
+++ b/src/java.compiler/share/classes/javax/lang/model/element/PackageElement.java	Thu May 30 16:21:08 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,6 +26,7 @@
 package javax.lang.model.element;
 
 import java.util.List;
+import javax.lang.model.type.TypeMirror;
 
 /**
  * Represents a package program element.  Provides access to information
@@ -38,6 +39,16 @@
  * @since 1.6
  */
 public interface PackageElement extends Element, QualifiedNameable {
+    /**
+     * Returns a {@linkplain javax.lang.model.type.NoType pseudo-type}
+     * for this package.
+     * @return a pseudo-type for this package
+     *
+     * @see javax.lang.model.type.NoType
+     * @see javax.lang.model.type.TypeKind#PACKAGE
+     */
+    @Override
+    TypeMirror asType();
 
     /**
      * Returns the fully qualified name of this package.
--- a/src/java.compiler/share/classes/javax/lang/model/element/TypeElement.java	Thu May 30 15:55:16 2019 -0700
+++ b/src/java.compiler/share/classes/javax/lang/model/element/TypeElement.java	Thu May 30 16:21:08 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -60,6 +60,28 @@
  */
 public interface TypeElement extends Element, Parameterizable, QualifiedNameable {
     /**
+     * Returns the type defined by this type element, returning the
+     * <i>prototypical</i> type for an element representing a generic type.
+     *
+     * <p>A generic element defines a family of types, not just one.
+     * If this is a generic element, a prototypical type is
+     * returned which has the element's invocation on the
+     * type variables corresponding to its own formal type parameters.
+     * For example,
+     * for the generic class element {@code C<N extends Number>},
+     * the parameterized type {@code C<N>} is returned.
+     * The {@link Types} utility interface has more general methods
+     * for obtaining the full range of types defined by an element.
+     *
+     * @return the type defined by this type element
+     *
+     * @see Types#asMemberOf(DeclaredType, Element)
+     * @see Types#getDeclaredType(TypeElement, TypeMirror...)
+     */
+    @Override
+    TypeMirror asType();
+
+    /**
      * Returns the fields, methods, constructors, and member types
      * that are directly declared in this class or interface.
      *
--- a/src/java.compiler/share/classes/javax/lang/model/element/TypeParameterElement.java	Thu May 30 15:55:16 2019 -0700
+++ b/src/java.compiler/share/classes/javax/lang/model/element/TypeParameterElement.java	Thu May 30 16:21:08 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -41,6 +41,15 @@
  * @since 1.6
  */
 public interface TypeParameterElement extends Element {
+    /**
+     * Returns the {@linkplain TypeVariable type variable} corresponding to this type parameter element.
+     *
+     * @see TypeVariable
+     *
+     * @return the type variable corresponding to this type parameter element
+     */
+    @Override
+    TypeMirror asType();
 
     /**
      * Returns the generic class, interface, method, or constructor that is
--- a/src/java.compiler/share/classes/javax/lang/model/element/VariableElement.java	Thu May 30 15:55:16 2019 -0700
+++ b/src/java.compiler/share/classes/javax/lang/model/element/VariableElement.java	Thu May 30 16:21:08 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,6 +26,8 @@
 package javax.lang.model.element;
 
 import javax.lang.model.util.Elements;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.type.TypeKind;
 
 /**
  * Represents a field, {@code enum} constant, method or constructor
@@ -38,6 +40,19 @@
  * @since 1.6
  */
 public interface VariableElement extends Element {
+    /**
+     * Returns the type of this variable.
+     *
+     * Note that the types of variables range over {@linkplain
+     * TypeKind many kinds} of types, including primitive types,
+     * declared types, and array types, among others.
+     *
+     * @return the type of this variable
+     *
+     * @see TypeKind
+     */
+    @Override
+    TypeMirror asType();
 
     /**
      * Returns the value of this variable if this is a {@code final}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/processing/model/element/TestElementAsType.java	Thu May 30 16:21:08 2019 -0700
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8224687
+ * @summary Test Element.asType and its overrides
+ * @library /tools/javac/lib
+ * @build   JavacTestingAbstractProcessor TestElementAsType
+ * @compile -processor TestElementAsType -proc:only TestElementAsType.java
+ */
+
+import java.util.*;
+import javax.annotation.processing.*;
+import javax.lang.model.element.*;
+import javax.lang.model.type.*;
+import javax.lang.model.util.*;
+import static javax.lang.model.util.ElementFilter.*;
+
+/*
+ * The leaf subinterfaces of javax.lang.model.Element of interest here
+ * are:
+ *
+ * ExecutableElement
+ * ModuleElement
+ * PackageElement
+ * TypeElement
+ * TypeParameterElement
+ * VariableElement
+ *
+ * For each of these categories of elements, at least one mapping of
+ * the result of its asType() method should be tested for its
+ * TypeMirror and TypeKind. Some elements will have more than one
+ * possible TypeMirror and/or TypeKind in its image under
+ * asType(). For example, a VariableElement representing a
+ * ElementKind.FIELD could be a DeclaredType, ArrayType,
+ * PrimitiveType, etc. In contrast, a ModuleElement should always map
+ * to the pseudo-type of a NoType with a TypeKind of MODULE.
+ */
+public class TestElementAsType extends JavacTestingAbstractProcessor {
+    public boolean process(Set<? extends TypeElement> annotations,
+                           RoundEnvironment roundEnv) {
+        if (!roundEnv.processingOver()) {
+            List<Element> elts = new ArrayList<>();
+            elts.add(Objects.requireNonNull(eltUtils.getModuleElement("java.base")));
+            elts.add(Objects.requireNonNull(eltUtils.getPackageElement("java.lang")));
+            elts.add(Objects.requireNonNull(eltUtils.getTypeElement("java.lang.String")));
+
+            // Get elements representing a class, field, method,
+            // constructor, and type variable from the nested class.
+            TypeElement tmp =
+                Objects.requireNonNull(eltUtils.getTypeElement("TestElementAsType.NestedClass"));
+            elts.add(tmp);
+            elts.add(ElementFilter.fieldsIn(tmp.getEnclosedElements()).get(0));
+            elts.add(ElementFilter.methodsIn(tmp.getEnclosedElements()).get(0));
+            elts.add(ElementFilter.constructorsIn(tmp.getEnclosedElements()).get(0));
+            elts.add(tmp.getTypeParameters().get(0));
+
+            // For a variety of different kinds of elements, check that
+            // the TypeKind and TypeMirror subinterface is as expected.
+            for(Element elt : elts) {
+                ElementKind eltKind = elt.getKind();
+                Class<?> expectedTypeClass = elementKindToTypeClass.get(eltKind);
+                TypeKind expectedTypeKind = elementKindToTypeKind.get(eltKind);
+
+                TypeMirror typeMirror = elt.asType();
+                TypeKind typeKind = typeMirror.getKind();
+
+                System.out.printf("%s\t%s\t%s%n",
+                                  typeMirror,
+                                  typeMirror.getClass(),
+                                  typeKind);
+
+                if (expectedTypeKind != typeKind) {
+                    System.out.printf("TypeKind mismatch on ''%s'';%n\texpected %s but got %s%n",
+                                      typeMirror, expectedTypeKind, typeKind);
+                    throw new RuntimeException();
+                }
+
+                Class<?> typeImplClass = typeMirror.getClass();
+                if (!expectedTypeClass.isAssignableFrom(typeImplClass)) {
+                    System.out.printf("Unexpected assignability failure on ''%s'';%n" +
+                                      "expected to be able to assign%n\t''%s'' to%n\t''%s''%n",
+                                      typeMirror, typeImplClass, expectedTypeClass);
+                    throw new RuntimeException();
+                }
+            }
+        }
+        return true;
+    }
+
+    /*
+     * For both of the maps below, a ElementKind value is mapped to
+     * one value related to an element's asType image. In some cases,
+     * the ElementKind -> (TypeMirror type, TypeKind) mapping is
+     * always the same, such as ElementKind.PACKAGE mapping to
+     * (NoType.class, TypeKind.PACKAGE). In other cases, such as for a
+     * field, there are many possible mappings and they are not
+     * attempted to be examined exhaustively by this test.
+     */
+    private static final Map<ElementKind, Class<?>> elementKindToTypeClass =
+        Map.of(ElementKind.CLASS,          DeclaredType.class,
+               ElementKind.CONSTRUCTOR,    ExecutableType.class,
+               ElementKind.METHOD,         ExecutableType.class,
+               ElementKind.PACKAGE,        NoType.class,
+               ElementKind.MODULE,         NoType.class,
+               ElementKind.TYPE_PARAMETER, TypeVariable.class,
+               // For the field NestedClass.name that is tested, a
+               // declared type is used.
+               ElementKind.FIELD,          DeclaredType.class);
+
+    private static final Map<ElementKind, TypeKind> elementKindToTypeKind =
+        Map.of(ElementKind.CLASS,          TypeKind.DECLARED,
+               ElementKind.CONSTRUCTOR,    TypeKind.EXECUTABLE,
+               ElementKind.METHOD,         TypeKind.EXECUTABLE,
+               ElementKind.PACKAGE,        TypeKind.PACKAGE,
+               ElementKind.MODULE,         TypeKind.MODULE,
+               ElementKind.TYPE_PARAMETER, TypeKind.TYPEVAR,
+               // For the field NestedClass.name that is tested, a
+               // declared type is used.
+               ElementKind.FIELD,          TypeKind.DECLARED);
+
+    static class NestedClass<N>  {
+        public NestedClass() {super();}
+
+        String name() {
+            return name;
+        }
+
+        private static String name = "NestedClass";
+    }
+}