You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

AtAjAttributes.java 78KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785
  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.Arrays;
  15. import java.util.Collections;
  16. import java.util.Comparator;
  17. import java.util.Iterator;
  18. import java.util.List;
  19. import org.aspectj.apache.bcel.Constants;
  20. import org.aspectj.apache.bcel.classfile.Attribute;
  21. import org.aspectj.apache.bcel.classfile.Constant;
  22. import org.aspectj.apache.bcel.classfile.ConstantUtf8;
  23. import org.aspectj.apache.bcel.classfile.Field;
  24. import org.aspectj.apache.bcel.classfile.JavaClass;
  25. import org.aspectj.apache.bcel.classfile.LocalVariable;
  26. import org.aspectj.apache.bcel.classfile.LocalVariableTable;
  27. import org.aspectj.apache.bcel.classfile.Method;
  28. import org.aspectj.apache.bcel.classfile.annotation.Annotation;
  29. import org.aspectj.apache.bcel.classfile.annotation.ClassElementValue;
  30. import org.aspectj.apache.bcel.classfile.annotation.ElementNameValuePair;
  31. import org.aspectj.apache.bcel.classfile.annotation.RuntimeAnnotations;
  32. import org.aspectj.apache.bcel.classfile.annotation.RuntimeVisibleAnnotations;
  33. import org.aspectj.apache.bcel.generic.Type;
  34. import org.aspectj.asm.AsmManager;
  35. import org.aspectj.asm.IHierarchy;
  36. import org.aspectj.asm.IProgramElement;
  37. import org.aspectj.bridge.IMessage;
  38. import org.aspectj.bridge.IMessageHandler;
  39. import org.aspectj.bridge.ISourceLocation;
  40. import org.aspectj.bridge.Message;
  41. import org.aspectj.bridge.MessageUtil;
  42. import org.aspectj.weaver.Advice;
  43. import org.aspectj.weaver.AdviceKind;
  44. import org.aspectj.weaver.AjAttribute;
  45. import org.aspectj.weaver.AjcMemberMaker;
  46. import org.aspectj.weaver.IHasPosition;
  47. import org.aspectj.weaver.ISourceContext;
  48. import org.aspectj.weaver.MethodDelegateTypeMunger;
  49. import org.aspectj.weaver.NameMangler;
  50. import org.aspectj.weaver.ReferenceType;
  51. import org.aspectj.weaver.ResolvedMember;
  52. import org.aspectj.weaver.ResolvedPointcutDefinition;
  53. import org.aspectj.weaver.ResolvedType;
  54. import org.aspectj.weaver.UnresolvedType;
  55. import org.aspectj.weaver.WeaverMessages;
  56. import org.aspectj.weaver.patterns.Bindings;
  57. import org.aspectj.weaver.patterns.DeclareErrorOrWarning;
  58. import org.aspectj.weaver.patterns.DeclareParents;
  59. import org.aspectj.weaver.patterns.DeclarePrecedence;
  60. import org.aspectj.weaver.patterns.FormalBinding;
  61. import org.aspectj.weaver.patterns.IScope;
  62. import org.aspectj.weaver.patterns.ParserException;
  63. import org.aspectj.weaver.patterns.PatternParser;
  64. import org.aspectj.weaver.patterns.PerCflow;
  65. import org.aspectj.weaver.patterns.PerClause;
  66. import org.aspectj.weaver.patterns.PerFromSuper;
  67. import org.aspectj.weaver.patterns.PerObject;
  68. import org.aspectj.weaver.patterns.PerSingleton;
  69. import org.aspectj.weaver.patterns.PerTypeWithin;
  70. import org.aspectj.weaver.patterns.Pointcut;
  71. import org.aspectj.weaver.patterns.SimpleScope;
  72. import org.aspectj.weaver.patterns.TypePattern;
  73. /**
  74. * Annotation defined aspect reader.
  75. * <p/>
  76. * It reads the Java 5 annotations and turns them into AjAttributes
  77. *
  78. * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
  79. */
  80. public class AtAjAttributes {
  81. private final static List EMPTY_LIST = new ArrayList();
  82. private final static String[] EMPTY_STRINGS = new String[0];
  83. private final static String VALUE = "value";
  84. private final static String POINTCUT = "pointcut";
  85. private final static String THROWING = "throwing";
  86. private final static String RETURNING = "returning";
  87. private final static String STRING_DESC = "Ljava/lang/String;";
  88. /**
  89. * A struct that allows to add extra arguments without always breaking the API
  90. *
  91. * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
  92. */
  93. private static class AjAttributeStruct {
  94. /**
  95. * The list of AjAttribute.XXX that we are populating from the @AJ read
  96. */
  97. List ajAttributes = new ArrayList();
  98. /**
  99. * The resolved type (class) for which we are reading @AJ for (be it class, method, field annotations)
  100. */
  101. final ResolvedType enclosingType;
  102. final ISourceContext context;
  103. final IMessageHandler handler;
  104. public AjAttributeStruct(ResolvedType type, ISourceContext sourceContext, IMessageHandler messageHandler) {
  105. enclosingType = type;
  106. context = sourceContext;
  107. handler = messageHandler;
  108. }
  109. }
  110. /**
  111. * A struct when we read @AJ on method
  112. *
  113. * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
  114. */
  115. private static class AjAttributeMethodStruct extends AjAttributeStruct {
  116. /**
  117. * Argument names as they appear in the SOURCE code, ordered, and lazyly populated
  118. * Used to do formal binding
  119. */
  120. private String[] m_argumentNamesLazy = null;
  121. final Method method;
  122. final BcelMethod bMethod;
  123. public AjAttributeMethodStruct(Method method, BcelMethod bMethod, ResolvedType type, ISourceContext sourceContext, IMessageHandler messageHandler) {
  124. super(type, sourceContext, messageHandler);
  125. this.method = method;
  126. this.bMethod = bMethod;
  127. }
  128. public String[] getArgumentNames() {
  129. if (m_argumentNamesLazy == null) {
  130. m_argumentNamesLazy = getMethodArgumentNamesAsInSource(method);
  131. }
  132. return m_argumentNamesLazy;
  133. }
  134. }
  135. /**
  136. * A struct when we read @AJ on field
  137. *
  138. * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
  139. */
  140. private static class AjAttributeFieldStruct extends AjAttributeStruct {
  141. final Field field;
  142. final BcelField bField;
  143. public AjAttributeFieldStruct(Field field, BcelField bField, ResolvedType type, ISourceContext sourceContext, IMessageHandler messageHandler) {
  144. super(type, sourceContext, messageHandler);
  145. this.field = field;
  146. this.bField = bField;
  147. }
  148. }
  149. /**
  150. * Annotations are RuntimeVisible only. This allow us to not visit RuntimeInvisible ones.
  151. *
  152. * @param attribute
  153. * @return true if runtime visible annotation
  154. */
  155. public static boolean acceptAttribute(Attribute attribute) {
  156. return (attribute instanceof RuntimeVisibleAnnotations);
  157. }
  158. /**
  159. * Extract class level annotations and turn them into AjAttributes.
  160. *
  161. * @param javaClass
  162. * @param type
  163. * @param context
  164. * @param msgHandler
  165. * @return list of AjAttributes
  166. */
  167. public static List readAj5ClassAttributes(JavaClass javaClass, ReferenceType type, ISourceContext context, IMessageHandler msgHandler, boolean isCodeStyleAspect) {
  168. //FIXME AV - 1.5 feature limitation, kick after implemented
  169. try {
  170. Constant[] cpool = javaClass.getConstantPool().getConstantPool();
  171. for (int i = 0; i < cpool.length; i++) {
  172. Constant constant = cpool[i];
  173. if (constant != null && constant.getTag() == Constants.CONSTANT_Utf8) {
  174. if (!javaClass.getClassName().startsWith("org.aspectj.lang.annotation")) {
  175. ConstantUtf8 constantUtf8 = (ConstantUtf8) constant;
  176. if ("Lorg/aspectj/lang/annotation/DeclareAnnotation;".equals(constantUtf8.getBytes())) {
  177. msgHandler.handleMessage(
  178. new Message(
  179. "Found @DeclareAnnotation while current release does not support it (see '" + type.getName() + "')",
  180. IMessage.WARNING,
  181. null,
  182. type.getSourceLocation()
  183. )
  184. );
  185. }
  186. }
  187. }
  188. }
  189. } catch (Throwable t) {
  190. ;
  191. }
  192. AjAttributeStruct struct = new AjAttributeStruct(type, context, msgHandler);
  193. Attribute[] attributes = javaClass.getAttributes();
  194. boolean hasAtAspectAnnotation = false;
  195. boolean hasAtPrecedenceAnnotation = false;
  196. for (int i = 0; i < attributes.length; i++) {
  197. Attribute attribute = attributes[i];
  198. if (acceptAttribute(attribute)) {
  199. RuntimeAnnotations rvs = (RuntimeAnnotations) attribute;
  200. // we don't need to look for several attribute occurence since it cannot happen as per JSR175
  201. if (!isCodeStyleAspect && !javaClass.isInterface()) {
  202. hasAtAspectAnnotation = handleAspectAnnotation(rvs, struct);
  203. //TODO AV - if put outside the if isCodeStyleAspect then we would enable mix style
  204. hasAtPrecedenceAnnotation = handlePrecedenceAnnotation(rvs, struct);
  205. }
  206. // there can only be one RuntimeVisible bytecode attribute
  207. break;
  208. }
  209. }
  210. // basic semantic check
  211. if (hasAtPrecedenceAnnotation && !hasAtAspectAnnotation) {
  212. msgHandler.handleMessage(
  213. new Message(
  214. "Found @DeclarePrecedence on a non @Aspect type '" + type.getName() + "'",
  215. IMessage.WARNING,
  216. null,
  217. type.getSourceLocation()
  218. )
  219. );
  220. // bypass what we have read
  221. return EMPTY_LIST;
  222. }
  223. // the following block will not detect @Pointcut in non @Aspect types for optimization purpose
  224. if (!hasAtAspectAnnotation) {
  225. return EMPTY_LIST;
  226. }
  227. //FIXME AV - turn on when ajcMightHaveAspect
  228. // if (hasAtAspectAnnotation && type.isInterface()) {
  229. // msgHandler.handleMessage(
  230. // new Message(
  231. // "Found @Aspect on an interface type '" + type.getName() + "'",
  232. // IMessage.WARNING,
  233. // null,
  234. // type.getSourceLocation()
  235. // )
  236. // );
  237. // // bypass what we have read
  238. // return EMPTY_LIST;
  239. // }
  240. // semantic check: @Aspect must be public
  241. // FIXME AV - do we really want to enforce that?
  242. // if (hasAtAspectAnnotation && !javaClass.isPublic()) {
  243. // msgHandler.handleMessage(
  244. // new Message(
  245. // "Found @Aspect annotation on a non public class '" + javaClass.getClassName() + "'",
  246. // IMessage.ERROR,
  247. // null,
  248. // type.getSourceLocation()
  249. // )
  250. // );
  251. // return EMPTY_LIST;
  252. // }
  253. // code style pointcuts are class attributes
  254. // we need to gather the @AJ pointcut right now and not at method level annotation extraction time
  255. // in order to be able to resolve the pointcut references later on
  256. // we don't need to look in super class, the pointcut reference in the grammar will do it
  257. for (int i = 0; i < javaClass.getMethods().length; i++) {
  258. Method method = javaClass.getMethods()[i];
  259. if (method.getName().startsWith(NameMangler.PREFIX)) continue; // already dealt with by ajc...
  260. //FIXME alex optimize, this method struct will gets recreated for advice extraction
  261. AjAttributeMethodStruct mstruct = new AjAttributeMethodStruct(method, null, type, context, msgHandler);//FIXME AVASM
  262. Attribute[] mattributes = method.getAttributes();
  263. for (int j = 0; j < mattributes.length; j++) {
  264. Attribute mattribute = mattributes[j];
  265. if (acceptAttribute(mattribute)) {
  266. RuntimeAnnotations mrvs = (RuntimeAnnotations) mattribute;
  267. handlePointcutAnnotation(mrvs, mstruct);
  268. // there can only be one RuntimeVisible bytecode attribute
  269. break;
  270. }
  271. }
  272. // FIXME asc should check we aren't adding multiple versions... will do once I get the tests passing again...
  273. struct.ajAttributes.add(new AjAttribute.WeaverVersionInfo());
  274. struct.ajAttributes.addAll(mstruct.ajAttributes);
  275. }
  276. // code style declare error / warning / implements / parents are field attributes
  277. for (int i = 0; i < javaClass.getFields().length; i++) {
  278. Field field = javaClass.getFields()[i];
  279. if (field.getName().startsWith(NameMangler.PREFIX)) continue; // already dealt with by ajc...
  280. //FIXME alex optimize, this method struct will gets recreated for advice extraction
  281. AjAttributeFieldStruct fstruct = new AjAttributeFieldStruct(field, null, type, context, msgHandler);
  282. Attribute[] fattributes = field.getAttributes();
  283. for (int j = 0; j < fattributes.length; j++) {
  284. Attribute fattribute = fattributes[j];
  285. if (acceptAttribute(fattribute)) {
  286. RuntimeAnnotations frvs = (RuntimeAnnotations) fattribute;
  287. if (handleDeclareErrorOrWarningAnnotation(frvs, fstruct)
  288. || handleDeclareParentsAnnotation(frvs, fstruct)) {
  289. // semantic check - must be in an @Aspect [remove if previous block bypassed in advance]
  290. if (!type.isAnnotationStyleAspect()) {
  291. msgHandler.handleMessage(
  292. new Message(
  293. "Found @AspectJ annotations in a non @Aspect type '" + type.getName() + "'",
  294. IMessage.WARNING,
  295. null,
  296. type.getSourceLocation()
  297. )
  298. );
  299. ;// go ahead
  300. }
  301. }
  302. // there can only be one RuntimeVisible bytecode attribute
  303. break;
  304. }
  305. }
  306. struct.ajAttributes.addAll(fstruct.ajAttributes);
  307. }
  308. return struct.ajAttributes;
  309. }
  310. /**
  311. * Extract method level annotations and turn them into AjAttributes.
  312. *
  313. * @param method
  314. * @param type
  315. * @param context
  316. * @param msgHandler
  317. * @return list of AjAttributes
  318. */
  319. public static List readAj5MethodAttributes(Method method, BcelMethod bMethod, ResolvedType type, ResolvedPointcutDefinition preResolvedPointcut, ISourceContext context, IMessageHandler msgHandler) {
  320. if (method.getName().startsWith(NameMangler.PREFIX)) return Collections.EMPTY_LIST; // already dealt with by ajc...
  321. AjAttributeMethodStruct struct = new AjAttributeMethodStruct(method, bMethod, type, context, msgHandler);
  322. Attribute[] attributes = method.getAttributes();
  323. // we remember if we found one @AJ annotation for minimal semantic error reporting
  324. // the real reporting beeing done thru AJDT and the compiler mapping @AJ to AjAtttribute
  325. // or thru APT
  326. //
  327. // Note: we could actually skip the whole thing if type is not itself an @Aspect
  328. // but then we would not see any warning. We do bypass for pointcut but not for advice since it would
  329. // be too silent.
  330. boolean hasAtAspectJAnnotation = false;
  331. boolean hasAtAspectJAnnotationMustReturnVoid = false;
  332. for (int i = 0; i < attributes.length; i++) {
  333. Attribute attribute = attributes[i];
  334. try {
  335. if (acceptAttribute(attribute)) {
  336. RuntimeAnnotations rvs = (RuntimeAnnotations) attribute;
  337. hasAtAspectJAnnotationMustReturnVoid = hasAtAspectJAnnotationMustReturnVoid || handleBeforeAnnotation(
  338. rvs, struct, preResolvedPointcut
  339. );
  340. hasAtAspectJAnnotationMustReturnVoid = hasAtAspectJAnnotationMustReturnVoid || handleAfterAnnotation(
  341. rvs, struct, preResolvedPointcut
  342. );
  343. hasAtAspectJAnnotationMustReturnVoid = hasAtAspectJAnnotationMustReturnVoid || handleAfterReturningAnnotation(
  344. rvs, struct, preResolvedPointcut, bMethod
  345. );
  346. hasAtAspectJAnnotationMustReturnVoid = hasAtAspectJAnnotationMustReturnVoid || handleAfterThrowingAnnotation(
  347. rvs, struct, preResolvedPointcut, bMethod
  348. );
  349. hasAtAspectJAnnotation = hasAtAspectJAnnotation || handleAroundAnnotation(
  350. rvs, struct, preResolvedPointcut
  351. );
  352. // there can only be one RuntimeVisible bytecode attribute
  353. break;
  354. }
  355. } catch (ReturningFormalNotDeclaredInAdviceSignatureException e) {
  356. msgHandler.handleMessage(
  357. new Message(
  358. WeaverMessages.format(WeaverMessages.RETURNING_FORMAL_NOT_DECLARED_IN_ADVICE,e.getFormalName()),
  359. IMessage.ERROR,
  360. null,
  361. bMethod.getSourceLocation())
  362. );
  363. } catch (ThrownFormalNotDeclaredInAdviceSignatureException e) {
  364. msgHandler.handleMessage(
  365. new Message(
  366. WeaverMessages.format(WeaverMessages.THROWN_FORMAL_NOT_DECLARED_IN_ADVICE,e.getFormalName()),
  367. IMessage.ERROR,
  368. null,
  369. bMethod.getSourceLocation())
  370. ); }
  371. }
  372. hasAtAspectJAnnotation = hasAtAspectJAnnotation || hasAtAspectJAnnotationMustReturnVoid;
  373. // semantic check - must be in an @Aspect [remove if previous block bypassed in advance]
  374. if (hasAtAspectJAnnotation && !type.isAnnotationStyleAspect()) {
  375. msgHandler.handleMessage(
  376. new Message(
  377. "Found @AspectJ annotations in a non @Aspect type '" + type.getName() + "'",
  378. IMessage.WARNING,
  379. null,
  380. type.getSourceLocation()
  381. )
  382. );
  383. ;// go ahead
  384. }
  385. // semantic check - advice must be public
  386. if (hasAtAspectJAnnotation && !struct.method.isPublic()) {
  387. msgHandler.handleMessage(
  388. new Message(
  389. "Found @AspectJ annotation on a non public advice '" + methodToString(struct.method) + "'",
  390. IMessage.ERROR,
  391. null,
  392. type.getSourceLocation()
  393. )
  394. );
  395. ;// go ahead
  396. }
  397. // semantic check - advice must not be static
  398. if (hasAtAspectJAnnotation && struct.method.isStatic()) {
  399. msgHandler.handleMessage(MessageUtil.error("Advice cannot be declared static '" + methodToString(struct.method) + "'",type.getSourceLocation()));
  400. // new Message(
  401. // "Advice cannot be declared static '" + methodToString(struct.method) + "'",
  402. // IMessage.ERROR,
  403. // null,
  404. // type.getSourceLocation()
  405. // )
  406. // );
  407. ;// go ahead
  408. }
  409. // semantic check for non around advice must return void
  410. if (hasAtAspectJAnnotationMustReturnVoid && !Type.VOID.equals(struct.method.getReturnType())) {
  411. msgHandler.handleMessage(
  412. new Message(
  413. "Found @AspectJ annotation on a non around advice not returning void '" + methodToString(
  414. struct.method
  415. ) + "'",
  416. IMessage.ERROR,
  417. null,
  418. type.getSourceLocation()
  419. )
  420. );
  421. ;// go ahead
  422. }
  423. return struct.ajAttributes;
  424. }
  425. /**
  426. * Extract field level annotations and turn them into AjAttributes.
  427. *
  428. * @param field
  429. * @param type
  430. * @param context
  431. * @param msgHandler
  432. * @return list of AjAttributes, always empty for now
  433. */
  434. public static List readAj5FieldAttributes(Field field, BcelField bField, ResolvedType type, ISourceContext context, IMessageHandler msgHandler) {
  435. // Note: field annotation are for ITD and DEOW - processed at class level directly
  436. return Collections.EMPTY_LIST;
  437. }
  438. /**
  439. * Read @Aspect
  440. *
  441. * @param runtimeAnnotations
  442. * @param struct
  443. * @return true if found
  444. */
  445. private static boolean handleAspectAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeStruct struct) {
  446. Annotation aspect = getAnnotation(runtimeAnnotations, AjcMemberMaker.ASPECT_ANNOTATION);
  447. if (aspect != null) {
  448. // semantic check for inheritance (only one level up)
  449. boolean extendsAspect = false;
  450. if (!"java.lang.Object".equals(struct.enclosingType.getSuperclass().getName())) {
  451. if (!struct.enclosingType.getSuperclass().isAbstract() && struct.enclosingType.getSuperclass().isAspect()) {
  452. reportError("cannot extend a concrete aspect", struct);
  453. return false;
  454. }
  455. extendsAspect = struct.enclosingType.getSuperclass().isAspect();
  456. }
  457. ElementNameValuePair aspectPerClause = getAnnotationElement(aspect, VALUE);
  458. final PerClause perClause;
  459. if (aspectPerClause == null) {
  460. // empty value means singleton unless inherited
  461. if (!extendsAspect) {
  462. perClause = new PerSingleton();
  463. } else {
  464. perClause = new PerFromSuper(struct.enclosingType.getSuperclass().getPerClause().getKind());
  465. }
  466. } else {
  467. String perX = aspectPerClause.getValue().stringifyValue();
  468. if (perX == null || perX.length() <= 0) {
  469. perClause = new PerSingleton();
  470. } else {
  471. perClause = parsePerClausePointcut(perX, struct);
  472. }
  473. }
  474. if (perClause == null) {
  475. // could not parse it, ignore the aspect
  476. return false;
  477. } else {
  478. perClause.setLocation(struct.context, -1,-1);//struct.context.getOffset(), struct.context.getOffset()+1);//FIXME AVASM
  479. // FIXME asc see related comment way about about the version...
  480. struct.ajAttributes.add(new AjAttribute.WeaverVersionInfo());
  481. AjAttribute.Aspect aspectAttribute = new AjAttribute.Aspect(perClause);
  482. struct.ajAttributes.add(aspectAttribute);
  483. FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0];
  484. final IScope binding;
  485. binding = new BindingScope(
  486. struct.enclosingType,
  487. struct.context,
  488. bindings
  489. );
  490. // // we can't resolve here since the perclause typically refers to pointcuts
  491. // // defined in the aspect that we haven't told the BcelObjectType about yet.
  492. //
  493. // perClause.resolve(binding);
  494. // so we prepare to do it later...
  495. aspectAttribute.setResolutionScope(binding);
  496. return true;
  497. }
  498. }
  499. return false;
  500. }
  501. /**
  502. * Read a perClause, returns null on failure and issue messages
  503. *
  504. * @param perClauseString like "pertarget(.....)"
  505. * @param struct for which we are parsing the per clause
  506. * @return a PerClause instance
  507. */
  508. private static PerClause parsePerClausePointcut(String perClauseString, AjAttributeStruct struct) {
  509. final String pointcutString;
  510. Pointcut pointcut = null;
  511. TypePattern typePattern = null;
  512. final PerClause perClause;
  513. if (perClauseString.startsWith(PerClause.KindAnnotationPrefix.PERCFLOW.getName())) {
  514. pointcutString = PerClause.KindAnnotationPrefix.PERCFLOW.extractPointcut(perClauseString);
  515. pointcut = parsePointcut(pointcutString, struct, false);
  516. perClause = new PerCflow(pointcut, false);
  517. } else if (perClauseString.startsWith(PerClause.KindAnnotationPrefix.PERCFLOWBELOW.getName())) {
  518. pointcutString = PerClause.KindAnnotationPrefix.PERCFLOWBELOW.extractPointcut(perClauseString);
  519. pointcut = parsePointcut(pointcutString, struct, false);
  520. perClause = new PerCflow(pointcut, true);
  521. } else if (perClauseString.startsWith(PerClause.KindAnnotationPrefix.PERTARGET.getName())) {
  522. pointcutString = PerClause.KindAnnotationPrefix.PERTARGET.extractPointcut(perClauseString);
  523. pointcut = parsePointcut(pointcutString, struct, false);
  524. perClause = new PerObject(pointcut, false);
  525. } else if (perClauseString.startsWith(PerClause.KindAnnotationPrefix.PERTHIS.getName())) {
  526. pointcutString = PerClause.KindAnnotationPrefix.PERTHIS.extractPointcut(perClauseString);
  527. pointcut = parsePointcut(pointcutString, struct, false);
  528. perClause = new PerObject(pointcut, true);
  529. } else if (perClauseString.startsWith(PerClause.KindAnnotationPrefix.PERTYPEWITHIN.getName())) {
  530. pointcutString = PerClause.KindAnnotationPrefix.PERTYPEWITHIN.extractPointcut(perClauseString);
  531. typePattern = parseTypePattern(pointcutString, struct);
  532. perClause = new PerTypeWithin(typePattern);
  533. } else if (perClauseString.equalsIgnoreCase(PerClause.SINGLETON.getName() + "()")) {
  534. perClause = new PerSingleton();
  535. } else {
  536. // could not parse the @AJ perclause - fallback to singleton and issue an error
  537. reportError("@Aspect per clause cannot be read '" + perClauseString + "'", struct);
  538. return null;
  539. }
  540. if (!PerClause.SINGLETON.equals(perClause.getKind())
  541. && !PerClause.PERTYPEWITHIN.equals(perClause.getKind())
  542. && pointcut == null) {
  543. // we could not parse the pointcut
  544. return null;
  545. }
  546. if (PerClause.PERTYPEWITHIN.equals(perClause.getKind()) && typePattern == null) {
  547. // we could not parse the type pattern
  548. return null;
  549. }
  550. return perClause;
  551. }
  552. /**
  553. * Read @DeclarePrecedence
  554. *
  555. * @param runtimeAnnotations
  556. * @param struct
  557. * @return true if found
  558. */
  559. private static boolean handlePrecedenceAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeStruct struct) {
  560. Annotation aspect = getAnnotation(runtimeAnnotations, AjcMemberMaker.DECLAREPRECEDENCE_ANNOTATION);
  561. if (aspect != null) {
  562. ElementNameValuePair precedence = getAnnotationElement(aspect, VALUE);
  563. if (precedence != null) {
  564. String precedencePattern = precedence.getValue().stringifyValue();
  565. PatternParser parser = new PatternParser(precedencePattern);
  566. DeclarePrecedence ajPrecedence = parser.parseDominates();
  567. struct.ajAttributes.add(new AjAttribute.DeclareAttribute(ajPrecedence));
  568. return true;
  569. }
  570. }
  571. return false;
  572. }
  573. // /**
  574. // * Read @DeclareImplements
  575. // *
  576. // * @param runtimeAnnotations
  577. // * @param struct
  578. // * @return true if found
  579. // */
  580. // private static boolean handleDeclareImplementsAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeFieldStruct struct) {//, ResolvedPointcutDefinition preResolvedPointcut) {
  581. // Annotation deci = getAnnotation(runtimeAnnotations, AjcMemberMaker.DECLAREIMPLEMENTS_ANNOTATION);
  582. // if (deci != null) {
  583. // ElementNameValuePair deciPatternNVP = getAnnotationElement(deci, VALUE);
  584. // String deciPattern = deciPatternNVP.getValue().stringifyValue();
  585. // if (deciPattern != null) {
  586. // TypePattern typePattern = parseTypePattern(deciPattern, struct);
  587. // ResolvedType fieldType = UnresolvedType.forSignature(struct.field.getSignature()).resolve(struct.enclosingType.getWorld());
  588. // if (fieldType.isPrimitiveType()) {
  589. // return false;
  590. // } else if (fieldType.isInterface()) {
  591. // TypePattern parent = new ExactTypePattern(UnresolvedType.forSignature(struct.field.getSignature()), false, false);
  592. // parent.resolve(struct.enclosingType.getWorld());
  593. // List parents = new ArrayList(1);
  594. // parents.add(parent);
  595. // //TODO kick ISourceLocation sl = struct.bField.getSourceLocation(); ??
  596. // struct.ajAttributes.add(
  597. // new AjAttribute.DeclareAttribute(
  598. // new DeclareParents(
  599. // typePattern,
  600. // parents,
  601. // false
  602. // )
  603. // )
  604. // );
  605. // return true;
  606. // } else {
  607. // reportError("@DeclareImplements: can only be used on field whose type is an interface", struct);
  608. // return false;
  609. // }
  610. // }
  611. // }
  612. // return false;
  613. // }
  614. /**
  615. * Read @DeclareParents
  616. *
  617. * @param runtimeAnnotations
  618. * @param struct
  619. * @return true if found
  620. */
  621. private static boolean handleDeclareParentsAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeFieldStruct struct) {//, ResolvedPointcutDefinition preResolvedPointcut) {
  622. Annotation decp = getAnnotation(runtimeAnnotations, AjcMemberMaker.DECLAREPARENTS_ANNOTATION);
  623. if (decp != null) {
  624. ElementNameValuePair decpPatternNVP = getAnnotationElement(decp, VALUE);
  625. String decpPattern = decpPatternNVP.getValue().stringifyValue();
  626. if (decpPattern != null) {
  627. TypePattern typePattern = parseTypePattern(decpPattern, struct);
  628. ResolvedType fieldType = UnresolvedType.forSignature(struct.field.getSignature()).resolve(struct.enclosingType.getWorld());
  629. if (fieldType.isInterface()) {
  630. TypePattern parent = parseTypePattern(fieldType.getName(),struct);
  631. FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0];
  632. IScope binding = new BindingScope(struct.enclosingType,struct.context,bindings);
  633. // first add the declare implements like
  634. List parents = new ArrayList(1); parents.add(parent);
  635. DeclareParents dp = new DeclareParents(typePattern,parents,false);
  636. dp.resolve(binding); // resolves the parent and child parts of the decp
  637. // resolve this so that we can use it for the MethodDelegateMungers below.
  638. // eg. '@Coloured *' will change from a WildTypePattern to an 'AnyWithAnnotationTypePattern' after this resolution
  639. typePattern = typePattern.resolveBindings(binding, Bindings.NONE, false, false);
  640. //TODO kick ISourceLocation sl = struct.bField.getSourceLocation(); ??
  641. // dp.setLocation(dp.getDeclaringType().getSourceContext(), dp.getDeclaringType().getSourceLocation().getOffset(), dp.getDeclaringType().getSourceLocation().getOffset());
  642. dp.setLocation(struct.context,-1,-1); // not ideal...
  643. struct.ajAttributes.add(new AjAttribute.DeclareAttribute(dp));
  644. // do we have a defaultImpl=xxx.class (ie implementation)
  645. String defaultImplClassName = null;
  646. ElementNameValuePair defaultImplNVP = getAnnotationElement(decp, "defaultImpl");
  647. if (defaultImplNVP != null) {
  648. ClassElementValue defaultImpl = (ClassElementValue) defaultImplNVP.getValue();
  649. defaultImplClassName = UnresolvedType.forSignature(defaultImpl.getClassString()).getName();
  650. if (defaultImplClassName.equals("org.aspectj.lang.annotation.DeclareParents")) {
  651. defaultImplClassName = null;
  652. } else {
  653. // check public no arg ctor
  654. ResolvedType impl = struct.enclosingType.getWorld().resolve(
  655. defaultImplClassName,
  656. false
  657. );
  658. ResolvedMember[] mm = impl.getDeclaredMethods();
  659. boolean hasNoCtorOrANoArgOne = true;
  660. for (int i = 0; i < mm.length; i++) {
  661. ResolvedMember resolvedMember = mm[i];
  662. if (resolvedMember.getName().equals("<init>")) {
  663. hasNoCtorOrANoArgOne = false;
  664. if (resolvedMember.getParameterTypes().length == 0
  665. && resolvedMember.isPublic()) {
  666. hasNoCtorOrANoArgOne = true;
  667. }
  668. }
  669. if (hasNoCtorOrANoArgOne) {
  670. break;
  671. }
  672. }
  673. if (!hasNoCtorOrANoArgOne) {
  674. reportError("@DeclareParents: defaultImpl=\""
  675. + defaultImplClassName
  676. + "\" has no public no-arg constructor", struct);
  677. }
  678. if (!fieldType.isAssignableFrom(impl)) {
  679. reportError("@DeclareParents: defaultImpl=\""+defaultImplClassName+"\" does not implement the interface '"+fieldType.toString()+"'",struct);
  680. }
  681. }
  682. }
  683. // then iterate on field interface hierarchy (not object)
  684. boolean hasAtLeastOneMethod = false;
  685. ResolvedMember[] methods = (ResolvedMember[])fieldType.getMethodsWithoutIterator(true, false).toArray(new ResolvedMember[0]);
  686. for (int i = 0; i < methods.length; i++) {
  687. ResolvedMember method = (ResolvedMember)methods[i];
  688. if (method.isAbstract()) {
  689. if (defaultImplClassName == null) {
  690. // non marker interface with no default impl provided
  691. reportError("@DeclareParents: used with a non marker interface and no defaultImpl=\"...\" provided", struct);
  692. return false;
  693. }
  694. hasAtLeastOneMethod = true;
  695. struct.ajAttributes.add(
  696. new AjAttribute.TypeMunger(
  697. new MethodDelegateTypeMunger(
  698. method,
  699. struct.enclosingType,
  700. defaultImplClassName,
  701. typePattern
  702. )
  703. )
  704. );
  705. }
  706. }
  707. // successfull so far, we thus need a bcel type munger to have
  708. // a field hosting the mixin in the target type
  709. if (hasAtLeastOneMethod) {
  710. struct.ajAttributes.add(
  711. new AjAttribute.TypeMunger(
  712. new MethodDelegateTypeMunger.FieldHostTypeMunger(
  713. AjcMemberMaker.itdAtDeclareParentsField(
  714. null,//prototyped
  715. fieldType,
  716. struct.enclosingType
  717. ),
  718. struct.enclosingType,
  719. typePattern
  720. )
  721. )
  722. );
  723. }
  724. return true;
  725. } else {
  726. reportError("@DeclareParents: can only be used on a field whose type is an interface", struct);
  727. return false;
  728. }
  729. }
  730. }
  731. return false;
  732. }
  733. /**
  734. * Read @Before
  735. *
  736. * @param runtimeAnnotations
  737. * @param struct
  738. * @return true if found
  739. */
  740. private static boolean handleBeforeAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeMethodStruct struct, ResolvedPointcutDefinition preResolvedPointcut) {
  741. Annotation before = getAnnotation(runtimeAnnotations, AjcMemberMaker.BEFORE_ANNOTATION);
  742. if (before != null) {
  743. ElementNameValuePair beforeAdvice = getAnnotationElement(before, VALUE);
  744. if (beforeAdvice != 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. //pc.resolve(binding);
  763. } else {
  764. pc = parsePointcut(beforeAdvice.getValue().stringifyValue(), struct, false);
  765. if (pc == null) return false;//parse error
  766. pc = pc.resolve(binding);
  767. }
  768. setIgnoreUnboundBindingNames(pc, bindings);
  769. ISourceLocation sl = struct.context.makeSourceLocation(struct.bMethod.getDeclarationLineNumber(), struct.bMethod.getDeclarationOffset());
  770. struct.ajAttributes.add(
  771. new AjAttribute.AdviceAttribute(
  772. AdviceKind.Before,
  773. pc,
  774. extraArgument,
  775. sl.getOffset(),
  776. sl.getOffset()+1,//FIXME AVASM
  777. struct.context
  778. )
  779. );
  780. return true;
  781. }
  782. }
  783. return false;
  784. }
  785. /**
  786. * Read @After
  787. *
  788. * @param runtimeAnnotations
  789. * @param struct
  790. * @return true if found
  791. */
  792. private static boolean handleAfterAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeMethodStruct struct, ResolvedPointcutDefinition preResolvedPointcut) {
  793. Annotation after = getAnnotation(runtimeAnnotations, AjcMemberMaker.AFTER_ANNOTATION);
  794. if (after != null) {
  795. ElementNameValuePair afterAdvice = getAnnotationElement(after, VALUE);
  796. if (afterAdvice != null) {
  797. // this/target/args binding
  798. FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0];
  799. try {
  800. bindings = extractBindings(struct);
  801. } catch (UnreadableDebugInfoException unreadableDebugInfoException) {
  802. return false;
  803. }
  804. IScope binding = new BindingScope(
  805. struct.enclosingType,
  806. struct.context,
  807. bindings
  808. );
  809. // joinpoint, staticJoinpoint binding
  810. int extraArgument = extractExtraArgument(struct.method);
  811. Pointcut pc = null;
  812. if (preResolvedPointcut != null) {
  813. pc = preResolvedPointcut.getPointcut();
  814. } else {
  815. pc = parsePointcut(afterAdvice.getValue().stringifyValue(), struct, false);
  816. if (pc == null) return false;//parse error
  817. pc.resolve(binding);
  818. }
  819. setIgnoreUnboundBindingNames(pc, bindings);
  820. ISourceLocation sl = struct.context.makeSourceLocation(struct.bMethod.getDeclarationLineNumber(), struct.bMethod.getDeclarationOffset());
  821. struct.ajAttributes.add(
  822. new AjAttribute.AdviceAttribute(
  823. AdviceKind.After,
  824. pc,
  825. extraArgument,
  826. sl.getOffset(),
  827. sl.getOffset()+1,//FIXME AVASM
  828. struct.context
  829. )
  830. );
  831. return true;
  832. }
  833. }
  834. return false;
  835. }
  836. /**
  837. * Read @AfterReturning
  838. *
  839. * @param runtimeAnnotations
  840. * @param struct
  841. * @return true if found
  842. */
  843. private static boolean handleAfterReturningAnnotation(
  844. RuntimeAnnotations runtimeAnnotations,
  845. AjAttributeMethodStruct struct,
  846. ResolvedPointcutDefinition preResolvedPointcut,
  847. BcelMethod owningMethod)
  848. throws ReturningFormalNotDeclaredInAdviceSignatureException
  849. {
  850. Annotation after = getAnnotation(runtimeAnnotations, AjcMemberMaker.AFTERRETURNING_ANNOTATION);
  851. if (after != null) {
  852. ElementNameValuePair annValue = getAnnotationElement(after, VALUE);
  853. ElementNameValuePair annPointcut = getAnnotationElement(after, POINTCUT);
  854. ElementNameValuePair annReturned = getAnnotationElement(after, RETURNING);
  855. // extract the pointcut and returned type/binding - do some checks
  856. String pointcut = null;
  857. String returned = null;
  858. if ((annValue != null && annPointcut != null) || (annValue == null && annPointcut == null)) {
  859. reportError("@AfterReturning: either 'value' or 'poincut' must be provided, not both", struct);
  860. return false;
  861. }
  862. if (annValue != null) {
  863. pointcut = annValue.getValue().stringifyValue();
  864. } else {
  865. pointcut = annPointcut.getValue().stringifyValue();
  866. }
  867. if (isNullOrEmpty(pointcut)) {
  868. reportError("@AfterReturning: either 'value' or 'poincut' must be provided, not both", struct);
  869. return false;
  870. }
  871. if (annReturned != null) {
  872. returned = annReturned.getValue().stringifyValue();
  873. if (isNullOrEmpty(returned)) {
  874. returned = null;
  875. } else {
  876. // check that thrownFormal exists as the last parameter in the advice
  877. String[] pNames = owningMethod.getParameterNames();
  878. if (pNames == null || pNames.length == 0 || !Arrays.asList(pNames).contains(returned)) {
  879. throw new ReturningFormalNotDeclaredInAdviceSignatureException(returned);
  880. }
  881. }
  882. }
  883. // this/target/args binding
  884. // exclude the return binding from the pointcut binding since it is an extraArg binding
  885. FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0];
  886. try {
  887. bindings = (returned == null ? extractBindings(struct) : extractBindings(struct, returned));
  888. } catch (UnreadableDebugInfoException unreadableDebugInfoException) {
  889. return false;
  890. }
  891. IScope binding = new BindingScope(
  892. struct.enclosingType,
  893. struct.context,
  894. bindings
  895. );
  896. // joinpoint, staticJoinpoint binding
  897. int extraArgument = extractExtraArgument(struct.method);
  898. // return binding
  899. if (returned != null) {
  900. extraArgument |= Advice.ExtraArgument;
  901. }
  902. Pointcut pc = null;
  903. if (preResolvedPointcut != null) {
  904. pc = preResolvedPointcut.getPointcut();
  905. } else {
  906. pc = parsePointcut(pointcut, struct, false);
  907. if (pc == null) return false;//parse error
  908. pc.resolve(binding);
  909. }
  910. setIgnoreUnboundBindingNames(pc, bindings);
  911. ISourceLocation sl = struct.context.makeSourceLocation(struct.bMethod.getDeclarationLineNumber(), struct.bMethod.getDeclarationOffset());
  912. struct.ajAttributes.add(
  913. new AjAttribute.AdviceAttribute(
  914. AdviceKind.AfterReturning,
  915. pc,
  916. extraArgument,
  917. sl.getOffset(),
  918. sl.getOffset()+1,//FIXME AVASM
  919. struct.context
  920. )
  921. );
  922. return true;
  923. }
  924. return false;
  925. }
  926. /**
  927. * Read @AfterThrowing
  928. *
  929. * @param runtimeAnnotations
  930. * @param struct
  931. * @return true if found
  932. */
  933. private static boolean handleAfterThrowingAnnotation(
  934. RuntimeAnnotations runtimeAnnotations,
  935. AjAttributeMethodStruct struct,
  936. ResolvedPointcutDefinition preResolvedPointcut,
  937. BcelMethod owningMethod)
  938. throws ThrownFormalNotDeclaredInAdviceSignatureException
  939. {
  940. Annotation after = getAnnotation(runtimeAnnotations, AjcMemberMaker.AFTERTHROWING_ANNOTATION);
  941. if (after != null) {
  942. ElementNameValuePair annValue = getAnnotationElement(after, VALUE);
  943. ElementNameValuePair annPointcut = getAnnotationElement(after, POINTCUT);
  944. ElementNameValuePair annThrown = getAnnotationElement(after, THROWING);
  945. // extract the pointcut and throwned type/binding - do some checks
  946. String pointcut = null;
  947. String thrownFormal = null;
  948. if ((annValue != null && annPointcut != null) || (annValue == null && annPointcut == null)) {
  949. reportError("@AfterThrowing: either 'value' or 'poincut' must be provided, not both", struct);
  950. return false;
  951. }
  952. if (annValue != null) {
  953. pointcut = annValue.getValue().stringifyValue();
  954. } else {
  955. pointcut = annPointcut.getValue().stringifyValue();
  956. }
  957. if (isNullOrEmpty(pointcut)) {
  958. reportError("@AfterThrowing: either 'value' or 'poincut' must be provided, not both", struct);
  959. return false;
  960. }
  961. if (annThrown != null) {
  962. thrownFormal = annThrown.getValue().stringifyValue();
  963. if (isNullOrEmpty(thrownFormal)) {
  964. thrownFormal = null;
  965. } else {
  966. // check that thrownFormal exists as the last parameter in the advice
  967. String[] pNames = owningMethod.getParameterNames();
  968. if (pNames == null || pNames.length == 0 || !Arrays.asList(pNames).contains(thrownFormal)) {
  969. throw new ThrownFormalNotDeclaredInAdviceSignatureException(thrownFormal);
  970. }
  971. }
  972. }
  973. // this/target/args binding
  974. // exclude the throwned binding from the pointcut binding since it is an extraArg binding
  975. FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0];
  976. try {
  977. bindings = (thrownFormal == null ? extractBindings(struct) : extractBindings(struct, thrownFormal));
  978. } catch (UnreadableDebugInfoException unreadableDebugInfoException) {
  979. return false;
  980. }
  981. IScope binding = new BindingScope(
  982. struct.enclosingType,
  983. struct.context,
  984. bindings
  985. );
  986. // joinpoint, staticJoinpoint binding
  987. int extraArgument = extractExtraArgument(struct.method);
  988. // return binding
  989. if (thrownFormal != null) {
  990. extraArgument |= Advice.ExtraArgument;
  991. }
  992. Pointcut pc = null;
  993. if (preResolvedPointcut != null) {
  994. pc = preResolvedPointcut.getPointcut();
  995. } else {
  996. pc = parsePointcut(pointcut, struct, false);
  997. if (pc == null) return false;//parse error
  998. pc.resolve(binding);
  999. }
  1000. setIgnoreUnboundBindingNames(pc, bindings);
  1001. ISourceLocation sl = struct.context.makeSourceLocation(struct.bMethod.getDeclarationLineNumber(), struct.bMethod.getDeclarationOffset());
  1002. struct.ajAttributes.add(
  1003. new AjAttribute.AdviceAttribute(
  1004. AdviceKind.AfterThrowing,
  1005. pc,
  1006. extraArgument,
  1007. sl.getOffset(),
  1008. sl.getOffset()+1,//FIXME AVASM
  1009. struct.context
  1010. )
  1011. );
  1012. return true;
  1013. }
  1014. return false;
  1015. }
  1016. /**
  1017. * Read @Around
  1018. *
  1019. * @param runtimeAnnotations
  1020. * @param struct
  1021. * @return true if found
  1022. */
  1023. private static boolean handleAroundAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeMethodStruct struct, ResolvedPointcutDefinition preResolvedPointcut) {
  1024. Annotation around = getAnnotation(runtimeAnnotations, AjcMemberMaker.AROUND_ANNOTATION);
  1025. if (around != null) {
  1026. ElementNameValuePair aroundAdvice = getAnnotationElement(around, VALUE);
  1027. if (aroundAdvice != null) {
  1028. // this/target/args binding
  1029. FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0];
  1030. try {
  1031. bindings = extractBindings(struct);
  1032. } catch (UnreadableDebugInfoException unreadableDebugInfoException) {
  1033. return false;
  1034. }
  1035. IScope binding = new BindingScope(
  1036. struct.enclosingType,
  1037. struct.context,
  1038. bindings
  1039. );
  1040. // joinpoint, staticJoinpoint binding
  1041. int extraArgument = extractExtraArgument(struct.method);
  1042. Pointcut pc = null;
  1043. if (preResolvedPointcut != null) {
  1044. pc = preResolvedPointcut.getPointcut();
  1045. } else {
  1046. pc = parsePointcut(aroundAdvice.getValue().stringifyValue(), struct, false);
  1047. if (pc == null) return false;//parse error
  1048. pc.resolve(binding);
  1049. }
  1050. setIgnoreUnboundBindingNames(pc, bindings);
  1051. ISourceLocation sl = struct.context.makeSourceLocation(struct.bMethod.getDeclarationLineNumber(), struct.bMethod.getDeclarationOffset());
  1052. struct.ajAttributes.add(
  1053. new AjAttribute.AdviceAttribute(
  1054. AdviceKind.Around,
  1055. pc,
  1056. extraArgument,
  1057. sl.getOffset(),
  1058. sl.getOffset()+1,//FIXME AVASM
  1059. struct.context
  1060. )
  1061. );
  1062. return true;
  1063. }
  1064. }
  1065. return false;
  1066. }
  1067. /**
  1068. * Read @Pointcut and handle the resolving in a lazy way to deal with pointcut references
  1069. *
  1070. * @param runtimeAnnotations
  1071. * @param struct
  1072. */
  1073. private static void handlePointcutAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeMethodStruct struct) {
  1074. Annotation pointcut = getAnnotation(runtimeAnnotations, AjcMemberMaker.POINTCUT_ANNOTATION);
  1075. if (pointcut != null) {
  1076. ElementNameValuePair pointcutExpr = getAnnotationElement(pointcut, VALUE);
  1077. // semantic check: the method must return void, or be "public static boolean" for if() support
  1078. if (!(Type.VOID.equals(struct.method.getReturnType())
  1079. || (Type.BOOLEAN.equals(struct.method.getReturnType()) && struct.method.isStatic() && struct.method.isPublic()))) {
  1080. reportWarning("Found @Pointcut on a method not returning 'void' or not 'public static boolean'", struct);
  1081. ;//no need to stop
  1082. }
  1083. // semantic check: the method must not throw anything
  1084. if (struct.method.getExceptionTable() != null) {
  1085. reportWarning("Found @Pointcut on a method throwing exception", struct);
  1086. ;// no need to stop
  1087. }
  1088. // this/target/args binding
  1089. final IScope binding;
  1090. try {
  1091. binding = new BindingScope(
  1092. struct.enclosingType,
  1093. struct.context,
  1094. extractBindings(struct)
  1095. );
  1096. } catch (UnreadableDebugInfoException e) {
  1097. return;
  1098. }
  1099. UnresolvedType[] argumentTypes = new UnresolvedType[struct.method.getArgumentTypes().length];
  1100. for (int i = 0; i < argumentTypes.length; i++) {
  1101. argumentTypes[i] = UnresolvedType.forSignature(struct.method.getArgumentTypes()[i].getSignature());
  1102. }
  1103. Pointcut pc = null;
  1104. if (struct.method.isAbstract()) {
  1105. if ((pointcutExpr != null && isNullOrEmpty(pointcutExpr.getValue().stringifyValue()))
  1106. || pointcutExpr == null) {
  1107. // abstract pointcut
  1108. // leave pc = null
  1109. } else {
  1110. reportError("Found defined @Pointcut on an abstract method", struct);
  1111. return;//stop
  1112. }
  1113. } else {
  1114. if (pointcutExpr==null || (pointcutExpr != null && isNullOrEmpty(pointcutExpr.getValue().stringifyValue()))) {
  1115. // the matches nothing pointcut (125475/125480) - perhaps not as cleanly supported as it could be.
  1116. } else {
  1117. if (pointcutExpr != null) {
  1118. // use a LazyResolvedPointcutDefinition so that the pointcut is resolved lazily
  1119. // since for it to be resolved, we will need other pointcuts to be registered as well
  1120. pc = parsePointcut(pointcutExpr.getValue().stringifyValue(), struct, true);
  1121. if (pc == null) return;//parse error
  1122. pc.setLocation(struct.context, -1, -1);//FIXME AVASM !! bMethod is null here..
  1123. } else {
  1124. reportError("Found undefined @Pointcut on a non-abstract method", struct);
  1125. return;
  1126. }
  1127. }
  1128. }
  1129. // do not resolve binding now but lazily
  1130. struct.ajAttributes.add(
  1131. new AjAttribute.PointcutDeclarationAttribute(
  1132. new LazyResolvedPointcutDefinition(
  1133. struct.enclosingType,
  1134. struct.method.getModifiers(),
  1135. struct.method.getName(),
  1136. argumentTypes,
  1137. UnresolvedType.forSignature(struct.method.getReturnType().getSignature()),
  1138. pc,//can be null for abstract pointcut
  1139. binding
  1140. )
  1141. )
  1142. );
  1143. }
  1144. }
  1145. /**
  1146. * Read @DeclareError, @DeclareWarning
  1147. *
  1148. * @param runtimeAnnotations
  1149. * @param struct
  1150. * @return true if found
  1151. */
  1152. private static boolean handleDeclareErrorOrWarningAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeFieldStruct struct) {
  1153. Annotation error = getAnnotation(runtimeAnnotations, AjcMemberMaker.DECLAREERROR_ANNOTATION);
  1154. boolean hasError = false;
  1155. if (error != null) {
  1156. ElementNameValuePair declareError = getAnnotationElement(error, VALUE);
  1157. if (declareError != null) {
  1158. if (!STRING_DESC.equals(struct.field.getSignature()) || struct.field.getConstantValue() == null) {
  1159. reportError("@DeclareError used on a non String constant field", struct);
  1160. return false;
  1161. }
  1162. Pointcut pc = parsePointcut(declareError.getValue().stringifyValue(), struct, false);
  1163. if (pc == null) {
  1164. hasError = false;//cannot parse pointcut
  1165. } else {
  1166. DeclareErrorOrWarning deow = new DeclareErrorOrWarning(true, pc, struct.field.getConstantValue().toString());
  1167. setDeclareErrorOrWarningLocation(deow,struct);
  1168. struct.ajAttributes.add(new AjAttribute.DeclareAttribute(deow));
  1169. hasError = true;
  1170. }
  1171. }
  1172. }
  1173. Annotation warning = getAnnotation(runtimeAnnotations, AjcMemberMaker.DECLAREWARNING_ANNOTATION);
  1174. boolean hasWarning = false;
  1175. if (warning != null) {
  1176. ElementNameValuePair declareWarning = getAnnotationElement(warning, VALUE);
  1177. if (declareWarning != null) {
  1178. if (!STRING_DESC.equals(struct.field.getSignature()) || struct.field.getConstantValue() == null) {
  1179. reportError("@DeclareWarning used on a non String constant field", struct);
  1180. return false;
  1181. }
  1182. Pointcut pc = parsePointcut(declareWarning.getValue().stringifyValue(), struct, false);
  1183. if (pc == null) {
  1184. hasWarning = false;//cannot parse pointcut
  1185. } else {
  1186. DeclareErrorOrWarning deow = new DeclareErrorOrWarning(false, pc, struct.field.getConstantValue().toString());
  1187. setDeclareErrorOrWarningLocation(deow,struct);
  1188. struct.ajAttributes.add(new AjAttribute.DeclareAttribute(deow));
  1189. return hasWarning = true;
  1190. }
  1191. }
  1192. }
  1193. return hasError || hasWarning;
  1194. }
  1195. /**
  1196. * Sets the location for the declare error / warning using the corresponding
  1197. * IProgramElement in the structure model. This will only fix bug 120356 if
  1198. * compiled with -emacssym, however, it does mean that the cross references
  1199. * view in AJDT will show the correct information.
  1200. *
  1201. * Other possibilities for fix:
  1202. * 1. using the information in ajcDeclareSoft (if this is set correctly)
  1203. * which will fix the problem if compiled with ajc but not if compiled
  1204. * with javac.
  1205. * 2. creating an AjAttribute called FieldDeclarationLineNumberAttribute
  1206. * (much like MethodDeclarationLineNumberAttribute) which we can ask
  1207. * for the offset. This will again only fix bug 120356 when compiled
  1208. * with ajc.
  1209. *
  1210. * @param deow
  1211. * @param struct
  1212. */
  1213. private static void setDeclareErrorOrWarningLocation(DeclareErrorOrWarning deow, AjAttributeFieldStruct struct) {
  1214. IHierarchy top = AsmManager.getDefault().getHierarchy();
  1215. if (top.getRoot() != null) {
  1216. IProgramElement ipe = top.findElementForLabel(top.getRoot(),
  1217. IProgramElement.Kind.FIELD,struct.field.getName());
  1218. if (ipe != null && ipe.getSourceLocation() != null) {
  1219. ISourceLocation sourceLocation = ipe.getSourceLocation();
  1220. int start = sourceLocation.getOffset();
  1221. int end = start + struct.field.getName().length();
  1222. deow.setLocation(struct.context,start,end);
  1223. return;
  1224. }
  1225. }
  1226. deow.setLocation(struct.context, -1, -1);
  1227. }
  1228. /**
  1229. * Returns a readable representation of a method.
  1230. * Method.toString() is not suitable.
  1231. *
  1232. * @param method
  1233. * @return a readable representation of a method
  1234. */
  1235. private static String methodToString(Method method) {
  1236. StringBuffer sb = new StringBuffer();
  1237. sb.append(method.getName());
  1238. sb.append(method.getSignature());
  1239. return sb.toString();
  1240. }
  1241. /**
  1242. * Returns a readable representation of a field.
  1243. * Field.toString() is not suitable.
  1244. *
  1245. * @param field
  1246. * @return a readable representation of a field
  1247. */
  1248. private static String fieldToString(Field field) {
  1249. StringBuffer sb = new StringBuffer();
  1250. sb.append(field.getName()).append(' ');
  1251. sb.append(field.getSignature());
  1252. return sb.toString();
  1253. }
  1254. /**
  1255. * Build the bindings for a given method (pointcut / advice)
  1256. *
  1257. * @param struct
  1258. * @return null if no debug info is available
  1259. */
  1260. private static FormalBinding[] extractBindings(AjAttributeMethodStruct struct)
  1261. throws UnreadableDebugInfoException {
  1262. Method method = struct.method;
  1263. String[] argumentNames = struct.getArgumentNames();
  1264. // assert debug info was here
  1265. if (argumentNames.length != method.getArgumentTypes().length) {
  1266. 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);
  1267. throw new UnreadableDebugInfoException();
  1268. }
  1269. List bindings = new ArrayList();
  1270. for (int i = 0; i < argumentNames.length; i++) {
  1271. String argumentName = argumentNames[i];
  1272. UnresolvedType argumentType = UnresolvedType.forSignature(method.getArgumentTypes()[i].getSignature());
  1273. // do not bind JoinPoint / StaticJoinPoint / EnclosingStaticJoinPoint
  1274. // TODO solve me : this means that the JP/SJP/ESJP cannot appear as binding
  1275. // f.e. when applying advice on advice etc
  1276. if ((AjcMemberMaker.TYPEX_JOINPOINT.equals(argumentType)
  1277. || AjcMemberMaker.TYPEX_PROCEEDINGJOINPOINT.equals(argumentType)
  1278. || AjcMemberMaker.TYPEX_STATICJOINPOINT.equals(argumentType)
  1279. || AjcMemberMaker.TYPEX_ENCLOSINGSTATICJOINPOINT.equals(argumentType)
  1280. || AjcMemberMaker.AROUND_CLOSURE_TYPE.equals(argumentType))) {
  1281. //continue;// skip
  1282. bindings.add(new FormalBinding.ImplicitFormalBinding(argumentType, argumentName, i));
  1283. } else {
  1284. bindings.add(new FormalBinding(argumentType, argumentName, i));
  1285. }
  1286. }
  1287. return (FormalBinding[]) bindings.toArray(new FormalBinding[]{});
  1288. }
  1289. //FIXME alex deal with exclude index
  1290. private static FormalBinding[] extractBindings(AjAttributeMethodStruct struct, String excludeFormal)
  1291. throws UnreadableDebugInfoException {
  1292. FormalBinding[] bindings = extractBindings(struct);
  1293. int excludeIndex = -1;
  1294. for (int i = 0; i < bindings.length; i++) {
  1295. FormalBinding binding = bindings[i];
  1296. if (binding.getName().equals(excludeFormal)) {
  1297. excludeIndex = i;
  1298. bindings[i] = new FormalBinding.ImplicitFormalBinding(
  1299. binding.getType(), binding.getName(), binding.getIndex()
  1300. );
  1301. break;
  1302. }
  1303. }
  1304. return bindings;
  1305. //
  1306. // if (excludeIndex >= 0) {
  1307. // FormalBinding[] bindingsFiltered = new FormalBinding[bindings.length-1];
  1308. // int k = 0;
  1309. // for (int i = 0; i < bindings.length; i++) {
  1310. // if (i == excludeIndex) {
  1311. // ;
  1312. // } else {
  1313. // bindingsFiltered[k] = new FormalBinding(bindings[i].getType(), bindings[i].getName(), k);
  1314. // k++;
  1315. // }
  1316. // }
  1317. // return bindingsFiltered;
  1318. // } else {
  1319. // return bindings;
  1320. // }
  1321. }
  1322. /**
  1323. * Compute the flag for the xxxJoinPoint extra argument
  1324. *
  1325. * @param method
  1326. * @return extra arg flag
  1327. */
  1328. private static int extractExtraArgument(Method method) {
  1329. Type[] methodArgs = method.getArgumentTypes();
  1330. String[] sigs = new String[methodArgs.length];
  1331. for (int i = 0; i < methodArgs.length; i++) {
  1332. sigs[i] = methodArgs[i].getSignature();
  1333. }
  1334. return extractExtraArgument(sigs);
  1335. }
  1336. /**
  1337. * Compute the flag for the xxxJoinPoint extra argument
  1338. *
  1339. * @param argumentSignatures
  1340. * @return extra arg flag
  1341. */
  1342. public static int extractExtraArgument(String[] argumentSignatures) {
  1343. int extraArgument = 0;
  1344. for (int i = 0; i < argumentSignatures.length; i++) {
  1345. if (AjcMemberMaker.TYPEX_JOINPOINT.getSignature().equals(argumentSignatures[i])) {
  1346. extraArgument |= Advice.ThisJoinPoint;
  1347. } else if (AjcMemberMaker.TYPEX_PROCEEDINGJOINPOINT.getSignature().equals(argumentSignatures[i])) {
  1348. extraArgument |= Advice.ThisJoinPoint;
  1349. } else if (AjcMemberMaker.TYPEX_STATICJOINPOINT.getSignature().equals(argumentSignatures[i])) {
  1350. extraArgument |= Advice.ThisJoinPointStaticPart;
  1351. } else if (AjcMemberMaker.TYPEX_ENCLOSINGSTATICJOINPOINT.getSignature().equals(argumentSignatures[i])) {
  1352. extraArgument |= Advice.ThisEnclosingJoinPointStaticPart;
  1353. }
  1354. }
  1355. return extraArgument;
  1356. }
  1357. /**
  1358. * Returns the runtime (RV/RIV) annotation of type annotationType or null if no such annotation
  1359. *
  1360. * @param rvs
  1361. * @param annotationType
  1362. * @return annotation
  1363. */
  1364. private static Annotation getAnnotation(RuntimeAnnotations rvs, UnresolvedType annotationType) {
  1365. final String annotationTypeName = annotationType.getName();
  1366. for (Iterator iterator = rvs.getAnnotations().iterator(); iterator.hasNext();) {
  1367. Annotation rv = (Annotation) iterator.next();
  1368. if (annotationTypeName.equals(rv.getTypeName())) {
  1369. return rv;
  1370. }
  1371. }
  1372. return null;
  1373. }
  1374. /**
  1375. * Returns the value of a given element of an annotation or null if not found
  1376. * Caution: Does not handles default value.
  1377. *
  1378. * @param annotation
  1379. * @param elementName
  1380. * @return annotation NVP
  1381. */
  1382. private static ElementNameValuePair getAnnotationElement(Annotation annotation, String elementName) {
  1383. for (Iterator iterator1 = annotation.getValues().iterator(); iterator1.hasNext();) {
  1384. ElementNameValuePair element = (ElementNameValuePair) iterator1.next();
  1385. if (elementName.equals(element.getNameString())) {
  1386. return element;
  1387. }
  1388. }
  1389. return null;
  1390. }
  1391. /**
  1392. * Extract the method argument names as in source from debug info
  1393. * returns an empty array upon inconsistency
  1394. *
  1395. * @param method
  1396. * @return method arg names as in source
  1397. */
  1398. private static String[] getMethodArgumentNamesAsInSource(Method method) {
  1399. if (method.getArgumentTypes().length == 0) {
  1400. return EMPTY_STRINGS;
  1401. }
  1402. final int startAtStackIndex = method.isStatic() ? 0 : 1;
  1403. final List arguments = new ArrayList();
  1404. LocalVariableTable lt = (LocalVariableTable) method.getLocalVariableTable();
  1405. if (lt != null) {
  1406. for (int j = 0; j < lt.getLocalVariableTable().length; j++) {
  1407. LocalVariable localVariable = lt.getLocalVariableTable()[j];
  1408. if (localVariable.getStartPC() == 0) {
  1409. if (localVariable.getIndex() >= startAtStackIndex) {
  1410. arguments.add(new MethodArgument(localVariable.getName(), localVariable.getIndex()));
  1411. }
  1412. }
  1413. }
  1414. }
  1415. if (arguments.size() != method.getArgumentTypes().length) {
  1416. return EMPTY_STRINGS;
  1417. }
  1418. // sort by index
  1419. Collections.sort(
  1420. arguments, new Comparator() {
  1421. public int compare(Object o, Object o1) {
  1422. MethodArgument mo = (MethodArgument) o;
  1423. MethodArgument mo1 = (MethodArgument) o1;
  1424. if (mo.indexOnStack == mo1.indexOnStack) {
  1425. return 0;
  1426. } else if (mo.indexOnStack > mo1.indexOnStack) {
  1427. return 1;
  1428. } else {
  1429. return -1;
  1430. }
  1431. }
  1432. }
  1433. );
  1434. String[] argumentNames = new String[arguments.size()];
  1435. int i = 0;
  1436. for (Iterator iterator = arguments.iterator(); iterator.hasNext(); i++) {
  1437. MethodArgument methodArgument = (MethodArgument) iterator.next();
  1438. argumentNames[i] = methodArgument.name;
  1439. }
  1440. return argumentNames;
  1441. }
  1442. /**
  1443. * A method argument, used for sorting by indexOnStack (ie order in signature)
  1444. *
  1445. * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
  1446. */
  1447. private static class MethodArgument {
  1448. String name;
  1449. int indexOnStack;
  1450. public MethodArgument(String name, int indexOnStack) {
  1451. this.name = name;
  1452. this.indexOnStack = indexOnStack;
  1453. }
  1454. }
  1455. /**
  1456. * BindingScope that knows the enclosingType, which is needed for pointcut reference resolution
  1457. *
  1458. * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
  1459. */
  1460. public static class BindingScope extends SimpleScope {
  1461. private ResolvedType m_enclosingType;
  1462. private ISourceContext m_sourceContext;
  1463. public BindingScope(ResolvedType type, ISourceContext sourceContext, FormalBinding[] bindings) {
  1464. super(type.getWorld(), bindings);
  1465. m_enclosingType = type;
  1466. m_sourceContext = sourceContext;
  1467. }
  1468. public ResolvedType getEnclosingType() {
  1469. return m_enclosingType;
  1470. }
  1471. public ISourceLocation makeSourceLocation(IHasPosition location) {
  1472. return m_sourceContext.makeSourceLocation(location);
  1473. }
  1474. public UnresolvedType lookupType(String name, IHasPosition location) {
  1475. // bug 126560
  1476. if (m_enclosingType != null) {
  1477. // add the package we're in to the list of imported
  1478. // prefixes so that we can find types in the same package
  1479. String pkgName = m_enclosingType.getPackageName();
  1480. if (pkgName != null && !pkgName.equals("")) {
  1481. String[] currentImports = getImportedPrefixes();
  1482. String[] newImports = new String[currentImports.length + 1];
  1483. for (int i = 0; i < currentImports.length; i++) {
  1484. newImports[i] = currentImports[i];
  1485. }
  1486. newImports[currentImports.length] = pkgName.concat(".");
  1487. setImportedPrefixes(newImports);
  1488. }
  1489. }
  1490. return super.lookupType(name,location);
  1491. }
  1492. }
  1493. /**
  1494. * LazyResolvedPointcutDefinition lazyly resolve the pointcut so that we have time to register all
  1495. * pointcut referenced before pointcut resolution happens
  1496. *
  1497. * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
  1498. */
  1499. public static class LazyResolvedPointcutDefinition extends ResolvedPointcutDefinition {
  1500. private Pointcut m_pointcutUnresolved;
  1501. private IScope m_binding;
  1502. private Pointcut m_lazyPointcut = null;
  1503. public LazyResolvedPointcutDefinition(ResolvedType declaringType, int modifiers, String name,
  1504. UnresolvedType[] parameterTypes, UnresolvedType returnType,
  1505. Pointcut pointcut, IScope binding) {
  1506. super(declaringType, modifiers, name, parameterTypes, returnType, null);
  1507. m_pointcutUnresolved = pointcut;
  1508. m_binding = binding;
  1509. }
  1510. public Pointcut getPointcut() {
  1511. if (m_lazyPointcut == null) {
  1512. m_lazyPointcut = m_pointcutUnresolved.resolve(m_binding);
  1513. m_lazyPointcut.copyLocationFrom(m_pointcutUnresolved);
  1514. }
  1515. return m_lazyPointcut;
  1516. }
  1517. }
  1518. /**
  1519. * Helper to test empty strings
  1520. *
  1521. * @param s
  1522. * @return true if empty or null
  1523. */
  1524. private static boolean isNullOrEmpty(String s) {
  1525. return (s == null || s.length() <= 0);
  1526. }
  1527. /**
  1528. * Set the pointcut bindings for which to ignore unbound issues, so that we can implicitly bind
  1529. * xxxJoinPoint for @AJ advices
  1530. *
  1531. * @param pointcut
  1532. * @param bindings
  1533. */
  1534. private static void setIgnoreUnboundBindingNames(Pointcut pointcut, FormalBinding[] bindings) {
  1535. // register ImplicitBindings as to be ignored since unbound
  1536. // TODO is it likely to fail in a bad way if f.e. this(jp) etc ?
  1537. List ignores = new ArrayList();
  1538. for (int i = 0; i < bindings.length; i++) {
  1539. FormalBinding formalBinding = bindings[i];
  1540. if (formalBinding instanceof FormalBinding.ImplicitFormalBinding) {
  1541. ignores.add(formalBinding.getName());
  1542. }
  1543. }
  1544. pointcut.m_ignoreUnboundBindingForNames = (String[]) ignores.toArray(new String[ignores.size()]);
  1545. }
  1546. /**
  1547. * A check exception when we cannot read debug info (needed for formal binding)
  1548. */
  1549. private static class UnreadableDebugInfoException extends Exception {
  1550. }
  1551. /**
  1552. * Report an error
  1553. *
  1554. * @param message
  1555. * @param location
  1556. */
  1557. private static void reportError(String message, AjAttributeStruct location) {
  1558. if (!location.handler.isIgnoring(IMessage.ERROR)) {
  1559. location.handler.handleMessage(
  1560. new Message(
  1561. message,
  1562. location.enclosingType.getSourceLocation(),
  1563. true
  1564. )
  1565. );
  1566. }
  1567. }
  1568. /**
  1569. * Report a warning
  1570. *
  1571. * @param message
  1572. * @param location
  1573. */
  1574. private static void reportWarning(String message, AjAttributeStruct location) {
  1575. if (!location.handler.isIgnoring(IMessage.WARNING)) {
  1576. location.handler.handleMessage(
  1577. new Message(
  1578. message,
  1579. location.enclosingType.getSourceLocation(),
  1580. false
  1581. )
  1582. );
  1583. }
  1584. }
  1585. /**
  1586. * Parse the given pointcut, return null on failure and issue an error
  1587. *
  1588. * @param pointcutString
  1589. * @param struct
  1590. * @param allowIf
  1591. * @return pointcut, unresolved
  1592. */
  1593. private static Pointcut parsePointcut(String pointcutString, AjAttributeStruct struct, boolean allowIf) {
  1594. try {
  1595. PatternParser parser = new PatternParser(pointcutString, struct.context);
  1596. Pointcut pointcut = parser.parsePointcut();
  1597. parser.checkEof();
  1598. pointcut.check(null,struct.enclosingType.getWorld());
  1599. if (!allowIf && pointcutString.indexOf("if()") >= 0 && hasIf(pointcut)) {
  1600. reportError("if() pointcut is not allowed at this pointcut location '" + pointcutString +"'", struct);
  1601. return null;
  1602. }
  1603. pointcut.setLocation(struct.context, -1, -1);//FIXME -1,-1 is not good enough
  1604. return pointcut;
  1605. } catch (ParserException e) {
  1606. reportError("Invalid pointcut '" + pointcutString + "': " + e.toString() +
  1607. (e.getLocation()==null?"":" at position "+e.getLocation().getStart()), struct);
  1608. throw e;
  1609. // return null;
  1610. }
  1611. }
  1612. private static boolean hasIf(Pointcut pointcut) {
  1613. IfFinder visitor = new IfFinder();
  1614. pointcut.accept(visitor, null);
  1615. return visitor.hasIf;
  1616. }
  1617. /**
  1618. * Parse the given type pattern, return null on failure and issue an error
  1619. *
  1620. * @param patternString
  1621. * @param location
  1622. * @return type pattern
  1623. */
  1624. private static TypePattern parseTypePattern(String patternString, AjAttributeStruct location) {
  1625. try {
  1626. TypePattern typePattern = new PatternParser(patternString).parseTypePattern();
  1627. typePattern.setLocation(location.context, -1, -1);//FIXME -1,-1 is not good enough
  1628. return typePattern;
  1629. } catch (ParserException e) {
  1630. reportError("Invalid type pattern'" + patternString + "' : " + e.getLocation(), location);
  1631. return null;
  1632. }
  1633. }
  1634. static class ThrownFormalNotDeclaredInAdviceSignatureException extends Exception {
  1635. private String formalName;
  1636. public ThrownFormalNotDeclaredInAdviceSignatureException(String formalName) {
  1637. this.formalName = formalName;
  1638. }
  1639. public String getFormalName() { return formalName; }
  1640. }
  1641. static class ReturningFormalNotDeclaredInAdviceSignatureException extends Exception {
  1642. private String formalName;
  1643. public ReturningFormalNotDeclaredInAdviceSignatureException(String formalName) {
  1644. this.formalName = formalName;
  1645. }
  1646. public String getFormalName() { return formalName; }
  1647. }
  1648. }