Index: lucene/tools/src/java/org/apache/lucene/validation/ForbiddenApisCheckTask.java =================================================================== --- lucene/tools/src/java/org/apache/lucene/validation/ForbiddenApisCheckTask.java (revision 1359372) +++ lucene/tools/src/java/org/apache/lucene/validation/ForbiddenApisCheckTask.java (working copy) @@ -25,6 +25,7 @@ import org.objectweb.asm.Type; import org.objectweb.asm.commons.Method; import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.FieldNode; import org.objectweb.asm.tree.MethodNode; import org.apache.tools.ant.AntClassLoader; @@ -67,23 +68,32 @@ private Path classpath = null; private final Map classCache = new HashMap(); + private final Map forbiddenFields = new HashMap(); private final Map forbiddenMethods = new HashMap(); private final Map forbiddenClasses = new HashMap(); /** Adds the method signature to the list of disallowed methods. The Signature is checked against the given ClassLoader. */ private void addSignature(ClassLoader loader, String signature) throws BuildException { final int p = signature.indexOf('#'); - final String clazz; - final Method dummy; + final String clazz, field; + final Method dummyMethod; if (p >= 0) { clazz = signature.substring(0, p); - // we ignore the return type, its just to match easier (so return type is void): - dummy = Method.getMethod("void " + signature.substring(p+1), true); + final String s = signature.substring(p+1); + if (s.indexOf('(') > 0) { + // we ignore the return type, its just to match easier (so return type is void): + dummyMethod = Method.getMethod("void " + s, true); + field = null; + } else { + field = s; + dummyMethod = null; + } } else { clazz = signature; - dummy = null; + dummyMethod = null; + field = null; } - // check class & method signature, if it is really existent (in classpath), but we don't really load the class into JVM: + // check class & method/field signature, if it is really existent (in classpath), but we don't really load the class into JVM: try { ClassNode c = classCache.get(clazz); if (c == null) { @@ -105,11 +115,11 @@ reader.accept(c = new ClassNode(Opcodes.ASM4), ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES); classCache.put(clazz, c); } - if (dummy != null) { + if (dummyMethod != null) { // list all methods with this signature: boolean found = false; for (final MethodNode mn : c.methods) { - if (mn.name.equals(dummy.getName()) && Arrays.equals(Type.getArgumentTypes(mn.desc), dummy.getArgumentTypes())) { + if (mn.name.equals(dummyMethod.getName()) && Arrays.equals(Type.getArgumentTypes(mn.desc), dummyMethod.getArgumentTypes())) { found = true; forbiddenMethods.put(c.name + '\000' + new Method(mn.name, mn.desc), signature); // don't break when found, as there may be more covariant overrides! @@ -117,6 +127,18 @@ } if (!found) throw new BuildException("No method found with following signature: " + signature); + } else if (field != null) { + // list all methods with this signature: + boolean found = false; + for (final FieldNode fld : c.fields) { + if (fld.name.equals(field)) { + found = true; + forbiddenFields.put(c.name + '\000' + fld.name, signature); + break; + } + } + if (!found) + throw new BuildException("No field found with following name: " + signature); } else { // only add the signature as class name forbiddenClasses.put(c.name, signature); @@ -149,16 +171,29 @@ public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { return new MethodVisitor(Opcodes.ASM4) { private int lineNo = -1; + + private boolean checkClassUse(String owner) { + final String printout = forbiddenClasses.get(owner); + if (printout != null) { + log("Forbidden class use: " + printout, Project.MSG_ERR); + return true; + } + return false; + } + + private void reportSourceAndLine() { + final StringBuilder sb = new StringBuilder(" in ").append(className); + if (source != null && lineNo >= 0) { + new Formatter(sb, Locale.ROOT).format(" (%s:%d)", source, lineNo).flush(); + } + log(sb.toString(), Project.MSG_ERR); + } @Override public void visitMethodInsn(int opcode, String owner, String name, String desc) { - boolean found = false; - String printout = forbiddenClasses.get(owner); - if (printout != null) { - found = true; - log("Forbidden class use: " + printout, Project.MSG_ERR); - } else { - printout = forbiddenMethods.get(owner + '\000' + new Method(name, desc)); + boolean found = checkClassUse(owner); + if (!found) { + final String printout = forbiddenMethods.get(owner + '\000' + new Method(name, desc)); if (printout != null) { found = true; log("Forbidden method invocation: " + printout, Project.MSG_ERR); @@ -166,12 +201,24 @@ } if (found) { violations[0]++; - final StringBuilder sb = new StringBuilder(" in ").append(className); - if (source != null && lineNo >= 0) { - new Formatter(sb, Locale.ROOT).format(" (%s:%d)", source, lineNo).flush(); + reportSourceAndLine(); + } + } + + @Override + public void visitFieldInsn(int opcode, String owner, String name, String desc) { + boolean found = checkClassUse(owner); + if (!found) { + final String printout = forbiddenFields.get(owner + '\000' + name); + if (printout != null) { + found = true; + log("Forbidden field access: " + printout, Project.MSG_ERR); } - log(sb.toString(), Project.MSG_ERR); } + if (found) { + violations[0]++; + reportSourceAndLine(); + } } @Override