blob: be494696f82802499658aa587d0bea186a38632e [file] [log] [blame]
/*
* 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;
}
}