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 }