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 }