
org.microbean.construct.Domain Maven / Gradle / Ivy
Show all versions of microbean-construct Show documentation
/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*-
*
* Copyright © 2024–2025 microBean™.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package org.microbean.construct;
import java.util.List;
import java.util.Objects;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.ModuleElement;
import javax.lang.model.element.Name;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.Parameterizable;
import javax.lang.model.element.QualifiedNameable;
import javax.lang.model.element.RecordComponentElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.TypeParameterElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.ArrayType;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.ExecutableType;
import javax.lang.model.type.NoType;
import javax.lang.model.type.NullType;
import javax.lang.model.type.PrimitiveType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.TypeVariable;
import javax.lang.model.type.WildcardType;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Elements.Origin;
import org.microbean.construct.element.StringName;
import org.microbean.construct.element.UniversalElement;
import org.microbean.construct.type.UniversalType;
import static javax.lang.model.element.ElementKind.CONSTRUCTOR;
import static javax.lang.model.element.ElementKind.METHOD;
/**
* A representation of a domain of valid Java constructs.
*
* A domain is a set of valid Java constructs. A {@link Domain}
* provides access to a domain and its members.
*
* A Java construct is either a type or an element.
*
* A type is a usage of a Java type, most commonly represented as a {@link TypeMirror}.
*
* An element ia a declaration of a Java program element, most commonly represented as an
* {@link Element}.
*
* Domains impose constraints on the types and elements they contain, and
* on the kinds and semantics of operations that can be performed on them.
*
* This interface is modeled on a deliberately restricted combination of the {@link javax.lang.model.util.Elements}
* and {@link javax.lang.model.util.Types} interfaces.
*
* {@link Domain} implementations must be thread-safe.
*
* @author Laird Nelson
*/
@SuppressWarnings("try")
public interface Domain {
/**
* Returns an {@link ArrayType} whose {@linkplain ArrayType#getComponentType() component type} is {@linkplain
* #sameType(TypeMirror, TypeMirror) the same as} the supplied {@code componentType}.
*
* @param componentType the component type; must not be {@code null}
*
* @return a non-{@code null} {@link ArrayType} whose {@linkplain ArrayType#getComponentType() component type} is
* {@linkplain #sameType(TypeMirror, TypeMirror) the same as} the supplied {@code componentType}
*
* @exception NullPointerException if {@code componentType} is {@code null}
*
* @exception IllegalArgumentException if {@code componentType} is not a valid component type
*
* @see javax.lang.model.util.Types#getArrayType(TypeMirror)
*/
public ArrayType arrayTypeOf(final TypeMirror componentType);
/**
* Returns a non-{@code null} {@link TypeMirror} representing the type of the supplied {@link Element} when that
* {@link Element} is viewed as a member of, or otherwise directly contained by, the supplied {@code containingType}.
*
* For example, when viewed as a member of the parameterized type {@link java.util.Set Set<String>}, the
* {@link java.util.Set#add(Object)} method (represented as an {@link ExecutableElement}) {@linkplain
* ExecutableElement#asType() has} a {@linkplain ExecutableType type} whose {@linkplain
* ExecutableType#getParameterTypes() method parameter is of type} {@link String} (not {@link String}'s erasure).
*
* @param containingType the containing {@link DeclaredType}; must not be {@code null}
*
* @param e the member {@link Element}; must not be {@code null}
*
* @return a non-{@code null} {@linkplain TypeMirror type} representing the {@linkplain Element#asType() type of} the
* supplied {@link Element} when viewed as a member of the supplied {@code containingType}; never {@code null}
*
* @exception NullPointerException if either {@code containingType} or {@code e} is {@code null}
*
* @exception IllegalArgumentException if {@code e} cannot be viewed as a member of the supplied {@code
* containingType} (because it is the wrong {@linkplain Element#getKind() kind}, for example)
*
* @see javax.lang.model.util.Types#asMemberOf(DeclaredType, Element)
*/
public TypeMirror asMemberOf(final DeclaredType containingType, final Element e);
/**
* Returns {@code true} if and only if the supplied {@code payload} (the first argument) is considered assignable to
* the supplied {@code receiver} (the second argument) according to the rules of the Java Language
* Specification.
*
* @param payload the {@link TypeMirror} being assigned; must not be {@code null}
*
* @param receiver the {@link TypeMirror} receiving the assignment; must not be {@code null}
*
* @return {@code true} if and only if {@code payload} is assignable to {@code receiver}
*
* @exception NullPointerException if either {@code payload} or {@code receiver} is {@code null}
*
* @exception IllegalArgumentException if either {@link TypeMirror} is not one that can take part in an assignment
*
* @see javax.lang.model.util.Types#isAssignable(TypeMirror, TypeMirror)
*
* @spec https://docs.oracle.com/javase/specs/jls/se21/html/jls-5.html#jls-5.2 Java Language Specification, section
* 5.2
*/
// Note the strange positioning of payload and receiver.
public boolean assignable(final TypeMirror payload, final TypeMirror receiver);
/**
* Returns the (non-{@code null}) binary name of the
* supplied {@link TypeElement}.
*
* @param e a {@link TypeElement}; must not be {@code null}
*
* @return a non-{@code null} {@link Name}
*
* @exception NullPointerException if {@code e} is {@code null}
*
* @see javax.lang.model.util.Elements#getBinaryName(TypeElement)
*
* @spec https://docs.oracle.com/javase/specs/jls/se21/html/jls-13.html#jls-13.1 Java Language Specification, section
* 13.1
*/
public Name binaryName(final TypeElement e);
/**
* Returns {@code true} if and only if the supplied {@link ExecutableElement} represents a bridge method.
*
* @param e an {@link ExecutableElement}; must not be {@code null}
*
* @return {@code true} if and only if the supplied {@link ExecutableElement} represents a bridge method
*
* @exception NullPointerException if {@code e} is {@code null}
*
* @see javax.lang.model.util.Elements#isBridge(ExecutableElement)
*
* @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-8.html#jls-8.4.8.3 Java Language Specification,
* section 8.4.8.3
*
* @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-15.html#jls-15.12.4.5 Java Language Specification,
* section 15.12.4.5
*/
public boolean bridge(final ExecutableElement e);
/**
* Applies capture
* conversion to the supplied {@link TypeMirror}, which is normally a {@linkplain TypeKind#WILDCARD wildcard
* type}.
*
* @param wildcard a {@link TypeMirror}; must not be {@code null}; if not a {@linkplain TypeKind#WILDCARD wildcard
* type}, then it will be returned unchanged
*
* @return a non-{@code null} {@link TypeMirror} representing the result of capture conversion applied to
* the supplied {@link TypeMirror}
*
* @exception NullPointerException if {@code wildcard} is {@code null}
*
* @see javax.lang.model.util.Types#capture(TypeMirror)
*
* @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-5.html#jls-5.1.10 Java Language Specification, section
* 5.1.10
*/
public TypeMirror capture(final TypeMirror wildcard);
/**
* Returns {@code true} if and only if {@code candidateContainer} contains {@code candidate}, according to
* the Java Language Specification,
* section 4.5.1.
*
* @param candidateContainer the putative containing type; normally a {@linkplain TypeKind#WILDCARD wildcard type};
* must not be {@code null}
*
* @param candidate the putative contained type; must not be {@code null}
*
* @return {@code true} if and only if {@code candidateContainer} contains {@code candidate}, according to
* the Java Language Specification,
* section 4.5.1; {@code false} otherwise
*
* @exception NullPointerException if either argument is {@code null}
*
* @exception IllegalArgumentException if either argument is either an {@linkplain TypeKind#EXECUTABLE executable
* type}, a {@linkplain TypeKind#MODULE module type}, or a {@linkplain TypeKind#PACKAGE package type}
*
* @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-4.html#jls-4.5.1 Java Language Specification, section
* 4.5.1
*/
public boolean contains(final TypeMirror candidateContainer, final TypeMirror candidate);
/**
* A convenience method that returns the {@link DeclaredType} {@linkplain TypeElement#asType() of} a {@link
* TypeElement} that bears the supplied {@code canonicalName}, or {@code null} if there is no such {@link
* TypeElement} (and therefore no such {@link DeclaredType}).
*
* @param canonicalName a valid canonical name; must not be {@code null}
*
* @return a {@link DeclaredType} with a {@link TypeKind} of {@link TypeKind#DECLARED}, or {@code null}
*
* @see #typeElement(CharSequence)
*
* @see #declaredType(TypeElement, TypeMirror...)
*
* @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-6.html#jls-6.7 Java Language Specification, section
* 6.7
*/
public default DeclaredType declaredType(final CharSequence canonicalName) {
final TypeElement e = this.typeElement(canonicalName);
return e == null ? null : this.declaredType(e);
}
/**
* Returns the {@link DeclaredType} {@linkplain TypeElement#asType() of} the supplied {@link TypeElement} with the
* supplied {@link TypeMirror} arguments (if any), yielding a parameterized type.
*
* Given a {@link TypeElement} representing the class named {@link java.util.Set java.util.Set} and a {@link
* TypeMirror} representing the type declared by {@link String java.lang.String}, for example, this method will return
* a {@link DeclaredType} representing the parameterized type corresponding to {@link java.util.Set
* java.util.Set<java.lang.String>}.
*
* The number of supplied type arguments must either equal the number of the supplied {@link TypeElement}'s
* {@linkplain TypeElement#getTypeParameters() formal type parameters}, or must be zero. If it is zero, and if the
* supplied {@link TypeElement} {@link #generic(Element) is generic}, then the supplied {@link TypeElement}'s raw type
* is returned.
*
* If a parameterized type is returned, {@linkplain DeclaredType#asElement() its TypeElement
} must not
* be contained within a {@linkplain #generic(Element) generic} outer class. The parameterized type {@code
* Outer.Inner}, for example, may be constructed by first using this method to get the type {@code
* Outer}, and then invoking {@link #declaredType(DeclaredType, TypeElement, TypeMirror...)}.
*
* @param typeElement a {@link TypeElement}; must not be {@code null}
*
* @param typeArguments any type arguments (represented by {@link TypeMirror}s); must not be {@code null}
*
* @return a non-{@code null} {@link DeclaredType} with a {@link TypeKind} of {@link TypeKind#DECLARED}
*
* @exception NullPointerException if {@code typeElement} or {@code typeArguments} is {@code null}
*
* @see javax.lang.model.util.Types#getDeclaredType(TypeElement, TypeMirror...)
*
* @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-4.html#jls-4.5 Java Language Specification, section 4.5
*/
public DeclaredType declaredType(final TypeElement typeElement,
final TypeMirror... typeArguments);
/**
* Returns the {@link DeclaredType} {@linkplain TypeElement#asType() of} the supplied {@link TypeElement} with the
* supplied {@link TypeMirror} arguments (if any), given a containing {@link DeclaredType} of which it is a member,
* yielding a parameterized type.
*
* Given a {@link DeclaredType} representing the parameterized type corresponding to {@code Outer<}{@link
* String}{@code >} (see the {@link #declaredType(TypeElement, TypeMirror...)} method), a {@link TypeElement}
* representing the class named {@code Outer.Inner} and a {@link DeclaredType} representing the non-generic class
* corresponding to {@link Number}, for example, this method will return a {@link DeclaredType} representing the
* parameterized type corresponding to {@code Outer<}{@link String}{@code >}{@code .Inner<}{@link Number}{@code >}.
*
* The number of supplied type arguments must either equal the number of the supplied {@link TypeElement}'s
* {@linkplain TypeElement#getTypeParameters() formal type parameters}, or must be zero. If it is zero, and if the
* supplied {@link TypeElement} {@link #generic(Element) is generic}, then the supplied {@link TypeElement}'s raw type
* is returned.
*
* @param enclosingType a {@link DeclaredType} representing the containing type; must not be {@code null}
*
* @param typeElement a {@link TypeElement}; must not be {@code null}
*
* @param typeArguments any type arguments (represented by {@link TypeMirror}s); must not be {@code null}
*
* @return a non-{@code null} {@link DeclaredType} with a {@link TypeKind} of {@link TypeKind#DECLARED}
*
* @exception NullPointerException if {@code enclosingType}, {@code typeElement}, or {@code typeArguments} is {@code
* null}
*
* @see #declaredType(TypeElement, TypeMirror...)
*
* @see javax.lang.model.util.Types#getDeclaredType(DeclaredType, TypeElement, TypeMirror...)
*
* @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-4.html#jls-4.5 Java Language Specification, section 4.5
*/
public DeclaredType declaredType(final DeclaredType enclosingType,
final TypeElement typeElement,
final TypeMirror... typeArguments);
/**
* Returns a non-{@code null} {@link List} of the direct supertypes of the supplied {@link TypeMirror},
* which is normally a {@linkplain TypeKind#DECLARED declared type}.
*
* @param t a {@link TypeMirror}; must not be {@code null}; must not be an {@linkplain TypeKind#EXECUTABLE executable
* type}, a {@linkplain TypeKind#MODULE module type}, or a {@linkplain TypeKind#PACKAGE package type}
*
* @return a non-{@code null}, immutable {@link List} of {@link TypeMirror}s representing the direct supertypes
*
* @exception NullPointerException if {@code t} is {@code null}
*
* @exception IllegalArgumentException if either argument is either an {@linkplain TypeKind#EXECUTABLE executable
* type}, a {@linkplain TypeKind#MODULE module type}, or a {@linkplain TypeKind#PACKAGE package type}
*
* @see javax.lang.model.util.Types#directSupertypes(TypeMirror)
*
* @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-4.html#jls-4.10 Java Language Specification, section
* 4.10
*/
public List extends TypeMirror> directSupertypes(final TypeMirror t);
/**
* Returns the {@link Element} responsible for declaring the supplied {@link TypeMirror}, which is most commonly a
* {@link DeclaredType}, a {@link TypeVariable}, a {@link NoType} with a {@link TypeKind} of {@link TypeKind#MODULE},
* or a {@link NoType} with a {@link TypeKind} of {@link TypeKind#PACKAGE}, or {@code null} if there is no
* such {@link Element}.
*
* @param t a {@link TypeMirror}; must not be {@code null}
*
* @return an {@link Element}, or {@code null}
*
* @exception NullPointerException if {@code t} is {@code null}
*
* @see javax.lang.model.util.Types#asElement(TypeMirror)
*/
public Element element(final TypeMirror t);
/**
* A convenience method that returns the element type of the supplied {@link TypeMirror}.
*
* The element type of an {@linkplain TypeKind#ARRAY array type} is the element type of its {@linkplain
* ArrayType#getComponentType() component type}.
.
*
* The element type of every other kind of type is the type itself. Note that the semantics of the prior sentence
* diverge deliberately, primarily for convenience, from those of the relevant section in the Java Language
* Specification.
*
* @param t a {@link TypeMirror}; must not be {@code null}
*
* @return the element type of the supplied {@link TypeMirror}; never {@code null}
*
* @exception NullPointerException if {@code t} is {@code null}
*
* @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-10.html#jls-10.1 Java Language Specification, section
* 10.1
*/
public default TypeMirror elementType(final TypeMirror t) {
return switch (t) {
case null -> throw new NullPointerException("t");
case UniversalType ut -> ut.elementType();
default -> {
try (var lock = lock()) {
yield t.getKind() == TypeKind.ARRAY ? this.elementType(((ArrayType)t).getComponentType()) : t;
}
}
};
}
/**
* Returns the erasure of the supplied {@link TypeMirror}.
*
* @param a {@link TypeMirror} specialization
*
* @param t the {@link TypeMirror} representing the type whose erasure should be returned; must not be {@code null}
*
* @return the erasure of the supplied {@link TypeMirror}; never {@code null}
*
* @exception NullPointerException if {@code t} is {@code null}
*
* @exception IllegalArgumentException if {@code t} is a {@link NoType} with a {@link TypeKind} of {@link
* TypeKind#MODULE}, or a {@link NoType} with a {@link TypeKind} of {@link TypeKind#PACKAGE}
*
* @see javax.lang.model.util.Types#erasure(TypeMirror)
*
* @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-4.html#jls-4.6 Java Language Specification, section
* 4.6
*/
public T erasure(final T t);
/**
* A convenience method that returns an {@link ExecutableElement} representing the static initializer, constructor or
* method described by the supplied arguments, or {@code null} if no such {@link ExecutableElement}
* exists.
*
* @param declaringElement a {@link TypeElement} representing the class that declares the executable; must not be
* {@code null}
*
* @param returnType the {@linkplain ExecutableElement#getReturnType() return type} of the executable; must not be
* {@code null}
*
* @param name the {@linkplain ExecutableElement#getSimpleName() name} of the executable; must not be {@code null}
*
* @param parameterTypes {@link TypeMirror}s that represent the executable's {@linkplain
* ExecutableElement#getParameters() parameter types}
*
* @return an {@link ExecutableElement} with an {@link ElementKind} of {@link ElementKind#CONSTRUCTOR}, {@link
* ElementKind#METHOD}, or {@link ElementKind#STATIC_INIT}, or {@code null}
*
* @exception NullPointerException if any argument is {@code null}
*/
public default ExecutableElement executableElement(final TypeElement declaringElement,
final TypeMirror returnType,
final CharSequence name,
final TypeMirror... parameterTypes) {
return switch (declaringElement) {
case null -> throw new NullPointerException("declaringElement");
case UniversalElement ue -> {
final List extends UniversalElement> ees = ue.getEnclosedElements();
yield ees.stream()
.sequential()
.filter(e -> e.getKind().isExecutable() && e.getSimpleName().contentEquals(name))
.map(UniversalElement.class::cast)
.filter(ee -> {
if (!this.sameType(returnType, ee.getReturnType())) {
return false;
}
final List extends UniversalElement> ps = ee.getParameters();
if (ps.size() != parameterTypes.length) {
return false;
}
for (int i = 0; i < parameterTypes.length; i++) {
if (!this.sameType(ps.get(i).asType(), parameterTypes[i])) {
return false;
}
}
return true;
})
.findFirst()
.orElse(null);
}
default -> {
try (var lock = this.lock()) {
final List extends Element> ees = declaringElement.getEnclosedElements();
yield ees.stream()
.sequential()
.filter(e -> e.getKind().isExecutable() && e.getSimpleName().contentEquals(name))
.map(ExecutableElement.class::cast)
.filter(ee -> {
if (!this.sameType(returnType, ee.getReturnType())) {
return false;
}
final List extends VariableElement> ps = ee.getParameters();
if (ps.size() != parameterTypes.length) {
return false;
}
for (int i = 0; i < parameterTypes.length; i++) {
if (!this.sameType(ps.get(i).asType(), parameterTypes[i])) {
return false;
}
}
return true;
})
.findFirst()
.orElse(null);
}
}
};
}
/**
* A convenience method that returns {@code true} if and only if the supplied {@link Element} is generic.
*
* @param e an {@link Element}; must not be {@code null}
*
* @return {@code true} if and only if the supplied {@link Element} is generic; {@code false} otherwise
*
* @exception NullPointerException if {@code e} is {@code null}
*
* @see Parameterizable
*
* @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-8.html#jls-8.1.2 Java Language Specification, section
* 8.1.2
*
* @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-8.html#jls-8.4.4 Java Language Specification, section
* 8.4.4
*
* @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-8.html#jls-8.8.4 Java Language Specification, section
* 8.8.4
*
* @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-9.html#jls-9.1.2 Java Language Specification, section
* 9.1.2
*/
public default boolean generic(final Element e) {
return switch (e) {
case null -> throw new NullPointerException("e");
case UniversalElement ue -> ue.generic();
case Parameterizable p -> {
try (var lock = this.lock()) {
yield switch (e.getKind()) {
case CLASS, CONSTRUCTOR, ENUM, INTERFACE, METHOD, RECORD -> !p.getTypeParameters().isEmpty();
default -> false;
};
}
}
default -> false;
};
}
/**
* A convenience method that returns {@code true} if and only if the supplied {@link TypeMirror} is declared by an
* {@link Element} that {@linkplain #generic(Element) is generic}.
*
* @param t a {@link TypeMirror}; must not be {@code null}
*
* @return {@code true} if and only if the supplied {@link TypeMirror} is declared by an {@link Element} that
* {@linkplain #generic(Element) is generic}
*
* @exception NullPointerException if {@code t} is {@code null}
*
* @see #generic(Element)
*
* @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-8.html#jls-8.1.2 Java Language Specification, section
* 8.1.2
*
* @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-8.html#jls-8.4.4 Java Language Specification, section
* 8.4.4
*
* @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-8.html#jls-8.8.4 Java Language Specification, section
* 8.8.4
*
* @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-9.html#jls-9.1.2 Java Language Specification, section
* 9.1.2
*/
public default boolean generic(final TypeMirror t) {
return switch (t) {
case null -> throw new NullPointerException("t");
case UniversalType ut -> ut.generic();
default -> {
try (var lock = this.lock()) {
final Element e = this.element(t);
yield e != null && this.generic(e);
}
}
};
}
/**
* A convenience method that returns {@code true} if and only if the supplied {@link Element} represents the (essentially
* primordial) {@code java.lang.Object} {@link Element}.
*
* @param e an {@link Element}; must not be {@code null}
*
* @return {@code true} if and only if the supplied {@link Element} represents the (essentially
* primordial) {@code java.lang.Object} {@link Element}; {@code false} otherwise
*
* @exception NullPointerException if {@code e} is {@code null}
*/
public default boolean javaLangObject(final Element e) {
return switch (e) {
case null -> throw new NullPointerException("e");
case UniversalElement ue -> ue.javaLangObject();
default -> {
try (var lock = this.lock()) {
yield
e.getKind() == ElementKind.CLASS &&
((QualifiedNameable)e).getQualifiedName().contentEquals("java.lang.Object");
}
}
};
}
/**
* A convenience method that returns {@code true} if and only if the supplied {@link TypeMirror} represents the {@link
* DeclaredType} declared by the (essentially primordial) {@code java.lang.Object} element.
*
* @param t a {@link TypeMirror}; must not be {@code null}
*
* @return {@code true} represents the {@link
* DeclaredType} declared by the (essentially primordial) {@code java.lang.Object} element; {@code false} otherwise
*
* @exception NullPointerException if {@code t} is {@code null}
*
* @see #javaLangObject(Element)
*/
public default boolean javaLangObject(final TypeMirror t) {
return switch (t) {
case null -> throw new NullPointerException("t");
case UniversalType ut -> ut.javaLangObject();
default -> {
try (var lock = this.lock()) {
yield
t.getKind() == TypeKind.DECLARED &&
javaLangObject(((DeclaredType)t).asElement());
}
}
};
}
/**
* A convenience method that returns the {@link TypeElement} representing the class named {@link Object
* java.lang.Object}.
*
* @return a non-{@code null} {@link TypeElement} whose {@linkplain TypeElement#getQualifiedName() qualified name} is
* {@linkplain Name#contentEquals(CharSequence) equal to} {@code java.lang.Object}
*
* @see #typeElement(CharSequence)
*/
public default TypeElement javaLangObject() {
return this.typeElement("java.lang.Object");
}
/**
* Semantically locks an opaque lock used to serialize symbol completion, and returns it in the form of an {@link
* Unlockable}.
*
* Implementations of this method must not return {@code null}.
*
* @return an {@link Unlockable} in a semantically locked state; never {@code null}
*
* @see Unlockable#close()
*/
public Unlockable lock();
/**
* Returns a {@link ModuleElement} representing the module {@linkplain ModuleElement#getQualifiedName() named} by the
* supplied {@code qualifiedName}, or {@code null} if there is no such {@link ModuleElement}.
*
* @param qualifiedName a name suitable for naming a module; must not be {@code null}; may be {@linkplain
* CharSequence#isEmpty() empty}, in which case a {@link ModuleElement} representing an unnamed module will
* be returned
*
* @return a {@link ModuleElement}, or {@code null}
*
* @exception NullPointerException if {@code qualifiedName} is {@code null}
*
* @see javax.lang.model.util.Elements#getModuleElement(CharSequence)
*
* @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-7.html#jls-7.7 Java Language Specification, section
* 7.7
*/
public ModuleElement moduleElement(final CharSequence qualifiedName);
/**
* Returns a {@link Name} representing the supplied {@link CharSequence}.
*
* @param name a {@link CharSequence}; must not be {@code null}
*
* @return a non-{@code null} {@link Name} representing the supplied {@link name}
*
* @exception NullPointerException if {@code name} is {@code null}
*
* @see #lock()
*
* @see javax.lang.model.util.Elements#getName(CharSequence)
*/
public Name name(final CharSequence name);
/**
* Returns a {@link NoType} {@linkplain TypeMirror#getKind() bearing} the supplied {@link TypeKind}, if the supplied
* {@link TypeKind} is either {@link TypeKind#NONE} or {@link TypeKind#VOID}.
*
* @param kind a {@link TypeKind}; must be either {@link TypeKind#NONE} or {@link TypeKind#VOID}
*
* @return a non-{@code null} {@link NoType} {@linkplain TypeMirror#getKind() bearing} the supplied {@link TypeKind}
*
* @exception NullPointerException if {@code kind} is {@code null}
*
* @exception IllegalArgumentException if {@code kind} is non-{@code null} and neither {@link TypeKind#NONE} nor
* {@link TypeKind#VOID}
*
* @see TypeKind#NONE
*
* @see TypeKind#VOID
*
* @see javax.lang.model.util.Types#getNoType(TypeKind)
*
* @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-8.html#jls-8.4.5 Java Language Specification, section
* 8.4.5
*/
public NoType noType(final TypeKind kind);
/**
* Returns a {@link NullType} implementation {@linkplain TypeMirror#getKind() whose TypeKind
} is {@link
* TypeKind#NULL}.
*
* @return a non-{@code null} {@link NullType}
*
* @see javax.lang.model.util.Types#getNullType()
*
* @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-4.html#jls-4.1 Java Language Specification, section 4.1
*/
public NullType nullType();
/**
* Returns the {@linkplain Origin origin} of the supplied {@link Element}.
*
* @param e a non-{@code null} {@link Element}
*
* @return a non-{@code null} {@link Origin}
*
* @see Elements#getOrigin(Element)
*/
public Origin origin(final Element e);
/**
* Returns a {@link PackageElement} representing the package bearing the supplied {@code canonicalName}, or
* {@code null} if there is no such {@link PackageElement}.
*
* @param canonicalName a canonical name suitable for naming a package; must not be {@code null}; may be {@linkplain
* CharSequence#isEmpty() empty}, in which case a {@link ModuleElement} representing an unnamed package will
* be returned
*
* @return a {@link PackageElement}, or {@code null}
*
* @exception NullPointerException if {@code canonicalName} is {@code null}
*
* @see javax.lang.model.util.Elements#getPackageElement(CharSequence)
*
* @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-6.html#jls-6.7 Java Language Specification, section
* 6.7
*/
public PackageElement packageElement(final CharSequence canonicalName);
/**
* Returns a {@link PackageElement} representing the package bearing the supplied {@code canonicalName} as seen from
* the module represented by the supplied {@link ModuleElement}, or {@code null} if there is no such {@link
* PackageElement}.
*
* @param asSeenFrom a {@link ModuleElement}; must not be {@code null}
*
* @param canonicalName a canonical name suitable for naming a package; must not be {@code null}; may be {@linkplain
* CharSequence#isEmpty() empty}, in which case a {@link ModuleElement} representing an unnamed package will
* be returned
*
* @return a {@link PackageElement}, or {@code null}
*
* @exception NullPointerException if either {@code asSeenFrom} or {@code canonicalName} is {@code null}
*
* @see javax.lang.model.util.Elements#getPackageElement(ModuleElement, CharSequence)
*
* @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-6.html#jls-6.7 Java Language Specification, section
* 6.7
*/
public PackageElement packageElement(final ModuleElement asSeenFrom, final CharSequence canonicalName);
/**
* A convenience method that returns {@code true} if and only if {@code t} is a {@link DeclaredType}, {@linkplain
* TypeMirror#getKind() has a TypeKind
} of {@link TypeKind#DECLARED DECLARED}, and {@linkplain
* DeclaredType#getTypeArguments() has an empty type arguments list}.
*
* @param t a {@link TypeMirror}; must not be {@code null}
*
* @return {@code true} if and only if {@code t} is a {@link DeclaredType}, {@linkplain
* TypeMirror#getKind() has a TypeKind
} of {@link TypeKind#DECLARED DECLARED}, and {@linkplain
* DeclaredType#getTypeArguments() has an empty type arguments list}; {@code false} otherwise
*
* @exception NullPointerException if {@code t} is {@code null}
*/
public default boolean parameterized(final TypeMirror t) {
return switch (t) {
case null -> throw new NullPointerException("t");
case UniversalType ut -> ut.parameterized();
default -> {
try (var lock = this.lock()) {
yield t.getKind() == TypeKind.DECLARED && !((DeclaredType)t).getTypeArguments().isEmpty();
}
}
};
}
/**
* Returns the result of applying unboxing conversion to the (logical) {@link TypeElement} bearing the
* supplied {@code canonicalName}.
*
* @param canonicalName a canonical name of either a primitive type or a so-called "wrapper" type; must not be {@code
* null}
*
* @return a non-{@code null} {@link PrimitiveType} with a {@linkplain TypeKind#isPrimitive() primitive} {@link
* TypeKind}
*
* @exception NullPointerException if {@code canonicalName} is {@code null}
*
* @exception IllegalArgumentException if {@code canonicalName} {@linkplain #toString(CharSequence) converted to a
* String
} {@linkplain String#equals(Object) is not equal to} {@code boolean}, {@code byte}, {@code
* char}, {@code double}, {@code float}, {@code int}, {@code long}, {@code short}, {@link Boolean java.lang.Boolean},
* {@link Byte java.lang.Byte}, {@link Character java.lang.Character}, {@link Double java.lang.Double}, {@link Float
* java.lang.Float}, {@link Integer java.lang.Integer}, {@link Long java.lang.Long}, or {@link Short java.lang.Short}
*
* @see #primitiveType(TypeKind)
*
* @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-5.html#jls-5.1.8 Java Language Specification, section
* 5.1.8
*
* @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-6.html#jls-6.7 Java Language Specification, section
* 6.7
*/
// (Convenience.)
// (Unboxing.)
public default PrimitiveType primitiveType(final CharSequence canonicalName) {
final String s = this.toString(Objects.requireNonNull(canonicalName, "canonicalName"));
return switch (s) {
case "boolean", "java.lang.Boolean" -> this.primitiveType(TypeKind.BOOLEAN);
case "byte", "java.lang.Byte" -> this.primitiveType(TypeKind.BYTE);
case "char", "java.lang.Character" -> this.primitiveType(TypeKind.CHAR);
case "double", "java.lang.Double" -> this.primitiveType(TypeKind.DOUBLE);
case "float", "java.lang.Float" -> this.primitiveType(TypeKind.FLOAT);
case "int", "java.lang.Integer" -> this.primitiveType(TypeKind.INT);
case "long", "java.lang.Long" -> this.primitiveType(TypeKind.LONG);
case "short", "java.lang.Short" -> this.primitiveType(TypeKind.SHORT);
default -> throw new IllegalArgumentException("canonicalName: " + s);
};
}
/**
* Returns the result of applying unboxing conversion to the {@linkplain Element#asType() type declared by
* the supplied TypeElement
}.
*
* @param e a {@link TypeElement}; must not be {@code null}
*
* @return a non-{@code null} {@link PrimitiveType} with a {@linkplain TypeKind#isPrimitive() primitive} {@link
* TypeKind}
*
* @exception NullPointerException if {@code e} is {@code null}
*
* @exception IllegalArgumentException if there is no unboxing conversion that can be applied to the {@linkplain
* Element#asType() type declared by e
}
*
* @see javax.lang.model.util.Types#unboxedType(TypeMirror)
*
* @see #primitiveType(TypeMirror)
*
* @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-5.html#jls-5.1.8 Java Language Specification, section
* 5.1.8
*/
// (Convenience.)
// (Unboxing.)
public default PrimitiveType primitiveType(final TypeElement e) {
return this.primitiveType(e.asType());
}
/**
* Returns the {@link PrimitiveType} corresponding to the supplied {@link TypeKind} (if it {@linkplain
* TypeKind#isPrimitive() is primitive}).
*
* @param kind a {@linkplain TypeKind#isPrimitive() primitive} {@link TypeKind}; must not be {@code null}
*
* @return a non-{@code null} {@link PrimitiveType} {@linkplain TypeMirror#getKind() with} a {@linkplain
* TypeKind#isPrimitive() primitive} {@link TypeKind}
*
* @exception NullPointerException if {@code kind} is {@code null}
*
* @exception IllegalArgumentException if {@code kind} {@linkplain TypeKind#isPrimitive() is not primitive}
*
* @see javax.lang.model.util.Types#getPrimitiveType(TypeKind)
*
* @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-4.html#jls-4.2 Java Language Specification, section
* 4.2
*/
// (Canonical.)
public PrimitiveType primitiveType(final TypeKind kind);
/**
* Returns the result of applying unboxing conversion to the supplied {@link TypeMirror}.
*
* @param t a {@link TypeMirror}; must not be {@code null}
*
* @return a non-{@code null} {@link PrimitiveType} with a {@linkplain TypeKind#isPrimitive() primitive} {@link
* TypeKind}
*
* @exception NullPointerException if {@code t} is {@code null}
*
* @exception IllegalArgumentException if there is no unboxing conversion that can be applied to {@code t}
*
* @see javax.lang.model.util.Types#unboxedType(TypeMirror)
*
* @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-5.html#jls-5.1.8 Java Language Specification, section
* 5.1.8
*/
// (Canonical.)
// (Unboxing.)
public PrimitiveType primitiveType(final TypeMirror t);
/**
* A convenience method that returns {@code true} if and only if the supplied {@link TypeMirror} is a raw
* type according to the rules
* of the Java Language Specification
*
* @param t a {@link TypeMirror}; must not be {@code null}
*
* @return {@code true} if and only if the supplied {@link TypeMirror} is a raw type according to the rules of the Java Language
* Specification
*
* @exception NullPointerException if {@code t} is {@code null}
*
* @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-4.html#jls-4.8 Java Language Specification, section 4.8
*/
public default boolean raw(final TypeMirror t) {
return switch (t) {
case null -> throw new NullPointerException("t");
case UniversalType ut -> ut.raw();
default -> {
try (var lock = this.lock()) {
yield switch (t.getKind()) {
case ARRAY -> raw(elementType((ArrayType)t));
case DECLARED -> {
final DeclaredType dt = (DeclaredType)t;
yield generic(dt.asElement()) && dt.getTypeArguments().isEmpty();
}
default -> false;
};
}
}
};
}
/**
* A convenience method that returns the raw type corresponding to {@code t}, or {@code null} if
* {@code t} is incapable of yielding
* a raw type.
*
* Overrides of this method must conform to the requirements imposed by the relevant section of the relevant
* version of the Java Language Specification concerning raw types.
*
* @param t a {@link TypeMirror}; must not be {@code null}
*
* @return the raw type corresponding to the supplied {@link TypeMirror}, or {@code null} if {@code t} is incapable of yielding a raw type
*
* @exception NullPointerException if {@code t} is {@code null}
*
* @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-4.html#jls-4.8 Java Language Specification, section
* 4.8
*/
public default TypeMirror rawType(final TypeMirror t) {
return switch (t) {
case null -> throw new NullPointerException("t");
case UniversalType ut -> ut.rawType();
default -> {
try (var lock = this.lock()) {
yield switch (t.getKind()) {
case ARRAY -> this.rawType(this.elementType(t)); // recursive
default -> this.parameterized(t) ? this.erasure(t) : null;
};
}
}
};
}
/**
* Returns a {@link RecordComponentElement} corresponding to the supplied {@link ExecutableElement}, or {@code
* null} if there is no such {@link RecordComponentElement}.
*
* @param e an {@link ExecutableElement} {@linkplain ExecutableElement#getEnclosingElement() enclosed by} a record
* representing an accessor method; must not be {@code null}
*
* @return a {@link RecordComponentElement} corresponding to the supplied {@link ExecutableElement}, or {@code null}
*
* @exception NullPointerException if {@code e} is {@code null}
*
* @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-8.html#jls-8.10.3 Java Language Specification, section
* 8.10.3
*/
public RecordComponentElement recordComponentElement(final ExecutableElement e);
/**
* Returns {@code true} if and only if the two arguments represent the same type.
*
* This method differs from the {@link javax.lang.model.util.Types#isSameType(TypeMirror, TypeMirror)} method in
* two ways:
*
*
*
* - Its arguments may be {@code null}. If both arguments are {@code null}, {@code true} is returned. If only one
* argument is {@code null}, {@code false} is returned.
*
* - If the same Java object reference is passed as both arguments, {@code true} is returned (even if it {@linkplain
* TypeMirror#getKind() has a
TypeKind
} of {@link TypeKind#WILDCARD}).
*
*
*
* @param t0 the first {@link TypeMirror}; may be {@code null}
*
* @param t1 the second {@link TypeMirror}; may be {@code null}
*
* @return {@code true} if and only if the two arguments represent the same type; {@code false} otherwise
*
* @see javax.lang.model.util.Types#isSameType(TypeMirror, TypeMirror)
*
* @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-4.html#jls-4.3.4 Java Language Specification, section
* 4.3.4
*
* @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-4.html#jls-4.5.1 Java Language Specification, section
* 4.5.1
*/
public boolean sameType(final TypeMirror t0, final TypeMirror t1);
/**
* Returns {@code true} if and only if {@code et0} is a subsignature of {@code et1}.
*
* @param et0 the first {@link ExecutableType}; must not be {@code null}
*
* @param et1 the second {@link ExecutableType}; must not be {@code null}
*
* @return {@code true} if and only if {@code et0} is a subsignature of {@code et1}
*
* @exception NullPointerException if either argument is {@code null}
*
* @exception ClassCastException if this method is implemented in terms of the {@link
* javax.lang.model.util.Types#isSubsignature(ExecutableType, ExecutableType)} method, and if each of the supplied
* {@link ExecutableType} arguments does not have an {@linkplain TypeKind#EXECUTABLE EXECUTABLE
* TypeKind
}; this exception type is undocumented by the {@link
* javax.lang.model.util.Types#isSubsignature(ExecutableType, ExecutableType)} method and so is subject to change
* without prior notice
*
* @see javax.lang.model.util.Types#isSubsignature(ExecutableType, ExecutableType)
*
* @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-8.html#jls-8.4.2 Java Language Specification, section
* 8.4.2
*/
public boolean subsignature(final ExecutableType et0, final ExecutableType et1);
/**
* Returns {@code true} if and only if {@code candidateSubtype} is a subtype of {@code supertype}.
*
* @param candidateSubtype the first {@link TypeMirror}; must not be {@code null}
*
* @param supertype the second {@link TypeMirror}; must not be {@code null}
*
* @return {@code true} if and only if {@code candidateSubtype} is a subtype of {@code supertype}
*
* @exception NullPointerException if either argument is {@code null}
*
* @see javax.lang.model.util.Types#isSubtype(TypeMirror, TypeMirror)
*
* @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-4.html#jls-4.10 Java Language Specification, section
* 4.10
*/
public boolean subtype(TypeMirror candidateSubtype, TypeMirror supertype);
/**
* Converts the supplied {@link CharSequence}, which is often a {@link Name}, into a {@link String}, and returns the
* conversion, {@linkplain #lock() locking} when appropriate to serialize symbol completion.
*
* @param name the {@link CharSequence} to convert; may be {@code null} in which case {@code null} will be returned
*
* @return a {@link String}, or {@code null} if {@code name} was {@code null}
*
* @see #lock()
*/
public default String toString(final CharSequence name) {
return switch (name) {
case null -> null;
case String s -> s;
case StringName sn -> sn.value();
case Name n -> {
try (var lock = this.lock()) {
yield n.toString();
}
}
default -> name.toString();
};
}
/**
* Returns a {@link TypeElement} representing the element bearing the supplied canonical name, or
* {@code null} if there is no such {@link TypeElement}.
*
* @param canonicalName a valid canonical name; must not be {@code null}
*
* @return a {@link TypeElement}, or {@code null}
*
* @exception NullPointerException if {@code canonicalName} is {@code null}
*
* @see javax.lang.model.util.Elements#getTypeElement(CharSequence)
*
* @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-6.html#jls-6.7 Java Language Specification, section
* 6.7
*/
public TypeElement typeElement(final CharSequence canonicalName);
/**
* Returns a {@link TypeElement} representing the element bearing the supplied canonical name, as read or
* seen from the module represented by the supplied {@link ModuleElement}, or {@code null} if there is no such
* {@link TypeElement}.
*
* @param asSeenFrom a {@link ModuleElement}; must not be {@code null}
*
* @param canonicalName a valid canonical name; must not be {@code null}
*
* @return a {@link TypeElement}, or {@code null}
*
* @exception NullPointerException if either {@code asSeenFrom} or {@code canonicalName} is {@code null}
*
* @see javax.lang.model.util.Elements#getTypeElement(ModuleElement, CharSequence)
*
* @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-6.html#jls-6.7 Java Language Specification, section
* 6.7
*/
public TypeElement typeElement(final ModuleElement asSeenFrom, final CharSequence canonicalName);
/**
* Returns a {@link TypeElement} representing the result of applying boxing conversion to the primitive
* type represented by the supplied {@link PrimitiveType} argument.
*
* The default implementation of this method calls the {@link #typeElement(TypeKind)} method with the supplied
* {@link PrimitiveType}'s {@linkplain TypeMirror#getKind() affiliated TypeKind
} and returns its
* result.
*
* @param t a {@link PrimitiveType} with a {@link TypeKind} that {@linkplain TypeKind#isPrimitive() is primitive};
* must not be {@code null}
*
* @return a non-{@code null} {@link TypeElement} representing the result of applying boxing conversion to the
* supplied argument
*
* @exception NullPointerException if {@code t} is {@code null}
*
* @exception ClassCastException if this method is implemented in terms of the {@link
* javax.lang.model.util.Types#boxedClass(PrimitiveType)} method, and if the supplied {@link PrimitiveType} does not
* have a {@linkplain TypeKind#isPrimitive() primitive TypeKind
}; this exception type is undocumented by
* the {@link javax.lang.model.util.Types#boxedClass(PrimitiveType)} method and so is subject to change without prior
* notice
*
* @exception IllegalArgumentException if {@code primitiveTypeKind} {@linkplain TypeKind#isPrimitive() is not
* primitive}
*
* @see #typeElement(TypeKind)
*
* @see javax.lang.model.util.Types#boxedClass(PrimitiveType)
*
* @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-5.html#jls-5.1.7 Java Language Specification, section
* 5.1.7
*/
// (Canonical.)
// (Boxing.)
public default TypeElement typeElement(final PrimitiveType t) {
return switch (t) {
case null -> throw new NullPointerException("t");
case UniversalType ut -> this.typeElement(ut.getKind());
default -> {
try (var lock = this.lock()) {
yield this.typeElement(t.getKind());
}
}
};
}
/**
* Returns a {@link TypeElement} representing the result of applying boxing conversion to the primitive
* type represented by the supplied {@link TypeKind} argument, if it {@linkplain TypeKind#isPrimitive() is primitive}.
*
* @param primitiveTypeKind a {@link TypeKind} that {@linkplain TypeKind#isPrimitive() is primitive}; must not be
* {@code null}
*
* @return a non-{@code null} {@link TypeElement} representing the result of applying boxing conversion to the
* supplied argument
*
* @exception IllegalArgumentException if {@code primitiveTypeKind} {@linkplain TypeKind#isPrimitive() is not
* primitive}
*
* @see #typeElement(PrimitiveType)
*
* @see javax.lang.model.util.Types#boxedClass(PrimitiveType)
*
* @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-5.html#jls-5.1.7 Java Language Specification, section
* 5.1.7
*/
// (Convenience.)
// (Boxing.)
public default TypeElement typeElement(final TypeKind primitiveTypeKind) {
return switch (primitiveTypeKind) {
case BOOLEAN -> this.typeElement("java.lang.Boolean");
case BYTE -> this.typeElement("java.lang.Byte");
case CHAR -> this.typeElement("java.lang.Character");
case DOUBLE -> this.typeElement("java.lang.Double");
case FLOAT -> this.typeElement("java.lang.Float");
case INT -> this.typeElement("java.lang.Integer");
case LONG -> this.typeElement("java.lang.Long");
case SHORT -> this.typeElement("java.lang.Short");
default -> throw new IllegalArgumentException("primitiveTypeKind: " + primitiveTypeKind);
};
}
/**
* Returns the {@link TypeParameterElement} {@linkplain Parameterizable#getTypeParameters() contained} by the supplied
* {@link Parameterizable} whose {@linkplain TypeParameterElement#getSimpleName() name} {@linkplain
* Name#contentEquals(CharSequence) is equal to} the supplied {@code name}, or {@code null} if there is no
* such {@link TypeParameterElement}.
*
* @param p a {@link Parameterizable}; must not be {@code null}
*
* @param name a name valid for a type parameter; must not be {@code null}
*
* @return a {@link TypeParameterElement}, or {@code null}
*/
public default TypeParameterElement typeParameterElement(Parameterizable p, final CharSequence name) {
Objects.requireNonNull(p, "p");
Objects.requireNonNull(name, "name");
while (p != null) {
switch (p) {
case UniversalElement ue:
for (final UniversalElement tpe : ue.getTypeParameters()) {
if (tpe.getSimpleName().contentEquals(name)) {
return tpe;
}
}
p = ue.getEnclosingElement();
break;
default:
try (var lock = this.lock()) {
for (final TypeParameterElement tpe : p.getTypeParameters()) {
if (tpe.getSimpleName().contentEquals(name)) {
return tpe;
}
}
p = (Parameterizable)((Element)p).getEnclosingElement();
}
break;
}
}
return null;
}
/**
* A convenience method that returns the {@link TypeVariable} {@linkplain TypeParameterElement#asType() declared by}
* the {@link TypeParameterElement} {@linkplain Parameterizable#getTypeParameters() contained} by the supplied {@link
* Parameterizable} whose {@linkplain TypeParameterElement#getSimpleName() name} {@linkplain
* Name#contentEquals(CharSequence) is equal to} the supplied {@code name}, or {@code null} if there is no
* such {@link TypeParameterElement} or {@link TypeVariable}.
*
* @param p a {@link Parameterizable}; must not be {@code null}
*
* @param name a name valid for a type parameter; must not be {@code null}
*
* @return a {@link TypeVariable}, or {@code null}
*
* @see #typeParameterElement(Parameterizable, CharSequence)
*/
public default TypeVariable typeVariable(Parameterizable p, final CharSequence name) {
final TypeParameterElement e = this.typeParameterElement(p, name);
return e == null ? null : (TypeVariable)e.asType();
}
/**
* A convenience method that returns the first {@link VariableElement} with a {@linkplain ElementKind#isVariable()
* variable ElementKind
} and {@linkplain Element#getSimpleName() bearing} the supplied {@code simpleName}
* that the supplied {@code enclosingElement} {@linkplain Element#getEnclosedElements() encloses}, or {@code
* null} if there is no such {@link VariableElement}.
*
* @param enclosingElement an {@link Element}; must not be {@code null}
*
* @param simpleName a {@link CharSequence}; must not be {@code null}
*
* @return a {@link VariableElement}, or {@code null}
*
* @exception NullPointerException if either argument is {@code null}
*
* @see Element#getEnclosedElements()
*
* @see ElementKind#isVariable()
*
* @see Element#getSimpleName()
*
* @see VariableElement
*/
public default VariableElement variableElement(final Element enclosingElement, final CharSequence simpleName) {
Objects.requireNonNull(simpleName, "simpleName");
return switch (enclosingElement) {
case null -> throw new NullPointerException("enclosingElement");
case UniversalElement ue -> {
for (final UniversalElement ee : ue.getEnclosedElements()) {
if (ee.getKind().isVariable() && ee.getSimpleName().contentEquals(simpleName)) {
yield ee;
}
}
yield null;
}
default -> {
try (var lock = lock()) {
for (final Element ee : enclosingElement.getEnclosedElements()) {
if (ee.getKind().isVariable() && ee.getSimpleName().contentEquals(simpleName)) {
yield (VariableElement)ee;
}
}
}
yield null;
}
};
}
/**
* A convenience method that returns a new {@link WildcardType} {@linkplain TypeMirror#getKind() with a
* TypeKind
} of {@link TypeKind#WILDCARD}, an {@linkplain WildcardType#getExtendsBound() extends bound}
* of {@code null}, and a {@linkplain WildcardType#getSuperBound() super bound} of {@code null}.
*
* @return a new, non-{@code null} {@link WildcardType}
*
* @see #wildcardType(TypeMirror, TypeMirror)
*
* @see javax.lang.model.util.Types#getWildcardType(TypeMirror, TypeMirror)
*
* @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-4.html#jls-4.5.1 Java Language Specification, section
* 4.5.1
*/
public default WildcardType wildcardType() {
return this.wildcardType(null, null);
}
/**
* Returns a new {@link WildcardType} {@linkplain TypeMirror#getKind() with a TypeKind
} of {@link
* TypeKind#WILDCARD}, an {@linkplain WildcardType#getExtendsBound() extends bound} of the supplied {@code
* extendsBound}, and a {@linkplain WildcardType#getSuperBound() super bound} of the supplied {@code superBound}.
*
* Any argument may be {@code null}. Both arguments may not be non-{@code null}.
*
* @param extendsBound the upper bound of the new {@link WildcardType}; may be {@code null}
*
* @param superBound the lower bound of the new {@link WildcardType}; may be {@code null}
*
* @return a new, non-{@code null} {@link WildcardType}
*
* @exception IllegalArgumentException if both arguments are non-{@code null} or otherwise unsuitable for being the
* bounds of a {@link WildcardType}
*
* @see javax.lang.model.util.Types#getWildcardType(TypeMirror, TypeMirror)
*
* @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-4.html#jls-4.5.1 Java Language Specification, section
* 4.5.1
*/
public WildcardType wildcardType(TypeMirror extendsBound, TypeMirror superBound);
}