void check(String dir, String... fileNames) throws IOException, ConstantPoolException, Descriptor.InvalidDescriptor { for (String fileName : fileNames) { ClassFile classFileToCheck = ClassFile.read(new File(dir, fileName)); for (Method method : classFileToCheck.methods) { if ((method.access_flags.flags & ACC_STRICT) == 0) { errors.add(String.format(offendingMethodErrorMessage, method.getName(classFileToCheck.constant_pool), classFileToCheck.getName())); } } } }
String getValue(Descriptor d) { try { return d.getValue(constant_pool); } catch (ConstantPoolException e) { return report(e); } }
void setStackMap(StackMapTable_attribute attr) { if (attr == null) { map = null; return; } Method m = classWriter.getMethod(); Descriptor d = m.descriptor; String[] args; try { ConstantPool cp = classWriter.getClassFile().constant_pool; String argString = d.getParameterTypes(cp); args = argString.substring(1, argString.length() - 1).split("[, ]+"); } catch (ConstantPoolException | InvalidDescriptor e) { return; } boolean isStatic = m.access_flags.is(AccessFlags.ACC_STATIC); verification_type_info[] initialLocals = new verification_type_info[(isStatic ? 0 : 1) + args.length]; if (!isStatic) initialLocals[0] = new CustomVerificationTypeInfo("this"); for (int i = 0; i < args.length; i++) { initialLocals[(isStatic ? 0 : 1) + i] = new CustomVerificationTypeInfo(args[i].replace(".", "/")); } map = new HashMap<>(); StackMapBuilder builder = new StackMapBuilder(); // using -1 as the pc for the initial frame effectively compensates for // the difference in behavior for the first stack map frame (where the // pc offset is just offset_delta) compared to subsequent frames (where // the pc offset is always offset_delta+1). int pc = -1; map.put(pc, new StackMap(initialLocals, empty)); for (int i = 0; i < attr.entries.length; i++) pc = attr.entries[i].accept(builder, pc); }
private void writeDescriptor(int index, boolean resolveIndices) { if (resolveIndices) { try { ConstantPool constant_pool = classWriter.getClassFile().constant_pool; Descriptor d = new Descriptor(index); print(d.getFieldType(constant_pool)); return; } catch (ConstantPoolException | InvalidDescriptor ignore) { } } print("#" + index); }
void check() throws IOException, ConstantPoolException, Descriptor.InvalidDescriptor { ClassFile classFileToCheck = ClassFile.read(new File("Test.class")); for (Method method : classFileToCheck.methods) { if ((method.access_flags.flags & ACC_STRICT) == 0) { errors.add(String.format(offendingMethodErrorMessage, method.getName(classFileToCheck.constant_pool), classFileToCheck.getName())); } } }
void analyzeClassFile(ClassFile classFileToCheck) throws IOException, ConstantPoolException, Descriptor.InvalidDescriptor { boolean enumClass = (classFileToCheck.access_flags.flags & ACC_ENUM) != 0; boolean nonFinalStaticEnumField; boolean nonFinalStaticField; currentFieldsToIgnore = classFieldsToIgnoreMap.get(classFileToCheck.getName()); for (Field field : classFileToCheck.fields) { if (ignoreField(field.getName(classFileToCheck.constant_pool))) { continue; } nonFinalStaticEnumField = (field.access_flags.flags & (ACC_ENUM | ACC_FINAL)) == 0; nonFinalStaticField = (field.access_flags.flags & ACC_STATIC) != 0 && (field.access_flags.flags & ACC_FINAL) == 0; if (enumClass ? nonFinalStaticEnumField : nonFinalStaticField) { errors.add("There is a mutable field named " + field.getName(classFileToCheck.constant_pool) + ", at class " + classFileToCheck.getName()); } } }
MethodInfo(ClassFile cf, Method m) { this.method = m; String name; String paramTypes; String returnType; LineNumberTable_attribute.Entry[] lineNumberTable; try { // method name name = m.getName(cf.constant_pool); // signature paramTypes = m.descriptor.getParameterTypes(cf.constant_pool); returnType = m.descriptor.getReturnType(cf.constant_pool); Code_attribute codeAttr = (Code_attribute) m.attributes.get(Attribute.Code); lineNumberTable = ((LineNumberTable_attribute) codeAttr.attributes.get(Attribute.LineNumberTable)).line_number_table; } catch (ConstantPoolException|Descriptor.InvalidDescriptor e) { throw new RuntimeException(e); } this.name = name; this.paramTypes = paramTypes; this.returnType = returnType; Arrays.stream(lineNumberTable).forEach(entry -> bciToLineNumbers.computeIfAbsent(entry.start_pc, _n -> new TreeSet<>()) .add(entry.line_number)); }