// Copyright 2015 The Bazel Authors. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. import java.util.ArrayList; import java.util.List; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.Attribute; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; /** * A {@code ClassVisitor} that checks that ijar did its job. */ final class StripVerifyingVisitor extends ClassVisitor { public List<String> errors = new ArrayList<String>(); private String className; public StripVerifyingVisitor() { super(Opcodes.ASM5); } @Override public void visit( int version, int access, String name, String signature, String superName, String[] interfaces) { className = name; if ((access & Opcodes.ACC_PRIVATE) != 0) { errors.add(String.format("Private class found %s", className)); } } @Override public void visitSource(String source, String debug) { errors.add(String.format("Source entry found %s %s", source, debug)); } @Override public void visitOuterClass(String owner, String name, String desc) { // Always okay. } @Override public AnnotationVisitor visitAnnotation(String desc, boolean visible) { // Always okay. return null; } @Override public void visitAttribute(Attribute attr) { // Just assume this is okay. } @Override public void visitInnerClass( String name, String outerName, String innerName, int access) { // Always okay // TODO(bazel-team): verify removal of leftover inner classes once implemented // TODO(bazel-team): verify removal of private inner classes once implemented } @Override public FieldVisitor visitField( int access, String name, String desc, String signature, Object value) { if ((access & Opcodes.ACC_PRIVATE) != 0) { errors.add(String.format("Private field %s found in %s", name, className)); } // We need to go deeper. return new StripVerifyingFieldVisitor(errors, className, name); } @Override public MethodVisitor visitMethod( int access, String name, String desc, String signature, String[] exceptions) { if ((access & Opcodes.ACC_PRIVATE) != 0) { errors.add(String.format("Private method %s found in %s", name, className)); } // We need to go deeper. return new StripVerifyingMethodVisitor(errors, className, name); } @Override public void visitEnd() { // Always okay. } private static class StripVerifyingFieldVisitor extends FieldVisitor { private final List<String> errors; private final String className; private final String fieldName; StripVerifyingFieldVisitor(List<String> errors, String className, String fieldName) { super(Opcodes.ASM5); this.errors = errors; this.className = className; this.fieldName = fieldName; } @Override public AnnotationVisitor visitAnnotation(String desc, boolean visible) { // Always okay. return null; } @Override public void visitAttribute(Attribute attr) { // Just assume this is okay. } @Override public void visitEnd() { // Always okay. } } private static class StripVerifyingMethodVisitor extends MethodVisitor { private final List<String> errors; private final String className; private final String methodName; StripVerifyingMethodVisitor(List<String> errors, String className, String methodName) { super(Opcodes.ASM5); this.errors = errors; this.className = className; this.methodName = methodName; } @Override public AnnotationVisitor visitAnnotationDefault() { // Always okay. return null; } @Override public AnnotationVisitor visitAnnotation(String desc, boolean visible) { // Always okay. return null; } @Override public AnnotationVisitor visitParameterAnnotation( int parameter, String desc, boolean visible) { // Always okay. return null; } @Override public void visitAttribute(Attribute attr) { // Just assume this is okay. } @Override public void visitCode() { errors.add(String.format("Code found for method %s of %s", methodName, className)); } @Override public void visitEnd() {} // We ignore all details about code segments. Presumably we already logged an error about code // existing at all. @Override public void visitFrame( int type, int nLocal, Object[] local, int nStack, Object[] stack) {} @Override public void visitInsn(int opcode) {} @Override public void visitIntInsn(int opcode, int operand) {} @Override public void visitVarInsn(int opcode, int var) {} @Override public void visitTypeInsn(int opcode, String type) {} @Override public void visitFieldInsn(int opcode, String owner, String name, String desc) {} @Override public void visitMethodInsn( int opcode, String owner, String name, String desc, boolean isInterface) {} @Override public void visitJumpInsn(int opcode, Label label) {} @Override public void visitLabel(Label label) {} @Override public void visitLdcInsn(Object cst) {} @Override public void visitIincInsn(int var, int increment) {} @Override public void visitTableSwitchInsn(int min, int max, Label dflt, Label... labels) {} @Override public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {} @Override public void visitMultiANewArrayInsn(String desc, int dims) {} @Override public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {} @Override public void visitLocalVariable( String name, String desc, String signature, Label start, Label end, int index) {} @Override public void visitLineNumber(int line, Label start) {} @Override public void visitMaxs(int maxStack, int maxLocals) {} } }