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