1 19 20 package jode.expr; 21 import java.lang.reflect.Modifier ; 22 23 import jode.decompiler.MethodAnalyzer; 24 import jode.decompiler.MethodAnalyzer; 25 import jode.decompiler.ClassAnalyzer; 26 import jode.decompiler.TabbedPrintWriter; 27 import jode.decompiler.Options; 28 import jode.decompiler.OuterValues; 29 import jode.decompiler.Scope; 30 import jode.GlobalOptions; 31 import jode.bytecode.*; 32 import jode.jvm.*; 33 import jode.type.*; 34 import jode.util.SimpleMap; 35 36 import java.lang.reflect.InvocationTargetException ; 37 import java.util.Hashtable ; 38 import java.util.Collections ; 39 import java.util.Collection ; 40 import java.util.Map ; 41 import java.util.Iterator ; 42 import java.util.Set ; 43 44 public final class InvokeOperator extends Operator 45 implements MatchableOperator { 46 47 public final static int VIRTUAL = 0; 48 public final static int SPECIAL = 1; 49 public final static int STATIC = 2; 50 public final static int CONSTRUCTOR = 3; 51 public final static int ACCESSSPECIAL = 4; 52 53 57 MethodAnalyzer methodAnalyzer; 58 int methodFlag; 59 MethodType methodType; 60 String methodName; 61 Reference ref; 62 int skippedArgs; 63 Type classType; 64 Type[] hints; 65 66 79 private final static Hashtable hintTypes = new Hashtable (); 80 81 static { 82 98 Type tCharHint = new IntegerType(IntegerType.IT_I, IntegerType.IT_C); 99 Type[] hintC = new Type[] { tCharHint }; 100 Type[] hint0C = new Type[] { null, tCharHint }; 101 Type[] hint0C0 = new Type[] { null, tCharHint, null }; 102 103 Map hintString0CMap = new SimpleMap 104 (Collections.singleton 105 (new SimpleMap.SimpleEntry(Type.tString, hint0C))); 106 Map hintString0C0Map = new SimpleMap 107 (Collections.singleton 108 (new SimpleMap.SimpleEntry(Type.tString, hint0C0))); 109 hintTypes.put("indexOf.(I)I", hintString0CMap); 110 hintTypes.put("lastIndexOf.(I)I", hintString0CMap); 111 hintTypes.put("indexOf.(II)I", hintString0C0Map); 112 hintTypes.put("lastIndexOf.(II)I", hintString0C0Map); 113 hintTypes.put("write.(I)V", new SimpleMap 114 (Collections.singleton 115 (new SimpleMap.SimpleEntry 116 (Type.tClass("java.io.Writer"), hint0C)))); 117 hintTypes.put("read.()I", new SimpleMap 118 (Collections.singleton 119 (new SimpleMap.SimpleEntry 120 (Type.tClass("java.io.Reader"), hintC)))); 121 hintTypes.put("unread.(I)V", new SimpleMap 122 (Collections.singleton 123 (new SimpleMap.SimpleEntry 124 (Type.tClass("java.io.PushbackReader"), hint0C)))); 125 } 126 127 128 public InvokeOperator(MethodAnalyzer methodAnalyzer, 129 int methodFlag, Reference reference) { 130 super(Type.tUnknown, 0); 131 this.ref = reference; 132 this.methodType = Type.tMethod(reference.getType()); 133 this.methodName = reference.getName(); 134 this.classType = Type.tType(reference.getClazz()); 135 this.hints = null; 136 Map allHints = (Map) hintTypes.get(methodName+"."+methodType); 137 if (allHints != null) { 138 for (Iterator i = allHints.entrySet().iterator(); i.hasNext();) { 139 Map.Entry e = (Map.Entry) i.next(); 140 if (classType.isOfType(((Type)e.getKey()).getSubType())) { 141 this.hints = (Type[]) e.getValue(); 142 break; 143 } 144 } 145 } 146 if (hints != null && hints[0] != null) 147 this.type = hints[0]; 148 else 149 this.type = methodType.getReturnType(); 150 this.methodAnalyzer = methodAnalyzer; 151 this.methodFlag = methodFlag; 152 if (methodFlag == STATIC) 153 methodAnalyzer.useType(classType); 154 skippedArgs = (methodFlag == STATIC ? 0 : 1); 155 initOperands(skippedArgs + methodType.getParameterTypes().length); 156 checkAnonymousClasses(); 157 } 158 159 public final boolean isStatic() { 160 return methodFlag == STATIC; 161 } 162 163 public MethodType getMethodType() { 164 return methodType; 165 } 166 167 public String getMethodName() { 168 return methodName; 169 } 170 171 private static MethodInfo getMethodInfo(ClassInfo clazz, 172 String name, String type) { 173 while (clazz != null) { 174 MethodInfo method = clazz.findMethod(name, type); 175 if (method != null) 176 return method; 177 clazz = clazz.getSuperclass(); 178 } 179 return null; 180 } 181 public MethodInfo getMethodInfo() { 182 ClassInfo clazz; 183 if (ref.getClazz().charAt(0) == '[') 184 clazz = ClassInfo.javaLangObject; 185 else 186 clazz = TypeSignature.getClassInfo(ref.getClazz()); 187 return getMethodInfo(clazz, ref.getName(), ref.getType()); 188 } 189 190 public Type getClassType() { 191 return classType; 192 } 193 194 public int getPriority() { 195 return 950; 196 } 197 198 public void checkAnonymousClasses() { 199 if (methodFlag != CONSTRUCTOR 200 || (Options.options & Options.OPTION_ANON) == 0) 201 return; 202 InnerClassInfo outer = getOuterClassInfo(getClassInfo()); 203 if (outer != null && (outer.outer == null || outer.name == null)) { 204 methodAnalyzer.addAnonymousConstructor(this); 205 } 206 } 207 208 public void updateSubTypes() { 209 int offset = 0; 210 if (!isStatic()) { 211 subExpressions[offset++].setType(Type.tSubType(getClassType())); 212 } 213 Type[] paramTypes = methodType.getParameterTypes(); 214 for (int i=0; i < paramTypes.length; i++) { 215 Type pType = (hints != null && hints[i+1] != null) 216 ? hints[i+1] : paramTypes[i]; 217 subExpressions[offset++].setType(Type.tSubType(pType)); 218 } 219 } 220 221 public void updateType() { 222 } 223 224 227 public void makeNonVoid() { 228 if (type != Type.tVoid) 229 throw new jode.AssertError("already non void"); 230 ClassInfo clazz = getClassInfo(); 231 InnerClassInfo outer = getOuterClassInfo(clazz); 232 if (outer != null && outer.name == null) { 233 234 if (clazz.getInterfaces().length > 0) 235 type = Type.tClass(clazz.getInterfaces()[0]); 236 else 237 type = Type.tClass(clazz.getSuperclass()); 238 } else 239 type = subExpressions[0].getType(); 240 } 241 242 public boolean isConstructor() { 243 return methodFlag == CONSTRUCTOR; 244 } 245 246 public ClassInfo getClassInfo() { 247 if (classType instanceof ClassInterfacesType) 248 return ((ClassInterfacesType) classType).getClassInfo(); 249 return null; 250 } 251 252 255 public boolean isThis() { 256 return getClassInfo() == methodAnalyzer.getClazz(); 257 } 258 259 public InnerClassInfo getOuterClassInfo(ClassInfo ci) { 260 if (ci != null) { 261 InnerClassInfo[] outers = ci.getOuterClasses(); 262 if (outers != null) 263 return outers[0]; 264 } 265 return null; 266 } 267 268 275 public ClassAnalyzer getClassAnalyzer() { 276 if ((Options.options & 277 (Options.OPTION_ANON | Options.OPTION_INNER)) == 0) 278 return null; 279 280 ClassInfo callee = getClassInfo(); 281 if (callee == null) 282 return null; 283 284 int nested = 0; 285 InnerClassInfo[] outers = callee.getOuterClasses(); 286 if ((Options.options & Options.OPTION_INNER) != 0 287 && outers != null) { 288 292 nested = outers.length; 293 if (outers[nested - 1].outer == null 294 || outers[nested - 1].name == null) 295 nested--; 296 297 if (nested > 0) 298 callee = ClassInfo.forName(outers[nested - 1].outer); 299 } 300 301 302 ClassAnalyzer ana = methodAnalyzer.getClassAnalyzer(callee); 303 304 if (ana == null) { 305 308 ana = methodAnalyzer.getClassAnalyzer(); 309 while (callee != ana.getClazz()) { 310 if (ana.getParent() == null) 311 return null; 312 if (ana.getParent() instanceof MethodAnalyzer 313 && (Options.options & Options.OPTION_ANON) != 0) 314 ana = ((MethodAnalyzer) ana.getParent()) 315 .getClassAnalyzer(); 316 else if (ana.getParent() instanceof ClassAnalyzer 317 && (Options.options 318 & Options.OPTION_INNER) != 0) 319 ana = (ClassAnalyzer) ana.getParent(); 320 else 321 throw new jode.AssertError 322 ("Unknown parent: "+ana+": "+ana.getParent()); 323 } 324 } 325 326 327 while (nested > 0) { 328 nested--; 329 ana = ana.getInnerClassAnalyzer(outers[nested].name); 330 if (ana == null) 331 return null; 332 } 333 return ana; 334 } 335 336 340 public boolean isOuter() { 341 if (classType instanceof ClassInterfacesType) { 342 ClassInfo clazz = ((ClassInterfacesType) classType).getClassInfo(); 343 ClassAnalyzer ana = methodAnalyzer.getClassAnalyzer(); 344 while (true) { 345 if (clazz == ana.getClazz()) 346 return true; 347 if (ana.getParent() == null) 348 break; 349 if (ana.getParent() instanceof MethodAnalyzer 350 && (Options.options & Options.OPTION_ANON) != 0) 351 ana = ((MethodAnalyzer) ana.getParent()) 352 .getClassAnalyzer(); 353 else if (ana.getParent() instanceof ClassAnalyzer 354 && (Options.options 355 & Options.OPTION_INNER) != 0) 356 ana = (ClassAnalyzer) ana.getParent(); 357 else 358 throw new jode.AssertError 359 ("Unknown parent: "+ana+": "+ana.getParent()); 360 } 361 } 362 return false; 363 } 364 365 372 public MethodAnalyzer getMethodAnalyzer() { 373 ClassAnalyzer ana = getClassAnalyzer(); 374 if (ana == null) 375 return null; 376 return ana.getMethod(methodName, methodType); 377 } 378 379 383 public boolean isSuperOrThis() { 384 ClassInfo clazz = getClassInfo(); 385 if (clazz != null) { 386 return clazz.superClassOf(methodAnalyzer.getClazz()); 387 } 388 return false; 389 } 390 391 public boolean isConstant() { 392 if ((Options.options & Options.OPTION_ANON) == 0) 393 return super.isConstant(); 394 395 ClassInfo clazz = getClassInfo(); 396 InnerClassInfo outer = getOuterClassInfo(clazz); 397 ClassAnalyzer clazzAna = methodAnalyzer.getClassAnalyzer(clazz); 398 if (clazzAna != null 399 && outer != null && outer.outer == null && outer.name != null 400 && clazzAna.getParent() == methodAnalyzer) { 401 404 return false; 405 } 406 return super.isConstant(); 407 } 408 409 412 public boolean matches(Operator loadop) { 413 return (loadop instanceof InvokeOperator 414 || loadop instanceof GetFieldOperator); 415 } 416 417 421 public boolean isGetClass() { 422 MethodAnalyzer mana = getMethodAnalyzer(); 423 if (mana == null) 424 return false; 425 SyntheticAnalyzer synth = getMethodAnalyzer().getSynthetic(); 426 return (synth != null 427 && synth.getKind() == SyntheticAnalyzer.GETCLASS); 428 } 429 430 class Environment extends SimpleRuntimeEnvironment { 431 432 Interpreter interpreter; 433 String classSig; 434 435 public Environment(String interpretedClassSig) { 436 classSig = interpretedClassSig.intern(); 437 } 438 439 public Object invokeMethod(Reference ref, boolean isVirtual, 440 Object cls, Object [] params) 441 throws InterpreterException, InvocationTargetException { 442 if (cls == null && ref.getClazz().equals(classSig)) { 443 String clazzName = ref.getClazz(); 444 clazzName = clazzName.substring(1, ref.getClazz().length() - 1) 445 .replace('/', '.'); 446 BytecodeInfo info = ClassInfo.forName(clazzName) 447 .findMethod(ref.getName(), ref.getType()) 448 .getBytecode(); 449 if (info != null) 450 return interpreter.interpretMethod(info, null, params); 451 throw new InterpreterException 452 ("Can't interpret static native method: "+ref); 453 } else 454 return super.invokeMethod(ref, isVirtual, cls, params); 455 } 456 } 457 458 public ConstOperator deobfuscateString(ConstOperator op) { 459 ClassAnalyzer clazz = methodAnalyzer.getClassAnalyzer(); 460 MethodAnalyzer ma = clazz.getMethod(methodName, methodType); 461 if (ma == null) 462 return null; 463 Environment env = new Environment("L"+methodAnalyzer.getClazz() 464 .getName().replace('.','/')+";"); 465 Interpreter interpreter = new Interpreter(env); 466 env.interpreter = interpreter; 467 468 String result; 469 try { 470 result = (String ) interpreter.interpretMethod 471 (ma.getBytecodeInfo(), null, new Object [] { op.getValue() }); 472 } catch (InterpreterException ex) { 473 if ((GlobalOptions.debuggingFlags & 474 GlobalOptions.DEBUG_INTERPRT) != 0) { 475 GlobalOptions.err.println("Warning: Can't interpret method " 476 +methodName); 477 ex.printStackTrace(GlobalOptions.err); 478 } 479 return null; 480 } catch (InvocationTargetException ex) { 481 if ((GlobalOptions.debuggingFlags & 482 GlobalOptions.DEBUG_INTERPRT) != 0) { 483 GlobalOptions.err.println("Warning: Interpreted method throws" 484 +" an uncaught exception: "); 485 ex.getTargetException().printStackTrace(GlobalOptions.err); 486 } 487 return null; 488 } 489 return new ConstOperator(result); 490 } 491 492 public Expression simplifyStringBuffer() { 493 if (getClassType().equals(Type.tStringBuffer)) { 494 if (isConstructor() 495 && subExpressions[0] instanceof NewOperator) { 496 if (methodType.getParameterTypes().length == 0) 497 return EMPTYSTRING; 498 if (methodType.getParameterTypes().length == 1 499 && methodType.getParameterTypes()[0].equals(Type.tString)) 500 return subExpressions[1].simplifyString(); 501 } 502 503 if (!isStatic() 504 && getMethodName().equals("append") 505 && getMethodType().getParameterTypes().length == 1) { 506 507 Expression firstOp = subExpressions[0].simplifyStringBuffer(); 508 if (firstOp == null) 509 return null; 510 511 subExpressions[1] = subExpressions[1].simplifyString(); 512 513 if (firstOp == EMPTYSTRING 514 && subExpressions[1].getType().isOfType(Type.tString)) 515 return subExpressions[1]; 516 517 if (firstOp instanceof StringAddOperator 518 && (((Operator)firstOp).getSubExpressions()[0] 519 == EMPTYSTRING)) 520 firstOp = ((Operator)firstOp).getSubExpressions()[1]; 521 522 Expression secondOp = subExpressions[1]; 523 Type[] paramTypes = new Type[] { 524 Type.tStringBuffer, secondOp.getType().getCanonic() 525 }; 526 if (needsCast(1, paramTypes)) { 527 Type castType = methodType.getParameterTypes()[0]; 528 Operator castOp = new ConvertOperator(castType, castType); 529 castOp.addOperand(secondOp); 530 secondOp = castOp; 531 } 532 Operator result = new StringAddOperator(); 533 result.addOperand(secondOp); 534 result.addOperand(firstOp); 535 return result; 536 } 537 } 538 return null; 539 } 540 541 public Expression simplifyString() { 542 if (getMethodName().equals("toString") 543 && !isStatic() 544 && getClassType().equals(Type.tStringBuffer) 545 && subExpressions.length == 1) { 546 Expression simple = subExpressions[0].simplifyStringBuffer(); 547 if (simple != null) 548 return simple; 549 } 550 else if (getMethodName().equals("valueOf") 551 && isStatic() 552 && getClassType().equals(Type.tString) 553 && subExpressions.length == 1) { 554 555 if (subExpressions[0].getType().isOfType(Type.tString)) 556 return subExpressions[0]; 557 558 Operator op = new StringAddOperator(); 559 op.addOperand(subExpressions[0]); 560 op.addOperand(EMPTYSTRING); 561 } 562 563 else if (getMethodName().equals("concat") 564 && !isStatic() 565 && getClassType().equals(Type.tString)) { 566 567 Expression result = new StringAddOperator(); 568 Expression right = subExpressions[1].simplify(); 569 if (right instanceof StringAddOperator) { 570 Operator op = (Operator) right; 571 if (op.subExpressions != null 572 && op.subExpressions[0] == EMPTYSTRING) 573 right = op.subExpressions[1]; 574 } 575 result.addOperand(right); 576 result.addOperand(subExpressions[0].simplify()); 577 } 578 else if ((Options.options & Options.OPTION_DECRYPT) != 0 579 && isThis() && isStatic() 580 && methodType.getParameterTypes().length == 1 581 && methodType.getParameterTypes()[0].equals(Type.tString) 582 && methodType.getReturnType().equals(Type.tString)) { 583 584 Expression expr = subExpressions[0].simplifyString(); 585 if (expr instanceof ConstOperator) { 586 expr = deobfuscateString((ConstOperator)expr); 587 if (expr != null) 588 return expr; 589 } 590 } 591 return this; 592 } 593 594 public Expression simplifyAccess() { 595 if (getMethodAnalyzer() != null) { 596 SyntheticAnalyzer synth = getMethodAnalyzer().getSynthetic(); 597 if (synth != null) { 598 int unifyParam = synth.getUnifyParam(); 599 Expression op = null; 600 switch (synth.getKind()) { 601 case SyntheticAnalyzer.ACCESSGETFIELD: 602 op = new GetFieldOperator(methodAnalyzer, false, 603 synth.getReference()); 604 break; 605 case SyntheticAnalyzer.ACCESSGETSTATIC: 606 op = new GetFieldOperator(methodAnalyzer, true, 607 synth.getReference()); 608 break; 609 case SyntheticAnalyzer.ACCESSPUTFIELD: 610 case SyntheticAnalyzer.ACCESSDUPPUTFIELD: 611 op = new StoreInstruction 612 (new PutFieldOperator(methodAnalyzer, false, 613 synth.getReference())); 614 if (synth.getKind() == synth.ACCESSDUPPUTFIELD) 615 ((StoreInstruction) op).makeNonVoid(); 616 break; 617 case SyntheticAnalyzer.ACCESSPUTSTATIC: 618 case SyntheticAnalyzer.ACCESSDUPPUTSTATIC: 619 op = new StoreInstruction 620 (new PutFieldOperator(methodAnalyzer, true, 621 synth.getReference())); 622 if (synth.getKind() == synth.ACCESSDUPPUTSTATIC) 623 ((StoreInstruction) op).makeNonVoid(); 624 break; 625 case SyntheticAnalyzer.ACCESSMETHOD: 626 op = new InvokeOperator(methodAnalyzer, ACCESSSPECIAL, 627 synth.getReference()); 628 break; 629 case SyntheticAnalyzer.ACCESSSTATICMETHOD: 630 op = new InvokeOperator(methodAnalyzer, STATIC, 631 synth.getReference()); 632 break; 633 case SyntheticAnalyzer.ACCESSCONSTRUCTOR: 634 if (subExpressions[unifyParam] instanceof ConstOperator 635 && ((ConstOperator) 636 subExpressions[unifyParam]).getValue() == null) { 637 op = new InvokeOperator(methodAnalyzer, CONSTRUCTOR, 638 synth.getReference()); 639 } 640 break; 641 } 642 643 if (op != null) { 644 if (subExpressions != null) { 645 for (int i=subExpressions.length; i-- > 0; ) { 646 if (i == unifyParam && synth.getKind() 647 == SyntheticAnalyzer.ACCESSCONSTRUCTOR) 648 continue; 650 op = op.addOperand(subExpressions[i]); 651 if (subExpressions[i].getFreeOperandCount() > 0) 652 break; 653 } 654 } 655 return op; 656 } 657 } 658 } 659 return null; 660 } 661 662 public boolean needsCast(int param, Type[] paramTypes) { 663 Type realClassType; 664 if (methodFlag == STATIC) 665 realClassType = classType; 666 else if (param == 0) { 667 if (paramTypes[0] instanceof NullType) 668 return true; 669 if (!(paramTypes[0] instanceof ClassInterfacesType 670 && classType instanceof ClassInterfacesType)) 671 return false; 672 673 ClassInfo clazz = ((ClassInterfacesType) classType).getClassInfo(); 674 ClassInfo parClazz 675 = ((ClassInterfacesType) paramTypes[0]).getClassInfo(); 676 MethodInfo method = getMethodInfo(); 677 if (method == null) 678 679 return false; 680 if (Modifier.isPrivate(method.getModifiers())) 681 return parClazz != clazz; 682 else if ((method.getModifiers() 683 & (Modifier.PROTECTED | Modifier.PUBLIC)) == 0) { 684 687 int lastDot = clazz.getName().lastIndexOf('.'); 688 if (lastDot != parClazz.getName().lastIndexOf('.') 689 || !(parClazz.getName() 690 .startsWith(clazz.getName().substring(0,lastDot+1)))) 691 return true; 692 } 693 return false; 694 } else { 695 realClassType = paramTypes[0]; 696 } 697 698 if (!(realClassType instanceof ClassInterfacesType)) { 699 700 return false; 701 } 702 ClassInfo clazz = ((ClassInterfacesType) realClassType).getClassInfo(); 703 int offset = skippedArgs; 704 705 Type[] myParamTypes = methodType.getParameterTypes(); 706 if (myParamTypes[param-offset].equals(paramTypes[param])) { 707 708 return false; 709 } 710 712 while (clazz != null) { 713 MethodInfo[] methods = clazz.getMethods(); 714 next_method: 715 for (int i=0; i< methods.length; i++) { 716 if (!methods[i].getName().equals(methodName)) 717 718 continue next_method; 719 720 Type[] otherParamTypes 721 = Type.tMethod(methods[i].getType()).getParameterTypes(); 722 if (otherParamTypes.length != myParamTypes.length) { 723 724 continue next_method; 725 } 726 727 if (myParamTypes[param-offset].isOfType 728 (Type.tSubType(otherParamTypes[param-offset]))) { 729 730 continue next_method; 731 } 732 for (int p = offset; p < paramTypes.length; p++) { 733 if (!paramTypes[p] 734 .isOfType(Type.tSubType(otherParamTypes[p-offset]))){ 735 736 continue next_method; 737 } 738 } 739 740 return true; 741 } 742 clazz = clazz.getSuperclass(); 743 } 744 return false; 745 } 746 747 public Expression simplify() { 748 Expression expr = simplifyAccess(); 749 if (expr != null) 750 return expr.simplify(); 751 expr = simplifyString(); 752 if (expr != this) 753 return expr.simplify(); 754 return super.simplify(); 755 } 756 757 758 762 public void fillDeclarables(Collection used) { 763 ClassInfo clazz = getClassInfo(); 764 InnerClassInfo outer = getOuterClassInfo(clazz); 765 ClassAnalyzer clazzAna = methodAnalyzer.getClassAnalyzer(clazz); 766 767 if ((Options.options & Options.OPTION_ANON) != 0 768 && outer != null && outer.outer == null && outer.name != null 769 && clazzAna != null 770 && clazzAna.getParent() == methodAnalyzer) { 771 772 776 clazzAna.fillDeclarables(used); 777 used.add(clazzAna); 778 } 779 780 if (!isConstructor() || isStatic()) { 781 super.fillDeclarables(used); 782 return; 783 } 784 int arg = 1; 785 int length = subExpressions.length; 786 boolean jikesAnonymousInner = false; 787 boolean implicitOuterClass = false; 788 789 if ((Options.options & Options.OPTION_ANON) != 0 790 && clazzAna != null 791 && outer != null && (outer.outer == null || outer.name == null)) { 792 793 OuterValues ov = clazzAna.getOuterValues(); 794 arg += ov.getCount(); 795 jikesAnonymousInner = ov.isJikesAnonymousInner(); 796 implicitOuterClass = ov.isImplicitOuterClass(); 797 798 for (int i=1; i< arg; i++) { 799 Expression expr = subExpressions[i]; 800 if (expr instanceof CheckNullOperator) { 801 CheckNullOperator cno = (CheckNullOperator) expr; 802 expr = cno.subExpressions[0]; 803 } 804 expr.fillDeclarables(used); 805 } 806 807 if (outer.name == null) { 808 809 ClassInfo superClazz = clazz.getSuperclass(); 810 ClassInfo[] interfaces = clazz.getInterfaces(); 811 if (interfaces.length == 1 812 && (superClazz == null 813 || superClazz == ClassInfo.javaLangObject)) { 814 clazz = interfaces[0]; 815 } else { 816 clazz = (superClazz != null 817 ? superClazz : ClassInfo.javaLangObject); 818 } 819 outer = getOuterClassInfo(clazz); 820 821 } 822 } 823 824 if ((Options.options & Options.OPTION_INNER) != 0 825 && outer != null && outer.outer != null && outer.name != null 826 && !Modifier.isStatic(outer.modifiers) 827 && !implicitOuterClass 828 && arg < length) { 829 830 Expression outerExpr = jikesAnonymousInner 831 ? subExpressions[--length] 832 : subExpressions[arg++]; 833 if (outerExpr instanceof CheckNullOperator) { 834 CheckNullOperator cno = (CheckNullOperator) outerExpr; 835 outerExpr = cno.subExpressions[0]; 836 } 837 outerExpr.fillDeclarables(used); 838 } 839 for (int i=arg; i < length; i++) 840 subExpressions[i].fillDeclarables(used); 841 } 842 843 847 public void makeDeclaration(Set done) { 848 super.makeDeclaration(done); 849 850 if (isConstructor() && !isStatic() 851 && (Options.options & Options.OPTION_ANON) != 0) { 852 ClassInfo clazz = getClassInfo(); 853 InnerClassInfo outer = getOuterClassInfo(clazz); 854 ClassAnalyzer clazzAna = methodAnalyzer.getClassAnalyzer(clazz); 855 if (clazzAna != null && outer != null && outer.name == null) { 856 857 859 clazzAna.makeDeclaration(done); 860 } 861 } 862 } 863 864 public int getBreakPenalty() { 865 return 5; 866 } 867 868 871 public void dumpExpression(TabbedPrintWriter writer) 872 throws java.io.IOException { 873 int arg = 1; 874 int length = subExpressions.length; 875 876 boolean anonymousNew = false; 877 ClassInfo clazz = getClassInfo(); 878 ClassAnalyzer clazzAna = null; 879 880 Type[] paramTypes = new Type[subExpressions.length]; 881 for (int i=0; i< subExpressions.length; i++) 882 paramTypes[i] = subExpressions[i].getType().getCanonic(); 883 884 writer.startOp(writer.NO_PAREN, 0); 885 switch (methodFlag) { 886 case CONSTRUCTOR: { 887 888 boolean qualifiedNew = false; 889 boolean jikesAnonymousInner = false; 890 boolean implicitOuterClass = false; 891 892 893 897 InnerClassInfo outer = getOuterClassInfo(clazz); 898 if (outer != null && outer.name == null 899 && (Options.options & Options.OPTION_ANON) != 0) 900 anonymousNew = true; 901 clazzAna = methodAnalyzer.getClassAnalyzer(clazz); 902 if ((~Options.options & 903 (Options.OPTION_ANON | Options.OPTION_CONTRAFO)) == 0 904 && clazzAna != null 905 && outer != null 906 && (outer.outer == null || outer.name == null)) { 907 908 909 OuterValues ov = clazzAna.getOuterValues(); 910 arg += ov.getCount(); 911 jikesAnonymousInner = ov.isJikesAnonymousInner(); 912 implicitOuterClass = ov.isImplicitOuterClass(); 913 914 if (outer.name == null) { 915 916 ClassInfo superClazz = clazz.getSuperclass(); 917 ClassInfo[] interfaces = clazz.getInterfaces(); 918 if (interfaces.length == 1 919 && (superClazz == null 920 || superClazz == ClassInfo.javaLangObject)) { 921 clazz = interfaces[0]; 922 } else { 923 if (interfaces.length > 0) { 924 writer.print("too many supers in ANONYMOUS "); 925 } 926 clazz = (superClazz != null 927 ? superClazz : ClassInfo.javaLangObject); 928 } 929 outer = getOuterClassInfo(clazz); 930 if (jikesAnonymousInner && outer != null 931 && outer.outer == null && outer.name != null) { 932 Expression thisExpr = subExpressions[--length]; 933 if (thisExpr instanceof CheckNullOperator) { 934 CheckNullOperator cno 935 = (CheckNullOperator) thisExpr; 936 thisExpr = cno.subExpressions[0]; 937 } 938 if (!(thisExpr instanceof ThisOperator) 939 || (((ThisOperator) thisExpr).getClassInfo() 940 != methodAnalyzer.getClazz())) 941 writer.print("ILLEGAL ANON CONSTR"); 942 } 943 } 944 } 945 946 949 if (outer != null && outer.outer != null && outer.name != null 950 && !Modifier.isStatic(outer.modifiers) 951 && (~Options.options & 952 (Options.OPTION_INNER 953 | Options.OPTION_CONTRAFO)) == 0) { 954 955 if (implicitOuterClass) { 956 959 } else if (arg < length) { 960 Expression outerExpr = jikesAnonymousInner 961 ? subExpressions[--length] 962 : subExpressions[arg++]; 963 if (outerExpr instanceof CheckNullOperator) { 964 CheckNullOperator cno = (CheckNullOperator) outerExpr; 965 outerExpr = cno.subExpressions[0]; 966 } else { 967 971 } 972 973 if (outerExpr instanceof ThisOperator) { 974 Scope scope = writer.getScope 975 (((ThisOperator) outerExpr).getClassInfo(), 976 Scope.CLASSSCOPE); 977 if (writer.conflicts(outer.name, scope, Scope.CLASSNAME)) { 978 qualifiedNew = true; 979 outerExpr.dumpExpression(writer, 950); 980 writer.breakOp(); 981 writer.print("."); 982 } 983 } else { 984 qualifiedNew = true; 985 if (outerExpr.getType().getCanonic() 986 instanceof NullType) { 987 writer.print("("); 988 writer.startOp(writer.EXPL_PAREN, 1); 989 writer.print("("); 990 writer.printType(Type.tClass 991 (ClassInfo.forName(outer.outer))); 992 writer.print(") "); 993 writer.breakOp(); 994 outerExpr.dumpExpression(writer, 700); 995 writer.endOp(); 996 writer.print(")"); 997 } else 998 outerExpr.dumpExpression(writer, 950); 999 writer.breakOp(); 1000 writer.print("."); 1001 } 1002 } else 1003 writer.print("MISSING OUTEREXPR "); 1004 } 1005 1006 if (subExpressions[0] instanceof NewOperator 1007 && paramTypes[0].equals(classType)) { 1008 writer.print("new "); 1009 if (qualifiedNew) 1010 writer.print(outer.name); 1011 else 1012 writer.printType(Type.tClass(clazz)); 1013 break; 1014 } 1015 1016 if (subExpressions[0] instanceof ThisOperator 1017 && (((ThisOperator)subExpressions[0]).getClassInfo() 1018 == methodAnalyzer.getClazz())) { 1019 if (isThis()) 1020 writer.print("this"); 1021 else 1022 writer.print("super"); 1023 break; 1024 } 1025 1026 writer.print("("); 1027 writer.startOp(writer.EXPL_PAREN, 0); 1028 writer.print("(UNCONSTRUCTED)"); 1029 writer.breakOp(); 1030 subExpressions[0].dumpExpression(writer, 700); 1031 writer.endOp(); 1032 writer.print(")"); 1033 writer.breakOp(); 1034 writer.print("."); 1035 writer.printType(Type.tClass(clazz)); 1036 break; 1037 } 1038 case SPECIAL: 1039 if (isSuperOrThis() 1040 && subExpressions[0] instanceof ThisOperator 1041 && (((ThisOperator)subExpressions[0]).getClassInfo() 1042 == methodAnalyzer.getClazz())) { 1043 if (!isThis()) { 1044 1047 writer.print("super"); 1048 ClassInfo superClazz = getClassInfo().getSuperclass(); 1049 paramTypes[0] = superClazz == null 1050 ? Type.tObject : Type.tClass(superClazz); 1051 writer.breakOp(); 1052 writer.print("."); 1053 } else { 1054 1055 } 1056 } else if (isThis()) { 1057 1058 if (needsCast(0, paramTypes)){ 1059 writer.print("("); 1060 writer.startOp(writer.EXPL_PAREN, 1); 1061 writer.print("("); 1062 writer.printType(classType); 1063 writer.print(") "); 1064 writer.breakOp(); 1065 subExpressions[0].dumpExpression(writer, 700); 1066 writer.endOp(); 1067 writer.print(")"); 1068 paramTypes[0] = classType; 1069 } else 1070 subExpressions[0].dumpExpression(writer, 950); 1071 writer.breakOp(); 1072 writer.print("."); 1073 } else { 1074 writer.print("("); 1075 writer.startOp(writer.EXPL_PAREN, 0); 1076 writer.print("(NON VIRTUAL "); 1077 writer.printType(classType); 1078 writer.print(") "); 1079 writer.breakOp(); 1080 subExpressions[0].dumpExpression(writer, 700); 1081 writer.endOp(); 1082 writer.print(")"); 1083 writer.breakOp(); 1084 writer.print("."); 1085 } 1086 writer.print(methodName); 1087 break; 1088 1089 case ACCESSSPECIAL: 1090 1093 if (paramTypes[0].equals(classType)) 1094 subExpressions[0].dumpExpression(writer, 950); 1095 else { 1096 writer.print("("); 1097 writer.startOp(writer.EXPL_PAREN, 0); 1098 writer.print("("); 1099 writer.printType(classType); 1100 writer.print(") "); 1101 writer.breakOp(); 1102 paramTypes[0] = classType; 1103 subExpressions[0].dumpExpression(writer, 700); 1104 writer.endOp(); 1105 writer.print(")"); 1106 } 1107 writer.breakOp(); 1108 writer.print("."); 1109 writer.print(methodName); 1110 break; 1111 1112 case STATIC: { 1113 arg = 0; 1114 Scope scope = writer.getScope(getClassInfo(), 1115 Scope.CLASSSCOPE); 1116 if (scope == null 1117 ||writer.conflicts(methodName, scope, Scope.METHODNAME)) { 1118 writer.printType(classType); 1119 writer.breakOp(); 1120 writer.print("."); 1121 } 1122 writer.print(methodName); 1123 break; 1124 } 1125 1126 case VIRTUAL: 1127 if (subExpressions[0] instanceof ThisOperator) { 1128 ThisOperator thisOp = (ThisOperator) subExpressions[0]; 1129 Scope scope = writer.getScope(thisOp.getClassInfo(), 1130 Scope.CLASSSCOPE); 1131 if (writer.conflicts(methodName, scope, Scope.METHODNAME) 1132 || ( 1137 getMethodAnalyzer() == null 1138 && (!isThis() || 1139 writer.conflicts(methodName, null, 1140 Scope.NOSUPERMETHODNAME)))) { 1141 thisOp.dumpExpression(writer, 950); 1142 writer.breakOp(); 1143 writer.print("."); 1144 } 1145 } else { 1146 if (needsCast(0, paramTypes)){ 1147 writer.print("("); 1148 writer.startOp(writer.EXPL_PAREN, 1); 1149 writer.print("("); 1150 writer.printType(classType); 1151 writer.print(") "); 1152 writer.breakOp(); 1153 subExpressions[0].dumpExpression(writer, 700); 1154 writer.endOp(); 1155 writer.print(")"); 1156 paramTypes[0] = classType; 1157 } else 1158 subExpressions[0].dumpExpression(writer, 950); 1159 writer.breakOp(); 1160 writer.print("."); 1161 } 1162 writer.print(methodName); 1163 } 1164 1165 writer.endOp(); 1166 writer.breakOp(); 1167 if ((Options.outputStyle & Options.GNU_SPACING) != 0) 1168 writer.print(" "); 1169 writer.print("("); 1170 writer.startOp(writer.EXPL_PAREN, 0); 1171 boolean first = true; 1172 int offset = skippedArgs; 1173 while (arg < length) { 1174 if (!first) { 1175 writer.print(", "); 1176 writer.breakOp(); 1177 } else 1178 first = false; 1179 int priority = 0; 1180 if (needsCast(arg, paramTypes)) { 1181 Type castType = methodType.getParameterTypes()[arg-offset]; 1182 writer.startOp(writer.IMPL_PAREN, 1); 1183 writer.print("("); 1184 writer.printType(castType); 1185 writer.print(") "); 1186 writer.breakOp(); 1187 paramTypes[arg] = castType; 1188 priority = 700; 1189 } 1190 subExpressions[arg++].dumpExpression(writer, priority); 1191 if (priority == 700) 1192 writer.endOp(); 1193 } 1194 writer.endOp(); 1195 writer.print(")"); 1196 1197 if (anonymousNew) { 1198 1201 Object state = writer.saveOps(); 1202 writer.openBraceClass(); 1203 writer.tab(); 1204 clazzAna.dumpBlock(writer); 1205 writer.untab(); 1206 writer.closeBraceClass(); 1207 writer.restoreOps(state); 1208 } 1209 } 1210 1211 public boolean opEquals(Operator o) { 1212 if (o instanceof InvokeOperator) { 1213 InvokeOperator i = (InvokeOperator)o; 1214 return classType.equals(i.classType) 1215 && methodName.equals(i.methodName) 1216 && methodType.equals(i.methodType) 1217 && methodFlag == i.methodFlag; 1218 } 1219 return false; 1220 } 1221} 1222 | Popular Tags |