1 /*
2 * Copyright (c) 1996, 2020, 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.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23 package org.openjdk.asmtools.jasm;
24
25 import static org.openjdk.asmtools.jasm.JasmTokens.Token;
26 import static org.openjdk.asmtools.jasm.RuntimeConstants.*;
27 import static org.openjdk.asmtools.jasm.Tables.CF_Context;
28
29 /**
30 *
31 *
32 */
33 public class Modifiers {
34
35 /*
36 * Modifier masks
37 */
38 public static final int MM_ATTR = SYNTHETIC_ATTRIBUTE | DEPRECATED_ATTRIBUTE;
39
40 public static final int MM_ACCESS = ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED;
41
42 public static final int MM_INTRF = MM_ACCESS | ACC_ABSTRACT | ACC_INTERFACE | MM_ATTR | ACC_ANNOTATION;
43
44 public static final int MM_CLASS = MM_ACCESS | ACC_FINAL | ACC_SUPER | ACC_ABSTRACT | ACC_ENUM |
45 MM_ATTR | ACC_MODULE |
46 ACC_VALUE | ACC_PRIMITIVE;
47
48 public static final int MM_FIELD = MM_ACCESS | ACC_STATIC | ACC_FINAL | ACC_VOLATILE | ACC_TRANSIENT |
49 ACC_SYNTHETIC | ACC_ENUM |
50 ACC_MANDATED | // JEP 359 Record
51 MM_ATTR;
52
53 public static final int MM_I_METHOD = ACC_ABSTRACT | ACC_PUBLIC | ACC_PRIVATE | ACC_STATIC | ACC_VARARGS |
54 ACC_BRIDGE | ACC_SYNTHETIC ; // interface method
55
56 public static final int MM_A_METHOD = MM_ACCESS | ACC_ABSTRACT | MM_ATTR;
57
58 public static final int MM_N_METHOD = MM_ACCESS | ACC_STRICT | ACC_VARARGS | ACC_SYNTHETIC | MM_ATTR; // <init>
59
60 public static final int MM_METHOD = MM_ACCESS | ACC_STATIC | ACC_FINAL | ACC_SYNCHRONIZED | ACC_BRIDGE |
61 ACC_VARARGS | ACC_NATIVE | ACC_ABSTRACT | ACC_STRICT | ACC_SYNTHETIC |
62 ACC_MANDATED | // JEP 359 Record
63 MM_ATTR ;
64
65 public static final int MM_INNERCLASS = MM_ACCESS | ACC_STATIC | ACC_FINAL | ACC_SUPER | ACC_INTERFACE |
66 ACC_ABSTRACT | ACC_SYNTHETIC | ACC_ANNOTATION | ACC_ENUM | MM_ATTR |
67 ACC_VALUE | ACC_PRIMITIVE;
68
69 public static final int MM_REQUIRES = ACC_TRANSITIVE | ACC_STATIC_PHASE | ACC_SYNTHETIC | ACC_MANDATED ;
70
71 public static final int MM_EXPORTS = ACC_SYNTHETIC | ACC_MANDATED ;
72
73 private Modifiers() {
74 }
75
76 public static boolean validRequires(int mod) {
77 return (mod & ~MM_REQUIRES) == 0;
78 }
79
80 public static boolean validExports(int mod) { return (mod & ~MM_EXPORTS) == 0; }
81
82 public static boolean validInnerClass(int mod) {
83 return (mod & ~MM_INNERCLASS) == 0;
84 }
85
86 public static boolean validField(int mod) {
87 return (mod & ~MM_FIELD) == 0;
88 }
89
90 public static boolean validMethod(int mod) {
91 return (mod & ~MM_METHOD) == 0;
92 }
93
94 public static boolean validInterface(int mod) {
95 return (mod & ~MM_INTRF) == 0;
96 }
97
98 public static int getInvalidModifiers4Interface(int mod) {
99 return mod & ~MM_INTRF;
100 }
101
102 public static boolean validClass(int mod) {
103 return (mod & ~MM_CLASS) == 0;
104 }
105
106 public static int getInvalidModifiers4Class(int mod) {
107 return (mod & ~MM_CLASS);
108 }
109
110 public static boolean validAbstractMethod(int mod) {
111 return (mod & ~MM_A_METHOD) == 0;
112 }
113
114 public static boolean validInitMethod(int mod) {
115 return (mod & ~MM_N_METHOD) == 0;
116 }
117
118 public static boolean validInterfaceMethod(int mod, ClassData cd) {
119 return ((mod & ~MM_I_METHOD) == 0) &&
120 (cd.cfv.major_version() >= 52 || isPublic(mod) && isAbstract(mod) && !isStatic(mod));
121 }
122
123 public static boolean validInterfaceField(int mod) {
124 return mod == (ACC_STATIC | ACC_PUBLIC | ACC_FINAL);
125 }
126
127 public static boolean isPublic(int mod) {
128 return (mod & ACC_PUBLIC) != 0;
129 }
130
131 public static boolean isPrivate(int mod) {
132 return (mod & ACC_PRIVATE) != 0;
133 }
134
135 public static boolean isProtected(int mod) {
136 return (mod & ACC_PROTECTED) != 0;
137 }
138
139 public static boolean isInterface(int mod) {
140 return (mod & ACC_INTERFACE) != 0;
141 }
142
143 public static boolean isAbstract(int mod) {
144 return (mod & ACC_ABSTRACT) != 0;
145 }
146
147 public static boolean isFinal(int mod) {
148 return (mod & ACC_FINAL) != 0;
149 }
150
151 public static boolean isStatic(int mod) {
152 return (mod & ACC_STATIC) != 0;
153 }
154
155 public static boolean isSynthetic(int mod) {
156 return (mod & ACC_SYNTHETIC) != 0;
157 }
158
159 public static boolean isDeprecated(int mod) {
160 return (mod & DEPRECATED_ATTRIBUTE) != 0;
161 }
162
163 public static boolean isTransient(int mod) {
164 return (mod & ACC_TRANSIENT) != 0;
165 }
166
167 public static boolean isAnnotation(int mod) {
168 return (mod & ACC_ANNOTATION) != 0;
169 }
170
171 public static boolean isNative(int mod) {
172 return (mod & ACC_NATIVE) != 0;
173 }
174
175 public static boolean isStrict(int mod) {
176 return (mod & ACC_STRICT) != 0;
177 }
178
179 public static boolean isEnum(int mod) {
180 return (mod & ACC_ENUM) != 0;
181 }
182
183 public static boolean isSuper(int mod) {
184 return (mod & ACC_SUPER) != 0;
185 }
186
187 public static boolean isModule(int mod) { return (mod & ACC_MODULE)!=0; }
188
189 public static boolean isMandated(int mod) { return (mod & ACC_MANDATED) != 0; }
190
191 public static boolean isSynchronized(int mod) {
192 return (mod & ACC_SYNCHRONIZED) != 0;
193 }
194
195 public static boolean isBridge(int mod) {
196 return (mod & ACC_BRIDGE) != 0;
197 }
198
199 public static boolean isVolatile(int mod) {
200 return (mod & ACC_VOLATILE) != 0;
201 }
202
203 public static boolean isVarArgs(int mod) {
204 return (mod & ACC_VARARGS) != 0;
205 }
206
207 public static boolean isSyntheticPseudoMod(int mod) {
208 return (mod & SYNTHETIC_ATTRIBUTE) != 0;
209 }
210
211 public static boolean isDeprecatedPseudoMod(int mod) {
212 return (mod & DEPRECATED_ATTRIBUTE) != 0;
213 }
214
215 public static boolean hasPseudoMod(int mod) {
216 return isSyntheticPseudoMod(mod) || isDeprecatedPseudoMod(mod);
217 }
218
219 public static boolean isTransitive(int mod) { return (mod & ACC_TRANSITIVE) != 0; }
220
221 public static boolean isStaticPhase(int mod) { return (mod & ACC_STATIC_PHASE) != 0; }
222
223 public static boolean isValue(int mod) {
224 return (mod & ACC_VALUE) != 0;
225 }
226
227 public static boolean isPrimitive(int mod) {
228 return (mod & ACC_PRIMITIVE) != 0;
229 }
230
231 /*
232 * Checks that only one (or none) of the Access flags are set.
233 */
234 public static boolean validAccess(int mod) {
235 boolean retval = true;
236 switch (mod & MM_ACCESS) {
237 case 0:
238 case ACC_PUBLIC:
239 case ACC_PRIVATE:
240 case ACC_PROTECTED:
241 break;
242 default:
243 retval = false;
244 }
245 return retval;
246 }
247
248 /*
249 * Are both flags set
250 *
251 */
252 public static boolean both(int mod, int flagA, int flagB) {
253 return (mod & (flagA | flagB)) == (flagA | flagB);
254 }
255
256 /**
257 * Check the modifier flags for the class
258 *
259 * @param env The error reporting environment.
260 * @param mod The modifier flags being checked
261 * @param scanner The file parser
262 */
263 public static void checkClassModifiers(Environment env, int mod, Scanner scanner) {
264 if (isInterface(mod)) {
265 if( isEnum(mod) ) {
266 env.error(scanner.pos, "warn.invalid.modifier.class.intenum");
267 } else if ( !validInterface(mod) ) {
268 env.error(scanner.pos, "warn.invalid.modifier.int",
269 toString(mod & ~MM_INTRF, CF_Context.CTX_CLASS));
270 }
271 if (!isAbstract(mod)) {
272 env.error(scanner.pos, "warn.invalid.modifier.int.abs");
273 }
274 } else {
275 if ( scanner.token != Token.CLASS && !isEnum(mod) && scanner.token != Token.ANNOTATION) {
276 env.error(scanner.pos, "warn.missing.modifier.class");
277 }
278 if (! validClass(mod)) {
279 env.error(scanner.pos, "warn.invalid.modifier.class",
280 toString(mod & ~MM_CLASS, CF_Context.CTX_CLASS));
281 }
282 if (isAbstract(mod) && Modifiers.isFinal(mod)) {
283 env.error(scanner.pos, "warn.invalid.modifier.class.finabs");
284 }
285 }
286 }
287
288 /**
289 * Check the modifier flags for the field
290 *
291 * @param cd The ClassData for the current class
292 * @param mod The modifier flags being checked
293 * @param pos the position of the parser in the file
294 */
295 public static void checkFieldModifiers(ClassData cd, int mod, int pos) {
296 Environment env = cd.env;
297 if (cd.isInterface()) {
298 // For interfaces
299 if (!validInterfaceField(mod)) {
300 env.error(pos, "warn.invalid.modifier.intfield");
301 }
302 } else {
303 // For non-interfaces
304 if (!validField(mod)) {
305 env.error(pos, "warn.invalid.modifier.field",
306 toString(mod & ~MM_FIELD, CF_Context.CTX_METHOD));
307 }
308 if (both(mod, ACC_FINAL, ACC_VOLATILE)) {
309 env.error(pos, "warn.invalid.modifier.fiva");
310 }
311 if (!validAccess(mod)) {
312 env.error(pos, "warn.invalid.modifier.acc");
313 }
314 }
315
316 }
317
318 /**
319 * Check the modifier flags for the method
320 *
321 * @param cd The ClassData for the current class
322 * @param mod The modifier flags being checked
323 * @param pos the position of the parser in the file
324 */
325 public static void checkMethodModifiers(ClassData cd, int mod, int pos, boolean is_init, boolean is_clinit) {
326 Environment env = cd.env;
327 if (!is_clinit) {
328 if (cd.isInterface()) {
329 if (is_init) {
330 env.error(pos, "warn.init.in_int");
331 } else if (!validInterfaceMethod(mod, cd)) {
332 int badflags = (mod & ~MM_I_METHOD);
333 env.error(pos, "warn.invalid.modifier.intmth", toString(badflags, CF_Context.CTX_METHOD)
334 + " *****" + toString(mod, CF_Context.CTX_METHOD) + "*****");
335 }
336 } else {
337 if (is_init && !validInitMethod(mod)) {
338 int badflags = (mod & ~MM_N_METHOD);
339 env.error(pos, "warn.invalid.modifier.init", toString(badflags, CF_Context.CTX_METHOD)
340 + " *****" + toString(mod, CF_Context.CTX_METHOD) + "*****");
341 } else if (isAbstract(mod)) {
342 if (!validAbstractMethod(mod)) {
343 int badflags = (mod & ~MM_A_METHOD);
344 env.error(pos, "warn.invalid.modifier.abst", toString(badflags, CF_Context.CTX_METHOD)
345 + " *****" + toString(mod, CF_Context.CTX_METHOD) + "*****");
346 }
347 } else {
348 if (!validMethod(mod)) {
349 env.error(pos, "warn.invalid.modifier.mth",
350 toString(mod & ~MM_METHOD, CF_Context.CTX_METHOD));
351 }
352 }
353 if (!validAccess(mod)) {
354 env.error(pos, "warn.invalid.modifier.acc");
355 }
356 }
357 }
358 }
359
360 /**
361 * Check the modifier flags for the inner-class
362 *
363 * @param cd The ClassData for the current class
364 * @param mod The modifier flags being checked
365 * @param pos the position of the parser in the file
366 */
367 public static void checkInnerClassModifiers(ClassData cd, int mod, int pos) {
368 Environment env = cd.env;
369
370 if (!validInnerClass(mod)) {
371 int badflags = (mod & ~MM_INNERCLASS);
372 env.error(pos, "warn.invalid.modifier.innerclass",
373 toString(badflags, CF_Context.CTX_INNERCLASS)
374 + " *****" + toString(mod, CF_Context.CTX_INNERCLASS) + "*****");
375 }
376
377 }
378
379 private static StringBuffer _accessString(int mod, CF_Context context) {
380 StringBuffer sb = new StringBuffer();
381 if (context == CF_Context.CTX_CLASS && isModule(mod)) {
382 sb.append(Token.MODULE.parseKey() + " ");
383 }
384 if (isPublic(mod)) {
385 sb.append(Token.PUBLIC.parseKey() + " ");
386 }
387 if (isPrivate(mod)) {
388 sb.append(Token.PRIVATE.parseKey() + " ");
389 }
390 if (isProtected(mod)) {
391 sb.append(Token.PROTECTED.parseKey() + " ");
392 }
393 if (isStatic(mod)) {
394 sb.append(Token.STATIC.parseKey() + " ");
395 }
396 if (context == CF_Context.CTX_METHOD && isFinal(mod)) {
397 sb.append(Token.FINAL.parseKey() + " ");
398 }
399 if (context == CF_Context.CTX_FIELD && isTransient(mod)) {
400 sb.append(Token.TRANSIENT.parseKey() + " ");
401 }
402 if (context == CF_Context.CTX_CLASS && isSuper(mod)) {
403 sb.append(Token.SUPER.parseKey() + " ");
404 }
405 if (context == CF_Context.CTX_METHOD && isSynchronized(mod)) {
406 sb.append(Token.SYNCHRONIZED.parseKey() + " ");
407 }
408 if (context == CF_Context.CTX_METHOD) {
409 if (isBridge(mod)) {
410 sb.append(Token.BRIDGE.parseKey() + " ");
411 }
412 if (isVarArgs(mod)) {
413 sb.append(Token.VARARGS.parseKey() + " ");
414 }
415 if (isNative(mod)) {
416 sb.append(Token.NATIVE.parseKey() + " ");
417 }
418 if (isStrict(mod)) {
419 sb.append(Token.STRICT.parseKey() + " ");
420 }
421 }
422 if (isAbstract(mod)) {
423 if ((context != CF_Context.CTX_CLASS) || !isInterface(mod)) {
424 sb.append(Token.ABSTRACT.parseKey() + " ");
425 }
426 }
427 if ( context.isOneOf(CF_Context.CTX_CLASS, CF_Context.CTX_INNERCLASS, CF_Context.CTX_FIELD) && isFinal(mod)) {
428 sb.append(Token.FINAL.parseKey() + " ");
429 }
430 if (context.isOneOf(CF_Context.CTX_CLASS, CF_Context.CTX_INNERCLASS) && isInterface(mod)) {
431 if (isAnnotation(mod)) {
432 sb.append(Token.ANNOTATION_ACCESS.parseKey() + " ");
433 }
434 sb.append(Token.INTERFACE.parseKey() + " ");
435 }
436 if (isSynthetic(mod)) {
437 sb.append(Token.SYNTHETIC.parseKey() + " ");
438 }
439 if (context == CF_Context.CTX_FIELD && isVolatile(mod)) {
440 sb.append(Token.VOLATILE.parseKey() + " ");
441 }
442 if (isEnum(mod)) {
443 sb.append(Token.ENUM.parseKey() + " ");
444 }
445 if (context.isOneOf(CF_Context.CTX_METHOD, CF_Context.CTX_FIELD) && isMandated(mod)) {
446 sb.append(Token.MANDATED.parseKey() + " ");
447 }
448 if (context.isOneOf(CF_Context.CTX_CLASS, CF_Context.CTX_INNERCLASS) && isPrimitive(mod)) {
449 sb.append(Token.PRIMITIVE.parseKey() + " ");
450 }
451 if (context.isOneOf(CF_Context.CTX_CLASS, CF_Context.CTX_INNERCLASS) && isValue(mod)) {
452 sb.append(Token.VALUE.parseKey() + " ");
453 }
454
455 return sb;
456 }
457
458 public static String toString(int mod, CF_Context context) {
459 StringBuffer sb = _accessString(mod, context);
460
461 if (isSyntheticPseudoMod(mod)) {
462 sb.append("Synthetic(Pseudo) ");
463 }
464 if (isDeprecatedPseudoMod(mod)) {
465 sb.append("Deprecated(Pseudo) ");
466 }
467
468 return sb.toString().trim();
469 }
470
471 public static String moduleFlags( int flags ) {
472 return "";
473 }
474
475 public static String accessString(int mod, CF_Context context) {
476 return (context == CF_Context.CTX_MODULE) ?
477 moduleFlags(mod) :
478 _accessString(mod, context).toString();
479 }
480
481 }