001: /*
002: $Id: VerifyClass.java 3419 2006-01-19 00:07:02Z blackdrag $
003:
004: Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
005:
006: Redistribution and use of this software and associated documentation
007: ("Software"), with or without modification, are permitted provided
008: that the following conditions are met:
009:
010: 1. Redistributions of source code must retain copyright
011: statements and notices. Redistributions must also contain a
012: copy of this document.
013:
014: 2. Redistributions in binary form must reproduce the
015: above copyright notice, this list of conditions and the
016: following disclaimer in the documentation and/or other
017: materials provided with the distribution.
018:
019: 3. The name "groovy" must not be used to endorse or promote
020: products derived from this Software without prior written
021: permission of The Codehaus. For written permission,
022: please contact info@codehaus.org.
023:
024: 4. Products derived from this Software may not be called "groovy"
025: nor may "groovy" appear in their names without prior written
026: permission of The Codehaus. "groovy" is a registered
027: trademark of The Codehaus.
028:
029: 5. Due credit should be given to The Codehaus -
030: http://groovy.codehaus.org/
031:
032: THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
033: ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
034: NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
035: FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
036: THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
037: INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
038: (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
039: SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
040: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
041: STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
042: ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
043: OF THE POSSIBILITY OF SUCH DAMAGE.
044:
045: */
046: package org.codehaus.groovy.ant;
047:
048: import java.io.File;
049: import java.io.FileInputStream;
050: import java.io.IOException;
051: import java.util.List;
052:
053: import org.apache.tools.ant.BuildException;
054: import org.apache.tools.ant.taskdefs.MatchingTask;
055: import org.objectweb.asm.ClassReader;
056: import org.objectweb.asm.Label;
057: import org.objectweb.asm.util.CheckClassAdapter;
058: import org.objectweb.asm.util.TraceMethodVisitor;
059: import org.objectweb.asm.tree.AbstractInsnNode;
060: import org.objectweb.asm.tree.ClassNode;
061: import org.objectweb.asm.tree.MethodNode;
062: import org.objectweb.asm.tree.analysis.Analyzer;
063: import org.objectweb.asm.tree.analysis.Frame;
064: import org.objectweb.asm.tree.analysis.SimpleVerifier;
065:
066: /**
067: * Verify Class files. This task can take the following
068: * arguments:
069: * <ul>
070: * <li>dir
071: * </ul>
072: * When this task executes, it will recursively scan the dir and
073: * look for class files to verify.
074: */
075: public class VerifyClass extends MatchingTask {
076: private String topDir = null;
077: private boolean verbose = false;
078:
079: public VerifyClass() {
080: }
081:
082: public void execute() throws BuildException {
083: if (topDir == null)
084: throw new BuildException("no dir attribute is set");
085: File top = new File(topDir);
086: if (!top.exists())
087: throw new BuildException("the directory " + top
088: + " does not exist");
089: log("top dir is " + top);
090: int fails = execute(top);
091: if (fails == 0) {
092: log("no bytecode problems found");
093: } else {
094: log("found " + fails + " failing classes");
095: }
096: }
097:
098: public void setDir(String dir) throws BuildException {
099: topDir = dir;
100: }
101:
102: public void setVerbose(boolean v) {
103: verbose = v;
104: }
105:
106: private int execute(File dir) {
107: int fails = 0;
108: File[] files = dir.listFiles();
109: for (int i = 0; i < files.length; i++) {
110: File f = files[i];
111: if (f.isDirectory()) {
112: fails += execute(f);
113: } else if (f.getName().endsWith(".class")) {
114: try {
115: boolean ok = readClass(f.getCanonicalPath());
116: if (!ok)
117: fails++;
118: } catch (IOException ioe) {
119: log(ioe.getMessage());
120: throw new BuildException(ioe);
121: }
122: }
123: }
124: return fails;
125: }
126:
127: private boolean readClass(String clazz) throws IOException {
128: ClassReader cr = new ClassReader(new FileInputStream(clazz));
129: ClassNode ca = new ClassNode() {
130: public void visitEnd() {
131: //accept(cv);
132: }
133: };
134: cr.accept(new CheckClassAdapter(ca), true);
135: boolean failed = false;
136:
137: List methods = ca.methods;
138: for (int i = 0; i < methods.size(); ++i) {
139: MethodNode method = (MethodNode) methods.get(i);
140: if (method.instructions.size() > 0) {
141: Analyzer a = new Analyzer(new SimpleVerifier());
142: try {
143: a.analyze(ca.name, method);
144: continue;
145: } catch (Exception e) {
146: e.printStackTrace();
147: }
148: final Frame[] frames = a.getFrames();
149:
150: if (!failed) {
151: failed = true;
152: log("verifying of class " + clazz + " failed");
153: }
154: if (verbose)
155: log(method.name + method.desc);
156: TraceMethodVisitor cv = new TraceMethodVisitor(null) {
157: public void visitMaxs(int maxStack, int maxLocals) {
158: StringBuffer buffer = new StringBuffer();
159: for (int i = 0; i < text.size(); ++i) {
160: String s = frames[i] == null ? "null"
161: : frames[i].toString();
162: while (s.length() < maxStack + maxLocals
163: + 1) {
164: s += " ";
165: }
166: buffer.append(Integer.toString(i + 100000)
167: .substring(1));
168: buffer.append(" ");
169: buffer.append(s);
170: buffer.append(" : ");
171: buffer.append(text.get(i));
172: }
173: if (verbose)
174: log(buffer.toString());
175: }
176: };
177: for (int j = 0; j < method.instructions.size(); ++j) {
178: Object insn = method.instructions.get(j);
179: if (insn instanceof AbstractInsnNode) {
180: ((AbstractInsnNode) insn).accept(cv);
181: } else {
182: cv.visitLabel((Label) insn);
183: }
184: }
185: cv.visitMaxs(method.maxStack, method.maxLocals);
186: }
187: }
188: return !failed;
189: }
190:
191: }
|