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 58KB

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