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 if (methodDeclaration.hasErrors()) {
153 ContextToken tok = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.VALIDATING_AT_ASPECTJ_ANNOTATIONS, methodDeclaration.selector);
154 ajAnnotations = new AspectJAnnotations(methodDeclaration.annotations);
155 if (!methodDeclaration.getClass().equals(AjMethodDeclaration.class)) {
156 // simply test for innapropriate use of annotations on code-style members
157 if (methodDeclaration instanceof PointcutDeclaration) {
158 if (ajAnnotations.hasMultiplePointcutAnnotations ||
159 ajAnnotations.hasAdviceAnnotation ||
160 ajAnnotations.hasAspectAnnotation ||
161 ajAnnotations.hasAdviceNameAnnotation) {
162 methodDeclaration.scope.problemReporter().signalError(
163 methodDeclaration.sourceStart,
164 methodDeclaration.sourceEnd,
165 "@AspectJ annotations cannot be declared on this aspect member");
167 } else if (methodDeclaration instanceof AdviceDeclaration) {
168 if (ajAnnotations.hasMultipleAdviceAnnotations ||
169 ajAnnotations.hasAspectAnnotation ||
170 ajAnnotations.hasPointcutAnnotation) {
171 methodDeclaration.scope.problemReporter().signalError(
172 methodDeclaration.sourceStart,
173 methodDeclaration.sourceEnd,
174 "Only @AdviceName AspectJ annotation allowed on advice");
177 if (ajAnnotations.hasAspectJAnnotations()) {
178 methodDeclaration.scope.problemReporter().signalError(
179 methodDeclaration.sourceStart,
180 methodDeclaration.sourceEnd,
181 "@AspectJ annotations cannot be declared on this aspect member");
184 CompilationAndWeavingContext.leavingPhase(tok);
188 if (ajAnnotations.hasAdviceAnnotation) {
189 validateAdvice(methodDeclaration);
190 } else if (ajAnnotations.hasPointcutAnnotation) {
191 convertToPointcutDeclaration(methodDeclaration,scope);
193 CompilationAndWeavingContext.leavingPhase(tok);
197 private boolean isAspectJAnnotation(Annotation ann) {
198 if (ann.resolvedType == null) return false;
199 char[] sig = ann.resolvedType.signature();
200 return CharOperation.contains(orgAspectJLangAnnotation, sig);
203 private boolean insideAspect() {
204 if (typeStack.empty()) return false;
205 TypeDeclaration typeDecl = (TypeDeclaration) typeStack.peek();
206 return isAspect(typeDecl);
209 private boolean isAspect(TypeDeclaration typeDecl) {
210 if (typeDecl instanceof AspectDeclaration) return true;
211 return new AspectJAnnotations(typeDecl.annotations).hasAspectAnnotation;
215 * aspect must be public
216 * nested aspect must be static
217 * cannot extend a concrete aspect
218 * pointcut in perclause must be good.
220 private void validateAspectDeclaration(TypeDeclaration typeDecl) {
221 if (typeStack.size() > 1) {
222 // it's a nested aspect
223 if (!Modifier.isStatic(typeDecl.modifiers)) {
224 typeDecl.scope.problemReporter().signalError(typeDecl.sourceStart, typeDecl.sourceEnd, "inner aspects must be static");
229 SourceTypeBinding binding = typeDecl.binding;
230 if (binding != null) {
231 if (binding.isEnum() || binding.isInterface() || binding.isAnnotationType()) {
232 typeDecl.scope.problemReporter().signalError(typeDecl.sourceStart,typeDecl.sourceEnd,"only classes can have an @Aspect annotation");
236 //FIXME AV - do we really want that
237 // if (!Modifier.isPublic(typeDecl.modifiers)) {
238 // typeDecl.scope.problemReporter().signalError(typeDecl.sourceStart,typeDecl.sourceEnd,"@Aspect class must be public");
241 TypeReference parentRef = typeDecl.superclass;
242 if (parentRef != null) {
243 TypeBinding parentBinding = parentRef.resolvedType;
244 if (parentBinding instanceof SourceTypeBinding) {
245 SourceTypeBinding parentSTB = (SourceTypeBinding) parentBinding;
246 if (parentSTB.scope!=null) { // scope is null if its a binarytypebinding (in AJ world, thats a subclass of SourceTypeBinding)
247 TypeDeclaration parentDecl = parentSTB.scope.referenceContext;
248 if (isAspect(parentDecl) && !Modifier.isAbstract(parentDecl.modifiers)) {
249 typeDecl.scope.problemReporter().signalError(typeDecl.sourceStart,typeDecl.sourceEnd,"cannot extend a concrete aspect");
255 Annotation aspectAnnotation = ajAnnotations.aspectAnnotation;
257 int[] pcLoc = new int[2];
258 String perClause = getStringLiteralFor("value", aspectAnnotation, pcLoc);
259 AspectDeclaration aspectDecl = new AspectDeclaration(typeDecl.compilationResult);
262 if (perClause != null && !perClause.equals("")) {
263 ISourceContext context = new EclipseSourceContext(unit.compilationResult,pcLoc[0]);
264 Pointcut pc = new PatternParser(perClause,context).maybeParsePerClause();
265 FormalBinding[] bindings = new FormalBinding[0];
266 if (pc != null) pc.resolve(new EclipseScope(bindings,typeDecl.scope));
268 } catch(ParserException pEx) {
269 typeDecl.scope.problemReporter().parseError(
270 pcLoc[0] + pEx.getLocation().getStart(),
271 pcLoc[0] + pEx.getLocation().getEnd() ,
273 perClause.toCharArray(),
275 new String[] {pEx.getMessage()});
280 * 1) Advice must be public
281 * 2) Advice must have a void return type if not around advice
282 * 3) Advice must not have any other @AspectJ annotations
283 * 4) After throwing advice must declare the thrown formal
284 * 5) After returning advice must declare the returning formal
286 private void validateAdvice(MethodDeclaration methodDeclaration) {
288 if (!insideAspect()) {
289 methodDeclaration.scope.problemReporter().signalError(methodDeclaration.sourceStart,
290 methodDeclaration.sourceEnd,
291 "Advice must be declared inside an aspect type");
294 if (!Modifier.isPublic(methodDeclaration.modifiers)) {
295 methodDeclaration.scope.problemReporter()
296 .signalError(methodDeclaration.sourceStart,methodDeclaration.sourceEnd,"advice must be public");
299 if (ajAnnotations.hasMultipleAdviceAnnotations) {
300 methodDeclaration.scope.problemReporter().disallowedTargetForAnnotation(ajAnnotations.duplicateAdviceAnnotation);
302 if (ajAnnotations.hasPointcutAnnotation) {
303 methodDeclaration.scope.problemReporter().disallowedTargetForAnnotation(ajAnnotations.pointcutAnnotation);
305 if (ajAnnotations.hasAspectAnnotation) {
306 methodDeclaration.scope.problemReporter().disallowedTargetForAnnotation(ajAnnotations.aspectAnnotation);
308 if (ajAnnotations.hasAdviceNameAnnotation) {
309 methodDeclaration.scope.problemReporter().disallowedTargetForAnnotation(ajAnnotations.adviceNameAnnotation);
312 if (ajAnnotations.adviceKind != AdviceKind.Around) {
313 ensureVoidReturnType(methodDeclaration);
316 if (ajAnnotations.adviceKind == AdviceKind.AfterThrowing) {
317 int[] throwingLocation = new int[2];
318 String thrownFormal = getStringLiteralFor("throwing",ajAnnotations.adviceAnnotation,throwingLocation);
319 if (thrownFormal != null) {
320 Argument[] arguments = methodDeclaration.arguments;
321 if (!toArgumentNames(methodDeclaration.arguments).contains(thrownFormal)) {
322 methodDeclaration.scope.problemReporter()
323 .signalError(methodDeclaration.sourceStart,methodDeclaration.sourceEnd,"throwing formal '" + thrownFormal + "' must be declared as a parameter in the advice signature");
328 if (ajAnnotations.adviceKind == AdviceKind.AfterReturning) {
329 int[] throwingLocation = new int[2];
330 String returningFormal = getStringLiteralFor("returning",ajAnnotations.adviceAnnotation,throwingLocation);
331 if (returningFormal != null) {
332 if (!toArgumentNames(methodDeclaration.arguments).contains(returningFormal)) {
333 methodDeclaration.scope.problemReporter()
334 .signalError(methodDeclaration.sourceStart,methodDeclaration.sourceEnd,"returning formal '" + returningFormal + "' must be declared as a parameter in the advice signature");
339 resolveAndSetPointcut(methodDeclaration, ajAnnotations.adviceAnnotation);
344 * Get the argument names as a string list
346 * @return argument names (possibly empty)
348 private List toArgumentNames(Argument[] arguments) {
349 List names = new ArrayList();
350 if (arguments == null) {
353 for (int i = 0; i < arguments.length; i++) {
354 names.add(new String(arguments[i].name));
360 private void resolveAndSetPointcut(MethodDeclaration methodDeclaration, Annotation adviceAnn) {
361 int[] pcLocation = new int[2];
362 String pointcutExpression = getStringLiteralFor("pointcut",adviceAnn,pcLocation);
363 if (pointcutExpression == null) pointcutExpression = getStringLiteralFor("value",adviceAnn,pcLocation);
365 ISourceContext context = new EclipseSourceContext(unit.compilationResult,pcLocation[0]);
366 Pointcut pc = new PatternParser(pointcutExpression,context).parsePointcut();
367 FormalBinding[] bindings = buildFormalAdviceBindingsFrom(methodDeclaration);
368 pc.resolve(new EclipseScope(bindings,methodDeclaration.scope));
369 EclipseFactory factory = EclipseFactory.fromScopeLookupEnvironment(methodDeclaration.scope);
370 // now create a ResolvedPointcutDefinition,make an attribute out of it, and add it to the method
371 UnresolvedType[] paramTypes = new UnresolvedType[bindings.length];
372 for (int i = 0; i < paramTypes.length; i++) paramTypes[i] = bindings[i].getType();
373 ResolvedPointcutDefinition resPcutDef =
374 new ResolvedPointcutDefinition(
375 factory.fromBinding(((TypeDeclaration)typeStack.peek()).binding),
376 methodDeclaration.modifiers,
381 AjAttribute attr = new AjAttribute.PointcutDeclarationAttribute(resPcutDef);
382 ((AjMethodDeclaration)methodDeclaration).addAttribute(new EclipseAttributeAdapter(attr));
383 } catch(ParserException pEx) {
384 methodDeclaration.scope.problemReporter().parseError(
385 pcLocation[0] + pEx.getLocation().getStart(),
386 pcLocation[0] + pEx.getLocation().getEnd() ,
388 pointcutExpression.toCharArray(),
390 new String[] {pEx.getMessage()});
394 private void ensureVoidReturnType(MethodDeclaration methodDeclaration) {
395 boolean returnsVoid = true;
396 if ((methodDeclaration.returnType instanceof SingleTypeReference)) {
397 SingleTypeReference retType = (SingleTypeReference) methodDeclaration.returnType;
398 if (!CharOperation.equals(voidType,retType.token)) {
405 methodDeclaration.scope.problemReporter().signalError(methodDeclaration.returnType.sourceStart,
406 methodDeclaration.returnType.sourceEnd,
407 "This advice must return void");
411 private FormalBinding[] buildFormalAdviceBindingsFrom(MethodDeclaration mDecl) {
412 if (mDecl.arguments == null) return new FormalBinding[0];
413 EclipseFactory factory = EclipseFactory.fromScopeLookupEnvironment(mDecl.scope);
414 String extraArgName = maybeGetExtraArgName();
415 if (extraArgName == null) extraArgName = "";
416 FormalBinding[] ret = new FormalBinding[mDecl.arguments.length];
417 for (int i = 0; i < mDecl.arguments.length; i++) {
418 Argument arg = mDecl.arguments[i];
419 String name = new String(arg.name);
420 TypeBinding argTypeBinding = mDecl.binding.parameters[i];
421 UnresolvedType type = factory.fromBinding(argTypeBinding);
422 if (CharOperation.equals(joinPoint,argTypeBinding.signature()) ||
423 CharOperation.equals(joinPointStaticPart,argTypeBinding.signature()) ||
424 CharOperation.equals(joinPointEnclosingStaticPart,argTypeBinding.signature()) ||
425 CharOperation.equals(proceedingJoinPoint,argTypeBinding.signature()) ||
426 name.equals(extraArgName)) {
427 ret[i] = new FormalBinding.ImplicitFormalBinding(type,name,i);
429 ret[i] = new FormalBinding(type, name, i, arg.sourceStart, arg.sourceEnd, "unknown");
435 private String maybeGetExtraArgName() {
436 String argName = null;
437 if (ajAnnotations.adviceKind == AdviceKind.AfterReturning) {
438 argName = getStringLiteralFor("returning",ajAnnotations.adviceAnnotation,new int[2]);
439 } else if (ajAnnotations.adviceKind == AdviceKind.AfterThrowing) {
440 argName = getStringLiteralFor("throwing",ajAnnotations.adviceAnnotation,new int[2]);
445 private String getStringLiteralFor(String memberName, Annotation inAnnotation, int[] location) {
446 if (inAnnotation instanceof SingleMemberAnnotation && memberName.equals("value")) {
447 SingleMemberAnnotation sma = (SingleMemberAnnotation) inAnnotation;
448 if (sma.memberValue instanceof StringLiteral) {
449 StringLiteral sv = (StringLiteral) sma.memberValue;
450 location[0] = sv.sourceStart;
451 location[1] = sv.sourceEnd;
452 return new String(sv.source());
455 if (! (inAnnotation instanceof NormalAnnotation)) return null;
456 NormalAnnotation ann = (NormalAnnotation) inAnnotation;
457 MemberValuePair[] mvps = ann.memberValuePairs;
458 if (mvps == null) return null;
459 for (int i = 0; i < mvps.length; i++) {
460 if (CharOperation.equals(memberName.toCharArray(),mvps[i].name)) {
461 if (mvps[i].value instanceof StringLiteral) {
462 StringLiteral sv = (StringLiteral) mvps[i].value;
463 location[0] = sv.sourceStart;
464 location[1] = sv.sourceEnd;
465 return new String(sv.source());
472 private void convertToPointcutDeclaration(MethodDeclaration methodDeclaration, ClassScope scope) {
473 TypeDeclaration typeDecl = (TypeDeclaration) typeStack.peek();
474 if (typeDecl.binding != null) {
475 if (!typeDecl.binding.isClass()) {
476 methodDeclaration.scope.problemReporter()
477 .signalError(methodDeclaration.sourceStart,methodDeclaration.sourceEnd,"pointcuts can only be declared in a class or an aspect");
481 if (methodDeclaration.thrownExceptions != null && methodDeclaration.thrownExceptions.length > 0) {
482 methodDeclaration.scope.problemReporter()
483 .signalError(methodDeclaration.sourceStart,methodDeclaration.sourceEnd,"pointcuts cannot throw exceptions!");
486 PointcutDeclaration pcDecl = new PointcutDeclaration(unit.compilationResult);
487 copyAllFields(methodDeclaration,pcDecl);
489 if (ajAnnotations.hasAdviceAnnotation) {
490 methodDeclaration.scope.problemReporter().disallowedTargetForAnnotation(ajAnnotations.adviceAnnotation);
492 if (ajAnnotations.hasAspectAnnotation) {
493 methodDeclaration.scope.problemReporter().disallowedTargetForAnnotation(ajAnnotations.aspectAnnotation);
495 if (ajAnnotations.hasAdviceNameAnnotation) {
496 methodDeclaration.scope.problemReporter().disallowedTargetForAnnotation(ajAnnotations.adviceNameAnnotation);
499 boolean noValueSupplied=true;
500 boolean containsIfPcd = false;
501 int[] pcLocation = new int[2];
502 String pointcutExpression = getStringLiteralFor("value",ajAnnotations.pointcutAnnotation,pcLocation);
504 ISourceContext context = new EclipseSourceContext(unit.compilationResult,pcLocation[0]);
505 Pointcut pc = null;//abstract
506 if (pointcutExpression == null || pointcutExpression.length() == 0) {
507 noValueSupplied=true; // matches nothing pointcut
509 noValueSupplied=false;
510 pc = new PatternParser(pointcutExpression,context).parsePointcut();
512 pcDecl.pointcutDesignator = (pc==null)?null:new PointcutDesignator(pc);
513 pcDecl.setGenerateSyntheticPointcutMethod();
514 TypeDeclaration onType = (TypeDeclaration) typeStack.peek();
515 pcDecl.postParse(onType);
516 // EclipseFactory factory = EclipseFactory.fromScopeLookupEnvironment(methodDeclaration.scope);
517 // int argsLength = methodDeclaration.arguments == null ? 0 : methodDeclaration.arguments.length;
518 FormalBinding[] bindings = buildFormalAdviceBindingsFrom(methodDeclaration);
519 // FormalBinding[] bindings = new FormalBinding[argsLength];
520 // for (int i = 0, len = bindings.length; i < len; i++) {
521 // Argument arg = methodDeclaration.arguments[i];
522 // String name = new String(arg.name);
523 // UnresolvedType type = factory.fromBinding(methodDeclaration.binding.parameters[i]);
524 // bindings[i] = new FormalBinding(type, name, i, arg.sourceStart, arg.sourceEnd, "unknown");
526 swap(onType,methodDeclaration,pcDecl);
529 pc.resolve(new EclipseScope(bindings,methodDeclaration.scope));
530 HasIfPCDVisitor ifFinder = new HasIfPCDVisitor();
531 pc.traverse(ifFinder, null);
532 containsIfPcd = ifFinder.containsIfPcd;
534 } catch(ParserException pEx) {
535 methodDeclaration.scope.problemReporter().parseError(
536 pcLocation[0] + pEx.getLocation().getStart(),
537 pcLocation[0] + pEx.getLocation().getEnd() ,
539 pointcutExpression.toCharArray(),
541 new String[] {pEx.getMessage()});
544 boolean returnsVoid = false;
545 boolean returnsBoolean = false;
546 if ((methodDeclaration.returnType instanceof SingleTypeReference)) {
547 SingleTypeReference retType = (SingleTypeReference) methodDeclaration.returnType;
548 if (CharOperation.equals(voidType,retType.token)) returnsVoid = true;
549 if (CharOperation.equals(booleanType,retType.token)) returnsBoolean = true;
551 if (!returnsVoid && !containsIfPcd) {
552 methodDeclaration.scope.problemReporter().signalError(methodDeclaration.returnType.sourceStart,
553 methodDeclaration.returnType.sourceEnd,
554 "Methods annotated with @Pointcut must return void unless the pointcut contains an if() expression");
556 if (!returnsBoolean && containsIfPcd) {
557 methodDeclaration.scope.problemReporter().signalError(methodDeclaration.returnType.sourceStart,
558 methodDeclaration.returnType.sourceEnd,
559 "Methods annotated with @Pointcut must return boolean when the pointcut contains an if() expression");
562 if (methodDeclaration.statements != null && methodDeclaration.statements.length > 0 && !containsIfPcd) {
563 methodDeclaration.scope.problemReporter().signalError(methodDeclaration.returnType.sourceStart,
564 methodDeclaration.returnType.sourceEnd,
565 "Pointcuts without an if() expression should have an empty method body");
568 if (pcDecl.pointcutDesignator == null) {
569 if (Modifier.isAbstract(methodDeclaration.modifiers)
570 || noValueSupplied // this is a matches nothing pointcut
571 //those 2 checks makes sense for aop.xml concretization but NOT for regular abstraction of pointcut
573 //&& (methodDeclaration.arguments == null || methodDeclaration.arguments.length == 0)) {
577 methodDeclaration.scope.problemReporter().signalError(methodDeclaration.returnType.sourceStart,
578 methodDeclaration.returnType.sourceEnd,
579 "Method annotated with @Pointcut() for abstract pointcut must be abstract");
581 } else if (Modifier.isAbstract(methodDeclaration.modifiers)) {
582 methodDeclaration.scope.problemReporter().signalError(methodDeclaration.returnType.sourceStart,
583 methodDeclaration.returnType.sourceEnd,
584 "Method annotated with non abstract @Pointcut(\""+pointcutExpression+"\") is abstract");
588 private void copyAllFields(MethodDeclaration from, MethodDeclaration to) {
589 to.annotations = from.annotations;
590 to.arguments = from.arguments;
591 to.binding = from.binding;
593 to.bodyEnd = from.bodyEnd;
594 to.bodyStart = from.bodyStart;
595 to.declarationSourceEnd = from.declarationSourceEnd;
596 to.declarationSourceStart = from.declarationSourceStart;
597 to.errorInSignature = from.errorInSignature;
598 to.explicitDeclarations = from.explicitDeclarations;
599 to.ignoreFurtherInvestigation = from.ignoreFurtherInvestigation;
600 to.javadoc = from.javadoc;
601 to.modifiers = from.modifiers;
602 to.modifiersSourceStart = from.modifiersSourceStart;
603 to.needFreeReturn = from.needFreeReturn;
604 to.returnType = from.returnType;
605 to.scope = from.scope;
606 to.selector = from.selector;
607 to.sourceEnd = from.sourceEnd;
608 to.sourceStart = from.sourceStart;
609 to.statements = from.statements;
610 to.thrownExceptions = from.thrownExceptions;
611 to.typeParameters = from.typeParameters;
614 private void swap(TypeDeclaration inType, MethodDeclaration thisDeclaration, MethodDeclaration forThatDeclaration) {
615 for (int i = 0; i < inType.methods.length; i++) {
616 if (inType.methods[i] == thisDeclaration) {
617 inType.methods[i] = forThatDeclaration;
623 private static class AspectJAnnotations {
624 boolean hasAdviceAnnotation = false;
625 boolean hasPointcutAnnotation = false;
626 boolean hasAspectAnnotation = false;
627 boolean hasAdviceNameAnnotation = false;
629 boolean hasMultipleAdviceAnnotations = false;
630 boolean hasMultiplePointcutAnnotations = false;
631 boolean hasMultipleAspectAnnotations = false;
633 AdviceKind adviceKind = null;
634 Annotation adviceAnnotation = null;
635 Annotation pointcutAnnotation = null;
636 Annotation aspectAnnotation = null;
637 Annotation adviceNameAnnotation = null;
639 Annotation duplicateAdviceAnnotation = null;
640 Annotation duplicatePointcutAnnotation = null;
641 Annotation duplicateAspectAnnotation = null;
643 public AspectJAnnotations(Annotation[] annotations) {
644 if (annotations == null) return;
645 for (int i = 0; i < annotations.length; i++) {
646 if (annotations[i].resolvedType == null) continue; // user messed up annotation declaration
647 char[] sig = annotations[i].resolvedType.signature();
648 if (CharOperation.equals(afterAdviceSig,sig)) {
649 adviceKind = AdviceKind.After;
650 addAdviceAnnotation(annotations[i]);
651 } else if (CharOperation.equals(afterReturningAdviceSig,sig)) {
652 adviceKind = AdviceKind.AfterReturning;
653 addAdviceAnnotation(annotations[i]);
654 } else if (CharOperation.equals(afterThrowingAdviceSig,sig)) {
655 adviceKind = AdviceKind.AfterThrowing;
656 addAdviceAnnotation(annotations[i]);
657 } else if (CharOperation.equals(beforeAdviceSig,sig)) {
658 adviceKind = AdviceKind.Before;
659 addAdviceAnnotation(annotations[i]);
660 } else if (CharOperation.equals(aroundAdviceSig,sig)) {
661 adviceKind = AdviceKind.Around;
662 addAdviceAnnotation(annotations[i]);
663 } else if (CharOperation.equals(adviceNameSig,sig)) {
664 hasAdviceNameAnnotation = true;
665 adviceNameAnnotation = annotations[i];
666 } else if (CharOperation.equals(aspectSig,sig)) {
667 if (hasAspectAnnotation) {
668 hasMultipleAspectAnnotations = true;
669 duplicateAspectAnnotation = annotations[i];
671 hasAspectAnnotation = true;
672 aspectAnnotation = annotations[i];
674 } else if (CharOperation.equals(pointcutSig,sig)) {
675 if (hasPointcutAnnotation) {
676 hasMultiplePointcutAnnotations = true;
677 duplicatePointcutAnnotation = annotations[i];
679 hasPointcutAnnotation = true;
680 pointcutAnnotation = annotations[i];
687 public boolean hasAspectJAnnotations() {
688 return hasAdviceAnnotation || hasPointcutAnnotation || hasAdviceNameAnnotation || hasAspectAnnotation;
691 private void addAdviceAnnotation(Annotation annotation) {
692 if (!hasAdviceAnnotation) {
693 hasAdviceAnnotation = true;
694 adviceAnnotation = annotation;
696 hasMultipleAdviceAnnotations = true;
697 duplicateAdviceAnnotation = annotation;
702 private static class HasIfPCDVisitor extends AbstractPatternNodeVisitor {
703 public boolean containsIfPcd = false;
705 public Object visit(IfPointcut node, Object data) {
706 containsIfPcd = true;