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.

MemberResolver.java 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535
  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 java.util.List;
  17. import java.util.Iterator;
  18. import javassist.*;
  19. import javassist.bytecode.*;
  20. import javassist.compiler.ast.*;
  21. /* Code generator methods depending on javassist.* classes.
  22. */
  23. public class MemberResolver implements TokenId {
  24. private ClassPool classPool;
  25. public MemberResolver(ClassPool cp) {
  26. classPool = cp;
  27. }
  28. public ClassPool getClassPool() { return classPool; }
  29. private static void fatal() throws CompileError {
  30. throw new CompileError("fatal");
  31. }
  32. /**
  33. * @param jvmClassName a class name. Not a package name.
  34. */
  35. public void recordPackage(String jvmClassName) {
  36. String classname = jvmToJavaName(jvmClassName);
  37. for (;;) {
  38. int i = classname.lastIndexOf('.');
  39. if (i > 0) {
  40. classname = classname.substring(0, i);
  41. classPool.recordInvalidClassName(classname);
  42. }
  43. else
  44. break;
  45. }
  46. }
  47. public static class Method {
  48. public CtClass declaring;
  49. public MethodInfo info;
  50. public Method(CtClass c, MethodInfo i) {
  51. declaring = c;
  52. info = i;
  53. }
  54. /**
  55. * Returns true if the invoked method is static.
  56. */
  57. public boolean isStatic() {
  58. int acc = info.getAccessFlags();
  59. return (acc & AccessFlag.STATIC) != 0;
  60. }
  61. }
  62. public Method lookupMethod(CtClass clazz, CtClass currentClass, MethodInfo current,
  63. String methodName,
  64. int[] argTypes, int[] argDims,
  65. String[] argClassNames)
  66. throws CompileError
  67. {
  68. Method maybe = null;
  69. // to enable the creation of a recursively called method
  70. if (current != null && clazz == currentClass)
  71. if (current.getName().equals(methodName)) {
  72. int res = compareSignature(current.getDescriptor(),
  73. argTypes, argDims, argClassNames);
  74. Method r = new Method(clazz, current);
  75. if (res == YES)
  76. return r;
  77. else if (res == MAYBE)
  78. maybe = r;
  79. }
  80. Method m = lookupMethod(clazz, methodName, argTypes, argDims,
  81. argClassNames, maybe != null);
  82. if (m != null)
  83. return m;
  84. else
  85. return maybe;
  86. }
  87. private Method lookupMethod(CtClass clazz, String methodName,
  88. int[] argTypes, int[] argDims,
  89. String[] argClassNames, boolean onlyExact)
  90. throws CompileError
  91. {
  92. Method maybe = null;
  93. List list = clazz.getClassFile2().getMethods();
  94. int n = list.size();
  95. for (int i = 0; i < n; ++i) {
  96. MethodInfo minfo = (MethodInfo)list.get(i);
  97. if (minfo.getName().equals(methodName)) {
  98. int res = compareSignature(minfo.getDescriptor(),
  99. argTypes, argDims, argClassNames);
  100. if (res != NO) {
  101. Method r = new Method(clazz, minfo);
  102. if (res == YES)
  103. return r;
  104. else if (maybe == null)
  105. maybe = r;
  106. }
  107. }
  108. }
  109. if (onlyExact)
  110. maybe = null;
  111. else
  112. onlyExact = maybe != null;
  113. try {
  114. CtClass pclazz = clazz.getSuperclass();
  115. if (pclazz != null) {
  116. Method r = lookupMethod(pclazz, methodName, argTypes,
  117. argDims, argClassNames, onlyExact);
  118. if (r != null)
  119. return r;
  120. }
  121. }
  122. catch (NotFoundException e) {}
  123. int mod = clazz.getModifiers();
  124. if (Modifier.isAbstract(mod) || Modifier.isInterface(mod))
  125. try {
  126. CtClass[] ifs = clazz.getInterfaces();
  127. int size = ifs.length;
  128. for (int i = 0; i < size; ++i) {
  129. Method r = lookupMethod(ifs[i], methodName,
  130. argTypes, argDims, argClassNames,
  131. onlyExact);
  132. if (r != null)
  133. return r;
  134. }
  135. }
  136. catch (NotFoundException e) {}
  137. return maybe;
  138. }
  139. private static final int YES = 2;
  140. private static final int MAYBE = 1;
  141. private static final int NO = 0;
  142. /*
  143. * Returns YES if actual parameter types matches the given signature.
  144. *
  145. * argTypes, argDims, and argClassNames represent actual parameters.
  146. *
  147. * This method does not correctly implement the Java method dispatch
  148. * algorithm.
  149. */
  150. private int compareSignature(String desc, int[] argTypes,
  151. int[] argDims, String[] argClassNames)
  152. throws CompileError
  153. {
  154. int result = YES;
  155. int i = 1;
  156. int nArgs = argTypes.length;
  157. if (nArgs != Descriptor.numOfParameters(desc))
  158. return NO;
  159. int len = desc.length();
  160. for (int n = 0; i < len; ++n) {
  161. char c = desc.charAt(i++);
  162. if (c == ')')
  163. return (n == nArgs ? result : NO);
  164. else if (n >= nArgs)
  165. return NO;
  166. int dim = 0;
  167. while (c == '[') {
  168. ++dim;
  169. c = desc.charAt(i++);
  170. }
  171. if (argTypes[n] == NULL) {
  172. if (dim == 0 && c != 'L')
  173. return NO;
  174. if (c == 'L')
  175. i = desc.indexOf(';', i) + 1;
  176. }
  177. else if (argDims[n] != dim) {
  178. if (!(dim == 0 && c == 'L'
  179. && desc.startsWith("java/lang/Object;", i)))
  180. return NO;
  181. // if the thread reaches here, c must be 'L'.
  182. i = desc.indexOf(';', i) + 1;
  183. result = MAYBE;
  184. if (i <= 0)
  185. return NO; // invalid descriptor?
  186. }
  187. else if (c == 'L') { // not compare
  188. int j = desc.indexOf(';', i);
  189. if (j < 0 || argTypes[n] != CLASS)
  190. return NO;
  191. String cname = desc.substring(i, j);
  192. if (!cname.equals(argClassNames[n])) {
  193. CtClass clazz = lookupClassByJvmName(argClassNames[n]);
  194. try {
  195. if (clazz.subtypeOf(lookupClassByJvmName(cname)))
  196. result = MAYBE;
  197. else
  198. return NO;
  199. }
  200. catch (NotFoundException e) {
  201. result = MAYBE; // should be NO?
  202. }
  203. }
  204. i = j + 1;
  205. }
  206. else {
  207. int t = descToType(c);
  208. int at = argTypes[n];
  209. if (t != at)
  210. if (t == INT
  211. && (at == SHORT || at == BYTE || at == CHAR))
  212. result = MAYBE;
  213. else
  214. return NO;
  215. }
  216. }
  217. return NO;
  218. }
  219. /**
  220. * Only used by fieldAccess() in MemberCodeGen and TypeChecker.
  221. *
  222. * @param jvmClassName a JVM class name. e.g. java/lang/String
  223. */
  224. public CtField lookupFieldByJvmName2(String jvmClassName, Symbol fieldSym,
  225. ASTree expr) throws NoFieldException
  226. {
  227. String field = fieldSym.get();
  228. CtClass cc = null;
  229. try {
  230. cc = lookupClass(jvmToJavaName(jvmClassName), true);
  231. }
  232. catch (CompileError e) {
  233. // EXPR might be part of a qualified class name.
  234. throw new NoFieldException(jvmClassName + "/" + field, expr);
  235. }
  236. try {
  237. return cc.getField(field);
  238. }
  239. catch (NotFoundException e) {
  240. // maybe an inner class.
  241. jvmClassName = javaToJvmName(cc.getName());
  242. throw new NoFieldException(jvmClassName + "$" + field, expr);
  243. }
  244. }
  245. /**
  246. * @param jvmClassName a JVM class name. e.g. java/lang/String
  247. */
  248. public CtField lookupFieldByJvmName(String jvmClassName, Symbol fieldName)
  249. throws CompileError
  250. {
  251. return lookupField(jvmToJavaName(jvmClassName), fieldName);
  252. }
  253. /**
  254. * @param name a qualified class name. e.g. java.lang.String
  255. */
  256. public CtField lookupField(String className, Symbol fieldName)
  257. throws CompileError
  258. {
  259. CtClass cc = lookupClass(className, false);
  260. try {
  261. return cc.getField(fieldName.get());
  262. }
  263. catch (NotFoundException e) {}
  264. throw new CompileError("no such field: " + fieldName.get());
  265. }
  266. public CtClass lookupClassByName(ASTList name) throws CompileError {
  267. return lookupClass(Declarator.astToClassName(name, '.'), false);
  268. }
  269. public CtClass lookupClassByJvmName(String jvmName) throws CompileError {
  270. return lookupClass(jvmToJavaName(jvmName), false);
  271. }
  272. public CtClass lookupClass(Declarator decl) throws CompileError {
  273. return lookupClass(decl.getType(), decl.getArrayDim(),
  274. decl.getClassName());
  275. }
  276. /**
  277. * @parma classname jvm class name.
  278. */
  279. public CtClass lookupClass(int type, int dim, String classname)
  280. throws CompileError
  281. {
  282. String cname = "";
  283. CtClass clazz;
  284. switch (type) {
  285. case CLASS :
  286. clazz = lookupClassByJvmName(classname);
  287. if (dim > 0)
  288. cname = clazz.getName();
  289. else
  290. return clazz;
  291. break;
  292. case BOOLEAN :
  293. cname = "boolean";
  294. break;
  295. case CHAR :
  296. cname = "char";
  297. break;
  298. case BYTE :
  299. cname = "byte";
  300. break;
  301. case SHORT :
  302. cname = "short";
  303. break;
  304. case INT :
  305. cname = "int";
  306. break;
  307. case LONG :
  308. cname = "long";
  309. break;
  310. case FLOAT :
  311. cname = "float";
  312. break;
  313. case DOUBLE :
  314. cname = "double";
  315. break;
  316. case VOID :
  317. cname = "void";
  318. break;
  319. default :
  320. fatal();
  321. }
  322. while (dim-- > 0)
  323. cname += "[]";
  324. return lookupClass(cname, false);
  325. }
  326. /**
  327. * @param name a qualified class name. e.g. java.lang.String
  328. */
  329. public CtClass lookupClass(String name, boolean notCheckInner)
  330. throws CompileError
  331. {
  332. try {
  333. return lookupClass0(name, notCheckInner);
  334. }
  335. catch (NotFoundException e) {
  336. return searchImports(name);
  337. }
  338. }
  339. private CtClass searchImports(String orgName)
  340. throws CompileError
  341. {
  342. if (orgName.indexOf('.') < 0) {
  343. Iterator it = classPool.getImportedPackages();
  344. while (it.hasNext()) {
  345. String pac = (String)it.next();
  346. String fqName = pac + '.' + orgName;
  347. try {
  348. CtClass cc = classPool.get(fqName);
  349. // if the class is found,
  350. classPool.recordInvalidClassName(orgName);
  351. return cc;
  352. }
  353. catch (NotFoundException e) {
  354. classPool.recordInvalidClassName(fqName);
  355. }
  356. }
  357. }
  358. throw new CompileError("no such class: " + orgName);
  359. }
  360. private CtClass lookupClass0(String classname, boolean notCheckInner)
  361. throws NotFoundException
  362. {
  363. CtClass cc = null;
  364. do {
  365. try {
  366. cc = classPool.get(classname);
  367. }
  368. catch (NotFoundException e) {
  369. int i = classname.lastIndexOf('.');
  370. if (notCheckInner || i < 0)
  371. throw e;
  372. else {
  373. StringBuffer sbuf = new StringBuffer(classname);
  374. sbuf.setCharAt(i, '$');
  375. classname = sbuf.toString();
  376. }
  377. }
  378. } while (cc == null);
  379. return cc;
  380. }
  381. /* Converts a class name into a JVM-internal representation.
  382. *
  383. * It may also expand a simple class name to java.lang.*.
  384. * For example, this converts Object into java/lang/Object.
  385. */
  386. public String resolveClassName(ASTList name) throws CompileError {
  387. if (name == null)
  388. return null;
  389. else
  390. return javaToJvmName(lookupClassByName(name).getName());
  391. }
  392. /* Expands a simple class name to java.lang.*.
  393. * For example, this converts Object into java/lang/Object.
  394. */
  395. public String resolveJvmClassName(String jvmName) throws CompileError {
  396. if (jvmName == null)
  397. return null;
  398. else
  399. return javaToJvmName(lookupClassByJvmName(jvmName).getName());
  400. }
  401. public static CtClass getSuperclass(CtClass c) throws CompileError {
  402. try {
  403. CtClass sc = c.getSuperclass();
  404. if (sc != null)
  405. return sc;
  406. }
  407. catch (NotFoundException e) {}
  408. throw new CompileError("cannot find the super class of "
  409. + c.getName());
  410. }
  411. public static String javaToJvmName(String classname) {
  412. return classname.replace('.', '/');
  413. }
  414. public static String jvmToJavaName(String classname) {
  415. return classname.replace('/', '.');
  416. }
  417. public static int descToType(char c) throws CompileError {
  418. switch (c) {
  419. case 'Z' :
  420. return BOOLEAN;
  421. case 'C' :
  422. return CHAR;
  423. case 'B' :
  424. return BYTE;
  425. case 'S' :
  426. return SHORT;
  427. case 'I' :
  428. return INT;
  429. case 'J' :
  430. return LONG;
  431. case 'F' :
  432. return FLOAT;
  433. case 'D' :
  434. return DOUBLE;
  435. case 'V' :
  436. return VOID;
  437. case 'L' :
  438. case '[' :
  439. return CLASS;
  440. default :
  441. fatal();
  442. return VOID; // never reach here
  443. }
  444. }
  445. public static int getModifiers(ASTList mods) {
  446. int m = 0;
  447. while (mods != null) {
  448. Keyword k = (Keyword)mods.head();
  449. mods = mods.tail();
  450. switch (k.get()) {
  451. case STATIC :
  452. m |= Modifier.STATIC;
  453. break;
  454. case FINAL :
  455. m |= Modifier.FINAL;
  456. break;
  457. case SYNCHRONIZED :
  458. m |= Modifier.SYNCHRONIZED;
  459. break;
  460. case ABSTRACT :
  461. m |= Modifier.ABSTRACT;
  462. break;
  463. case PUBLIC :
  464. m |= Modifier.PUBLIC;
  465. break;
  466. case PROTECTED :
  467. m |= Modifier.PROTECTED;
  468. break;
  469. case PRIVATE :
  470. m |= Modifier.PRIVATE;
  471. break;
  472. case VOLATILE :
  473. m |= Modifier.VOLATILE;
  474. break;
  475. case TRANSIENT :
  476. m |= Modifier.TRANSIENT;
  477. break;
  478. case STRICT :
  479. m |= Modifier.STRICT;
  480. break;
  481. }
  482. }
  483. return m;
  484. }
  485. }