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.

JDTLikeHandleProvider.java 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471
  1. /********************************************************************
  2. * Copyright (c) 2006 Contributors. All rights reserved.
  3. * This program and the accompanying materials are made available
  4. * under the terms of the Eclipse Public License v 2.0
  5. * which accompanies this distribution and is available at
  6. * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.txt
  7. *
  8. * Contributors: IBM Corporation - initial API and implementation
  9. * Helen Hawkins - initial version
  10. *******************************************************************/
  11. package org.aspectj.asm.internal;
  12. import java.io.File;
  13. import java.util.List;
  14. import org.aspectj.asm.AsmManager;
  15. import org.aspectj.asm.IElementHandleProvider;
  16. import org.aspectj.asm.IProgramElement;
  17. import org.aspectj.bridge.ISourceLocation;
  18. /**
  19. * Creates JDT-like handles, for example
  20. *
  21. * method with string argument: <tjp{Demo.java[Demo~main~\[QString; method with generic argument:
  22. * <pkg{MyClass.java[MyClass~myMethod~QList\<QString;>; an aspect: <pkg*A1.aj}A1 advice with Integer arg:
  23. * <pkg*A8.aj}A8&afterReturning&QInteger; method call: <pkg*A10.aj[C~m1?method-call(void pkg.C.m2())
  24. *
  25. */
  26. public class JDTLikeHandleProvider implements IElementHandleProvider {
  27. private final AsmManager asm;
  28. private static final char[] empty = new char[] {};
  29. private static final char[] countDelim = new char[] { HandleProviderDelimiter.COUNT.getDelimiter() };
  30. private static final String backslash = "\\";
  31. private static final String emptyString = "";
  32. public JDTLikeHandleProvider(AsmManager asm) {
  33. this.asm = asm;
  34. }
  35. public void initialize() {
  36. // nothing to do
  37. }
  38. public String createHandleIdentifier(IProgramElement ipe) {
  39. // AjBuildManager.setupModel --> top of the tree is either
  40. // <root> or the .lst file
  41. if (ipe == null || (ipe.getKind().equals(IProgramElement.Kind.FILE_JAVA) && ipe.getName().equals("<root>"))) {
  42. return "";
  43. } else if (ipe.getHandleIdentifier(false) != null) {
  44. // have already created the handle for this ipe
  45. // therefore just return it
  46. return ipe.getHandleIdentifier();
  47. } else if (ipe.getKind().equals(IProgramElement.Kind.FILE_LST)) {
  48. String configFile = asm.getHierarchy().getConfigFile();
  49. int start = configFile.lastIndexOf(File.separator);
  50. int end = configFile.lastIndexOf(".lst");
  51. if (end != -1) {
  52. configFile = configFile.substring(start + 1, end);
  53. } else {
  54. configFile = new StringBuilder("=").append(configFile.substring(start + 1)).toString();
  55. }
  56. ipe.setHandleIdentifier(configFile);
  57. return configFile;
  58. } else if (ipe.getKind() == IProgramElement.Kind.SOURCE_FOLDER) {
  59. StringBuilder sb = new StringBuilder();
  60. sb.append(createHandleIdentifier(ipe.getParent())).append("/");
  61. // pr249216 - escape any embedded slashes
  62. String folder = ipe.getName();
  63. if (folder.endsWith("/")) {
  64. folder = folder.substring(0, folder.length() - 1);
  65. }
  66. if (folder.contains("/")) {
  67. folder = folder.replace("/", "\\/");
  68. }
  69. sb.append(folder);
  70. String handle = sb.toString();
  71. ipe.setHandleIdentifier(handle);
  72. return handle;
  73. }
  74. IProgramElement parent = ipe.getParent();
  75. if (parent != null && parent.getKind().equals(IProgramElement.Kind.IMPORT_REFERENCE)) {
  76. // want to miss out '#import declaration' in the handle
  77. parent = ipe.getParent().getParent();
  78. }
  79. StringBuilder handle = new StringBuilder();
  80. // add the handle for the parent
  81. handle.append(createHandleIdentifier(parent));
  82. // add the correct delimiter for this ipe
  83. handle.append(HandleProviderDelimiter.getDelimiter(ipe));
  84. // add the name and any parameters unless we're an initializer
  85. // (initializer's names are '...')
  86. if (!ipe.getKind().equals(IProgramElement.Kind.INITIALIZER)) {
  87. if (ipe.getKind() == IProgramElement.Kind.CLASS && ipe.getName().endsWith("{..}")) {
  88. // format: 'new Runnable() {..}' but its anon-y-mouse
  89. // dont append anything, there may be a count to follow though (!<n>)
  90. } else {
  91. if (ipe.getKind() == IProgramElement.Kind.INTER_TYPE_CONSTRUCTOR) {
  92. handle.append(ipe.getName()).append("_new").append(getParameters(ipe));
  93. } else {
  94. // if (ipe.getKind() == IProgramElement.Kind.PACKAGE && ipe.getName().equals("DEFAULT")) {
  95. // // the delimiter will be in there, but skip the word DEFAULT as it is just a placeholder
  96. // } else {
  97. if (ipe.getKind().isDeclareAnnotation()) {
  98. // escape the @ (pr249216c9)
  99. handle.append("declare \\@").append(ipe.getName().substring(9)).append(getParameters(ipe));
  100. } else {
  101. if (ipe.getFullyQualifiedName() != null) {
  102. handle.append(ipe.getFullyQualifiedName());
  103. } else {
  104. handle.append(ipe.getName());
  105. }
  106. handle.append(getParameters(ipe));
  107. }
  108. }
  109. // }
  110. }
  111. }
  112. // add the count, for example '!2' if its the second ipe of its
  113. // kind in the aspect
  114. handle.append(getCount(ipe));
  115. ipe.setHandleIdentifier(handle.toString());
  116. return handle.toString();
  117. }
  118. private String getParameters(IProgramElement ipe) {
  119. if (ipe.getParameterSignatures() == null || ipe.getParameterSignatures().isEmpty()) {
  120. return "";
  121. }
  122. List<String> sourceRefs = ipe.getParameterSignaturesSourceRefs();
  123. List<char[]> parameterTypes = ipe.getParameterSignatures();
  124. StringBuilder sb = new StringBuilder();
  125. if (sourceRefs != null) {
  126. for (String sourceRef : sourceRefs) {
  127. sb.append(HandleProviderDelimiter.getDelimiter(ipe));
  128. sb.append(sourceRef);
  129. }
  130. } else {
  131. for (char[] element : parameterTypes) {
  132. sb.append(HandleProviderDelimiter.getDelimiter(ipe));
  133. sb.append(NameConvertor.createShortName(element, false, false));
  134. }
  135. }
  136. return sb.toString();
  137. }
  138. /**
  139. * Determine a count to be suffixed to the handle, this is only necessary for identical looking entries at the same level in the
  140. * model (for example two anonymous class declarations). The format is !<n> where n will be greater than 2.
  141. *
  142. * @param ipe the program element for which the handle is being constructed
  143. * @return a char suffix that will either be empty or of the form "!<n>"
  144. */
  145. private char[] getCount(IProgramElement ipe) {
  146. // TODO could optimize this code
  147. char[] byteCodeName = ipe.getBytecodeName().toCharArray();
  148. if (ipe.getKind().isInterTypeMember()) {
  149. int count = 1;
  150. List<IProgramElement> kids = ipe.getParent().getChildren();
  151. for (IProgramElement object : kids) {
  152. if (object.equals(ipe)) {
  153. break;
  154. }
  155. if (object.getKind().isInterTypeMember()) {
  156. if (object.getName().equals(ipe.getName()) && getParameters(object).equals(getParameters(ipe))) {
  157. String existingHandle = object.getHandleIdentifier();
  158. int suffixPosition = existingHandle.indexOf('!');
  159. if (suffixPosition != -1) {
  160. count = Integer.parseInt(existingHandle.substring(suffixPosition + 1)) + 1;
  161. } else {
  162. if (count == 1) {
  163. count = 2;
  164. }
  165. }
  166. }
  167. }
  168. }
  169. if (count > 1) {
  170. return CharOperation.concat(countDelim, Integer.toString(count).toCharArray());
  171. }
  172. } else if (ipe.getKind().isDeclare()) {
  173. // // look at peer declares
  174. int count = computeCountBasedOnPeers(ipe);
  175. if (count > 1) {
  176. return CharOperation.concat(countDelim, Integer.toString(count).toCharArray());
  177. }
  178. } else if (ipe.getKind().equals(IProgramElement.Kind.ADVICE)) {
  179. // Look at any peer advice
  180. int count = 1;
  181. List<IProgramElement> kids = ipe.getParent().getChildren();
  182. String ipeSig = ipe.getBytecodeSignature();
  183. // remove return type from the signature - it should not be included in the comparison
  184. int idx = 0;
  185. ipeSig = shortenIpeSig(ipeSig);
  186. for (IProgramElement object : kids) {
  187. if (object.equals(ipe)) {
  188. break;
  189. }
  190. if (object.getKind() == ipe.getKind()) {
  191. if (object.getName().equals(ipe.getName())) {
  192. String sig1 = object.getBytecodeSignature();
  193. if (sig1 != null && (idx = sig1.indexOf(")")) != -1) {
  194. sig1 = sig1.substring(0, idx);
  195. }
  196. // this code needs a speed overhaul... and some proper tests
  197. // Two static parts because one may be enclosing jpsp (269522)
  198. if (sig1 != null) {
  199. if (sig1.contains("Lorg/aspectj/lang")) {
  200. if (sig1.endsWith("Lorg/aspectj/lang/JoinPoint$StaticPart;")) {
  201. sig1 = sig1.substring(0, sig1.lastIndexOf("Lorg/aspectj/lang/JoinPoint$StaticPart;"));
  202. }
  203. if (sig1.endsWith("Lorg/aspectj/lang/JoinPoint;")) {
  204. sig1 = sig1.substring(0, sig1.lastIndexOf("Lorg/aspectj/lang/JoinPoint;"));
  205. }
  206. if (sig1.endsWith("Lorg/aspectj/lang/JoinPoint$StaticPart;")) {
  207. sig1 = sig1.substring(0, sig1.lastIndexOf("Lorg/aspectj/lang/JoinPoint$StaticPart;"));
  208. }
  209. }
  210. }
  211. if (sig1 == null && ipeSig == null || (sig1 != null && sig1.equals(ipeSig))) {
  212. String existingHandle = object.getHandleIdentifier();
  213. int suffixPosition = existingHandle.indexOf('!');
  214. if (suffixPosition != -1) {
  215. count = Integer.valueOf(existingHandle.substring(suffixPosition + 1)) + 1;
  216. } else {
  217. if (count == 1) {
  218. count = 2;
  219. }
  220. }
  221. }
  222. }
  223. }
  224. }
  225. if (count > 1) {
  226. return CharOperation.concat(countDelim, Integer.toString(count).toCharArray());
  227. }
  228. } else if (ipe.getKind().equals(IProgramElement.Kind.INITIALIZER)) {
  229. // return String.valueOf(++initializerCounter).toCharArray();
  230. // Look at any peer advice
  231. int count = 1;
  232. List<IProgramElement> kids = ipe.getParent().getChildren();
  233. String ipeSig = ipe.getBytecodeSignature();
  234. // remove return type from the signature - it should not be included in the comparison
  235. int idx = 0;
  236. ipeSig = shortenIpeSig(ipeSig);
  237. for (IProgramElement object : kids) {
  238. if (object.equals(ipe)) {
  239. break;
  240. }
  241. if (object.getKind() == ipe.getKind()) {
  242. if (object.getName().equals(ipe.getName())) {
  243. String sig1 = object.getBytecodeSignature();
  244. if (sig1 != null && (idx = sig1.indexOf(")")) != -1) {
  245. sig1 = sig1.substring(0, idx);
  246. }
  247. // this code needs a speed overhaul... and some proper tests
  248. // Two static parts because one may be enclosing jpsp (269522)
  249. if (sig1 != null) {
  250. if (sig1.contains("Lorg/aspectj/lang")) {
  251. if (sig1.endsWith("Lorg/aspectj/lang/JoinPoint$StaticPart;")) {
  252. sig1 = sig1.substring(0, sig1.lastIndexOf("Lorg/aspectj/lang/JoinPoint$StaticPart;"));
  253. }
  254. if (sig1.endsWith("Lorg/aspectj/lang/JoinPoint;")) {
  255. sig1 = sig1.substring(0, sig1.lastIndexOf("Lorg/aspectj/lang/JoinPoint;"));
  256. }
  257. if (sig1.endsWith("Lorg/aspectj/lang/JoinPoint$StaticPart;")) {
  258. sig1 = sig1.substring(0, sig1.lastIndexOf("Lorg/aspectj/lang/JoinPoint$StaticPart;"));
  259. }
  260. }
  261. }
  262. if (sig1 == null && ipeSig == null || (sig1 != null && sig1.equals(ipeSig))) {
  263. String existingHandle = object.getHandleIdentifier();
  264. int suffixPosition = existingHandle.indexOf('!');
  265. if (suffixPosition != -1) {
  266. count = Integer.valueOf(existingHandle.substring(suffixPosition + 1)) + 1;
  267. } else {
  268. if (count == 1) {
  269. count = 2;
  270. }
  271. }
  272. }
  273. }
  274. }
  275. }
  276. // if (count > 1) {
  277. return Integer.toString(count).toCharArray();
  278. // return CharOperation.concat(countDelim, new Integer(count).toString().toCharArray());
  279. // }
  280. } else if (ipe.getKind().equals(IProgramElement.Kind.CODE)) {
  281. int index = CharOperation.lastIndexOf('!', byteCodeName);
  282. if (index != -1) {
  283. return convertCount(CharOperation.subarray(byteCodeName, index + 1, byteCodeName.length));
  284. }
  285. } else if (ipe.getKind() == IProgramElement.Kind.CLASS) {
  286. // depends on previous children
  287. int count = 1;
  288. List<IProgramElement> kids = ipe.getParent().getChildren();
  289. if (ipe.getName().endsWith("{..}")) {
  290. // only depends on previous anonymous children, name irrelevant
  291. for (IProgramElement object : kids) {
  292. if (object.equals(ipe)) {
  293. break;
  294. }
  295. if (object.getKind() == ipe.getKind()) {
  296. if (object.getName().endsWith("{..}")) {
  297. String existingHandle = object.getHandleIdentifier();
  298. int suffixPosition = existingHandle.lastIndexOf('!');
  299. int lastSquareBracket = existingHandle.lastIndexOf('['); // type delimiter
  300. if (suffixPosition != -1 && lastSquareBracket < suffixPosition) { // pr260384
  301. count = Integer.valueOf(existingHandle.substring(suffixPosition + 1)) + 1;
  302. } else {
  303. if (count == 1) {
  304. count = 2;
  305. }
  306. }
  307. }
  308. }
  309. }
  310. } else {
  311. for (IProgramElement object : kids) {
  312. if (object.equals(ipe)) {
  313. break;
  314. }
  315. if (object.getKind() == ipe.getKind()) {
  316. if (object.getName().equals(ipe.getName())) {
  317. String existingHandle = object.getHandleIdentifier();
  318. int suffixPosition = existingHandle.lastIndexOf('!');
  319. int lastSquareBracket = existingHandle.lastIndexOf('['); // type delimiter
  320. if (suffixPosition != -1 && lastSquareBracket < suffixPosition) { // pr260384
  321. count = Integer.valueOf(existingHandle.substring(suffixPosition + 1)) + 1;
  322. } else {
  323. if (count == 1) {
  324. count = 2;
  325. }
  326. }
  327. }
  328. }
  329. }
  330. }
  331. if (count > 1) {
  332. return CharOperation.concat(countDelim, Integer.toString(count).toCharArray());
  333. }
  334. }
  335. return empty;
  336. }
  337. private String shortenIpeSig(String ipeSig) {
  338. int idx;
  339. if (ipeSig != null && ((idx = ipeSig.indexOf(")")) != -1)) {
  340. ipeSig = ipeSig.substring(0, idx);
  341. }
  342. if (ipeSig != null) {
  343. if (ipeSig.contains("Lorg/aspectj/lang")) {
  344. if (ipeSig.endsWith("Lorg/aspectj/lang/JoinPoint$StaticPart;")) {
  345. ipeSig = ipeSig.substring(0, ipeSig.lastIndexOf("Lorg/aspectj/lang/JoinPoint$StaticPart;"));
  346. }
  347. if (ipeSig.endsWith("Lorg/aspectj/lang/JoinPoint;")) {
  348. ipeSig = ipeSig.substring(0, ipeSig.lastIndexOf("Lorg/aspectj/lang/JoinPoint;"));
  349. }
  350. if (ipeSig.endsWith("Lorg/aspectj/lang/JoinPoint$StaticPart;")) {
  351. ipeSig = ipeSig.substring(0, ipeSig.lastIndexOf("Lorg/aspectj/lang/JoinPoint$StaticPart;"));
  352. }
  353. }
  354. }
  355. return ipeSig;
  356. }
  357. private int computeCountBasedOnPeers(IProgramElement ipe) {
  358. int count = 1;
  359. for (IProgramElement object : ipe.getParent().getChildren()) {
  360. if (object.equals(ipe)) {
  361. break;
  362. }
  363. if (object.getKind() == ipe.getKind()) {
  364. if (object.getKind().toString().equals(ipe.getKind().toString())) {
  365. String existingHandle = object.getHandleIdentifier();
  366. int suffixPosition = existingHandle.indexOf('!');
  367. if (suffixPosition != -1) {
  368. count = Integer.valueOf(existingHandle.substring(suffixPosition + 1)) + 1;
  369. } else {
  370. if (count == 1) {
  371. count = 2;
  372. }
  373. }
  374. }
  375. }
  376. }
  377. return count;
  378. }
  379. /**
  380. * Only returns the count if it's not equal to 1
  381. */
  382. private char[] convertCount(char[] c) {
  383. if ((c.length == 1 && c[0] != ' ' && c[0] != '1') || c.length > 1) {
  384. return CharOperation.concat(countDelim, c);
  385. }
  386. return empty;
  387. }
  388. public String getFileForHandle(String handle) {
  389. IProgramElement node = asm.getHierarchy().getElement(handle);
  390. if (node != null) {
  391. return asm.getCanonicalFilePath(node.getSourceLocation().getSourceFile());
  392. } else if (handle.charAt(0) == HandleProviderDelimiter.ASPECT_CU.getDelimiter()
  393. || handle.charAt(0) == HandleProviderDelimiter.COMPILATIONUNIT.getDelimiter()) {
  394. // it's something like *MyAspect.aj or {MyClass.java. In other words
  395. // it's a file node that's been created with no children and no
  396. // parent
  397. return backslash + handle.substring(1);
  398. }
  399. return emptyString;
  400. }
  401. public int getLineNumberForHandle(String handle) {
  402. IProgramElement node = asm.getHierarchy().getElement(handle);
  403. if (node != null) {
  404. return node.getSourceLocation().getLine();
  405. } else if (handle.charAt(0) == HandleProviderDelimiter.ASPECT_CU.getDelimiter()
  406. || handle.charAt(0) == HandleProviderDelimiter.COMPILATIONUNIT.getDelimiter()) {
  407. // it's something like *MyAspect.aj or {MyClass.java. In other words
  408. // it's a file node that's been created with no children and no
  409. // parent
  410. return 1;
  411. }
  412. return -1;
  413. }
  414. public int getOffSetForHandle(String handle) {
  415. IProgramElement node = asm.getHierarchy().getElement(handle);
  416. if (node != null) {
  417. return node.getSourceLocation().getOffset();
  418. } else if (handle.charAt(0) == HandleProviderDelimiter.ASPECT_CU.getDelimiter()
  419. || handle.charAt(0) == HandleProviderDelimiter.COMPILATIONUNIT.getDelimiter()) {
  420. // it's something like *MyAspect.aj or {MyClass.java. In other words
  421. // it's a file node that's been created with no children and no
  422. // parent
  423. return 0;
  424. }
  425. return -1;
  426. }
  427. public String createHandleIdentifier(ISourceLocation location) {
  428. IProgramElement node = asm.getHierarchy().findElementForSourceLine(location);
  429. if (node != null) {
  430. return createHandleIdentifier(node);
  431. }
  432. return null;
  433. }
  434. public String createHandleIdentifier(File sourceFile, int line, int column, int offset) {
  435. IProgramElement node = asm.getHierarchy().findElementForOffSet(sourceFile.getAbsolutePath(), line, offset);
  436. if (node != null) {
  437. return createHandleIdentifier(node);
  438. }
  439. return null;
  440. }
  441. public boolean dependsOnLocation() {
  442. // handles are independent of soureLocations therefore return false
  443. return false;
  444. }
  445. }