Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

AtAjAttributes.java 59KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427
  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 v1.0
  6. * which accompanies this distribution and is available at
  7. * http://eclipse.org/legal/epl-v10.html
  8. *
  9. * Contributors:
  10. * initial implementation Alexandre Vasseur
  11. *******************************************************************************/
  12. package org.aspectj.weaver.bcel;
  13. import java.util.ArrayList;
  14. import java.util.Collections;
  15. import java.util.Comparator;
  16. import java.util.Iterator;
  17. import java.util.List;
  18. import org.aspectj.apache.bcel.classfile.Attribute;
  19. import org.aspectj.apache.bcel.classfile.Field;
  20. import org.aspectj.apache.bcel.classfile.JavaClass;
  21. import org.aspectj.apache.bcel.classfile.LocalVariable;
  22. import org.aspectj.apache.bcel.classfile.LocalVariableTable;
  23. import org.aspectj.apache.bcel.classfile.Method;
  24. import org.aspectj.apache.bcel.classfile.annotation.Annotation;
  25. import org.aspectj.apache.bcel.classfile.annotation.ElementNameValuePair;
  26. import org.aspectj.apache.bcel.classfile.annotation.RuntimeAnnotations;
  27. import org.aspectj.apache.bcel.classfile.annotation.RuntimeVisibleAnnotations;
  28. import org.aspectj.apache.bcel.generic.Type;
  29. import org.aspectj.bridge.IMessage;
  30. import org.aspectj.bridge.IMessageHandler;
  31. import org.aspectj.bridge.ISourceLocation;
  32. import org.aspectj.bridge.Message;
  33. import org.aspectj.bridge.SourceLocation;
  34. import org.aspectj.weaver.Advice;
  35. import org.aspectj.weaver.AdviceKind;
  36. import org.aspectj.weaver.AjAttribute;
  37. import org.aspectj.weaver.AjcMemberMaker;
  38. import org.aspectj.weaver.IHasPosition;
  39. import org.aspectj.weaver.ISourceContext;
  40. import org.aspectj.weaver.NameMangler;
  41. import org.aspectj.weaver.ResolvedPointcutDefinition;
  42. import org.aspectj.weaver.ResolvedTypeX;
  43. import org.aspectj.weaver.TypeX;
  44. import org.aspectj.weaver.patterns.AndPointcut;
  45. import org.aspectj.weaver.patterns.DeclareErrorOrWarning;
  46. import org.aspectj.weaver.patterns.DeclarePrecedence;
  47. import org.aspectj.weaver.patterns.FormalBinding;
  48. import org.aspectj.weaver.patterns.IScope;
  49. import org.aspectj.weaver.patterns.IdentityPointcutVisitor;
  50. import org.aspectj.weaver.patterns.IfPointcut;
  51. import org.aspectj.weaver.patterns.NotPointcut;
  52. import org.aspectj.weaver.patterns.OrPointcut;
  53. import org.aspectj.weaver.patterns.ParserException;
  54. import org.aspectj.weaver.patterns.PatternParser;
  55. import org.aspectj.weaver.patterns.PerCflow;
  56. import org.aspectj.weaver.patterns.PerClause;
  57. import org.aspectj.weaver.patterns.PerFromSuper;
  58. import org.aspectj.weaver.patterns.PerObject;
  59. import org.aspectj.weaver.patterns.PerSingleton;
  60. import org.aspectj.weaver.patterns.PerTypeWithin;
  61. import org.aspectj.weaver.patterns.Pointcut;
  62. import org.aspectj.weaver.patterns.SimpleScope;
  63. import org.aspectj.weaver.patterns.TypePattern;
  64. /**
  65. * Annotation defined aspect reader.
  66. * <p/>
  67. * It reads the Java 5 annotations and turns them into AjAttributes
  68. *
  69. * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
  70. */
  71. public class AtAjAttributes {
  72. private final static List EMPTY_LIST = new ArrayList();
  73. private final static String[] EMPTY_STRINGS = new String[0];
  74. private final static String VALUE = "value";
  75. private final static String POINTCUT = "pointcut";
  76. private final static String THROWING = "throwing";
  77. private final static String RETURNING = "returning";
  78. private final static String STRING_DESC = "Ljava/lang/String;";
  79. /**
  80. * A struct that allows to add extra arguments without always breaking the API
  81. *
  82. * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
  83. */
  84. private static class AjAttributeStruct {
  85. /**
  86. * The list of AjAttribute.XXX that we are populating from the @AJ read
  87. */
  88. List ajAttributes = new ArrayList();
  89. /**
  90. * The resolved type (class) for which we are reading @AJ for (be it class, method, field annotations)
  91. */
  92. final ResolvedTypeX enclosingType;
  93. final ISourceContext context;
  94. final IMessageHandler handler;
  95. public AjAttributeStruct(ResolvedTypeX type, ISourceContext sourceContext, IMessageHandler messageHandler) {
  96. enclosingType = type;
  97. context = sourceContext;
  98. handler = messageHandler;
  99. }
  100. }
  101. /**
  102. * A struct when we read @AJ on method
  103. *
  104. * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
  105. */
  106. private static class AjAttributeMethodStruct extends AjAttributeStruct {
  107. /**
  108. * Argument names as they appear in the SOURCE code, ordered, and lazyly populated
  109. * Used to do formal binding
  110. */
  111. private String[] m_argumentNamesLazy = null;
  112. final Method method;
  113. final BcelMethod bMethod;
  114. public AjAttributeMethodStruct(Method method, BcelMethod bMethod, ResolvedTypeX type, ISourceContext sourceContext, IMessageHandler messageHandler) {
  115. super(type, sourceContext, messageHandler);
  116. this.method = method;
  117. this.bMethod = bMethod;
  118. }
  119. public String[] getArgumentNames() {
  120. if (m_argumentNamesLazy == null) {
  121. m_argumentNamesLazy = getMethodArgumentNamesAsInSource(method);
  122. }
  123. return m_argumentNamesLazy;
  124. }
  125. }
  126. /**
  127. * A struct when we read @AJ on field
  128. *
  129. * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
  130. */
  131. private static class AjAttributeFieldStruct extends AjAttributeStruct {
  132. final Field field;
  133. public AjAttributeFieldStruct(Field field, ResolvedTypeX type, ISourceContext sourceContext, IMessageHandler messageHandler) {
  134. super(type, sourceContext, messageHandler);
  135. this.field = field;
  136. }
  137. }
  138. /**
  139. * Annotations are RuntimeVisible only. This allow us to not visit RuntimeInvisible ones.
  140. *
  141. * @param attribute
  142. * @return
  143. */
  144. public static boolean acceptAttribute(Attribute attribute) {
  145. return (attribute instanceof RuntimeVisibleAnnotations);
  146. }
  147. /**
  148. * Extract class level annotations and turn them into AjAttributes.
  149. *
  150. * @param javaClass
  151. * @param type
  152. * @param context
  153. * @param msgHandler
  154. * @return list of AjAttributes
  155. */
  156. public static List readAj5ClassAttributes(JavaClass javaClass, ResolvedTypeX type, ISourceContext context, IMessageHandler msgHandler, boolean isCodeStyleAspect) {
  157. AjAttributeStruct struct = new AjAttributeStruct(type, context, msgHandler);
  158. Attribute[] attributes = javaClass.getAttributes();
  159. boolean hasAtAspectAnnotation = false;
  160. boolean hasAtPrecedenceAnnotation = false;
  161. for (int i = 0; i < attributes.length; i++) {
  162. Attribute attribute = attributes[i];
  163. if (acceptAttribute(attribute)) {
  164. RuntimeAnnotations rvs = (RuntimeAnnotations) attribute;
  165. // we don't need to look for several attribute occurence since it cannot happen as per JSR175
  166. if (!isCodeStyleAspect) {
  167. hasAtAspectAnnotation = handleAspectAnnotation(rvs, struct);
  168. //TODO AV - if put outside the if isCodeStyleAspect then we would enable mix style
  169. hasAtPrecedenceAnnotation = handlePrecedenceAnnotation(rvs, struct);
  170. }
  171. // there can only be one RuntimeVisible bytecode attribute
  172. break;
  173. }
  174. }
  175. // basic semantic check
  176. if (hasAtPrecedenceAnnotation && !hasAtAspectAnnotation) {
  177. msgHandler.handleMessage(
  178. new Message(
  179. "Found @DeclarePrecedence on a non @Aspect type '" + type.getName() + "'",
  180. IMessage.WARNING,
  181. null,
  182. type.getSourceLocation()
  183. )
  184. );
  185. // bypass what we have read
  186. return EMPTY_LIST;
  187. }
  188. //FIXME turn on when ajcMightHaveAspect
  189. // if (hasAtAspectAnnotation && type.isInterface()) {
  190. // msgHandler.handleMessage(
  191. // new Message(
  192. // "Found @Aspect on an interface type '" + type.getName() + "'",
  193. // IMessage.WARNING,
  194. // null,
  195. // type.getSourceLocation()
  196. // )
  197. // );
  198. // // bypass what we have read
  199. // return EMPTY_LIST;
  200. // }
  201. // the following block will not detect @Pointcut in non @Aspect types for optimization purpose
  202. if (!hasAtAspectAnnotation) {
  203. return EMPTY_LIST;
  204. }
  205. // code style pointcuts are class attributes
  206. // we need to gather the @AJ pointcut right now and not at method level annotation extraction time
  207. // in order to be able to resolve the pointcut references later on
  208. // we don't need to look in super class, the pointcut reference in the grammar will do it
  209. for (int i = 0; i < javaClass.getMethods().length; i++) {
  210. Method method = javaClass.getMethods()[i];
  211. if (method.getName().startsWith(NameMangler.PREFIX)) continue; // already dealt with by ajc...
  212. //FIXME alex optimize, this method struct will gets recreated for advice extraction
  213. AjAttributeMethodStruct mstruct = new AjAttributeMethodStruct(method, null, type, context, msgHandler);//FIXME AVASM
  214. Attribute[] mattributes = method.getAttributes();
  215. for (int j = 0; j < mattributes.length; j++) {
  216. Attribute mattribute = mattributes[j];
  217. if (acceptAttribute(mattribute)) {
  218. RuntimeAnnotations mrvs = (RuntimeAnnotations) mattribute;
  219. handlePointcutAnnotation(mrvs, mstruct);
  220. // there can only be one RuntimeVisible bytecode attribute
  221. break;
  222. }
  223. }
  224. struct.ajAttributes.addAll(mstruct.ajAttributes);
  225. }
  226. // code style declare error / warning are class attributes
  227. for (int i = 0; i < javaClass.getFields().length; i++) {
  228. Field field = javaClass.getFields()[i];
  229. if (field.getName().startsWith(NameMangler.PREFIX)) continue; // already dealt with by ajc...
  230. //FIXME alex optimize, this method struct will gets recreated for advice extraction
  231. AjAttributeFieldStruct fstruct = new AjAttributeFieldStruct(field, type, context, msgHandler);
  232. Attribute[] fattributes = field.getAttributes();
  233. for (int j = 0; j < fattributes.length; j++) {
  234. Attribute fattribute = fattributes[j];
  235. if (acceptAttribute(fattribute)) {
  236. RuntimeAnnotations frvs = (RuntimeAnnotations) fattribute;
  237. if (handleDeclareErrorOrWarningAnnotation(frvs, fstruct)) {
  238. // semantic check - must be in an @Aspect [remove if previous block bypassed in advance]
  239. if (!type.isAnnotationStyleAspect()) {
  240. msgHandler.handleMessage(
  241. new Message(
  242. "Found @AspectJ annotations in a non @Aspect type '" + type.getName() + "'",
  243. IMessage.WARNING,
  244. null,
  245. type.getSourceLocation()
  246. )
  247. );
  248. ;// go ahead
  249. }
  250. }
  251. // there can only be one RuntimeVisible bytecode attribute
  252. break;
  253. }
  254. }
  255. struct.ajAttributes.addAll(fstruct.ajAttributes);
  256. }
  257. return struct.ajAttributes;
  258. }
  259. /**
  260. * Extract method level annotations and turn them into AjAttributes.
  261. *
  262. * @param method
  263. * @param type
  264. * @param context
  265. * @param msgHandler
  266. * @return list of AjAttributes
  267. */
  268. public static List readAj5MethodAttributes(Method method, BcelMethod bMethod, ResolvedTypeX type, ResolvedPointcutDefinition preResolvedPointcut, ISourceContext context, IMessageHandler msgHandler) {
  269. if (method.getName().startsWith(NameMangler.PREFIX)) return Collections.EMPTY_LIST; // already dealt with by ajc...
  270. AjAttributeMethodStruct struct = new AjAttributeMethodStruct(method, bMethod, type, context, msgHandler);
  271. Attribute[] attributes = method.getAttributes();
  272. // we remember if we found one @AJ annotation for minimal semantic error reporting
  273. // the real reporting beeing done thru AJDT and the compiler mapping @AJ to AjAtttribute
  274. // or thru APT
  275. //
  276. // Note: we could actually skip the whole thing if type is not itself an @Aspect
  277. // but then we would not see any warning. We do bypass for pointcut but not for advice since it would
  278. // be too silent.
  279. boolean hasAtAspectJAnnotation = false;
  280. boolean hasAtAspectJAnnotationMustReturnVoid = false;
  281. for (int i = 0; i < attributes.length; i++) {
  282. Attribute attribute = attributes[i];
  283. if (acceptAttribute(attribute)) {
  284. RuntimeAnnotations rvs = (RuntimeAnnotations) attribute;
  285. hasAtAspectJAnnotationMustReturnVoid = hasAtAspectJAnnotationMustReturnVoid || handleBeforeAnnotation(
  286. rvs, struct, preResolvedPointcut
  287. );
  288. hasAtAspectJAnnotationMustReturnVoid = hasAtAspectJAnnotationMustReturnVoid || handleAfterAnnotation(
  289. rvs, struct, preResolvedPointcut
  290. );
  291. hasAtAspectJAnnotationMustReturnVoid = hasAtAspectJAnnotationMustReturnVoid || handleAfterReturningAnnotation(
  292. rvs, struct, preResolvedPointcut
  293. );
  294. hasAtAspectJAnnotationMustReturnVoid = hasAtAspectJAnnotationMustReturnVoid || handleAfterThrowingAnnotation(
  295. rvs, struct, preResolvedPointcut
  296. );
  297. hasAtAspectJAnnotation = hasAtAspectJAnnotation || handleAroundAnnotation(
  298. rvs, struct, preResolvedPointcut
  299. );
  300. // there can only be one RuntimeVisible bytecode attribute
  301. break;
  302. }
  303. }
  304. hasAtAspectJAnnotation = hasAtAspectJAnnotation || hasAtAspectJAnnotationMustReturnVoid;
  305. // semantic check - must be in an @Aspect [remove if previous block bypassed in advance]
  306. if (hasAtAspectJAnnotation && !type.isAnnotationStyleAspect()) {
  307. msgHandler.handleMessage(
  308. new Message(
  309. "Found @AspectJ annotations in a non @Aspect type '" + type.getName() + "'",
  310. IMessage.WARNING,
  311. null,
  312. type.getSourceLocation()
  313. )
  314. );
  315. ;// go ahead
  316. }
  317. // semantic check - advice must be public
  318. if (hasAtAspectJAnnotation && !struct.method.isPublic()) {
  319. msgHandler.handleMessage(
  320. new Message(
  321. "Found @AspectJ annotation on a non public advice '" + methodToString(struct.method) + "'",
  322. IMessage.ERROR,
  323. null,
  324. type.getSourceLocation()
  325. )
  326. );
  327. ;// go ahead
  328. }
  329. // semantic check for non around advice must return void
  330. if (hasAtAspectJAnnotationMustReturnVoid && !Type.VOID.equals(struct.method.getReturnType())) {
  331. msgHandler.handleMessage(
  332. new Message(
  333. "Found @AspectJ annotation on a non around advice not returning void '" + methodToString(
  334. struct.method
  335. ) + "'",
  336. IMessage.ERROR,
  337. null,
  338. type.getSourceLocation()
  339. )
  340. );
  341. ;// go ahead
  342. }
  343. return struct.ajAttributes;
  344. }
  345. /**
  346. * Extract field level annotations and turn them into AjAttributes.
  347. *
  348. * @param field
  349. * @param type
  350. * @param context
  351. * @param msgHandler
  352. * @return list of AjAttributes, always empty for now
  353. */
  354. public static List readAj5FieldAttributes(Field field, ResolvedTypeX type, ISourceContext context, IMessageHandler msgHandler) {
  355. return Collections.EMPTY_LIST;
  356. }
  357. /**
  358. * Read @Aspect
  359. *
  360. * @param runtimeAnnotations
  361. * @param struct
  362. * @return true if found
  363. */
  364. private static boolean handleAspectAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeStruct struct) {
  365. Annotation aspect = getAnnotation(runtimeAnnotations, AjcMemberMaker.ASPECT_ANNOTATION);
  366. if (aspect != null) {
  367. // semantic check for inheritance (only one level up)
  368. boolean extendsAspect = false;
  369. if (!"java.lang.Object".equals(struct.enclosingType.getSuperclass().getName())) {
  370. if (!struct.enclosingType.getSuperclass().isAbstract() && struct.enclosingType.getSuperclass().isAspect()) {
  371. reportError("cannot extend a concrete aspect", struct);
  372. return false;
  373. }
  374. extendsAspect = struct.enclosingType.getSuperclass().isAspect();
  375. }
  376. ElementNameValuePair aspectPerClause = getAnnotationElement(aspect, VALUE);
  377. final PerClause perClause;
  378. if (aspectPerClause == null) {
  379. // empty value means singleton unless inherited
  380. if (!extendsAspect) {
  381. perClause = new PerSingleton();
  382. } else {
  383. perClause = new PerFromSuper(struct.enclosingType.getSuperclass().getPerClause().getKind());
  384. }
  385. } else {
  386. String perX = aspectPerClause.getValue().stringifyValue();
  387. if (perX == null || perX.length() <= 0) {
  388. perClause = new PerSingleton();
  389. } else {
  390. perClause = parsePerClausePointcut(perX, struct);
  391. }
  392. }
  393. if (perClause == null) {
  394. // could not parse it, ignore the aspect
  395. return false;
  396. } else {
  397. perClause.setLocation(struct.context, struct.context.getOffset(), struct.context.getOffset()+1);//FIXME AVASM
  398. struct.ajAttributes.add(new AjAttribute.Aspect(perClause));
  399. return true;
  400. }
  401. }
  402. return false;
  403. }
  404. /**
  405. * Read a perClause, returns null on failure and issue messages
  406. *
  407. * @param perClauseString like "pertarget(.....)"
  408. * @param struct for which we are parsing the per clause
  409. * @return a PerClause instance
  410. */
  411. private static PerClause parsePerClausePointcut(String perClauseString, AjAttributeStruct struct) {
  412. final String pointcutString;
  413. Pointcut poincut = null;
  414. TypePattern typePattern = null;
  415. final PerClause perClause;
  416. if (perClauseString.startsWith(PerClause.KindAnnotationPrefix.PERCFLOW.getName())) {
  417. pointcutString = PerClause.KindAnnotationPrefix.PERCFLOW.extractPointcut(perClauseString);
  418. poincut = parsePointcut(pointcutString, struct, false);
  419. perClause = new PerCflow(poincut, false);
  420. } else if (perClauseString.startsWith(PerClause.KindAnnotationPrefix.PERCFLOWBELOW.getName())) {
  421. pointcutString = PerClause.KindAnnotationPrefix.PERCFLOWBELOW.extractPointcut(perClauseString);
  422. poincut = parsePointcut(pointcutString, struct, false);
  423. perClause = new PerCflow(poincut, true);
  424. } else if (perClauseString.startsWith(PerClause.KindAnnotationPrefix.PERTARGET.getName())) {
  425. pointcutString = PerClause.KindAnnotationPrefix.PERTARGET.extractPointcut(perClauseString);
  426. poincut = parsePointcut(pointcutString, struct, false);
  427. perClause = new PerObject(poincut, false);
  428. } else if (perClauseString.startsWith(PerClause.KindAnnotationPrefix.PERTHIS.getName())) {
  429. pointcutString = PerClause.KindAnnotationPrefix.PERTHIS.extractPointcut(perClauseString);
  430. poincut = parsePointcut(pointcutString, struct, false);
  431. perClause = new PerObject(poincut, true);
  432. } else if (perClauseString.startsWith(PerClause.KindAnnotationPrefix.PERTYPEWITHIN.getName())) {
  433. pointcutString = PerClause.KindAnnotationPrefix.PERTYPEWITHIN.extractPointcut(perClauseString);
  434. typePattern = parseTypePattern(pointcutString, struct);
  435. perClause = new PerTypeWithin(typePattern);
  436. } else if (perClauseString.equalsIgnoreCase(PerClause.SINGLETON.getName() + "()")) {
  437. perClause = new PerSingleton();
  438. } else {
  439. // could not parse the @AJ perclause - fallback to singleton and issue an error
  440. reportError("@Aspect per clause cannot be read '" + perClauseString + "'", struct);
  441. return null;
  442. }
  443. if (!PerClause.SINGLETON.equals(perClause.getKind())
  444. && !PerClause.PERTYPEWITHIN.equals(perClause.getKind())
  445. && poincut == null) {
  446. // we could not parse the pointcut
  447. return null;
  448. }
  449. if (PerClause.PERTYPEWITHIN.equals(perClause.getKind()) && typePattern == null) {
  450. // we could not parse the type pattern
  451. return null;
  452. }
  453. return perClause;
  454. }
  455. /**
  456. * Read @DeclarePrecedence
  457. *
  458. * @param runtimeAnnotations
  459. * @param struct
  460. * @return true if found
  461. */
  462. private static boolean handlePrecedenceAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeStruct struct) {
  463. Annotation aspect = getAnnotation(runtimeAnnotations, AjcMemberMaker.DECLAREPRECEDENCE_ANNOTATION);
  464. if (aspect != null) {
  465. ElementNameValuePair precedence = getAnnotationElement(aspect, VALUE);
  466. if (precedence != null) {
  467. String precedencePattern = precedence.getValue().stringifyValue();
  468. PatternParser parser = new PatternParser(precedencePattern);
  469. DeclarePrecedence ajPrecedence = parser.parseDominates();
  470. struct.ajAttributes.add(new AjAttribute.DeclareAttribute(ajPrecedence));
  471. return true;
  472. }
  473. }
  474. return false;
  475. }
  476. /**
  477. * Read @Before
  478. *
  479. * @param runtimeAnnotations
  480. * @param struct
  481. * @return true if found
  482. */
  483. private static boolean handleBeforeAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeMethodStruct struct, ResolvedPointcutDefinition preResolvedPointcut) {
  484. Annotation before = getAnnotation(runtimeAnnotations, AjcMemberMaker.BEFORE_ANNOTATION);
  485. if (before != null) {
  486. ElementNameValuePair beforeAdvice = getAnnotationElement(before, VALUE);
  487. if (beforeAdvice != null) {
  488. // this/target/args binding
  489. FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0];
  490. try {
  491. bindings = extractBindings(struct);
  492. } catch (UnreadableDebugInfoException unreadableDebugInfoException) {
  493. return false;
  494. }
  495. IScope binding = new BindingScope(
  496. struct.enclosingType,
  497. struct.context,
  498. bindings
  499. );
  500. // joinpoint, staticJoinpoint binding
  501. int extraArgument = extractExtraArgument(struct.method);
  502. Pointcut pc = null;
  503. if (preResolvedPointcut != null) {
  504. pc = preResolvedPointcut.getPointcut();
  505. //pc.resolve(binding);
  506. } else {
  507. pc = parsePointcut(beforeAdvice.getValue().stringifyValue(), struct, false);
  508. if (pc == null) return false;//parse error
  509. pc.resolve(binding);
  510. }
  511. setIgnoreUnboundBindingNames(pc, bindings);
  512. ISourceLocation sl = struct.context.makeSourceLocation(struct.bMethod.getDeclarationLineNumber());
  513. struct.ajAttributes.add(
  514. new AjAttribute.AdviceAttribute(
  515. AdviceKind.Before,
  516. pc,
  517. extraArgument,
  518. sl.getOffset(),
  519. sl.getOffset()+1,//FIXME AVASM
  520. struct.context
  521. )
  522. );
  523. return true;
  524. }
  525. }
  526. return false;
  527. }
  528. /**
  529. * Read @After
  530. *
  531. * @param runtimeAnnotations
  532. * @param struct
  533. * @return true if found
  534. */
  535. private static boolean handleAfterAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeMethodStruct struct, ResolvedPointcutDefinition preResolvedPointcut) {
  536. Annotation after = getAnnotation(runtimeAnnotations, AjcMemberMaker.AFTER_ANNOTATION);
  537. if (after != null) {
  538. ElementNameValuePair afterAdvice = getAnnotationElement(after, VALUE);
  539. if (afterAdvice != null) {
  540. // this/target/args binding
  541. FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0];
  542. try {
  543. bindings = extractBindings(struct);
  544. } catch (UnreadableDebugInfoException unreadableDebugInfoException) {
  545. return false;
  546. }
  547. IScope binding = new BindingScope(
  548. struct.enclosingType,
  549. struct.context,
  550. bindings
  551. );
  552. // joinpoint, staticJoinpoint binding
  553. int extraArgument = extractExtraArgument(struct.method);
  554. Pointcut pc = null;
  555. if (preResolvedPointcut != null) {
  556. pc = preResolvedPointcut.getPointcut();
  557. } else {
  558. pc = parsePointcut(afterAdvice.getValue().stringifyValue(), struct, false);
  559. if (pc == null) return false;//parse error
  560. pc.resolve(binding);
  561. }
  562. setIgnoreUnboundBindingNames(pc, bindings);
  563. ISourceLocation sl = struct.context.makeSourceLocation(struct.bMethod.getDeclarationLineNumber());
  564. struct.ajAttributes.add(
  565. new AjAttribute.AdviceAttribute(
  566. AdviceKind.After,
  567. pc,
  568. extraArgument,
  569. sl.getOffset(),
  570. sl.getOffset()+1,//FIXME AVASM
  571. struct.context
  572. )
  573. );
  574. return true;
  575. }
  576. }
  577. return false;
  578. }
  579. /**
  580. * Read @AfterReturning
  581. *
  582. * @param runtimeAnnotations
  583. * @param struct
  584. * @return true if found
  585. */
  586. private static boolean handleAfterReturningAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeMethodStruct struct, ResolvedPointcutDefinition preResolvedPointcut) {
  587. Annotation after = getAnnotation(runtimeAnnotations, AjcMemberMaker.AFTERRETURNING_ANNOTATION);
  588. if (after != null) {
  589. ElementNameValuePair annValue = getAnnotationElement(after, VALUE);
  590. ElementNameValuePair annPointcut = getAnnotationElement(after, POINTCUT);
  591. ElementNameValuePair annReturned = getAnnotationElement(after, RETURNING);
  592. // extract the pointcut and returned type/binding - do some checks
  593. String pointcut = null;
  594. String returned = null;
  595. if ((annValue != null && annPointcut != null) || (annValue == null && annPointcut == null)) {
  596. reportError("@AfterReturning: either 'value' or 'poincut' must be provided, not both", struct);
  597. return false;
  598. }
  599. if (annValue != null) {
  600. pointcut = annValue.getValue().stringifyValue();
  601. } else {
  602. pointcut = annPointcut.getValue().stringifyValue();
  603. }
  604. if (isNullOrEmpty(pointcut)) {
  605. reportError("@AfterReturning: either 'value' or 'poincut' must be provided, not both", struct);
  606. return false;
  607. }
  608. if (annReturned != null) {
  609. returned = annReturned.getValue().stringifyValue();
  610. if (isNullOrEmpty(returned))
  611. returned = null;
  612. }
  613. // this/target/args binding
  614. // exclude the return binding from the pointcut binding since it is an extraArg binding
  615. FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0];
  616. try {
  617. bindings = (returned == null ? extractBindings(struct) : extractBindings(struct, returned));
  618. } catch (UnreadableDebugInfoException unreadableDebugInfoException) {
  619. return false;
  620. }
  621. IScope binding = new BindingScope(
  622. struct.enclosingType,
  623. struct.context,
  624. bindings
  625. );
  626. // joinpoint, staticJoinpoint binding
  627. int extraArgument = extractExtraArgument(struct.method);
  628. // return binding
  629. if (returned != null) {
  630. extraArgument |= Advice.ExtraArgument;
  631. }
  632. Pointcut pc = null;
  633. if (preResolvedPointcut != null) {
  634. pc = preResolvedPointcut.getPointcut();
  635. } else {
  636. pc = parsePointcut(pointcut, struct, false);
  637. if (pc == null) return false;//parse error
  638. pc.resolve(binding);
  639. }
  640. setIgnoreUnboundBindingNames(pc, bindings);
  641. ISourceLocation sl = struct.context.makeSourceLocation(struct.bMethod.getDeclarationLineNumber());
  642. struct.ajAttributes.add(
  643. new AjAttribute.AdviceAttribute(
  644. AdviceKind.AfterReturning,
  645. pc,
  646. extraArgument,
  647. sl.getOffset(),
  648. sl.getOffset()+1,//FIXME AVASM
  649. struct.context
  650. )
  651. );
  652. return true;
  653. }
  654. return false;
  655. }
  656. /**
  657. * Read @AfterThrowing
  658. *
  659. * @param runtimeAnnotations
  660. * @param struct
  661. * @return true if found
  662. */
  663. private static boolean handleAfterThrowingAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeMethodStruct struct, ResolvedPointcutDefinition preResolvedPointcut) {
  664. Annotation after = getAnnotation(runtimeAnnotations, AjcMemberMaker.AFTERTHROWING_ANNOTATION);
  665. if (after != null) {
  666. ElementNameValuePair annValue = getAnnotationElement(after, VALUE);
  667. ElementNameValuePair annPointcut = getAnnotationElement(after, POINTCUT);
  668. ElementNameValuePair annThrowned = getAnnotationElement(after, THROWING);
  669. // extract the pointcut and throwned type/binding - do some checks
  670. String pointcut = null;
  671. String throwned = null;
  672. if ((annValue != null && annPointcut != null) || (annValue == null && annPointcut == null)) {
  673. reportError("@AfterThrowing: either 'value' or 'poincut' must be provided, not both", struct);
  674. return false;
  675. }
  676. if (annValue != null) {
  677. pointcut = annValue.getValue().stringifyValue();
  678. } else {
  679. pointcut = annPointcut.getValue().stringifyValue();
  680. }
  681. if (isNullOrEmpty(pointcut)) {
  682. reportError("@AfterThrowing: either 'value' or 'poincut' must be provided, not both", struct);
  683. return false;
  684. }
  685. if (annThrowned != null) {
  686. throwned = annThrowned.getValue().stringifyValue();
  687. if (isNullOrEmpty(throwned))
  688. throwned = null;
  689. }
  690. // this/target/args binding
  691. // exclude the throwned binding from the pointcut binding since it is an extraArg binding
  692. FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0];
  693. try {
  694. bindings = (throwned == null ? extractBindings(struct) : extractBindings(struct, throwned));
  695. } catch (UnreadableDebugInfoException unreadableDebugInfoException) {
  696. return false;
  697. }
  698. IScope binding = new BindingScope(
  699. struct.enclosingType,
  700. struct.context,
  701. bindings
  702. );
  703. // joinpoint, staticJoinpoint binding
  704. int extraArgument = extractExtraArgument(struct.method);
  705. // return binding
  706. if (throwned != null) {
  707. extraArgument |= Advice.ExtraArgument;
  708. }
  709. Pointcut pc = null;
  710. if (preResolvedPointcut != null) {
  711. pc = preResolvedPointcut.getPointcut();
  712. } else {
  713. pc = parsePointcut(pointcut, struct, false);
  714. if (pc == null) return false;//parse error
  715. pc.resolve(binding);
  716. }
  717. setIgnoreUnboundBindingNames(pc, bindings);
  718. ISourceLocation sl = struct.context.makeSourceLocation(struct.bMethod.getDeclarationLineNumber());
  719. struct.ajAttributes.add(
  720. new AjAttribute.AdviceAttribute(
  721. AdviceKind.AfterThrowing,
  722. pc,
  723. extraArgument,
  724. sl.getOffset(),
  725. sl.getOffset()+1,//FIXME AVASM
  726. struct.context
  727. )
  728. );
  729. return true;
  730. }
  731. return false;
  732. }
  733. /**
  734. * Read @Around
  735. *
  736. * @param runtimeAnnotations
  737. * @param struct
  738. * @return true if found
  739. */
  740. private static boolean handleAroundAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeMethodStruct struct, ResolvedPointcutDefinition preResolvedPointcut) {
  741. Annotation around = getAnnotation(runtimeAnnotations, AjcMemberMaker.AROUND_ANNOTATION);
  742. if (around != null) {
  743. ElementNameValuePair aroundAdvice = getAnnotationElement(around, VALUE);
  744. if (aroundAdvice != null) {
  745. // this/target/args binding
  746. FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0];
  747. try {
  748. bindings = extractBindings(struct);
  749. } catch (UnreadableDebugInfoException unreadableDebugInfoException) {
  750. return false;
  751. }
  752. IScope binding = new BindingScope(
  753. struct.enclosingType,
  754. struct.context,
  755. bindings
  756. );
  757. // joinpoint, staticJoinpoint binding
  758. int extraArgument = extractExtraArgument(struct.method);
  759. Pointcut pc = null;
  760. if (preResolvedPointcut != null) {
  761. pc = preResolvedPointcut.getPointcut();
  762. } else {
  763. pc = parsePointcut(aroundAdvice.getValue().stringifyValue(), struct, false);
  764. if (pc == null) return false;//parse error
  765. pc.resolve(binding);
  766. }
  767. setIgnoreUnboundBindingNames(pc, bindings);
  768. ISourceLocation sl = struct.context.makeSourceLocation(struct.bMethod.getDeclarationLineNumber());
  769. struct.ajAttributes.add(
  770. new AjAttribute.AdviceAttribute(
  771. AdviceKind.Around,
  772. pc,
  773. extraArgument,
  774. sl.getOffset(),
  775. sl.getOffset()+1,//FIXME AVASM
  776. struct.context
  777. )
  778. );
  779. return true;
  780. }
  781. }
  782. return false;
  783. }
  784. /**
  785. * Read @Pointcut and handle the resolving in a lazy way to deal with pointcut references
  786. *
  787. * @param runtimeAnnotations
  788. * @param struct
  789. */
  790. private static void handlePointcutAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeMethodStruct struct) {
  791. Annotation pointcut = getAnnotation(runtimeAnnotations, AjcMemberMaker.POINTCUT_ANNOTATION);
  792. if (pointcut != null) {
  793. ElementNameValuePair pointcutExpr = getAnnotationElement(pointcut, VALUE);
  794. if (pointcutExpr != null) {
  795. // semantic check: the method must return void, or be "public static boolean" for if() support
  796. if (!(Type.VOID.equals(struct.method.getReturnType())
  797. || (Type.BOOLEAN.equals(struct.method.getReturnType()) && struct.method.isStatic() && struct.method.isPublic()))) {
  798. reportWarning("Found @Pointcut on a method not returning 'void' or not 'public static boolean'", struct);
  799. ;//no need to stop
  800. }
  801. // semantic check: the method must not throw anything
  802. if (struct.method.getExceptionTable() != null) {
  803. reportWarning("Found @Pointcut on a method throwing exception", struct);
  804. ;// no need to stop
  805. }
  806. // this/target/args binding
  807. final IScope binding;
  808. try {
  809. binding = new BindingScope(
  810. struct.enclosingType,
  811. struct.context,
  812. extractBindings(struct)
  813. );
  814. } catch (UnreadableDebugInfoException e) {
  815. return;
  816. }
  817. TypeX[] argumentTypes = new TypeX[struct.method.getArgumentTypes().length];
  818. for (int i = 0; i < argumentTypes.length; i++) {
  819. argumentTypes[i] = TypeX.forSignature(struct.method.getArgumentTypes()[i].getSignature());
  820. }
  821. // use a LazyResolvedPointcutDefinition so that the pointcut is resolved lazily
  822. // since for it to be resolved, we will need other pointcuts to be registered as well
  823. Pointcut pc = parsePointcut(pointcutExpr.getValue().stringifyValue(), struct, true);
  824. if (pc == null) return;//parse error
  825. // do not resolve binding now but lazily
  826. pc.setLocation(struct.context, -1, -1);//FIXME AVASM !! bMethod is null here..
  827. struct.ajAttributes.add(
  828. new AjAttribute.PointcutDeclarationAttribute(
  829. new LazyResolvedPointcutDefinition(
  830. struct.enclosingType,
  831. struct.method.getModifiers(),
  832. struct.method.getName(),
  833. argumentTypes,
  834. TypeX.forSignature(struct.method.getReturnType().getSignature()),
  835. pc,
  836. binding
  837. )
  838. )
  839. );
  840. }
  841. }
  842. }
  843. /**
  844. * Read @DeclareError, @DeclareWarning
  845. *
  846. * @param runtimeAnnotations
  847. * @param struct
  848. * @return true if found
  849. */
  850. private static boolean handleDeclareErrorOrWarningAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeFieldStruct struct) {
  851. Annotation error = getAnnotation(runtimeAnnotations, AjcMemberMaker.DECLAREERROR_ANNOTATION);
  852. boolean hasError = false;
  853. if (error != null) {
  854. ElementNameValuePair declareError = getAnnotationElement(error, VALUE);
  855. if (declareError != null) {
  856. if (!STRING_DESC.equals(struct.field.getSignature()) || struct.field.getConstantValue() == null) {
  857. reportError("@DeclareError used on a non String constant field", struct);
  858. return false;
  859. }
  860. FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0];
  861. IScope binding = new BindingScope(
  862. struct.enclosingType,
  863. struct.context,
  864. bindings
  865. );
  866. Pointcut pc = parsePointcut(declareError.getValue().stringifyValue(), struct, false);
  867. if (pc == null) {
  868. hasError = false;//cannot parse pointcut
  869. } else {
  870. pc .resolve(binding);
  871. DeclareErrorOrWarning deow = new DeclareErrorOrWarning(true, pc, struct.field.getConstantValue().toString());
  872. deow.setLocation(struct.context, -1, -1);
  873. struct.ajAttributes.add(new AjAttribute.DeclareAttribute(deow));
  874. hasError = true;
  875. }
  876. }
  877. }
  878. Annotation warning = getAnnotation(runtimeAnnotations, AjcMemberMaker.DECLAREWARNING_ANNOTATION);
  879. boolean hasWarning = false;
  880. if (warning != null) {
  881. ElementNameValuePair declareWarning = getAnnotationElement(warning, VALUE);
  882. if (declareWarning != null) {
  883. if (!STRING_DESC.equals(struct.field.getSignature()) || struct.field.getConstantValue() == null) {
  884. reportError("@DeclareWarning used on a non String constant field", struct);
  885. return false;
  886. }
  887. FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0];
  888. IScope binding = new BindingScope(
  889. struct.enclosingType,
  890. struct.context,
  891. bindings
  892. );
  893. Pointcut pc = parsePointcut(declareWarning.getValue().stringifyValue(), struct, false);
  894. if (pc == null) {
  895. hasWarning = false;//cannot parse pointcut
  896. } else {
  897. pc.resolve(binding);
  898. DeclareErrorOrWarning deow = new DeclareErrorOrWarning(false, pc, struct.field.getConstantValue().toString());
  899. deow.setLocation(struct.context, -1, -1);
  900. struct.ajAttributes.add(new AjAttribute.DeclareAttribute(deow));
  901. return hasWarning = true;
  902. }
  903. }
  904. }
  905. return hasError || hasWarning;
  906. }
  907. /**
  908. * Returns a readable representation of a method.
  909. * Method.toString() is not suitable.
  910. *
  911. * @param method
  912. * @return
  913. */
  914. private static String methodToString(Method method) {
  915. StringBuffer sb = new StringBuffer();
  916. sb.append(method.getName());
  917. sb.append(method.getSignature());
  918. return sb.toString();
  919. }
  920. /**
  921. * Returns a readable representation of a field.
  922. * Field.toString() is not suitable.
  923. *
  924. * @param field
  925. * @return
  926. */
  927. private static String fieldToString(Field field) {
  928. StringBuffer sb = new StringBuffer();
  929. sb.append(field.getName()).append(' ');
  930. sb.append(field.getSignature());
  931. return sb.toString();
  932. }
  933. /**
  934. * Build the bindings for a given method (pointcut / advice)
  935. *
  936. * @param struct
  937. * @return null if no debug info is available
  938. */
  939. private static FormalBinding[] extractBindings(AjAttributeMethodStruct struct)
  940. throws UnreadableDebugInfoException {
  941. Method method = struct.method;
  942. String[] argumentNames = struct.getArgumentNames();
  943. // assert debug info was here
  944. if (argumentNames.length != method.getArgumentTypes().length) {
  945. reportError("Cannot read debug info for @Aspect to handle formal binding in pointcuts (please compile with 'javac -g' or '<javac debug='true'.../>' in Ant)", struct);
  946. throw new UnreadableDebugInfoException();
  947. }
  948. List bindings = new ArrayList();
  949. for (int i = 0; i < argumentNames.length; i++) {
  950. String argumentName = argumentNames[i];
  951. TypeX argumentType = TypeX.forSignature(method.getArgumentTypes()[i].getSignature());
  952. // do not bind JoinPoint / StaticJoinPoint / EnclosingStaticJoinPoint
  953. // TODO solve me : this means that the JP/SJP/ESJP cannot appear as binding
  954. // f.e. when applying advice on advice etc
  955. if ((AjcMemberMaker.TYPEX_JOINPOINT.equals(argumentType)
  956. || AjcMemberMaker.TYPEX_PROCEEDINGJOINPOINT.equals(argumentType)
  957. || AjcMemberMaker.TYPEX_STATICJOINPOINT.equals(argumentType)
  958. || AjcMemberMaker.TYPEX_ENCLOSINGSTATICJOINPOINT.equals(argumentType)
  959. || AjcMemberMaker.AROUND_CLOSURE_TYPE.equals(argumentType))) {
  960. //continue;// skip
  961. bindings.add(new FormalBinding.ImplicitFormalBinding(argumentType, argumentName, i));
  962. } else {
  963. bindings.add(new FormalBinding(argumentType, argumentName, i));
  964. }
  965. }
  966. return (FormalBinding[]) bindings.toArray(new FormalBinding[]{});
  967. }
  968. //FIXME alex deal with exclude index
  969. private static FormalBinding[] extractBindings(AjAttributeMethodStruct struct, String excludeFormal)
  970. throws UnreadableDebugInfoException {
  971. FormalBinding[] bindings = extractBindings(struct);
  972. int excludeIndex = -1;
  973. for (int i = 0; i < bindings.length; i++) {
  974. FormalBinding binding = bindings[i];
  975. if (binding.getName().equals(excludeFormal)) {
  976. excludeIndex = i;
  977. bindings[i] = new FormalBinding.ImplicitFormalBinding(
  978. binding.getType(), binding.getName(), binding.getIndex()
  979. );
  980. break;
  981. }
  982. }
  983. return bindings;
  984. //
  985. // if (excludeIndex >= 0) {
  986. // FormalBinding[] bindingsFiltered = new FormalBinding[bindings.length-1];
  987. // int k = 0;
  988. // for (int i = 0; i < bindings.length; i++) {
  989. // if (i == excludeIndex) {
  990. // ;
  991. // } else {
  992. // bindingsFiltered[k] = new FormalBinding(bindings[i].getType(), bindings[i].getName(), k);
  993. // k++;
  994. // }
  995. // }
  996. // return bindingsFiltered;
  997. // } else {
  998. // return bindings;
  999. // }
  1000. }
  1001. /**
  1002. * Compute the flag for the xxxJoinPoint extra argument
  1003. *
  1004. * @param method
  1005. * @return
  1006. */
  1007. private static int extractExtraArgument(Method method) {
  1008. Type[] methodArgs = method.getArgumentTypes();
  1009. String[] sigs = new String[methodArgs.length];
  1010. for (int i = 0; i < methodArgs.length; i++) {
  1011. sigs[i] = methodArgs[i].getSignature();
  1012. }
  1013. return extractExtraArgument(sigs);
  1014. }
  1015. /**
  1016. * Compute the flag for the xxxJoinPoint extra argument
  1017. *
  1018. * @param argumentSignatures
  1019. * @return
  1020. */
  1021. public static int extractExtraArgument(String[] argumentSignatures) {
  1022. int extraArgument = 0;
  1023. for (int i = 0; i < argumentSignatures.length; i++) {
  1024. if (AjcMemberMaker.TYPEX_JOINPOINT.getSignature().equals(argumentSignatures[i])) {
  1025. extraArgument |= Advice.ThisJoinPoint;
  1026. } else if (AjcMemberMaker.TYPEX_PROCEEDINGJOINPOINT.getSignature().equals(argumentSignatures[i])) {
  1027. extraArgument |= Advice.ThisJoinPoint;
  1028. } else if (AjcMemberMaker.TYPEX_STATICJOINPOINT.getSignature().equals(argumentSignatures[i])) {
  1029. extraArgument |= Advice.ThisJoinPointStaticPart;
  1030. } else if (AjcMemberMaker.TYPEX_ENCLOSINGSTATICJOINPOINT.getSignature().equals(argumentSignatures[i])) {
  1031. extraArgument |= Advice.ThisEnclosingJoinPointStaticPart;
  1032. }
  1033. }
  1034. return extraArgument;
  1035. }
  1036. /**
  1037. * Returns the runtime (RV/RIV) annotation of type annotationType or null if no such annotation
  1038. *
  1039. * @param rvs
  1040. * @param annotationType
  1041. * @return
  1042. */
  1043. private static Annotation getAnnotation(RuntimeAnnotations rvs, TypeX annotationType) {
  1044. final String annotationTypeName = annotationType.getName();
  1045. for (Iterator iterator = rvs.getAnnotations().iterator(); iterator.hasNext();) {
  1046. Annotation rv = (Annotation) iterator.next();
  1047. if (annotationTypeName.equals(rv.getTypeName())) {
  1048. return rv;
  1049. }
  1050. }
  1051. return null;
  1052. }
  1053. /**
  1054. * Returns the value of a given element of an annotation or null if not found
  1055. * Caution: Does not handles default value.
  1056. *
  1057. * @param annotation
  1058. * @param elementName
  1059. * @return
  1060. */
  1061. private static ElementNameValuePair getAnnotationElement(Annotation annotation, String elementName) {
  1062. for (Iterator iterator1 = annotation.getValues().iterator(); iterator1.hasNext();) {
  1063. ElementNameValuePair element = (ElementNameValuePair) iterator1.next();
  1064. if (elementName.equals(element.getNameString())) {
  1065. return element;
  1066. }
  1067. }
  1068. return null;
  1069. }
  1070. /**
  1071. * Extract the method argument names as in source from debug info
  1072. * returns an empty array upon inconsistency
  1073. *
  1074. * @param method
  1075. * @return
  1076. */
  1077. private static String[] getMethodArgumentNamesAsInSource(Method method) {
  1078. if (method.getArgumentTypes().length == 0) {
  1079. return EMPTY_STRINGS;
  1080. }
  1081. final int startAtStackIndex = method.isStatic() ? 0 : 1;
  1082. final List arguments = new ArrayList();
  1083. LocalVariableTable lt = (LocalVariableTable) method.getLocalVariableTable();
  1084. if (lt != null) {
  1085. for (int j = 0; j < lt.getLocalVariableTable().length; j++) {
  1086. LocalVariable localVariable = lt.getLocalVariableTable()[j];
  1087. if (localVariable.getStartPC() == 0) {
  1088. if (localVariable.getIndex() >= startAtStackIndex) {
  1089. arguments.add(new MethodArgument(localVariable.getName(), localVariable.getIndex()));
  1090. }
  1091. }
  1092. }
  1093. }
  1094. if (arguments.size() != method.getArgumentTypes().length) {
  1095. return EMPTY_STRINGS;
  1096. }
  1097. // sort by index
  1098. Collections.sort(
  1099. arguments, new Comparator() {
  1100. public int compare(Object o, Object o1) {
  1101. MethodArgument mo = (MethodArgument) o;
  1102. MethodArgument mo1 = (MethodArgument) o1;
  1103. if (mo.indexOnStack == mo1.indexOnStack) {
  1104. return 0;
  1105. } else if (mo.indexOnStack > mo1.indexOnStack) {
  1106. return 1;
  1107. } else {
  1108. return -1;
  1109. }
  1110. }
  1111. }
  1112. );
  1113. String[] argumentNames = new String[arguments.size()];
  1114. int i = 0;
  1115. for (Iterator iterator = arguments.iterator(); iterator.hasNext(); i++) {
  1116. MethodArgument methodArgument = (MethodArgument) iterator.next();
  1117. argumentNames[i] = methodArgument.name;
  1118. }
  1119. return argumentNames;
  1120. }
  1121. /**
  1122. * A method argument, used for sorting by indexOnStack (ie order in signature)
  1123. *
  1124. * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
  1125. */
  1126. private static class MethodArgument {
  1127. String name;
  1128. int indexOnStack;
  1129. public MethodArgument(String name, int indexOnStack) {
  1130. this.name = name;
  1131. this.indexOnStack = indexOnStack;
  1132. }
  1133. }
  1134. /**
  1135. * BindingScope that knows the enclosingType, which is needed for pointcut reference resolution
  1136. *
  1137. * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
  1138. */
  1139. public static class BindingScope extends SimpleScope {
  1140. private ResolvedTypeX m_enclosingType;
  1141. private ISourceContext m_sourceContext;
  1142. public BindingScope(ResolvedTypeX type, ISourceContext sourceContext, FormalBinding[] bindings) {
  1143. super(type.getWorld(), bindings);
  1144. m_enclosingType = type;
  1145. m_sourceContext = sourceContext;
  1146. }
  1147. public ResolvedTypeX getEnclosingType() {
  1148. return m_enclosingType;
  1149. }
  1150. public ISourceLocation makeSourceLocation(IHasPosition location) {
  1151. return m_sourceContext.makeSourceLocation(location);
  1152. }
  1153. }
  1154. /**
  1155. * LazyResolvedPointcutDefinition lazyly resolve the pointcut so that we have time to register all
  1156. * pointcut referenced before pointcut resolution happens
  1157. *
  1158. * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
  1159. */
  1160. public static class LazyResolvedPointcutDefinition extends ResolvedPointcutDefinition {
  1161. private Pointcut m_pointcutUnresolved;
  1162. private IScope m_binding;
  1163. private Pointcut m_lazyPointcut = null;
  1164. public LazyResolvedPointcutDefinition(ResolvedTypeX declaringType, int modifiers, String name,
  1165. TypeX[] parameterTypes, TypeX returnType,
  1166. Pointcut pointcut, IScope binding) {
  1167. super(declaringType, modifiers, name, parameterTypes, returnType, null);
  1168. m_pointcutUnresolved = pointcut;
  1169. m_binding = binding;
  1170. }
  1171. public Pointcut getPointcut() {
  1172. if (m_lazyPointcut == null) {
  1173. m_lazyPointcut = m_pointcutUnresolved.resolve(m_binding);
  1174. m_lazyPointcut.copyLocationFrom(m_pointcutUnresolved);
  1175. }
  1176. return m_lazyPointcut;
  1177. }
  1178. }
  1179. /**
  1180. * Helper to test empty strings
  1181. *
  1182. * @param s
  1183. * @return
  1184. */
  1185. private static boolean isNullOrEmpty(String s) {
  1186. return (s == null || s.length() <= 0);
  1187. }
  1188. /**
  1189. * Set the pointcut bindings for which to ignore unbound issues, so that we can implicitly bind
  1190. * xxxJoinPoint for @AJ advices
  1191. *
  1192. * @param pointcut
  1193. * @param bindings
  1194. */
  1195. private static void setIgnoreUnboundBindingNames(Pointcut pointcut, FormalBinding[] bindings) {
  1196. // register ImplicitBindings as to be ignored since unbound
  1197. // TODO is it likely to fail in a bad way if f.e. this(jp) etc ?
  1198. List ignores = new ArrayList();
  1199. for (int i = 0; i < bindings.length; i++) {
  1200. FormalBinding formalBinding = bindings[i];
  1201. if (formalBinding instanceof FormalBinding.ImplicitFormalBinding) {
  1202. ignores.add(formalBinding.getName());
  1203. }
  1204. }
  1205. pointcut.m_ignoreUnboundBindingForNames = (String[]) ignores.toArray(new String[ignores.size()]);
  1206. }
  1207. /**
  1208. * A check exception when we cannot read debug info (needed for formal binding)
  1209. */
  1210. private static class UnreadableDebugInfoException extends Exception {
  1211. }
  1212. /**
  1213. * Report an error
  1214. *
  1215. * @param message
  1216. * @param location
  1217. */
  1218. private static void reportError(String message, AjAttributeStruct location) {
  1219. if (!location.handler.isIgnoring(IMessage.ERROR)) {
  1220. location.handler.handleMessage(
  1221. new Message(
  1222. message,
  1223. location.enclosingType.getSourceLocation(),
  1224. true
  1225. )
  1226. );
  1227. }
  1228. }
  1229. /**
  1230. * Report a warning
  1231. *
  1232. * @param message
  1233. * @param location
  1234. */
  1235. private static void reportWarning(String message, AjAttributeStruct location) {
  1236. if (!location.handler.isIgnoring(IMessage.WARNING)) {
  1237. location.handler.handleMessage(
  1238. new Message(
  1239. message,
  1240. location.enclosingType.getSourceLocation(),
  1241. false
  1242. )
  1243. );
  1244. }
  1245. }
  1246. /**
  1247. * Parse the given pointcut, return null on failure and issue an error
  1248. *
  1249. * @param pointcutString
  1250. * @param struct
  1251. * @param allowIf
  1252. * @return
  1253. */
  1254. private static Pointcut parsePointcut(String pointcutString, AjAttributeStruct struct, boolean allowIf) {
  1255. try {
  1256. Pointcut pointcut = new PatternParser(pointcutString, struct.context).parsePointcut();
  1257. if (!allowIf && pointcutString.indexOf("if()") >= 0 && hasIf(pointcut)) {
  1258. reportError("if() pointcut is not allowed at this pointcut location '" + pointcutString +"'", struct);
  1259. return null;
  1260. }
  1261. pointcut.setLocation(struct.context, -1, -1);//FIXME -1,-1 is not good enough
  1262. return pointcut;
  1263. } catch (ParserException e) {
  1264. reportError("Invalid pointcut '" + pointcutString + "': " + e.toString(), struct);
  1265. return null;
  1266. }
  1267. }
  1268. private static boolean hasIf(Pointcut pointcut) {
  1269. IfFinder visitor = new IfFinder();
  1270. pointcut.accept(visitor, null);
  1271. return visitor.hasIf;
  1272. }
  1273. /**
  1274. * Parse the given type pattern, return null on failure and issue an error
  1275. *
  1276. * @param patternString
  1277. * @param location
  1278. * @return
  1279. */
  1280. private static TypePattern parseTypePattern(String patternString, AjAttributeStruct location) {
  1281. try {
  1282. TypePattern typePattern = new PatternParser(patternString).parseTypePattern();
  1283. typePattern.setLocation(location.context, -1, -1);//FIXME -1,-1 is not good enough
  1284. return typePattern;
  1285. } catch (ParserException e) {
  1286. reportError("Invalid type pattern'" + patternString + "' : " + e.getLocation(), location);
  1287. return null;
  1288. }
  1289. }
  1290. /**
  1291. * Look for an if() pointcut
  1292. */
  1293. private static class IfFinder extends IdentityPointcutVisitor {
  1294. boolean hasIf = false;
  1295. public Object visit(IfPointcut node, Object data) {
  1296. if (node.alwaysFalse() || node.alwaysTrue()) {
  1297. ;//IfFalse / IfTrue
  1298. } else {
  1299. hasIf = true;
  1300. }
  1301. return node;
  1302. }
  1303. public Object visit(AndPointcut node, Object data) {
  1304. if (!hasIf) node.getLeft().accept(this, data);
  1305. if (!hasIf) node.getLeft().accept(this, data);
  1306. return node;
  1307. }
  1308. public Object visit(NotPointcut node, Object data) {
  1309. if (!hasIf) node.getNegatedPointcut().accept(this, data);
  1310. return node;
  1311. }
  1312. public Object visit(OrPointcut node, Object data) {
  1313. if (!hasIf) node.getLeft().accept(this, data);
  1314. if (!hasIf) node.getLeft().accept(this, data);
  1315. return node;
  1316. }
  1317. }
  1318. }