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.MemberValuePair;
30 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
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.lookup.BlockScope;
38 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ClassScope;
39 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope;
40 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
41 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
42 import org.aspectj.weaver.AdviceKind;
43 import org.aspectj.weaver.AjAttribute;
44 import org.aspectj.weaver.ISourceContext;
45 import org.aspectj.weaver.ResolvedPointcutDefinition;
46 import org.aspectj.weaver.UnresolvedType;
47 import org.aspectj.weaver.patterns.AbstractPatternNodeVisitor;
48 import org.aspectj.weaver.patterns.FormalBinding;
49 import org.aspectj.weaver.patterns.IfPointcut;
50 import org.aspectj.weaver.patterns.ParserException;
51 import org.aspectj.weaver.patterns.PatternParser;
52 import org.aspectj.weaver.patterns.Pointcut;
54 public class ValidateAtAspectJAnnotationsVisitor extends ASTVisitor {
56 private static final char[] beforeAdviceSig = "Lorg/aspectj/lang/annotation/Before;".toCharArray();
57 private static final char[] afterAdviceSig = "Lorg/aspectj/lang/annotation/After;".toCharArray();
58 private static final char[] afterReturningAdviceSig = "Lorg/aspectj/lang/annotation/AfterReturning;".toCharArray();
59 private static final char[] afterThrowingAdviceSig = "Lorg/aspectj/lang/annotation/AfterThrowing;".toCharArray();
60 private static final char[] aroundAdviceSig = "Lorg/aspectj/lang/annotation/Around;".toCharArray();
61 private static final char[] pointcutSig = "Lorg/aspectj/lang/annotation/Pointcut;".toCharArray();
62 private static final char[] aspectSig = "Lorg/aspectj/lang/annotation/Aspect;".toCharArray();
63 private static final char[] adviceNameSig = "Lorg/aspectj/lang/annotation/AdviceName;".toCharArray();
64 private static final char[] orgAspectJLangAnnotation = "org/aspectj/lang/annotation/".toCharArray();
65 private static final char[] voidType = "void".toCharArray();
66 private static final char[] booleanType = "boolean".toCharArray();
67 private static final char[] joinPoint = "Lorg/aspectj/lang/JoinPoint;".toCharArray();
68 private static final char[] joinPointStaticPart = "Lorg/aspectj/lang/JoinPoint$StaticPart;".toCharArray();
69 private static final char[] joinPointEnclosingStaticPart = "Lorg/aspectj/lang/JoinPoint$EnclosingStaticPart;".toCharArray();
70 private static final char[] proceedingJoinPoint = "Lorg/aspectj/lang/ProceedingJoinPoint;".toCharArray();
71 private static final char[][] adviceSigs = new char[][] {beforeAdviceSig,afterAdviceSig,afterReturningAdviceSig,afterThrowingAdviceSig,aroundAdviceSig};
74 private CompilationUnitDeclaration unit;
75 private Stack typeStack = new Stack();
76 private AspectJAnnotations ajAnnotations;
78 public ValidateAtAspectJAnnotationsVisitor(CompilationUnitDeclaration unit) {
82 public boolean visit(TypeDeclaration localTypeDeclaration, BlockScope scope) {
83 typeStack.push(localTypeDeclaration);
84 ajAnnotations = new AspectJAnnotations(localTypeDeclaration.annotations);
85 checkTypeDeclaration(localTypeDeclaration);
89 public void endVisit(TypeDeclaration localTypeDeclaration,BlockScope scope) {
93 public boolean visit(TypeDeclaration memberTypeDeclaration,ClassScope scope) {
94 typeStack.push(memberTypeDeclaration);
95 ajAnnotations = new AspectJAnnotations(memberTypeDeclaration.annotations);
96 checkTypeDeclaration(memberTypeDeclaration);
100 public void endVisit(TypeDeclaration memberTypeDeclaration,ClassScope scope) {
104 public boolean visit(TypeDeclaration typeDeclaration, CompilationUnitScope scope) {
105 typeStack.push(typeDeclaration);
106 ajAnnotations = new AspectJAnnotations(typeDeclaration.annotations);
107 checkTypeDeclaration(typeDeclaration);
111 public void endVisit(TypeDeclaration typeDeclaration,CompilationUnitScope scope) {
115 private void checkTypeDeclaration(TypeDeclaration typeDecl) {
116 ContextToken tok = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.VALIDATING_AT_ASPECTJ_ANNOTATIONS, typeDecl.name);
117 if (!(typeDecl instanceof AspectDeclaration)) {
118 if (ajAnnotations.hasAspectAnnotation) {
119 validateAspectDeclaration(typeDecl);
121 // check that class doesn't extend aspect
122 TypeReference parentRef = typeDecl.superclass;
123 if (parentRef != null) {
124 TypeBinding parentBinding = parentRef.resolvedType;
125 if (parentBinding instanceof SourceTypeBinding) {
126 SourceTypeBinding parentSTB = (SourceTypeBinding) parentBinding;
127 if (parentSTB.scope != null) {
128 TypeDeclaration parentDecl = parentSTB.scope.referenceContext;
129 if (isAspect(parentDecl)) {
130 typeDecl.scope.problemReporter().signalError(typeDecl.sourceStart,typeDecl.sourceEnd,"a class cannot extend an aspect");
137 // check that aspect doesn't have @Aspect annotation, we've already added on ourselves.
138 if (ajAnnotations.hasMultipleAspectAnnotations) {
139 typeDecl.scope.problemReporter().signalError(
140 typeDecl.sourceStart,
142 "aspects cannot have @Aspect annotation"
146 CompilationAndWeavingContext.leavingPhase(tok);
149 public boolean visit(MethodDeclaration methodDeclaration, ClassScope scope) {
150 ContextToken tok = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.VALIDATING_AT_ASPECTJ_ANNOTATIONS, methodDeclaration.selector);
151 ajAnnotations = new AspectJAnnotations(methodDeclaration.annotations);
152 if (!methodDeclaration.getClass().equals(AjMethodDeclaration.class)) {
153 // simply test for innapropriate use of annotations on code-style members
154 if (methodDeclaration instanceof PointcutDeclaration) {
155 if (ajAnnotations.hasMultiplePointcutAnnotations ||
156 ajAnnotations.hasAdviceAnnotation ||
157 ajAnnotations.hasAspectAnnotation ||
158 ajAnnotations.hasAdviceNameAnnotation) {
159 methodDeclaration.scope.problemReporter().signalError(
160 methodDeclaration.sourceStart,
161 methodDeclaration.sourceEnd,
162 "@AspectJ annotations cannot be declared on this aspect member");
164 } else if (methodDeclaration instanceof AdviceDeclaration) {
165 if (ajAnnotations.hasMultipleAdviceAnnotations ||
166 ajAnnotations.hasAspectAnnotation ||
167 ajAnnotations.hasPointcutAnnotation) {
168 methodDeclaration.scope.problemReporter().signalError(
169 methodDeclaration.sourceStart,
170 methodDeclaration.sourceEnd,
171 "Only @AdviceName AspectJ annotation allowed on advice");
174 if (ajAnnotations.hasAspectJAnnotations()) {
175 methodDeclaration.scope.problemReporter().signalError(
176 methodDeclaration.sourceStart,
177 methodDeclaration.sourceEnd,
178 "@AspectJ annotations cannot be declared on this aspect member");
181 CompilationAndWeavingContext.leavingPhase(tok);
185 if (ajAnnotations.hasAdviceAnnotation) {
186 validateAdvice(methodDeclaration);
187 } else if (ajAnnotations.hasPointcutAnnotation) {
188 convertToPointcutDeclaration(methodDeclaration,scope);
190 CompilationAndWeavingContext.leavingPhase(tok);
194 private boolean isAspectJAnnotation(Annotation ann) {
195 if (ann.resolvedType == null) return false;
196 char[] sig = ann.resolvedType.signature();
197 return CharOperation.contains(orgAspectJLangAnnotation, sig);
200 private boolean insideAspect() {
201 if (typeStack.empty()) return false;
202 TypeDeclaration typeDecl = (TypeDeclaration) typeStack.peek();
203 return isAspect(typeDecl);
206 private boolean isAspect(TypeDeclaration typeDecl) {
207 if (typeDecl instanceof AspectDeclaration) return true;
208 return new AspectJAnnotations(typeDecl.annotations).hasAspectAnnotation;
212 * aspect must be public
213 * nested aspect must be static
214 * cannot extend a concrete aspect
215 * pointcut in perclause must be good.
217 private void validateAspectDeclaration(TypeDeclaration typeDecl) {
218 if (typeStack.size() > 1) {
219 // it's a nested aspect
220 if (!Modifier.isStatic(typeDecl.modifiers)) {
221 typeDecl.scope.problemReporter().signalError(typeDecl.sourceStart, typeDecl.sourceEnd, "inner aspects must be static");
226 SourceTypeBinding binding = typeDecl.binding;
227 if (binding != null) {
228 if (binding.isEnum() || binding.isInterface() || binding.isAnnotationType()) {
229 typeDecl.scope.problemReporter().signalError(typeDecl.sourceStart,typeDecl.sourceEnd,"only classes can have an @Aspect annotation");
233 //FIXME AV - do we really want that
234 // if (!Modifier.isPublic(typeDecl.modifiers)) {
235 // typeDecl.scope.problemReporter().signalError(typeDecl.sourceStart,typeDecl.sourceEnd,"@Aspect class must be public");
238 TypeReference parentRef = typeDecl.superclass;
239 if (parentRef != null) {
240 TypeBinding parentBinding = parentRef.resolvedType;
241 if (parentBinding instanceof SourceTypeBinding) {
242 SourceTypeBinding parentSTB = (SourceTypeBinding) parentBinding;
243 if (parentSTB.scope!=null) { // scope is null if its a binarytypebinding (in AJ world, thats a subclass of SourceTypeBinding)
244 TypeDeclaration parentDecl = parentSTB.scope.referenceContext;
245 if (isAspect(parentDecl) && !Modifier.isAbstract(parentDecl.modifiers)) {
246 typeDecl.scope.problemReporter().signalError(typeDecl.sourceStart,typeDecl.sourceEnd,"cannot extend a concrete aspect");
252 Annotation aspectAnnotation = ajAnnotations.aspectAnnotation;
254 int[] pcLoc = new int[2];
255 String perClause = getStringLiteralFor("value", aspectAnnotation, pcLoc);
256 AspectDeclaration aspectDecl = new AspectDeclaration(typeDecl.compilationResult);
259 if (perClause != null && !perClause.equals("")) {
260 ISourceContext context = new EclipseSourceContext(unit.compilationResult,pcLoc[0]);
261 Pointcut pc = new PatternParser(perClause,context).maybeParsePerClause();
262 FormalBinding[] bindings = new FormalBinding[0];
263 if (pc != null) pc.resolve(new EclipseScope(bindings,typeDecl.scope));
265 } catch(ParserException pEx) {
266 typeDecl.scope.problemReporter().parseError(
267 pcLoc[0] + pEx.getLocation().getStart(),
268 pcLoc[0] + pEx.getLocation().getEnd() ,
270 perClause.toCharArray(),
272 new String[] {pEx.getMessage()});
277 * 1) Advice must be public
278 * 2) Advice must have a void return type if not around advice
279 * 3) Advice must not have any other @AspectJ annotations
280 * 4) After throwing advice must declare the thrown formal
281 * 5) After returning advice must declare the returning formal
283 private void validateAdvice(MethodDeclaration methodDeclaration) {
285 if (!insideAspect()) {
286 methodDeclaration.scope.problemReporter().signalError(methodDeclaration.sourceStart,
287 methodDeclaration.sourceEnd,
288 "Advice must be declared inside an aspect type");
291 if (!Modifier.isPublic(methodDeclaration.modifiers)) {
292 methodDeclaration.scope.problemReporter()
293 .signalError(methodDeclaration.sourceStart,methodDeclaration.sourceEnd,"advice must be public");
296 if (ajAnnotations.hasMultipleAdviceAnnotations) {
297 methodDeclaration.scope.problemReporter().disallowedTargetForAnnotation(ajAnnotations.duplicateAdviceAnnotation);
299 if (ajAnnotations.hasPointcutAnnotation) {
300 methodDeclaration.scope.problemReporter().disallowedTargetForAnnotation(ajAnnotations.pointcutAnnotation);
302 if (ajAnnotations.hasAspectAnnotation) {
303 methodDeclaration.scope.problemReporter().disallowedTargetForAnnotation(ajAnnotations.aspectAnnotation);
305 if (ajAnnotations.hasAdviceNameAnnotation) {
306 methodDeclaration.scope.problemReporter().disallowedTargetForAnnotation(ajAnnotations.adviceNameAnnotation);
309 if (ajAnnotations.adviceKind != AdviceKind.Around) {
310 ensureVoidReturnType(methodDeclaration);
313 if (ajAnnotations.adviceKind == AdviceKind.AfterThrowing) {
314 int[] throwingLocation = new int[2];
315 String thrownFormal = getStringLiteralFor("throwing",ajAnnotations.adviceAnnotation,throwingLocation);
316 if (thrownFormal != null) {
317 Argument[] arguments = methodDeclaration.arguments;
318 if (!toArgumentNames(methodDeclaration.arguments).contains(thrownFormal)) {
319 methodDeclaration.scope.problemReporter()
320 .signalError(methodDeclaration.sourceStart,methodDeclaration.sourceEnd,"throwing formal '" + thrownFormal + "' must be declared as a parameter in the advice signature");
325 if (ajAnnotations.adviceKind == AdviceKind.AfterReturning) {
326 int[] throwingLocation = new int[2];
327 String returningFormal = getStringLiteralFor("returning",ajAnnotations.adviceAnnotation,throwingLocation);
328 if (returningFormal != null) {
329 if (!toArgumentNames(methodDeclaration.arguments).contains(returningFormal)) {
330 methodDeclaration.scope.problemReporter()
331 .signalError(methodDeclaration.sourceStart,methodDeclaration.sourceEnd,"returning formal '" + returningFormal + "' must be declared as a parameter in the advice signature");
336 resolveAndSetPointcut(methodDeclaration, ajAnnotations.adviceAnnotation);
341 * Get the argument names as a string list
343 * @return argument names (possibly empty)
345 private List toArgumentNames(Argument[] arguments) {
346 List names = new ArrayList();
347 if (arguments == null) {
350 for (int i = 0; i < arguments.length; i++) {
351 names.add(new String(arguments[i].name));
357 private void resolveAndSetPointcut(MethodDeclaration methodDeclaration, Annotation adviceAnn) {
358 int[] pcLocation = new int[2];
359 String pointcutExpression = getStringLiteralFor("pointcut",adviceAnn,pcLocation);
360 if (pointcutExpression == null) pointcutExpression = getStringLiteralFor("value",adviceAnn,pcLocation);
362 ISourceContext context = new EclipseSourceContext(unit.compilationResult,pcLocation[0]);
363 Pointcut pc = new PatternParser(pointcutExpression,context).parsePointcut();
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 it, and add it to the method
368 UnresolvedType[] paramTypes = new UnresolvedType[bindings.length];
369 for (int i = 0; i < paramTypes.length; i++) paramTypes[i] = bindings[i].getType();
370 ResolvedPointcutDefinition resPcutDef =
371 new ResolvedPointcutDefinition(
372 factory.fromBinding(((TypeDeclaration)typeStack.peek()).binding),
373 methodDeclaration.modifiers,
378 AjAttribute attr = new AjAttribute.PointcutDeclarationAttribute(resPcutDef);
379 ((AjMethodDeclaration)methodDeclaration).addAttribute(new EclipseAttributeAdapter(attr));
380 } catch(ParserException pEx) {
381 methodDeclaration.scope.problemReporter().parseError(
382 pcLocation[0] + pEx.getLocation().getStart(),
383 pcLocation[0] + pEx.getLocation().getEnd() ,
385 pointcutExpression.toCharArray(),
387 new String[] {pEx.getMessage()});
391 private void ensureVoidReturnType(MethodDeclaration methodDeclaration) {
392 boolean returnsVoid = true;
393 if ((methodDeclaration.returnType instanceof SingleTypeReference)) {
394 SingleTypeReference retType = (SingleTypeReference) methodDeclaration.returnType;
395 if (!CharOperation.equals(voidType,retType.token)) {
402 methodDeclaration.scope.problemReporter().signalError(methodDeclaration.returnType.sourceStart,
403 methodDeclaration.returnType.sourceEnd,
404 "This advice must return void");
408 private FormalBinding[] buildFormalAdviceBindingsFrom(MethodDeclaration mDecl) {
409 if (mDecl.arguments == null) return new FormalBinding[0];
410 EclipseFactory factory = EclipseFactory.fromScopeLookupEnvironment(mDecl.scope);
411 String extraArgName = maybeGetExtraArgName();
412 if (extraArgName == null) extraArgName = "";
413 FormalBinding[] ret = new FormalBinding[mDecl.arguments.length];
414 for (int i = 0; i < mDecl.arguments.length; i++) {
415 Argument arg = mDecl.arguments[i];
416 String name = new String(arg.name);
417 TypeBinding argTypeBinding = mDecl.binding.parameters[i];
418 UnresolvedType type = factory.fromBinding(argTypeBinding);
419 if (CharOperation.equals(joinPoint,argTypeBinding.signature()) ||
420 CharOperation.equals(joinPointStaticPart,argTypeBinding.signature()) ||
421 CharOperation.equals(joinPointEnclosingStaticPart,argTypeBinding.signature()) ||
422 CharOperation.equals(proceedingJoinPoint,argTypeBinding.signature()) ||
423 name.equals(extraArgName)) {
424 ret[i] = new FormalBinding.ImplicitFormalBinding(type,name,i);
426 ret[i] = new FormalBinding(type, name, i, arg.sourceStart, arg.sourceEnd, "unknown");
432 private String maybeGetExtraArgName() {
433 String argName = null;
434 if (ajAnnotations.adviceKind == AdviceKind.AfterReturning) {
435 argName = getStringLiteralFor("returning",ajAnnotations.adviceAnnotation,new int[2]);
436 } else if (ajAnnotations.adviceKind == AdviceKind.AfterThrowing) {
437 argName = getStringLiteralFor("throwing",ajAnnotations.adviceAnnotation,new int[2]);
442 private String getStringLiteralFor(String memberName, Annotation inAnnotation, int[] location) {
443 if (inAnnotation instanceof SingleMemberAnnotation && memberName.equals("value")) {
444 SingleMemberAnnotation sma = (SingleMemberAnnotation) inAnnotation;
445 if (sma.memberValue instanceof StringLiteral) {
446 StringLiteral sv = (StringLiteral) sma.memberValue;
447 location[0] = sv.sourceStart;
448 location[1] = sv.sourceEnd;
449 return new String(sv.source());
452 if (! (inAnnotation instanceof NormalAnnotation)) return null;
453 NormalAnnotation ann = (NormalAnnotation) inAnnotation;
454 MemberValuePair[] mvps = ann.memberValuePairs;
455 if (mvps == null) return null;
456 for (int i = 0; i < mvps.length; i++) {
457 if (CharOperation.equals(memberName.toCharArray(),mvps[i].name)) {
458 if (mvps[i].value instanceof StringLiteral) {
459 StringLiteral sv = (StringLiteral) mvps[i].value;
460 location[0] = sv.sourceStart;
461 location[1] = sv.sourceEnd;
462 return new String(sv.source());
469 private void convertToPointcutDeclaration(MethodDeclaration methodDeclaration, ClassScope scope) {
470 TypeDeclaration typeDecl = (TypeDeclaration) typeStack.peek();
471 if (typeDecl.binding != null) {
472 if (!typeDecl.binding.isClass()) {
473 methodDeclaration.scope.problemReporter()
474 .signalError(methodDeclaration.sourceStart,methodDeclaration.sourceEnd,"pointcuts can only be declared in a class or an aspect");
478 if (methodDeclaration.thrownExceptions != null && methodDeclaration.thrownExceptions.length > 0) {
479 methodDeclaration.scope.problemReporter()
480 .signalError(methodDeclaration.sourceStart,methodDeclaration.sourceEnd,"pointcuts cannot throw exceptions!");
483 PointcutDeclaration pcDecl = new PointcutDeclaration(unit.compilationResult);
484 copyAllFields(methodDeclaration,pcDecl);
486 if (ajAnnotations.hasAdviceAnnotation) {
487 methodDeclaration.scope.problemReporter().disallowedTargetForAnnotation(ajAnnotations.adviceAnnotation);
489 if (ajAnnotations.hasAspectAnnotation) {
490 methodDeclaration.scope.problemReporter().disallowedTargetForAnnotation(ajAnnotations.aspectAnnotation);
492 if (ajAnnotations.hasAdviceNameAnnotation) {
493 methodDeclaration.scope.problemReporter().disallowedTargetForAnnotation(ajAnnotations.adviceNameAnnotation);
496 boolean noValueSupplied=true;
497 boolean containsIfPcd = false;
498 int[] pcLocation = new int[2];
499 String pointcutExpression = getStringLiteralFor("value",ajAnnotations.pointcutAnnotation,pcLocation);
501 ISourceContext context = new EclipseSourceContext(unit.compilationResult,pcLocation[0]);
502 Pointcut pc = null;//abstract
503 if (pointcutExpression == null || pointcutExpression.length() == 0) {
504 noValueSupplied=true; // matches nothing pointcut
506 noValueSupplied=false;
507 pc = new PatternParser(pointcutExpression,context).parsePointcut();
509 pcDecl.pointcutDesignator = (pc==null)?null:new PointcutDesignator(pc);
510 pcDecl.setGenerateSyntheticPointcutMethod();
511 TypeDeclaration onType = (TypeDeclaration) typeStack.peek();
512 pcDecl.postParse(onType);
513 // EclipseFactory factory = EclipseFactory.fromScopeLookupEnvironment(methodDeclaration.scope);
514 // int argsLength = methodDeclaration.arguments == null ? 0 : methodDeclaration.arguments.length;
515 FormalBinding[] bindings = buildFormalAdviceBindingsFrom(methodDeclaration);
516 // FormalBinding[] bindings = new FormalBinding[argsLength];
517 // for (int i = 0, len = bindings.length; i < len; i++) {
518 // Argument arg = methodDeclaration.arguments[i];
519 // String name = new String(arg.name);
520 // UnresolvedType type = factory.fromBinding(methodDeclaration.binding.parameters[i]);
521 // bindings[i] = new FormalBinding(type, name, i, arg.sourceStart, arg.sourceEnd, "unknown");
523 swap(onType,methodDeclaration,pcDecl);
526 pc.resolve(new EclipseScope(bindings,methodDeclaration.scope));
527 HasIfPCDVisitor ifFinder = new HasIfPCDVisitor();
528 pc.traverse(ifFinder, null);
529 containsIfPcd = ifFinder.containsIfPcd;
531 } catch(ParserException pEx) {
532 methodDeclaration.scope.problemReporter().parseError(
533 pcLocation[0] + pEx.getLocation().getStart(),
534 pcLocation[0] + pEx.getLocation().getEnd() ,
536 pointcutExpression.toCharArray(),
538 new String[] {pEx.getMessage()});
541 boolean returnsVoid = false;
542 boolean returnsBoolean = false;
543 if ((methodDeclaration.returnType instanceof SingleTypeReference)) {
544 SingleTypeReference retType = (SingleTypeReference) methodDeclaration.returnType;
545 if (CharOperation.equals(voidType,retType.token)) returnsVoid = true;
546 if (CharOperation.equals(booleanType,retType.token)) returnsBoolean = true;
548 if (!returnsVoid && !containsIfPcd) {
549 methodDeclaration.scope.problemReporter().signalError(methodDeclaration.returnType.sourceStart,
550 methodDeclaration.returnType.sourceEnd,
551 "Methods annotated with @Pointcut must return void unless the pointcut contains an if() expression");
553 if (!returnsBoolean && containsIfPcd) {
554 methodDeclaration.scope.problemReporter().signalError(methodDeclaration.returnType.sourceStart,
555 methodDeclaration.returnType.sourceEnd,
556 "Methods annotated with @Pointcut must return boolean when the pointcut contains an if() expression");
559 if (methodDeclaration.statements != null && methodDeclaration.statements.length > 0 && !containsIfPcd) {
560 methodDeclaration.scope.problemReporter().signalError(methodDeclaration.returnType.sourceStart,
561 methodDeclaration.returnType.sourceEnd,
562 "Pointcuts without an if() expression should have an empty method body");
565 if (pcDecl.pointcutDesignator == null) {
566 if (Modifier.isAbstract(methodDeclaration.modifiers)
567 || noValueSupplied // this is a matches nothing pointcut
568 //those 2 checks makes sense for aop.xml concretization but NOT for regular abstraction of pointcut
570 //&& (methodDeclaration.arguments == null || methodDeclaration.arguments.length == 0)) {
574 methodDeclaration.scope.problemReporter().signalError(methodDeclaration.returnType.sourceStart,
575 methodDeclaration.returnType.sourceEnd,
576 "Method annotated with @Pointcut() for abstract pointcut must be abstract");
578 } else if (Modifier.isAbstract(methodDeclaration.modifiers)) {
579 methodDeclaration.scope.problemReporter().signalError(methodDeclaration.returnType.sourceStart,
580 methodDeclaration.returnType.sourceEnd,
581 "Method annotated with non abstract @Pointcut(\""+pointcutExpression+"\") is abstract");
585 private void copyAllFields(MethodDeclaration from, MethodDeclaration to) {
586 to.annotations = from.annotations;
587 to.arguments = from.arguments;
588 to.binding = from.binding;
590 to.bodyEnd = from.bodyEnd;
591 to.bodyStart = from.bodyStart;
592 to.declarationSourceEnd = from.declarationSourceEnd;
593 to.declarationSourceStart = from.declarationSourceStart;
594 to.errorInSignature = from.errorInSignature;
595 to.explicitDeclarations = from.explicitDeclarations;
596 to.ignoreFurtherInvestigation = from.ignoreFurtherInvestigation;
597 to.javadoc = from.javadoc;
598 to.modifiers = from.modifiers;
599 to.modifiersSourceStart = from.modifiersSourceStart;
600 to.needFreeReturn = from.needFreeReturn;
601 to.returnType = from.returnType;
602 to.scope = from.scope;
603 to.selector = from.selector;
604 to.sourceEnd = from.sourceEnd;
605 to.sourceStart = from.sourceStart;
606 to.statements = from.statements;
607 to.thrownExceptions = from.thrownExceptions;
608 to.typeParameters = from.typeParameters;
611 private void swap(TypeDeclaration inType, MethodDeclaration thisDeclaration, MethodDeclaration forThatDeclaration) {
612 for (int i = 0; i < inType.methods.length; i++) {
613 if (inType.methods[i] == thisDeclaration) {
614 inType.methods[i] = forThatDeclaration;
620 private static class AspectJAnnotations {
621 boolean hasAdviceAnnotation = false;
622 boolean hasPointcutAnnotation = false;
623 boolean hasAspectAnnotation = false;
624 boolean hasAdviceNameAnnotation = false;
626 boolean hasMultipleAdviceAnnotations = false;
627 boolean hasMultiplePointcutAnnotations = false;
628 boolean hasMultipleAspectAnnotations = false;
630 AdviceKind adviceKind = null;
631 Annotation adviceAnnotation = null;
632 Annotation pointcutAnnotation = null;
633 Annotation aspectAnnotation = null;
634 Annotation adviceNameAnnotation = null;
636 Annotation duplicateAdviceAnnotation = null;
637 Annotation duplicatePointcutAnnotation = null;
638 Annotation duplicateAspectAnnotation = null;
640 public AspectJAnnotations(Annotation[] annotations) {
641 if (annotations == null) return;
642 for (int i = 0; i < annotations.length; i++) {
643 if (annotations[i].resolvedType == null) continue; // user messed up annotation declaration
644 char[] sig = annotations[i].resolvedType.signature();
645 if (CharOperation.equals(afterAdviceSig,sig)) {
646 adviceKind = AdviceKind.After;
647 addAdviceAnnotation(annotations[i]);
648 } else if (CharOperation.equals(afterReturningAdviceSig,sig)) {
649 adviceKind = AdviceKind.AfterReturning;
650 addAdviceAnnotation(annotations[i]);
651 } else if (CharOperation.equals(afterThrowingAdviceSig,sig)) {
652 adviceKind = AdviceKind.AfterThrowing;
653 addAdviceAnnotation(annotations[i]);
654 } else if (CharOperation.equals(beforeAdviceSig,sig)) {
655 adviceKind = AdviceKind.Before;
656 addAdviceAnnotation(annotations[i]);
657 } else if (CharOperation.equals(aroundAdviceSig,sig)) {
658 adviceKind = AdviceKind.Around;
659 addAdviceAnnotation(annotations[i]);
660 } else if (CharOperation.equals(adviceNameSig,sig)) {
661 hasAdviceNameAnnotation = true;
662 adviceNameAnnotation = annotations[i];
663 } else if (CharOperation.equals(aspectSig,sig)) {
664 if (hasAspectAnnotation) {
665 hasMultipleAspectAnnotations = true;
666 duplicateAspectAnnotation = annotations[i];
668 hasAspectAnnotation = true;
669 aspectAnnotation = annotations[i];
671 } else if (CharOperation.equals(pointcutSig,sig)) {
672 if (hasPointcutAnnotation) {
673 hasMultiplePointcutAnnotations = true;
674 duplicatePointcutAnnotation = annotations[i];
676 hasPointcutAnnotation = true;
677 pointcutAnnotation = annotations[i];
684 public boolean hasAspectJAnnotations() {
685 return hasAdviceAnnotation || hasPointcutAnnotation || hasAdviceNameAnnotation || hasAspectAnnotation;
688 private void addAdviceAnnotation(Annotation annotation) {
689 if (!hasAdviceAnnotation) {
690 hasAdviceAnnotation = true;
691 adviceAnnotation = annotation;
693 hasMultipleAdviceAnnotations = true;
694 duplicateAdviceAnnotation = annotation;
699 private static class HasIfPCDVisitor extends AbstractPatternNodeVisitor {
700 public boolean containsIfPcd = false;
702 public Object visit(IfPointcut node, Object data) {
703 containsIfPcd = true;