1 25 26 package spoon.jdiet; 27 28 import java.io.File ; 29 import java.io.FileInputStream ; 30 import java.io.InputStream ; 31 import java.util.Enumeration ; 32 import java.util.HashMap ; 33 import java.util.HashSet ; 34 import java.util.Iterator ; 35 import java.util.Map ; 36 import java.util.Set ; 37 import java.util.zip.ZipEntry ; 38 import java.util.zip.ZipFile ; 39 40 import org.apache.tools.ant.BuildException; 41 import org.apache.tools.ant.taskdefs.MatchingTask; 42 import org.objectweb.asm.AnnotationVisitor; 43 import org.objectweb.asm.Attribute; 44 import org.objectweb.asm.ClassAdapter; 45 import org.objectweb.asm.ClassReader; 46 import org.objectweb.asm.ClassVisitor; 47 import org.objectweb.asm.ClassWriter; 48 import org.objectweb.asm.FieldVisitor; 49 import org.objectweb.asm.Label; 50 import org.objectweb.asm.MethodAdapter; 51 import org.objectweb.asm.MethodVisitor; 52 import org.objectweb.asm.Opcodes; 53 54 62 public class ASMJDietVerifier extends MatchingTask { 63 64 private File src; 65 66 private File cldcJar; 67 68 74 private Set cldcAPI; 76 77 83 private Map cldcMembers; 85 86 90 private Map cldcSupers; 92 93 private int errors; 94 95 public void setSrcdir (final File src) { 96 this.src = src; 97 } 98 99 public void setCldcjar (final File cldcJar) { 100 this.cldcJar = cldcJar; 101 } 102 103 106 107 public void execute () { 108 if (src == null) { 109 throw new BuildException("srcdir must be specified"); 110 } 111 112 try { 113 if (cldcJar != null) { 114 cldcAPI = new HashSet (); 115 cldcMembers = new HashMap (); 116 cldcSupers = new HashMap (); 117 118 ZipFile zf = new ZipFile (cldcJar); 119 Enumeration e = zf.entries(); 120 while (e.hasMoreElements()) { 121 ZipEntry ze = (ZipEntry )e.nextElement(); 122 if (ze.getName().endsWith(".class")) { 123 new ClassReader(zf.getInputStream(ze)).accept(new ClassAnalyzer(), true); 124 } 125 } 126 127 130 for (Iterator iter = cldcSupers.keySet().iterator(); iter.hasNext();) { 132 133 String clName = (String ) iter.next(); 134 Set superNames = (Set ) cldcSupers.get(clName); 135 136 int oldSize,newSize; 137 do { 138 Set closure = new HashSet (); 139 140 for (Iterator iterator2 = superNames.iterator(); iterator2.hasNext();) { 142 String superName = (String ) iterator2.next(); 143 144 Set ssupers = (Set ) cldcSupers.get(superName); 145 if( ssupers != null ) { 146 closure.addAll(ssupers); 147 } 148 } 149 150 oldSize = superNames.size(); 151 superNames.addAll(closure); 152 newSize = superNames.size(); 153 } 154 while( oldSize != newSize ); 155 } 156 157 160 for (Iterator iter = cldcSupers.keySet().iterator(); iter.hasNext();) { 162 163 String clName = (String ) iter.next(); 164 Set superNames = (Set ) cldcSupers.get(clName); 165 166 for (Iterator iterator2 = superNames.iterator(); iterator2.hasNext();) { 168 String superName = (String ) iterator2.next(); 169 170 Set members = (Set ) cldcMembers.get(superName); 172 if( members != null ) { 173 174 for (Iterator iterator3 = members.iterator(); iterator3.hasNext();) { 176 String member = (String ) iterator3.next(); 177 178 cldcAPI.add(clName+","+member); 180 } 181 } 182 } 183 } 184 } 185 } catch (Exception e) { 186 log(e.getMessage()); 187 } 188 189 int total = 0; 190 String [] files = getDirectoryScanner(src).getIncludedFiles(); 191 for (int i = 0; i < files.length; ++i) { 192 File srcFile = new File (src, files[i]); 193 194 ClassReader cr; 195 try { 196 InputStream is = new FileInputStream (srcFile); 197 cr = new ClassReader(is); 198 } catch (Exception e) { 199 log(e.getMessage()); 200 continue; 201 } 202 203 ClassWriter cw = new ClassWriter(false); 204 ClassVerifier converter = new ClassVerifier(cw); 205 cr.accept(converter, true); 206 207 ++total; 208 } 209 210 if (errors > 0) { 211 throw new BuildException(errors+" errors"); 212 } else if (total > 0) { 213 if (total == 1) { 214 log("1 class scanned"); 215 } else { 216 log(total + " classes scanned"); 217 } 218 } 219 } 220 221 225 class ClassAnalyzer implements ClassVisitor, Opcodes { 226 227 private String name; 228 229 public void visit ( 230 final int version, 231 final int access, 232 final String name, 233 final String signature, 234 final String superName, 235 final String [] interfaces) 236 { 237 this.name = name; 238 239 Set supers = (Set ) cldcSupers.get(name); 240 if( supers == null ) { 241 supers = new HashSet (); 242 cldcSupers.put(name,supers); 243 } 244 supers.add(superName); 245 } 246 247 public FieldVisitor visitField ( 248 int access, 249 String name, 250 String desc, 251 String signature, 252 Object value) 253 { 254 FieldVisitor fv = null; 255 if ((access & (ACC_PUBLIC | ACC_PROTECTED)) != 0) { 256 cldcAPI.add(this.name+","+name); 257 addMember(this.name,name); 258 } 259 return fv; 260 } 261 262 private void addMember( String clName, String memberName ) { 263 Set members = (Set ) cldcMembers.get(clName); 264 if( members == null ) { 265 members = new HashSet (); 266 cldcMembers.put(clName,members); 267 } 268 members.add(memberName); 269 } 270 271 public MethodVisitor visitMethod ( 272 final int access, 273 final String name, 274 final String desc, 275 final String signature, 276 final String [] exceptions) 277 { 278 if ((access & (ACC_PUBLIC | ACC_PROTECTED)) != 0) { 279 cldcAPI.add(this.name+","+name+desc); 280 addMember(this.name,name+desc); 281 } 282 MethodVisitor mv = null; 283 return mv; 284 } 285 286 public void visitInnerClass ( 287 final String name, 288 final String outerName, 289 final String innerName, 290 final int access) 291 { 292 } 293 294 public void visitEnd () { 295 } 296 297 public void visitSource(String source, String debug) { 298 } 299 300 public void visitOuterClass(String owner, String name, String desc) { 301 } 302 303 public AnnotationVisitor visitAnnotation(String desc, boolean visible) { 304 return null; 305 } 306 307 public void visitAttribute(Attribute attr) { 308 } 309 } 310 311 315 class ClassVerifier extends ClassAdapter implements Opcodes { 316 317 private String name; 318 319 public ClassVerifier (ClassVisitor cv) { 320 super(cv); 321 } 322 323 public void visit ( 324 final int version, 325 final int access, 326 final String name, 327 final String signature, 328 final String superName, 329 final String [] interfaces) 330 { 331 this.name = name; 332 333 for (int i = 0; i < interfaces.length; i++) { 334 if( interfaces[i].startsWith("java/") ) { 335 if( ! cldcMembers.keySet().contains(interfaces[i]) ) { 336 log(name + ": must not use " + interfaces[i] + "(not in CLDC API)"); 337 ++errors; 338 } 339 } 340 } 341 342 cv.visit(version, access, name, signature, superName, interfaces); 343 } 344 345 346 public FieldVisitor visitField ( 347 int access, 348 String name, 349 String desc, 350 String signature, 351 Object value) 352 { 353 return cv.visitField(access, name, desc,signature, value); 354 } 355 356 public MethodVisitor visitMethod ( 357 final int access, 358 final String name, 359 final String desc, 360 final String signature, 361 final String [] exceptions) 362 { 363 return new CodeVerifier( 364 this, cv.visitMethod(access, name, desc, signature, exceptions)); 365 } 366 367 } 368 369 class CodeVerifier extends MethodAdapter implements Opcodes { 370 371 private ClassVerifier c; 372 private String lastMethodCallInsn; 373 private boolean mustNotUseResult; 374 375 public CodeVerifier (ClassVerifier c, MethodVisitor mv) { 376 super(mv); 377 this.c = c; 378 } 379 380 private void check (int opcode) { 381 if (mustNotUseResult && opcode != POP) { 382 log(c.name + ": must not use result of " + lastMethodCallInsn); 383 ++errors; 384 } 385 mustNotUseResult = false; 386 } 387 388 public void visitInsn (final int opcode) { 389 check(opcode); 390 mv.visitInsn(opcode); 391 } 392 393 public void visitIntInsn (final int opcode, final int operand) { 394 check(opcode); 395 mv.visitIntInsn(opcode, operand); 396 } 397 398 public void visitVarInsn (final int opcode, final int var) { 399 check(opcode); 400 mv.visitVarInsn(opcode, var); 401 } 402 403 public void visitTypeInsn (final int opcode, final String desc) { 404 check(opcode); 405 mv.visitTypeInsn(opcode, desc); 406 } 407 408 public void visitFieldInsn ( 409 final int opcode, 410 final String owner, 411 final String name, 412 final String desc) 413 { 414 check(opcode); 415 if (cldcAPI != null && owner.startsWith("java")) { 416 String key = owner+","+name; 417 if (!cldcAPI.contains(key)) { 418 log(c.name + ": must not use " + key + "(not in CLDC API)"); 419 ++errors; 420 } 421 } 422 mv.visitFieldInsn(opcode, owner, name, desc); 423 } 424 425 public void visitMethodInsn ( 426 final int opcode, 427 final String owner, 428 final String name, 429 final String desc) 430 { 431 check(opcode); 432 String key = owner + "," + name + desc; 433 if (cldcAPI != null && owner.startsWith("java")) { 434 if (!cldcAPI.contains(key)) { 435 log(c.name + ": must not use " + key + " (not in CLDC API)"); 436 ++errors; 437 } 438 } 439 mv.visitMethodInsn(opcode, owner, name, desc); 440 } 441 442 public void visitJumpInsn (final int opcode, final Label label) { 443 check(opcode); 444 mv.visitJumpInsn(opcode, label); 445 } 446 447 public void visitLdcInsn (final Object cst) { 448 check(LDC); 449 mv.visitLdcInsn(cst); 450 } 451 452 public void visitIincInsn (final int var, final int increment) { 453 check(IINC); 454 mv.visitIincInsn(var, increment); 455 } 456 457 public void visitTableSwitchInsn ( 458 final int min, 459 final int max, 460 final Label dflt, 461 final Label labels[]) 462 { 463 check(TABLESWITCH); 464 mv.visitTableSwitchInsn(min, max, dflt, labels); 465 } 466 467 public void visitLookupSwitchInsn ( 468 final Label dflt, 469 final int keys[], 470 final Label labels[]) 471 { 472 check(LOOKUPSWITCH); 473 mv.visitLookupSwitchInsn(dflt, keys, labels); 474 } 475 476 public void visitMultiANewArrayInsn (final String desc, final int dims) { 477 check(MULTIANEWARRAY); 478 mv.visitMultiANewArrayInsn(desc, dims); 479 } 480 } 481 } 482 | Popular Tags |