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.

AsmRelationshipProvider.java 20KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466
  1. /* *******************************************************************
  2. * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
  3. * All rights reserved.
  4. * This program and the accompanying materials are made available
  5. * under the terms of the Eclipse Public License v1.0
  6. * which accompanies this distribution and is available at
  7. * http://www.eclipse.org/legal/epl-v10.html
  8. *
  9. * Contributors:
  10. * PARC initial implementation
  11. * ******************************************************************/
  12. package org.aspectj.weaver;
  13. import java.util.Iterator;
  14. import java.util.List;
  15. import org.aspectj.apache.bcel.classfile.Field;
  16. import org.aspectj.apache.bcel.classfile.Method;
  17. import org.aspectj.apache.bcel.classfile.Utility;
  18. import org.aspectj.apache.bcel.generic.Type;
  19. import org.aspectj.asm.AsmManager;
  20. import org.aspectj.asm.IHierarchy;
  21. import org.aspectj.asm.IProgramElement;
  22. import org.aspectj.asm.IRelationship;
  23. import org.aspectj.asm.IRelationshipMap;
  24. import org.aspectj.asm.internal.ProgramElement;
  25. import org.aspectj.bridge.ISourceLocation;
  26. import org.aspectj.bridge.SourceLocation;
  27. import org.aspectj.weaver.bcel.BcelAdvice;
  28. public class AsmRelationshipProvider {
  29. protected static AsmRelationshipProvider INSTANCE = new AsmRelationshipProvider();
  30. public static final String ADVISES = "advises";
  31. public static final String ADVISED_BY = "advised by";
  32. public static final String DECLARES_ON = "declares on";
  33. public static final String DECLAREDY_BY = "declared by";
  34. public static final String SOFTENS = "softens";
  35. public static final String SOFTENED_BY = "softened by";
  36. public static final String MATCHED_BY = "matched by";
  37. public static final String MATCHES_DECLARE = "matches declare";
  38. public static final String INTER_TYPE_DECLARES = "declared on";
  39. public static final String INTER_TYPE_DECLARED_BY = "aspect declarations";
  40. public static final String ANNOTATES = "annotates";
  41. public static final String ANNOTATED_BY = "annotated by";
  42. public void checkerMunger(IHierarchy model, Shadow shadow, Checker checker) {
  43. if (!AsmManager.isCreatingModel()) return;
  44. if (shadow.getSourceLocation() == null || checker.getSourceLocation() == null) return;
  45. if (World.createInjarHierarchy) {
  46. checker.createHierarchy();
  47. }
  48. // Ensure a node for the target exists
  49. IProgramElement targetNode = getNode(AsmManager.getDefault().getHierarchy(),shadow);
  50. if (targetNode == null) return;
  51. String targetHandle = AsmManager.getDefault().getHandleProvider()
  52. .createHandleIdentifier(targetNode);
  53. if (targetHandle == null) return;
  54. IProgramElement sourceNode = AsmManager.getDefault().getHierarchy()
  55. .findElementForSourceLine(checker.getSourceLocation());
  56. String sourceHandle = AsmManager.getDefault().getHandleProvider()
  57. .createHandleIdentifier(sourceNode);
  58. if (sourceHandle == null) return;
  59. IRelationshipMap mapper = AsmManager.getDefault().getRelationshipMap();
  60. IRelationship foreward = mapper.get(sourceHandle, IRelationship.Kind.DECLARE, MATCHED_BY,false,true);
  61. foreward.addTarget(targetHandle);
  62. IRelationship back = mapper.get(targetHandle, IRelationship.Kind.DECLARE, MATCHES_DECLARE,false,true);
  63. if (back != null && back.getTargets() != null) {
  64. back.addTarget(sourceHandle);
  65. }
  66. }
  67. // For ITDs
  68. public void addRelationship(
  69. ResolvedType onType,
  70. ResolvedTypeMunger munger,
  71. ResolvedType originatingAspect) {
  72. if (!AsmManager.isCreatingModel()) return;
  73. if (originatingAspect.getSourceLocation() != null) {
  74. String sourceHandle = "";
  75. if (munger.getSourceLocation()!=null && munger.getSourceLocation().getOffset()!=-1) {
  76. IProgramElement sourceNode = AsmManager.getDefault().getHierarchy()
  77. .findElementForSourceLine(munger.getSourceLocation());
  78. sourceHandle = AsmManager.getDefault().getHandleProvider()
  79. .createHandleIdentifier(sourceNode);
  80. } else {
  81. IProgramElement sourceNode = AsmManager.getDefault().getHierarchy()
  82. .findElementForSourceLine(originatingAspect.getSourceLocation());
  83. sourceHandle = AsmManager.getDefault().getHandleProvider()
  84. .createHandleIdentifier(sourceNode);
  85. }
  86. if (sourceHandle == null) return;
  87. IProgramElement targetNode = AsmManager.getDefault().getHierarchy()
  88. .findElementForSourceLine(onType.getSourceLocation());
  89. String targetHandle = AsmManager.getDefault().getHandleProvider()
  90. .createHandleIdentifier(targetNode);
  91. if (targetHandle == null) return;
  92. IRelationshipMap mapper = AsmManager.getDefault().getRelationshipMap();
  93. IRelationship foreward = mapper.get(sourceHandle, IRelationship.Kind.DECLARE_INTER_TYPE, INTER_TYPE_DECLARES,false,true);
  94. foreward.addTarget(targetHandle);
  95. IRelationship back = mapper.get(targetHandle, IRelationship.Kind.DECLARE_INTER_TYPE, INTER_TYPE_DECLARED_BY,false,true);
  96. back.addTarget(sourceHandle);
  97. }
  98. }
  99. public void addDeclareParentsRelationship(ISourceLocation decp,ResolvedType targetType, List newParents) {
  100. if (!AsmManager.isCreatingModel()) return;
  101. IProgramElement sourceNode = AsmManager.getDefault().getHierarchy()
  102. .findElementForSourceLine(decp);
  103. String sourceHandle = AsmManager.getDefault().getHandleProvider()
  104. .createHandleIdentifier(sourceNode);
  105. if (sourceHandle == null) return;
  106. IProgramElement targetNode = AsmManager.getDefault().getHierarchy()
  107. .findElementForSourceLine(targetType.getSourceLocation());
  108. String targetHandle = AsmManager.getDefault().getHandleProvider()
  109. .createHandleIdentifier(targetNode);
  110. if (targetHandle == null) return;
  111. IRelationshipMap mapper = AsmManager.getDefault().getRelationshipMap();
  112. IRelationship foreward = mapper.get(sourceHandle, IRelationship.Kind.DECLARE_INTER_TYPE, INTER_TYPE_DECLARES,false,true);
  113. foreward.addTarget(targetHandle);
  114. IRelationship back = mapper.get(targetHandle, IRelationship.Kind.DECLARE_INTER_TYPE, INTER_TYPE_DECLARED_BY,false,true);
  115. back.addTarget(sourceHandle);
  116. }
  117. /**
  118. * Adds a declare annotation relationship, sometimes entities don't have source locs (methods/fields) so use other
  119. * variants of this method if that is the case as they will look the entities up in the structure model.
  120. */
  121. public void addDeclareAnnotationRelationship(ISourceLocation declareAnnotationLocation,ISourceLocation annotatedLocation) {
  122. if (!AsmManager.isCreatingModel()) return;
  123. IProgramElement sourceNode = AsmManager.getDefault().getHierarchy()
  124. .findElementForSourceLine(declareAnnotationLocation);
  125. String sourceHandle = AsmManager.getDefault().getHandleProvider()
  126. .createHandleIdentifier(sourceNode);
  127. if (sourceHandle == null) return;
  128. IProgramElement targetNode = AsmManager.getDefault().getHierarchy()
  129. .findElementForSourceLine(annotatedLocation);
  130. String targetHandle = AsmManager.getDefault().getHandleProvider()
  131. .createHandleIdentifier(targetNode);
  132. if (targetHandle == null) return;
  133. IRelationshipMap mapper = AsmManager.getDefault().getRelationshipMap();
  134. IRelationship foreward = mapper.get(sourceHandle, IRelationship.Kind.DECLARE_INTER_TYPE, ANNOTATES,false,true);
  135. foreward.addTarget(targetHandle);
  136. IRelationship back = mapper.get(targetHandle, IRelationship.Kind.DECLARE_INTER_TYPE, ANNOTATED_BY,false,true);
  137. back.addTarget(sourceHandle);
  138. }
  139. public void adviceMunger(IHierarchy model, Shadow shadow, ShadowMunger munger) {
  140. if (!AsmManager.isCreatingModel()) return;
  141. if (munger instanceof Advice) {
  142. Advice advice = (Advice)munger;
  143. if (advice.getKind().isPerEntry() || advice.getKind().isCflow()) {
  144. // TODO: might want to show these in the future
  145. return;
  146. }
  147. if (World.createInjarHierarchy) {
  148. munger.createHierarchy();
  149. }
  150. IRelationshipMap mapper = AsmManager.getDefault().getRelationshipMap();
  151. IProgramElement targetNode = getNode(AsmManager.getDefault().getHierarchy(), shadow);
  152. if (targetNode == null) return;
  153. boolean runtimeTest = ((BcelAdvice)munger).hasDynamicTests();
  154. // Work out extra info to inform interested UIs !
  155. IProgramElement.ExtraInformation ai = new IProgramElement.ExtraInformation();
  156. String adviceHandle = advice.getHandle();
  157. if (adviceHandle == null) return;
  158. // What kind of advice is it?
  159. // TODO: Prob a better way to do this but I just want to
  160. // get it into CVS !!!
  161. AdviceKind ak = ((Advice)munger).getKind();
  162. ai.setExtraAdviceInformation(ak.getName());
  163. IProgramElement adviceElement = AsmManager.getDefault().getHierarchy().findElementForHandle(adviceHandle);
  164. if (adviceElement != null) {
  165. adviceElement.setExtraInfo(ai);
  166. }
  167. String targetHandle = targetNode.getHandleIdentifier();
  168. if (advice.getKind().equals(AdviceKind.Softener)) {
  169. IRelationship foreward = mapper.get(adviceHandle, IRelationship.Kind.DECLARE_SOFT, SOFTENS,runtimeTest,true);
  170. if (foreward != null) foreward.addTarget(targetHandle);//foreward.getTargets().add(targetHandle);
  171. IRelationship back = mapper.get(targetHandle, IRelationship.Kind.DECLARE, SOFTENED_BY,runtimeTest,true);
  172. if (back != null) back.addTarget(adviceHandle);//back.getTargets().add(adviceHandle);
  173. } else {
  174. IRelationship foreward = mapper.get(adviceHandle, IRelationship.Kind.ADVICE, ADVISES,runtimeTest,true);
  175. if (foreward != null) foreward.addTarget(targetHandle);//foreward.getTargets().add(targetHandle);
  176. IRelationship back = mapper.get(targetHandle, IRelationship.Kind.ADVICE, ADVISED_BY,runtimeTest,true);
  177. if (back != null) back.addTarget(adviceHandle);//back.getTargets().add(adviceHandle);
  178. }
  179. }
  180. }
  181. protected IProgramElement getNode(IHierarchy model, Shadow shadow) {
  182. Member enclosingMember = shadow.getEnclosingCodeSignature();
  183. IProgramElement enclosingNode = lookupMember(model, enclosingMember);
  184. if (enclosingNode == null) {
  185. Lint.Kind err = shadow.getIWorld().getLint().shadowNotInStructure;
  186. if (err.isEnabled()) {
  187. err.signal(shadow.toString(), shadow.getSourceLocation());
  188. }
  189. return null;
  190. }
  191. Member shadowSig = shadow.getSignature();
  192. if (!shadowSig.equals(enclosingMember)) {
  193. IProgramElement bodyNode = findOrCreateCodeNode(enclosingNode, shadowSig, shadow);
  194. return bodyNode;
  195. } else {
  196. return enclosingNode;
  197. }
  198. }
  199. private boolean sourceLinesMatch(ISourceLocation loc1,ISourceLocation loc2) {
  200. if (loc1.getLine()!=loc2.getLine()) return false;
  201. return true;
  202. }
  203. /**
  204. * Finds or creates a code IProgramElement for the given shadow.
  205. *
  206. * The byteCodeName of the created node is set to 'shadowSig.getName() + "!" + counter',
  207. * eg "println!3". The counter is the occurence count of children within
  208. * the enclosingNode which have the same name. So, for example, if a method
  209. * contains two System.out.println statements, the first one will have
  210. * byteCodeName 'println!1' and the second will have byteCodeName 'println!2'.
  211. * This is to ensure the two nodes have unique handles when the handles
  212. * do not depend on sourcelocations.
  213. *
  214. * Currently the shadows are examined in the sequence they appear in the
  215. * source file. This means that the counters are consistent over incremental
  216. * builds. All aspects are compiled up front and any new aspect created will force
  217. * a full build. Moreover, if the body of the enclosingShadow is changed, then
  218. * the model for this is rebuilt from scratch.
  219. */
  220. private IProgramElement findOrCreateCodeNode(IProgramElement enclosingNode, Member shadowSig, Shadow shadow)
  221. {
  222. for (Iterator it = enclosingNode.getChildren().iterator(); it.hasNext(); ) {
  223. IProgramElement node = (IProgramElement)it.next();
  224. int excl = node.getBytecodeName().lastIndexOf('!');
  225. if (((excl != -1
  226. && shadowSig.getName().equals(node.getBytecodeName().substring(0,excl)))
  227. || shadowSig.getName().equals(node.getBytecodeName()))
  228. && shadowSig.getSignature().equals(node.getBytecodeSignature())
  229. && sourceLinesMatch(node.getSourceLocation(),shadow.getSourceLocation())){
  230. return node;
  231. }
  232. }
  233. ISourceLocation sl = shadow.getSourceLocation();
  234. // XXX why not use shadow file? new SourceLocation(sl.getSourceFile(), sl.getLine()),
  235. SourceLocation peLoc = new SourceLocation(enclosingNode.getSourceLocation().getSourceFile(),sl.getLine());
  236. peLoc.setOffset(sl.getOffset());
  237. IProgramElement peNode = new ProgramElement(
  238. shadow.toString(),
  239. IProgramElement.Kind.CODE,
  240. peLoc,0,null,null);
  241. // check to see if the enclosing shadow already has children with the
  242. // same name. If so we want to add a counter to the byteCodeName otherwise
  243. // we wont get unique handles
  244. int numberOfChildrenWithThisName = 0;
  245. for (Iterator it = enclosingNode.getChildren().iterator(); it.hasNext(); ) {
  246. IProgramElement child = (IProgramElement)it.next();
  247. if (child.getName().equals(shadow.toString())) {
  248. numberOfChildrenWithThisName++;
  249. }
  250. }
  251. peNode.setBytecodeName(shadowSig.getName() + "!" + String.valueOf(numberOfChildrenWithThisName+1));
  252. peNode.setBytecodeSignature(shadowSig.getSignature());
  253. enclosingNode.addChild(peNode);
  254. return peNode;
  255. }
  256. protected IProgramElement lookupMember(IHierarchy model, Member member) {
  257. UnresolvedType declaringType = member.getDeclaringType();
  258. IProgramElement classNode =
  259. model.findElementForType(declaringType.getPackageName(), declaringType.getClassName());
  260. return findMemberInClass(classNode, member);
  261. }
  262. protected IProgramElement findMemberInClass(
  263. IProgramElement classNode,
  264. Member member)
  265. {
  266. if (classNode == null) return null; // XXX remove this check
  267. for (Iterator it = classNode.getChildren().iterator(); it.hasNext(); ) {
  268. IProgramElement node = (IProgramElement)it.next();
  269. if (member.getName().equals(node.getBytecodeName()) &&
  270. member.getSignature().equals(node.getBytecodeSignature()))
  271. {
  272. return node;
  273. }
  274. }
  275. // if we can't find the member, we'll just put it in the class
  276. return classNode;
  277. }
  278. // private static IProgramElement.Kind genShadowKind(Shadow shadow) {
  279. // IProgramElement.Kind shadowKind;
  280. // if (shadow.getKind() == Shadow.MethodCall
  281. // || shadow.getKind() == Shadow.ConstructorCall
  282. // || shadow.getKind() == Shadow.FieldGet
  283. // || shadow.getKind() == Shadow.FieldSet
  284. // || shadow.getKind() == Shadow.ExceptionHandler) {
  285. // return IProgramElement.Kind.CODE;
  286. //
  287. // } else if (shadow.getKind() == Shadow.MethodExecution) {
  288. // return IProgramElement.Kind.METHOD;
  289. //
  290. // } else if (shadow.getKind() == Shadow.ConstructorExecution) {
  291. // return IProgramElement.Kind.CONSTRUCTOR;
  292. //
  293. // } else if (shadow.getKind() == Shadow.PreInitialization
  294. // || shadow.getKind() == Shadow.Initialization) {
  295. // return IProgramElement.Kind.CLASS;
  296. //
  297. // } else if (shadow.getKind() == Shadow.AdviceExecution) {
  298. // return IProgramElement.Kind.ADVICE;
  299. //
  300. // } else {
  301. // return IProgramElement.Kind.ERROR;
  302. // }
  303. // }
  304. public static AsmRelationshipProvider getDefault() {
  305. return INSTANCE;
  306. }
  307. /**
  308. * Reset the instance of this class, intended for extensibility.
  309. * This enables a subclass to become used as the default instance.
  310. */
  311. public static void setDefault(AsmRelationshipProvider instance) {
  312. INSTANCE = instance;
  313. }
  314. /**
  315. * Add a relationship to the known set for a declare @method/@constructor construct.
  316. * Locating the method is a messy (for messy read 'fragile') bit of code that could break at any moment
  317. * but it's working for my simple testcase. Currently just fails silently if any of the lookup code
  318. * doesn't find anything...
  319. */
  320. public void addDeclareAnnotationRelationship(ISourceLocation sourceLocation, String typename,Method method) {
  321. if (!AsmManager.isCreatingModel()) return;
  322. String pkg = null;
  323. String type = typename;
  324. int packageSeparator = typename.lastIndexOf(".");
  325. if (packageSeparator!=-1) {
  326. pkg = typename.substring(0,packageSeparator);
  327. type = typename.substring(packageSeparator+1);
  328. }
  329. IProgramElement typeElem = AsmManager.getDefault().getHierarchy().findElementForType(pkg,type);
  330. if (typeElem == null) return;
  331. StringBuffer parmString = new StringBuffer("(");
  332. Type[] args = method.getArgumentTypes();
  333. for (int i = 0; i < args.length; i++) {
  334. Type type2 = args[i];
  335. String s = Utility.signatureToString(type2.getSignature(),false);
  336. parmString.append(s);
  337. if ((i+1)<args.length) parmString.append(",");
  338. }
  339. parmString.append(")");
  340. IProgramElement methodElem = null;
  341. if (method.getName().startsWith("<init>")) {
  342. // its a ctor
  343. methodElem = AsmManager.getDefault().getHierarchy().findElementForSignature(typeElem,IProgramElement.Kind.CONSTRUCTOR,type+parmString);
  344. if (methodElem == null && args.length==0) methodElem = typeElem; // assume default ctor
  345. } else {
  346. // its a method
  347. methodElem = AsmManager.getDefault().getHierarchy().findElementForSignature(typeElem,IProgramElement.Kind.METHOD,method.getName()+parmString);
  348. }
  349. if (methodElem == null) return;
  350. try {
  351. String targetHandle = methodElem.getHandleIdentifier();
  352. if (targetHandle == null) return;
  353. IProgramElement sourceNode = AsmManager.getDefault().getHierarchy().findElementForSourceLine(sourceLocation);
  354. String sourceHandle = AsmManager.getDefault().getHandleProvider().createHandleIdentifier(sourceNode);
  355. if (sourceHandle == null) return;
  356. IRelationshipMap mapper = AsmManager.getDefault().getRelationshipMap();
  357. IRelationship foreward = mapper.get(sourceHandle, IRelationship.Kind.DECLARE_INTER_TYPE, ANNOTATES,false,true);
  358. foreward.addTarget(targetHandle);
  359. IRelationship back = mapper.get(targetHandle, IRelationship.Kind.DECLARE_INTER_TYPE, ANNOTATED_BY,false,true);
  360. back.addTarget(sourceHandle);
  361. } catch (Throwable t) { // I'm worried about that code above, this will make sure we don't explode if it plays up
  362. t.printStackTrace(); // I know I know .. but I don't want to lose it!
  363. }
  364. }
  365. /**
  366. * Add a relationship to the known set for a declare @field construct. Locating the field is trickier than
  367. * it might seem since we have no line number info for it, we have to dig through the structure model under
  368. * the fields' type in order to locate it. Currently just fails silently if any of the lookup code
  369. * doesn't find anything...
  370. */
  371. public void addDeclareAnnotationRelationship(ISourceLocation sourceLocation, String typename,Field field) {
  372. if (!AsmManager.isCreatingModel()) return;
  373. String pkg = null;
  374. String type = typename;
  375. int packageSeparator = typename.lastIndexOf(".");
  376. if (packageSeparator!=-1) {
  377. pkg = typename.substring(0,packageSeparator);
  378. type = typename.substring(packageSeparator+1);
  379. }
  380. IProgramElement typeElem = AsmManager.getDefault().getHierarchy().findElementForType(pkg,type);
  381. if (typeElem == null) return;
  382. IProgramElement fieldElem = AsmManager.getDefault().getHierarchy().findElementForSignature(typeElem,IProgramElement.Kind.FIELD,field.getName());
  383. if (fieldElem== null) return;
  384. String targetHandle = fieldElem.getHandleIdentifier();
  385. if (targetHandle == null) return;
  386. IProgramElement sourceNode = AsmManager.getDefault().getHierarchy().findElementForSourceLine(sourceLocation);
  387. String sourceHandle = AsmManager.getDefault().getHandleProvider().createHandleIdentifier(sourceNode);
  388. if (sourceHandle == null) return;
  389. IRelationshipMap mapper = AsmManager.getDefault().getRelationshipMap();
  390. IRelationship foreward = mapper.get(sourceHandle, IRelationship.Kind.DECLARE_INTER_TYPE, ANNOTATES,false,true);
  391. foreward.addTarget(targetHandle);
  392. IRelationship back = mapper.get(targetHandle, IRelationship.Kind.DECLARE_INTER_TYPE, ANNOTATED_BY,false,true);
  393. back.addTarget(sourceHandle);
  394. }
  395. }