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 34KB

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