You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

TypeChecker.java 30KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925
  1. /*
  2. * Javassist, a Java-bytecode translator toolkit.
  3. * Copyright (C) 1999-2006 Shigeru Chiba. All Rights Reserved.
  4. *
  5. * The contents of this file are subject to the Mozilla Public License Version
  6. * 1.1 (the "License"); you may not use this file except in compliance with
  7. * the License. Alternatively, the contents of this file may be used under
  8. * the terms of the GNU Lesser General Public License Version 2.1 or later.
  9. *
  10. * Software distributed under the License is distributed on an "AS IS" basis,
  11. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12. * for the specific language governing rights and limitations under the
  13. * License.
  14. */
  15. package javassist.compiler;
  16. import javassist.CtClass;
  17. import javassist.CtField;
  18. import javassist.ClassPool;
  19. import javassist.Modifier;
  20. import javassist.NotFoundException;
  21. import javassist.compiler.ast.*;
  22. import javassist.bytecode.*;
  23. public class TypeChecker extends Visitor implements Opcode, TokenId {
  24. static final String javaLangObject = "java.lang.Object";
  25. static final String jvmJavaLangObject = "java/lang/Object";
  26. static final String jvmJavaLangString = "java/lang/String";
  27. static final String jvmJavaLangClass = "java/lang/Class";
  28. /* The following fields are used by atXXX() methods
  29. * for returning the type of the compiled expression.
  30. */
  31. protected int exprType; // VOID, NULL, CLASS, BOOLEAN, INT, ...
  32. protected int arrayDim;
  33. protected String className; // JVM-internal representation
  34. protected MemberResolver resolver;
  35. protected CtClass thisClass;
  36. protected MethodInfo thisMethod;
  37. public TypeChecker(CtClass cc, ClassPool cp) {
  38. resolver = new MemberResolver(cp);
  39. thisClass = cc;
  40. thisMethod = null;
  41. }
  42. /**
  43. * Records the currently compiled method.
  44. */
  45. public void setThisMethod(MethodInfo m) {
  46. thisMethod = m;
  47. }
  48. protected static void fatal() throws CompileError {
  49. throw new CompileError("fatal");
  50. }
  51. /**
  52. * Returns the JVM-internal representation of this class name.
  53. */
  54. protected String getThisName() {
  55. return MemberResolver.javaToJvmName(thisClass.getName());
  56. }
  57. /**
  58. * Returns the JVM-internal representation of this super class name.
  59. */
  60. protected String getSuperName() throws CompileError {
  61. return MemberResolver.javaToJvmName(
  62. MemberResolver.getSuperclass(thisClass).getName());
  63. }
  64. /* Converts a class name into a JVM-internal representation.
  65. *
  66. * It may also expand a simple class name to java.lang.*.
  67. * For example, this converts Object into java/lang/Object.
  68. */
  69. protected String resolveClassName(ASTList name) throws CompileError {
  70. return resolver.resolveClassName(name);
  71. }
  72. /* Expands a simple class name to java.lang.*.
  73. * For example, this converts Object into java/lang/Object.
  74. */
  75. protected String resolveClassName(String jvmName) throws CompileError {
  76. return resolver.resolveJvmClassName(jvmName);
  77. }
  78. public void atNewExpr(NewExpr expr) throws CompileError {
  79. if (expr.isArray())
  80. atNewArrayExpr(expr);
  81. else {
  82. CtClass clazz = resolver.lookupClassByName(expr.getClassName());
  83. String cname = clazz.getName();
  84. ASTList args = expr.getArguments();
  85. atMethodCallCore(clazz, MethodInfo.nameInit, args);
  86. exprType = CLASS;
  87. arrayDim = 0;
  88. className = MemberResolver.javaToJvmName(cname);
  89. }
  90. }
  91. public void atNewArrayExpr(NewExpr expr) throws CompileError {
  92. int type = expr.getArrayType();
  93. ASTList size = expr.getArraySize();
  94. ASTList classname = expr.getClassName();
  95. ASTree init = expr.getInitializer();
  96. if (init != null)
  97. init.accept(this);
  98. if (size.length() > 1)
  99. atMultiNewArray(type, classname, size);
  100. else {
  101. ASTree sizeExpr = size.head();
  102. if (sizeExpr != null)
  103. sizeExpr.accept(this);
  104. exprType = type;
  105. arrayDim = 1;
  106. if (type == CLASS)
  107. className = resolveClassName(classname);
  108. else
  109. className = null;
  110. }
  111. }
  112. public void atArrayInit(ArrayInit init) throws CompileError {
  113. ASTList list = init;
  114. while (list != null) {
  115. ASTree h = list.head();
  116. list = list.tail();
  117. if (h != null)
  118. h.accept(this);
  119. }
  120. }
  121. protected void atMultiNewArray(int type, ASTList classname, ASTList size)
  122. throws CompileError
  123. {
  124. int count, dim;
  125. dim = size.length();
  126. for (count = 0; size != null; size = size.tail()) {
  127. ASTree s = size.head();
  128. if (s == null)
  129. break; // int[][][] a = new int[3][4][];
  130. ++count;
  131. s.accept(this);
  132. }
  133. exprType = type;
  134. arrayDim = dim;
  135. if (type == CLASS)
  136. className = resolveClassName(classname);
  137. else
  138. className = null;
  139. }
  140. public void atAssignExpr(AssignExpr expr) throws CompileError {
  141. // =, %=, &=, *=, /=, +=, -=, ^=, |=, <<=, >>=, >>>=
  142. int op = expr.getOperator();
  143. ASTree left = expr.oprand1();
  144. ASTree right = expr.oprand2();
  145. if (left instanceof Variable)
  146. atVariableAssign(expr, op, (Variable)left,
  147. ((Variable)left).getDeclarator(),
  148. right);
  149. else {
  150. if (left instanceof Expr) {
  151. Expr e = (Expr)left;
  152. if (e.getOperator() == ARRAY) {
  153. atArrayAssign(expr, op, (Expr)left, right);
  154. return;
  155. }
  156. }
  157. atFieldAssign(expr, op, left, right);
  158. }
  159. }
  160. /* op is either =, %=, &=, *=, /=, +=, -=, ^=, |=, <<=, >>=, or >>>=.
  161. *
  162. * expr and var can be null.
  163. */
  164. private void atVariableAssign(Expr expr, int op, Variable var,
  165. Declarator d, ASTree right)
  166. throws CompileError
  167. {
  168. int varType = d.getType();
  169. int varArray = d.getArrayDim();
  170. String varClass = d.getClassName();
  171. if (op != '=')
  172. atVariable(var);
  173. right.accept(this);
  174. exprType = varType;
  175. arrayDim = varArray;
  176. className = varClass;
  177. }
  178. private void atArrayAssign(Expr expr, int op, Expr array,
  179. ASTree right) throws CompileError
  180. {
  181. atArrayRead(array.oprand1(), array.oprand2());
  182. int aType = exprType;
  183. int aDim = arrayDim;
  184. String cname = className;
  185. right.accept(this);
  186. exprType = aType;
  187. arrayDim = aDim;
  188. className = cname;
  189. }
  190. protected void atFieldAssign(Expr expr, int op, ASTree left, ASTree right)
  191. throws CompileError
  192. {
  193. CtField f = fieldAccess(left);
  194. atFieldRead(f);
  195. int fType = exprType;
  196. int fDim = arrayDim;
  197. String cname = className;
  198. right.accept(this);
  199. exprType = fType;
  200. arrayDim = fDim;
  201. className = cname;
  202. }
  203. public void atCondExpr(CondExpr expr) throws CompileError {
  204. booleanExpr(expr.condExpr());
  205. expr.thenExpr().accept(this);
  206. int type1 = exprType;
  207. int dim1 = arrayDim;
  208. String cname1 = className;
  209. expr.elseExpr().accept(this);
  210. if (dim1 == 0 && dim1 == arrayDim)
  211. if (CodeGen.rightIsStrong(type1, exprType))
  212. expr.setThen(new CastExpr(exprType, 0, expr.thenExpr()));
  213. else if (CodeGen.rightIsStrong(exprType, type1)) {
  214. expr.setElse(new CastExpr(type1, 0, expr.elseExpr()));
  215. exprType = type1;
  216. }
  217. }
  218. /*
  219. * If atBinExpr() substitutes a new expression for the original
  220. * binary-operator expression, it changes the operator name to '+'
  221. * (if the original is not '+') and sets the new expression to the
  222. * left-hand-side expression and null to the right-hand-side expression.
  223. */
  224. public void atBinExpr(BinExpr expr) throws CompileError {
  225. int token = expr.getOperator();
  226. int k = CodeGen.lookupBinOp(token);
  227. if (k >= 0) {
  228. /* arithmetic operators: +, -, *, /, %, |, ^, &, <<, >>, >>>
  229. */
  230. if (token == '+') {
  231. Expr e = atPlusExpr(expr);
  232. if (e != null) {
  233. /* String concatenation has been translated into
  234. * an expression using StringBuffer.
  235. */
  236. e = CallExpr.makeCall(Expr.make('.', e,
  237. new Member("toString")), null);
  238. expr.setOprand1(e);
  239. expr.setOprand2(null); // <---- look at this!
  240. className = jvmJavaLangString;
  241. }
  242. }
  243. else {
  244. ASTree left = expr.oprand1();
  245. ASTree right = expr.oprand2();
  246. left.accept(this);
  247. int type1 = exprType;
  248. right.accept(this);
  249. if (!isConstant(expr, token, left, right))
  250. computeBinExprType(expr, token, type1);
  251. }
  252. }
  253. else {
  254. /* equation: &&, ||, ==, !=, <=, >=, <, >
  255. */
  256. booleanExpr(expr);
  257. }
  258. }
  259. /* EXPR must be a + expression.
  260. * atPlusExpr() returns non-null if the given expression is string
  261. * concatenation. The returned value is "new StringBuffer().append..".
  262. */
  263. private Expr atPlusExpr(BinExpr expr) throws CompileError {
  264. ASTree left = expr.oprand1();
  265. ASTree right = expr.oprand2();
  266. if (right == null) {
  267. // this expression has been already type-checked.
  268. // see atBinExpr() above.
  269. left.accept(this);
  270. return null;
  271. }
  272. if (isPlusExpr(left)) {
  273. Expr newExpr = atPlusExpr((BinExpr)left);
  274. if (newExpr != null) {
  275. right.accept(this);
  276. exprType = CLASS;
  277. arrayDim = 0;
  278. className = "java/lang/StringBuffer";
  279. return makeAppendCall(newExpr, right);
  280. }
  281. }
  282. else
  283. left.accept(this);
  284. int type1 = exprType;
  285. int dim1 = arrayDim;
  286. String cname = className;
  287. right.accept(this);
  288. if (isConstant(expr, '+', left, right))
  289. return null;
  290. if ((type1 == CLASS && dim1 == 0 && jvmJavaLangString.equals(cname))
  291. || (exprType == CLASS && arrayDim == 0
  292. && jvmJavaLangString.equals(className))) {
  293. ASTList sbufClass = ASTList.make(new Symbol("java"),
  294. new Symbol("lang"), new Symbol("StringBuffer"));
  295. ASTree e = new NewExpr(sbufClass, null);
  296. exprType = CLASS;
  297. arrayDim = 0;
  298. className = "java/lang/StringBuffer";
  299. return makeAppendCall(makeAppendCall(e, left), right);
  300. }
  301. else {
  302. computeBinExprType(expr, '+', type1);
  303. return null;
  304. }
  305. }
  306. private boolean isConstant(BinExpr expr, int op, ASTree left,
  307. ASTree right) throws CompileError
  308. {
  309. left = stripPlusExpr(left);
  310. right = stripPlusExpr(right);
  311. ASTree newExpr = null;
  312. if (left instanceof StringL && right instanceof StringL && op == '+')
  313. newExpr = new StringL(((StringL)left).get()
  314. + ((StringL)right).get());
  315. else if (left instanceof IntConst)
  316. newExpr = ((IntConst)left).compute(op, right);
  317. else if (left instanceof DoubleConst)
  318. newExpr = ((DoubleConst)left).compute(op, right);
  319. if (newExpr == null)
  320. return false; // not a constant expression
  321. else {
  322. expr.setOperator('+');
  323. expr.setOprand1(newExpr);
  324. expr.setOprand2(null);
  325. newExpr.accept(this); // for setting exprType, arrayDim, ...
  326. return true;
  327. }
  328. }
  329. /* CodeGen.atSwitchStmnt() also calls stripPlusExpr().
  330. */
  331. static ASTree stripPlusExpr(ASTree expr) {
  332. if (expr instanceof BinExpr) {
  333. BinExpr e = (BinExpr)expr;
  334. if (e.getOperator() == '+' && e.oprand2() == null)
  335. return e.getLeft();
  336. }
  337. else if (expr instanceof Expr) { // note: BinExpr extends Expr.
  338. Expr e = (Expr)expr;
  339. int op = e.getOperator();
  340. if (op == MEMBER) {
  341. ASTree cexpr = getConstantFieldValue((Member)e.oprand2());
  342. if (cexpr != null)
  343. return cexpr;
  344. }
  345. else if (op == '+' && e.getRight() == null)
  346. return e.getLeft();
  347. }
  348. else if (expr instanceof Member) {
  349. ASTree cexpr = getConstantFieldValue((Member)expr);
  350. if (cexpr != null)
  351. return cexpr;
  352. }
  353. return expr;
  354. }
  355. /**
  356. * If MEM is a static final field, this method returns a constant
  357. * expression representing the value of that field.
  358. */
  359. private static ASTree getConstantFieldValue(Member mem) {
  360. return getConstantFieldValue(mem.getField());
  361. }
  362. public static ASTree getConstantFieldValue(CtField f) {
  363. if (f == null)
  364. return null;
  365. Object value = f.getConstantValue();
  366. if (value == null)
  367. return null;
  368. if (value instanceof String)
  369. return new StringL((String)value);
  370. else if (value instanceof Double || value instanceof Float) {
  371. int token = (value instanceof Double)
  372. ? DoubleConstant : FloatConstant;
  373. return new DoubleConst(((Number)value).doubleValue(), token);
  374. }
  375. else if (value instanceof Number) {
  376. int token = (value instanceof Long) ? LongConstant : IntConstant;
  377. return new IntConst(((Number)value).longValue(), token);
  378. }
  379. else if (value instanceof Boolean)
  380. return new Keyword(((Boolean)value).booleanValue()
  381. ? TokenId.TRUE : TokenId.FALSE);
  382. else
  383. return null;
  384. }
  385. private static boolean isPlusExpr(ASTree expr) {
  386. if (expr instanceof BinExpr) {
  387. BinExpr bexpr = (BinExpr)expr;
  388. int token = bexpr.getOperator();
  389. return token == '+';
  390. }
  391. return false;
  392. }
  393. private static Expr makeAppendCall(ASTree target, ASTree arg) {
  394. return CallExpr.makeCall(Expr.make('.', target, new Member("append")),
  395. new ASTList(arg));
  396. }
  397. private void computeBinExprType(BinExpr expr, int token, int type1)
  398. throws CompileError
  399. {
  400. // arrayDim should be 0.
  401. int type2 = exprType;
  402. if (token == LSHIFT || token == RSHIFT || token == ARSHIFT)
  403. exprType = type1;
  404. else
  405. insertCast(expr, type1, type2);
  406. if (CodeGen.isP_INT(exprType))
  407. exprType = INT; // type1 may be BYTE, ...
  408. }
  409. private void booleanExpr(ASTree expr)
  410. throws CompileError
  411. {
  412. int op = CodeGen.getCompOperator(expr);
  413. if (op == EQ) { // ==, !=, ...
  414. BinExpr bexpr = (BinExpr)expr;
  415. bexpr.oprand1().accept(this);
  416. int type1 = exprType;
  417. int dim1 = arrayDim;
  418. bexpr.oprand2().accept(this);
  419. if (dim1 == 0 && arrayDim == 0)
  420. insertCast(bexpr, type1, exprType);
  421. }
  422. else if (op == '!')
  423. ((Expr)expr).oprand1().accept(this);
  424. else if (op == ANDAND || op == OROR) {
  425. BinExpr bexpr = (BinExpr)expr;
  426. bexpr.oprand1().accept(this);
  427. bexpr.oprand2().accept(this);
  428. }
  429. else // others
  430. expr.accept(this);
  431. exprType = BOOLEAN;
  432. arrayDim = 0;
  433. }
  434. private void insertCast(BinExpr expr, int type1, int type2)
  435. throws CompileError
  436. {
  437. if (CodeGen.rightIsStrong(type1, type2))
  438. expr.setLeft(new CastExpr(type2, 0, expr.oprand1()));
  439. else
  440. exprType = type1;
  441. }
  442. public void atCastExpr(CastExpr expr) throws CompileError {
  443. String cname = resolveClassName(expr.getClassName());
  444. expr.getOprand().accept(this);
  445. exprType = expr.getType();
  446. arrayDim = expr.getArrayDim();
  447. className = cname;
  448. }
  449. public void atInstanceOfExpr(InstanceOfExpr expr) throws CompileError {
  450. expr.getOprand().accept(this);
  451. exprType = BOOLEAN;
  452. arrayDim = 0;
  453. }
  454. public void atExpr(Expr expr) throws CompileError {
  455. // array access, member access,
  456. // (unary) +, (unary) -, ++, --, !, ~
  457. int token = expr.getOperator();
  458. ASTree oprand = expr.oprand1();
  459. if (token == '.') {
  460. String member = ((Symbol)expr.oprand2()).get();
  461. if (member.equals("length"))
  462. atArrayLength(expr);
  463. else if (member.equals("class"))
  464. atClassObject(expr); // .class
  465. else
  466. atFieldRead(expr);
  467. }
  468. else if (token == MEMBER) { // field read
  469. String member = ((Symbol)expr.oprand2()).get();
  470. if (member.equals("class"))
  471. atClassObject(expr); // .class
  472. else
  473. atFieldRead(expr);
  474. }
  475. else if (token == ARRAY)
  476. atArrayRead(oprand, expr.oprand2());
  477. else if (token == PLUSPLUS || token == MINUSMINUS)
  478. atPlusPlus(token, oprand, expr);
  479. else if (token == '!')
  480. booleanExpr(expr);
  481. else if (token == CALL) // method call
  482. fatal();
  483. else {
  484. oprand.accept(this);
  485. if (!isConstant(expr, token, oprand))
  486. if (token == '-' || token == '~')
  487. if (CodeGen.isP_INT(exprType))
  488. exprType = INT; // type may be BYTE, ...
  489. }
  490. }
  491. private boolean isConstant(Expr expr, int op, ASTree oprand) {
  492. oprand = stripPlusExpr(oprand);
  493. if (oprand instanceof IntConst) {
  494. IntConst c = (IntConst)oprand;
  495. long v = c.get();
  496. if (op == '-')
  497. v = -v;
  498. else if (op == '~')
  499. v = ~v;
  500. else
  501. return false;
  502. c.set(v);
  503. }
  504. else if (oprand instanceof DoubleConst) {
  505. DoubleConst c = (DoubleConst)oprand;
  506. if (op == '-')
  507. c.set(-c.get());
  508. else
  509. return false;
  510. }
  511. else
  512. return false;
  513. expr.setOperator('+');
  514. return true;
  515. }
  516. public void atCallExpr(CallExpr expr) throws CompileError {
  517. String mname = null;
  518. CtClass targetClass = null;
  519. ASTree method = expr.oprand1();
  520. ASTList args = (ASTList)expr.oprand2();
  521. if (method instanceof Member) {
  522. mname = ((Member)method).get();
  523. targetClass = thisClass;
  524. }
  525. else if (method instanceof Keyword) { // constructor
  526. mname = MethodInfo.nameInit; // <init>
  527. if (((Keyword)method).get() == SUPER)
  528. targetClass = MemberResolver.getSuperclass(thisClass);
  529. else
  530. targetClass = thisClass;
  531. }
  532. else if (method instanceof Expr) {
  533. Expr e = (Expr)method;
  534. mname = ((Symbol)e.oprand2()).get();
  535. int op = e.getOperator();
  536. if (op == MEMBER) // static method
  537. targetClass
  538. = resolver.lookupClass(((Symbol)e.oprand1()).get(),
  539. false);
  540. else if (op == '.') {
  541. ASTree target = e.oprand1();
  542. try {
  543. target.accept(this);
  544. }
  545. catch (NoFieldException nfe) {
  546. if (nfe.getExpr() != target)
  547. throw nfe;
  548. // it should be a static method.
  549. exprType = CLASS;
  550. arrayDim = 0;
  551. className = nfe.getField(); // JVM-internal
  552. e.setOperator(MEMBER);
  553. e.setOprand1(new Symbol(MemberResolver.jvmToJavaName(
  554. className)));
  555. }
  556. if (arrayDim > 0)
  557. targetClass = resolver.lookupClass(javaLangObject, true);
  558. else if (exprType == CLASS /* && arrayDim == 0 */)
  559. targetClass = resolver.lookupClassByJvmName(className);
  560. else
  561. badMethod();
  562. }
  563. else
  564. badMethod();
  565. }
  566. else
  567. fatal();
  568. MemberResolver.Method minfo
  569. = atMethodCallCore(targetClass, mname, args);
  570. expr.setMethod(minfo);
  571. }
  572. private static void badMethod() throws CompileError {
  573. throw new CompileError("bad method");
  574. }
  575. /**
  576. * @return a pair of the class declaring the invoked method
  577. * and the MethodInfo of that method. Never null.
  578. */
  579. public MemberResolver.Method atMethodCallCore(CtClass targetClass,
  580. String mname, ASTList args)
  581. throws CompileError
  582. {
  583. int nargs = getMethodArgsLength(args);
  584. int[] types = new int[nargs];
  585. int[] dims = new int[nargs];
  586. String[] cnames = new String[nargs];
  587. atMethodArgs(args, types, dims, cnames);
  588. MemberResolver.Method found
  589. = resolver.lookupMethod(targetClass, thisClass, thisMethod,
  590. mname, types, dims, cnames);
  591. if (found == null) {
  592. String msg;
  593. if (mname.equals(MethodInfo.nameInit))
  594. msg = "constructor not found";
  595. else
  596. msg = "Method " + mname + " not found in "
  597. + targetClass.getName();
  598. throw new CompileError(msg);
  599. }
  600. String desc = found.info.getDescriptor();
  601. setReturnType(desc);
  602. return found;
  603. }
  604. public int getMethodArgsLength(ASTList args) {
  605. return ASTList.length(args);
  606. }
  607. public void atMethodArgs(ASTList args, int[] types, int[] dims,
  608. String[] cnames) throws CompileError {
  609. int i = 0;
  610. while (args != null) {
  611. ASTree a = args.head();
  612. a.accept(this);
  613. types[i] = exprType;
  614. dims[i] = arrayDim;
  615. cnames[i] = className;
  616. ++i;
  617. args = args.tail();
  618. }
  619. }
  620. void setReturnType(String desc) throws CompileError {
  621. int i = desc.indexOf(')');
  622. if (i < 0)
  623. badMethod();
  624. char c = desc.charAt(++i);
  625. int dim = 0;
  626. while (c == '[') {
  627. ++dim;
  628. c = desc.charAt(++i);
  629. }
  630. arrayDim = dim;
  631. if (c == 'L') {
  632. int j = desc.indexOf(';', i + 1);
  633. if (j < 0)
  634. badMethod();
  635. exprType = CLASS;
  636. className = desc.substring(i + 1, j);
  637. }
  638. else {
  639. exprType = MemberResolver.descToType(c);
  640. className = null;
  641. }
  642. }
  643. private void atFieldRead(ASTree expr) throws CompileError {
  644. atFieldRead(fieldAccess(expr));
  645. }
  646. private void atFieldRead(CtField f) throws CompileError {
  647. FieldInfo finfo = f.getFieldInfo2();
  648. String type = finfo.getDescriptor();
  649. int i = 0;
  650. int dim = 0;
  651. char c = type.charAt(i);
  652. while (c == '[') {
  653. ++dim;
  654. c = type.charAt(++i);
  655. }
  656. arrayDim = dim;
  657. exprType = MemberResolver.descToType(c);
  658. if (c == 'L')
  659. className = type.substring(i + 1, type.indexOf(';', i + 1));
  660. else
  661. className = null;
  662. }
  663. /* if EXPR is to access a static field, fieldAccess() translates EXPR
  664. * into an expression using '#' (MEMBER). For example, it translates
  665. * java.lang.Integer.TYPE into java.lang.Integer#TYPE. This translation
  666. * speeds up type resolution by MemberCodeGen.
  667. */
  668. protected CtField fieldAccess(ASTree expr) throws CompileError {
  669. if (expr instanceof Member) {
  670. Member mem = (Member)expr;
  671. String name = mem.get();
  672. try {
  673. CtField f = thisClass.getField(name);
  674. if (Modifier.isStatic(f.getModifiers()))
  675. mem.setField(f);
  676. return f;
  677. }
  678. catch (NotFoundException e) {
  679. // EXPR might be part of a static member access?
  680. throw new NoFieldException(name, expr);
  681. }
  682. }
  683. else if (expr instanceof Expr) {
  684. Expr e = (Expr)expr;
  685. int op = e.getOperator();
  686. if (op == MEMBER) {
  687. Member mem = (Member)e.oprand2();
  688. CtField f
  689. = resolver.lookupField(((Symbol)e.oprand1()).get(), mem);
  690. mem.setField(f);
  691. return f;
  692. }
  693. else if (op == '.')
  694. try {
  695. e.oprand1().accept(this);
  696. if (exprType == CLASS && arrayDim == 0)
  697. return resolver.lookupFieldByJvmName(className,
  698. (Symbol)e.oprand2());
  699. }
  700. catch (NoFieldException nfe) {
  701. if (nfe.getExpr() != e.oprand1())
  702. throw nfe;
  703. /* EXPR should be a static field.
  704. * If EXPR might be part of a qualified class name,
  705. * lookupFieldByJvmName2() throws NoFieldException.
  706. */
  707. Member fname = (Member)e.oprand2();
  708. String jvmClassName = nfe.getField();
  709. CtField f = resolver.lookupFieldByJvmName2(jvmClassName,
  710. fname, expr);
  711. e.setOperator(MEMBER);
  712. e.setOprand1(new Symbol(MemberResolver.jvmToJavaName(
  713. jvmClassName)));
  714. fname.setField(f);
  715. return f;
  716. }
  717. }
  718. throw new CompileError("bad filed access");
  719. }
  720. public void atClassObject(Expr expr) throws CompileError {
  721. exprType = CLASS;
  722. arrayDim = 0;
  723. className =jvmJavaLangClass;
  724. }
  725. public void atArrayLength(Expr expr) throws CompileError {
  726. expr.oprand1().accept(this);
  727. exprType = INT;
  728. arrayDim = 0;
  729. }
  730. public void atArrayRead(ASTree array, ASTree index)
  731. throws CompileError
  732. {
  733. array.accept(this);
  734. int type = exprType;
  735. int dim = arrayDim;
  736. String cname = className;
  737. index.accept(this);
  738. exprType = type;
  739. arrayDim = dim - 1;
  740. className = cname;
  741. }
  742. private void atPlusPlus(int token, ASTree oprand, Expr expr)
  743. throws CompileError
  744. {
  745. boolean isPost = oprand == null; // ++i or i++?
  746. if (isPost)
  747. oprand = expr.oprand2();
  748. if (oprand instanceof Variable) {
  749. Declarator d = ((Variable)oprand).getDeclarator();
  750. exprType = d.getType();
  751. arrayDim = d.getArrayDim();
  752. }
  753. else {
  754. if (oprand instanceof Expr) {
  755. Expr e = (Expr)oprand;
  756. if (e.getOperator() == ARRAY) {
  757. atArrayRead(e.oprand1(), e.oprand2());
  758. // arrayDim should be 0.
  759. int t = exprType;
  760. if (t == INT || t == BYTE || t == CHAR || t == SHORT)
  761. exprType = INT;
  762. return;
  763. }
  764. }
  765. atFieldPlusPlus(oprand);
  766. }
  767. }
  768. protected void atFieldPlusPlus(ASTree oprand) throws CompileError
  769. {
  770. CtField f = fieldAccess(oprand);
  771. atFieldRead(f);
  772. int t = exprType;
  773. if (t == INT || t == BYTE || t == CHAR || t == SHORT)
  774. exprType = INT;
  775. }
  776. public void atMember(Member mem) throws CompileError {
  777. atFieldRead(mem);
  778. }
  779. public void atVariable(Variable v) throws CompileError {
  780. Declarator d = v.getDeclarator();
  781. exprType = d.getType();
  782. arrayDim = d.getArrayDim();
  783. className = d.getClassName();
  784. }
  785. public void atKeyword(Keyword k) throws CompileError {
  786. arrayDim = 0;
  787. int token = k.get();
  788. switch (token) {
  789. case TRUE :
  790. case FALSE :
  791. exprType = BOOLEAN;
  792. break;
  793. case NULL :
  794. exprType = NULL;
  795. break;
  796. case THIS :
  797. case SUPER :
  798. exprType = CLASS;
  799. if (token == THIS)
  800. className = getThisName();
  801. else
  802. className = getSuperName();
  803. break;
  804. default :
  805. fatal();
  806. }
  807. }
  808. public void atStringL(StringL s) throws CompileError {
  809. exprType = CLASS;
  810. arrayDim = 0;
  811. className = jvmJavaLangString;
  812. }
  813. public void atIntConst(IntConst i) throws CompileError {
  814. arrayDim = 0;
  815. int type = i.getType();
  816. if (type == IntConstant || type == CharConstant)
  817. exprType = (type == IntConstant ? INT : CHAR);
  818. else
  819. exprType = LONG;
  820. }
  821. public void atDoubleConst(DoubleConst d) throws CompileError {
  822. arrayDim = 0;
  823. if (d.getType() == DoubleConstant)
  824. exprType = DOUBLE;
  825. else
  826. exprType = FLOAT;
  827. }
  828. }