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