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

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