| /* |
| * Copyright 2003-2007 the original author or authors. |
| * |
| * 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. |
| */ |
| package org.codehaus.groovy.ant; |
| |
| import org.apache.tools.ant.BuildException; |
| import org.apache.tools.ant.taskdefs.MatchingTask; |
| import org.objectweb.asm.ClassReader; |
| import org.objectweb.asm.Label; |
| import org.objectweb.asm.tree.AbstractInsnNode; |
| import org.objectweb.asm.tree.ClassNode; |
| import org.objectweb.asm.tree.MethodNode; |
| import org.objectweb.asm.tree.analysis.Analyzer; |
| import org.objectweb.asm.tree.analysis.Frame; |
| import org.objectweb.asm.tree.analysis.SimpleVerifier; |
| import org.objectweb.asm.util.CheckClassAdapter; |
| import org.objectweb.asm.util.TraceMethodVisitor; |
| |
| import java.io.File; |
| import java.io.FileInputStream; |
| import java.io.IOException; |
| import java.util.List; |
| |
| /** |
| * Verify Class files. This task can take the following |
| * arguments: |
| * <ul> |
| * <li>dir |
| * </ul> |
| * When this task executes, it will recursively scan the dir and |
| * look for class files to verify. |
| */ |
| public class VerifyClass extends MatchingTask { |
| private String topDir = null; |
| private boolean verbose = false; |
| |
| public VerifyClass() { |
| } |
| |
| public void execute() throws BuildException { |
| if (topDir == null) throw new BuildException("no dir attribute is set"); |
| File top = new File(topDir); |
| if (!top.exists()) throw new BuildException("the directory " + top + " does not exist"); |
| log("top dir is " + top); |
| int fails = execute(top); |
| if (fails == 0) { |
| log("no bytecode problems found"); |
| } else { |
| log("found " + fails + " failing classes"); |
| } |
| } |
| |
| public void setDir(String dir) throws BuildException { |
| topDir = dir; |
| } |
| |
| public void setVerbose(boolean v) { |
| verbose = v; |
| } |
| |
| private int execute(File dir) { |
| int fails = 0; |
| File[] files = dir.listFiles(); |
| for (int i = 0; i < files.length; i++) { |
| File f = files[i]; |
| if (f.isDirectory()) { |
| fails += execute(f); |
| } else if (f.getName().endsWith(".class")) { |
| try { |
| boolean ok = readClass(f.getCanonicalPath()); |
| if (!ok) fails++; |
| } catch (IOException ioe) { |
| log(ioe.getMessage()); |
| throw new BuildException(ioe); |
| } |
| } |
| } |
| return fails; |
| } |
| |
| private boolean readClass(String clazz) throws IOException { |
| ClassReader cr = new ClassReader(new FileInputStream(clazz)); |
| ClassNode ca = new ClassNode() { |
| public void visitEnd() { |
| //accept(cv); |
| } |
| }; |
| cr.accept(new CheckClassAdapter(ca), true); |
| boolean failed = false; |
| |
| List methods = ca.methods; |
| for (int i = 0; i < methods.size(); ++i) { |
| MethodNode method = (MethodNode) methods.get(i); |
| if (method.instructions.size() > 0) { |
| Analyzer a = new Analyzer(new SimpleVerifier()); |
| try { |
| a.analyze(ca.name, method); |
| continue; |
| } catch (Exception e) { |
| e.printStackTrace(); |
| } |
| final Frame[] frames = a.getFrames(); |
| |
| if (!failed) { |
| failed = true; |
| log("verifying of class " + clazz + " failed"); |
| } |
| if (verbose) log(method.name + method.desc); |
| TraceMethodVisitor mv = new TraceMethodVisitor(null) { |
| public void visitMaxs(int maxStack, int maxLocals) { |
| StringBuffer buffer = new StringBuffer(); |
| for (int i = 0; i < text.size(); ++i) { |
| String s = frames[i] == null ? "null" : frames[i].toString(); |
| while (s.length() < maxStack + maxLocals + 1) { |
| s += " "; |
| } |
| buffer.append(Integer.toString(i + 100000).substring(1)); |
| buffer.append(" "); |
| buffer.append(s); |
| buffer.append(" : "); |
| buffer.append(text.get(i)); |
| } |
| if (verbose) log(buffer.toString()); |
| } |
| }; |
| for (int j = 0; j < method.instructions.size(); ++j) { |
| Object insn = method.instructions.get(j); |
| if (insn instanceof AbstractInsnNode) { |
| ((AbstractInsnNode) insn).accept(mv); |
| } else { |
| mv.visitLabel((Label) insn); |
| } |
| } |
| mv.visitMaxs(method.maxStack, method.maxLocals); |
| } |
| } |
| return !failed; |
| } |
| |
| } |