1 /* *******************************************************************
2 * Copyright (c) 2005 IBM Corporation Ltd
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
10 * Adrian Colyer initial implementation
11 * ******************************************************************/
12 package org.aspectj.ajdt.internal.compiler.ast;
14 import java.lang.reflect.Modifier;
15 import java.util.Stack;
16 import java.util.ArrayList;
17 import java.util.List;
19 import org.aspectj.ajdt.internal.compiler.lookup.EclipseFactory;
20 import org.aspectj.ajdt.internal.compiler.lookup.EclipseScope;
21 import org.aspectj.ajdt.internal.core.builder.EclipseSourceContext;
22 import org.aspectj.bridge.context.CompilationAndWeavingContext;
23 import org.aspectj.bridge.context.ContextToken;
24 import org.aspectj.org.eclipse.jdt.core.compiler.CharOperation;
25 import org.aspectj.org.eclipse.jdt.internal.compiler.ASTVisitor;
26 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Annotation;
27 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Argument;
28 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
29 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
30 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.MemberValuePair;
31 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
32 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.NormalAnnotation;
33 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.SingleMemberAnnotation;
34 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.SingleTypeReference;
35 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.StringLiteral;
36 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
37 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeReference;
38 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.BlockScope;
39 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ClassScope;
40 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope;
41 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.MethodScope;
42 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
43 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
44 import org.aspectj.weaver.AdviceKind;
45 import org.aspectj.weaver.AjAttribute;
46 import org.aspectj.weaver.ISourceContext;
47 import org.aspectj.weaver.ResolvedPointcutDefinition;
48 import org.aspectj.weaver.UnresolvedType;
49 import org.aspectj.weaver.patterns.AbstractPatternNodeVisitor;
50 import org.aspectj.weaver.patterns.FormalBinding;
51 import org.aspectj.weaver.patterns.IfPointcut;
52 import org.aspectj.weaver.patterns.ParserException;
53 import org.aspectj.weaver.patterns.PatternParser;
54 import org.aspectj.weaver.patterns.Pointcut;
56 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 = "org/aspectj/lang/annotation/".toCharArray();
68 private static final char[] voidType = "void".toCharArray();
69 private static final char[] booleanType = "boolean".toCharArray();
70 private static final char[] joinPoint = "Lorg/aspectj/lang/JoinPoint;".toCharArray();
71 private static final char[] joinPointStaticPart = "Lorg/aspectj/lang/JoinPoint$StaticPart;".toCharArray();
72 private static final char[] joinPointEnclosingStaticPart = "Lorg/aspectj/lang/JoinPoint$EnclosingStaticPart;".toCharArray();
73 private static final char[] proceedingJoinPoint = "Lorg/aspectj/lang/ProceedingJoinPoint;".toCharArray();
74 private static final char[][] adviceSigs = new char[][] {beforeAdviceSig,afterAdviceSig,afterReturningAdviceSig,afterThrowingAdviceSig,aroundAdviceSig};
77 private CompilationUnitDeclaration unit;
78 private Stack typeStack = new Stack();
79 private AspectJAnnotations ajAnnotations;
81 public ValidateAtAspectJAnnotationsVisitor(CompilationUnitDeclaration unit) {
85 public boolean visit(TypeDeclaration localTypeDeclaration, BlockScope scope) {
86 typeStack.push(localTypeDeclaration);
87 ajAnnotations = new AspectJAnnotations(localTypeDeclaration.annotations);
88 checkTypeDeclaration(localTypeDeclaration);
92 public void endVisit(TypeDeclaration localTypeDeclaration,BlockScope scope) {
96 public boolean visit(TypeDeclaration memberTypeDeclaration,ClassScope scope) {
97 typeStack.push(memberTypeDeclaration);
98 ajAnnotations = new AspectJAnnotations(memberTypeDeclaration.annotations);
99 checkTypeDeclaration(memberTypeDeclaration);
103 public void endVisit(TypeDeclaration memberTypeDeclaration,ClassScope scope) {
107 public boolean visit(TypeDeclaration typeDeclaration, CompilationUnitScope scope) {
108 typeStack.push(typeDeclaration);
109 ajAnnotations = new AspectJAnnotations(typeDeclaration.annotations);
110 checkTypeDeclaration(typeDeclaration);
114 public void endVisit(TypeDeclaration typeDeclaration,CompilationUnitScope scope) {
118 private void checkTypeDeclaration(TypeDeclaration typeDecl) {
119 ContextToken tok = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.VALIDATING_AT_ASPECTJ_ANNOTATIONS, typeDecl.name);
120 if (!(typeDecl instanceof AspectDeclaration)) {
121 if (ajAnnotations.hasAspectAnnotation) {
122 validateAspectDeclaration(typeDecl);
124 // check that class doesn't extend aspect
125 TypeReference parentRef = typeDecl.superclass;
126 if (parentRef != null) {
127 TypeBinding parentBinding = parentRef.resolvedType;
128 if (parentBinding instanceof SourceTypeBinding) {
129 SourceTypeBinding parentSTB = (SourceTypeBinding) parentBinding;
130 if (parentSTB.scope != null) {
131 TypeDeclaration parentDecl = parentSTB.scope.referenceContext;
132 if (isAspect(parentDecl)) {
133 typeDecl.scope.problemReporter().signalError(typeDecl.sourceStart,typeDecl.sourceEnd,"a class cannot extend an aspect");
140 // check that aspect doesn't have @Aspect annotation, we've already added on ourselves.
141 if (ajAnnotations.hasMultipleAspectAnnotations) {
142 typeDecl.scope.problemReporter().signalError(
143 typeDecl.sourceStart,
145 "aspects cannot have @Aspect annotation"
149 CompilationAndWeavingContext.leavingPhase(tok);
152 public boolean visit(FieldDeclaration fieldDeclaration, MethodScope scope) {
153 ajAnnotations = new AspectJAnnotations(fieldDeclaration.annotations);
154 if (ajAnnotations.hasDeclareParents && !insideAspect()) {
155 scope.problemReporter().signalError(fieldDeclaration.sourceStart,
156 fieldDeclaration.sourceEnd,
157 "DeclareParents can only be used inside an aspect type");
161 public boolean visit(MethodDeclaration methodDeclaration, ClassScope scope) {
162 if (methodDeclaration.hasErrors()) {
165 ContextToken tok = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.VALIDATING_AT_ASPECTJ_ANNOTATIONS, methodDeclaration.selector);
166 ajAnnotations = new AspectJAnnotations(methodDeclaration.annotations);
167 if (!methodDeclaration.getClass().equals(AjMethodDeclaration.class)) {
168 // simply test for innapropriate use of annotations on code-style members
169 if (methodDeclaration instanceof PointcutDeclaration) {
170 if (ajAnnotations.hasMultiplePointcutAnnotations ||
171 ajAnnotations.hasAdviceAnnotation ||
172 ajAnnotations.hasAspectAnnotation ||
173 ajAnnotations.hasAdviceNameAnnotation) {
174 methodDeclaration.scope.problemReporter().signalError(
175 methodDeclaration.sourceStart,
176 methodDeclaration.sourceEnd,
177 "@AspectJ annotations cannot be declared on this aspect member");
179 } else if (methodDeclaration instanceof AdviceDeclaration) {
180 if (ajAnnotations.hasMultipleAdviceAnnotations ||
181 ajAnnotations.hasAspectAnnotation ||
182 ajAnnotations.hasPointcutAnnotation) {
183 methodDeclaration.scope.problemReporter().signalError(
184 methodDeclaration.sourceStart,
185 methodDeclaration.sourceEnd,
186 "Only @AdviceName AspectJ annotation allowed on advice");
189 if (ajAnnotations.hasAspectJAnnotations()) {
190 methodDeclaration.scope.problemReporter().signalError(
191 methodDeclaration.sourceStart,
192 methodDeclaration.sourceEnd,
193 "@AspectJ annotations cannot be declared on this aspect member");
196 CompilationAndWeavingContext.leavingPhase(tok);
200 if (ajAnnotations.hasAdviceAnnotation) {
201 validateAdvice(methodDeclaration);
202 } else if (ajAnnotations.hasPointcutAnnotation) {
203 convertToPointcutDeclaration(methodDeclaration,scope);
205 CompilationAndWeavingContext.leavingPhase(tok);
209 private boolean isAspectJAnnotation(Annotation ann) {
210 if (ann.resolvedType == null) return false;
211 char[] sig = ann.resolvedType.signature();
212 return CharOperation.contains(orgAspectJLangAnnotation, sig);
215 private boolean insideAspect() {
216 if (typeStack.empty()) return false;
217 TypeDeclaration typeDecl = (TypeDeclaration) typeStack.peek();
218 return isAspect(typeDecl);
221 private boolean isAspect(TypeDeclaration typeDecl) {
222 if (typeDecl instanceof AspectDeclaration) return true;
223 return new AspectJAnnotations(typeDecl.annotations).hasAspectAnnotation;
227 * aspect must be public
228 * nested aspect must be static
229 * cannot extend a concrete aspect
230 * pointcut in perclause must be good.
232 private void validateAspectDeclaration(TypeDeclaration typeDecl) {
233 if (typeStack.size() > 1) {
234 // it's a nested aspect
235 if (!Modifier.isStatic(typeDecl.modifiers)) {
236 typeDecl.scope.problemReporter().signalError(typeDecl.sourceStart, typeDecl.sourceEnd, "inner aspects must be static");
241 SourceTypeBinding binding = typeDecl.binding;
242 if (binding != null) {
243 if (binding.isEnum() || binding.isInterface() || binding.isAnnotationType()) {
244 typeDecl.scope.problemReporter().signalError(typeDecl.sourceStart,typeDecl.sourceEnd,"only classes can have an @Aspect annotation");
248 //FIXME AV - do we really want that
249 // if (!Modifier.isPublic(typeDecl.modifiers)) {
250 // typeDecl.scope.problemReporter().signalError(typeDecl.sourceStart,typeDecl.sourceEnd,"@Aspect class must be public");
253 TypeReference parentRef = typeDecl.superclass;
254 if (parentRef != null) {
255 TypeBinding parentBinding = parentRef.resolvedType;
256 if (parentBinding instanceof SourceTypeBinding) {
257 SourceTypeBinding parentSTB = (SourceTypeBinding) parentBinding;
258 if (parentSTB.scope!=null) { // scope is null if its a binarytypebinding (in AJ world, thats a subclass of SourceTypeBinding)
259 TypeDeclaration parentDecl = parentSTB.scope.referenceContext;
260 if (isAspect(parentDecl) && !Modifier.isAbstract(parentDecl.modifiers)) {
261 typeDecl.scope.problemReporter().signalError(typeDecl.sourceStart,typeDecl.sourceEnd,"cannot extend a concrete aspect");
267 Annotation aspectAnnotation = ajAnnotations.aspectAnnotation;
269 int[] pcLoc = new int[2];
270 String perClause = getStringLiteralFor("value", aspectAnnotation, pcLoc);
271 AspectDeclaration aspectDecl = new AspectDeclaration(typeDecl.compilationResult);
274 if (perClause != null && !perClause.equals("")) {
275 ISourceContext context = new EclipseSourceContext(unit.compilationResult,pcLoc[0]);
276 Pointcut pc = new PatternParser(perClause,context).maybeParsePerClause();
277 FormalBinding[] bindings = new FormalBinding[0];
278 if (pc != null) pc.resolve(new EclipseScope(bindings,typeDecl.scope));
280 } catch(ParserException pEx) {
281 typeDecl.scope.problemReporter().parseError(
282 pcLoc[0] + pEx.getLocation().getStart(),
283 pcLoc[0] + pEx.getLocation().getEnd() ,
285 perClause.toCharArray(),
287 new String[] {pEx.getMessage()});
292 * 1) Advice must be public
293 * 2) Advice must have a void return type if not around advice
294 * 3) Advice must not have any other @AspectJ annotations
295 * 4) After throwing advice must declare the thrown formal
296 * 5) After returning advice must declare the returning formal
297 * 6) Advice must not be static
299 private void validateAdvice(MethodDeclaration methodDeclaration) {
301 if (!insideAspect()) {
302 methodDeclaration.scope.problemReporter().signalError(methodDeclaration.sourceStart,
303 methodDeclaration.sourceEnd,
304 "Advice must be declared inside an aspect type");
307 if (!Modifier.isPublic(methodDeclaration.modifiers)) {
308 methodDeclaration.scope.problemReporter()
309 .signalError(methodDeclaration.sourceStart,methodDeclaration.sourceEnd,"advice must be public");
312 if (Modifier.isStatic(methodDeclaration.modifiers)) {
313 methodDeclaration.scope.problemReporter()
314 .signalError(methodDeclaration.sourceStart,methodDeclaration.sourceEnd,"advice can not be declared static");
317 if (ajAnnotations.hasMultipleAdviceAnnotations) {
318 methodDeclaration.scope.problemReporter().disallowedTargetForAnnotation(ajAnnotations.duplicateAdviceAnnotation);
320 if (ajAnnotations.hasPointcutAnnotation) {
321 methodDeclaration.scope.problemReporter().disallowedTargetForAnnotation(ajAnnotations.pointcutAnnotation);
323 if (ajAnnotations.hasAspectAnnotation) {
324 methodDeclaration.scope.problemReporter().disallowedTargetForAnnotation(ajAnnotations.aspectAnnotation);
326 if (ajAnnotations.hasAdviceNameAnnotation) {
327 methodDeclaration.scope.problemReporter().disallowedTargetForAnnotation(ajAnnotations.adviceNameAnnotation);
330 if (ajAnnotations.adviceKind != AdviceKind.Around) {
331 ensureVoidReturnType(methodDeclaration);
334 if (ajAnnotations.adviceKind == AdviceKind.AfterThrowing) {
335 int[] throwingLocation = new int[2];
336 String thrownFormal = getStringLiteralFor("throwing",ajAnnotations.adviceAnnotation,throwingLocation);
337 if (thrownFormal != null) {
338 Argument[] arguments = methodDeclaration.arguments;
339 if (!toArgumentNames(methodDeclaration.arguments).contains(thrownFormal)) {
340 methodDeclaration.scope.problemReporter()
341 .signalError(methodDeclaration.sourceStart,methodDeclaration.sourceEnd,"throwing formal '" + thrownFormal + "' must be declared as a parameter in the advice signature");
346 if (ajAnnotations.adviceKind == AdviceKind.AfterReturning) {
347 int[] throwingLocation = new int[2];
348 String returningFormal = getStringLiteralFor("returning",ajAnnotations.adviceAnnotation,throwingLocation);
349 if (returningFormal != null) {
350 if (!toArgumentNames(methodDeclaration.arguments).contains(returningFormal)) {
351 methodDeclaration.scope.problemReporter()
352 .signalError(methodDeclaration.sourceStart,methodDeclaration.sourceEnd,"returning formal '" + returningFormal + "' must be declared as a parameter in the advice signature");
357 resolveAndSetPointcut(methodDeclaration, ajAnnotations.adviceAnnotation);
362 * Get the argument names as a string list
364 * @return argument names (possibly empty)
366 private List toArgumentNames(Argument[] arguments) {
367 List names = new ArrayList();
368 if (arguments == null) {
371 for (int i = 0; i < arguments.length; i++) {
372 names.add(new String(arguments[i].name));
378 private void resolveAndSetPointcut(MethodDeclaration methodDeclaration, Annotation adviceAnn) {
379 int[] pcLocation = new int[2];
380 String pointcutExpression = getStringLiteralFor("pointcut",adviceAnn,pcLocation);
381 if (pointcutExpression == null) pointcutExpression = getStringLiteralFor("value",adviceAnn,pcLocation);
383 ISourceContext context = new EclipseSourceContext(unit.compilationResult,pcLocation[0]);
384 Pointcut pc = new PatternParser(pointcutExpression,context).parsePointcut();
385 FormalBinding[] bindings = buildFormalAdviceBindingsFrom(methodDeclaration);
386 pc.resolve(new EclipseScope(bindings,methodDeclaration.scope));
387 EclipseFactory factory = EclipseFactory.fromScopeLookupEnvironment(methodDeclaration.scope);
388 // now create a ResolvedPointcutDefinition,make an attribute out of it, and add it to the method
389 UnresolvedType[] paramTypes = new UnresolvedType[bindings.length];
390 for (int i = 0; i < paramTypes.length; i++) paramTypes[i] = bindings[i].getType();
391 ResolvedPointcutDefinition resPcutDef =
392 new ResolvedPointcutDefinition(
393 factory.fromBinding(((TypeDeclaration)typeStack.peek()).binding),
394 methodDeclaration.modifiers,
399 AjAttribute attr = new AjAttribute.PointcutDeclarationAttribute(resPcutDef);
400 ((AjMethodDeclaration)methodDeclaration).addAttribute(new EclipseAttributeAdapter(attr));
401 } catch(ParserException pEx) {
402 methodDeclaration.scope.problemReporter().parseError(
403 pcLocation[0] + pEx.getLocation().getStart(),
404 pcLocation[0] + pEx.getLocation().getEnd() ,
406 pointcutExpression.toCharArray(),
408 new String[] {pEx.getMessage()});
412 private void ensureVoidReturnType(MethodDeclaration methodDeclaration) {
413 boolean returnsVoid = true;
414 if ((methodDeclaration.returnType instanceof SingleTypeReference)) {
415 SingleTypeReference retType = (SingleTypeReference) methodDeclaration.returnType;
416 if (!CharOperation.equals(voidType,retType.token)) {
423 methodDeclaration.scope.problemReporter().signalError(methodDeclaration.returnType.sourceStart,
424 methodDeclaration.returnType.sourceEnd,
425 "This advice must return void");
429 private FormalBinding[] buildFormalAdviceBindingsFrom(MethodDeclaration mDecl) {
430 if (mDecl.arguments == null) return new FormalBinding[0];
431 if (mDecl.binding == null) return new FormalBinding[0];
432 EclipseFactory factory = EclipseFactory.fromScopeLookupEnvironment(mDecl.scope);
433 String extraArgName = maybeGetExtraArgName();
434 if (extraArgName == null) extraArgName = "";
435 FormalBinding[] ret = new FormalBinding[mDecl.arguments.length];
436 for (int i = 0; i < mDecl.arguments.length; i++) {
437 Argument arg = mDecl.arguments[i];
438 String name = new String(arg.name);
439 TypeBinding argTypeBinding = mDecl.binding.parameters[i];
440 UnresolvedType type = factory.fromBinding(argTypeBinding);
441 if (CharOperation.equals(joinPoint,argTypeBinding.signature()) ||
442 CharOperation.equals(joinPointStaticPart,argTypeBinding.signature()) ||
443 CharOperation.equals(joinPointEnclosingStaticPart,argTypeBinding.signature()) ||
444 CharOperation.equals(proceedingJoinPoint,argTypeBinding.signature()) ||
445 name.equals(extraArgName)) {
446 ret[i] = new FormalBinding.ImplicitFormalBinding(type,name,i);
448 ret[i] = new FormalBinding(type, name, i, arg.sourceStart, arg.sourceEnd, "unknown");
454 private String maybeGetExtraArgName() {
455 String argName = null;
456 if (ajAnnotations.adviceKind == AdviceKind.AfterReturning) {
457 argName = getStringLiteralFor("returning",ajAnnotations.adviceAnnotation,new int[2]);
458 } else if (ajAnnotations.adviceKind == AdviceKind.AfterThrowing) {
459 argName = getStringLiteralFor("throwing",ajAnnotations.adviceAnnotation,new int[2]);
464 private String getStringLiteralFor(String memberName, Annotation inAnnotation, int[] location) {
465 if (inAnnotation instanceof SingleMemberAnnotation && memberName.equals("value")) {
466 SingleMemberAnnotation sma = (SingleMemberAnnotation) inAnnotation;
467 if (sma.memberValue instanceof StringLiteral) {
468 StringLiteral sv = (StringLiteral) sma.memberValue;
469 location[0] = sv.sourceStart;
470 location[1] = sv.sourceEnd;
471 return new String(sv.source());
474 if (! (inAnnotation instanceof NormalAnnotation)) return null;
475 NormalAnnotation ann = (NormalAnnotation) inAnnotation;
476 MemberValuePair[] mvps = ann.memberValuePairs;
477 if (mvps == null) return null;
478 for (int i = 0; i < mvps.length; i++) {
479 if (CharOperation.equals(memberName.toCharArray(),mvps[i].name)) {
480 if (mvps[i].value instanceof StringLiteral) {
481 StringLiteral sv = (StringLiteral) mvps[i].value;
482 location[0] = sv.sourceStart;
483 location[1] = sv.sourceEnd;
484 return new String(sv.source());
491 private void convertToPointcutDeclaration(MethodDeclaration methodDeclaration, ClassScope scope) {
492 TypeDeclaration typeDecl = (TypeDeclaration) typeStack.peek();
493 if (typeDecl.binding != null) {
494 if (!typeDecl.binding.isClass()) {
495 methodDeclaration.scope.problemReporter()
496 .signalError(methodDeclaration.sourceStart,methodDeclaration.sourceEnd,"pointcuts can only be declared in a class or an aspect");
500 if (methodDeclaration.thrownExceptions != null && methodDeclaration.thrownExceptions.length > 0) {
501 methodDeclaration.scope.problemReporter()
502 .signalError(methodDeclaration.sourceStart,methodDeclaration.sourceEnd,"pointcuts cannot throw exceptions!");
505 PointcutDeclaration pcDecl = new PointcutDeclaration(unit.compilationResult);
506 copyAllFields(methodDeclaration,pcDecl);
508 if (ajAnnotations.hasAdviceAnnotation) {
509 methodDeclaration.scope.problemReporter().disallowedTargetForAnnotation(ajAnnotations.adviceAnnotation);
511 if (ajAnnotations.hasAspectAnnotation) {
512 methodDeclaration.scope.problemReporter().disallowedTargetForAnnotation(ajAnnotations.aspectAnnotation);
514 if (ajAnnotations.hasAdviceNameAnnotation) {
515 methodDeclaration.scope.problemReporter().disallowedTargetForAnnotation(ajAnnotations.adviceNameAnnotation);
518 boolean noValueSupplied=true;
519 boolean containsIfPcd = false;
520 int[] pcLocation = new int[2];
521 String pointcutExpression = getStringLiteralFor("value",ajAnnotations.pointcutAnnotation,pcLocation);
523 ISourceContext context = new EclipseSourceContext(unit.compilationResult,pcLocation[0]);
524 Pointcut pc = null;//abstract
525 if (pointcutExpression == null || pointcutExpression.length() == 0) {
526 noValueSupplied=true; // matches nothing pointcut
528 noValueSupplied=false;
529 pc = new PatternParser(pointcutExpression,context).parsePointcut();
531 pcDecl.pointcutDesignator = (pc==null)?null:new PointcutDesignator(pc);
532 pcDecl.setGenerateSyntheticPointcutMethod();
533 TypeDeclaration onType = (TypeDeclaration) typeStack.peek();
534 pcDecl.postParse(onType);
535 // EclipseFactory factory = EclipseFactory.fromScopeLookupEnvironment(methodDeclaration.scope);
536 // int argsLength = methodDeclaration.arguments == null ? 0 : methodDeclaration.arguments.length;
537 FormalBinding[] bindings = buildFormalAdviceBindingsFrom(methodDeclaration);
538 // FormalBinding[] bindings = new FormalBinding[argsLength];
539 // for (int i = 0, len = bindings.length; i < len; i++) {
540 // Argument arg = methodDeclaration.arguments[i];
541 // String name = new String(arg.name);
542 // UnresolvedType type = factory.fromBinding(methodDeclaration.binding.parameters[i]);
543 // bindings[i] = new FormalBinding(type, name, i, arg.sourceStart, arg.sourceEnd, "unknown");
545 swap(onType,methodDeclaration,pcDecl);
548 pc.resolve(new EclipseScope(bindings,methodDeclaration.scope));
549 HasIfPCDVisitor ifFinder = new HasIfPCDVisitor();
550 pc.traverse(ifFinder, null);
551 containsIfPcd = ifFinder.containsIfPcd;
553 } catch(ParserException pEx) {
554 methodDeclaration.scope.problemReporter().parseError(
555 pcLocation[0] + pEx.getLocation().getStart(),
556 pcLocation[0] + pEx.getLocation().getEnd() ,
558 pointcutExpression.toCharArray(),
560 new String[] {pEx.getMessage()});
563 boolean returnsVoid = false;
564 boolean returnsBoolean = false;
565 if ((methodDeclaration.returnType instanceof SingleTypeReference)) {
566 SingleTypeReference retType = (SingleTypeReference) methodDeclaration.returnType;
567 if (CharOperation.equals(voidType,retType.token)) returnsVoid = true;
568 if (CharOperation.equals(booleanType,retType.token)) returnsBoolean = true;
570 if (!returnsVoid && !containsIfPcd) {
571 methodDeclaration.scope.problemReporter().signalError(methodDeclaration.returnType.sourceStart,
572 methodDeclaration.returnType.sourceEnd,
573 "Methods annotated with @Pointcut must return void unless the pointcut contains an if() expression");
575 if (!returnsBoolean && containsIfPcd) {
576 methodDeclaration.scope.problemReporter().signalError(methodDeclaration.returnType.sourceStart,
577 methodDeclaration.returnType.sourceEnd,
578 "Methods annotated with @Pointcut must return boolean when the pointcut contains an if() expression");
581 if (methodDeclaration.statements != null && methodDeclaration.statements.length > 0 && !containsIfPcd) {
582 methodDeclaration.scope.problemReporter().signalError(methodDeclaration.returnType.sourceStart,
583 methodDeclaration.returnType.sourceEnd,
584 "Pointcuts without an if() expression should have an empty method body");
587 if (pcDecl.pointcutDesignator == null) {
588 if (Modifier.isAbstract(methodDeclaration.modifiers)
589 || noValueSupplied // this is a matches nothing pointcut
590 //those 2 checks makes sense for aop.xml concretization but NOT for regular abstraction of pointcut
592 //&& (methodDeclaration.arguments == null || methodDeclaration.arguments.length == 0)) {
596 methodDeclaration.scope.problemReporter().signalError(methodDeclaration.returnType.sourceStart,
597 methodDeclaration.returnType.sourceEnd,
598 "Method annotated with @Pointcut() for abstract pointcut must be abstract");
600 } else if (Modifier.isAbstract(methodDeclaration.modifiers)) {
601 methodDeclaration.scope.problemReporter().signalError(methodDeclaration.returnType.sourceStart,
602 methodDeclaration.returnType.sourceEnd,
603 "Method annotated with non abstract @Pointcut(\""+pointcutExpression+"\") is abstract");
607 private void copyAllFields(MethodDeclaration from, MethodDeclaration to) {
608 to.annotations = from.annotations;
609 to.arguments = from.arguments;
610 to.binding = from.binding;
612 to.bodyEnd = from.bodyEnd;
613 to.bodyStart = from.bodyStart;
614 to.declarationSourceEnd = from.declarationSourceEnd;
615 to.declarationSourceStart = from.declarationSourceStart;
616 to.errorInSignature = from.errorInSignature;
617 to.explicitDeclarations = from.explicitDeclarations;
618 to.ignoreFurtherInvestigation = from.ignoreFurtherInvestigation;
619 to.javadoc = from.javadoc;
620 to.modifiers = from.modifiers;
621 to.modifiersSourceStart = from.modifiersSourceStart;
622 to.needFreeReturn = from.needFreeReturn;
623 to.returnType = from.returnType;
624 to.scope = from.scope;
625 to.selector = from.selector;
626 to.sourceEnd = from.sourceEnd;
627 to.sourceStart = from.sourceStart;
628 to.statements = from.statements;
629 to.thrownExceptions = from.thrownExceptions;
630 to.typeParameters = from.typeParameters;
633 private void swap(TypeDeclaration inType, MethodDeclaration thisDeclaration, MethodDeclaration forThatDeclaration) {
634 for (int i = 0; i < inType.methods.length; i++) {
635 if (inType.methods[i] == thisDeclaration) {
636 inType.methods[i] = forThatDeclaration;
642 private static class AspectJAnnotations {
643 boolean hasAdviceAnnotation = false;
644 boolean hasPointcutAnnotation = false;
645 boolean hasAspectAnnotation = false;
646 boolean hasAdviceNameAnnotation = false;
647 boolean hasDeclareParents = false;
648 boolean hasMultipleAdviceAnnotations = false;
649 boolean hasMultiplePointcutAnnotations = false;
650 boolean hasMultipleAspectAnnotations = false;
652 AdviceKind adviceKind = null;
653 Annotation adviceAnnotation = null;
654 Annotation pointcutAnnotation = null;
655 Annotation aspectAnnotation = null;
656 Annotation adviceNameAnnotation = null;
658 Annotation duplicateAdviceAnnotation = null;
659 Annotation duplicatePointcutAnnotation = null;
660 Annotation duplicateAspectAnnotation = null;
662 public AspectJAnnotations(Annotation[] annotations) {
663 if (annotations == null) return;
664 for (int i = 0; i < annotations.length; i++) {
665 if (annotations[i].resolvedType == null) continue; // user messed up annotation declaration
666 char[] sig = annotations[i].resolvedType.signature();
667 if (CharOperation.equals(afterAdviceSig,sig)) {
668 adviceKind = AdviceKind.After;
669 addAdviceAnnotation(annotations[i]);
670 } else if (CharOperation.equals(afterReturningAdviceSig,sig)) {
671 adviceKind = AdviceKind.AfterReturning;
672 addAdviceAnnotation(annotations[i]);
673 } else if (CharOperation.equals(afterThrowingAdviceSig,sig)) {
674 adviceKind = AdviceKind.AfterThrowing;
675 addAdviceAnnotation(annotations[i]);
676 } else if (CharOperation.equals(beforeAdviceSig,sig)) {
677 adviceKind = AdviceKind.Before;
678 addAdviceAnnotation(annotations[i]);
679 } else if (CharOperation.equals(aroundAdviceSig,sig)) {
680 adviceKind = AdviceKind.Around;
681 addAdviceAnnotation(annotations[i]);
682 } else if (CharOperation.equals(adviceNameSig,sig)) {
683 hasAdviceNameAnnotation = true;
684 adviceNameAnnotation = annotations[i];
685 } else if (CharOperation.equals(declareParentsSig,sig)) {
686 hasDeclareParents = true;
687 } else if (CharOperation.equals(aspectSig,sig)) {
688 if (hasAspectAnnotation) {
689 hasMultipleAspectAnnotations = true;
690 duplicateAspectAnnotation = annotations[i];
692 hasAspectAnnotation = true;
693 aspectAnnotation = annotations[i];
695 } else if (CharOperation.equals(pointcutSig,sig)) {
696 if (hasPointcutAnnotation) {
697 hasMultiplePointcutAnnotations = true;
698 duplicatePointcutAnnotation = annotations[i];
700 hasPointcutAnnotation = true;
701 pointcutAnnotation = annotations[i];
708 public boolean hasAspectJAnnotations() {
709 return hasAdviceAnnotation || hasPointcutAnnotation || hasAdviceNameAnnotation || hasAspectAnnotation;
712 private void addAdviceAnnotation(Annotation annotation) {
713 if (!hasAdviceAnnotation) {
714 hasAdviceAnnotation = true;
715 adviceAnnotation = annotation;
717 hasMultipleAdviceAnnotations = true;
718 duplicateAdviceAnnotation = annotation;
723 private static class HasIfPCDVisitor extends AbstractPatternNodeVisitor {
724 public boolean containsIfPcd = false;
726 public Object visit(IfPointcut node, Object data) {
727 containsIfPcd = true;