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 a {@link java.lang.classfile##u2 u2} value.
73 *
74 * @see Class#getModifiers()
75 * @see AccessFlag.Location#INNER_CLASS
76 */
77 int flagsMask();
78
79 /**
80 * {@return a set of flag enums denoting access permissions and properties
81 * of the nested class}
82 *
83 * @throws IllegalArgumentException if the flags mask has any undefined bit set
84 * @see Class#accessFlags()
85 * @see AccessFlag.Location#INNER_CLASS
86 */
87 default Set<AccessFlag> flags() {
88 return AccessFlag.maskToAccessFlags(flagsMask(), AccessFlag.Location.INNER_CLASS, ClassFileFormatVersion.CURRENT_PREVIEW_FEATURES);
89 }
90
91 /**
92 * {@return whether a specific access flag is set}
93 *
94 * @param flag the access flag
95 * @see AccessFlag.Location#INNER_CLASS
96 */
97 default boolean has(AccessFlag flag) {
98 return Util.has(AccessFlag.Location.INNER_CLASS, flagsMask(), flag);
99 }
100
101 /**
102 * {@return a nested class description}
103 * @param innerClass the nested class being described
104 * @param outerClass the class that has the nested class as a member, if it exists
105 * @param innerName the simple name of the nested class, if it is not anonymous
106 * @param flags the inner class access flags
107 * @throws IllegalArgumentException if {@code flags} is not {@link
108 * java.lang.classfile##u2 u2}
109 */
110 static InnerClassInfo of(ClassEntry innerClass, Optional<ClassEntry> outerClass,
111 Optional<Utf8Entry> innerName, int flags) {
112 return new UnboundAttribute.UnboundInnerClassInfo(innerClass, outerClass, innerName, flags);
113 }
114
115 /**
116 * {@return a nested class description}
117 * @param innerClass the nested class being described
118 * @param outerClass the class that has the nested class as a member, if it exists
119 * @param innerName the simple name of the nested class, if it is not anonymous
120 * @param flags the inner class access flags
121 * @throws IllegalArgumentException if {@code innerClass} or {@code outerClass}
122 * represents a primitive type, or if {@code flags} is not {@link
123 * java.lang.classfile##u2 u2}
124 */
125 static InnerClassInfo of(ClassDesc innerClass, Optional<ClassDesc> outerClass, Optional<String> innerName, int flags) {
126 return new UnboundAttribute.UnboundInnerClassInfo(TemporaryConstantPool.INSTANCE.classEntry(innerClass),
127 outerClass.map(TemporaryConstantPool.INSTANCE::classEntry),
128 innerName.map(TemporaryConstantPool.INSTANCE::utf8Entry),
129 flags);
130 }
131
132 /**
133 * {@return a nested class description}
134 * @param innerClass the nested class being described
135 * @param outerClass the class that has the nested class as a member, if it exists
136 * @param innerName the name of the nested class, if it is not anonymous
137 * @param flags the inner class access flags
138 * @throws IllegalArgumentException if {@code innerClass} or {@code outerClass}
139 * represents a primitive type, or if any flag cannot be applied to
140 * the {@link AccessFlag.Location#INNER_CLASS} location
141 */
142 static InnerClassInfo of(ClassDesc innerClass, Optional<ClassDesc> outerClass, Optional<String> innerName, AccessFlag... flags) {
143 return of(innerClass, outerClass, innerName, Util.flagsToBits(AccessFlag.Location.INNER_CLASS, flags));
144 }
145 }