1 /* 2 * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.lang.reflect; 27 28 import jdk.internal.javac.PreviewFeature; 29 import jdk.internal.misc.PreviewFeatures; 30 31 import java.util.Collections; 32 import java.util.Objects; 33 import java.util.Map; 34 import java.util.Set; 35 import java.util.function.Function; 36 import static java.util.Map.entry; 37 38 /** 39 * Represents a JVM access or module-related flag on a runtime member, 40 * such as a {@linkplain Class class}, {@linkplain Field field}, or 41 * {@linkplain Executable method}. 42 * 43 * <P>JVM access and module-related flags are related to, but distinct 44 * from Java language {@linkplain Modifier modifiers}. Some modifiers 45 * and access flags have a one-to-one correspondence, such as {@code 46 * public}. In other cases, some language-level modifiers do 47 * <em>not</em> have an access flag, such as {@code sealed} (JVMS 48 * {@jvms 4.7.31}) and some access flags have no corresponding 49 * modifier, such as {@linkplain #SYNTHETIC synthetic}. 50 * 51 * <p>The values for the constants representing the access and module 52 * flags are taken from sections of <cite>The Java Virtual Machine 53 * Specification</cite> including {@jvms 4.1} (class access and 54 * property modifiers), {@jvms 4.5} (field access and property flags), 55 * {@jvms 4.6} (method access and property flags), {@jvms 4.7.6} 56 * (nested class access and property flags), {@jvms 4.7.24} (method 57 * parameters), and {@jvms 4.7.25} (module flags and requires, 58 * exports, and opens flags). 59 * 60 * <p>The {@linkplain #mask() mask} values for the different access 61 * flags are <em>not</em> distinct. Flags are defined for different 62 * kinds of JVM structures and the same bit position has different 63 * meanings in different contexts. For example, {@code 0x0000_0040} 64 * indicates a {@link #VOLATILE volatile} field but a {@linkplain 65 * #BRIDGE bridge method}; {@code 0x0000_0080} indicates a {@link 66 * #TRANSIENT transient} field but a {@linkplain #VARARGS variable 67 * arity (varargs)} method. 68 * 69 * @implSpec 70 * The access flag constants are ordered by non-decreasing mask 71 * value; that is the mask value of a constant is greater than or 72 * equal to the mask value of an immediate neighbor to its (syntactic) 73 * left. If new constants are added, this property will be 74 * maintained. That implies new constants will not necessarily be 75 * added at the end of the existing list. 76 * 77 * @apiNote 78 * The JVM class file format has a {@linkplain ClassFileFormatVersion new version} defined for each new 79 * {@linkplain Runtime.Version#feature() feature release}. A new class 80 * file version may define new access flags or retire old ones. {@code 81 * AccessFlag} is intended to model the set of access flags across 82 * class file format versions. The range of versions an access flag is 83 * recognized is not explicitly indicated in this API. See the current 84 * <cite>The Java Virtual Machine Specification</cite> for 85 * details. Unless otherwise indicated, access flags can be assumed to 86 * be recognized in the {@linkplain Runtime#version() current 87 * version}. 88 * 89 * @see java.lang.reflect.Modifier 90 * @see java.lang.module.ModuleDescriptor.Modifier 91 * @see java.lang.module.ModuleDescriptor.Requires.Modifier 92 * @see java.lang.module.ModuleDescriptor.Exports.Modifier 93 * @see java.lang.module.ModuleDescriptor.Opens.Modifier 94 * @see java.compiler/javax.lang.model.element.Modifier 95 * @since 20 96 */ 97 @SuppressWarnings("doclint:reference") // cross-module link 98 public enum AccessFlag { 99 // Note to maintainers: anonymous class instances are used rather 100 // than lambdas to initialize the functions used for the 101 // cffvToLocations field to avoid using lambdas too early in JDK 102 // initialization. 103 104 /** 105 * The access flag {@code ACC_PUBLIC}, corresponding to the source 106 * modifier {@link Modifier#PUBLIC public}, with a mask value of 107 * <code>{@value "0x%04x" Modifier#PUBLIC}</code>. 108 */ 109 PUBLIC(Modifier.PUBLIC, true, 110 Location.SET_PUBLIC_1, 111 new Function<ClassFileFormatVersion, Set<Location>>() { 112 @Override 113 public Set<Location> apply(ClassFileFormatVersion cffv) { 114 return (cffv == ClassFileFormatVersion.RELEASE_0) ? 115 Location.SET_CLASS_FIELD_METHOD: 116 Location.SET_PUBLIC_1; 117 } 118 }), 119 120 /** 121 * The access flag {@code ACC_PRIVATE}, corresponding to the 122 * source modifier {@link Modifier#PRIVATE private}, with a mask 123 * value of <code>{@value "0x%04x" Modifier#PRIVATE}</code>. 124 */ 125 PRIVATE(Modifier.PRIVATE, true, Location.SET_FIELD_METHOD_INNER_CLASS, 126 new Function<ClassFileFormatVersion, Set<Location>>() { 127 @Override 128 public Set<Location> apply(ClassFileFormatVersion cffv) { 129 return (cffv == ClassFileFormatVersion.RELEASE_0) ? 130 Location.SET_FIELD_METHOD: 131 Location.SET_FIELD_METHOD_INNER_CLASS; 132 } 133 }), 134 135 /** 136 * The access flag {@code ACC_PROTECTED}, corresponding to the 137 * source modifier {@link Modifier#PROTECTED protected}, with a mask 138 * value of <code>{@value "0x%04x" Modifier#PROTECTED}</code>. 139 */ 140 PROTECTED(Modifier.PROTECTED, true, Location.SET_FIELD_METHOD_INNER_CLASS, 141 new Function<ClassFileFormatVersion, Set<Location>>() { 142 @Override 143 public Set<Location> apply(ClassFileFormatVersion cffv) { 144 return (cffv == ClassFileFormatVersion.RELEASE_0) ? 145 Location.SET_FIELD_METHOD: 146 Location.SET_FIELD_METHOD_INNER_CLASS; 147 } 148 }), 149 150 /** 151 * The access flag {@code ACC_STATIC}, corresponding to the source 152 * modifier {@link Modifier#STATIC static}, with a mask value of 153 * <code>{@value "0x%04x" Modifier#STATIC}</code>. 154 */ 155 STATIC(Modifier.STATIC, true, Location.SET_FIELD_METHOD_INNER_CLASS, 156 new Function<ClassFileFormatVersion, Set<Location>>() { 157 @Override 158 public Set<Location> apply(ClassFileFormatVersion cffv) { 159 return (cffv == ClassFileFormatVersion.RELEASE_0) ? 160 Location.SET_FIELD_METHOD: 161 Location.SET_FIELD_METHOD_INNER_CLASS;} 162 }), 163 164 /** 165 * The access flag {@code ACC_FINAL}, corresponding to the source 166 * modifier {@link Modifier#FINAL final}, with a mask 167 * value of <code>{@value "0x%04x" Modifier#FINAL}</code>. 168 */ 169 FINAL(Modifier.FINAL, true, 170 Location.SET_FINAL_8, 171 new Function<ClassFileFormatVersion, Set<Location>>() { 172 @Override 173 public Set<Location> apply(ClassFileFormatVersion cffv) { 174 if (cffv.compareTo(ClassFileFormatVersion.RELEASE_8) >= 0) { 175 return Location.SET_FINAL_8; 176 } else { 177 return (cffv == ClassFileFormatVersion.RELEASE_0) ? 178 Location.SET_CLASS_FIELD_METHOD : 179 Location.SET_CLASS_FIELD_METHOD_INNER_CLASS; 180 } 181 } 182 }), 183 184 /** 185 * The access flag {@code ACC_SUPER} with a mask value of {@code 186 * 0x0020}. 187 * 188 * @apiNote 189 * In Java SE 8 and above, the JVM treats the {@code ACC_SUPER} 190 * flag as set in every class file (JVMS {@jvms 4.1}). 191 * If preview feature is enabled, 192 * the {@code 0x0020} access flag bit is {@linkplain #IDENTITY IDENTITY access flag}. 193 */ 194 SUPER(0x0000_0020, false, 195 PreviewFeatures.isEnabled() ? Location.EMPTY_SET : Location.SET_CLASS, 196 new Function<ClassFileFormatVersion, Set<Location>>() { 197 @Override 198 public Set<Location> apply(ClassFileFormatVersion cffv) { 199 return (cffv.compareTo(ClassFileFormatVersion.RELEASE_22) >= 0) && 200 PreviewFeatures.isEnabled() ? Location.EMPTY_SET : Location.SET_CLASS; 201 } 202 }), 203 204 /** 205 * The access flag {@code ACC_IDENTITY}, corresponding to the 206 * source modifier {@link Modifier#IDENTITY identity}, with a mask 207 * value of <code>{@value "0x%04x" Modifier#IDENTITY}</code>. 208 * @jvms 4.1 -B. Class access and property modifiers 209 */ 210 @PreviewFeature(feature = PreviewFeature.Feature.VALUE_OBJECTS) 211 IDENTITY(Modifier.IDENTITY, false, 212 PreviewFeatures.isEnabled() ? Location.SET_CLASS_INNER_CLASS : Location.EMPTY_SET, 213 new Function<ClassFileFormatVersion, Set<Location>>() { 214 @Override 215 public Set<Location> apply(ClassFileFormatVersion cffv) { 216 return (cffv.compareTo(ClassFileFormatVersion.RELEASE_22) >= 0 217 && PreviewFeatures.isEnabled()) 218 ? Location.SET_CLASS_INNER_CLASS : Location.EMPTY_SET; 219 } 220 }), 221 222 /** 223 * The module flag {@code ACC_OPEN} with a mask value of {@code 224 * 0x0020}. 225 * @see java.lang.module.ModuleDescriptor#isOpen 226 */ 227 OPEN(0x0000_0020, false, Location.SET_MODULE, 228 new Function<ClassFileFormatVersion, Set<Location>>() { 229 @Override 230 public Set<Location> apply(ClassFileFormatVersion cffv) { 231 return (cffv.compareTo(ClassFileFormatVersion.RELEASE_9) >= 0 ) ? 232 Location.SET_MODULE: 233 Location.EMPTY_SET;} 234 }), 235 236 /** 237 * The module requires flag {@code ACC_TRANSITIVE} with a mask 238 * value of {@code 0x0020}. 239 * @see java.lang.module.ModuleDescriptor.Requires.Modifier#TRANSITIVE 240 */ 241 TRANSITIVE(0x0000_0020, false, Location.SET_MODULE_REQUIRES, 242 new Function<ClassFileFormatVersion, Set<Location>>() { 243 @Override 244 public Set<Location> apply(ClassFileFormatVersion cffv) { 245 return (cffv.compareTo(ClassFileFormatVersion.RELEASE_9) >= 0 ) ? 246 Location.SET_MODULE_REQUIRES: 247 Location.EMPTY_SET;} 248 }), 249 250 /** 251 * The access flag {@code ACC_SYNCHRONIZED}, corresponding to the 252 * source modifier {@link Modifier#SYNCHRONIZED synchronized}, with 253 * a mask value of <code>{@value "0x%04x" Modifier#SYNCHRONIZED}</code>. 254 */ 255 SYNCHRONIZED(Modifier.SYNCHRONIZED, true, Location.SET_METHOD, null), 256 257 /** 258 * The module requires flag {@code ACC_STATIC_PHASE} with a mask 259 * value of {@code 0x0040}. 260 * @see java.lang.module.ModuleDescriptor.Requires.Modifier#STATIC 261 */ 262 STATIC_PHASE(0x0000_0040, false, Location.SET_MODULE_REQUIRES, 263 new Function<ClassFileFormatVersion, Set<Location>>() { 264 @Override 265 public Set<Location> apply(ClassFileFormatVersion cffv) { 266 return (cffv.compareTo(ClassFileFormatVersion.RELEASE_9) >= 0 ) ? 267 Location.SET_MODULE_REQUIRES: 268 Location.EMPTY_SET;} 269 }), 270 271 /** 272 * The access flag {@code ACC_VOLATILE}, corresponding to the 273 * source modifier {@link Modifier#VOLATILE volatile}, with a mask 274 * value of <code>{@value "0x%04x" Modifier#VOLATILE}</code>. 275 */ 276 VOLATILE(Modifier.VOLATILE, true, Location.SET_FIELD, null), 277 278 /** 279 * The access flag {@code ACC_BRIDGE} with a mask value of 280 * <code>{@value "0x%04x" Modifier#BRIDGE}</code> 281 * @see Method#isBridge() 282 */ 283 BRIDGE(Modifier.BRIDGE, false, Location.SET_METHOD, 284 new Function<ClassFileFormatVersion, Set<Location>>() { 285 @Override 286 public Set<Location> apply(ClassFileFormatVersion cffv) { 287 return (cffv.compareTo(ClassFileFormatVersion.RELEASE_5) >= 0 ) ? 288 Location.SET_METHOD: 289 Location.EMPTY_SET;} 290 }), 291 292 /** 293 * The access flag {@code ACC_TRANSIENT}, corresponding to the 294 * source modifier {@link Modifier#TRANSIENT transient}, with a 295 * mask value of <code>{@value "0x%04x" Modifier#TRANSIENT}</code>. 296 */ 297 TRANSIENT(Modifier.TRANSIENT, true, Location.SET_FIELD, null), 298 299 /** 300 * The access flag {@code ACC_VARARGS} with a mask value of 301 <code>{@value "0x%04x" Modifier#VARARGS}</code>. 302 * @see Executable#isVarArgs() 303 */ 304 VARARGS(Modifier.VARARGS, false, Location.SET_METHOD, 305 new Function<ClassFileFormatVersion, Set<Location>>() { 306 @Override 307 public Set<Location> apply(ClassFileFormatVersion cffv) { 308 return (cffv.compareTo(ClassFileFormatVersion.RELEASE_5) >= 0 ) ? 309 Location.SET_METHOD: 310 Location.EMPTY_SET;} 311 }), 312 313 /** 314 * The access flag {@code ACC_NATIVE}, corresponding to the source 315 * modifier {@link Modifier#NATIVE native}, with a mask value of 316 * <code>{@value "0x%04x" Modifier#NATIVE}</code>. 317 */ 318 NATIVE(Modifier.NATIVE, true, Location.SET_METHOD, null), 319 320 /** 321 * The access flag {@code ACC_INTERFACE} with a mask value of 322 * {@code 0x0200}. 323 * @see Class#isInterface() 324 */ 325 INTERFACE(Modifier.INTERFACE, false, Location.SET_CLASS_INNER_CLASS, 326 new Function<ClassFileFormatVersion, Set<Location>>() { 327 @Override 328 public Set<Location> apply(ClassFileFormatVersion cffv) { 329 return (cffv.compareTo(ClassFileFormatVersion.RELEASE_0) == 0 ) ? 330 Location.SET_CLASS: 331 Location.SET_CLASS_INNER_CLASS;} 332 }), 333 334 /** 335 * The access flag {@code ACC_ABSTRACT}, corresponding to the 336 * source modifier {@link Modifier#ABSTRACT abstract}, with a mask 337 * value of <code>{@value "0x%04x" Modifier#ABSTRACT}</code>. 338 */ 339 ABSTRACT(Modifier.ABSTRACT, true, 340 Location.SET_CLASS_METHOD_INNER_CLASS, 341 new Function<ClassFileFormatVersion, Set<Location>>() { 342 @Override 343 public Set<Location> apply(ClassFileFormatVersion cffv) { 344 return (cffv.compareTo(ClassFileFormatVersion.RELEASE_0) == 0 ) ? 345 Location.SET_CLASS_METHOD: 346 Location.SET_CLASS_METHOD_INNER_CLASS;} 347 }), 348 349 /** 350 * The access flag {@code ACC_STRICT}, corresponding to the source 351 * modifier {@link Modifier#STRICT strictfp}, with a mask value of 352 * <code>{@value "0x%04x" Modifier#STRICT}</code>. 353 * 354 * @apiNote 355 * The {@code ACC_STRICT} access flag is defined for class file 356 * major versions 46 through 60, inclusive (JVMS {@jvms 4.6}), 357 * corresponding to Java SE 1.2 through 16. 358 */ 359 STRICT(Modifier.STRICT, true, Location.EMPTY_SET, 360 new Function<ClassFileFormatVersion, Set<Location>>() { 361 @Override 362 public Set<Location> apply(ClassFileFormatVersion cffv) { 363 return (cffv.compareTo(ClassFileFormatVersion.RELEASE_2) >= 0 && 364 cffv.compareTo(ClassFileFormatVersion.RELEASE_16) <= 0) ? 365 Location.SET_METHOD: 366 Location.EMPTY_SET;} 367 }), 368 369 /** 370 * The access flag {@code ACC_SYNTHETIC} with a mask value of 371 * <code>{@value "0x%04x" Modifier#SYNTHETIC}</code>. 372 * @see Class#isSynthetic() 373 * @see Executable#isSynthetic() 374 * @see java.lang.module.ModuleDescriptor.Modifier#SYNTHETIC 375 */ 376 SYNTHETIC(Modifier.SYNTHETIC, false, Location.SET_SYNTHETIC_9, 377 new Function<ClassFileFormatVersion, Set<Location>>() { 378 @Override 379 public Set<Location> apply(ClassFileFormatVersion cffv) { 380 if (cffv.compareTo(ClassFileFormatVersion.RELEASE_9) >= 0 ) 381 return Location.SET_SYNTHETIC_9; 382 else { 383 return 384 switch(cffv) { 385 case RELEASE_7 -> Location.SET_SYNTHETIC_7; 386 case RELEASE_8 -> Location.SET_SYNTHETIC_8; 387 default -> Location.EMPTY_SET; 388 }; 389 } 390 } 391 }), 392 393 /** 394 * The access flag {@code ACC_ANNOTATION} with a mask value of 395 * <code>{@value "0x%04x" Modifier#ANNOTATION}</code>. 396 * @see Class#isAnnotation() 397 */ 398 ANNOTATION(Modifier.ANNOTATION, false, Location.SET_CLASS_INNER_CLASS, 399 new Function<ClassFileFormatVersion, Set<Location>>() { 400 @Override 401 public Set<Location> apply(ClassFileFormatVersion cffv) { 402 return (cffv.compareTo(ClassFileFormatVersion.RELEASE_5) >= 0 ) ? 403 Location.SET_CLASS_INNER_CLASS: 404 Location.EMPTY_SET;} 405 }), 406 407 /** 408 * The access flag {@code ACC_ENUM} with a mask value of 409 * <code>{@value "0x%04x" Modifier#ENUM}</code>. 410 * @see Class#isEnum() 411 */ 412 ENUM(Modifier.ENUM, false, Location.SET_CLASS_FIELD_INNER_CLASS, 413 new Function<ClassFileFormatVersion, Set<Location>>() { 414 @Override 415 public Set<Location> apply(ClassFileFormatVersion cffv) { 416 return (cffv.compareTo(ClassFileFormatVersion.RELEASE_5) >= 0 ) ? 417 Location.SET_CLASS_FIELD_INNER_CLASS: 418 Location.EMPTY_SET;} 419 }), 420 421 /** 422 * The access flag {@code ACC_MANDATED} with a mask value of 423 * <code>{@value "0x%04x" Modifier#MANDATED}</code>. 424 */ 425 MANDATED(Modifier.MANDATED, false, Location.SET_MANDATED_9, 426 new Function<ClassFileFormatVersion, Set<Location>>() { 427 @Override 428 public Set<Location> apply(ClassFileFormatVersion cffv) { 429 if (cffv.compareTo(ClassFileFormatVersion.RELEASE_9) >= 0 ) { 430 return Location.SET_MANDATED_9; 431 } else { 432 return (cffv == ClassFileFormatVersion.RELEASE_8) ? 433 Location.SET_METHOD_PARAM: 434 Location.EMPTY_SET; 435 } 436 } 437 }), 438 439 /** 440 * The access flag {@code ACC_MODULE} with a mask value of {@code 441 * 0x8000}. 442 */ 443 MODULE(0x0000_8000, false, Location.SET_CLASS, 444 new Function<ClassFileFormatVersion, Set<Location>>() { 445 @Override 446 public Set<Location> apply(ClassFileFormatVersion cffv) { 447 return (cffv.compareTo(ClassFileFormatVersion.RELEASE_9) >= 0 ) ? 448 Location.SET_CLASS: 449 Location.EMPTY_SET;} 450 }) 451 ; 452 453 // May want to override toString for a different enum constant -> 454 // name mapping. 455 456 private final int mask; 457 private final boolean sourceModifier; 458 459 // Intentionally using Set rather than EnumSet since EnumSet is 460 // mutable. 461 private final Set<Location> locations; 462 // Lambda to implement locations(ClassFileFormatVersion cffv) 463 private final Function<ClassFileFormatVersion, Set<Location>> cffvToLocations; 464 465 private AccessFlag(int mask, 466 boolean sourceModifier, 467 Set<Location> locations, 468 Function<ClassFileFormatVersion, Set<Location>> cffvToLocations) { 469 this.mask = mask; 470 this.sourceModifier = sourceModifier; 471 this.locations = locations; 472 this.cffvToLocations = cffvToLocations; 473 } 474 475 /** 476 * {@return the corresponding integer mask for the access flag} 477 */ 478 public int mask() { 479 return mask; 480 } 481 482 /** 483 * {@return whether or not the flag has a directly corresponding 484 * modifier in the Java programming language} 485 */ 486 public boolean sourceModifier() { 487 return sourceModifier; 488 } 489 490 /** 491 * {@return kinds of constructs the flag can be applied to in the 492 * latest class file format version} 493 */ 494 public Set<Location> locations() { 495 return locations; 496 } 497 498 /** 499 * {@return kinds of constructs the flag can be applied to in the 500 * given class file format version} 501 * @param cffv the class file format version to use 502 * @throws NullPointerException if the parameter is {@code null} 503 */ 504 public Set<Location> locations(ClassFileFormatVersion cffv) { 505 Objects.requireNonNull(cffv); 506 if (cffvToLocations == null) { 507 return locations; 508 } else { 509 return cffvToLocations.apply(cffv); 510 } 511 } 512 513 /** 514 * {@return an unmodifiable set of access flags for the given mask value 515 * appropriate for the location in question} 516 * 517 * @param mask bit mask of access flags 518 * @param location context to interpret mask value 519 * @throws IllegalArgumentException if the mask contains bit 520 * positions not supported for the location in question 521 */ 522 public static Set<AccessFlag> maskToAccessFlags(int mask, Location location) { 523 Set<AccessFlag> result = java.util.EnumSet.noneOf(AccessFlag.class); 524 for (var accessFlag : LocationToFlags.locationToFlags.get(location)) { 525 int accessMask = accessFlag.mask(); 526 if ((mask & accessMask) != 0) { 527 result.add(accessFlag); 528 mask = mask & ~accessMask; 529 if (mask == 0) { 530 break; // no more mask bits 531 } 532 } 533 } 534 if (mask != 0) { 535 throw new IllegalArgumentException("Unmatched bit position 0x" + 536 Integer.toHexString(mask) + 537 " for location " + location); 538 } 539 return Collections.unmodifiableSet(result); 540 } 541 542 /** 543 * {@return an unmodifiable set of access flags for the given mask value 544 * appropriate for the location in question} 545 * 546 * @param mask bit mask of access flags 547 * @param location context to interpret mask value 548 * @param cffv the class file format version 549 * @throws IllegalArgumentException if the mask contains bit 550 * positions not supported for the location in question 551 */ 552 public static Set<AccessFlag> maskToAccessFlags(int mask, Location location, 553 ClassFileFormatVersion cffv) { 554 Set<AccessFlag> result = java.util.EnumSet.noneOf(AccessFlag.class); 555 for (var accessFlag : AccessFlag.values()) { 556 int accessMask = accessFlag.mask(); 557 if ((mask & accessMask) != 0) { 558 var locations = accessFlag.locations(cffv); 559 if (locations.contains(location)) { 560 result.add(accessFlag); 561 mask = mask & ~accessMask; 562 if (mask == 0) { 563 break; // no more mask bits 564 } 565 } 566 } 567 } 568 if (mask != 0) { 569 throw new IllegalArgumentException("Unmatched bit position 0x" + 570 Integer.toHexString(mask) + 571 " for location " + location + 572 " for class file format version " + cffv); 573 } 574 return Collections.unmodifiableSet(result); 575 } 576 577 578 /** 579 * A location within a class file where flags can be applied. 580 * 581 * Note that since these locations represent class file structures 582 * rather than language structures many language structures, such 583 * as constructors and interfaces, are <em>not</em> present. 584 * @since 20 585 */ 586 public enum Location { 587 /** 588 * Class location. 589 * @jvms 4.1 The ClassFile Structure 590 */ 591 CLASS, 592 593 /** 594 * Field location. 595 * @jvms 4.5 Fields 596 */ 597 FIELD, 598 599 /** 600 * Method location. 601 * @jvms 4.6 Method 602 */ 603 METHOD, 604 605 /** 606 * Inner class location. 607 * @jvms 4.7.6 The InnerClasses Attribute 608 */ 609 INNER_CLASS, 610 611 /** 612 * Method parameter location. 613 * @jvms 4.7.24. The MethodParameters Attribute 614 */ 615 METHOD_PARAMETER, 616 617 /** 618 * Module location 619 * @jvms 4.7.25. The Module Attribute 620 */ 621 MODULE, 622 623 /** 624 * Module requires location 625 * @jvms 4.7.25. The Module Attribute 626 */ 627 MODULE_REQUIRES, 628 629 /** 630 * Module exports location 631 * @jvms 4.7.25. The Module Attribute 632 */ 633 MODULE_EXPORTS, 634 635 /** 636 * Module opens location 637 * @jvms 4.7.25. The Module Attribute 638 */ 639 MODULE_OPENS; 640 641 // Repeated sets of locations used by AccessFlag constants 642 private static final Set<Location> EMPTY_SET = Set.of(); 643 private static final Set<Location> SET_MODULE = Set.of(MODULE); 644 private static final Set<Location> SET_CLASS_METHOD_INNER_CLASS = 645 Set.of(CLASS, METHOD, INNER_CLASS); 646 private static final Set<Location> SET_CLASS_FIELD_METHOD = 647 Set.of(CLASS, FIELD, METHOD); 648 private static final Set<Location> SET_CLASS_FIELD_INNER_CLASS = 649 Set.of(CLASS, FIELD, INNER_CLASS); 650 private static final Set<Location> SET_CLASS_FIELD_METHOD_INNER_CLASS = 651 Set.of(CLASS, FIELD, METHOD, INNER_CLASS); 652 private static final Set<Location> SET_CLASS_METHOD = 653 Set.of(CLASS, METHOD); 654 private static final Set<Location> SET_FIELD_METHOD = 655 Set.of(FIELD, METHOD); 656 private static final Set<Location> SET_FIELD_METHOD_INNER_CLASS = 657 Set.of(FIELD, METHOD, INNER_CLASS); 658 private static final Set<Location> SET_METHOD = Set.of(METHOD); 659 private static final Set<Location> SET_METHOD_PARAM = Set.of(METHOD_PARAMETER); 660 private static final Set<Location> SET_FIELD = Set.of(FIELD); 661 private static final Set<Location> SET_CLASS = Set.of(CLASS); 662 private static final Set<Location> SET_CLASS_INNER_CLASS = 663 Set.of(CLASS, INNER_CLASS); 664 private static final Set<Location> SET_MODULE_REQUIRES = 665 Set.of(MODULE_REQUIRES); 666 private static final Set<Location> SET_PUBLIC_1 = 667 Set.of(CLASS, FIELD, METHOD, INNER_CLASS); 668 private static final Set<Location> SET_FINAL_8 = 669 Set.of(CLASS, FIELD, METHOD, 670 INNER_CLASS, /* added in 1.1 */ 671 METHOD_PARAMETER); /* added in 8 */ 672 private static final Set<Location> SET_SYNTHETIC_7 = 673 Set.of(CLASS, FIELD, METHOD, 674 INNER_CLASS); 675 private static final Set<Location> SET_SYNTHETIC_8 = 676 Set.of(CLASS, FIELD, METHOD, 677 INNER_CLASS, METHOD_PARAMETER); 678 private static final Set<Location> SET_SYNTHETIC_9 = 679 // Added as an access flag in 7 680 Set.of(CLASS, FIELD, METHOD, 681 INNER_CLASS, 682 METHOD_PARAMETER, // Added in 8 683 // Module-related items added in 9 684 MODULE, MODULE_REQUIRES, 685 MODULE_EXPORTS, MODULE_OPENS); 686 private static final Set<Location> SET_MANDATED_9 = 687 Set.of(METHOD_PARAMETER, // From 8 688 // Starting in 9 689 MODULE, MODULE_REQUIRES, 690 MODULE_EXPORTS, MODULE_OPENS); 691 } 692 693 private static class LocationToFlags { 694 private static Map<Location, Set<AccessFlag>> locationToFlags = 695 Map.ofEntries(entry(Location.CLASS, 696 Set.of(PUBLIC, FINAL, (PreviewFeatures.isEnabled() ? IDENTITY : SUPER), 697 INTERFACE, ABSTRACT, 698 SYNTHETIC, ANNOTATION, 699 ENUM, AccessFlag.MODULE)), 700 entry(Location.FIELD, 701 Set.of(PUBLIC, PRIVATE, PROTECTED, 702 STATIC, FINAL, VOLATILE, 703 TRANSIENT, SYNTHETIC, ENUM, STRICT)), 704 entry(Location.METHOD, 705 Set.of(PUBLIC, PRIVATE, PROTECTED, 706 STATIC, FINAL, SYNCHRONIZED, 707 BRIDGE, VARARGS, NATIVE, 708 ABSTRACT, STRICT, SYNTHETIC)), 709 entry(Location.INNER_CLASS, 710 Set.of(PUBLIC, PRIVATE, PROTECTED, IDENTITY, 711 STATIC, FINAL, INTERFACE, ABSTRACT, 712 SYNTHETIC, ANNOTATION, ENUM)), 713 entry(Location.METHOD_PARAMETER, 714 Set.of(FINAL, SYNTHETIC, MANDATED)), 715 entry(Location.MODULE, 716 Set.of(OPEN, SYNTHETIC, MANDATED)), 717 entry(Location.MODULE_REQUIRES, 718 Set.of(TRANSITIVE, STATIC_PHASE, SYNTHETIC, MANDATED)), 719 entry(Location.MODULE_EXPORTS, 720 Set.of(SYNTHETIC, MANDATED)), 721 entry(Location.MODULE_OPENS, 722 Set.of(SYNTHETIC, MANDATED))); 723 } 724 }