001/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*- 002 * 003 * Copyright © 2024 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.constant; 015 016import java.lang.constant.ClassDesc; 017import java.lang.constant.Constable; 018import java.lang.constant.ConstantDesc; 019import java.lang.constant.DynamicConstantDesc; 020import java.lang.constant.MethodHandleDesc; 021import java.lang.constant.MethodTypeDesc; 022 023import java.util.List; 024import java.util.Optional; 025 026import javax.lang.model.AnnotatedConstruct; 027 028import javax.lang.model.element.Element; 029import javax.lang.model.element.ExecutableElement; 030import javax.lang.model.element.ModuleElement; 031import javax.lang.model.element.PackageElement; 032import javax.lang.model.element.Name; 033import javax.lang.model.element.RecordComponentElement; 034import javax.lang.model.element.TypeElement; 035import javax.lang.model.element.TypeParameterElement; 036import javax.lang.model.element.VariableElement; 037 038import javax.lang.model.type.ArrayType; 039import javax.lang.model.type.DeclaredType; 040import javax.lang.model.type.NoType; 041import javax.lang.model.type.NullType; 042import javax.lang.model.type.PrimitiveType; 043import javax.lang.model.type.TypeKind; 044import javax.lang.model.type.TypeMirror; 045import javax.lang.model.type.TypeVariable; 046import javax.lang.model.type.WildcardType; 047 048import org.microbean.construct.Domain; 049 050import static java.lang.constant.ConstantDescs.BSM_INVOKE; 051import static java.lang.constant.ConstantDescs.NULL; 052 053import static java.lang.constant.DirectMethodHandleDesc.Kind.VIRTUAL; 054 055import static org.microbean.construct.constant.ConstantDescs.CD_ArrayType; 056import static org.microbean.construct.constant.ConstantDescs.CD_CharSequence; 057import static org.microbean.construct.constant.ConstantDescs.CD_DeclaredType; 058import static org.microbean.construct.constant.ConstantDescs.CD_Element; 059import static org.microbean.construct.constant.ConstantDescs.CD_ExecutableElement; 060import static org.microbean.construct.constant.ConstantDescs.CD_ModuleElement; 061import static org.microbean.construct.constant.ConstantDescs.CD_Name; 062import static org.microbean.construct.constant.ConstantDescs.CD_NoType; 063import static org.microbean.construct.constant.ConstantDescs.CD_NullType; 064import static org.microbean.construct.constant.ConstantDescs.CD_PackageElement; 065import static org.microbean.construct.constant.ConstantDescs.CD_Parameterizable; 066import static org.microbean.construct.constant.ConstantDescs.CD_PrimitiveType; 067import static org.microbean.construct.constant.ConstantDescs.CD_RecordComponentElement; 068import static org.microbean.construct.constant.ConstantDescs.CD_TypeElement; 069import static org.microbean.construct.constant.ConstantDescs.CD_TypeKind; 070import static org.microbean.construct.constant.ConstantDescs.CD_TypeParameterElement; 071import static org.microbean.construct.constant.ConstantDescs.CD_TypeMirror; 072import static org.microbean.construct.constant.ConstantDescs.CD_TypeVariable; 073import static org.microbean.construct.constant.ConstantDescs.CD_WildcardType; 074 075/** 076 * A utility class that returns nominal descriptors for constructs. 077 * 078 * @author <a href="https://about.me/lairdnelson" target="_top">Laird Nelson</a> 079 * 080 * @see #describe(Element, Domain) 081 * 082 * @see #describe(TypeMirror, Domain) 083 */ 084@SuppressWarnings("try") 085public final class Constables { 086 087 private Constables() { 088 super(); 089 } 090 091 /** 092 * Returns a nominal descriptor for the supplied argument, presuming it to have originated from the supplied {@link 093 * Domain}, or an {@linkplain Optional#empty() empty} {@link Optional} if the supplied argument cannot be described. 094 * 095 * @param n the argument; may be {@code null} 096 * 097 * @param d the {@link Domain} from which the argument originated; must not be {@code null} 098 * 099 * @return a non-{@code null} {@link Optional} 100 * 101 * @exception NullPointerException if {@code d} is {@code null} 102 */ 103 public static final Optional<? extends ConstantDesc> describe(final Name n, final Domain d) { 104 return switch (n) { 105 case null -> Optional.of(NULL); 106 case Constable c -> c.describeConstable(); 107 case ConstantDesc cd -> Optional.of(cd); // future proofing? 108 default -> (d instanceof Constable c ? c.describeConstable() : Optional.<ConstantDesc>empty()) 109 .map(domainDesc -> DynamicConstantDesc.of(BSM_INVOKE, 110 MethodHandleDesc.ofMethod(VIRTUAL, 111 ClassDesc.of(d.getClass().getName()), 112 "name", 113 MethodTypeDesc.of(CD_Name, 114 CD_CharSequence)), 115 domainDesc, 116 d.toString(n))); 117 }; 118 } 119 120 /** 121 * Returns a nominal descriptor for the supplied argument, presuming it to have originated from the supplied {@link 122 * Domain}, or an {@linkplain Optional#empty() empty} {@link Optional} if the supplied argument cannot be described. 123 * 124 * @param ac the argument; may be {@code null} 125 * 126 * @param d the {@link Domain} from which the argument originated; must not be {@code null} 127 * 128 * @return a non-{@code null} {@link Optional} 129 * 130 * @exception NullPointerException if {@code d} is {@code null} 131 */ 132 public static final Optional<? extends ConstantDesc> describe(final AnnotatedConstruct ac, final Domain d) { 133 return switch (ac) { 134 case null -> Optional.of(NULL); 135 case Constable c -> c.describeConstable(); 136 case ConstantDesc cd -> Optional.of(cd); // future proofing? 137 case Element e -> describe(e, d); 138 case TypeMirror t -> describe(t, d); 139 default -> Optional.empty(); 140 }; 141 } 142 143 /** 144 * Returns a nominal descriptor for the supplied argument, presuming it to have originated from the supplied {@link 145 * Domain}, or an {@linkplain Optional#empty() empty} {@link Optional} if the supplied argument cannot be described. 146 * 147 * @param e the argument; may be {@code null} 148 * 149 * @param d the {@link Domain} from which the argument originated; must not be {@code null} 150 * 151 * @return a non-{@code null} {@link Optional} 152 * 153 * @exception NullPointerException if {@code d} is {@code null} 154 */ 155 public static final Optional<? extends ConstantDesc> describe(final Element e, final Domain d) { 156 return switch (e) { 157 case null -> Optional.of(NULL); 158 case Constable c -> c.describeConstable(); 159 case ConstantDesc cd -> Optional.of(cd); // future proofing? 160 default -> { 161 try (var lock = d.lock()) { 162 yield switch (e.getKind()) { 163 case ANNOTATION_TYPE, CLASS, ENUM, INTERFACE, RECORD -> describe((TypeElement)e, d); 164 case BINDING_VARIABLE, EXCEPTION_PARAMETER, LOCAL_VARIABLE, OTHER, RESOURCE_VARIABLE -> 165 // No way to get these from javax.lang.model.Elements 166 Optional.empty(); 167 case CONSTRUCTOR, INSTANCE_INIT, METHOD, STATIC_INIT -> describe((ExecutableElement)e, d); 168 case ENUM_CONSTANT, FIELD, PARAMETER -> describe((VariableElement)e, d); 169 case MODULE -> describe((ModuleElement)e, d); 170 case PACKAGE -> describe((PackageElement)e, d); 171 case RECORD_COMPONENT -> describe((RecordComponentElement)e, d); 172 case TYPE_PARAMETER -> describe((TypeParameterElement)e, d); 173 }; 174 } 175 } 176 }; 177 } 178 179 /** 180 * Returns a nominal descriptor for the supplied argument, presuming it to have originated from the supplied {@link 181 * Domain}, or an {@linkplain Optional#empty() empty} {@link Optional} if the supplied argument cannot be described. 182 * 183 * @param e the argument; may be {@code null} 184 * 185 * @param d the {@link Domain} from which the argument originated; must not be {@code null} 186 * 187 * @return a non-{@code null} {@link Optional} 188 * 189 * @exception NullPointerException if {@code d} is {@code null} 190 */ 191 public static final Optional<? extends ConstantDesc> describe(final ExecutableElement e, final Domain d) { 192 return switch (e) { 193 case null -> Optional.of(NULL); 194 case Constable c -> c.describeConstable(); 195 case ConstantDesc cd -> Optional.of(cd); // future proofing? 196 default -> { 197 final ConstantDesc domainDesc = d instanceof Constable c ? c.describeConstable().orElse(null) : null; 198 if (domainDesc == null) { 199 yield Optional.empty(); 200 } 201 try (var lock = d.lock()) { 202 // Trying to do this via flatMap etc. simply will not work because type inference does not work properly, even 203 // with hints/coercion. Feel free to try again, but make sure you keep this implementation around to revert 204 // back to. 205 final List<? extends VariableElement> parameters = e.getParameters(); 206 final int parameterCount = parameters.size(); 207 final ConstantDesc[] args = new ConstantDesc[5 + parameterCount]; 208 args[0] = 209 MethodHandleDesc.ofMethod(VIRTUAL, 210 ClassDesc.of(d.getClass().getName()), 211 "executableElement", 212 MethodTypeDesc.of(CD_ExecutableElement, 213 CD_TypeElement, 214 CD_TypeMirror, 215 CD_CharSequence, 216 CD_TypeMirror.arrayType())); 217 args[1] = domainDesc; 218 args[2] = describe(e.getEnclosingElement(), d).orElse(null); 219 if (args[2] == null) { 220 yield Optional.empty(); 221 } 222 args[3] = describe(e.getReturnType(), d).orElse(null); 223 if (args[3] == null) { 224 yield Optional.empty(); 225 } 226 args[4] = describe(e.getSimpleName(), d).orElse(null); 227 if (args[4] == null) { 228 yield Optional.empty(); 229 } 230 for (int i = 0; i < parameterCount; i++) { 231 int index = i + 5; 232 args[index] = describe(parameters.get(i).asType(), d).orElse(null); 233 if (args[index] == null) { 234 yield Optional.empty(); 235 } 236 } 237 yield Optional.of(DynamicConstantDesc.of(BSM_INVOKE, args)); 238 } 239 } 240 }; 241 } 242 243 /** 244 * Returns a nominal descriptor for the supplied argument, presuming it to have originated from the supplied {@link 245 * Domain}, or an {@linkplain Optional#empty() empty} {@link Optional} if the supplied argument cannot be described. 246 * 247 * @param e the argument; may be {@code null} 248 * 249 * @param d the {@link Domain} from which the argument originated; must not be {@code null} 250 * 251 * @return a non-{@code null} {@link Optional} 252 * 253 * @exception NullPointerException if {@code d} is {@code null} 254 */ 255 public static final Optional<? extends ConstantDesc> describe(final ModuleElement e, final Domain d) { 256 return switch (e) { 257 case null -> Optional.of(NULL); 258 case Constable c -> c.describeConstable(); 259 case ConstantDesc cd -> Optional.of(cd); // future proofing? 260 default -> describe(e.getQualifiedName(), d) // getQualifiedName() does not cause symbol completion 261 .map(nameDesc -> DynamicConstantDesc.of(BSM_INVOKE, 262 MethodHandleDesc.ofMethod(VIRTUAL, 263 ClassDesc.of(d.getClass().getName()), 264 "moduleElement", 265 MethodTypeDesc.of(CD_ModuleElement, 266 CD_CharSequence)), 267 ((Constable)d).describeConstable().orElseThrow(), 268 nameDesc)); 269 }; 270 } 271 272 /** 273 * Returns a nominal descriptor for the supplied argument, presuming it to have originated from the supplied {@link 274 * Domain}, or an {@linkplain Optional#empty() empty} {@link Optional} if the supplied argument cannot be described. 275 * 276 * @param e the argument; may be {@code null} 277 * 278 * @param d the {@link Domain} from which the argument originated; must not be {@code null} 279 * 280 * @return a non-{@code null} {@link Optional} 281 * 282 * @exception NullPointerException if {@code d} is {@code null} 283 */ 284 public static final Optional<? extends ConstantDesc> describe(final PackageElement e, final Domain d) { 285 return switch (e) { 286 case null -> Optional.of(NULL); 287 case Constable c -> c.describeConstable(); 288 case ConstantDesc cd -> Optional.of(cd); // future proofing? 289 default -> describe(e.getQualifiedName(), d) // getQualifiedName() does not cause symbol completion 290 .map(nameDesc -> DynamicConstantDesc.of(BSM_INVOKE, 291 MethodHandleDesc.ofMethod(VIRTUAL, 292 ClassDesc.of(d.getClass().getName()), 293 "packageElement", 294 MethodTypeDesc.of(CD_PackageElement, 295 CD_CharSequence)), 296 ((Constable)d).describeConstable().orElseThrow(), 297 nameDesc)); 298 }; 299 } 300 301 /** 302 * Returns a nominal descriptor for the supplied argument, presuming it to have originated from the supplied {@link 303 * Domain}, or an {@linkplain Optional#empty() empty} {@link Optional} if the supplied argument cannot be described. 304 * 305 * @param e the argument; may be {@code null} 306 * 307 * @param d the {@link Domain} from which the argument originated; must not be {@code null} 308 * 309 * @return a non-{@code null} {@link Optional} 310 * 311 * @exception NullPointerException if {@code d} is {@code null} 312 */ 313 public static final Optional<? extends ConstantDesc> describe(final TypeElement e, final Domain d) { 314 return switch (e) { 315 case null -> Optional.of(NULL); 316 case Constable c -> c.describeConstable(); 317 case ConstantDesc cd -> Optional.of(cd); // future proofing? 318 default -> describe(e.getQualifiedName(), d) // getQualifiedName() does not cause symbol completion 319 .map(nameDesc -> DynamicConstantDesc.of(BSM_INVOKE, 320 MethodHandleDesc.ofMethod(VIRTUAL, 321 ClassDesc.of(d.getClass().getName()), 322 "typeElement", 323 MethodTypeDesc.of(CD_TypeElement, 324 CD_CharSequence)), 325 ((Constable)d).describeConstable().orElseThrow(), 326 nameDesc)); 327 }; 328 } 329 330 /** 331 * Returns a nominal descriptor for the supplied argument, presuming it to have originated from the supplied {@link 332 * Domain}, or an {@linkplain Optional#empty() empty} {@link Optional} if the supplied argument cannot be described. 333 * 334 * @param e the argument; may be {@code null} 335 * 336 * @param d the {@link Domain} from which the argument originated; must not be {@code null} 337 * 338 * @return a non-{@code null} {@link Optional} 339 * 340 * @exception NullPointerException if {@code d} is {@code null} 341 */ 342 public static final Optional<? extends ConstantDesc> describe(final TypeParameterElement e, final Domain d) { 343 return switch (e) { 344 case null -> Optional.of(NULL); 345 case Constable c -> c.describeConstable(); 346 case ConstantDesc cd -> Optional.of(cd); // future proofing? 347 default -> { 348 try (var lock = d.lock()) { 349 yield describe(e.getEnclosingElement(), d) 350 .flatMap(parameterizableDesc -> describe(e.getSimpleName(), d) 351 .map(nameDesc -> DynamicConstantDesc.of(BSM_INVOKE, 352 MethodHandleDesc.ofMethod(VIRTUAL, 353 ClassDesc.of(d.getClass().getName()), 354 "typeParameterElement", 355 MethodTypeDesc.of(CD_TypeParameterElement, 356 CD_Parameterizable, 357 CD_Name)), 358 ((Constable)d).describeConstable().orElseThrow(), 359 parameterizableDesc, 360 nameDesc))); 361 } 362 } 363 }; 364 } 365 366 /** 367 * Returns a nominal descriptor for the supplied argument, presuming it to have originated from the supplied {@link 368 * Domain}, or an {@linkplain Optional#empty() empty} {@link Optional} if the supplied argument cannot be described. 369 * 370 * @param e the argument; may be {@code null} 371 * 372 * @param d the {@link Domain} from which the argument originated; must not be {@code null} 373 * 374 * @return a non-{@code null} {@link Optional} 375 * 376 * @exception NullPointerException if {@code d} is {@code null} 377 */ 378 public static final Optional<? extends ConstantDesc> describe(final RecordComponentElement e, final Domain d) { 379 return switch (e) { 380 case null -> Optional.of(NULL); 381 case Constable c -> c.describeConstable(); 382 case ConstantDesc cd -> Optional.of(cd); // future proofing? 383 default -> { 384 try (var lock = d.lock()) { 385 yield describe((TypeElement)e.getEnclosingElement(), d) 386 .map(executableDesc -> DynamicConstantDesc.of(BSM_INVOKE, 387 MethodHandleDesc.ofMethod(VIRTUAL, 388 ClassDesc.of(d.getClass().getName()), 389 "recordComponentElement", 390 MethodTypeDesc.of(CD_RecordComponentElement, 391 CD_ExecutableElement)), 392 ((Constable)d).describeConstable().orElseThrow(), 393 executableDesc)); 394 } 395 } 396 }; 397 } 398 399 /** 400 * Returns a nominal descriptor for the supplied argument, presuming it to have originated from the supplied {@link 401 * Domain}, or an {@linkplain Optional#empty() empty} {@link Optional} if the supplied argument cannot be described. 402 * 403 * @param e the argument; may be {@code null} 404 * 405 * @param d the {@link Domain} from which the argument originated; must not be {@code null} 406 * 407 * @return a non-{@code null} {@link Optional} 408 * 409 * @exception NullPointerException if {@code d} is {@code null} 410 */ 411 public static final Optional<? extends ConstantDesc> describe(final VariableElement e, final Domain d) { 412 return switch (e) { 413 case null -> Optional.of(NULL); 414 case Constable c -> c.describeConstable(); 415 case ConstantDesc cd -> Optional.of(cd); // future proofing? 416 default -> { 417 try (var lock = d.lock()) { 418 yield describe(e.getSimpleName(), d) 419 .flatMap(nameDesc -> describe(e.getEnclosingElement(), d) 420 .map(enclosingElementDesc -> DynamicConstantDesc.of(BSM_INVOKE, 421 MethodHandleDesc.ofMethod(VIRTUAL, 422 ClassDesc.of(d.getClass().getName()), 423 "variableElement", 424 MethodTypeDesc.of(CD_Element, 425 CD_CharSequence)), 426 ((Constable)d).describeConstable().orElseThrow(), 427 nameDesc))); 428 } 429 } 430 }; 431 } 432 433 /** 434 * Returns a nominal descriptor for the supplied argument, presuming it to have originated from the supplied {@link 435 * Domain}, or an {@linkplain Optional#empty() empty} {@link Optional} if the supplied argument cannot be described. 436 * 437 * @param t the argument; may be {@code null} 438 * 439 * @param d the {@link Domain} from which the argument originated; must not be {@code null} 440 * 441 * @return a non-{@code null} {@link Optional} 442 * 443 * @exception NullPointerException if {@code d} is {@code null} 444 */ 445 public static final Optional<? extends ConstantDesc> describe(final TypeMirror t, final Domain d) { 446 return switch (t) { 447 case null -> Optional.of(NULL); 448 case Constable c -> c.describeConstable(); 449 case ConstantDesc cd -> Optional.of(cd); // future proofing? 450 default -> { 451 try (var lock = d.lock()) { 452 yield switch (t.getKind()) { 453 case ARRAY -> describe((ArrayType)t, d); 454 case BOOLEAN, BYTE, CHAR, DOUBLE, FLOAT, INT, LONG, SHORT -> describe((PrimitiveType)t, d); 455 case DECLARED -> describe((DeclaredType)t, d); 456 case EXECUTABLE, INTERSECTION, UNION -> Optional.empty(); // No way to get these from javax.lang.model.util.Types 457 case ERROR, OTHER -> Optional.empty(); 458 case MODULE, NONE, PACKAGE, VOID -> describe((NoType)t, d); 459 case NULL -> describe((NullType)t, d); 460 case TYPEVAR -> describe((TypeVariable)t, d); // Prefer working with TypeParameterElement instead 461 case WILDCARD -> describe((WildcardType)t, d); 462 }; 463 } 464 } 465 }; 466 } 467 468 /** 469 * Returns a nominal descriptor for the supplied argument, presuming it to have originated from the supplied {@link 470 * Domain}, or an {@linkplain Optional#empty() empty} {@link Optional} if the supplied argument cannot be described. 471 * 472 * @param t the argument; may be {@code null} 473 * 474 * @param d the {@link Domain} from which the argument originated; must not be {@code null} 475 * 476 * @return a non-{@code null} {@link Optional} 477 * 478 * @exception NullPointerException if {@code d} is {@code null} 479 */ 480 public static final Optional<? extends ConstantDesc> describe(final ArrayType t, final Domain d) { 481 return switch (t) { 482 case null -> Optional.of(NULL); 483 case Constable c -> c.describeConstable(); 484 case ConstantDesc cd -> Optional.of(cd); // future proofing? 485 default -> { 486 try (var lock = d.lock()) { 487 yield describe(t.getComponentType(), d) 488 .map(componentTypeDesc -> DynamicConstantDesc.of(BSM_INVOKE, 489 MethodHandleDesc.ofMethod(VIRTUAL, 490 ClassDesc.of(d.getClass().getName()), 491 "arrayTypeOf", 492 MethodTypeDesc.of(CD_ArrayType, 493 CD_TypeMirror)), 494 ((Constable)d).describeConstable().orElseThrow(), 495 componentTypeDesc)); 496 } 497 } 498 }; 499 } 500 501 /** 502 * Returns a nominal descriptor for the supplied argument, presuming it to have originated from the supplied {@link 503 * Domain}, or an {@linkplain Optional#empty() empty} {@link Optional} if the supplied argument cannot be described. 504 * 505 * @param t the argument; may be {@code null} 506 * 507 * @param d the {@link Domain} from which the argument originated; must not be {@code null} 508 * 509 * @return a non-{@code null} {@link Optional} 510 * 511 * @exception NullPointerException if {@code d} is {@code null} 512 */ 513 public static final Optional<? extends ConstantDesc> describe(final DeclaredType t, final Domain d) { 514 return switch (t) { 515 case null -> Optional.of(NULL); 516 case Constable c -> c.describeConstable(); 517 case ConstantDesc cd -> Optional.of(cd); // future proofing? 518 default -> { 519 final ConstantDesc domainDesc = d instanceof Constable constableDomain ? constableDomain.describeConstable().orElse(null) : null; 520 if (domainDesc == null) { 521 yield Optional.empty(); 522 } 523 try (var lock = d.lock()) { 524 yield switch (t.getKind()) { 525 case DECLARED -> { 526 final List<? extends TypeMirror> typeArguments = t.getTypeArguments(); 527 final int typeArgumentCount = typeArguments.size(); 528 final ConstantDesc[] args = new ConstantDesc[3 + typeArgumentCount]; 529 final TypeMirror enclosingType = t.getEnclosingType(); 530 args[0] = MethodHandleDesc.ofMethod(VIRTUAL, 531 ClassDesc.of(d.getClass().getName()), 532 "declaredType", 533 MethodTypeDesc.of(CD_DeclaredType, 534 CD_DeclaredType, 535 CD_TypeElement, 536 CD_TypeMirror.arrayType())); 537 args[1] = domainDesc; 538 args[2] = enclosingType.getKind() == TypeKind.NONE ? NULL : describe(enclosingType, d).orElse(null); 539 if (args[2] == null) { 540 yield Optional.empty(); 541 } 542 args[3] = describe((TypeElement)t.asElement(), d).orElse(null); 543 if (args[3] == null) { 544 yield Optional.empty(); 545 } 546 for (int i = 0; i < typeArgumentCount; i++) { 547 final int index = i + 3; 548 args[index] = describe(typeArguments.get(i), d).orElse(null); 549 if (args[index] == null) { 550 yield Optional.empty(); 551 } 552 } 553 yield Optional.of(DynamicConstantDesc.of(BSM_INVOKE, args)); 554 } 555 default -> Optional.empty(); // could be an error type 556 }; 557 } 558 } 559 }; 560 } 561 562 /** 563 * Returns a nominal descriptor for the supplied argument, presuming it to have originated from the supplied {@link 564 * Domain}, or an {@linkplain Optional#empty() empty} {@link Optional} if the supplied argument cannot be described. 565 * 566 * @param t the argument; may be {@code null} 567 * 568 * @param d the {@link Domain} from which the argument originated; must not be {@code null} 569 * 570 * @return a non-{@code null} {@link Optional} 571 * 572 * @exception NullPointerException if {@code d} is {@code null} 573 */ 574 public static final Optional<? extends ConstantDesc> describe(final NoType t, final Domain d) { 575 return switch (t) { 576 case null -> Optional.of(NULL); 577 case Constable c -> c.describeConstable(); 578 case ConstantDesc cd -> Optional.of(cd); // future proofing? 579 default -> { 580 final ConstantDesc domainDesc = d instanceof Constable c ? c.describeConstable().orElse(null) : null; 581 if (domainDesc == null) { 582 yield Optional.empty(); 583 } 584 try (var lock = d.lock()) { 585 yield t.getKind().describeConstable() 586 .map(typeKindDesc -> DynamicConstantDesc.of(BSM_INVOKE, 587 MethodHandleDesc.ofMethod(VIRTUAL, 588 ClassDesc.of(d.getClass().getName()), 589 "noType", 590 MethodTypeDesc.of(CD_NoType, 591 CD_TypeKind)), 592 domainDesc, 593 typeKindDesc)); 594 } 595 } 596 }; 597 } 598 599 /** 600 * Returns a nominal descriptor for the supplied argument, presuming it to have originated from the supplied {@link 601 * Domain}, or an {@linkplain Optional#empty() empty} {@link Optional} if the supplied argument cannot be described. 602 * 603 * @param t the argument; may be {@code null} 604 * 605 * @param d the {@link Domain} from which the argument originated; must not be {@code null} 606 * 607 * @return a non-{@code null} {@link Optional} 608 * 609 * @exception NullPointerException if {@code d} is {@code null} 610 */ 611 public static final Optional<? extends ConstantDesc> describe(final NullType t, final Domain d) { 612 return switch (t) { 613 case null -> Optional.of(NULL); 614 case Constable c -> c.describeConstable(); 615 case ConstantDesc cd -> Optional.of(cd); // future proofing? 616 default -> (d instanceof Constable c ? c.describeConstable() : Optional.<ConstantDesc>empty()) 617 .map(domainDesc -> DynamicConstantDesc.of(BSM_INVOKE, 618 MethodHandleDesc.ofMethod(VIRTUAL, 619 ClassDesc.of(d.getClass().getName()), 620 "nullType", 621 MethodTypeDesc.of(CD_NullType)), 622 domainDesc)); 623 }; 624 } 625 626 /** 627 * Returns a nominal descriptor for the supplied argument, presuming it to have originated from the supplied {@link 628 * Domain}, or an {@linkplain Optional#empty() empty} {@link Optional} if the supplied argument cannot be described. 629 * 630 * @param t the argument; may be {@code null} 631 * 632 * @param d the {@link Domain} from which the argument originated; must not be {@code null} 633 * 634 * @return a non-{@code null} {@link Optional} 635 * 636 * @exception NullPointerException if {@code d} is {@code null} 637 */ 638 public static final Optional<? extends ConstantDesc> describe(final PrimitiveType t, final Domain d) { 639 return switch (t) { 640 case null -> Optional.of(NULL); 641 case Constable c -> c.describeConstable(); 642 case ConstantDesc cd -> Optional.of(cd); // future proofing? 643 default -> { 644 final ConstantDesc domainDesc = d instanceof Constable constableDomain ? constableDomain.describeConstable().orElse(null) : null; 645 if (domainDesc == null) { 646 yield Optional.empty(); 647 } 648 try (var lock = d.lock()) { 649 yield t.getKind().describeConstable() 650 .map(typeKindDesc -> DynamicConstantDesc.of(BSM_INVOKE, 651 MethodHandleDesc.ofMethod(VIRTUAL, 652 ClassDesc.of(d.getClass().getName()), 653 "primitiveType", 654 MethodTypeDesc.of(CD_PrimitiveType, 655 CD_TypeKind)), 656 domainDesc, 657 typeKindDesc)); 658 } 659 } 660 }; 661 } 662 663 /** 664 * Returns a nominal descriptor for the supplied argument, presuming it to have originated from the supplied {@link 665 * Domain}, or an {@linkplain Optional#empty() empty} {@link Optional} if the supplied argument cannot be described. 666 * 667 * @param t the argument; may be {@code null} 668 * 669 * @param d the {@link Domain} from which the argument originated; must not be {@code null} 670 * 671 * @return a non-{@code null} {@link Optional} 672 * 673 * @exception NullPointerException if {@code d} is {@code null} 674 */ 675 public static final Optional<? extends ConstantDesc> describe(final TypeVariable t, final Domain d) { 676 return switch (t) { 677 case null -> Optional.of(NULL); 678 case Constable c -> c.describeConstable(); 679 case ConstantDesc cd -> Optional.of(cd); // future proofing? 680 default -> { 681 final ConstantDesc domainDesc = d instanceof Constable constableDomain ? constableDomain.describeConstable().orElse(null) : null; 682 if (domainDesc == null) { 683 yield Optional.empty(); 684 } 685 try (var lock = d.lock()) { 686 final TypeParameterElement e = (TypeParameterElement)t.asElement(); 687 final ConstantDesc parameterizableDesc = describe(e.getEnclosingElement(), d).orElse(null); 688 if (parameterizableDesc == null) { 689 yield Optional.empty(); 690 } 691 final String name = d.toString(e.getSimpleName()); 692 yield Optional.of(DynamicConstantDesc.of(BSM_INVOKE, 693 MethodHandleDesc.ofMethod(VIRTUAL, 694 ClassDesc.of(d.getClass().getName()), 695 "typeVariable", 696 MethodTypeDesc.of(CD_TypeVariable, 697 CD_Parameterizable, 698 CD_CharSequence)), 699 domainDesc, 700 parameterizableDesc, 701 name)); 702 } 703 } 704 }; 705 } 706 707 /** 708 * Returns a nominal descriptor for the supplied argument, presuming it to have originated from the supplied {@link 709 * Domain}, or an {@linkplain Optional#empty() empty} {@link Optional} if the supplied argument cannot be described. 710 * 711 * @param t the argument; may be {@code null} 712 * 713 * @param d the {@link Domain} from which the argument originated; must not be {@code null} 714 * 715 * @return a non-{@code null} {@link Optional} 716 * 717 * @exception NullPointerException if {@code d} is {@code null} 718 */ 719 public static final Optional<? extends ConstantDesc> describe(final WildcardType t, final Domain d) { 720 return switch (t) { 721 case null -> Optional.of(NULL); 722 case Constable c -> c.describeConstable(); 723 case ConstantDesc cd -> Optional.of(cd); // future proofing? 724 default -> { 725 try (var lock = d.lock()) { 726 yield describe(t.getExtendsBound(), d) 727 .flatMap(domainDesc -> describe(t.getExtendsBound(), d) 728 .flatMap(extendsBoundDesc -> describe(t.getSuperBound(), d) 729 .map(superBoundDesc -> DynamicConstantDesc.of(BSM_INVOKE, 730 MethodHandleDesc.ofMethod(VIRTUAL, 731 ClassDesc.of(d.getClass().getName()), 732 "wildcardType", 733 MethodTypeDesc.of(CD_WildcardType, 734 CD_TypeMirror, 735 CD_TypeMirror)), 736 737 domainDesc, 738 extendsBoundDesc, 739 superBoundDesc)))); 740 } 741 } 742 }; 743 } 744 745}