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.util.List;
017import java.util.Objects;
018
019import javax.lang.model.element.Element;
020import javax.lang.model.element.ElementKind;
021import javax.lang.model.element.ExecutableElement;
022import javax.lang.model.element.ModuleElement;
023import javax.lang.model.element.Name;
024import javax.lang.model.element.PackageElement;
025import javax.lang.model.element.Parameterizable;
026import javax.lang.model.element.QualifiedNameable;
027import javax.lang.model.element.RecordComponentElement;
028import javax.lang.model.element.TypeElement;
029import javax.lang.model.element.TypeParameterElement;
030import javax.lang.model.element.VariableElement;
031
032import javax.lang.model.type.ArrayType;
033import javax.lang.model.type.DeclaredType;
034import javax.lang.model.type.ExecutableType;
035import javax.lang.model.type.NoType;
036import javax.lang.model.type.NullType;
037import javax.lang.model.type.PrimitiveType;
038import javax.lang.model.type.TypeKind;
039import javax.lang.model.type.TypeMirror;
040import javax.lang.model.type.TypeVariable;
041import javax.lang.model.type.WildcardType;
042
043import org.microbean.construct.element.StringName;
044import org.microbean.construct.element.UniversalElement;
045
046import org.microbean.construct.type.UniversalType;
047
048import static javax.lang.model.element.ElementKind.CONSTRUCTOR;
049import static javax.lang.model.element.ElementKind.METHOD;
050
051/**
052 * A representation of a domain of valid Java constructs.
053 *
054 * <p>A <dfn id="domain">domain</dfn> is a set of valid Java <a href="#construct">constructs</a>. A {@link Domain}
055 * provides access to a domain and its members.</p>
056 *
057 * <p>A Java <dfn id="construct">construct</dfn> is either a <a href="#type">type</a> or an <a
058 * href="#element">element</a>.</p>
059 *
060 * <p>A <dfn id="type">type</dfn> is a usage of a Java type, most commonly represented as a {@link TypeMirror}.</p>
061 *
062 * <p>An <dfn id="element">element</dfn> ia a declaration of a Java program element, most commonly represented as an
063 * {@link Element}.</p>
064 *
065 * <p>Domains impose constraints on the <a href="#type">types</a> and <a href="#element">elements</a> they contain, and
066 * on the kinds and semantics of operations that can be performed on them.</p>
067 *
068 * <p>This interface is modeled on a deliberately restricted combination of the {@link javax.lang.model.util.Elements}
069 * and {@link javax.lang.model.util.Types} interfaces.</p>
070 *
071 * <p>{@link Domain} implementations must be thread-safe.</p>
072 *
073 * @author <a href="https://about.me/lairdnelson" target="_top">Laird Nelson</a>
074 */
075@SuppressWarnings("try")
076public interface Domain {
077
078  /**
079   * Returns an {@link ArrayType} whose {@linkplain ArrayType#getComponentType() component type} is {@linkplain
080   * #sameType(TypeMirror, TypeMirror) the same as} the supplied {@code componentType}.
081   *
082   * @param componentType the component type; must not be {@code null}
083   *
084   * @return a non-{@code null} {@link ArrayType} whose {@linkplain ArrayType#getComponentType() component type} is
085   * {@linkplain #sameType(TypeMirror, TypeMirror) the same as} the supplied {@code componentType}
086   *
087   * @exception NullPointerException if {@code componentType} is {@code null}
088   *
089   * @exception IllegalArgumentException if {@code componentType} is not a valid component type
090   *
091   * @see javax.lang.model.util.Types#getArrayType(TypeMirror)
092   */
093  public ArrayType arrayTypeOf(final TypeMirror componentType);
094
095  /**
096   * Returns a non-{@code null} {@link TypeMirror} representing the type of the supplied {@link Element} when that
097   * {@link Element} is viewed as a member of, or otherwise directly contained by, the supplied {@code containingType}.
098   *
099   * <p>For example, when viewed as a member of the parameterized type {@link java.util.Set Set&lt;String&gt;}, the
100   * {@link java.util.Set#add(Object)} method (represented as an {@link ExecutableElement}) {@linkplain
101   * ExecutableElement#asType() has} a {@linkplain ExecutableType type} whose {@linkplain
102   * ExecutableType#getParameterTypes() method parameter is of type} {@link String} (not {@link String}'s erasure).</p>
103   *
104   * @param containingType the containing {@link DeclaredType}; must not be {@code null}
105   *
106   * @param e the member {@link Element}; must not be {@code null}
107   *
108   * @return a non-{@code null} {@linkplain TypeMirror type} representing the {@linkplain Element#asType() type of} the
109   * supplied {@link Element} when viewed as a member of the supplied {@code containingType}; never {@code null}
110   *
111   * @exception NullPointerException if either {@code containingType} or {@code e} is {@code null}
112   *
113   * @exception IllegalArgumentException if {@code e} cannot be viewed as a member of the supplied {@code
114   * containingType} (because it is the wrong {@linkplain Element#getKind() kind}, for example)
115   *
116   * @see javax.lang.model.util.Types#asMemberOf(DeclaredType, Element)
117   */
118  public TypeMirror asMemberOf(final DeclaredType containingType, final Element e);
119
120  /**
121   * Returns {@code true} if and only if the supplied {@code payload} (the first argument) is considered assignable to
122   * the supplied {@code receiver} (the second argument) according to <a
123   * href="https://docs.oracle.com/javase/specs/jls/se21/html/jls-5.html#jls-5.2">the rules of the Java Language
124   * Specification</a>.
125   *
126   * @param payload the {@link TypeMirror} being assigned; must not be {@code null}
127   *
128   * @param receiver the {@link TypeMirror} receiving the assignment; must not be {@code null}
129   *
130   * @return {@code true} if and only if {@code payload} is assignable to {@code receiver}
131   *
132   * @exception NullPointerException if either {@code payload} or {@code receiver} is {@code null}
133   *
134   * @exception IllegalArgumentException if either {@link TypeMirror} is not one that can take part in an assignment
135   *
136   * @see javax.lang.model.util.Types#isAssignable(TypeMirror, TypeMirror)
137   *
138   * @spec https://docs.oracle.com/javase/specs/jls/se21/html/jls-5.html#jls-5.2 Java Language Specification, section
139   * 5.2
140   */
141  // Note the strange positioning of payload and receiver.
142  public boolean assignable(final TypeMirror payload, final TypeMirror receiver);
143
144  /**
145   * Returns the (non-{@code null}) <a
146   * href="https://docs.oracle.com/javase/specs/jls/se21/html/jls-13.html#jls-13.1"><dfn>binary name</dfn></a> of the
147   * supplied {@link TypeElement}.
148   *
149   * @param e a {@link TypeElement}; must not be {@code null}
150   *
151   * @return a non-{@code null} {@link Name}
152   *
153   * @see javax.lang.model.util.Elements#getBinaryName(TypeElement)
154   *
155   * @spec https://docs.oracle.com/javase/specs/jls/se21/html/jls-13.html#jls-13.1 Java Language Specification, section
156   * 13.1
157   */
158  public Name binaryName(final TypeElement e);
159
160  /**
161   * Applies <a href="https://docs.oracle.com/javase/specs/jls/se23/html/jls-5.html#jls-5.1.10"><dfn>capture
162   * conversion</dfn></a> to the supplied {@link TypeMirror}, which is normally a {@linkplain TypeKind#WILDCARD wildcard
163   * type}.
164   *
165   * @param wildcard a {@link TypeMirror}; must not be {@code null}; if not a {@linkplain TypeKind#WILDCARD wildcard
166   * type}, then it will be returned unchanged
167   *
168   * @return a non-{@code null} {@link TypeMirror} representing the result of <a
169   * href="https://docs.oracle.com/javase/specs/jls/se23/html/jls-5.html#jls-5.1.10">capture conversion</a> applied to
170   * the supplied {@link TypeMirror}
171   *
172   * @exception NullPointerException if {@code wildcard} is {@code null}
173   *
174   * @see javax.lang.model.util.Types#capture(TypeMirror)
175   *
176   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-5.html#jls-5.1.10 Java Language Specification, section
177   * 5.1.10
178   */
179  public TypeMirror capture(final TypeMirror wildcard);
180
181  /**
182   * Returns {@code true} if and only if {@code candidateContainer} <dfn>contains</dfn> {@code candidate}, according to
183   * the <a href="https://docs.oracle.com/javase/specs/jls/se23/html/jls-4.html#jls-4.5.1">Java Language Specification,
184   * section 4.5.1</a>.
185   *
186   * @param candidateContainer the putative containing type; normally a {@linkplain TypeKind#WILDCARD wildcard type};
187   * must not be {@code null}
188   *
189   * @param candidate the putative contained type; must not be {@code null}
190   *
191   * @return {@code true} if and only if {@code candidateContainer} <dfn>contains</dfn> {@code candidate}, according to
192   * the <a href="https://docs.oracle.com/javase/specs/jls/se23/html/jls-4.html#jls-4.5.1">Java Language Specification,
193   * section 4.5.1</a>; {@code false} otherwise
194   *
195   * @exception NullPointerException if either argument is {@code null}
196   *
197   * @exception IllegalArgumentException if either argument is either an {@linkplain TypeKind#EXECUTABLE executable
198   * type}, a {@linkplain TypeKind#MODULE module type}, or a {@linkplain TypeKind#PACKAGE package type}
199   *
200   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-4.html#jls-4.5.1 Java Language Specification, section
201   * 4.5.1
202   */
203  public boolean contains(final TypeMirror candidateContainer, final TypeMirror candidate);
204
205  /**
206   * A convenience method that returns the {@link DeclaredType} {@linkplain TypeElement#asType() of} a {@link
207   * TypeElement} that bears the supplied {@code canonicalName}, <strong>or {@code null} if there is no such {@link
208   * TypeElement} (and therefore no such {@link DeclaredType})</strong>.
209   *
210   * @param canonicalName a valid canonical name; must not be {@code null}
211   *
212   * @return a {@link DeclaredType} with a {@link TypeKind} of {@link TypeKind#DECLARED}, or {@code null}
213   *
214   * @see #typeElement(CharSequence)
215   *
216   * @see #declaredType(TypeElement, TypeMirror...)
217   *
218   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-6.html#jls-6.7 Java Language Specification, section
219   * 6.7
220   */
221  public default DeclaredType declaredType(final CharSequence canonicalName) {
222    final TypeElement e = this.typeElement(canonicalName);
223    return e == null ? null : this.declaredType(e);
224  }
225
226  /**
227   * Returns the {@link DeclaredType} {@linkplain TypeElement#asType() of} the supplied {@link TypeElement} with the
228   * supplied {@link TypeMirror} arguments (if any), yielding a parameterized type.
229   *
230   * <p>Given a {@link TypeElement} representing the class named {@link java.util.Set java.util.Set} and a {@link
231   * TypeMirror} representing the type declared by {@link String java.lang.String}, for example, this method will return
232   * a {@link DeclaredType} representing the parameterized type corresponding to {@link java.util.Set
233   * java.util.Set&lt;java.lang.String&gt;}.</p>
234   *
235   * <p>The number of supplied type arguments must either equal the number of the supplied {@link TypeElement}'s
236   * {@linkplain TypeElement#getTypeParameters() formal type parameters}, or must be zero. If it is zero, and if the
237   * supplied {@link TypeElement} {@link #generic(Element) is generic}, then the supplied {@link TypeElement}'s raw type
238   * is returned.</p>
239   *
240   * <p>If a parameterized type is returned, {@linkplain DeclaredType#asElement() its <code>TypeElement</code>} must not
241   * be contained within a {@linkplain #generic(Element) generic} outer class. The parameterized type {@code
242   * Outer<String>.Inner<Number>}, for example, may be constructed by first using this method to get the type {@code
243   * Outer<String>}, and then invoking {@link #declaredType(DeclaredType, TypeElement, TypeMirror...)}.</p>
244   *
245   * @param typeElement a {@link TypeElement}; must not be {@code null}
246   *
247   * @param typeArguments any type arguments (represented by {@link TypeMirror}s); must not be {@code null}
248   *
249   * @return a non-{@code null} {@link DeclaredType} with a {@link TypeKind} of {@link TypeKind#DECLARED}
250   *
251   * @exception NullPointerException if {@code typeElement} or {@code typeArguments} is {@code null}
252   *
253   * @see javax.lang.model.util.Types#getDeclaredType(TypeElement, TypeMirror...)
254   *
255   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-4.html#jls-4.5 Java Language Specification, section 4.5
256   */
257  public DeclaredType declaredType(final TypeElement typeElement,
258                                   final TypeMirror... typeArguments);
259
260  /**
261   * Returns the {@link DeclaredType} {@linkplain TypeElement#asType() of} the supplied {@link TypeElement} with the
262   * supplied {@link TypeMirror} arguments (if any), given a containing {@link DeclaredType} of which it is a member,
263   * yielding a parameterized type.
264   *
265   * <p>Given a {@link DeclaredType} representing the parameterized type corresponding to {@code Outer<}{@link
266   * String}{@code >} (see the {@link #declaredType(TypeElement, TypeMirror...)} method), a {@link TypeElement}
267   * representing the class named {@code Outer.Inner} and a {@link DeclaredType} representing the non-generic class
268   * corresponding to {@link Number}, for example, this method will return a {@link DeclaredType} representing the
269   * parameterized type corresponding to {@code Outer<}{@link String}{@code >}{@code .Inner<}{@link Number}{@code >}.</p>
270   *
271   * <p>The number of supplied type arguments must either equal the number of the supplied {@link TypeElement}'s
272   * {@linkplain TypeElement#getTypeParameters() formal type parameters}, or must be zero. If it is zero, and if the
273   * supplied {@link TypeElement} {@link #generic(Element) is generic}, then the supplied {@link TypeElement}'s raw type
274   * is returned.</p>
275   *
276   * @param enclosingType a {@link DeclaredType} representing the containing type; must not be {@code null}
277   *
278   * @param typeElement a {@link TypeElement}; must not be {@code null}
279   *
280   * @param typeArguments any type arguments (represented by {@link TypeMirror}s); must not be {@code null}
281   *
282   * @return a non-{@code null} {@link DeclaredType} with a {@link TypeKind} of {@link TypeKind#DECLARED}
283   *
284   * @exception NullPointerException if {@code enclosingType}, {@code typeElement}, or {@code typeArguments} is {@code
285   * null}
286   *
287   * @see #declaredType(TypeElement, TypeMirror...)
288   *
289   * @see javax.lang.model.util.Types#getDeclaredType(DeclaredType, TypeElement, TypeMirror...)
290   *
291   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-4.html#jls-4.5 Java Language Specification, section 4.5
292   */
293  public DeclaredType declaredType(final DeclaredType enclosingType,
294                                   final TypeElement typeElement,
295                                   final TypeMirror... typeArguments);
296
297  /**
298   * Returns a non-{@code null} {@link List} of the <dfn>direct supertypes</dfn> of the supplied {@link TypeMirror},
299   * which is normally a {@linkplain TypeKind#DECLARED declared type}.
300   *
301   * @param t a {@link TypeMirror}; must not be {@code null}; must not be an {@linkplain TypeKind#EXECUTABLE executable
302   * type}, a {@linkplain TypeKind#MODULE module type}, or a {@linkplain TypeKind#PACKAGE package type}
303   *
304   * @return a non-{@code null}, immutable {@link List} of {@link TypeMirror}s representing the direct supertypes
305   *
306   * @exception NullPointerException if {@code t} is {@code null}
307   *
308   * @exception IllegalArgumentException if either argument is either an {@linkplain TypeKind#EXECUTABLE executable
309   * type}, a {@linkplain TypeKind#MODULE module type}, or a {@linkplain TypeKind#PACKAGE package type}
310   *
311   * @see javax.lang.model.util.Types#directSupertypes(TypeMirror)
312   *
313   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-4.html#jls-4.10 Java Language Specification, section
314   * 4.10
315   */
316  public List<? extends TypeMirror> directSupertypes(final TypeMirror t);
317
318  /**
319   * Returns the {@link Element} responsible for declaring the supplied {@link TypeMirror}, which is most commonly a
320   * {@link DeclaredType}, a {@link TypeVariable}, a {@link NoType} with a {@link TypeKind} of {@link TypeKind#MODULE},
321   * or a {@link NoType} with a {@link TypeKind} of {@link TypeKind#PACKAGE}, <strong>or {@code null} if there is no
322   * such {@link Element}</strong>.
323   *
324   * @param t a {@link TypeMirror}; must not be {@code null}
325   *
326   * @return an {@link Element}, or {@code null}
327   *
328   * @exception NullPointerException if {@code t} is {@code null}
329   *
330   * @see javax.lang.model.util.Types#asElement(TypeMirror)
331   */
332  public Element element(final TypeMirror t);
333
334  /**
335   * A convenience method that returns the <dfn>element type</dfn> of the supplied {@link TypeMirror}.
336   *
337   * <p>The element type of an {@linkplain TypeKind#ARRAY array type} is the element type of its {@linkplain
338   * ArrayType#getComponentType() component type}.</p>.
339   *
340   * <p>The element type of every other kind of type is the type itself. Note that the semantics of the prior sentence
341   * diverge deliberately, primarily for convenience, from those of the relevant section in the Java Language
342   * Specification.</p>
343   *
344   * @param t a {@link TypeMirror}; must not be {@code null}
345   *
346   * @return the <dfn>element type</dfn> of the supplied {@link TypeMirror}; never {@code null}
347   *
348   * @exception NullPointerException if {@code t} is {@code null}
349   *
350   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-10.html#jls-10.1 Java Language Specification, section
351   * 10.1
352   */
353  public default TypeMirror elementType(final TypeMirror t) {
354    return switch (t) {
355    case null -> throw new NullPointerException("t");
356    case UniversalType ut -> ut.elementType();
357    default -> {
358      try (var lock = lock()) {
359        yield t.getKind() == TypeKind.ARRAY ? this.elementType(((ArrayType)t).getComponentType()) : t;
360      }
361    }
362    };
363  }
364
365  /**
366   * Returns the <dfn>erasure</dfn> of the supplied {@link TypeMirror}.
367   *
368   * @param <T> a {@link TypeMirror} specialization
369   *
370   * @param t the {@link TypeMirror} representing the type whose erasure should be returned; must not be {@code null}
371   *
372   * @return the erasure of the supplied {@link TypeMirror}; never {@code null}
373   *
374   * @exception NullPointerException if {@code t} is {@code null}
375   *
376   * @exception IllegalArgumentException if {@code t} is a {@link NoType} with a {@link TypeKind} of {@link
377   * TypeKind#MODULE}, or a {@link NoType} with a {@link TypeKind} of {@link TypeKind#PACKAGE}
378   *
379   * @see javax.lang.model.util.Types#erasure(TypeMirror)
380   *
381   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-4.html#jls-4.6 Java Language Specification, section
382   * 4.6
383   */
384  public <T extends TypeMirror> T erasure(final T t);
385
386  /**
387   * A convenience method that returns an {@link ExecutableElement} representing the static initializer, constructor or
388   * method described by the supplied arguments, <strong>or {@code null} if no such {@link ExecutableElement}
389   * exists</strong>.
390   *
391   * @param declaringElement a {@link TypeElement} representing the class that declares the executable; must not be
392   * {@code null}
393   *
394   * @param returnType the {@linkplain ExecutableElement#getReturnType() return type} of the executable; must not be
395   * {@code null}
396   *
397   * @param name the {@linkplain ExecutableElement#getSimpleName() name} of the executable; must not be {@code null}
398   *
399   * @param parameterTypes {@link TypeMirror}s that represent the executable's {@linkplain
400   * ExecutableElement#getParameters() parameter types}
401   *
402   * @return an {@link ExecutableElement} with an {@link ElementKind} of {@link ElementKind#CONSTRUCTOR}, {@link
403   * ElementKind#METHOD}, or {@link ElementKind#STATIC_INIT}, or {@code null}
404   *
405   * @exception NullPointerException if any argument is {@code null}
406   */
407  public default ExecutableElement executableElement(final TypeElement declaringElement,
408                                                     final TypeMirror returnType,
409                                                     final CharSequence name,
410                                                     final TypeMirror... parameterTypes) {
411    return switch (declaringElement) {
412    case null -> throw new NullPointerException("declaringElement");
413    case UniversalElement ue -> {
414      final List<? extends UniversalElement> ees = ue.getEnclosedElements();
415      yield ees.stream()
416        .sequential()
417        .filter(e -> e.getKind().isExecutable() && e.getSimpleName().contentEquals(name))
418        .map(UniversalElement.class::cast)
419        .filter(ee -> {
420            if (!this.sameType(returnType, ee.getReturnType())) {
421              return false;
422            }
423            final List<? extends UniversalElement> ps = ee.getParameters();
424            if (ps.size() != parameterTypes.length) {
425              return false;
426            }
427            for (int i = 0; i < parameterTypes.length; i++) {
428              if (!this.sameType(ps.get(i).asType(), parameterTypes[i])) {
429                return false;
430              }
431            }
432            return true;
433          })
434        .findFirst()
435        .orElse(null);
436    }
437    default -> {
438      try (var lock = this.lock()) {
439        final List<? extends Element> ees = declaringElement.getEnclosedElements();
440        yield ees.stream()
441          .sequential()
442          .filter(e -> e.getKind().isExecutable() && e.getSimpleName().contentEquals(name))
443          .map(ExecutableElement.class::cast)
444          .filter(ee -> {
445              if (!this.sameType(returnType, ee.getReturnType())) {
446                return false;
447              }
448              final List<? extends VariableElement> ps = ee.getParameters();
449              if (ps.size() != parameterTypes.length) {
450                return false;
451              }
452              for (int i = 0; i < parameterTypes.length; i++) {
453                if (!this.sameType(ps.get(i).asType(), parameterTypes[i])) {
454                  return false;
455                }
456              }
457              return true;
458            })
459          .findFirst()
460          .orElse(null);
461      }
462    }
463    };
464  }
465
466  /**
467   * A convenience method that returns {@code true} if and only if the supplied {@link Element} is <dfn>generic</dfn>.
468   *
469   * @param e an {@link Element}; must not be {@code null}
470   *
471   * @return {@code true} if and only if the supplied {@link Element} is <dfn>generic</dfn>; {@code false} otherwise
472   *
473   * @exception NullPointerException if {@code e} is {@code null}
474   *
475   * @see Parameterizable
476   *
477   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-8.html#jls-8.1.2 Java Language Specification, section
478   * 8.1.2
479   *
480   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-8.html#jls-8.4.4 Java Language Specification, section
481   * 8.4.4
482   *
483   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-8.html#jls-8.8.4 Java Language Specification, section
484   * 8.8.4
485   *
486   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-9.html#jls-9.1.2 Java Language Specification, section
487   * 9.1.2
488   */
489  public default boolean generic(final Element e) {
490    return switch (e) {
491    case null -> throw new NullPointerException("e");
492    case UniversalElement ue -> ue.generic();
493    case Parameterizable p -> {
494      try (var lock = this.lock()) {
495        yield switch (e.getKind()) {
496        case CLASS, CONSTRUCTOR, ENUM, INTERFACE, METHOD, RECORD -> !p.getTypeParameters().isEmpty();
497        default -> false;
498        };
499      }
500    }
501    default -> false;
502    };
503  }
504
505  /**
506   * A convenience method that returns {@code true} if and only if the supplied {@link TypeMirror} is declared by an
507   * {@link Element} that {@linkplain #generic(Element) is generic}.
508   *
509   * @param t a {@link TypeMirror}; must not be {@code null}
510   *
511   * @return {@code true} if and only if the supplied {@link TypeMirror} is declared by an {@link Element} that
512   * {@linkplain #generic(Element) is generic}
513   *
514   * @exception NullPointerException if {@code t} is {@code null}
515   *
516   * @see #generic(Element)
517   *
518   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-8.html#jls-8.1.2 Java Language Specification, section
519   * 8.1.2
520   *
521   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-8.html#jls-8.4.4 Java Language Specification, section
522   * 8.4.4
523   *
524   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-8.html#jls-8.8.4 Java Language Specification, section
525   * 8.8.4
526   *
527   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-9.html#jls-9.1.2 Java Language Specification, section
528   * 9.1.2
529   */
530  public default boolean generic(final TypeMirror t) {
531    return switch (t) {
532    case null -> throw new NullPointerException("t");
533    case UniversalType ut -> ut.generic();
534    default -> {
535      try (var lock = this.lock()) {
536        final Element e = this.element(t);
537        yield e != null && this.generic(e);
538      }
539    }
540    };
541  }
542
543  /**
544   * A convenience method that returns {@code true} if and only if the supplied {@link Element} represents the (essentially
545   * primordial) {@code java.lang.Object} {@link Element}.
546   *
547   * @param e an {@link Element}; must not be {@code null}
548   *
549   * @return {@code true} if and only if the supplied {@link Element} represents the (essentially
550   * primordial) {@code java.lang.Object} {@link Element}; {@code false} otherwise
551   *
552   * @exception NullPointerException if {@code e} is {@code null}
553   */
554  public default boolean javaLangObject(final Element e) {
555    return switch (e) {
556    case null -> throw new NullPointerException("e");
557    case UniversalElement ue -> ue.javaLangObject();
558    default -> {
559      try (var lock = this.lock()) {
560        yield
561          e.getKind() == ElementKind.CLASS &&
562          ((QualifiedNameable)e).getQualifiedName().contentEquals("java.lang.Object");
563      }
564    }
565    };
566  }
567
568  /**
569   * A convenience method that returns {@code true} if and only if the supplied {@link TypeMirror} represents the {@link
570   * DeclaredType} declared by the (essentially primordial) {@code java.lang.Object} element.
571   *
572   * @param t a {@link TypeMirror}; must not be {@code null}
573   *
574   * @return {@code true} represents the {@link
575   * DeclaredType} declared by the (essentially primordial) {@code java.lang.Object} element; {@code false} otherwise
576   *
577   * @exception NullPointerException if {@code t} is {@code null}
578   *
579   * @see #javaLangObject(Element)
580   */
581  public default boolean javaLangObject(final TypeMirror t) {
582    return switch (t) {
583    case null -> throw new NullPointerException("t");
584    case UniversalType ut -> ut.javaLangObject();
585    default -> {
586      try (var lock = this.lock()) {
587        yield
588          t.getKind() == TypeKind.DECLARED &&
589          javaLangObject(((DeclaredType)t).asElement());
590      }
591    }
592    };
593  }
594
595  /**
596   * A convenience method that returns the {@link TypeElement} representing the class named {@link Object
597   * java.lang.Object}.
598   *
599   * @return a non-{@code null} {@link TypeElement} whose {@linkplain TypeElement#getQualifiedName() qualified name} is
600   * {@linkplain Name#contentEquals(CharSequence) equal to} {@code java.lang.Object}
601   *
602   * @see #typeElement(CharSequence)
603   */
604  public default TypeElement javaLangObject() {
605    return this.typeElement("java.lang.Object");
606  }
607
608  /**
609   * Semantically locks an opaque lock used to serialize symbol completion, and returns it in the form of an {@link
610   * Unlockable}.
611   *
612   * <p>Implementations of this method must not return {@code null}.</p>
613   *
614   * @return an {@link Unlockable} in a semantically locked state; never {@code null}
615   *
616   * @see Unlockable#close()
617   */
618  public Unlockable lock();
619
620  /**
621   * Returns a {@link ModuleElement} representing the module {@linkplain ModuleElement#getQualifiedName() named} by the
622   * supplied {@code qualifiedName}, <strong>or {@code null} if there is no such {@link ModuleElement}</strong>.
623   *
624   * @param qualifiedName a name suitable for naming a module; must not be {@code null}; may be {@linkplain
625   * CharSequence#isEmpty() empty}, in which case a {@link ModuleElement} representing an <dfn>unnamed module</dfn> will
626   * be returned
627   *
628   * @return a {@link ModuleElement}, or {@code null}
629   *
630   * @exception NullPointerException if {@code qualifiedName} is {@code null}
631   *
632   * @see javax.lang.model.util.Elements#getModuleElement(CharSequence)
633   *
634   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-7.html#jls-7.7 Java Language Specification, section
635   * 7.7
636   */
637  public ModuleElement moduleElement(final CharSequence qualifiedName);
638
639  /**
640   * Returns a {@link Name} representing the supplied {@link CharSequence}.
641   *
642   * @param name a {@link CharSequence}; must not be {@code null}
643   *
644   * @return a non-{@code null} {@link Name} representing the supplied {@link name}
645   *
646   * @exception NullPointerException if {@code name} is {@code null}
647   *
648   * @see #lock()
649   *
650   * @see javax.lang.model.util.Elements#getName(CharSequence)
651   */
652  public Name name(final CharSequence name);
653
654  /**
655   * Returns a {@link NoType} {@linkplain TypeMirror#getKind() bearing} the supplied {@link TypeKind}, if the supplied
656   * {@link TypeKind} is either {@link TypeKind#NONE} or {@link TypeKind#VOID}.
657   *
658   * @param kind a {@link TypeKind}; must be either {@link TypeKind#NONE} or {@link TypeKind#VOID}
659   *
660   * @return a non-{@code null} {@link NoType} {@linkplain TypeMirror#getKind() bearing} the supplied {@link TypeKind}
661   *
662   * @exception NullPointerException if {@code kind} is {@code null}
663   *
664   * @exception IllegalArgumentException if {@code kind} is non-{@code null} and neither {@link TypeKind#NONE} nor
665   * {@link TypeKind#VOID}
666   *
667   * @see TypeKind#NONE
668   *
669   * @see TypeKind#VOID
670   *
671   * @see javax.lang.model.util.Types#getNoType(TypeKind)
672   *
673   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-8.html#jls-8.4.5 Java Language Specification, section
674   * 8.4.5
675   */
676  public NoType noType(final TypeKind kind);
677
678  /**
679   * Returns a {@link NullType} implementation {@linkplain TypeMirror#getKind() whose <code>TypeKind</code>} is {@link
680   * TypeKind#NULL}.
681   *
682   * @return a non-{@code null} {@link NullType}
683   *
684   * @see javax.lang.model.util.Types#getNullType()
685   *
686   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-4.html#jls-4.1 Java Language Specification, section 4.1
687   */
688  public NullType nullType();
689
690  /**
691   * Returns a {@link PackageElement} representing the package bearing the supplied {@code canonicalName}, <strong>or
692   * {@code null} if there is no such {@link PackageElement}</strong>.
693   *
694   * @param canonicalName a canonical name suitable for naming a package; must not be {@code null}; may be {@linkplain
695   * CharSequence#isEmpty() empty}, in which case a {@link ModuleElement} representing an <dfn>unnamed package</dfn> will
696   * be returned
697   *
698   * @return a {@link PackageElement}, or {@code null}
699   *
700   * @exception NullPointerException if {@code canonicalName} is {@code null}
701   *
702   * @see javax.lang.model.util.Elements#getPackageElement(CharSequence)
703   *
704   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-6.html#jls-6.7 Java Language Specification, section
705   * 6.7
706   */
707  public PackageElement packageElement(final CharSequence canonicalName);
708
709  /**
710   * Returns a {@link PackageElement} representing the package bearing the supplied {@code canonicalName} as seen from
711   * the module represented by the supplied {@link ModuleElement}, <strong>or {@code null} if there is no such {@link
712   * PackageElement}</strong>.
713   *
714   * @param asSeenFrom a {@link ModuleElement}; must not be {@code null}
715   *
716   * @param canonicalName a canonical name suitable for naming a package; must not be {@code null}; may be {@linkplain
717   * CharSequence#isEmpty() empty}, in which case a {@link ModuleElement} representing an <dfn>unnamed package</dfn> will
718   * be returned
719   *
720   * @return a {@link PackageElement}, or {@code null}
721   *
722   * @exception NullPointerException if either {@code asSeenFrom} or {@code canonicalName} is {@code null}
723   *
724   * @see javax.lang.model.util.Elements#getPackageElement(ModuleElement, CharSequence)
725   *
726   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-6.html#jls-6.7 Java Language Specification, section
727   * 6.7
728   */
729  public PackageElement packageElement(final ModuleElement asSeenFrom, final CharSequence canonicalName);
730
731  /**
732   * A convenience method that returns {@code true} if and only if {@code t} is a {@link DeclaredType}, {@linkplain
733   * TypeMirror#getKind() has a <code>TypeKind</code>} of {@link TypeKind#DECLARED DECLARED}, and {@linkplain
734   * DeclaredType#getTypeArguments() has an empty type arguments list}.
735   *
736   * @param t a {@link TypeMirror}; must not be {@code null}
737   *
738   * @return {@code true} if and only if {@code t} is a {@link DeclaredType}, {@linkplain
739   * TypeMirror#getKind() has a <code>TypeKind</code>} of {@link TypeKind#DECLARED DECLARED}, and {@linkplain
740   * DeclaredType#getTypeArguments() has an empty type arguments list}; {@code false} otherwise
741   *
742   * @exception NullPointerException if {@code t} is {@code null}
743   */
744  public default boolean parameterized(final TypeMirror t) {
745    return switch (t) {
746    case null -> throw new NullPointerException("t");
747    case UniversalType ut -> ut.parameterized();
748    default -> {
749      try (var lock = this.lock()) {
750        yield t.getKind() == TypeKind.DECLARED && !((DeclaredType)t).getTypeArguments().isEmpty();
751      }
752    }
753    };
754  }
755
756  /**
757   * Returns the result of applying <dfn>unboxing conversion</dfn> to the (logical) {@link TypeElement} bearing the
758   * supplied {@code canonicalName}.
759   *
760   * @param canonicalName a canonical name of either a primitive type or a so-called "wrapper" type; must not be {@code
761   * null}
762   *
763   * @return a non-{@code null} {@link PrimitiveType} with a {@linkplain TypeKind#isPrimitive() primitive} {@link
764   * TypeKind}
765   *
766   * @exception NullPointerException if {@code canonicalName} is {@code null}
767   *
768   * @exception IllegalArgumentException if {@code canonicalName} {@linkplain #toString(CharSequence) converted to a
769   * <code>String</code>} {@linkplain String#equals(Object) is not equal to} {@code boolean}, {@code byte}, {@code
770   * char}, {@code double}, {@code float}, {@code int}, {@code long}, {@code short}, {@link Boolean java.lang.Boolean},
771   * {@link Byte java.lang.Byte}, {@link Character java.lang.Character}, {@link Double java.lang.Double}, {@link Float
772   * java.lang.Float}, {@link Integer java.lang.Integer}, {@link Long java.lang.Long}, or {@link Short java.lang.Short}
773   *
774   * @see #primitiveType(TypeKind)
775   *
776   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-5.html#jls-5.1.8 Java Language Specification, section
777   * 5.1.8
778   *
779   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-6.html#jls-6.7 Java Language Specification, section
780   * 6.7
781   */
782  // (Convenience.)
783  // (Unboxing.)
784  public default PrimitiveType primitiveType(final CharSequence canonicalName) {
785    final String s = this.toString(Objects.requireNonNull(canonicalName, "canonicalName"));
786    return switch (s) {
787    case "boolean", "java.lang.Boolean" -> this.primitiveType(TypeKind.BOOLEAN);
788    case "byte", "java.lang.Byte" -> this.primitiveType(TypeKind.BYTE);
789    case "char", "java.lang.Character" -> this.primitiveType(TypeKind.CHAR);
790    case "double", "java.lang.Double" -> this.primitiveType(TypeKind.DOUBLE);
791    case "float", "java.lang.Float" -> this.primitiveType(TypeKind.FLOAT);
792    case "int", "java.lang.Integer" -> this.primitiveType(TypeKind.INT);
793    case "long", "java.lang.Long" -> this.primitiveType(TypeKind.LONG);
794    case "short", "java.lang.Short" -> this.primitiveType(TypeKind.SHORT);
795    default -> throw new IllegalArgumentException("canonicalName: " + s);
796    };
797  }
798
799  /**
800   * Returns the result of applying <dfn>unboxing conversion</dfn> to the {@linkplain Element#asType() type declared by
801   * the supplied <code>TypeElement</code>}.
802   *
803   * @param e a {@link TypeElement}; must not be {@code null}
804   *
805   * @return a non-{@code null} {@link PrimitiveType} with a {@linkplain TypeKind#isPrimitive() primitive} {@link
806   * TypeKind}
807   *
808   * @exception NullPointerException if {@code e} is {@code null}
809   *
810   * @exception IllegalArgumentException if there is no unboxing conversion that can be applied to the {@linkplain
811   * Element#asType() type declared by <code>e</code>}
812   *
813   * @see javax.lang.model.util.Types#unboxedType(TypeMirror)
814   *
815   * @see #primitiveType(TypeMirror)
816   *
817   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-5.html#jls-5.1.8 Java Language Specification, section
818   * 5.1.8
819   */
820  // (Convenience.)
821  // (Unboxing.)
822  public default PrimitiveType primitiveType(final TypeElement e) {
823    return this.primitiveType(e.asType());
824  }
825
826  /**
827   * Returns the {@link PrimitiveType} corresponding to the supplied {@link TypeKind} (if it {@linkplain
828   * TypeKind#isPrimitive() is primitive}).
829   *
830   * @param kind a {@linkplain TypeKind#isPrimitive() primitive} {@link TypeKind}; must not be {@code null}
831   *
832   * @return a non-{@code null} {@link PrimitiveType} {@linkplain TypeMirror#getKind() with} a {@linkplain
833   * TypeKind#isPrimitive() primitive} {@link TypeKind}
834   *
835   * @exception NullPointerException if {@code kind} is {@code null}
836   *
837   * @exception IllegalArgumentException if {@code kind} {@linkplain TypeKind#isPrimitive() is not primitive}
838   *
839   * @see javax.lang.model.util.Types#getPrimitiveType(TypeKind)
840   *
841   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-4.html#jls-4.2 Java Language Specification, section
842   * 4.2
843   */
844  // (Canonical.)
845  public PrimitiveType primitiveType(final TypeKind kind);
846
847  /**
848   * Returns the result of applying <dfn>unboxing conversion</dfn> to the supplied {@link TypeMirror}.
849   *
850   * @param t a {@link TypeMirror}; must not be {@code null}
851   *
852   * @return a non-{@code null} {@link PrimitiveType} with a {@linkplain TypeKind#isPrimitive() primitive} {@link
853   * TypeKind}
854   *
855   * @exception NullPointerException if {@code t} is {@code null}
856   *
857   * @exception IllegalArgumentException if there is no unboxing conversion that can be applied to {@code t}
858   *
859   * @see javax.lang.model.util.Types#unboxedType(TypeMirror)
860   *
861   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-5.html#jls-5.1.8 Java Language Specification, section
862   * 5.1.8
863   */
864  // (Canonical.)
865  // (Unboxing.)
866  public PrimitiveType primitiveType(final TypeMirror t);
867
868  /**
869   * A convenience method that returns {@code true} if and only if the supplied {@link TypeMirror} is a <dfn>raw
870   * type</dfn> according to <a href="https://docs.oracle.com/javase/specs/jls/se23/html/jls-4.html#jls-4.8">the rules
871   * of the Java Language Specification</a>
872   *
873   * @param t a {@link TypeMirror}; must not be {@code null}
874   *
875   * @return {@code true} if and only if the supplied {@link TypeMirror} is a <dfn>raw type</dfn> according to <a
876   * href="https://docs.oracle.com/javase/specs/jls/se23/html/jls-4.html#jls-4.8">the rules of the Java Language
877   * Specification</a>
878   *
879   * @exception NullPointerException if {@code t} is {@code null}
880   *
881   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-4.html#jls-4.8 Java Language Specification, section 4.8
882   */
883  public default boolean raw(final TypeMirror t) {
884    return switch (t) {
885    case null -> throw new NullPointerException("t");
886    case UniversalType ut -> ut.raw();
887    default -> {
888      try (var lock = this.lock()) {
889        yield switch (t.getKind()) {
890        case ARRAY -> raw(elementType((ArrayType)t));
891        case DECLARED -> {
892          final DeclaredType dt = (DeclaredType)t;
893          yield generic(dt.asElement()) && dt.getTypeArguments().isEmpty();
894        }
895        default -> false;
896        };
897      }
898    }
899    };
900  }
901
902  /**
903   * A convenience method that returns the <dfn>raw type</dfn> corresponding to {@code t}, <strong>or {@code null} if
904   * {@code t} is <a href="https://docs.oracle.com/javase/specs/jls/se23/html/jls-4.html#jls-4.8">incapable of yielding
905   * a raw type</a></strong>.
906   *
907   * <p>Overrides of this method must conform to the requirements imposed by the relevant section of the relevant
908   * version of the Java Language Specification concerning raw types.</p>
909   *
910   * @param t a {@link TypeMirror}; must not be {@code null}
911   *
912   * @return the raw type corresponding to the supplied {@link TypeMirror}, or {@code null} if {@code t} is <a
913   * href="https://docs.oracle.com/javase/specs/jls/se23/html/jls-4.html#jls-4.8">incapable of yielding a raw type</a>
914   *
915   * @exception NullPointerException if {@code t} is {@code null}
916   *
917   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-4.html#jls-4.8 Java Language Specification, section
918   * 4.8
919   */
920  public default TypeMirror rawType(final TypeMirror t) {
921    return switch (t) {
922    case null -> throw new NullPointerException("t");
923    case UniversalType ut -> ut.rawType();
924    default -> {
925      try (var lock = this.lock()) {
926        yield switch (t.getKind()) {
927        case ARRAY -> this.rawType(this.elementType(t)); // recursive
928        default -> this.parameterized(t) ? this.erasure(t) : null;
929        };
930      }
931    }
932    };
933  }
934
935  /**
936   * Returns a {@link RecordComponentElement} corresponding to the supplied {@link ExecutableElement}, <strong>or {@code
937   * null} if there is no such {@link RecordComponentElement}</strong>.
938   *
939   * @param e an {@link ExecutableElement} {@linkplain ExecutableElement#getEnclosingElement() enclosed by} a record
940   * representing an <dfn>accessor method</dfn>; must not be {@code null}
941   *
942   * @return a {@link RecordComponentElement} corresponding to the supplied {@link ExecutableElement}, or {@code null}
943   *
944   * @exception NullPointerException if {@code e} is {@code null}
945   *
946   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-8.html#jls-8.10.3 Java Language Specification, section
947   * 8.10.3
948   */
949  public RecordComponentElement recordComponentElement(final ExecutableElement e);
950
951  /**
952   * Returns {@code true} if and only if the two arguments represent the <dfn>same type</dfn>.
953   *
954   * <p>This method differs from the {@link javax.lang.model.util.Types#isSameType(TypeMirror, TypeMirror)} method in
955   * two ways:</p>
956   *
957   * <ul>
958   *
959   * <li>Its arguments may be {@code null}. If both arguments are {@code null}, {@code true} is returned. If only one
960   * argument is {@code null}, {@code false} is returned.</li>
961   *
962   * <li>If the same Java object reference is passed as both arguments, {@code true} is returned (even if it {@linkplain
963   * TypeMirror#getKind() has a <code>TypeKind</code>} of {@link TypeKind#WILDCARD}).</li>
964   *
965   * </ul>
966   *
967   * @param t0 the first {@link TypeMirror}; may be {@code null}
968   *
969   * @param t1 the second {@link TypeMirror}; may be {@code null}
970   *
971   * @return {@code true} if and only if the two arguments represent the <dfn>same type</dfn>; {@code false} otherwise
972   *
973   * @see javax.lang.model.util.Types#isSameType(TypeMirror, TypeMirror)
974   *
975   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-4.html#jls-4.3.4 Java Language Specification, section
976   * 4.3.4
977   *
978   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-4.html#jls-4.5.1 Java Language Specification, section
979   * 4.5.1
980   */
981  public boolean sameType(final TypeMirror t0, final TypeMirror t1);
982
983  /**
984   * Returns {@code true} if and only if {@code et0} is a <dfn>subsignature</dfn> of {@code et1}.
985   *
986   * @param et0 the first {@link ExecutableType}; must not be {@code null}
987   *
988   * @param et1 the second {@link ExecutableType}; must not be {@code null}
989   *
990   * @return {@code true} if and only if {@code et0} is a <dfn>subsignature</dfn> of {@code et1}
991   *
992   * @exception NullPointerException if either argument is {@code null}
993   *
994   * @exception ClassCastException if this method is implemented in terms of the {@link
995   * javax.lang.model.util.Types#isSubsignature(ExecutableType, ExecutableType)} method, and if each of the supplied
996   * {@link ExecutableType} arguments does not have an {@linkplain TypeKind#EXECUTABLE <code>EXECUTABLE</code>
997   * <code>TypeKind</code>}; this exception type is undocumented by the {@link
998   * javax.lang.model.util.Types#isSubsignature(ExecutableType, ExecutableType)} method and so is subject to change
999   * without prior notice
1000   *
1001   * @see javax.lang.model.util.Types#isSubsignature(ExecutableType, ExecutableType)
1002   *
1003   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-8.html#jls-8.4.2 Java Language Specification, section
1004   * 8.4.2
1005   */
1006  public boolean subsignature(final ExecutableType et0, final ExecutableType et1);
1007
1008  /**
1009   * Returns {@code true} if and only if {@code candidateSubtype} is a <dfn>subtype</dfn> of {@code supertype}.
1010   *
1011   * @param candidateSubtype the first {@link TypeMirror}; must not be {@code null}
1012   *
1013   * @param supertype the second {@link TypeMirror}; must not be {@code null}
1014   *
1015   * @return {@code true} if and only if {@code candidateSubtype} is a <dfn>subtype</dfn> of {@code supertype}
1016   *
1017   * @exception NullPointerException if either argument is {@code null}
1018   *
1019   * @see javax.lang.model.util.Types#isSubtype(TypeMirror, TypeMirror)
1020   *
1021   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-4.html#jls-4.10 Java Language Specification, section
1022   * 4.10
1023   */
1024  public boolean subtype(TypeMirror candidateSubtype, TypeMirror supertype);
1025
1026  /**
1027   * Converts the supplied {@link CharSequence}, which is often a {@link Name}, into a {@link String}, and returns the
1028   * conversion, {@linkplain #lock() locking} when appropriate to serialize symbol completion.
1029   *
1030   * @param name the {@link CharSequence} to convert; may be {@code null} in which case {@code null} will be returned
1031   *
1032   * @return a {@link String}, or {@code null} if {@code name} was {@code null}
1033   *
1034   * @see #lock()
1035   */
1036  public default String toString(final CharSequence name) {
1037    return switch (name) {
1038    case null -> null;
1039    case String s -> s;
1040    case StringName sn -> sn.value();
1041    case Name n -> {
1042      try (var lock = this.lock()) {
1043        yield n.toString();
1044      }
1045    }
1046    default -> name.toString();
1047    };
1048  }
1049
1050  /**
1051   * Returns a {@link TypeElement} representing the element bearing the supplied <dfn>canonical name</dfn>, <strong>or
1052   * {@code null} if there is no such {@link TypeElement}</strong>.
1053   *
1054   * @param canonicalName a valid canonical name; must not be {@code null}
1055   *
1056   * @return a {@link TypeElement}, or {@code null}
1057   *
1058   * @exception NullPointerException if {@code canonicalName} is {@code null}
1059   *
1060   * @see javax.lang.model.util.Elements#getTypeElement(CharSequence)
1061   *
1062   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-6.html#jls-6.7 Java Language Specification, section
1063   * 6.7
1064   */
1065  public TypeElement typeElement(final CharSequence canonicalName);
1066
1067  /**
1068   * Returns a {@link TypeElement} representing the element bearing the supplied <dfn>canonical name</dfn>, as read or
1069   * seen from the module represented by the supplied {@link ModuleElement}, <strong>or {@code null} if there is no such
1070   * {@link TypeElement}</strong>.
1071   *
1072   * @param asSeenFrom a {@link ModuleElement}; must not be {@code null}
1073   *
1074   * @param canonicalName a valid canonical name; must not be {@code null}
1075   *
1076   * @return a {@link TypeElement}, or {@code null}
1077   *
1078   * @exception NullPointerException if either {@code asSeenFrom} or {@code canonicalName} is {@code null}
1079   *
1080   * @see javax.lang.model.util.Elements#getTypeElement(ModuleElement, CharSequence)
1081   *
1082   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-6.html#jls-6.7 Java Language Specification, section
1083   * 6.7
1084   */
1085  public TypeElement typeElement(final ModuleElement asSeenFrom, final CharSequence canonicalName);
1086
1087  /**
1088   * Returns a {@link TypeElement} representing the result of applying <dfn>boxing conversion</dfn> to the primitive
1089   * type represented by the supplied {@link PrimitiveType} argument.
1090   *
1091   * <p>The default implementation of this method calls the {@link #typeElement(TypeKind)} method with the supplied
1092   * {@link PrimitiveType}'s {@linkplain TypeMirror#getKind() affiliated <code>TypeKind</code>} and returns its
1093   * result.</p>
1094   *
1095   * @param t a {@link PrimitiveType} with a {@link TypeKind} that {@linkplain TypeKind#isPrimitive() is primitive};
1096   * must not be {@code null}
1097   *
1098   * @return a non-{@code null} {@link TypeElement} representing the result of applying boxing conversion to the
1099   * supplied argument
1100   *
1101   * @exception NullPointerException if {@code t} is {@code null}
1102   *
1103   * @exception ClassCastException if this method is implemented in terms of the {@link
1104   * javax.lang.model.util.Types#boxedClass(PrimitiveType)} method, and if the supplied {@link PrimitiveType} does not
1105   * have a {@linkplain TypeKind#isPrimitive() primitive <code>TypeKind</code>}; this exception type is undocumented by
1106   * the {@link javax.lang.model.util.Types#boxedClass(PrimitiveType)} method and so is subject to change without prior
1107   * notice
1108   *
1109   * @exception IllegalArgumentException if {@code primitiveTypeKind} {@linkplain TypeKind#isPrimitive() is not
1110   * primitive}
1111   *
1112   * @see #typeElement(TypeKind)
1113   *
1114   * @see javax.lang.model.util.Types#boxedClass(PrimitiveType)
1115   *
1116   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-5.html#jls-5.1.7 Java Language Specification, section
1117   * 5.1.7
1118   */
1119  // (Canonical.)
1120  // (Boxing.)
1121  public default TypeElement typeElement(final PrimitiveType t) {
1122    return switch (t) {
1123    case null -> throw new NullPointerException("t");
1124    case UniversalType ut -> this.typeElement(ut.getKind());
1125    default -> {
1126      try (var lock = this.lock()) {
1127        yield this.typeElement(t.getKind());
1128      }
1129    }
1130    };
1131  }
1132
1133  /**
1134   * Returns a {@link TypeElement} representing the result of applying <dfn>boxing conversion</dfn> to the primitive
1135   * type represented by the supplied {@link TypeKind} argument, if it {@linkplain TypeKind#isPrimitive() is primitive}.
1136   *
1137   * @param primitiveTypeKind a {@link TypeKind} that {@linkplain TypeKind#isPrimitive() is primitive}; must not be
1138   * {@code null}
1139   *
1140   * @return a non-{@code null} {@link TypeElement} representing the result of applying boxing conversion to the
1141   * supplied argument
1142   *
1143   * @exception IllegalArgumentException if {@code primitiveTypeKind} {@linkplain TypeKind#isPrimitive() is not
1144   * primitive}
1145   *
1146   * @see #typeElement(PrimitiveType)
1147   *
1148   * @see javax.lang.model.util.Types#boxedClass(PrimitiveType)
1149   *
1150   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-5.html#jls-5.1.7 Java Language Specification, section
1151   * 5.1.7
1152   */
1153  // (Convenience.)
1154  // (Boxing.)
1155  public default TypeElement typeElement(final TypeKind primitiveTypeKind) {
1156    return switch (primitiveTypeKind) {
1157    case BOOLEAN -> this.typeElement("java.lang.Boolean");
1158    case BYTE -> this.typeElement("java.lang.Byte");
1159    case CHAR -> this.typeElement("java.lang.Character");
1160    case DOUBLE -> this.typeElement("java.lang.Double");
1161    case FLOAT -> this.typeElement("java.lang.Float");
1162    case INT -> this.typeElement("java.lang.Integer");
1163    case LONG -> this.typeElement("java.lang.Long");
1164    case SHORT -> this.typeElement("java.lang.Short");
1165    default -> throw new IllegalArgumentException("primitiveTypeKind: " + primitiveTypeKind);
1166    };
1167  }
1168
1169  /**
1170   * Returns the {@link TypeParameterElement} {@linkplain Parameterizable#getTypeParameters() contained} by the supplied
1171   * {@link Parameterizable} whose {@linkplain TypeParameterElement#getSimpleName() name} {@linkplain
1172   * Name#contentEquals(CharSequence) is equal to} the supplied {@code name}, <strong>or {@code null} if there is no
1173   * such {@link TypeParameterElement}</strong>.
1174   *
1175   * @param p a {@link Parameterizable}; must not be {@code null}
1176   *
1177   * @param name a name valid for a type parameter; must not be {@code null}
1178   *
1179   * @return a {@link TypeParameterElement}, or {@code null}
1180   */
1181  public default TypeParameterElement typeParameterElement(Parameterizable p, final CharSequence name) {
1182    Objects.requireNonNull(p, "p");
1183    Objects.requireNonNull(name, "name");
1184    while (p != null) {
1185      switch (p) {
1186      case UniversalElement ue:
1187        for (final UniversalElement tpe : ue.getTypeParameters()) {
1188          if (tpe.getSimpleName().contentEquals(name)) {
1189            return tpe;
1190          }
1191        }
1192        p = ue.getEnclosingElement();
1193        break;
1194      default:
1195        try (var lock = this.lock()) {
1196          for (final TypeParameterElement tpe : p.getTypeParameters()) {
1197            if (tpe.getSimpleName().contentEquals(name)) {
1198              return tpe;
1199            }
1200          }
1201          p = (Parameterizable)((Element)p).getEnclosingElement();
1202        }
1203        break;
1204      }
1205    }
1206    return null;
1207  }
1208
1209  /**
1210   * A convenience method that returns the {@link TypeVariable} {@linkplain TypeParameterElement#asType() declared by}
1211   * the {@link TypeParameterElement} {@linkplain Parameterizable#getTypeParameters() contained} by the supplied {@link
1212   * Parameterizable} whose {@linkplain TypeParameterElement#getSimpleName() name} {@linkplain
1213   * Name#contentEquals(CharSequence) is equal to} the supplied {@code name}, <strong>or {@code null} if there is no
1214   * such {@link TypeParameterElement} or {@link TypeVariable}</strong>.
1215   *
1216   * @param p a {@link Parameterizable}; must not be {@code null}
1217   *
1218   * @param name a name valid for a type parameter; must not be {@code null}
1219   *
1220   * @return a {@link TypeVariable}, or {@code null}
1221   *
1222   * @see #typeParameterElement(Parameterizable, CharSequence)
1223   */
1224  public default TypeVariable typeVariable(Parameterizable p, final CharSequence name) {
1225    final TypeParameterElement e = this.typeParameterElement(p, name);
1226    return e == null ? null : (TypeVariable)e.asType();
1227  }
1228
1229  /**
1230   * A convenience method that returns the first {@link VariableElement} with a {@linkplain ElementKind#isVariable()
1231   * variable <code>ElementKind</code>} and {@linkplain Element#getSimpleName() bearing} the supplied {@code simpleName}
1232   * that the supplied {@code enclosingElement} {@linkplain Element#getEnclosedElements() encloses}, <strong>or {@code
1233   * null} if there is no such {@link VariableElement}</strong>.
1234   *
1235   * @param enclosingElement an {@link Element}; must not be {@code null}
1236   *
1237   * @param simpleName a {@link CharSequence}; must not be {@code null}
1238   *
1239   * @return a {@link VariableElement}, or {@code null}
1240   *
1241   * @exception NullPointerException if either argument is {@code null}
1242   *
1243   * @see Element#getEnclosedElements()
1244   *
1245   * @see ElementKind#isVariable()
1246   *
1247   * @see Element#getSimpleName()
1248   *
1249   * @see VariableElement
1250   */
1251  public default VariableElement variableElement(final Element enclosingElement, final CharSequence simpleName) {
1252    Objects.requireNonNull(simpleName, "simpleName");
1253    return switch (enclosingElement) {
1254    case null -> throw new NullPointerException("enclosingElement");
1255    case UniversalElement ue -> {
1256      for (final UniversalElement ee : ue.getEnclosedElements()) {
1257        if (ee.getKind().isVariable() && ee.getSimpleName().contentEquals(simpleName)) {
1258          yield ee;
1259        }
1260      }
1261      yield null;
1262    }
1263    default -> {
1264      try (var lock = lock()) {
1265        for (final Element ee : enclosingElement.getEnclosedElements()) {
1266          if (ee.getKind().isVariable() && ee.getSimpleName().contentEquals(simpleName)) {
1267            yield (VariableElement)ee;
1268          }
1269        }
1270      }
1271      yield null;
1272    }
1273    };
1274  }
1275
1276  /**
1277   * A convenience method that returns a new {@link WildcardType} {@linkplain TypeMirror#getKind() with a
1278   * <code>TypeKind</code>} of {@link TypeKind#WILDCARD}, an {@linkplain WildcardType#getExtendsBound() extends bound}
1279   * of {@code null}, and a {@linkplain WildcardType#getSuperBound() super bound} of {@code null}.
1280   *
1281   * @return a new, non-{@code null} {@link WildcardType}
1282   *
1283   * @see #wildcardType(TypeMirror, TypeMirror)
1284   *
1285   * @see javax.lang.model.util.Types#getWildcardType(TypeMirror, TypeMirror)
1286   *
1287   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-4.html#jls-4.5.1 Java Language Specification, section
1288   * 4.5.1
1289   */
1290  public default WildcardType wildcardType() {
1291    return this.wildcardType(null, null);
1292  }
1293
1294  /**
1295   * Returns a new {@link WildcardType} {@linkplain TypeMirror#getKind() with a <code>TypeKind</code>} of {@link
1296   * TypeKind#WILDCARD}, an {@linkplain WildcardType#getExtendsBound() extends bound} of the supplied {@code
1297   * extendsBound}, and a {@linkplain WildcardType#getSuperBound() super bound} of the supplied {@code superBound}.
1298   *
1299   * <p>Any argument may be {@code null}. Both arguments may not be non-{@code null}.</p>
1300   *
1301   * @param extendsBound the upper bound of the new {@link WildcardType}; may be {@code null}
1302   *
1303   * @param superBound the lower bound of the new {@link WildcardType}; may be {@code null}
1304   *
1305   * @return a new, non-{@code null} {@link WildcardType}
1306   *
1307   * @exception IllegalArgumentException if both arguments are non-{@code null} or otherwise unsuitable for being the
1308   * bounds of a {@link WildcardType}
1309   *
1310   * @see javax.lang.model.util.Types#getWildcardType(TypeMirror, TypeMirror)
1311   *
1312   * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-4.html#jls-4.5.1 Java Language Specification, section
1313   * 4.5.1
1314   */
1315  public WildcardType wildcardType(TypeMirror extendsBound, TypeMirror superBound);
1316
1317}