1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46 package org.codehaus.groovy.ant;
47
48 import java.io.File;
49 import java.io.FileInputStream;
50 import java.io.IOException;
51 import java.util.List;
52
53 import org.apache.tools.ant.BuildException;
54 import org.apache.tools.ant.taskdefs.MatchingTask;
55 import org.objectweb.asm.ClassReader;
56 import org.objectweb.asm.Label;
57 import org.objectweb.asm.util.CheckClassAdapter;
58 import org.objectweb.asm.util.TraceMethodVisitor;
59 import org.objectweb.asm.tree.AbstractInsnNode ;
60 import org.objectweb.asm.tree.ClassNode ;
61 import org.objectweb.asm.tree.MethodNode ;
62 import org.objectweb.asm.tree.analysis.Analyzer ;
63 import org.objectweb.asm.tree.analysis.Frame ;
64 import org.objectweb.asm.tree.analysis.SimpleVerifier ;
65
66 /***
67 * Compiles Groovy source files. This task can take the following
68 * arguments:
69 * <ul>
70 * <li>sourcedir
71 * <li>destdir
72 * <li>classpath
73 * </ul>
74 * Of these arguments, the <b>sourcedir</b> and <b>destdir</b> are required.
75 * <p>
76 * When this task executes, it will recursively scan the sourcedir and
77 * destdir looking for Groovy source files to compile. This task makes its
78 * compile decision based on timestamp.
79 *
80 * Based heavily on the Javac implementation in Ant
81 *
82 * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
83 * @version $Revision: 1.2 $
84 */
85 public class VerifyClass extends MatchingTask {
86 private String topDir=null;
87 private boolean verbose = false;
88
89 public VerifyClass() {}
90
91 public void execute() throws BuildException {
92 if (topDir==null) throw new BuildException("no dir attribute is set");
93 File top = new File(topDir);
94 if (!top.exists()) throw new BuildException("the directory "+top+" does not exist");
95 log ("top dir is "+top);
96 int fails = execute(top);
97 if (fails==0) {
98 log ("no bytecode problems found");
99 } else {
100 log ("found "+fails+" failing classes");
101 }
102 }
103
104 public void setDir(String dir) throws BuildException {
105 topDir = dir;
106 }
107
108 public void setVerbose(boolean v) {
109 verbose = v;
110 }
111
112 private int execute(File dir) {
113 int fails = 0;
114 File[] files = dir.listFiles();
115 for (int i = 0; i < files.length; i++) {
116 File f =files[i];
117 if (f.isDirectory()) {
118 fails += execute(f);
119 } else if (f.getName().endsWith(".class")) {
120 try {
121 boolean ok = readClass(f.getCanonicalPath());
122 if (!ok) fails++;
123 } catch (IOException ioe) {
124 log(ioe.getMessage());
125 throw new BuildException(ioe);
126 }
127 }
128 }
129 return fails;
130 }
131
132 private boolean readClass(String clazz) throws IOException {
133 ClassReader cr = new ClassReader(new FileInputStream(clazz));
134 ClassNode ca = new ClassNode ( )
135 {
136 public void visitEnd () {
137
138 }
139 } ;
140 cr.accept(new CheckClassAdapter(ca), true);
141 boolean failed=false;
142
143 List methods = ca.methods;
144 for (int i = 0; i < methods.size(); ++i) {
145 MethodNode method = (MethodNode)methods.get(i);
146 if (method.instructions.size() > 0) {
147 Analyzer a = new Analyzer(new SimpleVerifier());
148 try {
149 a.analyze(ca.name, method);
150 continue;
151 } catch (Exception e) {
152 e.printStackTrace();
153 }
154 final Frame[] frames = a.getFrames();
155
156 if (!failed) {
157 failed=true;
158 log("verifying of class "+clazz+" failed");
159 }
160 if (verbose) log(method.name + method.desc);
161 TraceMethodVisitor cv = new TraceMethodVisitor(null) {
162 public void visitMaxs (int maxStack, int maxLocals) {
163 StringBuffer buffer = new StringBuffer();
164 for (int i = 0; i < text.size(); ++i) {
165 String s = frames[i] == null ? "null" : frames[i].toString();
166 while (s.length() < maxStack+maxLocals+1) {
167 s += " ";
168 }
169 buffer.append(Integer.toString(i + 100000).substring(1));
170 buffer.append(" ");
171 buffer.append(s);
172 buffer.append(" : ");
173 buffer.append(text.get(i));
174 }
175 if (verbose) log(buffer.toString());
176 }
177 };
178 for (int j = 0; j < method.instructions.size(); ++j) {
179 Object insn = method.instructions.get(j);
180 if (insn instanceof AbstractInsnNode) {
181 ((AbstractInsnNode)insn).accept(cv);
182 } else {
183 cv.visitLabel((Label)insn);
184 }
185 }
186 cv.visitMaxs(method.maxStack, method.maxLocals);
187 }
188 }
189 return !failed;
190 }
191
192 }