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.ArrayList;
16 import java.util.List;
17 import java.util.Stack;
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.NameReference;
33 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.NormalAnnotation;
34 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.SingleMemberAnnotation;
35 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.SingleTypeReference;
36 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.StringLiteral;
37 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
38 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeReference;
39 import org.aspectj.org.eclipse.jdt.internal.compiler.impl.Constant;
40 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.Binding;
41 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.BlockScope;
42 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ClassScope;
43 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope;
44 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
45 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.MethodScope;
46 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
47 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
48 import org.aspectj.weaver.AdviceKind;
49 import org.aspectj.weaver.AjAttribute;
50 import org.aspectj.weaver.ISourceContext;
51 import org.aspectj.weaver.ResolvedPointcutDefinition;
52 import org.aspectj.weaver.UnresolvedType;
53 import org.aspectj.weaver.patterns.AbstractPatternNodeVisitor;
54 import org.aspectj.weaver.patterns.FormalBinding;
55 import org.aspectj.weaver.patterns.IfPointcut;
56 import org.aspectj.weaver.patterns.ParserException;
57 import org.aspectj.weaver.patterns.PatternParser;
58 import org.aspectj.weaver.patterns.Pointcut;
60 public class ValidateAtAspectJAnnotationsVisitor extends ASTVisitor {
62 private static final char[] beforeAdviceSig = "Lorg/aspectj/lang/annotation/Before;".toCharArray();
63 private static final char[] afterAdviceSig = "Lorg/aspectj/lang/annotation/After;".toCharArray();
64 private static final char[] afterReturningAdviceSig = "Lorg/aspectj/lang/annotation/AfterReturning;".toCharArray();
65 private static final char[] afterThrowingAdviceSig = "Lorg/aspectj/lang/annotation/AfterThrowing;".toCharArray();
66 private static final char[] aroundAdviceSig = "Lorg/aspectj/lang/annotation/Around;".toCharArray();
67 private static final char[] pointcutSig = "Lorg/aspectj/lang/annotation/Pointcut;".toCharArray();
68 private static final char[] aspectSig = "Lorg/aspectj/lang/annotation/Aspect;".toCharArray();
69 private static final char[] declareParentsSig = "Lorg/aspectj/lang/annotation/DeclareParents;".toCharArray();
70 private static final char[] adviceNameSig = "Lorg/aspectj/lang/annotation/AdviceName;".toCharArray();
71 // private static final char[] orgAspectJLangAnnotation =
72 // "org/aspectj/lang/annotation/".toCharArray();
73 private static final char[] voidType = "void".toCharArray();
74 private static final char[] booleanType = "boolean".toCharArray();
75 private static final char[] joinPoint = "Lorg/aspectj/lang/JoinPoint;".toCharArray();
76 private static final char[] joinPointStaticPart = "Lorg/aspectj/lang/JoinPoint$StaticPart;".toCharArray();
77 private static final char[] joinPointEnclosingStaticPart = "Lorg/aspectj/lang/JoinPoint$EnclosingStaticPart;".toCharArray();
78 private static final char[] proceedingJoinPoint = "Lorg/aspectj/lang/ProceedingJoinPoint;".toCharArray();
79 // private static final char[][] adviceSigs = new char[][] {
80 // beforeAdviceSig, afterAdviceSig, afterReturningAdviceSig,
81 // afterThrowingAdviceSig, aroundAdviceSig };
83 private final CompilationUnitDeclaration unit;
84 private final Stack typeStack = new Stack();
85 private AspectJAnnotations ajAnnotations;
87 public ValidateAtAspectJAnnotationsVisitor(CompilationUnitDeclaration unit) {
91 public boolean visit(TypeDeclaration localTypeDeclaration, BlockScope scope) {
92 typeStack.push(localTypeDeclaration);
93 ajAnnotations = new AspectJAnnotations(localTypeDeclaration.annotations);
94 checkTypeDeclaration(localTypeDeclaration);
98 public void endVisit(TypeDeclaration localTypeDeclaration, BlockScope scope) {
102 public boolean visit(TypeDeclaration memberTypeDeclaration, ClassScope scope) {
103 typeStack.push(memberTypeDeclaration);
104 ajAnnotations = new AspectJAnnotations(memberTypeDeclaration.annotations);
105 checkTypeDeclaration(memberTypeDeclaration);
109 public void endVisit(TypeDeclaration memberTypeDeclaration, ClassScope scope) {
113 public boolean visit(TypeDeclaration typeDeclaration, CompilationUnitScope scope) {
114 typeStack.push(typeDeclaration);
115 ajAnnotations = new AspectJAnnotations(typeDeclaration.annotations);
116 checkTypeDeclaration(typeDeclaration);
120 public void endVisit(TypeDeclaration typeDeclaration, CompilationUnitScope scope) {
124 private void checkTypeDeclaration(TypeDeclaration typeDecl) {
125 ContextToken tok = CompilationAndWeavingContext.enteringPhase(
126 CompilationAndWeavingContext.VALIDATING_AT_ASPECTJ_ANNOTATIONS, typeDecl.name);
127 if (!(typeDecl instanceof AspectDeclaration)) {
128 if (ajAnnotations.hasAspectAnnotation) {
129 validateAspectDeclaration(typeDecl);
131 // check that class doesn't extend aspect
132 TypeReference parentRef = typeDecl.superclass;
133 if (parentRef != null) {
134 TypeBinding parentBinding = parentRef.resolvedType;
135 if (parentBinding instanceof SourceTypeBinding) {
136 SourceTypeBinding parentSTB = (SourceTypeBinding) parentBinding;
137 if (parentSTB.scope != null) {
138 TypeDeclaration parentDecl = parentSTB.scope.referenceContext;
139 if (isAspect(parentDecl)) {
140 typeDecl.scope.problemReporter().signalError(typeDecl.sourceStart, typeDecl.sourceEnd,
141 "a class cannot extend an aspect");
148 // check that aspect doesn't have @Aspect annotation, we've already
149 // added on ourselves.
150 if (ajAnnotations.hasMultipleAspectAnnotations) {
151 typeDecl.scope.problemReporter().signalError(typeDecl.sourceStart, typeDecl.sourceEnd,
152 "aspects cannot have @Aspect annotation");
155 CompilationAndWeavingContext.leavingPhase(tok);
158 public boolean visit(FieldDeclaration fieldDeclaration, MethodScope scope) {
159 ajAnnotations = new AspectJAnnotations(fieldDeclaration.annotations);
160 if (ajAnnotations.hasDeclareParents && !insideAspect()) {
161 scope.problemReporter().signalError(fieldDeclaration.sourceStart, fieldDeclaration.sourceEnd,
162 "DeclareParents can only be used inside an aspect type");
167 public boolean visit(MethodDeclaration methodDeclaration, ClassScope scope) {
168 if (methodDeclaration.hasErrors()) {
171 ContextToken tok = CompilationAndWeavingContext.enteringPhase(
172 CompilationAndWeavingContext.VALIDATING_AT_ASPECTJ_ANNOTATIONS, methodDeclaration.selector);
173 ajAnnotations = new AspectJAnnotations(methodDeclaration.annotations);
174 if (!methodDeclaration.getClass().equals(AjMethodDeclaration.class)) {
175 // simply test for innapropriate use of annotations on code-style
177 if (methodDeclaration instanceof PointcutDeclaration) {
178 if (ajAnnotations.hasMultiplePointcutAnnotations || ajAnnotations.hasAdviceAnnotation
179 || ajAnnotations.hasAspectAnnotation || ajAnnotations.hasAdviceNameAnnotation) {
180 methodDeclaration.scope.problemReporter().signalError(methodDeclaration.sourceStart,
181 methodDeclaration.sourceEnd, "@AspectJ annotations cannot be declared on this aspect member");
183 } else if (methodDeclaration instanceof AdviceDeclaration) {
184 if (ajAnnotations.hasMultipleAdviceAnnotations || ajAnnotations.hasAspectAnnotation
185 || ajAnnotations.hasPointcutAnnotation) {
186 methodDeclaration.scope.problemReporter().signalError(methodDeclaration.sourceStart,
187 methodDeclaration.sourceEnd, "Only @AdviceName AspectJ annotation allowed on advice");
190 if (ajAnnotations.hasAspectJAnnotations()) {
191 methodDeclaration.scope.problemReporter().signalError(methodDeclaration.sourceStart,
192 methodDeclaration.sourceEnd, "@AspectJ annotations cannot be declared on this aspect member");
195 CompilationAndWeavingContext.leavingPhase(tok);
199 if (ajAnnotations.hasAdviceAnnotation) {
200 validateAdvice(methodDeclaration);
201 } else if (ajAnnotations.hasPointcutAnnotation) {
202 convertToPointcutDeclaration(methodDeclaration, scope);
204 CompilationAndWeavingContext.leavingPhase(tok);
208 // private boolean isAspectJAnnotation(Annotation ann) {
209 // if (ann.resolvedType == null) return false;
210 // char[] sig = ann.resolvedType.signature();
211 // return CharOperation.contains(orgAspectJLangAnnotation, sig);
214 private boolean insideAspect() {
215 if (typeStack.empty())
217 TypeDeclaration typeDecl = (TypeDeclaration) typeStack.peek();
218 return isAspect(typeDecl);
221 private boolean isAspect(TypeDeclaration typeDecl) {
222 if (typeDecl instanceof AspectDeclaration)
224 return new AspectJAnnotations(typeDecl.annotations).hasAspectAnnotation;
228 * aspect must be public nested aspect must be static cannot extend a
229 * concrete aspect pointcut in perclause must be good.
231 private void validateAspectDeclaration(TypeDeclaration typeDecl) {
232 if (typeStack.size() > 1) {
233 // it's a nested aspect
234 if (!Modifier.isStatic(typeDecl.modifiers)) {
235 typeDecl.scope.problemReporter().signalError(typeDecl.sourceStart, typeDecl.sourceEnd,
236 "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,
245 "only classes can have an @Aspect annotation");
249 // FIXME AV - do we really want that
250 // if (!Modifier.isPublic(typeDecl.modifiers)) {
251 // typeDecl.scope.problemReporter().signalError(typeDecl.sourceStart,
252 // typeDecl.sourceEnd,"@Aspect class must be public");
255 TypeReference parentRef = typeDecl.superclass;
256 if (parentRef != null) {
257 TypeBinding parentBinding = parentRef.resolvedType;
258 if (parentBinding instanceof SourceTypeBinding) {
259 SourceTypeBinding parentSTB = (SourceTypeBinding) parentBinding;
260 if (parentSTB.scope != null) { // scope is null if its a
261 // binarytypebinding (in AJ
262 // world, thats a subclass of
263 // SourceTypeBinding)
264 TypeDeclaration parentDecl = parentSTB.scope.referenceContext;
265 if (isAspect(parentDecl) && !Modifier.isAbstract(parentDecl.modifiers)) {
266 typeDecl.scope.problemReporter().signalError(typeDecl.sourceStart, typeDecl.sourceEnd,
267 "cannot extend a concrete aspect");
273 Annotation aspectAnnotation = ajAnnotations.aspectAnnotation;
275 int[] pcLoc = new int[2];
276 String perClause = getStringLiteralFor("value", aspectAnnotation, pcLoc);
277 // AspectDeclaration aspectDecl = new
278 // AspectDeclaration(typeDecl.compilationResult);
281 if (perClause != null && !perClause.equals("")) {
282 ISourceContext context = new EclipseSourceContext(unit.compilationResult, pcLoc[0]);
283 Pointcut pc = new PatternParser(perClause, context).maybeParsePerClause();
284 FormalBinding[] bindings = new FormalBinding[0];
286 pc.resolve(new EclipseScope(bindings, typeDecl.scope));
288 } catch (ParserException pEx) {
289 typeDecl.scope.problemReporter().parseError(pcLoc[0] + pEx.getLocation().getStart(),
290 pcLoc[0] + pEx.getLocation().getEnd(), -1, perClause.toCharArray(), perClause,
291 new String[] { pEx.getMessage() });
296 * 1) Advice must be public 2) Advice must have a void return type if not
297 * around advice 3) Advice must not have any other @AspectJ annotations 4)
298 * After throwing advice must declare the thrown formal 5) After returning
299 * advice must declare the returning formal 6) Advice must not be static
301 private void validateAdvice(MethodDeclaration methodDeclaration) {
303 if (!insideAspect()) {
304 methodDeclaration.scope.problemReporter().signalError(methodDeclaration.sourceStart, methodDeclaration.sourceEnd,
305 "Advice must be declared inside an aspect type");
308 if (!Modifier.isPublic(methodDeclaration.modifiers)) {
309 methodDeclaration.scope.problemReporter().signalError(methodDeclaration.sourceStart, methodDeclaration.sourceEnd,
310 "advice must be public");
313 if (Modifier.isStatic(methodDeclaration.modifiers)) {
314 methodDeclaration.scope.problemReporter().signalError(methodDeclaration.sourceStart, methodDeclaration.sourceEnd,
315 "advice can not be declared static");
318 if (ajAnnotations.hasMultipleAdviceAnnotations) {
319 methodDeclaration.scope.problemReporter().disallowedTargetForAnnotation(ajAnnotations.duplicateAdviceAnnotation);
321 if (ajAnnotations.hasPointcutAnnotation) {
322 methodDeclaration.scope.problemReporter().disallowedTargetForAnnotation(ajAnnotations.pointcutAnnotation);
324 if (ajAnnotations.hasAspectAnnotation) {
325 methodDeclaration.scope.problemReporter().disallowedTargetForAnnotation(ajAnnotations.aspectAnnotation);
327 if (ajAnnotations.hasAdviceNameAnnotation) {
328 methodDeclaration.scope.problemReporter().disallowedTargetForAnnotation(ajAnnotations.adviceNameAnnotation);
331 if (ajAnnotations.adviceKind != AdviceKind.Around) {
332 ensureVoidReturnType(methodDeclaration);
335 if (ajAnnotations.adviceKind == AdviceKind.AfterThrowing) {
336 int[] throwingLocation = new int[2];
337 String thrownFormal = getStringLiteralFor("throwing", ajAnnotations.adviceAnnotation, throwingLocation);
338 if (thrownFormal != null) {
339 // Argument[] arguments = methodDeclaration.arguments;
340 if (!toArgumentNames(methodDeclaration.arguments).contains(thrownFormal)) {
341 methodDeclaration.scope.problemReporter().signalError(methodDeclaration.sourceStart,
342 methodDeclaration.sourceEnd,
343 "throwing formal '" + thrownFormal + "' must be declared as a parameter in the advice signature");
348 if (ajAnnotations.adviceKind == AdviceKind.AfterReturning) {
349 int[] throwingLocation = new int[2];
350 String returningFormal = getStringLiteralFor("returning", ajAnnotations.adviceAnnotation, throwingLocation);
351 if (returningFormal != null) {
352 if (!toArgumentNames(methodDeclaration.arguments).contains(returningFormal)) {
353 methodDeclaration.scope.problemReporter().signalError(methodDeclaration.sourceStart,
354 methodDeclaration.sourceEnd,
355 "returning formal '" + returningFormal + "' must be declared as a parameter in the advice signature");
360 resolveAndSetPointcut(methodDeclaration, ajAnnotations.adviceAnnotation);
365 * Get the argument names as a string list
368 * @return argument names (possibly empty)
370 private List toArgumentNames(Argument[] arguments) {
371 List names = new ArrayList();
372 if (arguments == null) {
375 for (int i = 0; i < arguments.length; i++) {
376 names.add(new String(arguments[i].name));
382 private void resolveAndSetPointcut(MethodDeclaration methodDeclaration, Annotation adviceAnn) {
383 int[] pcLocation = new int[2];
384 String pointcutExpression = getStringLiteralFor("pointcut", adviceAnn, pcLocation);
385 if (pointcutExpression == null)
386 pointcutExpression = getStringLiteralFor("value", adviceAnn, pcLocation);
388 ISourceContext context = new EclipseSourceContext(unit.compilationResult, pcLocation[0]);
389 PatternParser pp = new PatternParser(pointcutExpression, context);
390 Pointcut pc = pp.parsePointcut();
392 FormalBinding[] bindings = buildFormalAdviceBindingsFrom(methodDeclaration);
393 pc.resolve(new EclipseScope(bindings, methodDeclaration.scope));
394 EclipseFactory factory = EclipseFactory.fromScopeLookupEnvironment(methodDeclaration.scope);
395 // now create a ResolvedPointcutDefinition,make an attribute out of
396 // it, and add it to the method
397 UnresolvedType[] paramTypes = new UnresolvedType[bindings.length];
398 for (int i = 0; i < paramTypes.length; i++)
399 paramTypes[i] = bindings[i].getType();
400 ResolvedPointcutDefinition resPcutDef = new ResolvedPointcutDefinition(factory.fromBinding(((TypeDeclaration) typeStack
401 .peek()).binding), methodDeclaration.modifiers, "anonymous", paramTypes, pc);
402 AjAttribute attr = new AjAttribute.PointcutDeclarationAttribute(resPcutDef);
403 ((AjMethodDeclaration) methodDeclaration).addAttribute(new EclipseAttributeAdapter(attr));
404 } catch (ParserException pEx) {
405 methodDeclaration.scope.problemReporter().parseError(pcLocation[0] + pEx.getLocation().getStart(),
406 pcLocation[0] + pEx.getLocation().getEnd(), -1, pointcutExpression.toCharArray(), pointcutExpression,
407 new String[] { pEx.getMessage() });
411 private void ensureVoidReturnType(MethodDeclaration methodDeclaration) {
412 boolean returnsVoid = true;
413 if ((methodDeclaration.returnType instanceof SingleTypeReference)) {
414 SingleTypeReference retType = (SingleTypeReference) methodDeclaration.returnType;
415 if (!CharOperation.equals(voidType, retType.token)) {
422 methodDeclaration.scope.problemReporter().signalError(methodDeclaration.returnType.sourceStart,
423 methodDeclaration.returnType.sourceEnd, "This advice must return void");
427 private FormalBinding[] buildFormalAdviceBindingsFrom(MethodDeclaration mDecl) {
428 if (mDecl.arguments == null)
429 return new FormalBinding[0];
430 if (mDecl.binding == null)
431 return new FormalBinding[0];
432 EclipseFactory factory = EclipseFactory.fromScopeLookupEnvironment(mDecl.scope);
433 String extraArgName = maybeGetExtraArgName();
434 if (extraArgName == null)
436 FormalBinding[] ret = new FormalBinding[mDecl.arguments.length];
437 for (int i = 0; i < mDecl.arguments.length; i++) {
438 Argument arg = mDecl.arguments[i];
439 String name = new String(arg.name);
440 TypeBinding argTypeBinding = mDecl.binding.parameters[i];
441 UnresolvedType type = factory.fromBinding(argTypeBinding);
442 if (CharOperation.equals(joinPoint, argTypeBinding.signature())
443 || CharOperation.equals(joinPointStaticPart, argTypeBinding.signature())
444 || CharOperation.equals(joinPointEnclosingStaticPart, argTypeBinding.signature())
445 || CharOperation.equals(proceedingJoinPoint, argTypeBinding.signature()) || name.equals(extraArgName)) {
446 ret[i] = new FormalBinding.ImplicitFormalBinding(type, name, i);
448 ret[i] = new FormalBinding(type, name, i, arg.sourceStart, arg.sourceEnd);
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());
472 } else if (sma.memberValue instanceof NameReference
473 && (((NameReference) sma.memberValue).binding instanceof FieldBinding)) {
474 Binding b = ((NameReference) sma.memberValue).binding;
475 Constant c = ((FieldBinding) b).constant;
476 return c.stringValue();
479 if (!(inAnnotation instanceof NormalAnnotation))
481 NormalAnnotation ann = (NormalAnnotation) inAnnotation;
482 MemberValuePair[] mvps = ann.memberValuePairs;
485 for (int i = 0; i < mvps.length; i++) {
486 if (CharOperation.equals(memberName.toCharArray(), mvps[i].name)) {
487 if (mvps[i].value instanceof StringLiteral) {
488 StringLiteral sv = (StringLiteral) mvps[i].value;
489 location[0] = sv.sourceStart;
490 location[1] = sv.sourceEnd;
491 return new String(sv.source());
498 private void convertToPointcutDeclaration(MethodDeclaration methodDeclaration, ClassScope scope) {
499 TypeDeclaration typeDecl = (TypeDeclaration) typeStack.peek();
500 if (typeDecl.binding != null) {
501 if (!typeDecl.binding.isClass()) {
502 methodDeclaration.scope.problemReporter().signalError(methodDeclaration.sourceStart, methodDeclaration.sourceEnd,
503 "pointcuts can only be declared in a class or an aspect");
507 if (methodDeclaration.thrownExceptions != null && methodDeclaration.thrownExceptions.length > 0) {
508 methodDeclaration.scope.problemReporter().signalError(methodDeclaration.sourceStart, methodDeclaration.sourceEnd,
509 "pointcuts cannot throw exceptions!");
512 PointcutDeclaration pcDecl = new PointcutDeclaration(unit.compilationResult);
513 copyAllFields(methodDeclaration, pcDecl);
515 if (ajAnnotations.hasAdviceAnnotation) {
516 methodDeclaration.scope.problemReporter().disallowedTargetForAnnotation(ajAnnotations.adviceAnnotation);
518 if (ajAnnotations.hasAspectAnnotation) {
519 methodDeclaration.scope.problemReporter().disallowedTargetForAnnotation(ajAnnotations.aspectAnnotation);
521 if (ajAnnotations.hasAdviceNameAnnotation) {
522 methodDeclaration.scope.problemReporter().disallowedTargetForAnnotation(ajAnnotations.adviceNameAnnotation);
525 boolean noValueSupplied = true;
526 boolean containsIfPcd = false;
527 int[] pcLocation = new int[2];
528 String pointcutExpression = getStringLiteralFor("value", ajAnnotations.pointcutAnnotation, pcLocation);
530 ISourceContext context = new EclipseSourceContext(unit.compilationResult, pcLocation[0]);
531 Pointcut pc = null;// abstract
532 if (pointcutExpression == null || pointcutExpression.length() == 0) {
533 noValueSupplied = true; // matches nothing pointcut
535 noValueSupplied = false;
536 pc = new PatternParser(pointcutExpression, context).parsePointcut();
538 pcDecl.pointcutDesignator = (pc == null) ? null : new PointcutDesignator(pc);
539 pcDecl.setGenerateSyntheticPointcutMethod();
540 TypeDeclaration onType = (TypeDeclaration) typeStack.peek();
541 pcDecl.postParse(onType);
542 // EclipseFactory factory =
543 // EclipseFactory.fromScopeLookupEnvironment
544 // (methodDeclaration.scope);
545 // int argsLength = methodDeclaration.arguments == null ? 0 :
546 // methodDeclaration.arguments.length;
547 FormalBinding[] bindings = buildFormalAdviceBindingsFrom(methodDeclaration);
548 // FormalBinding[] bindings = new FormalBinding[argsLength];
549 // for (int i = 0, len = bindings.length; i < len; i++) {
550 // Argument arg = methodDeclaration.arguments[i];
551 // String name = new String(arg.name);
552 // UnresolvedType type =
553 // factory.fromBinding(methodDeclaration.binding.parameters[i]);
554 // bindings[i] = new FormalBinding(type, name, i, arg.sourceStart,
555 // arg.sourceEnd, "unknown");
557 swap(onType, methodDeclaration, pcDecl);
560 EclipseScope eScope = new EclipseScope(bindings, methodDeclaration.scope);
561 char[] packageName = null;
562 if (typeDecl.binding != null && typeDecl.binding.getPackage() != null) {
563 packageName = typeDecl.binding.getPackage().readableName();
565 eScope.setLimitedImports(packageName);
567 HasIfPCDVisitor ifFinder = new HasIfPCDVisitor();
568 pc.traverse(ifFinder, null);
569 containsIfPcd = ifFinder.containsIfPcd;
571 } catch (ParserException pEx) {
572 methodDeclaration.scope.problemReporter().parseError(pcLocation[0] + pEx.getLocation().getStart(),
573 pcLocation[0] + pEx.getLocation().getEnd(), -1, pointcutExpression.toCharArray(), pointcutExpression,
574 new String[] { pEx.getMessage() });
577 boolean returnsVoid = false;
578 boolean returnsBoolean = false;
579 if ((methodDeclaration.returnType instanceof SingleTypeReference)) {
580 SingleTypeReference retType = (SingleTypeReference) methodDeclaration.returnType;
581 if (CharOperation.equals(voidType, retType.token))
583 if (CharOperation.equals(booleanType, retType.token))
584 returnsBoolean = true;
586 if (!returnsVoid && !containsIfPcd) {
587 methodDeclaration.scope.problemReporter().signalError(methodDeclaration.returnType.sourceStart,
588 methodDeclaration.returnType.sourceEnd,
589 "Methods annotated with @Pointcut must return void unless the pointcut contains an if() expression");
591 if (!returnsBoolean && containsIfPcd) {
592 methodDeclaration.scope.problemReporter().signalError(methodDeclaration.returnType.sourceStart,
593 methodDeclaration.returnType.sourceEnd,
594 "Methods annotated with @Pointcut must return boolean when the pointcut contains an if() expression");
597 if (methodDeclaration.statements != null && methodDeclaration.statements.length > 0 && !containsIfPcd) {
598 methodDeclaration.scope.problemReporter()
599 .signalError(methodDeclaration.returnType.sourceStart, methodDeclaration.returnType.sourceEnd,
600 "Pointcuts without an if() expression should have an empty method body");
603 if (pcDecl.pointcutDesignator == null) {
604 if (Modifier.isAbstract(methodDeclaration.modifiers) || noValueSupplied // this
610 // those 2 checks makes sense for aop.xml concretization but NOT for
611 // regular abstraction of pointcut
613 // && (methodDeclaration.arguments == null ||
614 // methodDeclaration.arguments.length == 0)) {
618 methodDeclaration.scope.problemReporter().signalError(methodDeclaration.returnType.sourceStart,
619 methodDeclaration.returnType.sourceEnd,
620 "Method annotated with @Pointcut() for abstract pointcut must be abstract");
622 } else if (Modifier.isAbstract(methodDeclaration.modifiers)) {
623 methodDeclaration.scope.problemReporter().signalError(methodDeclaration.returnType.sourceStart,
624 methodDeclaration.returnType.sourceEnd,
625 "Method annotated with non abstract @Pointcut(\"" + pointcutExpression + "\") is abstract");
629 private void copyAllFields(MethodDeclaration from, MethodDeclaration to) {
630 to.annotations = from.annotations;
631 to.arguments = from.arguments;
632 to.binding = from.binding;
634 to.bodyEnd = from.bodyEnd;
635 to.bodyStart = from.bodyStart;
636 to.declarationSourceEnd = from.declarationSourceEnd;
637 to.declarationSourceStart = from.declarationSourceStart;
638 to.explicitDeclarations = from.explicitDeclarations;
639 to.ignoreFurtherInvestigation = from.ignoreFurtherInvestigation;
640 to.javadoc = from.javadoc;
641 to.modifiers = from.modifiers;
642 to.modifiersSourceStart = from.modifiersSourceStart;
643 to.returnType = from.returnType;
644 to.scope = from.scope;
645 to.selector = from.selector;
646 to.sourceEnd = from.sourceEnd;
647 to.sourceStart = from.sourceStart;
648 to.statements = from.statements;
649 to.thrownExceptions = from.thrownExceptions;
650 to.typeParameters = from.typeParameters;
653 private void swap(TypeDeclaration inType, MethodDeclaration thisDeclaration, MethodDeclaration forThatDeclaration) {
654 for (int i = 0; i < inType.methods.length; i++) {
655 if (inType.methods[i] == thisDeclaration) {
656 inType.methods[i] = forThatDeclaration;
662 private static class AspectJAnnotations {
663 boolean hasAdviceAnnotation = false;
664 boolean hasPointcutAnnotation = false;
665 boolean hasAspectAnnotation = false;
666 boolean hasAdviceNameAnnotation = false;
667 boolean hasDeclareParents = false;
668 boolean hasMultipleAdviceAnnotations = false;
669 boolean hasMultiplePointcutAnnotations = false;
670 boolean hasMultipleAspectAnnotations = false;
672 AdviceKind adviceKind = null;
673 Annotation adviceAnnotation = null;
674 Annotation pointcutAnnotation = null;
675 Annotation aspectAnnotation = null;
676 Annotation adviceNameAnnotation = null;
678 Annotation duplicateAdviceAnnotation = null;
679 Annotation duplicatePointcutAnnotation = null;
680 Annotation duplicateAspectAnnotation = null;
682 public AspectJAnnotations(Annotation[] annotations) {
683 if (annotations == null)
685 for (int i = 0; i < annotations.length; i++) {
686 if (annotations[i].resolvedType == null)
687 continue; // user messed up annotation declaration
688 char[] sig = annotations[i].resolvedType.signature();
689 if (CharOperation.equals(afterAdviceSig, sig)) {
690 adviceKind = AdviceKind.After;
691 addAdviceAnnotation(annotations[i]);
692 } else if (CharOperation.equals(afterReturningAdviceSig, sig)) {
693 adviceKind = AdviceKind.AfterReturning;
694 addAdviceAnnotation(annotations[i]);
695 } else if (CharOperation.equals(afterThrowingAdviceSig, sig)) {
696 adviceKind = AdviceKind.AfterThrowing;
697 addAdviceAnnotation(annotations[i]);
698 } else if (CharOperation.equals(beforeAdviceSig, sig)) {
699 adviceKind = AdviceKind.Before;
700 addAdviceAnnotation(annotations[i]);
701 } else if (CharOperation.equals(aroundAdviceSig, sig)) {
702 adviceKind = AdviceKind.Around;
703 addAdviceAnnotation(annotations[i]);
704 } else if (CharOperation.equals(adviceNameSig, sig)) {
705 hasAdviceNameAnnotation = true;
706 adviceNameAnnotation = annotations[i];
707 } else if (CharOperation.equals(declareParentsSig, sig)) {
708 hasDeclareParents = true;
709 } else if (CharOperation.equals(aspectSig, sig)) {
710 if (hasAspectAnnotation) {
711 hasMultipleAspectAnnotations = true;
712 duplicateAspectAnnotation = annotations[i];
714 hasAspectAnnotation = true;
715 aspectAnnotation = annotations[i];
717 } else if (CharOperation.equals(pointcutSig, sig)) {
718 if (hasPointcutAnnotation) {
719 hasMultiplePointcutAnnotations = true;
720 duplicatePointcutAnnotation = annotations[i];
722 hasPointcutAnnotation = true;
723 pointcutAnnotation = annotations[i];
730 public boolean hasAspectJAnnotations() {
731 return hasAdviceAnnotation || hasPointcutAnnotation || hasAdviceNameAnnotation || hasAspectAnnotation;
734 private void addAdviceAnnotation(Annotation annotation) {
735 if (!hasAdviceAnnotation) {
736 hasAdviceAnnotation = true;
737 adviceAnnotation = annotation;
739 hasMultipleAdviceAnnotations = true;
740 duplicateAdviceAnnotation = annotation;
745 private static class HasIfPCDVisitor extends AbstractPatternNodeVisitor {
746 public boolean containsIfPcd = false;
748 public Object visit(IfPointcut node, Object data) {
749 containsIfPcd = true;