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.

TypeFactory.java 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  1. /* *******************************************************************
  2. * Copyright (c) 2005-2010 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. package org.aspectj.weaver;
  10. import java.util.ArrayList;
  11. import java.util.List;
  12. /**
  13. * @author Adrian Colyer
  14. * @author Andy Clement
  15. */
  16. public class TypeFactory {
  17. /**
  18. * Create a parameterized version of a generic type.
  19. *
  20. * @param aBaseType
  21. * @param someTypeParameters note, in the case of an inner type of a parameterized type, this parameter may legitimately be null
  22. * @param inAWorld
  23. * @return
  24. */
  25. public static ReferenceType createParameterizedType(ResolvedType aBaseType, UnresolvedType[] someTypeParameters, World inAWorld) {
  26. ResolvedType baseType = aBaseType;
  27. if (!aBaseType.isGenericType()) {
  28. if (someTypeParameters != null && someTypeParameters.length > 0) {
  29. if (!aBaseType.isRawType()) {
  30. throw new IllegalStateException("Expecting raw type, but " + aBaseType+" is of type "+aBaseType.getTypekind());
  31. }
  32. baseType = baseType.getGenericType();
  33. if (baseType == null) {
  34. throw new IllegalStateException("Raw type does not have generic type set");
  35. }
  36. } // else if someTypeParameters is null, then the base type is allowed to be non-generic, it's an inner
  37. }
  38. ResolvedType[] resolvedParameters = inAWorld.resolve(someTypeParameters);
  39. ReferenceType existingType = ((ReferenceType)baseType).findDerivativeType(resolvedParameters);
  40. ReferenceType pType = null;
  41. if (existingType!=null) {
  42. pType = existingType;
  43. } else {
  44. pType =new ReferenceType(baseType, resolvedParameters, inAWorld);
  45. }
  46. // pType.setSourceContext(aBaseType.getSourceContext());
  47. return (ReferenceType) pType.resolve(inAWorld);
  48. }
  49. /**
  50. * Create an *unresolved* parameterized version of a generic type.
  51. */
  52. public static UnresolvedType createUnresolvedParameterizedType(String sig, String erasuresig, UnresolvedType[] arguments) {
  53. return new UnresolvedType(sig, erasuresig, arguments);
  54. }
  55. // public static ReferenceType createRawType(
  56. // ResolvedType aBaseType,
  57. // World inAWorld
  58. // ) {
  59. // if (aBaseType.isRawType()) return (ReferenceType) aBaseType;
  60. // if (!aBaseType.isGenericType()) {
  61. // if (!aBaseType.isRawType()) throw new IllegalStateException("Expecting generic type");
  62. // }
  63. // ReferenceType rType = new ReferenceType(aBaseType,inAWorld);
  64. // //rType.setSourceContext(aBaseType.getSourceContext());
  65. // return (ReferenceType) rType.resolve(inAWorld);
  66. // }
  67. /**
  68. * Creates a sensible unresolvedtype from some signature, for example: signature = LIGuard<TT;>; bound = toString=IGuard<T>
  69. * sig=PIGuard<TT;>; sigErasure=LIGuard; kind=parameterized
  70. */
  71. static UnresolvedType convertSigToType(String aSignature) {
  72. UnresolvedType bound = null;
  73. int startOfParams = aSignature.indexOf('<');
  74. if (startOfParams == -1) {
  75. bound = UnresolvedType.forSignature(aSignature);
  76. } else {
  77. int endOfParams = aSignature.lastIndexOf('>');
  78. String signatureErasure = "L" + aSignature.substring(1, startOfParams) + ";";
  79. UnresolvedType[] typeParams = createTypeParams(aSignature.substring(startOfParams + 1, endOfParams));
  80. bound = new UnresolvedType("P" + aSignature.substring(1), signatureErasure, typeParams);
  81. }
  82. return bound;
  83. }
  84. /**
  85. * Used by UnresolvedType.read, creates a type from a full signature.
  86. */
  87. public static UnresolvedType createTypeFromSignature(String signature) {
  88. // if (signature.equals(ResolvedType.MISSING_NAME)) {
  89. // return ResolvedType.MISSING;
  90. // }
  91. char firstChar = signature.charAt(0);
  92. if (firstChar == 'P') {
  93. // parameterized type, calculate signature erasure and type parameters
  94. // (see pr122458) It is possible for a parameterized type to have *no* type parameters visible in its signature.
  95. // This happens for an inner type of a parameterized type which simply inherits the type parameters
  96. // of its parent. In this case it is parameterized but theres no < in the signature.
  97. int startOfParams = signature.indexOf('<');
  98. if (startOfParams == -1) {
  99. // Should be an inner type of a parameterized type - could assert there is a '$' in the signature....
  100. String signatureErasure = "L" + signature.substring(1);
  101. return new UnresolvedType(signature, signatureErasure, UnresolvedType.NONE);
  102. } else {
  103. int endOfParams = locateMatchingEndAngleBracket(signature, startOfParams);
  104. StringBuilder erasureSig = new StringBuilder(signature);
  105. erasureSig.setCharAt(0, 'L');
  106. while (startOfParams != -1) {
  107. erasureSig.delete(startOfParams, endOfParams + 1);
  108. startOfParams = locateFirstBracket(erasureSig);
  109. if (startOfParams != -1) {
  110. endOfParams = locateMatchingEndAngleBracket(erasureSig, startOfParams);
  111. }
  112. }
  113. String signatureErasure = erasureSig.toString();// "L" + erasureSig.substring(1);
  114. // the type parameters of interest are only those that apply to the 'last type' in the signature
  115. // if the signature is 'PMyInterface<String>$MyOtherType;' then there are none...
  116. String lastType = null;
  117. int nestedTypePosition = signature.indexOf("$", endOfParams); // don't look for $ INSIDE the parameters
  118. if (nestedTypePosition != -1) {
  119. lastType = signature.substring(nestedTypePosition + 1);
  120. } else {
  121. lastType = new String(signature);
  122. }
  123. startOfParams = lastType.indexOf("<");
  124. UnresolvedType[] typeParams = UnresolvedType.NONE;
  125. if (startOfParams != -1) {
  126. endOfParams = locateMatchingEndAngleBracket(lastType, startOfParams);
  127. typeParams = createTypeParams(lastType.substring(startOfParams + 1, endOfParams));
  128. }
  129. StringBuilder s = new StringBuilder();
  130. int firstAngleBracket = signature.indexOf('<');
  131. s.append("P").append(signature.substring(1, firstAngleBracket));
  132. s.append('<');
  133. for (UnresolvedType typeParameter : typeParams) {
  134. s.append(typeParameter.getSignature());
  135. }
  136. s.append(">;");
  137. signature = s.toString();// 'P' + signature.substring(1);
  138. return new UnresolvedType(signature, signatureErasure, typeParams);
  139. }
  140. // can't replace above with convertSigToType - leads to stackoverflow
  141. } else if ((firstChar == '?' || firstChar == '*') && signature.length()==1) {
  142. return WildcardedUnresolvedType.QUESTIONMARK;
  143. } else if (firstChar == '+') {
  144. // ? extends ...
  145. UnresolvedType upperBound = convertSigToType(signature.substring(1));
  146. WildcardedUnresolvedType wildcardedUT = new WildcardedUnresolvedType(signature, upperBound, null);
  147. return wildcardedUT;
  148. } else if (firstChar == '-') {
  149. // ? super ...
  150. UnresolvedType lowerBound = convertSigToType(signature.substring(1));
  151. WildcardedUnresolvedType wildcardedUT = new WildcardedUnresolvedType(signature, null, lowerBound);
  152. return wildcardedUT;
  153. } else if (firstChar == 'T') {
  154. String typeVariableName = signature.substring(1);
  155. if (typeVariableName.endsWith(";")) {
  156. typeVariableName = typeVariableName.substring(0, typeVariableName.length() - 1);
  157. }
  158. return new UnresolvedTypeVariableReferenceType(new TypeVariable(typeVariableName));
  159. } else if (firstChar == '[') {
  160. int dims = 0;
  161. while (signature.charAt(dims) == '[') {
  162. dims++;
  163. }
  164. UnresolvedType componentType = createTypeFromSignature(signature.substring(dims));
  165. return new UnresolvedType(signature, signature.substring(0, dims) + componentType.getErasureSignature());
  166. } else if (signature.length() == 1) { // could be a primitive
  167. switch (firstChar) {
  168. case 'V':
  169. return UnresolvedType.VOID;
  170. case 'Z':
  171. return UnresolvedType.BOOLEAN;
  172. case 'B':
  173. return UnresolvedType.BYTE;
  174. case 'C':
  175. return UnresolvedType.CHAR;
  176. case 'D':
  177. return UnresolvedType.DOUBLE;
  178. case 'F':
  179. return UnresolvedType.FLOAT;
  180. case 'I':
  181. return UnresolvedType.INT;
  182. case 'J':
  183. return UnresolvedType.LONG;
  184. case 'S':
  185. return UnresolvedType.SHORT;
  186. }
  187. } else if (firstChar == '@') {
  188. // missing type
  189. return ResolvedType.MISSING;
  190. } else if (firstChar == 'L') {
  191. // only an issue if there is also an angle bracket
  192. int leftAngleBracket = signature.indexOf('<');
  193. if (leftAngleBracket == -1) {
  194. return new UnresolvedType(signature);
  195. } else {
  196. int endOfParams = locateMatchingEndAngleBracket(signature, leftAngleBracket);
  197. StringBuilder erasureSig = new StringBuilder(signature);
  198. erasureSig.setCharAt(0, 'L');
  199. while (leftAngleBracket != -1) {
  200. erasureSig.delete(leftAngleBracket, endOfParams + 1);
  201. leftAngleBracket = locateFirstBracket(erasureSig);
  202. if (leftAngleBracket != -1) {
  203. endOfParams = locateMatchingEndAngleBracket(erasureSig, leftAngleBracket);
  204. }
  205. }
  206. String signatureErasure = erasureSig.toString();
  207. // TODO should consider all the intermediate parameterizations as well!
  208. // the type parameters of interest are only those that apply to the 'last type' in the signature
  209. // if the signature is 'PMyInterface<String>$MyOtherType;' then there are none...
  210. String lastType = null;
  211. int nestedTypePosition = signature.indexOf("$", endOfParams); // don't look for $ INSIDE the parameters
  212. if (nestedTypePosition != -1) {
  213. lastType = signature.substring(nestedTypePosition + 1);
  214. } else {
  215. lastType = new String(signature);
  216. }
  217. leftAngleBracket = lastType.indexOf("<");
  218. UnresolvedType[] typeParams = UnresolvedType.NONE;
  219. if (leftAngleBracket != -1) {
  220. endOfParams = locateMatchingEndAngleBracket(lastType, leftAngleBracket);
  221. typeParams = createTypeParams(lastType.substring(leftAngleBracket + 1, endOfParams));
  222. }
  223. StringBuilder s = new StringBuilder();
  224. int firstAngleBracket = signature.indexOf('<');
  225. s.append("P").append(signature.substring(1, firstAngleBracket));
  226. s.append('<');
  227. for (UnresolvedType typeParameter : typeParams) {
  228. s.append(typeParameter.getSignature());
  229. }
  230. s.append(">;");
  231. signature = s.toString();// 'P' + signature.substring(1);
  232. return new UnresolvedType(signature, signatureErasure, typeParams);
  233. }
  234. }
  235. return new UnresolvedType(signature);
  236. }
  237. private static int locateMatchingEndAngleBracket(CharSequence signature, int startOfParams) {
  238. if (startOfParams == -1) {
  239. return -1;
  240. }
  241. int count = 1;
  242. int idx = startOfParams;
  243. int max = signature.length();
  244. while (idx < max) {
  245. char ch = signature.charAt(++idx);
  246. if (ch == '<') {
  247. count++;
  248. } else if (ch == '>') {
  249. if (count == 1) {
  250. break;
  251. }
  252. count--;
  253. }
  254. }
  255. return idx;
  256. }
  257. private static int locateFirstBracket(StringBuilder signature) {
  258. int idx = 0;
  259. int max = signature.length();
  260. while (idx < max) {
  261. if (signature.charAt(idx) == '<') {
  262. return idx;
  263. }
  264. idx++;
  265. }
  266. return -1;
  267. }
  268. private static UnresolvedType[] createTypeParams(String typeParameterSpecification) {
  269. String remainingToProcess = typeParameterSpecification;
  270. List<UnresolvedType> types = new ArrayList<>();
  271. while (remainingToProcess.length() != 0) {
  272. int endOfSig = 0;
  273. int anglies = 0;
  274. boolean hadAnglies = false;
  275. boolean sigFound = false; // OPTIMIZE can this be done better?
  276. for (endOfSig = 0; (endOfSig < remainingToProcess.length()) && !sigFound; endOfSig++) {
  277. char thisChar = remainingToProcess.charAt(endOfSig);
  278. switch (thisChar) {
  279. case '<':
  280. anglies++;
  281. hadAnglies = true;
  282. break;
  283. case '>':
  284. anglies--;
  285. break;
  286. case '*':
  287. if (anglies==0) {
  288. int nextCharPos = endOfSig+1;
  289. if (nextCharPos>=remainingToProcess.length()) {
  290. sigFound=true;
  291. } else {
  292. char nextChar = remainingToProcess.charAt(nextCharPos);
  293. if (!(nextChar=='+' || nextChar=='-')) {
  294. // dont need to set endOfSig as the loop will increment
  295. // it to the right place before it exits
  296. sigFound=true;
  297. }
  298. }
  299. }
  300. break;
  301. case '[':
  302. if (anglies == 0) {
  303. // the next char might be a [ or a primitive type ref (BCDFIJSZ)
  304. int nextChar = endOfSig + 1;
  305. while (remainingToProcess.charAt(nextChar) == '[') {
  306. nextChar++;
  307. }
  308. if ("BCDFIJSZ".indexOf(remainingToProcess.charAt(nextChar)) != -1) {
  309. // it is something like [I or [[S
  310. sigFound = true;
  311. endOfSig = nextChar;
  312. break;
  313. }
  314. }
  315. break;
  316. case ';':
  317. if (anglies == 0) {
  318. sigFound = true;
  319. break;
  320. }
  321. }
  322. }
  323. String forProcessing = remainingToProcess.substring(0, endOfSig);
  324. if (hadAnglies && forProcessing.charAt(0) == 'L') {
  325. forProcessing = "P" + forProcessing.substring(1);
  326. }
  327. types.add(createTypeFromSignature(forProcessing));
  328. remainingToProcess = remainingToProcess.substring(endOfSig);
  329. }
  330. UnresolvedType[] typeParams = new UnresolvedType[types.size()];
  331. types.toArray(typeParams);
  332. return typeParams;
  333. }
  334. // OPTIMIZE improve all this signature processing stuff, use char arrays, etc
  335. /**
  336. * Create a signature then delegate to the other factory method. Same input/output: baseTypeSignature="LSomeType;" arguments[0]=
  337. * something with sig "Pcom/Foo&lt;Ljava/lang/String;&gt;;" signature created = "PSomeType&lt;Pcom/Foo&lt;Ljava/lang/String;&gt;;&gt;;"
  338. */
  339. public static UnresolvedType createUnresolvedParameterizedType(String baseTypeSignature, UnresolvedType[] arguments) {
  340. StringBuilder parameterizedSig = new StringBuilder();
  341. parameterizedSig.append(ResolvedType.PARAMETERIZED_TYPE_IDENTIFIER);
  342. parameterizedSig.append(baseTypeSignature.substring(1, baseTypeSignature.length() - 1));
  343. if (arguments.length > 0) {
  344. parameterizedSig.append("<");
  345. for (UnresolvedType argument : arguments) {
  346. parameterizedSig.append(argument.getSignature());
  347. }
  348. parameterizedSig.append(">");
  349. }
  350. parameterizedSig.append(";");
  351. return createUnresolvedParameterizedType(parameterizedSig.toString(), baseTypeSignature, arguments);
  352. }
  353. }