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

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