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 }