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.

ValidateAtAspectJAnnotationsVisitor.java 32KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763
  1. /* *******************************************************************
  2. * Copyright (c) 2005 IBM Corporation Ltd
  3. * All rights reserved.
  4. * This program and the accompanying materials are made available
  5. * under the terms of the Eclipse Public License v 2.0
  6. * which accompanies this distribution and is available at
  7. * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.txt
  8. *
  9. * Contributors:
  10. * Adrian Colyer initial implementation
  11. * ******************************************************************/
  12. package org.aspectj.ajdt.internal.compiler.ast;
  13. import java.lang.reflect.Modifier;
  14. import java.util.ArrayList;
  15. import java.util.List;
  16. import java.util.Stack;
  17. import org.aspectj.ajdt.internal.compiler.lookup.EclipseFactory;
  18. import org.aspectj.ajdt.internal.compiler.lookup.EclipseScope;
  19. import org.aspectj.ajdt.internal.core.builder.EclipseSourceContext;
  20. import org.aspectj.bridge.context.CompilationAndWeavingContext;
  21. import org.aspectj.bridge.context.ContextToken;
  22. import org.aspectj.org.eclipse.jdt.core.compiler.CharOperation;
  23. import org.aspectj.org.eclipse.jdt.internal.compiler.ASTVisitor;
  24. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Annotation;
  25. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Argument;
  26. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
  27. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
  28. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.MemberValuePair;
  29. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
  30. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.NameReference;
  31. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.NormalAnnotation;
  32. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.SingleMemberAnnotation;
  33. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.SingleTypeReference;
  34. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.StringLiteral;
  35. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
  36. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeReference;
  37. import org.aspectj.org.eclipse.jdt.internal.compiler.impl.Constant;
  38. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.Binding;
  39. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.BlockScope;
  40. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ClassScope;
  41. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope;
  42. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
  43. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.MethodScope;
  44. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
  45. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
  46. import org.aspectj.weaver.AdviceKind;
  47. import org.aspectj.weaver.AjAttribute;
  48. import org.aspectj.weaver.ISourceContext;
  49. import org.aspectj.weaver.ResolvedPointcutDefinition;
  50. import org.aspectj.weaver.UnresolvedType;
  51. import org.aspectj.weaver.patterns.AbstractPatternNodeVisitor;
  52. import org.aspectj.weaver.patterns.FormalBinding;
  53. import org.aspectj.weaver.patterns.IfPointcut;
  54. import org.aspectj.weaver.patterns.ParserException;
  55. import org.aspectj.weaver.patterns.PatternParser;
  56. import org.aspectj.weaver.patterns.Pointcut;
  57. public class ValidateAtAspectJAnnotationsVisitor extends ASTVisitor {
  58. private static final char[] beforeAdviceSig = "Lorg/aspectj/lang/annotation/Before;".toCharArray();
  59. private static final char[] afterAdviceSig = "Lorg/aspectj/lang/annotation/After;".toCharArray();
  60. private static final char[] afterReturningAdviceSig = "Lorg/aspectj/lang/annotation/AfterReturning;".toCharArray();
  61. private static final char[] afterThrowingAdviceSig = "Lorg/aspectj/lang/annotation/AfterThrowing;".toCharArray();
  62. private static final char[] aroundAdviceSig = "Lorg/aspectj/lang/annotation/Around;".toCharArray();
  63. private static final char[] pointcutSig = "Lorg/aspectj/lang/annotation/Pointcut;".toCharArray();
  64. private static final char[] aspectSig = "Lorg/aspectj/lang/annotation/Aspect;".toCharArray();
  65. private static final char[] declareParentsSig = "Lorg/aspectj/lang/annotation/DeclareParents;".toCharArray();
  66. private static final char[] adviceNameSig = "Lorg/aspectj/lang/annotation/AdviceName;".toCharArray();
  67. // private static final char[] orgAspectJLangAnnotation =
  68. // "org/aspectj/lang/annotation/".toCharArray();
  69. private static final char[] voidType = "void".toCharArray();
  70. private static final char[] booleanType = "boolean".toCharArray();
  71. private static final char[] joinPoint = "Lorg/aspectj/lang/JoinPoint;".toCharArray();
  72. private static final char[] joinPointStaticPart = "Lorg/aspectj/lang/JoinPoint$StaticPart;".toCharArray();
  73. private static final char[] joinPointEnclosingStaticPart = "Lorg/aspectj/lang/JoinPoint$EnclosingStaticPart;".toCharArray();
  74. private static final char[] proceedingJoinPoint = "Lorg/aspectj/lang/ProceedingJoinPoint;".toCharArray();
  75. // private static final char[][] adviceSigs = new char[][] {
  76. // beforeAdviceSig, afterAdviceSig, afterReturningAdviceSig,
  77. // afterThrowingAdviceSig, aroundAdviceSig };
  78. private final CompilationUnitDeclaration unit;
  79. private final Stack typeStack = new Stack();
  80. private AspectJAnnotations ajAnnotations;
  81. public ValidateAtAspectJAnnotationsVisitor(CompilationUnitDeclaration unit) {
  82. this.unit = unit;
  83. }
  84. public boolean visit(TypeDeclaration localTypeDeclaration, BlockScope scope) {
  85. typeStack.push(localTypeDeclaration);
  86. ajAnnotations = new AspectJAnnotations(localTypeDeclaration.annotations);
  87. checkTypeDeclaration(localTypeDeclaration);
  88. return true;
  89. }
  90. public void endVisit(TypeDeclaration localTypeDeclaration, BlockScope scope) {
  91. typeStack.pop();
  92. }
  93. public boolean visit(TypeDeclaration memberTypeDeclaration, ClassScope scope) {
  94. typeStack.push(memberTypeDeclaration);
  95. ajAnnotations = new AspectJAnnotations(memberTypeDeclaration.annotations);
  96. checkTypeDeclaration(memberTypeDeclaration);
  97. return true;
  98. }
  99. public void endVisit(TypeDeclaration memberTypeDeclaration, ClassScope scope) {
  100. typeStack.pop();
  101. }
  102. public boolean visit(TypeDeclaration typeDeclaration, CompilationUnitScope scope) {
  103. typeStack.push(typeDeclaration);
  104. ajAnnotations = new AspectJAnnotations(typeDeclaration.annotations);
  105. checkTypeDeclaration(typeDeclaration);
  106. return true;
  107. }
  108. public void endVisit(TypeDeclaration typeDeclaration, CompilationUnitScope scope) {
  109. typeStack.pop();
  110. }
  111. private void checkTypeDeclaration(TypeDeclaration typeDecl) {
  112. ContextToken tok = CompilationAndWeavingContext.enteringPhase(
  113. CompilationAndWeavingContext.VALIDATING_AT_ASPECTJ_ANNOTATIONS, typeDecl.name);
  114. if (!(typeDecl instanceof AspectDeclaration)) {
  115. if (ajAnnotations.hasAspectAnnotation) {
  116. validateAspectDeclaration(typeDecl);
  117. } else {
  118. // check that class doesn't extend aspect
  119. TypeReference parentRef = typeDecl.superclass;
  120. if (parentRef != null) {
  121. TypeBinding parentBinding = parentRef.resolvedType;
  122. if (parentBinding instanceof SourceTypeBinding) {
  123. SourceTypeBinding parentSTB = (SourceTypeBinding) parentBinding;
  124. if (parentSTB.scope != null) {
  125. TypeDeclaration parentDecl = parentSTB.scope.referenceContext;
  126. if (isAspect(parentDecl)) {
  127. typeDecl.scope.problemReporter().signalError(typeDecl.sourceStart, typeDecl.sourceEnd,
  128. "a class cannot extend an aspect");
  129. }
  130. }
  131. }
  132. }
  133. }
  134. } else {
  135. // check that aspect doesn't have @Aspect annotation, we've already
  136. // added on ourselves.
  137. if (ajAnnotations.hasMultipleAspectAnnotations) {
  138. typeDecl.scope.problemReporter().signalError(typeDecl.sourceStart, typeDecl.sourceEnd,
  139. "aspects cannot have @Aspect annotation");
  140. }
  141. }
  142. CompilationAndWeavingContext.leavingPhase(tok);
  143. }
  144. public boolean visit(FieldDeclaration fieldDeclaration, MethodScope scope) {
  145. ajAnnotations = new AspectJAnnotations(fieldDeclaration.annotations);
  146. if (ajAnnotations.hasDeclareParents && !insideAspect()) {
  147. scope.problemReporter().signalError(fieldDeclaration.sourceStart, fieldDeclaration.sourceEnd,
  148. "DeclareParents can only be used inside an aspect type");
  149. }
  150. return true;
  151. }
  152. public boolean visit(MethodDeclaration methodDeclaration, ClassScope scope) {
  153. if (methodDeclaration.hasErrors()) {
  154. return false;
  155. }
  156. ContextToken tok = CompilationAndWeavingContext.enteringPhase(
  157. CompilationAndWeavingContext.VALIDATING_AT_ASPECTJ_ANNOTATIONS, methodDeclaration.selector);
  158. ajAnnotations = new AspectJAnnotations(methodDeclaration.annotations);
  159. if (!methodDeclaration.getClass().equals(AjMethodDeclaration.class)) {
  160. // simply test for innapropriate use of annotations on code-style
  161. // members
  162. if (methodDeclaration instanceof PointcutDeclaration) {
  163. if (ajAnnotations.hasMultiplePointcutAnnotations || ajAnnotations.hasAdviceAnnotation
  164. || ajAnnotations.hasAspectAnnotation || ajAnnotations.hasAdviceNameAnnotation) {
  165. methodDeclaration.scope.problemReporter().signalError(methodDeclaration.sourceStart,
  166. methodDeclaration.sourceEnd, "@AspectJ annotations cannot be declared on this aspect member");
  167. }
  168. } else if (methodDeclaration instanceof AdviceDeclaration) {
  169. if (ajAnnotations.hasMultipleAdviceAnnotations || ajAnnotations.hasAspectAnnotation
  170. || ajAnnotations.hasPointcutAnnotation) {
  171. methodDeclaration.scope.problemReporter().signalError(methodDeclaration.sourceStart,
  172. methodDeclaration.sourceEnd, "Only @AdviceName AspectJ annotation allowed on advice");
  173. }
  174. } else {
  175. if (ajAnnotations.hasAspectJAnnotations()) {
  176. methodDeclaration.scope.problemReporter().signalError(methodDeclaration.sourceStart,
  177. methodDeclaration.sourceEnd, "@AspectJ annotations cannot be declared on this aspect member");
  178. }
  179. }
  180. CompilationAndWeavingContext.leavingPhase(tok);
  181. return false;
  182. }
  183. if (ajAnnotations.hasAdviceAnnotation) {
  184. validateAdvice(methodDeclaration);
  185. } else if (ajAnnotations.hasPointcutAnnotation) {
  186. convertToPointcutDeclaration(methodDeclaration, scope);
  187. }
  188. CompilationAndWeavingContext.leavingPhase(tok);
  189. return false;
  190. }
  191. // private boolean isAspectJAnnotation(Annotation ann) {
  192. // if (ann.resolvedType == null) return false;
  193. // char[] sig = ann.resolvedType.signature();
  194. // return CharOperation.contains(orgAspectJLangAnnotation, sig);
  195. // }
  196. private boolean insideAspect() {
  197. if (typeStack.empty())
  198. return false;
  199. TypeDeclaration typeDecl = (TypeDeclaration) typeStack.peek();
  200. return isAspect(typeDecl);
  201. }
  202. private boolean isAspect(TypeDeclaration typeDecl) {
  203. if (typeDecl instanceof AspectDeclaration)
  204. return true;
  205. return new AspectJAnnotations(typeDecl.annotations).hasAspectAnnotation;
  206. }
  207. /**
  208. * aspect must be public nested aspect must be static cannot extend a concrete aspect pointcut in perclause must be good.
  209. */
  210. private void validateAspectDeclaration(TypeDeclaration typeDecl) {
  211. if (typeStack.size() > 1) {
  212. // it's a nested aspect
  213. if (!Modifier.isStatic(typeDecl.modifiers)) {
  214. typeDecl.scope.problemReporter().signalError(typeDecl.sourceStart, typeDecl.sourceEnd,
  215. "inner aspects must be static");
  216. return;
  217. }
  218. }
  219. SourceTypeBinding binding = typeDecl.binding;
  220. if (binding != null) {
  221. if (binding.isEnum() || binding.isInterface() || binding.isAnnotationType()) {
  222. typeDecl.scope.problemReporter().signalError(typeDecl.sourceStart, typeDecl.sourceEnd,
  223. "only classes can have an @Aspect annotation");
  224. }
  225. }
  226. // FIXME AV - do we really want that
  227. // if (!Modifier.isPublic(typeDecl.modifiers)) {
  228. // typeDecl.scope.problemReporter().signalError(typeDecl.sourceStart,
  229. // typeDecl.sourceEnd,"@Aspect class must be public");
  230. // }
  231. TypeReference parentRef = typeDecl.superclass;
  232. if (parentRef != null) {
  233. TypeBinding parentBinding = parentRef.resolvedType;
  234. if (parentBinding instanceof SourceTypeBinding) {
  235. SourceTypeBinding parentSTB = (SourceTypeBinding) parentBinding;
  236. if (parentSTB.scope != null) { // scope is null if its a
  237. // binarytypebinding (in AJ
  238. // world, thats a subclass of
  239. // SourceTypeBinding)
  240. TypeDeclaration parentDecl = parentSTB.scope.referenceContext;
  241. if (isAspect(parentDecl) && !Modifier.isAbstract(parentDecl.modifiers)) {
  242. typeDecl.scope.problemReporter().signalError(typeDecl.sourceStart, typeDecl.sourceEnd,
  243. "cannot extend a concrete aspect");
  244. }
  245. }
  246. }
  247. }
  248. Annotation aspectAnnotation = ajAnnotations.aspectAnnotation;
  249. int[] pcLoc = new int[2];
  250. String perClause = getStringLiteralFor("value", aspectAnnotation, pcLoc);
  251. // AspectDeclaration aspectDecl = new
  252. // AspectDeclaration(typeDecl.compilationResult);
  253. try {
  254. if (perClause != null && !perClause.equals("")) {
  255. ISourceContext context = new EclipseSourceContext(unit.compilationResult, pcLoc[0]);
  256. Pointcut pc = new PatternParser(perClause, context).maybeParsePerClause();
  257. FormalBinding[] bindings = FormalBinding.NONE;
  258. if (pc != null)
  259. pc.resolve(new EclipseScope(bindings, typeDecl.scope));
  260. }
  261. } catch (ParserException pEx) {
  262. typeDecl.scope.problemReporter().parseError(pcLoc[0] + pEx.getLocation().getStart(),
  263. pcLoc[0] + pEx.getLocation().getEnd(), -1, perClause.toCharArray(), perClause,
  264. new String[] { pEx.getMessage() });
  265. }
  266. }
  267. /**
  268. * 1) Advice must be public 2) Advice must have a void return type if not around advice 3) Advice must not have any other @AspectJ
  269. * annotations 4) After throwing advice must declare the thrown formal 5) After returning advice must declare the returning
  270. * formal 6) Advice must not be static
  271. */
  272. private void validateAdvice(MethodDeclaration methodDeclaration) {
  273. if (!insideAspect()) {
  274. methodDeclaration.scope.problemReporter().signalError(methodDeclaration.sourceStart, methodDeclaration.sourceEnd,
  275. "Advice must be declared inside an aspect type");
  276. }
  277. if (!Modifier.isPublic(methodDeclaration.modifiers)) {
  278. methodDeclaration.scope.problemReporter().signalError(methodDeclaration.sourceStart, methodDeclaration.sourceEnd,
  279. "advice must be public");
  280. }
  281. if (Modifier.isStatic(methodDeclaration.modifiers)) {
  282. methodDeclaration.scope.problemReporter().signalError(methodDeclaration.sourceStart, methodDeclaration.sourceEnd,
  283. "advice can not be declared static");
  284. }
  285. if (ajAnnotations.hasMultipleAdviceAnnotations) {
  286. methodDeclaration.scope.problemReporter().disallowedTargetForAnnotation(ajAnnotations.duplicateAdviceAnnotation);
  287. }
  288. if (ajAnnotations.hasPointcutAnnotation) {
  289. methodDeclaration.scope.problemReporter().disallowedTargetForAnnotation(ajAnnotations.pointcutAnnotation);
  290. }
  291. if (ajAnnotations.hasAspectAnnotation) {
  292. methodDeclaration.scope.problemReporter().disallowedTargetForAnnotation(ajAnnotations.aspectAnnotation);
  293. }
  294. if (ajAnnotations.hasAdviceNameAnnotation) {
  295. methodDeclaration.scope.problemReporter().disallowedTargetForAnnotation(ajAnnotations.adviceNameAnnotation);
  296. }
  297. if (ajAnnotations.adviceKind != AdviceKind.Around) {
  298. ensureVoidReturnType(methodDeclaration);
  299. }
  300. if (ajAnnotations.adviceKind == AdviceKind.AfterThrowing) {
  301. int[] throwingLocation = new int[2];
  302. String thrownFormal = getStringLiteralFor("throwing", ajAnnotations.adviceAnnotation, throwingLocation);
  303. if (thrownFormal != null) {
  304. // Argument[] arguments = methodDeclaration.arguments;
  305. if (!toArgumentNames(methodDeclaration.arguments).contains(thrownFormal)) {
  306. methodDeclaration.scope.problemReporter().signalError(methodDeclaration.sourceStart,
  307. methodDeclaration.sourceEnd,
  308. "throwing formal '" + thrownFormal + "' must be declared as a parameter in the advice signature");
  309. }
  310. }
  311. }
  312. if (ajAnnotations.adviceKind == AdviceKind.AfterReturning) {
  313. int[] throwingLocation = new int[2];
  314. String returningFormal = getStringLiteralFor("returning", ajAnnotations.adviceAnnotation, throwingLocation);
  315. if (returningFormal != null) {
  316. if (!toArgumentNames(methodDeclaration.arguments).contains(returningFormal)) {
  317. methodDeclaration.scope.problemReporter().signalError(methodDeclaration.sourceStart,
  318. methodDeclaration.sourceEnd,
  319. "returning formal '" + returningFormal + "' must be declared as a parameter in the advice signature");
  320. }
  321. }
  322. }
  323. resolveAndSetPointcut(methodDeclaration, ajAnnotations.adviceAnnotation);
  324. }
  325. /**
  326. * Get the argument names as a string list
  327. *
  328. * @param arguments
  329. * @return argument names (possibly empty)
  330. */
  331. private List toArgumentNames(Argument[] arguments) {
  332. List names = new ArrayList();
  333. if (arguments == null) {
  334. return names;
  335. } else {
  336. for (Argument argument : arguments) {
  337. names.add(new String(argument.name));
  338. }
  339. return names;
  340. }
  341. }
  342. private void resolveAndSetPointcut(MethodDeclaration methodDeclaration, Annotation adviceAnn) {
  343. int[] pcLocation = new int[2];
  344. String pointcutExpression = getStringLiteralFor("pointcut", adviceAnn, pcLocation);
  345. if (pointcutExpression == null)
  346. pointcutExpression = getStringLiteralFor("value", adviceAnn, pcLocation);
  347. try {
  348. // +1 to give first char of pointcut string
  349. ISourceContext context = new EclipseSourceContext(unit.compilationResult, pcLocation[0] + 1);
  350. if (pointcutExpression == null) {
  351. methodDeclaration.scope.problemReporter().signalError(methodDeclaration.sourceStart,
  352. methodDeclaration.sourceEnd, "the advice annotation must specify a pointcut value");
  353. return;
  354. }
  355. PatternParser pp = new PatternParser(pointcutExpression, context);
  356. Pointcut pc = pp.parsePointcut();
  357. pp.checkEof();
  358. FormalBinding[] bindings = buildFormalAdviceBindingsFrom(methodDeclaration);
  359. pc.resolve(new EclipseScope(bindings, methodDeclaration.scope));
  360. EclipseFactory factory = EclipseFactory.fromScopeLookupEnvironment(methodDeclaration.scope);
  361. // now create a ResolvedPointcutDefinition,make an attribute out of
  362. // it, and add it to the method
  363. UnresolvedType[] paramTypes = new UnresolvedType[bindings.length];
  364. for (int i = 0; i < paramTypes.length; i++)
  365. paramTypes[i] = bindings[i].getType();
  366. ResolvedPointcutDefinition resPcutDef = new ResolvedPointcutDefinition(factory.fromBinding(((TypeDeclaration) typeStack
  367. .peek()).binding), methodDeclaration.modifiers, "anonymous", paramTypes, pc);
  368. AjAttribute attr = new AjAttribute.PointcutDeclarationAttribute(resPcutDef);
  369. ((AjMethodDeclaration) methodDeclaration).addAttribute(new EclipseAttributeAdapter(attr));
  370. } catch (ParserException pEx) {
  371. methodDeclaration.scope.problemReporter().parseError(pcLocation[0] + pEx.getLocation().getStart(),
  372. pcLocation[0] + pEx.getLocation().getEnd(), -1, pointcutExpression.toCharArray(), pointcutExpression,
  373. new String[] { pEx.getMessage() });
  374. }
  375. }
  376. private void ensureVoidReturnType(MethodDeclaration methodDeclaration) {
  377. boolean returnsVoid = true;
  378. if ((methodDeclaration.returnType instanceof SingleTypeReference)) {
  379. SingleTypeReference retType = (SingleTypeReference) methodDeclaration.returnType;
  380. if (!CharOperation.equals(voidType, retType.token)) {
  381. returnsVoid = false;
  382. }
  383. } else {
  384. returnsVoid = false;
  385. }
  386. if (!returnsVoid) {
  387. methodDeclaration.scope.problemReporter().signalError(methodDeclaration.returnType.sourceStart,
  388. methodDeclaration.returnType.sourceEnd, "This advice must return void");
  389. }
  390. }
  391. private FormalBinding[] buildFormalAdviceBindingsFrom(MethodDeclaration mDecl) {
  392. if (mDecl.arguments == null)
  393. return FormalBinding.NONE;
  394. if (mDecl.binding == null)
  395. return FormalBinding.NONE;
  396. EclipseFactory factory = EclipseFactory.fromScopeLookupEnvironment(mDecl.scope);
  397. String extraArgName = maybeGetExtraArgName();
  398. if (extraArgName == null)
  399. extraArgName = "";
  400. FormalBinding[] ret = new FormalBinding[mDecl.arguments.length];
  401. for (int i = 0; i < mDecl.arguments.length; i++) {
  402. Argument arg = mDecl.arguments[i];
  403. String name = new String(arg.name);
  404. TypeBinding argTypeBinding = mDecl.binding.parameters[i];
  405. UnresolvedType type = factory.fromBinding(argTypeBinding);
  406. if (CharOperation.equals(joinPoint, argTypeBinding.signature())
  407. || CharOperation.equals(joinPointStaticPart, argTypeBinding.signature())
  408. || CharOperation.equals(joinPointEnclosingStaticPart, argTypeBinding.signature())
  409. || CharOperation.equals(proceedingJoinPoint, argTypeBinding.signature()) || name.equals(extraArgName)) {
  410. ret[i] = new FormalBinding.ImplicitFormalBinding(type, name, i);
  411. } else {
  412. ret[i] = new FormalBinding(type, name, i, arg.sourceStart, arg.sourceEnd);
  413. }
  414. }
  415. return ret;
  416. }
  417. private String maybeGetExtraArgName() {
  418. String argName = null;
  419. if (ajAnnotations.adviceKind == AdviceKind.AfterReturning) {
  420. argName = getStringLiteralFor("returning", ajAnnotations.adviceAnnotation, new int[2]);
  421. } else if (ajAnnotations.adviceKind == AdviceKind.AfterThrowing) {
  422. argName = getStringLiteralFor("throwing", ajAnnotations.adviceAnnotation, new int[2]);
  423. }
  424. return argName;
  425. }
  426. private String getStringLiteralFor(String memberName, Annotation inAnnotation, int[] location) {
  427. if (inAnnotation instanceof SingleMemberAnnotation && memberName.equals("value")) {
  428. SingleMemberAnnotation sma = (SingleMemberAnnotation) inAnnotation;
  429. if (sma.memberValue instanceof StringLiteral) {
  430. StringLiteral sv = (StringLiteral) sma.memberValue;
  431. location[0] = sv.sourceStart;
  432. location[1] = sv.sourceEnd;
  433. return new String(sv.source());
  434. } else if (sma.memberValue instanceof NameReference
  435. && (((NameReference) sma.memberValue).binding instanceof FieldBinding)) {
  436. Binding b = ((NameReference) sma.memberValue).binding;
  437. Constant c = ((FieldBinding) b).constant();
  438. return c.stringValue();
  439. }
  440. }
  441. if (!(inAnnotation instanceof NormalAnnotation))
  442. return null;
  443. NormalAnnotation ann = (NormalAnnotation) inAnnotation;
  444. MemberValuePair[] mvps = ann.memberValuePairs;
  445. if (mvps == null)
  446. return null;
  447. for (MemberValuePair mvp : mvps) {
  448. if (CharOperation.equals(memberName.toCharArray(), mvp.name)) {
  449. if (mvp.value instanceof StringLiteral) {
  450. StringLiteral sv = (StringLiteral) mvp.value;
  451. location[0] = sv.sourceStart;
  452. location[1] = sv.sourceEnd;
  453. return new String(sv.source());
  454. }
  455. }
  456. }
  457. return null;
  458. }
  459. private void convertToPointcutDeclaration(MethodDeclaration methodDeclaration, ClassScope scope) {
  460. TypeDeclaration typeDecl = (TypeDeclaration) typeStack.peek();
  461. if (typeDecl.binding != null) {
  462. if (!typeDecl.binding.isClass()) {
  463. methodDeclaration.scope.problemReporter().signalError(methodDeclaration.sourceStart, methodDeclaration.sourceEnd,
  464. "pointcuts can only be declared in a class or an aspect");
  465. }
  466. }
  467. if (methodDeclaration.thrownExceptions != null && methodDeclaration.thrownExceptions.length > 0) {
  468. methodDeclaration.scope.problemReporter().signalError(methodDeclaration.sourceStart, methodDeclaration.sourceEnd,
  469. "pointcuts cannot throw exceptions!");
  470. }
  471. PointcutDeclaration pcDecl = new PointcutDeclaration(unit.compilationResult);
  472. copyAllFields(methodDeclaration, pcDecl);
  473. if (ajAnnotations.hasAdviceAnnotation) {
  474. methodDeclaration.scope.problemReporter().disallowedTargetForAnnotation(ajAnnotations.adviceAnnotation);
  475. }
  476. if (ajAnnotations.hasAspectAnnotation) {
  477. methodDeclaration.scope.problemReporter().disallowedTargetForAnnotation(ajAnnotations.aspectAnnotation);
  478. }
  479. if (ajAnnotations.hasAdviceNameAnnotation) {
  480. methodDeclaration.scope.problemReporter().disallowedTargetForAnnotation(ajAnnotations.adviceNameAnnotation);
  481. }
  482. boolean noValueSupplied = true;
  483. boolean containsIfPcd = false;
  484. boolean isIfTrueOrFalse = false;
  485. int[] pcLocation = new int[2];
  486. String pointcutExpression = getStringLiteralFor("value", ajAnnotations.pointcutAnnotation, pcLocation);
  487. try {
  488. ISourceContext context = new EclipseSourceContext(unit.compilationResult, pcLocation[0]);
  489. Pointcut pc = null;// abstract
  490. if (pointcutExpression == null || pointcutExpression.length() == 0) {
  491. noValueSupplied = true; // matches nothing pointcut
  492. } else {
  493. noValueSupplied = false;
  494. pc = new PatternParser(pointcutExpression, context).parsePointcut();
  495. if (pc instanceof IfPointcut) {
  496. if (((IfPointcut)pc).alwaysFalse() || ((IfPointcut)pc).alwaysTrue()) {
  497. isIfTrueOrFalse = true;
  498. }
  499. }
  500. }
  501. pcDecl.pointcutDesignator = (pc == null) ? null : new PointcutDesignator(pc);
  502. pcDecl.setGenerateSyntheticPointcutMethod();
  503. TypeDeclaration onType = (TypeDeclaration) typeStack.peek();
  504. pcDecl.postParse(onType);
  505. // EclipseFactory factory =
  506. // EclipseFactory.fromScopeLookupEnvironment
  507. // (methodDeclaration.scope);
  508. // int argsLength = methodDeclaration.arguments == null ? 0 :
  509. // methodDeclaration.arguments.length;
  510. FormalBinding[] bindings = buildFormalAdviceBindingsFrom(methodDeclaration);
  511. // FormalBinding[] bindings = new FormalBinding[argsLength];
  512. // for (int i = 0, len = bindings.length; i < len; i++) {
  513. // Argument arg = methodDeclaration.arguments[i];
  514. // String name = new String(arg.name);
  515. // UnresolvedType type =
  516. // factory.fromBinding(methodDeclaration.binding.parameters[i]);
  517. // bindings[i] = new FormalBinding(type, name, i, arg.sourceStart,
  518. // arg.sourceEnd, "unknown");
  519. // }
  520. swap(onType, methodDeclaration, pcDecl);
  521. if (pc != null) {
  522. // has an expression
  523. EclipseScope eScope = new EclipseScope(bindings, methodDeclaration.scope);
  524. char[] packageName = null;
  525. if (typeDecl.binding != null && typeDecl.binding.getPackage() != null) {
  526. packageName = typeDecl.binding.getPackage().readableName();
  527. }
  528. eScope.setLimitedImports(packageName);
  529. pc.resolve(eScope);
  530. HasIfPCDVisitor ifFinder = new HasIfPCDVisitor();
  531. pc.traverse(ifFinder, null);
  532. containsIfPcd = ifFinder.containsIfPcd;
  533. }
  534. } catch (ParserException pEx) {
  535. methodDeclaration.scope.problemReporter().parseError(pcLocation[0] + pEx.getLocation().getStart(),
  536. pcLocation[0] + pEx.getLocation().getEnd(), -1, pointcutExpression.toCharArray(), pointcutExpression,
  537. new String[] { pEx.getMessage() });
  538. }
  539. boolean returnsVoid = false;
  540. boolean returnsBoolean = false;
  541. if ((methodDeclaration.returnType instanceof SingleTypeReference)) {
  542. SingleTypeReference retType = (SingleTypeReference) methodDeclaration.returnType;
  543. if (CharOperation.equals(voidType, retType.token))
  544. returnsVoid = true;
  545. if (CharOperation.equals(booleanType, retType.token))
  546. returnsBoolean = true;
  547. }
  548. if (!returnsVoid && !containsIfPcd) {
  549. methodDeclaration.scope.problemReporter().signalError(methodDeclaration.returnType.sourceStart,
  550. methodDeclaration.returnType.sourceEnd,
  551. "Methods annotated with @Pointcut must return void unless the pointcut contains an if() expression");
  552. }
  553. if (!returnsBoolean && containsIfPcd && !isIfTrueOrFalse) {
  554. methodDeclaration.scope.problemReporter().signalError(methodDeclaration.returnType.sourceStart,
  555. methodDeclaration.returnType.sourceEnd,
  556. "Methods annotated with @Pointcut must return boolean when the pointcut contains an if() expression unless it is if(false) or if(true)");
  557. }
  558. if (methodDeclaration.statements != null && methodDeclaration.statements.length > 0 && !containsIfPcd) {
  559. methodDeclaration.scope.problemReporter()
  560. .signalError(methodDeclaration.returnType.sourceStart, methodDeclaration.returnType.sourceEnd,
  561. "Pointcuts without an if() expression should have an empty method body");
  562. }
  563. if (pcDecl.pointcutDesignator == null) {
  564. if (Modifier.isAbstract(methodDeclaration.modifiers) || noValueSupplied // this
  565. // is
  566. // a
  567. // matches
  568. // nothing
  569. // pointcut
  570. // those 2 checks makes sense for aop.xml concretization but NOT for
  571. // regular abstraction of pointcut
  572. // && returnsVoid
  573. // && (methodDeclaration.arguments == null ||
  574. // methodDeclaration.arguments.length == 0)) {
  575. ) {
  576. // fine
  577. } else {
  578. methodDeclaration.scope.problemReporter().signalError(methodDeclaration.returnType.sourceStart,
  579. methodDeclaration.returnType.sourceEnd,
  580. "Method annotated with @Pointcut() for abstract pointcut must be abstract");
  581. }
  582. } else if (Modifier.isAbstract(methodDeclaration.modifiers)) {
  583. methodDeclaration.scope.problemReporter().signalError(methodDeclaration.returnType.sourceStart,
  584. methodDeclaration.returnType.sourceEnd,
  585. "Method annotated with non abstract @Pointcut(\"" + pointcutExpression + "\") is abstract");
  586. }
  587. }
  588. private void copyAllFields(MethodDeclaration from, MethodDeclaration to) {
  589. to.annotations = from.annotations;
  590. to.arguments = from.arguments;
  591. to.binding = from.binding;
  592. to.bits = from.bits;
  593. to.bodyEnd = from.bodyEnd;
  594. to.bodyStart = from.bodyStart;
  595. to.declarationSourceEnd = from.declarationSourceEnd;
  596. to.declarationSourceStart = from.declarationSourceStart;
  597. to.explicitDeclarations = from.explicitDeclarations;
  598. to.ignoreFurtherInvestigation = from.ignoreFurtherInvestigation;
  599. to.javadoc = from.javadoc;
  600. to.modifiers = from.modifiers;
  601. to.modifiersSourceStart = from.modifiersSourceStart;
  602. to.returnType = from.returnType;
  603. to.scope = from.scope;
  604. to.selector = from.selector;
  605. to.sourceEnd = from.sourceEnd;
  606. to.sourceStart = from.sourceStart;
  607. to.statements = from.statements;
  608. to.thrownExceptions = from.thrownExceptions;
  609. to.typeParameters = from.typeParameters;
  610. }
  611. private void swap(TypeDeclaration inType, MethodDeclaration thisDeclaration, MethodDeclaration forThatDeclaration) {
  612. for (int i = 0; i < inType.methods.length; i++) {
  613. if (inType.methods[i] == thisDeclaration) {
  614. inType.methods[i] = forThatDeclaration;
  615. break;
  616. }
  617. }
  618. }
  619. private static class AspectJAnnotations {
  620. boolean hasAdviceAnnotation = false;
  621. boolean hasPointcutAnnotation = false;
  622. boolean hasAspectAnnotation = false;
  623. boolean hasAdviceNameAnnotation = false;
  624. boolean hasDeclareParents = false;
  625. boolean hasMultipleAdviceAnnotations = false;
  626. boolean hasMultiplePointcutAnnotations = false;
  627. boolean hasMultipleAspectAnnotations = false;
  628. AdviceKind adviceKind = null;
  629. Annotation adviceAnnotation = null;
  630. Annotation pointcutAnnotation = null;
  631. Annotation aspectAnnotation = null;
  632. Annotation adviceNameAnnotation = null;
  633. Annotation duplicateAdviceAnnotation = null;
  634. Annotation duplicatePointcutAnnotation = null;
  635. Annotation duplicateAspectAnnotation = null;
  636. public AspectJAnnotations(Annotation[] annotations) {
  637. if (annotations == null)
  638. return;
  639. for (Annotation annotation : annotations) {
  640. if (annotation.resolvedType == null)
  641. continue; // user messed up annotation declaration
  642. char[] sig = annotation.resolvedType.signature();
  643. if (CharOperation.equals(afterAdviceSig, sig)) {
  644. adviceKind = AdviceKind.After;
  645. addAdviceAnnotation(annotation);
  646. } else if (CharOperation.equals(afterReturningAdviceSig, sig)) {
  647. adviceKind = AdviceKind.AfterReturning;
  648. addAdviceAnnotation(annotation);
  649. } else if (CharOperation.equals(afterThrowingAdviceSig, sig)) {
  650. adviceKind = AdviceKind.AfterThrowing;
  651. addAdviceAnnotation(annotation);
  652. } else if (CharOperation.equals(beforeAdviceSig, sig)) {
  653. adviceKind = AdviceKind.Before;
  654. addAdviceAnnotation(annotation);
  655. } else if (CharOperation.equals(aroundAdviceSig, sig)) {
  656. adviceKind = AdviceKind.Around;
  657. addAdviceAnnotation(annotation);
  658. } else if (CharOperation.equals(adviceNameSig, sig)) {
  659. hasAdviceNameAnnotation = true;
  660. adviceNameAnnotation = annotation;
  661. } else if (CharOperation.equals(declareParentsSig, sig)) {
  662. hasDeclareParents = true;
  663. } else if (CharOperation.equals(aspectSig, sig)) {
  664. if (hasAspectAnnotation) {
  665. hasMultipleAspectAnnotations = true;
  666. duplicateAspectAnnotation = annotation;
  667. } else {
  668. hasAspectAnnotation = true;
  669. aspectAnnotation = annotation;
  670. }
  671. } else if (CharOperation.equals(pointcutSig, sig)) {
  672. if (hasPointcutAnnotation) {
  673. hasMultiplePointcutAnnotations = true;
  674. duplicatePointcutAnnotation = annotation;
  675. } else {
  676. hasPointcutAnnotation = true;
  677. pointcutAnnotation = annotation;
  678. }
  679. }
  680. }
  681. }
  682. public boolean hasAspectJAnnotations() {
  683. return hasAdviceAnnotation || hasPointcutAnnotation || hasAdviceNameAnnotation || hasAspectAnnotation;
  684. }
  685. private void addAdviceAnnotation(Annotation annotation) {
  686. if (!hasAdviceAnnotation) {
  687. hasAdviceAnnotation = true;
  688. adviceAnnotation = annotation;
  689. } else {
  690. hasMultipleAdviceAnnotations = true;
  691. duplicateAdviceAnnotation = annotation;
  692. }
  693. }
  694. }
  695. private static class HasIfPCDVisitor extends AbstractPatternNodeVisitor {
  696. public boolean containsIfPcd = false;
  697. public Object visit(IfPointcut node, Object data) {
  698. containsIfPcd = true;
  699. return data;
  700. }
  701. }
  702. }