1 15 16 package javassist.compiler; 17 18 import javassist.CtClass; 19 import javassist.CtField; 20 import javassist.ClassPool; 21 import javassist.Modifier; 22 import javassist.NotFoundException; 23 import javassist.compiler.ast.*; 24 import javassist.bytecode.*; 25 26 public class TypeChecker extends Visitor implements Opcode, TokenId { 27 static final String javaLangObject = "java.lang.Object"; 28 static final String jvmJavaLangObject = "java/lang/Object"; 29 static final String jvmJavaLangString = "java/lang/String"; 30 static final String jvmJavaLangClass = "java/lang/Class"; 31 32 35 protected int exprType; protected int arrayDim; 37 protected String className; 39 protected MemberResolver resolver; 40 protected CtClass thisClass; 41 protected MethodInfo thisMethod; 42 43 public TypeChecker(CtClass cc, ClassPool cp) { 44 resolver = new MemberResolver(cp); 45 thisClass = cc; 46 thisMethod = null; 47 } 48 49 52 public void setThisMethod(MethodInfo m) { 53 thisMethod = m; 54 } 55 56 protected static void fatal() throws CompileError { 57 throw new CompileError("fatal"); 58 } 59 60 63 protected String getThisName() { 64 return MemberResolver.javaToJvmName(thisClass.getName()); 65 } 66 67 70 protected String getSuperName() throws CompileError { 71 return MemberResolver.javaToJvmName( 72 MemberResolver.getSuperclass(thisClass).getName()); 73 } 74 75 80 protected String resolveClassName(ASTList name) throws CompileError { 81 return resolver.resolveClassName(name); 82 } 83 84 87 protected String resolveClassName(String jvmName) throws CompileError { 88 return resolver.resolveJvmClassName(jvmName); 89 } 90 91 public void atNewExpr(NewExpr expr) throws CompileError { 92 if (expr.isArray()) 93 atNewArrayExpr(expr); 94 else { 95 CtClass clazz = resolver.lookupClassByName(expr.getClassName()); 96 String cname = clazz.getName(); 97 ASTList args = expr.getArguments(); 98 atMethodCallCore(clazz, MethodInfo.nameInit, args); 99 exprType = CLASS; 100 arrayDim = 0; 101 className = MemberResolver.javaToJvmName(cname); 102 } 103 } 104 105 public void atNewArrayExpr(NewExpr expr) throws CompileError { 106 int type = expr.getArrayType(); 107 ASTList size = expr.getArraySize(); 108 ASTList classname = expr.getClassName(); 109 if (size.length() > 1) 110 atMultiNewArray(type, classname, size); 111 else { 112 size.head().accept(this); 113 exprType = type; 114 arrayDim = 1; 115 if (type == CLASS) 116 className = resolveClassName(classname); 117 else 118 className = null; 119 } 120 } 121 122 protected void atMultiNewArray(int type, ASTList classname, ASTList size) 123 throws CompileError 124 { 125 int count, dim; 126 dim = size.length(); 127 for (count = 0; size != null; size = size.tail()) { 128 ASTree s = size.head(); 129 if (s == null) 130 break; 132 ++count; 133 s.accept(this); 134 } 135 136 exprType = type; 137 arrayDim = dim; 138 if (type == CLASS) 139 className = resolveClassName(classname); 140 else 141 className = null; 142 } 143 144 public void atAssignExpr(AssignExpr expr) throws CompileError { 145 int op = expr.getOperator(); 147 ASTree left = expr.oprand1(); 148 ASTree right = expr.oprand2(); 149 if (left instanceof Variable) 150 atVariableAssign(expr, op, (Variable)left, 151 ((Variable)left).getDeclarator(), 152 right); 153 else { 154 if (left instanceof Expr) { 155 Expr e = (Expr)left; 156 if (e.getOperator() == ARRAY) { 157 atArrayAssign(expr, op, (Expr)left, right); 158 return; 159 } 160 } 161 162 atFieldAssign(expr, op, left, right); 163 } 164 } 165 166 170 private void atVariableAssign(Expr expr, int op, Variable var, 171 Declarator d, ASTree right) 172 throws CompileError 173 { 174 int varType = d.getType(); 175 int varArray = d.getArrayDim(); 176 String varClass = d.getClassName(); 177 178 if (op != '=') 179 atVariable(var); 180 181 right.accept(this); 182 exprType = varType; 183 arrayDim = varArray; 184 className = varClass; 185 } 186 187 private void atArrayAssign(Expr expr, int op, Expr array, 188 ASTree right) throws CompileError 189 { 190 atArrayRead(array.oprand1(), array.oprand2()); 191 int aType = exprType; 192 int aDim = arrayDim; 193 String cname = className; 194 right.accept(this); 195 exprType = aType; 196 arrayDim = aDim; 197 className = cname; 198 } 199 200 protected void atFieldAssign(Expr expr, int op, ASTree left, ASTree right) 201 throws CompileError 202 { 203 CtField f = fieldAccess(left); 204 atFieldRead(f); 205 int fType = exprType; 206 int fDim = arrayDim; 207 String cname = className; 208 right.accept(this); 209 exprType = fType; 210 arrayDim = fDim; 211 className = cname; 212 } 213 214 public void atCondExpr(CondExpr expr) throws CompileError { 215 booleanExpr(expr.condExpr()); 216 expr.thenExpr().accept(this); 217 int type1 = exprType; 218 int dim1 = arrayDim; 219 String cname1 = className; 220 expr.elseExpr().accept(this); 221 222 if (dim1 == 0 && dim1 == arrayDim) 223 if (CodeGen.rightIsStrong(type1, exprType)) 224 expr.setThen(new CastExpr(exprType, 0, expr.thenExpr())); 225 else if (CodeGen.rightIsStrong(exprType, type1)) { 226 expr.setElse(new CastExpr(type1, 0, expr.elseExpr())); 227 exprType = type1; 228 } 229 } 230 231 237 public void atBinExpr(BinExpr expr) throws CompileError { 238 int token = expr.getOperator(); 239 int k = CodeGen.lookupBinOp(token); 240 if (k >= 0) { 241 243 if (token == '+') { 244 Expr e = atPlusExpr(expr); 245 if (e != null) { 246 249 e = CallExpr.makeCall(Expr.make('.', e, 250 new Member("toString")), null); 251 expr.setOprand1(e); 252 expr.setOprand2(null); className = jvmJavaLangString; 254 } 255 } 256 else { 257 ASTree left = expr.oprand1(); 258 ASTree right = expr.oprand2(); 259 left.accept(this); 260 int type1 = exprType; 261 right.accept(this); 262 if (!isConstant(expr, token, left, right)) 263 computeBinExprType(expr, token, type1); 264 } 265 } 266 else { 267 269 booleanExpr(expr); 270 } 271 } 272 273 277 private Expr atPlusExpr(BinExpr expr) throws CompileError { 278 ASTree left = expr.oprand1(); 279 ASTree right = expr.oprand2(); 280 if (right == null) { 281 left.accept(this); 284 return null; 285 } 286 287 if (isPlusExpr(left)) { 288 Expr newExpr = atPlusExpr((BinExpr)left); 289 if (newExpr != null) { 290 right.accept(this); 291 exprType = CLASS; 292 arrayDim = 0; 293 className = "java/lang/StringBuffer"; 294 return makeAppendCall(newExpr, right); 295 } 296 } 297 else 298 left.accept(this); 299 300 int type1 = exprType; 301 int dim1 = arrayDim; 302 String cname = className; 303 right.accept(this); 304 305 if (isConstant(expr, '+', left, right)) 306 return null; 307 308 if ((type1 == CLASS && dim1 == 0 && jvmJavaLangString.equals(cname)) 309 || (exprType == CLASS && arrayDim == 0 310 && jvmJavaLangString.equals(className))) { 311 ASTList sbufClass = ASTList.make(new Symbol("java"), 312 new Symbol("lang"), new Symbol("StringBuffer")); 313 ASTree e = new NewExpr(sbufClass, null); 314 exprType = CLASS; 315 arrayDim = 0; 316 className = "java/lang/StringBuffer"; 317 return makeAppendCall(makeAppendCall(e, left), right); 318 } 319 else { 320 computeBinExprType(expr, '+', type1); 321 return null; 322 } 323 } 324 325 private boolean isConstant(BinExpr expr, int op, ASTree left, 326 ASTree right) throws CompileError 327 { 328 left = stripPlusExpr(left); 329 right = stripPlusExpr(right); 330 ASTree newExpr = null; 331 if (left instanceof StringL && right instanceof StringL && op == '+') 332 newExpr = new StringL(((StringL)left).get() 333 + ((StringL)right).get()); 334 else if (left instanceof IntConst) 335 newExpr = ((IntConst)left).compute(op, right); 336 else if (left instanceof DoubleConst) 337 newExpr = ((DoubleConst)left).compute(op, right); 338 339 if (newExpr == null) 340 return false; else { 342 expr.setOperator('+'); 343 expr.setOprand1(newExpr); 344 expr.setOprand2(null); 345 newExpr.accept(this); return true; 347 } 348 } 349 350 352 static ASTree stripPlusExpr(ASTree expr) { 353 if (expr instanceof BinExpr) { 354 BinExpr e = (BinExpr)expr; 355 if (e.getOperator() == '+' && e.oprand2() == null) 356 return e.getLeft(); 357 } 358 else if (expr instanceof Expr) { Expr e = (Expr)expr; 360 int op = e.getOperator(); 361 if (op == MEMBER) { 362 ASTree cexpr = getConstantFieldValue((Member)e.oprand2()); 363 if (cexpr != null) 364 return cexpr; 365 } 366 else if (op == '+' && e.getRight() == null) 367 return e.getLeft(); 368 } 369 else if (expr instanceof Member) { 370 ASTree cexpr = getConstantFieldValue((Member)expr); 371 if (cexpr != null) 372 return cexpr; 373 } 374 375 return expr; 376 } 377 378 382 private static ASTree getConstantFieldValue(Member mem) { 383 return getConstantFieldValue(mem.getField()); 384 } 385 386 public static ASTree getConstantFieldValue(CtField f) { 387 if (f == null) 388 return null; 389 390 Object value = f.getConstantValue(); 391 if (value == null) 392 return null; 393 394 if (value instanceof String ) 395 return new StringL((String )value); 396 else if (value instanceof Double || value instanceof Float ) { 397 int token = (value instanceof Double ) 398 ? DoubleConstant : FloatConstant; 399 return new DoubleConst(((Number )value).doubleValue(), token); 400 } 401 else if (value instanceof Number ) { 402 int token = (value instanceof Long ) ? LongConstant : IntConstant; 403 return new IntConst(((Number )value).longValue(), token); 404 } 405 else if (value instanceof Boolean ) 406 return new Keyword(((Boolean )value).booleanValue() 407 ? TokenId.TRUE : TokenId.FALSE); 408 else 409 return null; 410 } 411 412 private static boolean isPlusExpr(ASTree expr) { 413 if (expr instanceof BinExpr) { 414 BinExpr bexpr = (BinExpr)expr; 415 int token = bexpr.getOperator(); 416 return token == '+'; 417 } 418 419 return false; 420 } 421 422 private static Expr makeAppendCall(ASTree target, ASTree arg) { 423 return CallExpr.makeCall(Expr.make('.', target, new Member("append")), 424 new ASTList(arg)); 425 } 426 427 private void computeBinExprType(BinExpr expr, int token, int type1) 428 throws CompileError 429 { 430 int type2 = exprType; 432 if (token == LSHIFT || token == RSHIFT || token == ARSHIFT) 433 exprType = type1; 434 else 435 insertCast(expr, type1, type2); 436 437 if (CodeGen.isP_INT(exprType)) 438 exprType = INT; } 440 441 private void booleanExpr(ASTree expr) 442 throws CompileError 443 { 444 int op = CodeGen.getCompOperator(expr); 445 if (op == EQ) { BinExpr bexpr = (BinExpr)expr; 447 bexpr.oprand1().accept(this); 448 int type1 = exprType; 449 int dim1 = arrayDim; 450 bexpr.oprand2().accept(this); 451 if (dim1 == 0 && arrayDim == 0) 452 insertCast(bexpr, type1, exprType); 453 } 454 else if (op == '!') 455 ((Expr)expr).oprand1().accept(this); 456 else if (op == ANDAND || op == OROR) { 457 BinExpr bexpr = (BinExpr)expr; 458 bexpr.oprand1().accept(this); 459 bexpr.oprand2().accept(this); 460 } 461 else expr.accept(this); 463 464 exprType = BOOLEAN; 465 arrayDim = 0; 466 } 467 468 private void insertCast(BinExpr expr, int type1, int type2) 469 throws CompileError 470 { 471 if (CodeGen.rightIsStrong(type1, type2)) 472 expr.setLeft(new CastExpr(type2, 0, expr.oprand1())); 473 else 474 exprType = type1; 475 } 476 477 public void atCastExpr(CastExpr expr) throws CompileError { 478 String cname = resolveClassName(expr.getClassName()); 479 expr.getOprand().accept(this); 480 exprType = expr.getType(); 481 arrayDim = expr.getArrayDim(); 482 className = cname; 483 } 484 485 public void atInstanceOfExpr(InstanceOfExpr expr) throws CompileError { 486 expr.getOprand().accept(this); 487 exprType = BOOLEAN; 488 arrayDim = 0; 489 } 490 491 public void atExpr(Expr expr) throws CompileError { 492 495 int token = expr.getOperator(); 496 ASTree oprand = expr.oprand1(); 497 if (token == '.') { 498 String member = ((Symbol)expr.oprand2()).get(); 499 if (member.equals("length")) 500 atArrayLength(expr); 501 else if (member.equals("class")) 502 atClassObject(expr); else 504 atFieldRead(expr); 505 } 506 else if (token == MEMBER) { String member = ((Symbol)expr.oprand2()).get(); 508 if (member.equals("class")) 509 atClassObject(expr); else 511 atFieldRead(expr); 512 } 513 else if (token == ARRAY) 514 atArrayRead(oprand, expr.oprand2()); 515 else if (token == PLUSPLUS || token == MINUSMINUS) 516 atPlusPlus(token, oprand, expr); 517 else if (token == '!') 518 booleanExpr(expr); 519 else if (token == CALL) fatal(); 521 else { 522 oprand.accept(this); 523 if (!isConstant(expr, token, oprand)) 524 if (token == '-' || token == '~') 525 if (CodeGen.isP_INT(exprType)) 526 exprType = INT; } 528 } 529 530 private boolean isConstant(Expr expr, int op, ASTree oprand) { 531 oprand = stripPlusExpr(oprand); 532 if (oprand instanceof IntConst) { 533 IntConst c = (IntConst)oprand; 534 long v = c.get(); 535 if (op == '-') 536 v = -v; 537 else if (op == '~') 538 v = ~v; 539 else 540 return false; 541 542 c.set(v); 543 } 544 else if (oprand instanceof DoubleConst) { 545 DoubleConst c = (DoubleConst)oprand; 546 if (op == '-') 547 c.set(-c.get()); 548 else 549 return false; 550 } 551 else 552 return false; 553 554 expr.setOperator('+'); 555 return true; 556 } 557 558 public void atCallExpr(CallExpr expr) throws CompileError { 559 String mname = null; 560 CtClass targetClass = null; 561 ASTree method = expr.oprand1(); 562 ASTList args = (ASTList)expr.oprand2(); 563 564 if (method instanceof Member) { 565 mname = ((Member)method).get(); 566 targetClass = thisClass; 567 } 568 else if (method instanceof Keyword) { mname = MethodInfo.nameInit; if (((Keyword)method).get() == SUPER) 571 targetClass = MemberResolver.getSuperclass(thisClass); 572 else 573 targetClass = thisClass; 574 } 575 else if (method instanceof Expr) { 576 Expr e = (Expr)method; 577 mname = ((Symbol)e.oprand2()).get(); 578 int op = e.getOperator(); 579 if (op == MEMBER) targetClass 581 = resolver.lookupClass(((Symbol)e.oprand1()).get(), 582 false); 583 else if (op == '.') { 584 ASTree target = e.oprand1(); 585 try { 586 target.accept(this); 587 } 588 catch (NoFieldException nfe) { 589 if (nfe.getExpr() != target) 590 throw nfe; 591 592 exprType = CLASS; 594 arrayDim = 0; 595 className = nfe.getField(); e.setOperator(MEMBER); 597 e.setOprand1(new Symbol(MemberResolver.jvmToJavaName( 598 className))); 599 } 600 601 if (arrayDim > 0) 602 targetClass = resolver.lookupClass(javaLangObject, true); 603 else if (exprType == CLASS ) 604 targetClass = resolver.lookupClassByJvmName(className); 605 else 606 badMethod(); 607 } 608 else 609 badMethod(); 610 } 611 else 612 fatal(); 613 614 MemberResolver.Method minfo 615 = atMethodCallCore(targetClass, mname, args); 616 expr.setMethod(minfo); 617 } 618 619 private static void badMethod() throws CompileError { 620 throw new CompileError("bad method"); 621 } 622 623 627 public MemberResolver.Method atMethodCallCore(CtClass targetClass, 628 String mname, ASTList args) 629 throws CompileError 630 { 631 int nargs = getMethodArgsLength(args); 632 int[] types = new int[nargs]; 633 int[] dims = new int[nargs]; 634 String [] cnames = new String [nargs]; 635 atMethodArgs(args, types, dims, cnames); 636 637 MemberResolver.Method found 638 = resolver.lookupMethod(targetClass, thisMethod, mname, 639 types, dims, cnames, false); 640 if (found == null) { 641 String msg; 642 if (mname.equals(MethodInfo.nameInit)) 643 msg = "constructor not found"; 644 else 645 msg = "Method " + mname + " not found in " 646 + targetClass.getName(); 647 648 throw new CompileError(msg); 649 } 650 651 String desc = found.info.getDescriptor(); 652 setReturnType(desc); 653 return found; 654 } 655 656 public int getMethodArgsLength(ASTList args) { 657 return ASTList.length(args); 658 } 659 660 public void atMethodArgs(ASTList args, int[] types, int[] dims, 661 String [] cnames) throws CompileError { 662 int i = 0; 663 while (args != null) { 664 ASTree a = args.head(); 665 a.accept(this); 666 types[i] = exprType; 667 dims[i] = arrayDim; 668 cnames[i] = className; 669 ++i; 670 args = args.tail(); 671 } 672 } 673 674 void setReturnType(String desc) throws CompileError { 675 int i = desc.indexOf(')'); 676 if (i < 0) 677 badMethod(); 678 679 char c = desc.charAt(++i); 680 int dim = 0; 681 while (c == '[') { 682 ++dim; 683 c = desc.charAt(++i); 684 } 685 686 arrayDim = dim; 687 if (c == 'L') { 688 int j = desc.indexOf(';', i + 1); 689 if (j < 0) 690 badMethod(); 691 692 exprType = CLASS; 693 className = desc.substring(i + 1, j); 694 } 695 else { 696 exprType = MemberResolver.descToType(c); 697 className = null; 698 } 699 } 700 701 private void atFieldRead(ASTree expr) throws CompileError { 702 atFieldRead(fieldAccess(expr)); 703 } 704 705 private void atFieldRead(CtField f) throws CompileError { 706 FieldInfo finfo = f.getFieldInfo2(); 707 String type = finfo.getDescriptor(); 708 709 int i = 0; 710 int dim = 0; 711 char c = type.charAt(i); 712 while (c == '[') { 713 ++dim; 714 c = type.charAt(++i); 715 } 716 717 arrayDim = dim; 718 exprType = MemberResolver.descToType(c); 719 720 if (c == 'L') 721 className = type.substring(i + 1, type.indexOf(';', i + 1)); 722 else 723 className = null; 724 } 725 726 731 protected CtField fieldAccess(ASTree expr) throws CompileError { 732 if (expr instanceof Member) { 733 Member mem = (Member)expr; 734 String name = mem.get(); 735 try { 736 CtField f = thisClass.getField(name); 737 if (Modifier.isStatic(f.getModifiers())) 738 mem.setField(f); 739 740 return f; 741 } 742 catch (NotFoundException e) { 743 throw new NoFieldException(name, expr); 745 } 746 } 747 else if (expr instanceof Expr) { 748 Expr e = (Expr)expr; 749 int op = e.getOperator(); 750 if (op == MEMBER) { 751 Member mem = (Member)e.oprand2(); 752 CtField f 753 = resolver.lookupField(((Symbol)e.oprand1()).get(), mem); 754 mem.setField(f); 755 return f; 756 } 757 else if (op == '.') 758 try { 759 e.oprand1().accept(this); 760 if (exprType == CLASS && arrayDim == 0) 761 return resolver.lookupFieldByJvmName(className, 762 (Symbol)e.oprand2()); 763 } 764 catch (NoFieldException nfe) { 765 if (nfe.getExpr() != e.oprand1()) 766 throw nfe; 767 768 772 Member fname = (Member)e.oprand2(); 773 String jvmClassName = nfe.getField(); 774 CtField f = resolver.lookupFieldByJvmName2(jvmClassName, 775 fname, expr); 776 e.setOperator(MEMBER); 777 e.setOprand1(new Symbol(MemberResolver.jvmToJavaName( 778 jvmClassName))); 779 fname.setField(f); 780 return f; 781 } 782 } 783 784 throw new CompileError("bad filed access"); 785 } 786 787 public void atClassObject(Expr expr) throws CompileError { 788 exprType = CLASS; 789 arrayDim = 0; 790 className =jvmJavaLangClass; 791 } 792 793 public void atArrayLength(Expr expr) throws CompileError { 794 expr.oprand1().accept(this); 795 exprType = INT; 796 arrayDim = 0; 797 } 798 799 public void atArrayRead(ASTree array, ASTree index) 800 throws CompileError 801 { 802 array.accept(this); 803 int type = exprType; 804 int dim = arrayDim; 805 String cname = className; 806 index.accept(this); 807 exprType = type; 808 arrayDim = dim - 1; 809 className = cname; 810 } 811 812 private void atPlusPlus(int token, ASTree oprand, Expr expr) 813 throws CompileError 814 { 815 boolean isPost = oprand == null; if (isPost) 817 oprand = expr.oprand2(); 818 819 if (oprand instanceof Variable) { 820 Declarator d = ((Variable)oprand).getDeclarator(); 821 exprType = d.getType(); 822 arrayDim = d.getArrayDim(); 823 } 824 else { 825 if (oprand instanceof Expr) { 826 Expr e = (Expr)oprand; 827 if (e.getOperator() == ARRAY) { 828 atArrayRead(e.oprand1(), e.oprand2()); 829 int t = exprType; 831 if (t == INT || t == BYTE || t == CHAR || t == SHORT) 832 exprType = INT; 833 834 return; 835 } 836 } 837 838 atFieldPlusPlus(oprand); 839 } 840 } 841 842 protected void atFieldPlusPlus(ASTree oprand) throws CompileError 843 { 844 CtField f = fieldAccess(oprand); 845 atFieldRead(f); 846 int t = exprType; 847 if (t == INT || t == BYTE || t == CHAR || t == SHORT) 848 exprType = INT; 849 } 850 851 public void atMember(Member mem) throws CompileError { 852 atFieldRead(mem); 853 } 854 855 public void atVariable(Variable v) throws CompileError { 856 Declarator d = v.getDeclarator(); 857 exprType = d.getType(); 858 arrayDim = d.getArrayDim(); 859 className = d.getClassName(); 860 } 861 862 public void atKeyword(Keyword k) throws CompileError { 863 arrayDim = 0; 864 int token = k.get(); 865 switch (token) { 866 case TRUE : 867 case FALSE : 868 exprType = BOOLEAN; 869 break; 870 case NULL : 871 exprType = NULL; 872 break; 873 case THIS : 874 case SUPER : 875 exprType = CLASS; 876 if (token == THIS) 877 className = getThisName(); 878 else 879 className = getSuperName(); 880 break; 881 default : 882 fatal(); 883 } 884 } 885 886 public void atStringL(StringL s) throws CompileError { 887 exprType = CLASS; 888 arrayDim = 0; 889 className = jvmJavaLangString; 890 } 891 892 public void atIntConst(IntConst i) throws CompileError { 893 arrayDim = 0; 894 int type = i.getType(); 895 if (type == IntConstant || type == CharConstant) 896 exprType = (type == IntConstant ? INT : CHAR); 897 else 898 exprType = LONG; 899 } 900 901 public void atDoubleConst(DoubleConst d) throws CompileError { 902 arrayDim = 0; 903 if (d.getType() == DoubleConstant) 904 exprType = DOUBLE; 905 else 906 exprType = FLOAT; 907 } 908 } 909 | Popular Tags |