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

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