8224687: Add clarifying overrides of Element.asType to more specific subinterfaces

Reviewed-by: jjg
This commit is contained in:
Joe Darcy 2019-05-30 16:21:08 -07:00
parent 110ead8bea
commit bcd13b790f
8 changed files with 243 additions and 17 deletions

View File

@ -63,20 +63,15 @@ import javax.lang.model.util.*;
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();

View File

@ -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
@ -40,6 +40,17 @@ import javax.lang.model.type.*;
* @since 1.6
*/
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.

View File

@ -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 @@ import java.util.List;
* @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

View File

@ -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 @@ import java.util.List;
* @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.

View File

@ -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
@ -59,6 +59,28 @@ import javax.lang.model.util.*;
* @since 1.6
*/
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.

View File

@ -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 @@ import javax.lang.model.type.TypeVariable;
* @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

View File

@ -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 @@ import javax.lang.model.util.Elements;
* @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}

View File

@ -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";
}
}