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