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

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