1 /*
  2  * Copyright (c) 2022, 2025, 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 package java.lang.classfile.attribute;
 26 
 27 import java.lang.classfile.constantpool.ClassEntry;
 28 import java.lang.classfile.constantpool.Utf8Entry;
 29 import java.lang.constant.ClassDesc;
 30 import java.lang.reflect.AccessFlag;
 31 import java.lang.reflect.ClassFileFormatVersion;
 32 import java.util.Optional;
 33 import java.util.Set;
 34 
 35 import jdk.internal.classfile.impl.TemporaryConstantPool;
 36 import jdk.internal.classfile.impl.UnboundAttribute;
 37 import jdk.internal.classfile.impl.Util;
 38 
 39 /**
 40  * Models a single entry in the {@link InnerClassesAttribute}.
 41  *
 42  * @see InnerClassesAttribute#classes()
 43  * @jvms 4.7.6 The {@code InnerClasses} Attribute
 44  * @since 24
 45  */
 46 public sealed interface InnerClassInfo
 47         permits UnboundAttribute.UnboundInnerClassInfo {
 48 
 49     /**
 50      * {@return the nested class described by this entry}
 51      */
 52     ClassEntry innerClass();
 53 
 54     /**
 55      * {@return the class or interface of which this class is a member, if it is
 56      * a member of a class or interface}  This may be empty if this class is
 57      * local or anonymous.
 58      *
 59      * @see Class#getDeclaringClass()
 60      */
 61     Optional<ClassEntry> outerClass();
 62 
 63     /**
 64      * {@return the simple name of this class, or empty if this class is anonymous}
 65      *
 66      * @see Class#getSimpleName()
 67      */
 68     Optional<Utf8Entry> innerName();
 69 
 70     /**
 71      * {@return a bit mask of flags denoting access permissions and properties
 72      * of the inner class}  It is in the range of unsigned short, {@code [0,
 73      * 0xFFFF]}.
 74      *
 75      * @see Class#getModifiers()
 76      * @see AccessFlag.Location#INNER_CLASS
 77      */
 78     int flagsMask();
 79 
 80     /**
 81      * {@return a set of flag enums denoting access permissions and properties
 82      * of the nested class}
 83      *
 84      * @throws IllegalArgumentException if the flags mask has any undefined bit set
 85      * @see Class#accessFlags()
 86      * @see AccessFlag.Location#INNER_CLASS
 87      */
 88     default Set<AccessFlag> flags() {
 89         return AccessFlag.maskToAccessFlags(flagsMask(), AccessFlag.Location.INNER_CLASS, ClassFileFormatVersion.CURRENT_PREVIEW_FEATURES);
 90     }
 91 
 92     /**
 93      * {@return whether a specific access flag is set}
 94      *
 95      * @param flag the access flag
 96      * @see AccessFlag.Location#INNER_CLASS
 97      */
 98     default boolean has(AccessFlag flag) {
 99         return Util.has(AccessFlag.Location.INNER_CLASS, flagsMask(), flag);
100     }
101 
102     /**
103      * {@return a nested class description}
104      * @param innerClass the nested class being described
105      * @param outerClass the class that has the nested class as a member, if it exists
106      * @param innerName the simple name of the nested class, if it is not anonymous
107      * @param flags the inner class access flags
108      */
109     static InnerClassInfo of(ClassEntry innerClass, Optional<ClassEntry> outerClass,
110                              Optional<Utf8Entry> innerName, int flags) {
111         return new UnboundAttribute.UnboundInnerClassInfo(innerClass, outerClass, innerName, flags);
112     }
113 
114     /**
115      * {@return a nested class description}
116      * @param innerClass the nested class being described
117      * @param outerClass the class that has the nested class as a member, if it exists
118      * @param innerName the simple name of the nested class, if it is not anonymous
119      * @param flags the inner class access flags
120      * @throws IllegalArgumentException if {@code innerClass} or {@code outerClass} represents a primitive type
121      */
122     static InnerClassInfo of(ClassDesc innerClass, Optional<ClassDesc> outerClass, Optional<String> innerName, int flags) {
123         return new UnboundAttribute.UnboundInnerClassInfo(TemporaryConstantPool.INSTANCE.classEntry(innerClass),
124                                                           outerClass.map(TemporaryConstantPool.INSTANCE::classEntry),
125                                                           innerName.map(TemporaryConstantPool.INSTANCE::utf8Entry),
126                                                           flags);
127     }
128 
129     /**
130      * {@return a nested class description}
131      * @param innerClass the nested class being described
132      * @param outerClass the class that has the nested class as a member, if it exists
133      * @param innerName the name of the nested class, if it is not anonymous
134      * @param flags the inner class access flags
135      * @throws IllegalArgumentException if {@code innerClass} or {@code outerClass}
136      *         represents a primitive type, or if any flag cannot be applied to
137      *         the {@link AccessFlag.Location#INNER_CLASS} location
138      */
139     static InnerClassInfo of(ClassDesc innerClass, Optional<ClassDesc> outerClass, Optional<String> innerName, AccessFlag... flags) {
140         return of(innerClass, outerClass, innerName, Util.flagsToBits(AccessFlag.Location.INNER_CLASS, flags));
141     }
142 }