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