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