1 19 20 package jode.decompiler; 21 import jode.GlobalOptions; 22 import jode.type.MethodType; 23 import jode.type.Type; 24 import jode.bytecode.ClassInfo; 25 import jode.bytecode.FieldInfo; 26 import jode.bytecode.MethodInfo; 27 import jode.bytecode.InnerClassInfo; 28 import jode.bytecode.ConstantPool; 29 import jode.expr.Expression; 30 import jode.expr.ThisOperator; 31 import jode.flow.TransformConstructors; 32 import jode.flow.StructuredBlock; 33 import jode.util.SimpleSet; 34 35 import java.lang.reflect.Modifier ; 36 import java.util.NoSuchElementException ; 37 import java.util.Vector ; 38 import java.util.Enumeration ; 39 import java.io.IOException ; 40 41 import java.util.Collection ; 42 import java.util.Set ; 43 44 public class ClassAnalyzer 45 implements Scope, Declarable, ClassDeclarer 46 { 47 ImportHandler imports; 48 ClassInfo clazz; 49 ClassDeclarer parent; 50 ProgressListener progressListener; 51 52 55 private static double INITIALIZE_COMPLEXITY = 0.03; 56 59 private static double STEP_COMPLEXITY = 0.03; 60 64 private static int STRICTFP = 0x800; 65 66 double methodComplexity = 0.0; 67 double innerComplexity = 0.0; 68 69 String name; 70 StructuredBlock[] blockInitializers; 71 FieldAnalyzer[] fields; 72 MethodAnalyzer[] methods; 73 ClassAnalyzer[] inners; 74 int modifiers; 75 76 TransformConstructors constrAna; 77 MethodAnalyzer staticConstructor; 78 MethodAnalyzer[] constructors; 79 80 OuterValues outerValues; 81 82 public ClassAnalyzer(ClassDeclarer parent, 83 ClassInfo clazz, ImportHandler imports, 84 Expression[] outerValues) 85 { 86 clazz.loadInfo(clazz.MOSTINFO); 87 this.parent = parent; 88 this.clazz = clazz; 89 this.imports = imports; 90 if (outerValues != null) 91 this.outerValues = new OuterValues(this, outerValues); 92 modifiers = clazz.getModifiers(); 93 94 if (parent != null) { 95 InnerClassInfo[] outerInfos = clazz.getOuterClasses(); 96 if (outerInfos[0].outer == null || outerInfos[0].name == null) { 97 if (parent instanceof ClassAnalyzer) 98 throw new jode.AssertError 99 ("ClassInfo Attributes are inconsistent: " 100 + clazz.getName()); 101 } else { 102 if (!(parent instanceof ClassAnalyzer) 103 || !(((ClassAnalyzer) parent).clazz.getName() 104 .equals(outerInfos[0].outer)) 105 || outerInfos[0].name == null) 106 throw new jode.AssertError 107 ("ClassInfo Attributes are inconsistent: " 108 + clazz.getName()); 109 } 110 name = outerInfos[0].name; 111 modifiers = outerInfos[0].modifiers; 112 } else { 113 name = clazz.getName(); 114 int dot = name.lastIndexOf('.'); 115 if (dot >= 0) 116 name = name.substring(dot+1); 117 } 118 } 119 120 public ClassAnalyzer(ClassDeclarer parent, 121 ClassInfo clazz, ImportHandler imports) 122 { 123 this(parent, clazz, imports, null); 124 } 125 126 public ClassAnalyzer(ClassInfo clazz, ImportHandler imports) 127 { 128 this(null, clazz, imports); 129 } 130 131 public final boolean isStatic() { 132 return Modifier.isStatic(modifiers); 133 } 134 135 public final boolean isStrictFP() { 136 return (modifiers & STRICTFP) != 0; 137 } 138 139 public FieldAnalyzer getField(int index) { 140 return fields[index]; 141 } 142 143 public int getFieldIndex(String fieldName, Type fieldType) { 144 for (int i=0; i< fields.length; i++) { 145 if (fields[i].getName().equals(fieldName) 146 && fields[i].getType().equals(fieldType)) 147 return i; 148 } 149 return -1; 150 } 151 152 public MethodAnalyzer getMethod(String methodName, MethodType methodType) { 153 for (int i=0; i< methods.length; i++) { 154 if (methods[i].getName().equals(methodName) 155 && methods[i].getType().equals(methodType)) 156 return methods[i]; 157 } 158 return null; 159 } 160 161 public int getModifiers() { 162 return modifiers; 163 } 164 165 public ClassDeclarer getParent() { 166 return parent; 167 } 168 169 public void setParent(ClassDeclarer newParent) { 170 this.parent = newParent; 171 } 172 173 public ClassInfo getClazz() { 174 return clazz; 175 } 176 177 178 public String getName() { 179 return name; 180 } 181 182 public void setName(String name) { 183 this.name = name; 184 } 185 186 public OuterValues getOuterValues() { 187 return outerValues; 188 } 189 190 public void addBlockInitializer(int index, StructuredBlock initializer) { 191 if (blockInitializers[index] == null) 192 blockInitializers[index] = initializer; 193 else 194 blockInitializers[index].appendBlock(initializer); 195 } 196 197 public void initialize() { 198 FieldInfo[] finfos = clazz.getFields(); 199 MethodInfo[] minfos = clazz.getMethods(); 200 InnerClassInfo[] innerInfos = clazz.getInnerClasses(); 201 202 if (finfos == null) { 203 206 return; 207 } 208 209 if ((Options.options & Options.OPTION_INNER) != 0 210 && innerInfos != null) { 211 212 Expression[] outerThis = new Expression[] { 213 new ThisOperator(clazz) 214 }; 215 216 int innerCount = innerInfos.length; 217 inners = new ClassAnalyzer[innerCount]; 218 for (int i=0; i < innerCount; i++) { 219 ClassInfo ci = ClassInfo.forName(innerInfos[i].inner); 220 inners[i] = new ClassAnalyzer 221 (this, ci, imports, 222 Modifier.isStatic(innerInfos[i].modifiers) 223 ? null : outerThis); 224 } 225 } else 226 inners = new ClassAnalyzer[0]; 227 228 fields = new FieldAnalyzer[finfos.length]; 229 methods = new MethodAnalyzer[minfos.length]; 230 blockInitializers = new StructuredBlock[finfos.length+1]; 231 for (int j=0; j < finfos.length; j++) 232 fields[j] = new FieldAnalyzer(this, finfos[j], imports); 233 234 staticConstructor = null; 235 Vector constrVector = new Vector (); 236 for (int j=0; j < methods.length; j++) { 237 methods[j] = new MethodAnalyzer(this, minfos[j], imports); 238 239 if (methods[j].isConstructor()) { 240 if (methods[j].isStatic()) 241 staticConstructor = methods[j]; 242 else 243 constrVector.addElement(methods[j]); 244 245 253 if (methods[j].isStrictFP()) 254 modifiers |= STRICTFP; 255 } 256 methodComplexity += methods[j].getComplexity(); 257 } 258 259 constructors = new MethodAnalyzer[constrVector.size()]; 260 constrVector.copyInto(constructors); 261 262 for (int j=0; j < inners.length; j++) { 264 inners[j].initialize(); 265 innerComplexity += inners[j].getComplexity(); 266 } 267 } 268 269 273 public double getComplexity() { 274 return (methodComplexity + innerComplexity); 275 } 276 277 public void analyze(ProgressListener pl, double done, double scale) { 278 if (GlobalOptions.verboseLevel > 0) 279 GlobalOptions.err.println("Class " + name); 280 double subScale = scale / methodComplexity; 281 if (pl != null) 282 pl.updateProgress(done, name); 283 284 imports.useClass(clazz); 285 if (clazz.getSuperclass() != null) 286 imports.useClass(clazz.getSuperclass()); 287 ClassInfo[] interfaces = clazz.getInterfaces(); 288 for (int j=0; j< interfaces.length; j++) 289 imports.useClass(interfaces[j]); 290 291 if (fields == null) { 292 295 return; 296 } 297 298 299 constrAna = null; 301 if (constructors.length > 0) { 302 for (int j=0; j< constructors.length; j++) 303 { 304 if (pl != null) { 305 double constrCompl = constructors[j].getComplexity() 306 * subScale; 307 if (constrCompl > STEP_COMPLEXITY) 308 constructors[j].analyze(pl, done, constrCompl); 309 else { 310 pl.updateProgress(done, name); 311 constructors[j].analyze(null, 0.0, 0.0); 312 } 313 done += constrCompl; 314 } else 315 constructors[j].analyze(null, 0.0, 0.0); 316 } 317 constrAna = new TransformConstructors(this, false, constructors); 318 constrAna.removeSynthInitializers(); 319 } 320 if (staticConstructor != null) { 321 if (pl != null) { 322 double constrCompl 323 = staticConstructor.getComplexity() * subScale; 324 if (constrCompl > STEP_COMPLEXITY) 325 staticConstructor.analyze(pl, done, constrCompl); 326 else { 327 pl.updateProgress(done, name); 328 staticConstructor.analyze(null, 0.0, 0.0); 329 } 330 done += constrCompl; 331 } else 332 staticConstructor.analyze(null, 0.0, 0.0); 333 } 334 335 if ((Options.options & Options.OPTION_IMMEDIATE) != 0) 339 return; 340 341 for (int j=0; j < fields.length; j++) 343 fields[j].analyze(); 344 345 for (int j=0; j < methods.length; j++) { 347 if (!methods[j].isConstructor()) 348 if (pl != null) { 349 double methodCompl = methods[j].getComplexity() 350 * subScale; 351 if (methodCompl > STEP_COMPLEXITY) 352 methods[j].analyze(pl, done, methodCompl); 353 else { 354 pl.updateProgress(done, methods[j].getName()); 355 methods[j].analyze(null, 0.0, 0.0); 356 } 357 done += methodCompl; 358 } else 359 methods[j].analyze(null, 0.0, 0.0); 360 } 361 } 362 363 public void analyzeInnerClasses(ProgressListener pl, 364 double done, double scale) { 365 double subScale = scale / innerComplexity; 366 if ((Options.options & Options.OPTION_IMMEDIATE) != 0) 370 return; 371 372 for (int j=0; j < inners.length; j++) { 374 if (pl != null) { 375 double innerCompl = inners[j].getComplexity() * subScale; 376 if (innerCompl > STEP_COMPLEXITY) { 377 double innerscale = subScale * inners[j].methodComplexity; 378 inners[j].analyze(pl, done, innerscale); 379 inners[j].analyzeInnerClasses(null, done + innerscale, 380 innerCompl - innerscale); 381 } else { 382 pl.updateProgress(done, inners[j].name); 383 inners[j].analyze(null, 0.0, 0.0); 384 inners[j].analyzeInnerClasses(null, 0.0, 0.0); 385 } 386 done += innerCompl; 387 } else { 388 inners[j].analyze(null, 0.0, 0.0); 389 inners[j].analyzeInnerClasses(null, 0.0, 0.0); 390 } 391 } 392 393 for (int j=0; j < methods.length; j++) 395 methods[j].analyzeInnerClasses(); 396 397 } 398 399 public void makeDeclaration(Set done) { 400 if (constrAna != null) 401 constrAna.transform(); 402 if (staticConstructor != null) { 403 new TransformConstructors 404 (this, true, new MethodAnalyzer[] { staticConstructor }) 405 .transform(); 406 } 407 408 if ((Options.options & Options.OPTION_IMMEDIATE) != 0) 412 return; 413 414 for (int j=0; j < fields.length; j++) 415 fields[j].makeDeclaration(done); 416 for (int j=0; j < inners.length; j++) 417 inners[j].makeDeclaration(done); 418 for (int j=0; j < methods.length; j++) 419 methods[j].makeDeclaration(done); 420 } 421 422 public void dumpDeclaration(TabbedPrintWriter writer) throws IOException 423 { 424 dumpDeclaration(writer, null, 0.0, 0.0); 425 } 426 427 public void dumpDeclaration(TabbedPrintWriter writer, 428 ProgressListener pl, double done, double scale) 429 throws IOException 430 { 431 if (fields == null) { 432 435 return; 436 } 437 438 writer.startOp(writer.NO_PAREN, 0); 439 440 int modifiedModifiers = modifiers & ~(Modifier.SYNCHRONIZED 441 | STRICTFP); 442 if (clazz.isInterface()) 443 444 modifiedModifiers &= ~Modifier.ABSTRACT; 445 if (parent instanceof MethodAnalyzer) { 446 447 modifiedModifiers &= ~Modifier.PRIVATE; 448 449 if (name == null) 450 modifiedModifiers &= ~Modifier.FINAL; 451 } 452 String modif = Modifier.toString(modifiedModifiers); 453 if (modif.length() > 0) 454 writer.print(modif + " "); 455 if (isStrictFP()) { 456 459 writer.print("strictfp "); 460 } 461 462 if (!clazz.isInterface()) 463 writer.print("class "); 464 writer.print(name); 465 ClassInfo superClazz = clazz.getSuperclass(); 466 if (superClazz != null && 467 superClazz != ClassInfo.javaLangObject) { 468 writer.breakOp(); 469 writer.print(" extends " + (writer.getClassString 470 (superClazz, Scope.CLASSNAME))); 471 } 472 ClassInfo[] interfaces = clazz.getInterfaces(); 473 if (interfaces.length > 0) { 474 writer.breakOp(); 475 writer.print(clazz.isInterface() ? " extends " : " implements "); 476 writer.startOp(writer.EXPL_PAREN, 1); 477 for (int i=0; i < interfaces.length; i++) { 478 if (i > 0) { 479 writer.print(", "); 480 writer.breakOp(); 481 } 482 writer.print(writer.getClassString 483 (interfaces[i], Scope.CLASSNAME)); 484 } 485 writer.endOp(); 486 } 487 writer.println(); 488 489 writer.openBraceClass(); 490 writer.tab(); 491 dumpBlock(writer, pl, done, scale); 492 writer.untab(); 493 writer.closeBraceClass(); 494 } 495 496 public void dumpBlock(TabbedPrintWriter writer) 497 throws IOException 498 { 499 dumpBlock(writer, null, 0.0, 0.0); 500 } 501 502 public void dumpBlock(TabbedPrintWriter writer, 503 ProgressListener pl, double done, double scale) 504 throws IOException 505 { 506 double subScale = scale / getComplexity(); 507 writer.pushScope(this); 508 boolean needFieldNewLine = false; 509 boolean needNewLine = false; 510 Set declared = null; 511 if ((Options.options & Options.OPTION_IMMEDIATE) != 0) 512 declared = new SimpleSet(); 513 for (int i=0; i< fields.length; i++) { 514 if (blockInitializers[i] != null) { 515 if (needNewLine) 516 writer.println(); 517 writer.openBrace(); 518 writer.tab(); 519 blockInitializers[i].dumpSource(writer); 520 writer.untab(); 521 writer.closeBrace(); 522 needFieldNewLine = needNewLine = true; 523 } 524 if ((Options.options & Options.OPTION_IMMEDIATE) != 0) { 525 fields[i].analyze(); 527 fields[i].makeDeclaration(declared); 528 } 529 if (fields[i].skipWriting()) 530 continue; 531 if (needFieldNewLine) 532 writer.println(); 533 fields[i].dumpSource(writer); 534 needNewLine = true; 535 } 536 if (blockInitializers[fields.length] != null) { 537 if (needNewLine) 538 writer.println(); 539 writer.openBrace(); 540 writer.tab(); 541 blockInitializers[fields.length].dumpSource(writer); 542 writer.untab(); 543 writer.closeBrace(); 544 needNewLine = true; 545 } 546 for (int i=0; i< inners.length; i++) { 547 if (needNewLine) 548 writer.println(); 549 550 if ((Options.options & Options.OPTION_IMMEDIATE) != 0) { 551 inners[i].analyze(null, 0.0, 0.0); 553 inners[i].analyzeInnerClasses(null, 0.0, 0.0); 554 inners[i].makeDeclaration(declared); 555 } 556 557 if (pl != null) { 558 double innerCompl = inners[i].getComplexity() * subScale; 559 if (innerCompl > STEP_COMPLEXITY) 560 inners[i].dumpSource(writer, pl, done, innerCompl); 561 else { 562 pl.updateProgress(done, name); 563 inners[i].dumpSource(writer); 564 } 565 done += innerCompl; 566 } else 567 inners[i].dumpSource(writer); 568 needNewLine = true; 569 } 570 for (int i=0; i< methods.length; i++) { 571 if ((Options.options & Options.OPTION_IMMEDIATE) != 0) { 572 if (!methods[i].isConstructor()) 574 methods[i].analyze(null, 0.0, 0.0); 575 methods[i].analyzeInnerClasses(); 576 methods[i].makeDeclaration(declared); 577 } 578 579 if (methods[i].skipWriting()) 580 continue; 581 if (needNewLine) 582 writer.println(); 583 584 if (pl != null) { 585 double methodCompl = methods[i].getComplexity() * subScale; 586 pl.updateProgress(done, methods[i].getName()); 587 methods[i].dumpSource(writer); 588 done += methodCompl; 589 } else 590 methods[i].dumpSource(writer); 591 needNewLine = true; 592 } 593 writer.popScope(); 594 clazz.dropInfo(clazz.KNOWNATTRIBS | clazz.UNKNOWNATTRIBS); 595 } 596 597 public void dumpSource(TabbedPrintWriter writer) 598 throws IOException 599 { 600 dumpSource(writer, null, 0.0, 0.0); 601 } 602 603 public void dumpSource(TabbedPrintWriter writer, 604 ProgressListener pl, double done, double scale) 605 throws IOException 606 { 607 dumpDeclaration(writer, pl, done, scale); 608 writer.println(); 609 } 610 611 public void dumpJavaFile(TabbedPrintWriter writer) 612 throws IOException { 613 dumpJavaFile(writer, null); 614 } 615 616 public void dumpJavaFile(TabbedPrintWriter writer, ProgressListener pl) 617 throws IOException { 618 imports.init(clazz.getName()); 619 LocalInfo.init(); 620 initialize(); 621 double done = 0.05; 622 double scale = (0.75) * methodComplexity 623 / (methodComplexity + innerComplexity); 624 analyze(pl, INITIALIZE_COMPLEXITY, scale); 625 done += scale; 626 analyzeInnerClasses(pl, done, 0.8 - done); 627 makeDeclaration(new SimpleSet()); 628 imports.dumpHeader(writer); 629 dumpSource(writer, pl, 0.8, 0.2); 630 if (pl != null) 631 pl.updateProgress(1.0, name); 632 } 633 634 public boolean isScopeOf(Object obj, int scopeType) { 635 if (clazz.equals(obj) && scopeType == CLASSSCOPE) 636 return true; 637 return false; 638 } 639 640 static int serialnr = 0; 641 public void makeNameUnique() { 642 name = name + "_" + serialnr++ + "_"; 643 } 644 645 public boolean conflicts(String name, int usageType) { 646 return conflicts(clazz, name, usageType); 647 } 648 649 private static boolean conflicts(ClassInfo info, 650 String name, int usageType) { 651 while (info != null) { 652 if (usageType == NOSUPERMETHODNAME || usageType == METHODNAME) { 653 MethodInfo[] minfos = info.getMethods(); 654 for (int i = 0; i< minfos.length; i++) 655 if (minfos[i].getName().equals(name)) 656 return true; 657 } 658 if (usageType == NOSUPERFIELDNAME || usageType == FIELDNAME 659 || usageType == AMBIGUOUSNAME) { 660 FieldInfo[] finfos = info.getFields(); 661 for (int i=0; i < finfos.length; i++) { 662 if (finfos[i].getName().equals(name)) 663 return true; 664 } 665 } 666 if (usageType == CLASSNAME || usageType == AMBIGUOUSNAME) { 667 InnerClassInfo[] iinfos = info.getInnerClasses(); 668 if (iinfos != null) { 669 for (int i=0; i < iinfos.length; i++) { 670 if (iinfos[i].name.equals(name)) 671 return true; 672 } 673 } 674 } 675 if (usageType == NOSUPERFIELDNAME 676 || usageType == NOSUPERMETHODNAME) 677 return false; 678 679 ClassInfo[] ifaces = info.getInterfaces(); 680 for (int i = 0; i < ifaces.length; i++) 681 if (conflicts(ifaces[i], name, usageType)) 682 return true; 683 info = info.getSuperclass(); 684 } 685 return false; 686 } 687 688 697 public ClassAnalyzer getClassAnalyzer(ClassInfo cinfo) { 698 if (cinfo == getClazz()) 699 return this; 700 if (parent == null) 701 return null; 702 return getParent().getClassAnalyzer(cinfo); 703 } 704 705 711 public ClassAnalyzer getInnerClassAnalyzer(String name) { 712 713 int innerCount = inners.length; 714 for (int i=0; i < innerCount; i++) { 715 if (inners[i].name.equals(name)) 716 return inners[i]; 717 } 718 return null; 719 } 720 721 724 public void fillDeclarables(Collection used) { 725 for (int j=0; j < methods.length; j++) 726 methods[j].fillDeclarables(used); 727 } 728 729 public void addClassAnalyzer(ClassAnalyzer clazzAna) { 730 if (parent != null) 731 parent.addClassAnalyzer(clazzAna); 732 } 733 734 public String toString() { 735 return getClass().getName()+"["+getClazz()+"]"; 736 } 737 } 738 | Popular Tags |