001/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*-
002 *
003 * Copyright © 2024–2026 microBean™.
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
006 * the License. You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
011 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
012 * specific language governing permissions and limitations under the License.
013 */
014package org.microbean.construct;
015
016import java.lang.reflect.Constructor;
017import java.lang.reflect.Executable;
018import java.lang.reflect.GenericArrayType;
019import java.lang.reflect.GenericDeclaration;
020import java.lang.reflect.Method;
021import java.lang.reflect.ParameterizedType;
022import java.lang.reflect.Type;
023
024import java.util.ArrayList;
025import java.util.List;
026
027import javax.lang.model.AnnotatedConstruct;
028
029import javax.lang.model.element.AnnotationMirror;
030import javax.lang.model.element.Element;
031import javax.lang.model.element.ElementKind;
032import javax.lang.model.element.ExecutableElement;
033import javax.lang.model.element.ModuleElement;
034import javax.lang.model.element.Name;
035import javax.lang.model.element.PackageElement;
036import javax.lang.model.element.Parameterizable;
037import javax.lang.model.element.QualifiedNameable;
038import javax.lang.model.element.RecordComponentElement;
039import javax.lang.model.element.TypeElement;
040import javax.lang.model.element.TypeParameterElement;
041import javax.lang.model.element.VariableElement;
042
043import javax.lang.model.type.ArrayType;
044import javax.lang.model.type.DeclaredType;
045import javax.lang.model.type.ExecutableType;
046import javax.lang.model.type.NoType;
047import javax.lang.model.type.NullType;
048import javax.lang.model.type.PrimitiveType;
049import javax.lang.model.type.TypeKind;
050import javax.lang.model.type.TypeMirror;
051import javax.lang.model.type.TypeVariable;
052import javax.lang.model.type.WildcardType;
053
054import javax.lang.model.util.Elements;
055import javax.lang.model.util.Elements.Origin;
056
057import org.microbean.construct.element.AnnotationMirrors;
058import org.microbean.construct.element.UniversalElement;
059
060import org.microbean.construct.type.UniversalType;
061
062import static java.util.Collections.unmodifiableList;
063
064import static java.util.Objects.requireNonNull;
065
066import static javax.lang.model.type.TypeKind.DECLARED;
067
068/**
069 * A {@link PrimordialDomain} that represents a domain of valid Java language constructs.
070 *
071 * <p>A <dfn id="domain">domain</dfn> is a set of valid Java language <a href="#construct">constructs</a>. A {@link
072 * Domain} provides access to a domain and its members.</p>
073 *
074 * <p>A Java <dfn id="construct">construct</dfn> is either a <a href="#type">type</a> or an <a
075 * href="#element">element</a>.</p>
076 *
077 * <p>A <dfn id="type">type</dfn> is a usage of a Java type, most commonly represented as a {@link TypeMirror}.</p>
078 *
079 * <p>An <dfn id="element">element</dfn> ia a declaration of a Java program element, most commonly represented as an
080 * {@link Element}.</p>
081 *
082 * <p>Domains impose constraints on the <a href="#type">types</a> and <a href="#element">elements</a> they contain, and
083 * on the kinds and semantics of operations that can be performed on them.</p>
084 *
085 * <p>This interface is modeled on a deliberately restricted combination of the {@link javax.lang.model.util.Elements}
086 * and {@link javax.lang.model.util.Types} interfaces.</p>
087 *
088 * <p>{@link Domain} implementations must be thread-safe.</p>
089 *
090 * @author <a href="https://about.me/lairdnelson" target="_top">Laird Nelson</a>
091 *
092 * @see PrimordialDomain
093 *
094 * @see DefaultDomain
095 *
096 * @see <a href="https://bugs.openjdk.org/browse/JDK-8055219">JDK-8055219</a>
097 */
098@SuppressWarnings("try")
099public interface Domain extends PrimordialDomain {
100
101  /**
102   * Returns an immutable, determinate, non-{@code null} {@link List} of {@link AnnotationMirror} instances representing
103   * all annotations <dfn>present</dfn> on an element, whether <dfn>directly present</dfn> or present via inheritance.
104   *
105   * <p>The default implementation of this method calls {@link UniversalElement#of(Element, Domain)} with the supplied
106   * {@code element} and {@code this} as arguments, calls the {@link
107   * AnnotationMirrors#allAnnotationMirrors(Element)} with the result, and returns the result.</p>
108   *
109   * @param element the {@link Element} whose present annotations should be returned; must not be {@code null}
110   *
111   * @return an immutable, determinate, non-{@code null} {@link List} of {@link AnnotationMirror} instances representing
112   * all annotations <dfn>present</dfn> on an element, whether <dfn>directly present</dfn> or present via inheritance
113   *
114   * @exception NullPointerException if {@code element} is {@code null}
115   *
116   * @see AnnotationMirrors#allAnnotationMirrors(Element)
117   *
118   * @see javax.lang.model.util.Elements#getAllAnnotationMirrors(Element)
119   */
120  public default List<? extends AnnotationMirror> allAnnotationMirrors(final Element element) {
121    return AnnotationMirrors.allAnnotationMirrors(UniversalElement.of(element, this)); // handles locking, symbol completion
122  }
123
124  /**
125   * Returns a non-{@code null}, determinate, immutable {@link List} whose elements comprise the <dfn>members</dfn> of
126   * the supplied {@link TypeElement}, whether they are inherited or declared directly.
127   *
128   * <p>If the supplied {@link TypeElement} is a {@linkplain ElementKind#CLASS class}, the returned {@link List} will
129   * also include the class' constructors, but not any local or anonymous classes.</p>
130   *
131   * @param e a {@link TypeElement}; must not be {@code null}
132   *
133   * @return a non-{@code null}, determinate, immutable {@link List} whose elements comprise the <dfn>members</dfn> of
134   * the supplied {@link TypeElement}, whether they are inherited or declared directly
135   *
136   * @exception NullPointerException if {@code e} is {@code null}
137   *
138   * @see Elements#getAllMembers(TypeElement)
139   */
140  public abstract List<? extends Element> allMembers(TypeElement e);
141
142  /**
143   * An <strong>experimental</strong> method that returns an {@link Element} that is {@linkplain Element#equals(Object)
144   * equal to} the supplied {@link Element} but {@linkplain Element#getAnnotationMirrors() with} a {@link List} of
145   * annotations {@linkplain List#equals(Object) equal to} the supplied {@link List} of {@link AnnotationMirror}s.
146   *
147   * <p>The supplied {@link Element} may be modified in place if the return value of its {@link
148   * Element#getAnnotationMirrors() getAnnotationMirrors()} method is mutable.</p>
149   *
150   * <p>No validation of any kind is performed on either argument.</p>
151   *
152   * @param annotations a {@link List} of {@link AnnotationMirror}s; must not be {@code null}
153   *
154   * @param e an {@link Element}; must not be {@code null}
155   *
156   * @return an {@link Element} that is {@linkplain Element#equals(Object) equal to} the supplied {@link Element} but
157   * {@linkplain Element#getAnnotationMirrors() with} a {@link List} of annotations {@linkplain List#equals(Object)
158   * equal to} the supplied {@link List} of {@link AnnotationMirror}s
159   *
160   * @exception NullPointerException if any argument is {@code null}
161   *
162   * @see UniversalElement#getAnnotationMirrors()
163   */
164  public default Element annotate(final List<? extends AnnotationMirror> annotations, final Element e) {
165    final UniversalElement ue = UniversalElement.of(e, this);
166    final List<AnnotationMirror> l = ue.getAnnotationMirrors();
167    l.clear();
168    l.addAll(annotations);
169    return ue;
170  }
171
172  /**
173   * An <strong>experimental</strong> method that returns a {@link TypeMirror} that is {@linkplain
174   * TypeMirror#equals(Object) equal to} the supplied {@link TypeMirror} but {@linkplain
175   * TypeMirror#getAnnotationMirrors() with} a {@link List} of annotations {@linkplain List#equals(Object) equal to} the
176   * supplied {@link List} of {@link AnnotationMirror}s.
177   *
178   * <p>The supplied {@link TypeMirror} may be modified in place if the return value of its {@link
179   * TypeMirror#getAnnotationMirrors() getAnnotationMirrors()} method is mutable.</p>
180   *
181   * <p>No validation of any kind is performed on either argument.</p>
182   *
183   * @param annotations a {@link List} of {@link AnnotationMirror}s; must not be {@code null}
184   *
185   * @param t a {@link TypeMirror}; must not be {@code null}
186   *
187   * @return a {@link TypeMirror} that is {@linkplain TypeMirror#equals(Object) equal to} the supplied {@link
188   * TypeMirror} but {@linkplain TypeMirror#getAnnotationMirrors() with} a {@link List} of annotations {@linkplain
189   * List#equals(Object) equal to} the supplied {@link List} of {@link AnnotationMirror}s
190   *
191   * @exception NullPointerException if any argument is {@code null}
192   *
193   * @see UniversalType#getAnnotationMirrors()
194   */
195  public default TypeMirror annotate(final List<? extends AnnotationMirror> annotations, final TypeMirror t) {
196    final UniversalType ut = UniversalType.of(t, this);
197    final List<AnnotationMirror> l = ut.getAnnotationMirrors();
198    l.clear();
199    l.addAll(annotations);
200    return ut;
201  }
202
203  /**
204   * Returns an {@link ArrayType} whose {@linkplain ArrayType#getComponentType() component type} is {@linkplain
205   * #sameType(TypeMirror, TypeMirror) the same as} the supplied {@code componentType}.
206   *
207   * @param componentType the component type; must not be {@code null}
208   *
209   * @return a non-{@code null} {@link ArrayType} whose {@linkplain ArrayType#getComponentType() component type} is
210   * {@linkplain #sameType(TypeMirror, TypeMirror) the same as} the supplied {@code componentType}
211   *
212   * @exception NullPointerException if {@code componentType} is {@code null}
213   *
214   * @exception IllegalArgumentException if {@code componentType} is not a valid component type
215   *
216   * @see javax.lang.model.util.Types#getArrayType(TypeMirror)
217   */
218  // Type factory method
219  public ArrayType arrayTypeOf(final TypeMirror componentType);
220
221  /**
222   * Returns a non-{@code null} {@link TypeMirror} representing the type of the supplied {@link Element} when that
223   * {@link Element} is viewed as a member of, or otherwise directly contained by, the supplied {@code containingType}.
224   *
225   * <p>For example, when viewed as a member of the parameterized type {@link java.util.Set Set&lt;String&gt;}, the
226   * {@link java.util.Set#add(Object)} method (represented as an {@link ExecutableElement}) {@linkplain
227   * ExecutableElement#asType() has} a {@linkplain ExecutableType type} whose {@linkplain
228   * ExecutableType#getParameterTypes() method parameter is of type} {@link String} (not {@link String}'s erasure).</p>
229   *
230   * @param containingType the containing {@link DeclaredType}; must not be {@code null}
231   *
232   * @param e the member {@link Element}; must not be {@code null}
233   *
234   * @return a non-{@code null} {@linkplain TypeMirror type} representing the {@linkplain Element#asType() type of} the
235   * supplied {@link Element} when viewed as a member of the supplied {@code containingType}; never {@code null}
236   *
237   * @exception NullPointerException if either {@code containingType} or {@code e} is {@code null}
238   *
239   * @exception IllegalArgumentException if {@code e} cannot be viewed as a member of the supplied {@code
240   * containingType} (because it is the wrong {@linkplain Element#getKind() kind}, for example)
241   *
242   * @see javax.lang.model.util.Types#asMemberOf(DeclaredType, Element)
243   */
244  public TypeMirror asMemberOf(final DeclaredType containingType, final Element e);
245
246  /**
247   * Returns {@code true} if and only if the supplied {@code payload} (the first argument) is considered assignable to
248   * the supplied {@code receiver} (the second argument) according to <a
249   * href="https://docs.oracle.com/javase/specs/jls/se21/html/jls-5.html#jls-5.2">the rules of the Java Language
250   * Specification</a>; <strong>note the counterintuitive order of the parameters</strong>.
251   *
252   * <p>Perhaps surprisingly, the "left hand side" of the putative assignment is represented by the second parameter
253   * ({@code receiver}). The "right hand side" of the putative assignment is represented by the first parameter
254   * ({@code payload}). This follows the contract of the {@link javax.lang.model.util.Types#isAssignable(TypeMirror,
255   * TypeMirror)} method, on which this method is modeled.</p>
256   *
257   * @param payload the {@link TypeMirror} being assigned; must not be {@code null}
258   *
259   * @param receiver the {@link TypeMirror} receiving the assignment; must not be {@code null}
260   *
261   * @return {@code true} if and only if {@code payload} is assignable to {@code receiver} according to <a
262   * href="https://docs.oracle.com/javase/specs/jls/se21/html/jls-5.html#jls-5.2">the rules of the Java Language
263   * Specification</a>
264   *
265   * @exception NullPointerException if either {@code payload} or {@code receiver} is {@code null}
266   *
267   * @exception IllegalArgumentException if either {@link TypeMirror} is not one that can take part in an assignment
268   *
269   * @see javax.lang.model.util.Types#isAssignable(TypeMirror, TypeMirror)
270   *
271   * @spec https://docs.oracle.com/javase/specs/jls/se21/html/jls-5.html#jls-5.2 Java Language Specification, section
272   * 5.2
273   */
274  // Note the strange positioning of payload and receiver.
275  public boolean assignable(final TypeMirror payload, final TypeMirror receiver);
276
277  /**
278   * Returns the (non-{@code null}) <a
279   * href="https://docs.oracle.com/javase/specs/jls/se21/html/jls-13.html#jls-13.1"><dfn>binary name</dfn></a> of the
280   * supplied {@link TypeElement}.
281   *
282   * @param e a {@link TypeElement}; must not be {@code null}
283   *
284   * @return a non-{@code null} {@link Name}
285   *
286   * @exception NullPointerException if {@code e} is {@code null}
287   *
288   * @see javax.lang.model.util.Elements#getBinaryName(TypeElement)
289   *
290   * @spec https://docs.oracle.com/javase/specs/jls/se21/html/jls-13.html#jls-13.1 Java Language Specification, section
291   * 13.1
292   */
293  public Name binaryName(final TypeElement e);
294
295  /**
296   * Returns {@code true} if and only if the supplied {@link ExecutableElement} represents a <dfn>bridge method</dfn>.
297   *
298   * @param e an {@link ExecutableElement}; must not be {@code null}
299   *
300   * @return {@code true} if and only if the supplied {@link ExecutableElement} represents a bridge method
301   *
302   * @exception NullPointerException if {@code e} is {@code null}
303   *
304   * @see javax.lang.model.util.Elements#isBridge(ExecutableElement)
305   *
306   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-8.html#jls-8.4.8.3 Java Language Specification,
307   * section 8.4.8.3
308   *
309   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-15.html#jls-15.12.4.5 Java Language Specification,
310   * section 15.12.4.5
311   */
312  public boolean bridge(final ExecutableElement e);
313
314  /**
315   * Applies <a href="https://docs.oracle.com/javase/specs/jls/se23/html/jls-5.html#jls-5.1.10"><dfn>capture
316   * conversion</dfn></a> to the supplied {@link TypeMirror}, which is normally a {@linkplain TypeKind#WILDCARD wildcard
317   * type}.
318   *
319   * @param wildcard a {@link TypeMirror}; must not be {@code null}; if not a {@linkplain TypeKind#WILDCARD wildcard
320   * type}, then it will be returned unchanged
321   *
322   * @return a non-{@code null} {@link TypeMirror} representing the result of <a
323   * href="https://docs.oracle.com/javase/specs/jls/se23/html/jls-5.html#jls-5.1.10">capture conversion</a> applied to
324   * the supplied {@link TypeMirror}
325   *
326   * @exception NullPointerException if {@code wildcard} is {@code null}
327   *
328   * @see javax.lang.model.util.Types#capture(TypeMirror)
329   *
330   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-5.html#jls-5.1.10 Java Language Specification, section
331   * 5.1.10
332   */
333  public TypeMirror capture(final TypeMirror wildcard);
334
335  /**
336   * Returns {@code true} if and only if {@code candidateContainer} <dfn>contains</dfn> {@code candidate}, according to
337   * the <a href="https://docs.oracle.com/javase/specs/jls/se23/html/jls-4.html#jls-4.5.1">Java Language Specification,
338   * section 4.5.1</a>.
339   *
340   * @param candidateContainer the putative containing type; normally a {@linkplain TypeKind#WILDCARD wildcard type};
341   * must not be {@code null}
342   *
343   * @param candidate the putative contained type; must not be {@code null}
344   *
345   * @return {@code true} if and only if {@code candidateContainer} <dfn>contains</dfn> {@code candidate}, according to
346   * the <a href="https://docs.oracle.com/javase/specs/jls/se23/html/jls-4.html#jls-4.5.1">Java Language Specification,
347   * section 4.5.1</a>; {@code false} otherwise
348   *
349   * @exception NullPointerException if either argument is {@code null}
350   *
351   * @exception IllegalArgumentException if either argument is either an {@linkplain TypeKind#EXECUTABLE executable
352   * type}, a {@linkplain TypeKind#MODULE module type}, or a {@linkplain TypeKind#PACKAGE package type}
353   *
354   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-4.html#jls-4.5.1 Java Language Specification, section
355   * 4.5.1
356   */
357  public boolean contains(final TypeMirror candidateContainer, final TypeMirror candidate);
358
359  /**
360   * A convenience method that returns the {@link DeclaredType} {@linkplain TypeElement#asType() of} a {@link
361   * TypeElement} that bears the supplied {@code canonicalName}, <strong>or {@code null} if there is no such {@link
362   * TypeElement} (and therefore no such {@link DeclaredType})</strong>.
363   *
364   * @param canonicalName a valid canonical name; must not be {@code null}
365   *
366   * @return a {@link DeclaredType} with a {@link TypeKind} of {@link TypeKind#DECLARED}, or {@code null}
367   *
368   * @see #typeElement(CharSequence)
369   *
370   * @see #declaredType(TypeElement, TypeMirror...)
371   *
372   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-6.html#jls-6.7 Java Language Specification, section
373   * 6.7
374   */
375  // (Convenience.)
376  public default DeclaredType declaredType(final CharSequence canonicalName) {
377    final TypeElement e = this.typeElement(canonicalName);
378    return e == null ? null : this.declaredType(e);
379  }
380
381  /**
382   * Returns the {@link DeclaredType} {@linkplain TypeElement#asType() of} the supplied {@link TypeElement} with the
383   * supplied {@link TypeMirror} arguments (if any), yielding a parameterized type.
384   *
385   * <p>Given a {@link TypeElement} representing the class named {@link java.util.Set java.util.Set} and a {@link
386   * TypeMirror} representing the type declared by {@link String java.lang.String}, for example, this method will return
387   * a {@link DeclaredType} representing the parameterized type corresponding to {@link java.util.Set
388   * java.util.Set&lt;java.lang.String&gt;}.</p>
389   *
390   * <p>The number of supplied type arguments must either equal the number of the supplied {@link TypeElement}'s
391   * {@linkplain TypeElement#getTypeParameters() formal type parameters}, or must be zero. If it is zero, and if the
392   * supplied {@link TypeElement} {@linkplain #generic(Element) is generic}, then the supplied {@link TypeElement}'s raw
393   * type is returned.</p>
394   *
395   * <p>If a parameterized type is returned, {@linkplain DeclaredType#asElement() its <code>TypeElement</code>} must not
396   * be contained within a {@linkplain #generic(Element) generic} outer class. The parameterized type {@code
397   * Outer<String>.Inner<Number>}, for example, may be constructed by first using this method to get the type {@code
398   * Outer<String>}, and then invoking {@link #declaredType(DeclaredType, TypeElement, TypeMirror...)}.</p>
399   *
400   * @param typeElement a {@link TypeElement}; must not be {@code null}
401   *
402   * @param typeArguments any type arguments (represented by {@link TypeMirror}s); must not be {@code null}
403   *
404   * @return a non-{@code null} {@link DeclaredType} with a {@link TypeKind} of {@link TypeKind#DECLARED}
405   *
406   * @exception NullPointerException if {@code typeElement} or {@code typeArguments} is {@code null}
407   *
408   * @see javax.lang.model.util.Types#getDeclaredType(TypeElement, TypeMirror...)
409   *
410   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-4.html#jls-4.5 Java Language Specification, section 4.5
411   */
412  // Type factory method.
413  public DeclaredType declaredType(final TypeElement typeElement,
414                                   final TypeMirror... typeArguments);
415
416  /**
417   * Returns the {@link DeclaredType} {@linkplain TypeElement#asType() of} the supplied {@link TypeElement} with the
418   * supplied {@link TypeMirror} arguments (if any), given a containing {@link DeclaredType} of which it is a member,
419   * yielding a parameterized type.
420   *
421   * <p>Given a {@link DeclaredType} representing the parameterized type corresponding to {@code Outer<}{@link
422   * String}{@code >} (see the {@link #declaredType(TypeElement, TypeMirror...)} method), a {@link TypeElement}
423   * representing the class named {@code Outer.Inner} and a {@link DeclaredType} representing the non-generic class
424   * corresponding to {@link Number}, for example, this method will return a {@link DeclaredType} representing the
425   * parameterized type corresponding to {@code Outer<}{@link String}{@code >}{@code .Inner<}{@link Number}{@code >}.</p>
426   *
427   * <p>The number of supplied type arguments must either equal the number of the supplied {@link TypeElement}'s
428   * {@linkplain TypeElement#getTypeParameters() formal type parameters}, or must be zero. If it is zero, and if the
429   * supplied {@link TypeElement} {@link #generic(Element) is generic}, then the supplied {@link TypeElement}'s raw type
430   * is returned.</p>
431   *
432   * @param enclosingType a {@link DeclaredType} representing the containing type; must not be {@code null}
433   *
434   * @param typeElement a {@link TypeElement}; must not be {@code null}
435   *
436   * @param typeArguments any type arguments (represented by {@link TypeMirror}s); must not be {@code null}
437   *
438   * @return a non-{@code null} {@link DeclaredType} with a {@link TypeKind} of {@link TypeKind#DECLARED}
439   *
440   * @exception NullPointerException if {@code enclosingType}, {@code typeElement}, or {@code typeArguments} is {@code
441   * null}
442   *
443   * @see #declaredType(TypeElement, TypeMirror...)
444   *
445   * @see javax.lang.model.util.Types#getDeclaredType(DeclaredType, TypeElement, TypeMirror...)
446   *
447   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-4.html#jls-4.5 Java Language Specification, section 4.5
448   */
449  // Type factory method.
450  public DeclaredType declaredType(final DeclaredType enclosingType,
451                                   final TypeElement typeElement,
452                                   final TypeMirror... typeArguments);
453
454  /**
455   * Returns a non-{@code null} {@link List} of the <dfn>direct supertypes</dfn> of the supplied {@link TypeMirror},
456   * which is normally a {@linkplain TypeKind#DECLARED declared type}.
457   *
458   * <p>The direct supertypes returned by this method are actually a subset of the direct supertypes of a type as
459   * defined in the <a href="https://docs.oracle.com/javase/specs/jls/se25/html/jls-4.html#jls-4.10">Java Language
460   * Specification, section 4.10</a>. Specifically, the subset contains only those types that can be expressed in the
461   * {@code extends} or {@code implements} clauses of the Java language. For example, a type {@code Baz} can declare
462   * only that it {@code extends Foo<Bar>}, not {@code Foo<?>}, even though {@code Foo<?>} is a specification-described
463   * direct supertype of {@code Baz}.</p>
464   *
465   * @param t a {@link TypeMirror}; must not be {@code null}; must not be an {@linkplain TypeKind#EXECUTABLE executable
466   * type}, a {@linkplain TypeKind#MODULE module type}, or a {@linkplain TypeKind#PACKAGE package type}
467   *
468   * @return a non-{@code null}, immutable {@link List} of {@link TypeMirror}s representing the direct supertypes
469   *
470   * @exception NullPointerException if {@code t} is {@code null}
471   *
472   * @exception IllegalArgumentException if either argument is either an {@linkplain TypeKind#EXECUTABLE executable
473   * type}, a {@linkplain TypeKind#MODULE module type}, or a {@linkplain TypeKind#PACKAGE package type}
474   *
475   * @see javax.lang.model.util.Types#directSupertypes(TypeMirror)
476   *
477   * @see <a href="https://bugs.openjdk.org/browse/JDK-8055219">JDK-8055219</a>
478   *
479   * @spec https://docs.oracle.com/javase/specs/jls/se25/html/jls-4.html#jls-4.10 Java Language Specification, section
480   * 4.10
481   */
482  public List<? extends TypeMirror> directSupertypes(final TypeMirror t);
483
484  /**
485   * Returns the {@link Element} responsible for declaring the supplied {@link TypeMirror}, which is most commonly a
486   * {@link DeclaredType}, a {@link TypeVariable}, a {@link NoType} with a {@link TypeKind} of {@link TypeKind#MODULE},
487   * or a {@link NoType} with a {@link TypeKind} of {@link TypeKind#PACKAGE}, <strong>or {@code null} if there is no
488   * such {@link Element}</strong>.
489   *
490   * @param t a {@link TypeMirror}; must not be {@code null}
491   *
492   * @return an {@link Element}, or {@code null}
493   *
494   * @exception NullPointerException if {@code t} is {@code null}
495   *
496   * @see javax.lang.model.util.Types#asElement(TypeMirror)
497   */
498  public Element element(final TypeMirror t);
499
500  /**
501   * A convenience method that returns the <dfn>element type</dfn> of the supplied {@link TypeMirror}.
502   *
503   * <p>The element type of an {@linkplain TypeKind#ARRAY array type} is the element type of its {@linkplain
504   * ArrayType#getComponentType() component type}.</p>.
505   *
506   * <p>The element type of every other kind of type is the type itself. Note that the semantics of the prior sentence
507   * diverge deliberately, primarily for convenience, from those of the relevant section in the Java Language
508   * Specification.</p>
509   *
510   * @param t a {@link TypeMirror}; must not be {@code null}
511   *
512   * @return the <dfn>element type</dfn> of the supplied {@link TypeMirror}; never {@code null}
513   *
514   * @exception NullPointerException if {@code t} is {@code null}
515   *
516   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-10.html#jls-10.1 Java Language Specification, section
517   * 10.1
518   */
519  // (Convenience.)
520  public default TypeMirror elementType(final TypeMirror t) {
521    return switch (t) {
522    case null -> throw new NullPointerException("t");
523    case UniversalType ut -> ut.elementType();
524    default -> {
525      try (var lock = lock()) {
526        yield t.getKind() == TypeKind.ARRAY ? this.elementType(((ArrayType)t).getComponentType()) : t;
527      }
528    }
529    };
530  }
531
532  /**
533   * Returns the <dfn>erasure</dfn> of the supplied {@link TypeMirror}.
534   *
535   * @param <T> a {@link TypeMirror} specialization
536   *
537   * @param t the {@link TypeMirror} representing the type whose erasure should be returned; must not be {@code null}
538   *
539   * @return the erasure of the supplied {@link TypeMirror}; never {@code null}
540   *
541   * @exception NullPointerException if {@code t} is {@code null}
542   *
543   * @exception IllegalArgumentException if {@code t} is a {@link NoType} with a {@link TypeKind} of {@link
544   * TypeKind#MODULE}, or a {@link NoType} with a {@link TypeKind} of {@link TypeKind#PACKAGE}
545   *
546   * @see javax.lang.model.util.Types#erasure(TypeMirror)
547   *
548   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-4.html#jls-4.6 Java Language Specification, section
549   * 4.6
550   */
551  public <T extends TypeMirror> T erasure(final T t);
552
553  /**
554   * Returns an {@link ExecutableElement} corresponding to the supplied {@link Executable}.
555   *
556   * @param e an {@link Executable}; must not be {@code null}
557   *
558   * @return an {@link ExecutableElement} corresponding to the supplied {@link Executable}; never {@code null}
559   *
560   * @exception NullPointerException if {@code e} is {@code null}
561   *
562   * @exception IllegalArgumentException if somehow {@code e} is neither a {@link Constructor} nor a {@link Method}
563   */
564  // (Convenience.)
565  public default ExecutableElement executableElement(final Executable e) {
566    return switch (e) {
567    case null -> throw new NullPointerException("e");
568    case Constructor<?> c ->
569      this.executableElement(this.typeElement(c.getDeclaringClass().getCanonicalName()),
570                             this.noType(TypeKind.VOID),
571                             "<init>",
572                             this.types(c.getParameterTypes()));
573    case Method m ->
574      this.executableElement(this.typeElement(m.getDeclaringClass().getCanonicalName()),
575                             this.type(m.getReturnType()),
576                             m.getName(),
577                             this.types(m.getParameterTypes()));
578    default -> throw new IllegalArgumentException("e: " + e);
579    };
580  }
581
582
583  /**
584   * A convenience method that returns an {@link ExecutableElement} representing the static initializer, constructor or
585   * method described by the supplied arguments, <strong>or {@code null} if no such {@link ExecutableElement}
586   * exists</strong>.
587   *
588   * @param declaringElement a {@link TypeElement} representing the class that declares the executable; must not be
589   * {@code null}
590   *
591   * @param returnType the {@linkplain ExecutableElement#getReturnType() return type} of the executable; must not be
592   * {@code null}
593   *
594   * @param name the {@linkplain ExecutableElement#getSimpleName() name} of the executable; must not be {@code null}
595   *
596   * @param parameterTypes {@link TypeMirror}s that represent the executable's {@linkplain
597   * ExecutableElement#getParameters() parameter types}
598   *
599   * @return an {@link ExecutableElement} with an {@link ElementKind} of {@link ElementKind#CONSTRUCTOR}, {@link
600   * ElementKind#METHOD}, or {@link ElementKind#STATIC_INIT}, or {@code null}
601   *
602   * @exception NullPointerException if any argument is {@code null}
603   */
604  // (Convenience.)
605  public default ExecutableElement executableElement(final TypeElement declaringElement,
606                                                     final TypeMirror returnType,
607                                                     final CharSequence name,
608                                                     final TypeMirror... parameterTypes) {
609    return switch (declaringElement) {
610    case null -> throw new NullPointerException("declaringElement");
611    case UniversalElement ue -> {
612      final List<? extends UniversalElement> ees = ue.getEnclosedElements();
613      yield ees.stream()
614        .sequential()
615        .filter(e -> e.getKind().isExecutable() && e.getSimpleName().contentEquals(name))
616        .map(UniversalElement.class::cast)
617        .filter(ee -> {
618            if (!this.sameType(returnType, ee.getReturnType())) {
619              return false;
620            }
621            final List<? extends UniversalElement> ps = ee.getParameters();
622            if (ps.size() != parameterTypes.length) {
623              return false;
624            }
625            for (int i = 0; i < parameterTypes.length; i++) {
626              if (!this.sameType(ps.get(i).asType(), parameterTypes[i])) {
627                return false;
628              }
629            }
630            return true;
631          })
632        .findFirst()
633        .orElse(null);
634    }
635    default -> {
636      try (var lock = this.lock()) {
637        final List<? extends Element> ees = declaringElement.getEnclosedElements();
638        yield ees.stream()
639          .sequential()
640          .filter(e -> e.getKind().isExecutable() && e.getSimpleName().contentEquals(name))
641          .map(ExecutableElement.class::cast)
642          .filter(ee -> {
643              if (!this.sameType(returnType, ee.getReturnType())) {
644                return false;
645              }
646              final List<? extends VariableElement> ps = ee.getParameters();
647              if (ps.size() != parameterTypes.length) {
648                return false;
649              }
650              for (int i = 0; i < parameterTypes.length; i++) {
651                if (!this.sameType(ps.get(i).asType(), parameterTypes[i])) {
652                  return false;
653                }
654              }
655              return true;
656            })
657          .findFirst()
658          .orElse(null);
659      }
660    }
661    };
662  }
663
664  /**
665   * A convenience method that returns {@code true} if and only if the supplied {@link Element} is <dfn>generic</dfn>.
666   *
667   * @param e an {@link Element}; must not be {@code null}
668   *
669   * @return {@code true} if and only if the supplied {@link Element} is <dfn>generic</dfn>; {@code false} otherwise
670   *
671   * @exception NullPointerException if {@code e} is {@code null}
672   *
673   * @see Parameterizable
674   *
675   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-8.html#jls-8.1.2 Java Language Specification, section
676   * 8.1.2
677   *
678   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-8.html#jls-8.4.4 Java Language Specification, section
679   * 8.4.4
680   *
681   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-8.html#jls-8.8.4 Java Language Specification, section
682   * 8.8.4
683   *
684   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-9.html#jls-9.1.2 Java Language Specification, section
685   * 9.1.2
686   */
687  // (Convenience.)
688  public default boolean generic(final Element e) {
689    return switch (e) {
690    case null -> throw new NullPointerException("e");
691    case UniversalElement ue -> ue.generic();
692    case Parameterizable p -> {
693      try (var lock = this.lock()) {
694        yield switch (e.getKind()) {
695        case CLASS, CONSTRUCTOR, ENUM, INTERFACE, METHOD, RECORD -> !p.getTypeParameters().isEmpty();
696        default -> false;
697        };
698      }
699    }
700    default -> false;
701    };
702  }
703
704  /**
705   * A convenience method that returns {@code true} if and only if the supplied {@link TypeMirror} is declared by an
706   * {@link Element} that {@linkplain #generic(Element) is generic}.
707   *
708   * @param t a {@link TypeMirror}; must not be {@code null}
709   *
710   * @return {@code true} if and only if the supplied {@link TypeMirror} is declared by an {@link Element} that
711   * {@linkplain #generic(Element) is generic}
712   *
713   * @exception NullPointerException if {@code t} is {@code null}
714   *
715   * @see #generic(Element)
716   *
717   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-8.html#jls-8.1.2 Java Language Specification, section
718   * 8.1.2
719   *
720   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-8.html#jls-8.4.4 Java Language Specification, section
721   * 8.4.4
722   *
723   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-8.html#jls-8.8.4 Java Language Specification, section
724   * 8.8.4
725   *
726   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-9.html#jls-9.1.2 Java Language Specification, section
727   * 9.1.2
728   */
729  // (Convenience.)
730  public default boolean generic(final TypeMirror t) {
731    return switch (t) {
732    case null -> throw new NullPointerException("t");
733    case UniversalType ut -> ut.generic();
734    default -> {
735      try (var lock = this.lock()) {
736        final Element e = this.element(t);
737        yield e != null && this.generic(e);
738      }
739    }
740    };
741  }
742
743  /**
744   * A convenience method that returns {@code true} if and only if the supplied {@link Element} represents the (essentially
745   * primordial) {@code java.lang.Object} {@link Element}.
746   *
747   * @param e an {@link Element}; must not be {@code null}
748   *
749   * @return {@code true} if and only if the supplied {@link Element} represents the (essentially
750   * primordial) {@code java.lang.Object} {@link Element}; {@code false} otherwise
751   *
752   * @exception NullPointerException if {@code e} is {@code null}
753   */
754  // (Convenience.)
755  public default boolean javaLangObject(final Element e) {
756    return switch (e) {
757    case null -> throw new NullPointerException("e");
758    case UniversalElement ue -> ue.javaLangObject();
759    default -> {
760      try (var lock = this.lock()) {
761        yield
762          e.getKind() == ElementKind.CLASS &&
763          ((QualifiedNameable)e).getQualifiedName().contentEquals("java.lang.Object");
764      }
765    }
766    };
767  }
768
769  /**
770   * A convenience method that returns {@code true} if and only if the supplied {@link TypeMirror} represents the {@link
771   * DeclaredType} declared by the (essentially primordial) {@code java.lang.Object} element.
772   *
773   * @param t a {@link TypeMirror}; must not be {@code null}
774   *
775   * @return {@code true} represents the {@link
776   * DeclaredType} declared by the (essentially primordial) {@code java.lang.Object} element; {@code false} otherwise
777   *
778   * @exception NullPointerException if {@code t} is {@code null}
779   *
780   * @see #javaLangObject(Element)
781   */
782  // (Convenience.)
783  public default boolean javaLangObject(final TypeMirror t) {
784    return switch (t) {
785    case null -> throw new NullPointerException("t");
786    case UniversalType ut -> ut.javaLangObject();
787    default -> {
788      try (var lock = this.lock()) {
789        yield
790          t.getKind() == DECLARED &&
791          javaLangObject(((DeclaredType)t).asElement());
792      }
793    }
794    };
795  }
796
797  /**
798   * A convenience method that returns the {@link TypeElement} representing the class named {@link Object
799   * java.lang.Object}.
800   *
801   * @return a non-{@code null} {@link TypeElement} whose {@linkplain TypeElement#getQualifiedName() qualified name} is
802   * {@linkplain Name#contentEquals(CharSequence) equal to} {@code java.lang.Object}
803   *
804   * @see #typeElement(CharSequence)
805   */
806  // (Convenience.)
807  public default TypeElement javaLangObject() {
808    return this.typeElement("java.lang.Object");
809  }
810
811  // (Convenience.)
812  @Override // PrimordialDomain
813  public default DeclaredType javaLangObjectType() {
814    return (DeclaredType)this.javaLangObject().asType();
815  }
816
817  /**
818   * Returns a {@link ModuleElement} representing the module {@linkplain ModuleElement#getQualifiedName() named} by the
819   * supplied {@code qualifiedName}, <strong>or {@code null} if there is no such {@link ModuleElement}</strong>.
820   *
821   * @param qualifiedName a name suitable for naming a module; must not be {@code null}; may be {@linkplain
822   * CharSequence#isEmpty() empty}, in which case a {@link ModuleElement} representing an <dfn>unnamed module</dfn> will
823   * be returned
824   *
825   * @return a {@link ModuleElement}, or {@code null}
826   *
827   * @exception NullPointerException if {@code qualifiedName} is {@code null}
828   *
829   * @see javax.lang.model.util.Elements#getModuleElement(CharSequence)
830   *
831   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-7.html#jls-7.7 Java Language Specification, section
832   * 7.7
833   */
834  // Element factory method.
835  public ModuleElement moduleElement(final CharSequence qualifiedName);
836
837  /**
838   * Returns a {@link Name} representing the supplied {@link CharSequence}.
839   *
840   * @param name a {@link CharSequence}; must not be {@code null}
841   *
842   * @return a non-{@code null} {@link Name} representing the supplied {@link name}
843   *
844   * @exception NullPointerException if {@code name} is {@code null}
845   *
846   * @see #lock()
847   *
848   * @see javax.lang.model.util.Elements#getName(CharSequence)
849   */
850  // Element factory method.
851  public Name name(final CharSequence name);
852
853  /**
854   * Returns a {@link NoType} {@linkplain TypeMirror#getKind() bearing} the supplied {@link TypeKind}, if the supplied
855   * {@link TypeKind} is either {@link TypeKind#NONE} or {@link TypeKind#VOID}.
856   *
857   * @param kind a {@link TypeKind}; must be either {@link TypeKind#NONE} or {@link TypeKind#VOID}
858   *
859   * @return a non-{@code null} {@link NoType} {@linkplain TypeMirror#getKind() bearing} the supplied {@link TypeKind}
860   *
861   * @exception NullPointerException if {@code kind} is {@code null}
862   *
863   * @exception IllegalArgumentException if {@code kind} is non-{@code null} and neither {@link TypeKind#NONE} nor
864   * {@link TypeKind#VOID}
865   *
866   * @see TypeKind#NONE
867   *
868   * @see TypeKind#VOID
869   *
870   * @see javax.lang.model.util.Types#getNoType(TypeKind)
871   *
872   * @see NoType
873   *
874   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-8.html#jls-8.4.5 Java Language Specification, section
875   * 8.4.5
876   */
877  // Type factory method.
878  @Override // PrimordialDomain
879  public NoType noType(final TypeKind kind);
880
881  /**
882   * Returns a {@link NullType} implementation {@linkplain TypeMirror#getKind() whose <code>TypeKind</code>} is {@link
883   * TypeKind#NULL}.
884   *
885   * @return a non-{@code null} {@link NullType}
886   *
887   * @see javax.lang.model.util.Types#getNullType()
888   *
889   * @see NullType
890   *
891   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-4.html#jls-4.1 Java Language Specification, section 4.1
892   */
893  // Type factory method.
894  @Override // PrimordialDomain
895  public NullType nullType();
896
897  /**
898   * Returns the {@linkplain Origin origin} of the supplied {@link Element}.
899   *
900   * @param e a non-{@code null} {@link Element}
901   *
902   * @return a non-{@code null} {@link Origin}
903   *
904   * @see Elements#getOrigin(Element)
905   *
906   * @see Origin
907   */
908  public Origin origin(final Element e);
909
910  /**
911   * Returns a {@link PackageElement} representing the package bearing the supplied {@code canonicalName}, <strong>or
912   * {@code null} if there is no such {@link PackageElement}</strong>.
913   *
914   * @param canonicalName a canonical name suitable for naming a package; must not be {@code null}; may be {@linkplain
915   * CharSequence#isEmpty() empty}, in which case a {@link ModuleElement} representing an <dfn>unnamed package</dfn> will
916   * be returned
917   *
918   * @return a {@link PackageElement}, or {@code null}
919   *
920   * @exception NullPointerException if {@code canonicalName} is {@code null}
921   *
922   * @see javax.lang.model.util.Elements#getPackageElement(CharSequence)
923   *
924   * @see PackageElement
925   *
926   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-6.html#jls-6.7 Java Language Specification, section
927   * 6.7
928   */
929  // Element factory method.
930  public PackageElement packageElement(final CharSequence canonicalName);
931
932  /**
933   * Returns a {@link PackageElement} representing the package bearing the supplied {@code canonicalName} as seen from
934   * the module represented by the supplied {@link ModuleElement}, <strong>or {@code null} if there is no such {@link
935   * PackageElement}</strong>.
936   *
937   * @param asSeenFrom a {@link ModuleElement}; must not be {@code null}
938   *
939   * @param canonicalName a canonical name suitable for naming a package; must not be {@code null}; may be {@linkplain
940   * CharSequence#isEmpty() empty}, in which case a {@link ModuleElement} representing an <dfn>unnamed package</dfn> will
941   * be returned
942   *
943   * @return a {@link PackageElement}, or {@code null}
944   *
945   * @exception NullPointerException if either {@code asSeenFrom} or {@code canonicalName} is {@code null}
946   *
947   * @see javax.lang.model.util.Elements#getPackageElement(ModuleElement, CharSequence)
948   *
949   * @see PackageElement
950   *
951   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-6.html#jls-6.7 Java Language Specification, section
952   * 6.7
953   */
954  // Element factory method.
955  public PackageElement packageElement(final ModuleElement asSeenFrom, final CharSequence canonicalName);
956
957  /**
958   * Returns a {@link Parameterizable} corresponding to the supplied (reflective) {@link GenericDeclaration}.
959   *
960   * @param gd a {@link GenericDeclaration}; must not be {@code null}
961   *
962   * @return a {@link Parameterizable} corresponding to the supplied {@link GenericDeclaration}; never {@code null}
963   *
964   * @exception NullPointerException if {@code gd} is {@code null}
965   *
966   * @exception IllegalArgumentException if {@code gd} is neither a {@link Class} nor an {@link Executable}
967   *
968   * @see Parameterizable
969   */
970  // (Convenience.)
971  public default Parameterizable parameterizable(final GenericDeclaration gd) {
972    return switch (gd) {
973    case null -> throw new NullPointerException("gd");
974    case Class<?> c -> this.typeElement(c.getCanonicalName());
975    case Executable e -> this.executableElement(e);
976    default -> throw new IllegalArgumentException("gd: " + gd);
977    };
978  }
979
980  /**
981   * A convenience method that returns {@code true} if and only if {@code t} is a {@link DeclaredType}, {@linkplain
982   * TypeMirror#getKind() has a <code>TypeKind</code>} of {@link TypeKind#DECLARED DECLARED}, and {@linkplain
983   * DeclaredType#getTypeArguments() has a non-empty type arguments list}.
984   *
985   * @param t a {@link TypeMirror}; must not be {@code null}
986   *
987   * @return {@code true} if and only if {@code t} is a {@link DeclaredType}, {@linkplain
988   * TypeMirror#getKind() has a <code>TypeKind</code>} of {@link TypeKind#DECLARED DECLARED}, and {@linkplain
989   * DeclaredType#getTypeArguments() has a non-empty type arguments list}; {@code false} otherwise
990   *
991   * @exception NullPointerException if {@code t} is {@code null}
992   */
993  // (Convenience.)
994  public default boolean parameterized(final TypeMirror t) {
995    return switch (t) {
996    case null -> throw new NullPointerException("t");
997    case UniversalType ut -> ut.parameterized();
998    default -> {
999      try (var lock = this.lock()) {
1000        yield t.getKind() == DECLARED && !((DeclaredType)t).getTypeArguments().isEmpty();
1001      }
1002    }
1003    };
1004  }
1005
1006  /**
1007   * Returns the result of applying <dfn>unboxing conversion</dfn> to the (logical) {@link TypeElement} bearing the
1008   * supplied {@code canonicalName}.
1009   *
1010   * @param canonicalName a canonical name of either a primitive type or a so-called "wrapper" type; must not be {@code
1011   * null}
1012   *
1013   * @return a non-{@code null} {@link PrimitiveType} with a {@linkplain TypeKind#isPrimitive() primitive} {@link
1014   * TypeKind}
1015   *
1016   * @exception NullPointerException if {@code canonicalName} is {@code null}
1017   *
1018   * @exception IllegalArgumentException if {@code canonicalName} {@linkplain #toString(CharSequence) converted to a
1019   * <code>String</code>} {@linkplain String#equals(Object) is not equal to} {@code boolean}, {@code byte}, {@code
1020   * char}, {@code double}, {@code float}, {@code int}, {@code long}, {@code short}, {@link Boolean java.lang.Boolean},
1021   * {@link Byte java.lang.Byte}, {@link Character java.lang.Character}, {@link Double java.lang.Double}, {@link Float
1022   * java.lang.Float}, {@link Integer java.lang.Integer}, {@link Long java.lang.Long}, or {@link Short java.lang.Short}
1023   *
1024   * @see #primitiveType(TypeKind)
1025   *
1026   * @see PrimitiveType
1027   *
1028   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-5.html#jls-5.1.8 Java Language Specification, section
1029   * 5.1.8
1030   *
1031   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-6.html#jls-6.7 Java Language Specification, section
1032   * 6.7
1033   */
1034  // (Convenience.)
1035  // (Unboxing.)
1036  public default PrimitiveType primitiveType(final CharSequence canonicalName) {
1037    final String s = this.toString(requireNonNull(canonicalName, "canonicalName"));
1038    return switch (s) {
1039    case "boolean", "java.lang.Boolean" -> this.primitiveType(TypeKind.BOOLEAN);
1040    case "byte", "java.lang.Byte" -> this.primitiveType(TypeKind.BYTE);
1041    case "char", "java.lang.Character" -> this.primitiveType(TypeKind.CHAR);
1042    case "double", "java.lang.Double" -> this.primitiveType(TypeKind.DOUBLE);
1043    case "float", "java.lang.Float" -> this.primitiveType(TypeKind.FLOAT);
1044    case "int", "java.lang.Integer" -> this.primitiveType(TypeKind.INT);
1045    case "long", "java.lang.Long" -> this.primitiveType(TypeKind.LONG);
1046    case "short", "java.lang.Short" -> this.primitiveType(TypeKind.SHORT);
1047    default -> throw new IllegalArgumentException("canonicalName: " + s);
1048    };
1049  }
1050
1051  /**
1052   * Returns the result of applying <dfn>unboxing conversion</dfn> to the {@linkplain Element#asType() type declared by
1053   * the supplied <code>TypeElement</code>}.
1054   *
1055   * @param e a {@link TypeElement}; must not be {@code null}
1056   *
1057   * @return a non-{@code null} {@link PrimitiveType} with a {@linkplain TypeKind#isPrimitive() primitive} {@link
1058   * TypeKind}
1059   *
1060   * @exception NullPointerException if {@code e} is {@code null}
1061   *
1062   * @exception IllegalArgumentException if there is no unboxing conversion that can be applied to the {@linkplain
1063   * Element#asType() type declared by <code>e</code>}
1064   *
1065   * @see javax.lang.model.util.Types#unboxedType(TypeMirror)
1066   *
1067   * @see #primitiveType(TypeMirror)
1068   *
1069   * @see PrimitiveType
1070   *
1071   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-5.html#jls-5.1.8 Java Language Specification, section
1072   * 5.1.8
1073   */
1074  // (Convenience.)
1075  // (Unboxing.)
1076  public default PrimitiveType primitiveType(final TypeElement e) {
1077    return this.primitiveType(e.asType());
1078  }
1079
1080  /**
1081   * Returns the {@link PrimitiveType} corresponding to the supplied {@link TypeKind} (if it {@linkplain
1082   * TypeKind#isPrimitive() is primitive}).
1083   *
1084   * @param kind a {@linkplain TypeKind#isPrimitive() primitive} {@link TypeKind}; must not be {@code null}
1085   *
1086   * @return a non-{@code null} {@link PrimitiveType} {@linkplain TypeMirror#getKind() with} a {@linkplain
1087   * TypeKind#isPrimitive() primitive} {@link TypeKind}
1088   *
1089   * @exception NullPointerException if {@code kind} is {@code null}
1090   *
1091   * @exception IllegalArgumentException if {@code kind} {@linkplain TypeKind#isPrimitive() is not primitive}
1092   *
1093   * @see javax.lang.model.util.Types#getPrimitiveType(TypeKind)
1094   *
1095   * @see PrimitiveType
1096   *
1097   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-4.html#jls-4.2 Java Language Specification, section
1098   * 4.2
1099   */
1100  // (Canonical.)
1101  // Type factory method.
1102  public PrimitiveType primitiveType(final TypeKind kind);
1103
1104  /**
1105   * Returns the result of applying <dfn>unboxing conversion</dfn> to the supplied {@link TypeMirror}.
1106   *
1107   * @param t a {@link TypeMirror}; must not be {@code null}
1108   *
1109   * @return a non-{@code null} {@link PrimitiveType} with a {@linkplain TypeKind#isPrimitive() primitive} {@link
1110   * TypeKind}
1111   *
1112   * @exception NullPointerException if {@code t} is {@code null}
1113   *
1114   * @exception IllegalArgumentException if there is no unboxing conversion that can be applied to {@code t}
1115   *
1116   * @see javax.lang.model.util.Types#unboxedType(TypeMirror)
1117   *
1118   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-5.html#jls-5.1.8 Java Language Specification, section
1119   * 5.1.8
1120   */
1121  // (Canonical.)
1122  // (Unboxing.)
1123  // Type factory method.
1124  public PrimitiveType primitiveType(final TypeMirror t);
1125
1126  /**
1127   * A convenience method that returns {@code true} if and only if the supplied {@link TypeMirror} represents a
1128   * <dfn>prototypical type</dfn>.
1129   *
1130   * <p>Prototypical types are not defined by the Java Language Specification. They are partially defined by the
1131   * {@linkplain TypeElement#asType() specification of the <code>TypeElement#asType()</code>
1132   * method}.</p>
1133   *
1134   * @param t a {@link TypeMirror}; must not be {@code null}
1135   *
1136   * @return {@code true} if and only if {@code t} represents a <dfn>prototypical type</dfn>
1137   *
1138   * @exception NullPointerException if {@code t} is {@code null}
1139   *
1140   * @see TypeElement#asType()
1141   */
1142  // (Convenience.)
1143  public default boolean prototypical(final TypeMirror t) {
1144    return switch (t) {
1145    case null -> throw new NullPointerException("t");
1146    case UniversalType ut -> ut.prototypical();
1147    default -> {
1148      try (var lock = this.lock()) {
1149        yield t.getKind() == DECLARED && t.equals(((DeclaredType)t).asElement().asType());
1150      }
1151    }
1152    };
1153  }
1154
1155  /**
1156   * A convenience method that returns {@code true} if and only if the supplied {@link TypeMirror} is a <dfn>raw
1157   * type</dfn> according to <a href="https://docs.oracle.com/javase/specs/jls/se23/html/jls-4.html#jls-4.8">the rules
1158   * of the Java Language Specification</a>
1159   *
1160   * @param t a {@link TypeMirror}; must not be {@code null}
1161   *
1162   * @return {@code true} if and only if the supplied {@link TypeMirror} is a <dfn>raw type</dfn> according to <a
1163   * href="https://docs.oracle.com/javase/specs/jls/se23/html/jls-4.html#jls-4.8">the rules of the Java Language
1164   * Specification</a>
1165   *
1166   * @exception NullPointerException if {@code t} is {@code null}
1167   *
1168   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-4.html#jls-4.8 Java Language Specification, section 4.8
1169   */
1170  // (Convenience.)
1171  public default boolean raw(final TypeMirror t) {
1172    return switch (t) {
1173    case null -> throw new NullPointerException("t");
1174    case UniversalType ut -> ut.raw();
1175    default -> {
1176      try (var lock = this.lock()) {
1177        yield switch (t.getKind()) {
1178        case ARRAY -> raw(elementType((ArrayType)t));
1179        case DECLARED -> {
1180          final DeclaredType dt = (DeclaredType)t;
1181          yield generic(dt.asElement()) && dt.getTypeArguments().isEmpty();
1182        }
1183        default -> false;
1184        };
1185      }
1186    }
1187    };
1188  }
1189
1190  /**
1191   * A convenience method that returns the <dfn>raw type</dfn> corresponding to {@code t}, <strong>or {@code null} if
1192   * {@code t} is <a href="https://docs.oracle.com/javase/specs/jls/se23/html/jls-4.html#jls-4.8">incapable of yielding
1193   * a raw type</a></strong>.
1194   *
1195   * <p>Overrides of this method must conform to the requirements imposed by the relevant section of the relevant
1196   * version of the Java Language Specification concerning raw types.</p>
1197   *
1198   * @param t a {@link TypeMirror}; must not be {@code null}
1199   *
1200   * @return the raw type corresponding to the supplied {@link TypeMirror}, or {@code null} if {@code t} is <a
1201   * href="https://docs.oracle.com/javase/specs/jls/se23/html/jls-4.html#jls-4.8">incapable of yielding a raw type</a>
1202   *
1203   * @exception NullPointerException if {@code t} is {@code null}
1204   *
1205   * @see #parameterized(TypeMirror)
1206   *
1207   * @see #elementType(TypeMirror)
1208   *
1209   * @see #erasure(TypeMirror)
1210   *
1211   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-4.html#jls-4.8 Java Language Specification, section
1212   * 4.8
1213   */
1214  // (Convenience.)
1215  public default TypeMirror rawType(TypeMirror t) {
1216    return switch (t) {
1217    case null -> throw new NullPointerException("t");
1218    case UniversalType ut -> ut.elementType().parameterized() ? this.erasure(ut) : null;
1219    default -> this.parameterized(this.elementType(t)) ? this.erasure(t) : null;
1220    };
1221  }
1222
1223  /**
1224   * Returns a {@link RecordComponentElement} corresponding to the supplied {@link ExecutableElement}, <strong>or {@code
1225   * null} if there is no such {@link RecordComponentElement}</strong>.
1226   *
1227   * @param e an {@link ExecutableElement} {@linkplain ExecutableElement#getEnclosingElement() enclosed by} a record
1228   * representing an <dfn>accessor method</dfn>; must not be {@code null}
1229   *
1230   * @return a {@link RecordComponentElement} corresponding to the supplied {@link ExecutableElement}, or {@code null}
1231   *
1232   * @exception NullPointerException if {@code e} is {@code null}
1233   *
1234   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-8.html#jls-8.10.3 Java Language Specification, section
1235   * 8.10.3
1236   */
1237  public RecordComponentElement recordComponentElement(final ExecutableElement e);
1238
1239  /**
1240   * Returns {@code true} if and only if the two arguments represent the <dfn>same type</dfn>.
1241   *
1242   * <p>This method differs from the {@link javax.lang.model.util.Types#isSameType(TypeMirror, TypeMirror)} method in
1243   * two ways:</p>
1244   *
1245   * <ul>
1246   *
1247   * <li>Its arguments may be {@code null}. If both arguments are {@code null}, {@code true} is returned. If only one
1248   * argument is {@code null}, {@code false} is returned.</li>
1249   *
1250   * <li>If the same Java object reference is passed as both arguments, {@code true} is returned (even if it {@linkplain
1251   * TypeMirror#getKind() has a <code>TypeKind</code>} of {@link TypeKind#WILDCARD}).</li>
1252   *
1253   * </ul>
1254   *
1255   * @param t0 the first {@link TypeMirror}; may be {@code null}
1256   *
1257   * @param t1 the second {@link TypeMirror}; may be {@code null}
1258   *
1259   * @return {@code true} if and only if the two arguments represent the <dfn>same type</dfn>; {@code false} otherwise
1260   *
1261   * @see javax.lang.model.util.Types#isSameType(TypeMirror, TypeMirror)
1262   *
1263   * @see <a href="https://bugs.openjdk.org/browse/JDK-8055219">JDK-8055219</a>
1264   *
1265   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-4.html#jls-4.3.4 Java Language Specification, section
1266   * 4.3.4
1267   *
1268   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-4.html#jls-4.5.1 Java Language Specification, section
1269   * 4.5.1
1270   */
1271  public boolean sameType(final TypeMirror t0, final TypeMirror t1);
1272
1273  /**
1274   * Returns {@code true} if and only if {@code et0} is a <dfn>subsignature</dfn> of {@code et1}.
1275   *
1276   * @param et0 the first {@link ExecutableType}; must not be {@code null}
1277   *
1278   * @param et1 the second {@link ExecutableType}; must not be {@code null}
1279   *
1280   * @return {@code true} if and only if {@code et0} is a <dfn>subsignature</dfn> of {@code et1}
1281   *
1282   * @exception NullPointerException if either argument is {@code null}
1283   *
1284   * @exception ClassCastException if this method is implemented in terms of the {@link
1285   * javax.lang.model.util.Types#isSubsignature(ExecutableType, ExecutableType)} method, and if each of the supplied
1286   * {@link ExecutableType} arguments does not have an {@linkplain TypeKind#EXECUTABLE <code>EXECUTABLE</code>
1287   * <code>TypeKind</code>}; this exception type is undocumented by the {@link
1288   * javax.lang.model.util.Types#isSubsignature(ExecutableType, ExecutableType)} method and so is subject to change
1289   * without prior notice
1290   *
1291   * @see javax.lang.model.util.Types#isSubsignature(ExecutableType, ExecutableType)
1292   *
1293   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-8.html#jls-8.4.2 Java Language Specification, section
1294   * 8.4.2
1295   */
1296  public boolean subsignature(final ExecutableType et0, final ExecutableType et1);
1297
1298  /**
1299   * Returns {@code true} if and only if {@code candidateSubtype} is a <dfn>subtype</dfn> of {@code supertype}.
1300   *
1301   * @param candidateSubtype the first {@link TypeMirror}; must not be {@code null}
1302   *
1303   * @param supertype the second {@link TypeMirror}; must not be {@code null}
1304   *
1305   * @return {@code true} if and only if {@code candidateSubtype} is a <dfn>subtype</dfn> of {@code supertype}
1306   *
1307   * @exception NullPointerException if either argument is {@code null}
1308   *
1309   * @see javax.lang.model.util.Types#isSubtype(TypeMirror, TypeMirror)
1310   *
1311   * @spec https://docs.oracle.com/javase/specs/jls/se25/html/jls-4.html#jls-4.10 Java Language Specification, section
1312   * 4.10
1313   */
1314  public boolean subtype(TypeMirror candidateSubtype, TypeMirror supertype);
1315
1316  /**
1317   * A convenience method that returns the {@link TypeMirror} corresponding to the supplied (reflective) {@link Type}.
1318   *
1319   * @param t a {@link Type}; must not be {@code null}
1320   *
1321   * @return the {@link TypeMirror} corresponding to the supplied {@link Type}; never {@code null}
1322   *
1323   * @exception NullPointerException if {@code t} is {@code null}
1324   *
1325   * @exception IllegalArgumentException if {@code t} is not a {@link Class}, {@link GenericArrayType}, {@link
1326   * ParameterizedType}, {@link java.lang.reflect.TypeVariable} or {@link java.lang.reflect.WildcardType}
1327   */
1328  // (Convenience.)
1329  public default TypeMirror type(final Type t) {
1330    // TODO: anywhere there is domain.declaredType(), consider passing
1331    // domain.moduleElement(this.getClass().getModule().getName()) as the first argument. Not sure how this works
1332    // exactly but I think it might be necessary.
1333    return switch (t) {
1334    case null -> throw new NullPointerException("t");
1335    case Class<?> c when t == boolean.class -> this.primitiveType(TypeKind.BOOLEAN);
1336    case Class<?> c when t == byte.class -> this.primitiveType(TypeKind.BYTE);
1337    case Class<?> c when t == char.class -> this.primitiveType(TypeKind.CHAR);
1338    case Class<?> c when t == double.class -> this.primitiveType(TypeKind.DOUBLE);
1339    case Class<?> c when t == float.class -> this.primitiveType(TypeKind.FLOAT);
1340    case Class<?> c when t == int.class -> this.primitiveType(TypeKind.INT);
1341    case Class<?> c when t == long.class -> this.primitiveType(TypeKind.LONG);
1342    case Class<?> c when t == short.class -> this.primitiveType(TypeKind.SHORT);
1343    case Class<?> c when t == void.class -> this.noType(TypeKind.VOID);
1344    case Class<?> c when t == Object.class -> this.javaLangObject().asType(); // cheap and easy optimization
1345    case Class<?> c when c.isArray() -> this.arrayTypeOf(this.type(c.getComponentType()));
1346    case Class<?> c -> this.declaredType(c.getCanonicalName());
1347    case GenericArrayType g -> this.arrayTypeOf(this.type(g.getGenericComponentType()));
1348    case ParameterizedType pt when pt.getOwnerType() == null ->
1349      this.declaredType(this.typeElement(((Class<?>)pt.getRawType()).getCanonicalName()),
1350                        this.types(pt.getActualTypeArguments()));
1351    case ParameterizedType pt ->
1352      this.declaredType((DeclaredType)this.type(pt.getOwnerType()),
1353                        this.typeElement(((Class<?>)pt.getRawType()).getCanonicalName()),
1354                        this.types(pt.getActualTypeArguments()));
1355    case java.lang.reflect.TypeVariable<?> tv -> this.typeVariable(this.parameterizable(tv.getGenericDeclaration()), tv.getName());
1356    case java.lang.reflect.WildcardType w when w.getLowerBounds().length <= 0 -> this.wildcardType(this.type(w.getUpperBounds()[0]), null);
1357    case java.lang.reflect.WildcardType w -> this.wildcardType(null, this.type(w.getLowerBounds()[0]));
1358    default -> throw new IllegalArgumentException("t: " + t);
1359    };
1360  }
1361
1362  /**
1363   * A convenience method that returns an array of {@link TypeMirror}s whose elements correspond, in order, to the
1364   * elements in the supplied {@link Type} array.
1365   *
1366   * @param ts an array of {@link Type}s; must not be {@code null}
1367   *
1368   * @return an array of {@link TypeMirror}s whose elements correspond, in order, to the elements in the supplied {@link
1369   * Type} array; never {@code null}
1370   *
1371   * @exception NullPointerException if {@code ts} is {@code null} or contains {@code null} elements
1372   *
1373   * @exception IllegalArgumentException if any element of {@code ts} is deemed illegal by the {@link #type(Type)}
1374   * method
1375   *
1376   * @see #type(Type)
1377   */
1378  // (Convenience.)
1379  public default TypeMirror[] types(final Type[] ts) {
1380    return switch (ts.length) {
1381    case 0 -> new TypeMirror[0];
1382    case 1 -> new TypeMirror[] { this.type(ts[0]) };
1383    default -> {
1384      final TypeMirror[] rv = new TypeMirror[ts.length];
1385      for (int i = 0; i < ts.length; i++) {
1386        rv[i] = this.type(ts[i]);
1387      }
1388      yield rv;
1389    }
1390    };
1391  }
1392
1393  /**
1394   * Returns a {@link TypeElement} representing the element bearing the supplied <dfn>canonical name</dfn>, <strong>or
1395   * {@code null} if there is no such {@link TypeElement}</strong>.
1396   *
1397   * @param canonicalName a valid canonical name; must not be {@code null}
1398   *
1399   * @return a {@link TypeElement}, or {@code null}
1400   *
1401   * @exception NullPointerException if {@code canonicalName} is {@code null}
1402   *
1403   * @see javax.lang.model.util.Elements#getTypeElement(CharSequence)
1404   *
1405   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-6.html#jls-6.7 Java Language Specification, section
1406   * 6.7
1407   */
1408  // Element factory method.
1409  public TypeElement typeElement(final CharSequence canonicalName);
1410
1411  /**
1412   * Returns a {@link TypeElement} representing the element bearing the supplied <dfn>canonical name</dfn>, as read or
1413   * seen from the module represented by the supplied {@link ModuleElement}, <strong>or {@code null} if there is no such
1414   * {@link TypeElement}</strong>.
1415   *
1416   * @param asSeenFrom a {@link ModuleElement}; must not be {@code null}
1417   *
1418   * @param canonicalName a valid canonical name; must not be {@code null}
1419   *
1420   * @return a {@link TypeElement}, or {@code null}
1421   *
1422   * @exception NullPointerException if either {@code asSeenFrom} or {@code canonicalName} is {@code null}
1423   *
1424   * @see javax.lang.model.util.Elements#getTypeElement(ModuleElement, CharSequence)
1425   *
1426   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-6.html#jls-6.7 Java Language Specification, section
1427   * 6.7
1428   */
1429  // Element factory method.
1430  public TypeElement typeElement(final ModuleElement asSeenFrom, final CharSequence canonicalName);
1431
1432  /**
1433   * Returns a {@link TypeElement} representing the result of applying <dfn>boxing conversion</dfn> to the primitive
1434   * type represented by the supplied {@link PrimitiveType} argument.
1435   *
1436   * <p>The default implementation of this method calls the {@link #typeElement(TypeKind)} method with the supplied
1437   * {@link PrimitiveType}'s {@linkplain TypeMirror#getKind() affiliated <code>TypeKind</code>} and returns its
1438   * result.</p>
1439   *
1440   * @param t a {@link PrimitiveType} with a {@link TypeKind} that {@linkplain TypeKind#isPrimitive() is primitive};
1441   * must not be {@code null}
1442   *
1443   * @return a non-{@code null} {@link TypeElement} representing the result of applying boxing conversion to the
1444   * supplied argument
1445   *
1446   * @exception NullPointerException if {@code t} is {@code null}
1447   *
1448   * @exception ClassCastException if this method is implemented in terms of the {@link
1449   * javax.lang.model.util.Types#boxedClass(PrimitiveType)} method, and if the supplied {@link PrimitiveType} does not
1450   * have a {@linkplain TypeKind#isPrimitive() primitive <code>TypeKind</code>}; this exception type is undocumented by
1451   * the {@link javax.lang.model.util.Types#boxedClass(PrimitiveType)} method and so is subject to change without prior
1452   * notice
1453   *
1454   * @exception IllegalArgumentException if {@code primitiveTypeKind} {@linkplain TypeKind#isPrimitive() is not
1455   * primitive}
1456   *
1457   * @see #typeElement(TypeKind)
1458   *
1459   * @see javax.lang.model.util.Types#boxedClass(PrimitiveType)
1460   *
1461   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-5.html#jls-5.1.7 Java Language Specification, section
1462   * 5.1.7
1463   */
1464  // Element factory method.
1465  // (Canonical.)
1466  // (Boxing.)
1467  public default TypeElement typeElement(final PrimitiveType t) {
1468    return switch (t) {
1469    case null -> throw new NullPointerException("t");
1470    case UniversalType ut -> this.typeElement(ut.getKind());
1471    default -> {
1472      try (var lock = this.lock()) {
1473        yield this.typeElement(t.getKind());
1474      }
1475    }
1476    };
1477  }
1478
1479  /**
1480   * Returns a {@link TypeElement} representing the result of applying <dfn>boxing conversion</dfn> to the primitive
1481   * type represented by the supplied {@link TypeKind} argument, if it {@linkplain TypeKind#isPrimitive() is primitive}.
1482   *
1483   * @param primitiveTypeKind a {@link TypeKind} that {@linkplain TypeKind#isPrimitive() is primitive}; must not be
1484   * {@code null}
1485   *
1486   * @return a non-{@code null} {@link TypeElement} representing the result of applying boxing conversion to the
1487   * supplied argument
1488   *
1489   * @exception IllegalArgumentException if {@code primitiveTypeKind} {@linkplain TypeKind#isPrimitive() is not
1490   * primitive}
1491   *
1492   * @see #typeElement(PrimitiveType)
1493   *
1494   * @see javax.lang.model.util.Types#boxedClass(PrimitiveType)
1495   *
1496   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-5.html#jls-5.1.7 Java Language Specification, section
1497   * 5.1.7
1498   */
1499  // (Convenience.)
1500  // (Boxing.)
1501  public default TypeElement typeElement(final TypeKind primitiveTypeKind) {
1502    return switch (primitiveTypeKind) {
1503    case BOOLEAN -> this.typeElement("java.lang.Boolean");
1504    case BYTE -> this.typeElement("java.lang.Byte");
1505    case CHAR -> this.typeElement("java.lang.Character");
1506    case DOUBLE -> this.typeElement("java.lang.Double");
1507    case FLOAT -> this.typeElement("java.lang.Float");
1508    case INT -> this.typeElement("java.lang.Integer");
1509    case LONG -> this.typeElement("java.lang.Long");
1510    case SHORT -> this.typeElement("java.lang.Short");
1511    default -> throw new IllegalArgumentException("primitiveTypeKind: " + primitiveTypeKind);
1512    };
1513  }
1514
1515  /**
1516   * Returns the {@link TypeParameterElement} {@linkplain Parameterizable#getTypeParameters() contained} by the supplied
1517   * {@link Parameterizable} whose {@linkplain TypeParameterElement#getSimpleName() name} {@linkplain
1518   * Name#contentEquals(CharSequence) is equal to} the supplied {@code name}, <strong>or {@code null} if there is no
1519   * such {@link TypeParameterElement}</strong>.
1520   *
1521   * @param p a {@link Parameterizable}; must not be {@code null}
1522   *
1523   * @param name a name valid for a type parameter; must not be {@code null}
1524   *
1525   * @return a {@link TypeParameterElement}, or {@code null}
1526   */
1527  // (Convenience.)
1528  public default TypeParameterElement typeParameterElement(Parameterizable p, final CharSequence name) {
1529    requireNonNull(p, "p");
1530    requireNonNull(name, "name");
1531    while (p != null) {
1532      switch (p) {
1533      case UniversalElement ue:
1534        for (final UniversalElement tpe : ue.getTypeParameters()) {
1535          if (tpe.getSimpleName().contentEquals(name)) {
1536            return tpe;
1537          }
1538        }
1539        p = ue.getEnclosingElement();
1540        break;
1541      default:
1542        try (var lock = this.lock()) {
1543          for (final TypeParameterElement tpe : p.getTypeParameters()) {
1544            if (tpe.getSimpleName().contentEquals(name)) {
1545              return tpe;
1546            }
1547          }
1548          p = (Parameterizable)((Element)p).getEnclosingElement();
1549        }
1550        break;
1551      }
1552    }
1553    return null;
1554  }
1555
1556  /**
1557   * A convenience method that returns the {@link TypeVariable} {@linkplain TypeParameterElement#asType() declared by}
1558   * the {@link TypeParameterElement} {@linkplain Parameterizable#getTypeParameters() contained} by the supplied {@link
1559   * Parameterizable} whose {@linkplain TypeParameterElement#getSimpleName() name} {@linkplain
1560   * Name#contentEquals(CharSequence) is equal to} the supplied {@code name}, <strong>or {@code null} if there is no
1561   * such {@link TypeParameterElement} or {@link TypeVariable}</strong>.
1562   *
1563   * @param p a {@link Parameterizable}; must not be {@code null}
1564   *
1565   * @param name a name valid for a type parameter; must not be {@code null}
1566   *
1567   * @return a {@link TypeVariable}, or {@code null}
1568   *
1569   * @see #typeParameterElement(Parameterizable, CharSequence)
1570   */
1571  // (Convenience.)
1572  public default TypeVariable typeVariable(Parameterizable p, final CharSequence name) {
1573    final TypeParameterElement e = this.typeParameterElement(p, name);
1574    return e == null ? null : (TypeVariable)e.asType();
1575  }
1576
1577  /**
1578   * A convenience method that returns the first {@link VariableElement} {@linkplain Element#getSimpleName() bearing}
1579   * the supplied {@code simpleName} that the supplied {@code enclosingElement} {@linkplain
1580   * Element#getEnclosedElements() encloses}, <strong>or {@code null} if there is no such {@link
1581   * VariableElement}</strong>.
1582   *
1583   * @param enclosingElement an {@link Element}; must not be {@code null}
1584   *
1585   * @param simpleName a {@link CharSequence}; must not be {@code null}
1586   *
1587   * @return a {@link VariableElement}, or {@code null}
1588   *
1589   * @exception NullPointerException if either argument is {@code null}
1590   *
1591   * @see Element#getEnclosedElements()
1592   *
1593   * @see Element#getSimpleName()
1594   *
1595   * @see VariableElement
1596   */
1597  // (Convenience.)
1598  public default VariableElement variableElement(final Element enclosingElement, final CharSequence simpleName) {
1599    requireNonNull(simpleName, "simpleName");
1600    return switch (enclosingElement) {
1601    case null -> throw new NullPointerException("enclosingElement");
1602    case UniversalElement ue -> {
1603      for (final UniversalElement ee : ue.getEnclosedElements()) {
1604        if (ee.getSimpleName().contentEquals(simpleName)) {
1605          yield ee;
1606        }
1607      }
1608      yield null;
1609    }
1610    default -> {
1611      try (var lock = lock()) {
1612        for (final Element ee : enclosingElement.getEnclosedElements()) {
1613          if (ee.getSimpleName().contentEquals(simpleName)) {
1614            yield (VariableElement)ee;
1615          }
1616        }
1617      }
1618      yield null;
1619    }
1620    };
1621  }
1622
1623  /**
1624   * A convenience method that returns a new {@link WildcardType} {@linkplain TypeMirror#getKind() with a
1625   * <code>TypeKind</code>} of {@link TypeKind#WILDCARD}, an {@linkplain WildcardType#getExtendsBound() extends bound}
1626   * of {@code null}, and a {@linkplain WildcardType#getSuperBound() super bound} of {@code null}.
1627   *
1628   * @return a new, non-{@code null} {@link WildcardType}
1629   *
1630   * @see #wildcardType(TypeMirror, TypeMirror)
1631   *
1632   * @see javax.lang.model.util.Types#getWildcardType(TypeMirror, TypeMirror)
1633   *
1634   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-4.html#jls-4.5.1 Java Language Specification, section
1635   * 4.5.1
1636   */
1637  // (Convenience.)
1638  public default WildcardType wildcardType() {
1639    return this.wildcardType(null, null);
1640  }
1641
1642  /**
1643   * Returns a new {@link WildcardType} {@linkplain TypeMirror#getKind() with a <code>TypeKind</code>} of {@link
1644   * TypeKind#WILDCARD}, an {@linkplain WildcardType#getExtendsBound() extends bound} of the supplied {@code
1645   * extendsBound}, and a {@linkplain WildcardType#getSuperBound() super bound} of the supplied {@code superBound}.
1646   *
1647   * <p>Any argument may be {@code null}. Both arguments may not be non-{@code null}.</p>
1648   *
1649   * @param extendsBound the upper bound of the new {@link WildcardType}; may be {@code null}
1650   *
1651   * @param superBound the lower bound of the new {@link WildcardType}; may be {@code null}
1652   *
1653   * @return a new, non-{@code null} {@link WildcardType}
1654   *
1655   * @exception IllegalArgumentException if both arguments are non-{@code null} or otherwise unsuitable for being the
1656   * bounds of a {@link WildcardType}
1657   *
1658   * @see javax.lang.model.util.Types#getWildcardType(TypeMirror, TypeMirror)
1659   *
1660   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-4.html#jls-4.5.1 Java Language Specification, section
1661   * 4.5.1
1662   */
1663  // Type factory method.
1664  public WildcardType wildcardType(TypeMirror extendsBound, TypeMirror superBound);
1665
1666}