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

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