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.

Descriptor.java 25KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872
  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.bytecode;
  17. import javassist.ClassPool;
  18. import javassist.CtClass;
  19. import javassist.CtPrimitiveType;
  20. import javassist.NotFoundException;
  21. import java.util.Map;
  22. /**
  23. * A support class for dealing with descriptors.
  24. *
  25. * <p>See chapter 4.3 in "The Java Virtual Machine Specification (2nd ed.)"
  26. */
  27. public class Descriptor {
  28. /**
  29. * Converts a class name into the internal representation used in
  30. * the JVM.
  31. *
  32. * <p>Note that <code>toJvmName(toJvmName(s))</code> is equivalent
  33. * to <code>toJvmName(s)</code>.
  34. */
  35. public static String toJvmName(String classname) {
  36. return classname.replace('.', '/');
  37. }
  38. /**
  39. * Converts a class name from the internal representation used in
  40. * the JVM to the normal one used in Java.
  41. * This method does not deal with an array type name such as
  42. * "[Ljava/lang/Object;" and "[I;". For such names, use
  43. * <code>toClassName()</code>.
  44. *
  45. * @see #toClassName(String)
  46. */
  47. public static String toJavaName(String classname) {
  48. return classname.replace('/', '.');
  49. }
  50. /**
  51. * Returns the internal representation of the class name in the
  52. * JVM.
  53. */
  54. public static String toJvmName(CtClass clazz) {
  55. if (clazz.isArray())
  56. return of(clazz);
  57. else
  58. return toJvmName(clazz.getName());
  59. }
  60. /**
  61. * Converts to a Java class name from a descriptor.
  62. *
  63. * @param descriptor type descriptor.
  64. */
  65. public static String toClassName(String descriptor) {
  66. int arrayDim = 0;
  67. int i = 0;
  68. char c = descriptor.charAt(0);
  69. while (c == '[') {
  70. ++arrayDim;
  71. c = descriptor.charAt(++i);
  72. }
  73. String name;
  74. if (c == 'L') {
  75. int i2 = descriptor.indexOf(';', i++);
  76. name = descriptor.substring(i, i2).replace('/', '.');
  77. i = i2;
  78. }
  79. else if (c == 'V')
  80. name = "void";
  81. else if (c == 'I')
  82. name = "int";
  83. else if (c == 'B')
  84. name = "byte";
  85. else if (c == 'J')
  86. name = "long";
  87. else if (c == 'D')
  88. name = "double";
  89. else if (c == 'F')
  90. name = "float";
  91. else if (c == 'C')
  92. name = "char";
  93. else if (c == 'S')
  94. name = "short";
  95. else if (c == 'Z')
  96. name = "boolean";
  97. else
  98. throw new RuntimeException("bad descriptor: " + descriptor);
  99. if (i + 1 != descriptor.length())
  100. throw new RuntimeException("multiple descriptors?: " + descriptor);
  101. if (arrayDim == 0)
  102. return name;
  103. else {
  104. StringBuffer sbuf = new StringBuffer(name);
  105. do {
  106. sbuf.append("[]");
  107. } while (--arrayDim > 0);
  108. return sbuf.toString();
  109. }
  110. }
  111. /**
  112. * Converts to a descriptor from a Java class name
  113. */
  114. public static String of(String classname) {
  115. if (classname.equals("void"))
  116. return "V";
  117. else if (classname.equals("int"))
  118. return "I";
  119. else if (classname.equals("byte"))
  120. return "B";
  121. else if (classname.equals("long"))
  122. return "J";
  123. else if (classname.equals("double"))
  124. return "D";
  125. else if (classname.equals("float"))
  126. return "F";
  127. else if (classname.equals("char"))
  128. return "C";
  129. else if (classname.equals("short"))
  130. return "S";
  131. else if (classname.equals("boolean"))
  132. return "Z";
  133. else
  134. return "L" + toJvmName(classname) + ";";
  135. }
  136. /**
  137. * Substitutes a class name
  138. * in the given descriptor string.
  139. *
  140. * @param desc descriptor string
  141. * @param oldname replaced JVM class name
  142. * @param newname substituted JVM class name
  143. *
  144. * @see Descriptor#toJvmName(String)
  145. */
  146. public static String rename(String desc, String oldname, String newname) {
  147. if (desc.indexOf(oldname) < 0)
  148. return desc;
  149. StringBuffer newdesc = new StringBuffer();
  150. int head = 0;
  151. int i = 0;
  152. for (;;) {
  153. int j = desc.indexOf('L', i);
  154. if (j < 0)
  155. break;
  156. else if (desc.startsWith(oldname, j + 1)
  157. && desc.charAt(j + oldname.length() + 1) == ';') {
  158. newdesc.append(desc.substring(head, j));
  159. newdesc.append('L');
  160. newdesc.append(newname);
  161. newdesc.append(';');
  162. head = i = j + oldname.length() + 2;
  163. }
  164. else {
  165. i = desc.indexOf(';', j) + 1;
  166. if (i < 1)
  167. break; // ';' was not found.
  168. }
  169. }
  170. if (head == 0)
  171. return desc;
  172. else {
  173. int len = desc.length();
  174. if (head < len)
  175. newdesc.append(desc.substring(head, len));
  176. return newdesc.toString();
  177. }
  178. }
  179. /**
  180. * Substitutes class names in the given descriptor string
  181. * according to the given <code>map</code>.
  182. *
  183. * @param map a map between replaced and substituted
  184. * JVM class names.
  185. * @see Descriptor#toJvmName(String)
  186. */
  187. public static String rename(String desc, Map map) {
  188. if (map == null)
  189. return desc;
  190. StringBuffer newdesc = new StringBuffer();
  191. int head = 0;
  192. int i = 0;
  193. for (;;) {
  194. int j = desc.indexOf('L', i);
  195. if (j < 0)
  196. break;
  197. int k = desc.indexOf(';', j);
  198. if (k < 0)
  199. break;
  200. i = k + 1;
  201. String name = desc.substring(j + 1, k);
  202. String name2 = (String)map.get(name);
  203. if (name2 != null) {
  204. newdesc.append(desc.substring(head, j));
  205. newdesc.append('L');
  206. newdesc.append(name2);
  207. newdesc.append(';');
  208. head = i;
  209. }
  210. }
  211. if (head == 0)
  212. return desc;
  213. else {
  214. int len = desc.length();
  215. if (head < len)
  216. newdesc.append(desc.substring(head, len));
  217. return newdesc.toString();
  218. }
  219. }
  220. /**
  221. * Returns the descriptor representing the given type.
  222. */
  223. public static String of(CtClass type) {
  224. StringBuffer sbuf = new StringBuffer();
  225. toDescriptor(sbuf, type);
  226. return sbuf.toString();
  227. }
  228. private static void toDescriptor(StringBuffer desc, CtClass type) {
  229. if (type.isArray()) {
  230. desc.append('[');
  231. try {
  232. toDescriptor(desc, type.getComponentType());
  233. }
  234. catch (NotFoundException e) {
  235. desc.append('L');
  236. String name = type.getName();
  237. desc.append(toJvmName(name.substring(0, name.length() - 2)));
  238. desc.append(';');
  239. }
  240. }
  241. else if (type.isPrimitive()) {
  242. CtPrimitiveType pt = (CtPrimitiveType)type;
  243. desc.append(pt.getDescriptor());
  244. }
  245. else { // class type
  246. desc.append('L');
  247. desc.append(type.getName().replace('.', '/'));
  248. desc.append(';');
  249. }
  250. }
  251. /**
  252. * Returns the descriptor representing a constructor receiving
  253. * the given parameter types.
  254. *
  255. * @param paramTypes parameter types
  256. */
  257. public static String ofConstructor(CtClass[] paramTypes) {
  258. return ofMethod(CtClass.voidType, paramTypes);
  259. }
  260. /**
  261. * Returns the descriptor representing a method that receives
  262. * the given parameter types and returns the given type.
  263. *
  264. * @param returnType return type
  265. * @param paramTypes parameter types
  266. */
  267. public static String ofMethod(CtClass returnType, CtClass[] paramTypes) {
  268. StringBuffer desc = new StringBuffer();
  269. desc.append('(');
  270. if (paramTypes != null) {
  271. int n = paramTypes.length;
  272. for (int i = 0; i < n; ++i)
  273. toDescriptor(desc, paramTypes[i]);
  274. }
  275. desc.append(')');
  276. if (returnType != null)
  277. toDescriptor(desc, returnType);
  278. return desc.toString();
  279. }
  280. /**
  281. * Returns the descriptor representing a list of parameter types.
  282. * For example, if the given parameter types are two <code>int</code>,
  283. * then this method returns <code>"(II)"</code>.
  284. *
  285. * @param paramTypes parameter types
  286. */
  287. public static String ofParameters(CtClass[] paramTypes) {
  288. return ofMethod(null, paramTypes);
  289. }
  290. /**
  291. * Appends a parameter type to the parameter list represented
  292. * by the given descriptor.
  293. *
  294. * <p><code>classname</code> must not be an array type.
  295. *
  296. * @param classname parameter type (not primitive type)
  297. * @param desc descriptor
  298. */
  299. public static String appendParameter(String classname, String desc) {
  300. int i = desc.indexOf(')');
  301. if (i < 0)
  302. return desc;
  303. else {
  304. StringBuffer newdesc = new StringBuffer();
  305. newdesc.append(desc.substring(0, i));
  306. newdesc.append('L');
  307. newdesc.append(classname.replace('.', '/'));
  308. newdesc.append(';');
  309. newdesc.append(desc.substring(i));
  310. return newdesc.toString();
  311. }
  312. }
  313. /**
  314. * Inserts a parameter type at the beginning of the parameter
  315. * list represented
  316. * by the given descriptor.
  317. *
  318. * <p><code>classname</code> must not be an array type.
  319. *
  320. * @param classname parameter type (not primitive type)
  321. * @param desc descriptor
  322. */
  323. public static String insertParameter(String classname, String desc) {
  324. if (desc.charAt(0) != '(')
  325. return desc;
  326. else
  327. return "(L" + classname.replace('.', '/') + ';'
  328. + desc.substring(1);
  329. }
  330. /**
  331. * Appends a parameter type to the parameter list represented
  332. * by the given descriptor. The appended parameter becomes
  333. * the last parameter.
  334. *
  335. * @param type the type of the appended parameter.
  336. * @param descriptor the original descriptor.
  337. */
  338. public static String appendParameter(CtClass type, String descriptor) {
  339. int i = descriptor.indexOf(')');
  340. if (i < 0)
  341. return descriptor;
  342. else {
  343. StringBuffer newdesc = new StringBuffer();
  344. newdesc.append(descriptor.substring(0, i));
  345. toDescriptor(newdesc, type);
  346. newdesc.append(descriptor.substring(i));
  347. return newdesc.toString();
  348. }
  349. }
  350. /**
  351. * Inserts a parameter type at the beginning of the parameter
  352. * list represented
  353. * by the given descriptor.
  354. *
  355. * @param type the type of the inserted parameter.
  356. * @param descriptor the descriptor of the method.
  357. */
  358. public static String insertParameter(CtClass type,
  359. String descriptor) {
  360. if (descriptor.charAt(0) != '(')
  361. return descriptor;
  362. else
  363. return "(" + of(type) + descriptor.substring(1);
  364. }
  365. /**
  366. * Changes the return type included in the given descriptor.
  367. *
  368. * <p><code>classname</code> must not be an array type.
  369. *
  370. * @param classname return type
  371. * @param desc descriptor
  372. */
  373. public static String changeReturnType(String classname, String desc) {
  374. int i = desc.indexOf(')');
  375. if (i < 0)
  376. return desc;
  377. else {
  378. StringBuffer newdesc = new StringBuffer();
  379. newdesc.append(desc.substring(0, i + 1));
  380. newdesc.append('L');
  381. newdesc.append(classname.replace('.', '/'));
  382. newdesc.append(';');
  383. return newdesc.toString();
  384. }
  385. }
  386. /**
  387. * Returns the <code>CtClass</code> objects representing the parameter
  388. * types specified by the given descriptor.
  389. *
  390. * @param desc descriptor
  391. * @param cp the class pool used for obtaining
  392. * a <code>CtClass</code> object.
  393. */
  394. public static CtClass[] getParameterTypes(String desc, ClassPool cp)
  395. throws NotFoundException
  396. {
  397. if (desc.charAt(0) != '(')
  398. return null;
  399. else {
  400. int num = numOfParameters(desc);
  401. CtClass[] args = new CtClass[num];
  402. int n = 0;
  403. int i = 1;
  404. do {
  405. i = toCtClass(cp, desc, i, args, n++);
  406. } while (i > 0);
  407. return args;
  408. }
  409. }
  410. /**
  411. * Returns true if the list of the parameter types of desc1 is equal to
  412. * that of desc2.
  413. * For example, "(II)V" and "(II)I" are equal.
  414. */
  415. public static boolean eqParamTypes(String desc1, String desc2) {
  416. if (desc1.charAt(0) != '(')
  417. return false;
  418. for (int i = 0; true; ++i) {
  419. char c = desc1.charAt(i);
  420. if (c != desc2.charAt(i))
  421. return false;
  422. if (c == ')')
  423. return true;
  424. }
  425. }
  426. /**
  427. * Returns the signature of the given descriptor. The signature does
  428. * not include the return type. For example, the signature of "(I)V"
  429. * is "(I)".
  430. */
  431. public static String getParamDescriptor(String decl) {
  432. return decl.substring(0, decl.indexOf(')') + 1);
  433. }
  434. /**
  435. * Returns the <code>CtClass</code> object representing the return
  436. * type specified by the given descriptor.
  437. *
  438. * @param desc descriptor
  439. * @param cp the class pool used for obtaining
  440. * a <code>CtClass</code> object.
  441. */
  442. public static CtClass getReturnType(String desc, ClassPool cp)
  443. throws NotFoundException
  444. {
  445. int i = desc.indexOf(')');
  446. if (i < 0)
  447. return null;
  448. else {
  449. CtClass[] type = new CtClass[1];
  450. toCtClass(cp, desc, i + 1, type, 0);
  451. return type[0];
  452. }
  453. }
  454. /**
  455. * Returns the number of the prameters included in the given
  456. * descriptor.
  457. *
  458. * @param desc descriptor
  459. */
  460. public static int numOfParameters(String desc) {
  461. int n = 0;
  462. int i = 1;
  463. for (;;) {
  464. char c = desc.charAt(i);
  465. if (c == ')')
  466. break;
  467. while (c == '[')
  468. c = desc.charAt(++i);
  469. if (c == 'L') {
  470. i = desc.indexOf(';', i) + 1;
  471. if (i <= 0)
  472. throw new IndexOutOfBoundsException("bad descriptor");
  473. }
  474. else
  475. ++i;
  476. ++n;
  477. }
  478. return n;
  479. }
  480. /**
  481. * Returns a <code>CtClass</code> object representing the type
  482. * specified by the given descriptor.
  483. *
  484. * <p>This method works even if the package-class separator is
  485. * not <code>/</code> but <code>.</code> (period). For example,
  486. * it accepts <code>Ljava.lang.Object;</code>
  487. * as well as <code>Ljava/lang/Object;</code>.
  488. *
  489. * @param desc descriptor.
  490. * @param cp the class pool used for obtaining
  491. * a <code>CtClass</code> object.
  492. */
  493. public static CtClass toCtClass(String desc, ClassPool cp)
  494. throws NotFoundException
  495. {
  496. CtClass[] clazz = new CtClass[1];
  497. int res = toCtClass(cp, desc, 0, clazz, 0);
  498. if (res >= 0)
  499. return clazz[0];
  500. else {
  501. // maybe, you forgot to surround the class name with
  502. // L and ;. It violates the protocol, but I'm tolerant...
  503. return cp.get(desc.replace('/', '.'));
  504. }
  505. }
  506. private static int toCtClass(ClassPool cp, String desc, int i,
  507. CtClass[] args, int n)
  508. throws NotFoundException
  509. {
  510. int i2;
  511. String name;
  512. int arrayDim = 0;
  513. char c = desc.charAt(i);
  514. while (c == '[') {
  515. ++arrayDim;
  516. c = desc.charAt(++i);
  517. }
  518. if (c == 'L') {
  519. i2 = desc.indexOf(';', ++i);
  520. name = desc.substring(i, i2++).replace('/', '.');
  521. }
  522. else {
  523. CtClass type = toPrimitiveClass(c);
  524. if (type == null)
  525. return -1; // error
  526. i2 = i + 1;
  527. if (arrayDim == 0) {
  528. args[n] = type;
  529. return i2; // neither an array type or a class type
  530. }
  531. else
  532. name = type.getName();
  533. }
  534. if (arrayDim > 0) {
  535. StringBuffer sbuf = new StringBuffer(name);
  536. while (arrayDim-- > 0)
  537. sbuf.append("[]");
  538. name = sbuf.toString();
  539. }
  540. args[n] = cp.get(name);
  541. return i2;
  542. }
  543. static CtClass toPrimitiveClass(char c) {
  544. CtClass type = null;
  545. switch (c) {
  546. case 'Z' :
  547. type = CtClass.booleanType;
  548. break;
  549. case 'C' :
  550. type = CtClass.charType;
  551. break;
  552. case 'B' :
  553. type = CtClass.byteType;
  554. break;
  555. case 'S' :
  556. type = CtClass.shortType;
  557. break;
  558. case 'I' :
  559. type = CtClass.intType;
  560. break;
  561. case 'J' :
  562. type = CtClass.longType;
  563. break;
  564. case 'F' :
  565. type = CtClass.floatType;
  566. break;
  567. case 'D' :
  568. type = CtClass.doubleType;
  569. break;
  570. case 'V' :
  571. type = CtClass.voidType;
  572. break;
  573. }
  574. return type;
  575. }
  576. /**
  577. * Computes the dimension of the array represented by the given
  578. * descriptor. For example, if the descriptor is <code>"[[I"</code>,
  579. * then this method returns 2.
  580. *
  581. * @param desc the descriptor.
  582. * @return 0 if the descriptor does not represent an array type.
  583. */
  584. public static int arrayDimension(String desc) {
  585. int dim = 0;
  586. while (desc.charAt(dim) == '[')
  587. ++dim;
  588. return dim;
  589. }
  590. /**
  591. * Returns the descriptor of the type of the array component.
  592. * For example, if the given descriptor is
  593. * <code>"[[Ljava/lang/String;"</code> and the given dimension is 2,
  594. * then this method returns <code>"Ljava/lang/String;"</code>.
  595. *
  596. * @param desc the descriptor.
  597. * @param dim the array dimension.
  598. */
  599. public static String toArrayComponent(String desc, int dim) {
  600. return desc.substring(dim);
  601. }
  602. /**
  603. * Computes the data size specified by the given descriptor.
  604. * For example, if the descriptor is "D", this method returns 2.
  605. *
  606. * <p>If the descriptor represents a method type, this method returns
  607. * (the size of the returned value) - (the sum of the data sizes
  608. * of all the parameters). For example, if the descriptor is
  609. * <code>"(I)D"</code>, then this method returns 1 (= 2 - 1).
  610. *
  611. * @param desc descriptor
  612. */
  613. public static int dataSize(String desc) {
  614. return dataSize(desc, true);
  615. }
  616. /**
  617. * Computes the data size of parameters.
  618. * If one of the parameters is double type, the size of that parameter
  619. * is 2 words. For example, if the given descriptor is
  620. * <code>"(IJ)D"</code>, then this method returns 3. The size of the
  621. * return type is not computed.
  622. *
  623. * @param desc a method descriptor.
  624. */
  625. public static int paramSize(String desc) {
  626. return -dataSize(desc, false);
  627. }
  628. private static int dataSize(String desc, boolean withRet) {
  629. int n = 0;
  630. char c = desc.charAt(0);
  631. if (c == '(') {
  632. int i = 1;
  633. for (;;) {
  634. c = desc.charAt(i);
  635. if (c == ')') {
  636. c = desc.charAt(i + 1);
  637. break;
  638. }
  639. boolean array = false;
  640. while (c == '[') {
  641. array = true;
  642. c = desc.charAt(++i);
  643. }
  644. if (c == 'L') {
  645. i = desc.indexOf(';', i) + 1;
  646. if (i <= 0)
  647. throw new IndexOutOfBoundsException("bad descriptor");
  648. }
  649. else
  650. ++i;
  651. if (!array && (c == 'J' || c == 'D'))
  652. n -= 2;
  653. else
  654. --n;
  655. }
  656. }
  657. if (withRet)
  658. if (c == 'J' || c == 'D')
  659. n += 2;
  660. else if (c != 'V')
  661. ++n;
  662. return n;
  663. }
  664. /**
  665. * Returns a human-readable representation of the
  666. * given descriptor. For example, <code>Ljava/lang/Object;</code>
  667. * is converted into <code>java.lang.Object</code>.
  668. * <code>(I[I)V</code> is converted into <code>(int, int[])</code>
  669. * (the return type is ignored).
  670. */
  671. public static String toString(String desc) {
  672. return PrettyPrinter.toString(desc);
  673. }
  674. static class PrettyPrinter {
  675. static String toString(String desc) {
  676. StringBuffer sbuf = new StringBuffer();
  677. if (desc.charAt(0) == '(') {
  678. int pos = 1;
  679. sbuf.append('(');
  680. while (desc.charAt(pos) != ')') {
  681. if (pos > 1)
  682. sbuf.append(',');
  683. pos = readType(sbuf, pos, desc);
  684. }
  685. sbuf.append(')');
  686. }
  687. else
  688. readType(sbuf, 0, desc);
  689. return sbuf.toString();
  690. }
  691. static int readType(StringBuffer sbuf, int pos, String desc) {
  692. char c = desc.charAt(pos);
  693. int arrayDim = 0;
  694. while (c == '[') {
  695. arrayDim++;
  696. c = desc.charAt(++pos);
  697. }
  698. if (c == 'L')
  699. while (true) {
  700. c = desc.charAt(++pos);
  701. if (c == ';')
  702. break;
  703. if (c == '/')
  704. c = '.';
  705. sbuf.append(c);
  706. }
  707. else {
  708. CtClass t = toPrimitiveClass(c);
  709. sbuf.append(t.getName());
  710. }
  711. while (arrayDim-- > 0)
  712. sbuf.append("[]");
  713. return pos + 1;
  714. }
  715. }
  716. /**
  717. * An Iterator over a descriptor.
  718. */
  719. public static class Iterator {
  720. private String desc;
  721. private int index, curPos;
  722. private boolean param;
  723. /**
  724. * Constructs an iterator.
  725. *
  726. * @param s descriptor.
  727. */
  728. public Iterator(String s) {
  729. desc = s;
  730. index = curPos = 0;
  731. param = false;
  732. }
  733. /**
  734. * Returns true if the iteration has more elements.
  735. */
  736. public boolean hasNext() {
  737. return index < desc.length();
  738. }
  739. /**
  740. * Returns true if the current element is a parameter type.
  741. */
  742. public boolean isParameter() { return param; }
  743. /**
  744. * Returns the first character of the current element.
  745. */
  746. public char currentChar() { return desc.charAt(curPos); }
  747. /**
  748. * Returns true if the current element is double or long type.
  749. */
  750. public boolean is2byte() {
  751. char c = currentChar();
  752. return c == 'D' || c == 'J';
  753. }
  754. /**
  755. * Returns the position of the next type character.
  756. * That type character becomes a new current element.
  757. */
  758. public int next() {
  759. int nextPos = index;
  760. char c = desc.charAt(nextPos);
  761. if (c == '(') {
  762. ++index;
  763. c = desc.charAt(++nextPos);
  764. param = true;
  765. }
  766. if (c == ')') {
  767. ++index;
  768. c = desc.charAt(++nextPos);
  769. param = false;
  770. }
  771. while (c == '[')
  772. c = desc.charAt(++nextPos);
  773. if (c == 'L') {
  774. nextPos = desc.indexOf(';', nextPos) + 1;
  775. if (nextPos <= 0)
  776. throw new IndexOutOfBoundsException("bad descriptor");
  777. }
  778. else
  779. ++nextPos;
  780. curPos = index;
  781. index = nextPos;
  782. return curPos;
  783. }
  784. }
  785. }