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.

GenericSignatureParsingTest.java 17KB

преди 16 години
преди 16 години
преди 16 години
преди 16 години
преди 16 години
преди 16 години
преди 16 години
преди 16 години
преди 16 години
преди 16 години
преди 16 години
преди 16 години
преди 16 години
преди 16 години
преди 16 години
преди 16 години
преди 16 години
преди 16 години
преди 16 години
преди 16 години
преди 16 години
преди 16 години
преди 16 години
преди 16 години
преди 16 години
преди 16 години
преди 16 години
преди 16 години
преди 16 години
преди 16 години
преди 16 години
преди 16 години
преди 16 години
преди 16 години
преди 16 години
преди 16 години
преди 16 години
преди 16 години
преди 16 години
преди 16 години
преди 16 години
преди 16 години
преди 16 години
преди 16 години
преди 16 години
преди 16 години
преди 16 години
преди 16 години
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472
  1. /* *******************************************************************
  2. * Copyright (c) 2005 Contributors
  3. * All rights reserved.
  4. * This program and the accompanying materials are made available
  5. * under the terms of the Eclipse Public License v 2.0
  6. * which accompanies this distribution and is available at
  7. * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.txt
  8. *
  9. * Contributors:
  10. * Andy Clement (IBM) initial implementation
  11. * ******************************************************************/
  12. package org.aspectj.apache.bcel.classfile.tests;
  13. import java.util.ArrayList;
  14. import java.util.List;
  15. import org.aspectj.apache.bcel.Constants;
  16. import org.aspectj.apache.bcel.classfile.Attribute;
  17. import org.aspectj.apache.bcel.classfile.ClassFormatException;
  18. import org.aspectj.apache.bcel.classfile.JavaClass;
  19. import org.aspectj.apache.bcel.classfile.Method;
  20. import org.aspectj.apache.bcel.classfile.Signature;
  21. import org.aspectj.apache.bcel.classfile.Utility;
  22. /**
  23. * Generics introduces more complex signature possibilities, they are no longer just
  24. * made up of primitives or big 'L' types. The addition of 'anglies' due to
  25. * parameterization and the ability to specify wildcards (possibly bounded)
  26. * when talking about parameterized types means we need to be much more sophisticated.
  27. *
  28. *
  29. * Notes:
  30. * Signatures are used to encode Java programming language type informaiton
  31. * that is not part of the JVM type system, such as generic type and method
  32. * declarations and parameterized types. This kind of information is
  33. * needed to support reflection and debugging, and by the Java compiler.
  34. *
  35. * =============================================
  36. *
  37. * ClassTypeSignature = LPackageSpecifier* SimpleClassTypeSignature ClassTypeSignatureSuffix*;
  38. *
  39. * PackageSpecifier = Identifier/PackageSpecifier*
  40. * SimpleClassTypeSignature= Identifier TypeArguments(opt)
  41. * ClassTypeSignatureSuffix= .SimpleClassTypeSignature
  42. * TypeVariableSignature = TIdentifier;
  43. * TypeArguments = <TypeArgument+>
  44. * TypeArgument = WildcardIndiciator(opt) FieldTypeSignature
  45. * *
  46. * WildcardIndicator = +
  47. * -
  48. * ArrayTypeSignature = [TypeSignature
  49. * TypeSignature = [FieldTypeSignature
  50. * [BaseType
  51. *
  52. * <not sure those [ should be prefixing fts and bt>
  53. * Examples:
  54. * Ljava/util/List; == java.util.List
  55. * Ljava/util/List<Ljava/lang/String;>; == java.util.List<java.lang.String>
  56. * Ljava/util/List<Ljava/lang/Double;>; == java.util.List<java.lang.Double>
  57. * Ljava/util/List<+Ljava/lang/Number;>; == java.util.List<? extends java.lang.Number>
  58. * Ljava/util/List<-Ljava/lang/Number;>; == java.util.List<? super java.lang.Number>
  59. * Ljava/util/List<*>; == java.util.List<?>
  60. * Ljava/util/Map<*-Ljava/lang/Number;>; == java.util.Map<?,? super java.lang.Number>
  61. *
  62. * =============================================
  63. *
  64. * ClassSignature = FormalTypeParameters(opt) SuperclassSignature SuperinterfaceSignatures*
  65. *
  66. * optional formal type parameters then a superclass signature then a superinterface signature
  67. *
  68. * FormalTypeParameters = <FormalTypeParameter+>
  69. * FormalTypeParameter = Identifier ClassBound InterfaceBound*
  70. * ClassBound = :FieldTypeSignature(opt)
  71. * InterfaceBound = :FieldTypeSignature
  72. *
  73. * If it exists, a set of formal type parameters are contained in anglies and consist of an identifier a classbound (assumed to be
  74. * object if not specified) and then an optional list of InterfaceBounds
  75. *
  76. * SuperclassSignature = ClassTypeSignature
  77. * SuperinterfaceSignature = ClassTypeSignature
  78. * FieldTypeSignature = ClassTypeSignature
  79. * ArrayTypeSignature
  80. * TypeVariableSignature
  81. *
  82. *
  83. * MethodTypeSignature = FormalTypeParameters(opt) ( TypeSignature* ) ReturnType ThrowsSignature*
  84. * ReturnType = TypeSignature
  85. * VoidDescriptor
  86. * ThrowsSignature = ^ClassTypeSignature
  87. * ^TypeVariableSignature
  88. *
  89. * Examples:
  90. *
  91. * <T::Ljava/lang/Comparable<-Ljava/lang/Number;>;>
  92. *
  93. * ClassBound not supplied, Object assumed. Interface bound is Comparable<? super Number>
  94. *
  95. * "T:Ljava/lang/Object;:Ljava/lang/Comparable<-TT;>;","T extends java.lang.Object & java.lang.Comparable<? super T>"
  96. *
  97. */
  98. public class GenericSignatureParsingTest extends BcelTestCase {
  99. /**
  100. * Throw some generic format signatures at the BCEL signature
  101. * parsing code and see what it does.
  102. */
  103. public void testParsingGenericSignatures_ClassTypeSignature() {
  104. // trivial
  105. checkClassTypeSignature("Ljava/util/List;","java.util.List");
  106. // basics
  107. checkClassTypeSignature("Ljava/util/List<Ljava/lang/String;>;","java.util.List<java.lang.String>");
  108. checkClassTypeSignature("Ljava/util/List<Ljava/lang/Double;>;","java.util.List<java.lang.Double>");
  109. // madness
  110. checkClassTypeSignature("Ljava/util/List<+Ljava/lang/Number;>;","java.util.List<? extends java.lang.Number>");
  111. checkClassTypeSignature("Ljava/util/List<-Ljava/lang/Number;>;","java.util.List<? super java.lang.Number>");
  112. checkClassTypeSignature("Ljava/util/List<*>;", "java.util.List<?>");
  113. checkClassTypeSignature("Ljava/util/Map<*-Ljava/lang/Number;>;","java.util.Map<?,? super java.lang.Number>");
  114. // with type params
  115. checkClassTypeSignature("Ljava/util/Collection<TT;>;","java.util.Collection<T>");
  116. // arrays
  117. checkClassTypeSignature("Ljava/util/List<[Ljava/lang/String;>;","java.util.List<java.lang.String[]>");
  118. checkClassTypeSignature("[Ljava/util/List<Ljava/lang/String;>;","java.util.List<java.lang.String>[]");
  119. }
  120. public void testMethodTypeToSignature() {
  121. checkMethodTypeToSignature("void",new String[]{"java.lang.String[]","boolean"},"([Ljava/lang/String;Z)V");
  122. checkMethodTypeToSignature("void",new String[]{"java.util.List<java/lang/String>"},"(Ljava/util/List<java/lang/String>;)V");
  123. }
  124. public void testMethodSignatureToArgumentTypes() {
  125. checkMethodSignatureArgumentTypes("([Ljava/lang/String;Z)V",new String[]{"java.lang.String[]","boolean"});
  126. // checkMethodSignatureArgumentTypes("(Ljava/util/List<java/lang/String>;)V",new String[]{"java.util.List<java/lang/String>"});
  127. }
  128. public void testMethodSignatureReturnType() {
  129. checkMethodSignatureReturnType("([Ljava/lang/String;)Z","boolean");
  130. }
  131. public void testLoadingGenerics() throws ClassNotFoundException {
  132. JavaClass clazz = getClassFromJar("PossibleGenericsSigs");
  133. // J5TODO asc fill this bit in...
  134. }
  135. // helper methods below
  136. // These routines call BCEL to determine if it can correctly translate from one form to the other.
  137. private void checkClassTypeSignature(String sig, String expected) {
  138. StringBuffer result = new StringBuffer();
  139. int p = GenericSignatureParsingTest.readClassTypeSignatureFrom(sig,0,result,false);
  140. assertTrue("Only swallowed "+p+" chars of this sig "+sig+" (len="+sig.length()+")",p==sig.length());
  141. assertTrue("Expected '"+expected+"' but got '"+result.toString()+"'",result.toString().equals(expected));
  142. }
  143. private void checkMethodTypeToSignature(String ret,String[] args,String expected) {
  144. String res = GenericSignatureParsingTest.methodTypeToSignature(ret,args);
  145. if (!res.equals(expected)) {
  146. fail("Should match. Got: "+res+" Expected:"+expected);
  147. }
  148. }
  149. private void checkMethodSignatureReturnType(String sig,String expected) {
  150. String result = GenericSignatureParsingTest.methodSignatureReturnType(sig,false);
  151. if (!result.equals(expected)) {
  152. fail("Should match. Got: "+result+" Expected:"+expected);
  153. }
  154. }
  155. private void checkMethodSignatureArgumentTypes(String in,String[] expected) {
  156. String[] result = GenericSignatureParsingTest.methodSignatureArgumentTypes(in,false);
  157. if (result.length!=expected.length) {
  158. fail("Expected "+expected.length+" entries to be returned but only got "+result.length);
  159. }
  160. for (int i = 0; i < expected.length; i++) {
  161. String string = result[i];
  162. if (!string.equals(expected[i]))
  163. fail("Argument: "+i+" should have been "+expected[i]+" but was "+string);
  164. }
  165. }
  166. public Signature getSignatureAttribute(JavaClass clazz,String name) {
  167. Method m = getMethod(clazz,name);
  168. Attribute[] as = m.getAttributes();
  169. for (Attribute attribute : as) {
  170. if (attribute.getName().equals("Signature")) {
  171. return (Signature) attribute;
  172. }
  173. }
  174. return null;
  175. }
  176. /**
  177. * Takes a string and consumes a single complete signature from it, returning
  178. * how many chars it consumed. The chopit flag indicates whether to shorten
  179. * type references ( java/lang/String => String )
  180. *
  181. * FIXME asc this should also create some kind of object you can query for information about whether its parameterized, what the bounds are, etc...
  182. */
  183. public static final int readClassTypeSignatureFrom(String signature, int posn, StringBuffer result, boolean chopit) {
  184. int idx = posn;
  185. try {
  186. switch (signature.charAt(idx)) {
  187. case 'B' : result.append("byte"); return 1;
  188. case 'C' : result.append("char"); return 1;
  189. case 'D' : result.append("double"); return 1;
  190. case 'F' : result.append("float"); return 1;
  191. case 'I' : result.append("int"); return 1;
  192. case 'J' : result.append("long"); return 1;
  193. case 'S' : result.append("short"); return 1;
  194. case 'Z' : result.append("boolean");return 1;
  195. case 'V' : result.append("void"); return 1;
  196. //FIXME ASC Need a state machine to check we are parsing the right stuff here !
  197. case 'T' :
  198. idx++;
  199. int nextSemiIdx = signature.indexOf(';',idx);
  200. result.append(signature.substring(idx,nextSemiIdx));
  201. return nextSemiIdx+1-posn;
  202. case '+' :
  203. result.append("? extends ");
  204. return readClassTypeSignatureFrom(signature,idx+1,result,chopit)+1;
  205. case '-' :
  206. result.append("? super ");
  207. return readClassTypeSignatureFrom(signature,idx+1,result,chopit)+1;
  208. case '*' :
  209. result.append("?");
  210. return 1;
  211. case 'L' : // Full class name
  212. boolean parameterized = false;
  213. int idxSemicolon = signature.indexOf(';',idx); // Look for closing ';' or '<'
  214. int idxAngly = signature.indexOf('<',idx);
  215. int endOfSig = idxSemicolon;
  216. if ((idxAngly!=-1) && idxAngly<endOfSig) { endOfSig = idxAngly; parameterized = true; }
  217. String p = signature.substring(idx+1,endOfSig);
  218. String t = Utility.compactClassName(p,chopit);
  219. result.append(t);
  220. idx=endOfSig;
  221. // we might have finished now, depending on whether this is a parameterized type...
  222. if (parameterized) {
  223. idx++;
  224. result.append("<");
  225. while (signature.charAt(idx)!='>') {
  226. idx+=readClassTypeSignatureFrom(signature,idx,result,chopit);
  227. if (signature.charAt(idx)!='>') result.append(",");
  228. }
  229. result.append(">");idx++;
  230. }
  231. if (signature.charAt(idx)!=';') throw new RuntimeException("Did not find ';' at end of signature, found "+signature.charAt(idx));
  232. idx++;
  233. return idx-posn;
  234. case '[' : // Array declaration
  235. int dim = 0;
  236. while (signature.charAt(idx)=='[') {dim++;idx++;}
  237. idx+=readClassTypeSignatureFrom(signature,idx,result,chopit);
  238. while (dim>0) {result.append("[]");dim--;}
  239. return idx-posn;
  240. default : throw new ClassFormatException("Invalid signature: `" +
  241. signature + "'");
  242. }
  243. } catch(StringIndexOutOfBoundsException e) { // Should never occur
  244. throw new ClassFormatException("Invalid signature: " + e + ":" + signature);
  245. }
  246. }
  247. public static final String readClassTypeSignatureFrom(String signature) {
  248. StringBuffer sb = new StringBuffer();
  249. GenericSignatureParsingTest.readClassTypeSignatureFrom(signature,0,sb,false);
  250. return sb.toString();
  251. }
  252. public static int countBrackets(String brackets) {
  253. char[] chars = brackets.toCharArray();
  254. int count = 0;
  255. boolean open = false;
  256. for (char aChar : chars) {
  257. switch (aChar) {
  258. case '[':
  259. if (open) throw new RuntimeException("Illegally nested brackets:" + brackets);
  260. open = true;
  261. break;
  262. case ']':
  263. if (!open) throw new RuntimeException("Illegally nested brackets:" + brackets);
  264. open = false;
  265. count++;
  266. break;
  267. default:
  268. }
  269. }
  270. if (open) throw new RuntimeException("Illegally nested brackets:" + brackets);
  271. return count;
  272. }
  273. /**
  274. * Parse Java type such as "char", or "java.lang.String[]" and return the
  275. * signature in byte code format, e.g. "C" or "[Ljava/lang/String;" respectively.
  276. *
  277. * @param type Java type
  278. * @return byte code signature
  279. */
  280. public static String getSignature(String type) {
  281. StringBuilder buf = new StringBuilder();
  282. char[] chars = type.toCharArray();
  283. boolean char_found = false, delim = false;
  284. int index = -1;
  285. loop:
  286. for (int i=0; i < chars.length; i++) {
  287. switch (chars[i]) {
  288. case ' ': case '\t': case '\n': case '\r': case '\f':
  289. if (char_found) delim = true;
  290. break;
  291. case '[':
  292. if (!char_found) throw new RuntimeException("Illegal type: " + type);
  293. index = i;
  294. break loop;
  295. default:
  296. char_found = true;
  297. if (!delim) buf.append(chars[i]);
  298. }
  299. }
  300. int brackets = 0;
  301. if(index > 0) brackets = GenericSignatureParsingTest.countBrackets(type.substring(index));
  302. type = buf.toString();
  303. buf.setLength(0);
  304. for (int i=0; i < brackets; i++) buf.append('[');
  305. boolean found = false;
  306. for(int i=Constants.T_BOOLEAN; (i <= Constants.T_VOID) && !found; i++) {
  307. if (Constants.TYPE_NAMES[i].equals(type)) {
  308. found = true;
  309. buf.append(Constants.SHORT_TYPE_NAMES[i]);
  310. }
  311. }
  312. // Class name
  313. if (!found) buf.append('L' + type.replace('.', '/') + ';');
  314. return buf.toString();
  315. }
  316. /**
  317. * For some method signature (class file format) like '([Ljava/lang/String;)Z' this returns
  318. * the string representing the return type its 'normal' form, e.g. 'boolean'
  319. *
  320. * @param signature Method signature
  321. * @param chopit Shorten class names
  322. * @return return type of method
  323. */
  324. public static final String methodSignatureReturnType(String signature,boolean chopit) throws ClassFormatException {
  325. int index;
  326. String type;
  327. try {
  328. // Read return type after `)'
  329. index = signature.lastIndexOf(')') + 1;
  330. type = Utility.signatureToString(signature.substring(index), chopit);
  331. } catch (StringIndexOutOfBoundsException e) {
  332. throw new ClassFormatException("Invalid method signature: " + signature);
  333. }
  334. return type;
  335. }
  336. /**
  337. * For some method signature (class file format) like '([Ljava/lang/String;)Z' this returns
  338. * the string representing the return type its 'normal' form, e.g. 'boolean'
  339. *
  340. * @param signature Method signature
  341. * @return return type of method
  342. * @throws ClassFormatException
  343. */
  344. public static final String methodSignatureReturnType(String signature) throws ClassFormatException {
  345. return GenericSignatureParsingTest.methodSignatureReturnType(signature, true);
  346. }
  347. /**
  348. * For some method signature (class file format) like '([Ljava/lang/String;Z)V' this returns an array
  349. * of strings representing the arguments in their 'normal' form, e.g. '{java.lang.String[],boolean}'
  350. *
  351. * @param signature Method signature
  352. * @param chopit Shorten class names
  353. * @return Array of argument types
  354. */
  355. public static final String[] methodSignatureArgumentTypes(String signature,boolean chopit) throws ClassFormatException {
  356. List<String> vec = new ArrayList<>();
  357. int index;
  358. String[] types;
  359. try { // Read all declarations between for `(' and `)'
  360. if (signature.charAt(0) != '(')
  361. throw new ClassFormatException("Invalid method signature: " + signature);
  362. index = 1; // current string position
  363. while(signature.charAt(index) != ')') {
  364. Utility.ResultHolder rh = Utility.signatureToStringInternal(signature.substring(index),chopit);
  365. vec.add(rh.getResult());
  366. index += rh.getConsumedChars();
  367. }
  368. } catch(StringIndexOutOfBoundsException e) {
  369. throw new ClassFormatException("Invalid method signature: " + signature);
  370. }
  371. types = new String[vec.size()];
  372. vec.toArray(types);
  373. return types;
  374. }
  375. /**
  376. * Converts string containing the method return and argument types
  377. * to a byte code method signature.
  378. *
  379. * @param returnType Return type of method (e.g. "char" or "java.lang.String[]")
  380. * @param methodArgs Types of method arguments
  381. * @return Byte code representation of method signature
  382. */
  383. public final static String methodTypeToSignature(String returnType, String[] methodArgs) throws ClassFormatException {
  384. StringBuilder buf = new StringBuilder("(");
  385. if (methodArgs != null) {
  386. for (String methodArg : methodArgs) {
  387. String str = GenericSignatureParsingTest.getSignature(methodArg);
  388. if (str.equals("V")) // void can't be a method argument
  389. throw new ClassFormatException("Invalid type: " + methodArg);
  390. buf.append(str);
  391. }
  392. }
  393. buf.append(")" + GenericSignatureParsingTest.getSignature(returnType));
  394. return buf.toString();
  395. }
  396. }