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