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;
17 import org.aspectj.ajdt.internal.compiler.lookup.EclipseFactory;
18 import org.aspectj.ajdt.internal.compiler.lookup.EclipseScope;
19 import org.aspectj.ajdt.internal.core.builder.EclipseSourceContext;
20 import org.aspectj.bridge.context.CompilationAndWeavingContext;
21 import org.aspectj.bridge.context.ContextToken;
22 import org.aspectj.org.eclipse.jdt.core.compiler.CharOperation;
23 import org.aspectj.org.eclipse.jdt.internal.compiler.ASTVisitor;
24 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Annotation;
25 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Argument;
26 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
27 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.MemberValuePair;
28 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
29 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.NormalAnnotation;
30 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.SingleMemberAnnotation;
31 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.SingleTypeReference;
32 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.StringLiteral;
33 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
34 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeReference;
35 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.BlockScope;
36 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ClassScope;
37 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope;
38 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
39 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
40 import org.aspectj.weaver.AdviceKind;
41 import org.aspectj.weaver.AjAttribute;
42 import org.aspectj.weaver.ISourceContext;
43 import org.aspectj.weaver.ResolvedPointcutDefinition;
44 import org.aspectj.weaver.UnresolvedType;
45 import org.aspectj.weaver.patterns.AbstractPatternNodeVisitor;
46 import org.aspectj.weaver.patterns.FormalBinding;
47 import org.aspectj.weaver.patterns.IfPointcut;
48 import org.aspectj.weaver.patterns.ParserException;
49 import org.aspectj.weaver.patterns.PatternParser;
50 import org.aspectj.weaver.patterns.Pointcut;
52 public class ValidateAtAspectJAnnotationsVisitor extends ASTVisitor {
54 private static final char[] beforeAdviceSig = "Lorg/aspectj/lang/annotation/Before;".toCharArray();
55 private static final char[] afterAdviceSig = "Lorg/aspectj/lang/annotation/After;".toCharArray();
56 private static final char[] afterReturningAdviceSig = "Lorg/aspectj/lang/annotation/AfterReturning;".toCharArray();
57 private static final char[] afterThrowingAdviceSig = "Lorg/aspectj/lang/annotation/AfterThrowing;".toCharArray();
58 private static final char[] aroundAdviceSig = "Lorg/aspectj/lang/annotation/Around;".toCharArray();
59 private static final char[] pointcutSig = "Lorg/aspectj/lang/annotation/Pointcut;".toCharArray();
60 private static final char[] aspectSig = "Lorg/aspectj/lang/annotation/Aspect;".toCharArray();
61 private static final char[] adviceNameSig = "Lorg/aspectj/lang/annotation/AdviceName;".toCharArray();
62 private static final char[] orgAspectJLangAnnotation = "org/aspectj/lang/annotation/".toCharArray();
63 private static final char[] voidType = "void".toCharArray();
64 private static final char[] booleanType = "boolean".toCharArray();
65 private static final char[] joinPoint = "Lorg/aspectj/lang/JoinPoint;".toCharArray();
66 private static final char[] joinPointStaticPart = "Lorg/aspectj/lang/JoinPoint$StaticPart;".toCharArray();
67 private static final char[] joinPointEnclosingStaticPart = "Lorg/aspectj/lang/JoinPoint$EnclosingStaticPart;".toCharArray();
68 private static final char[] proceedingJoinPoint = "Lorg/aspectj/lang/ProceedingJoinPoint;".toCharArray();
69 private static final char[][] adviceSigs = new char[][] {beforeAdviceSig,afterAdviceSig,afterReturningAdviceSig,afterThrowingAdviceSig,aroundAdviceSig};
72 private CompilationUnitDeclaration unit;
73 private Stack typeStack = new Stack();
74 private AspectJAnnotations ajAnnotations;
76 public ValidateAtAspectJAnnotationsVisitor(CompilationUnitDeclaration unit) {
80 public boolean visit(TypeDeclaration localTypeDeclaration, BlockScope scope) {
81 typeStack.push(localTypeDeclaration);
82 ajAnnotations = new AspectJAnnotations(localTypeDeclaration.annotations);
83 checkTypeDeclaration(localTypeDeclaration);
87 public void endVisit(TypeDeclaration localTypeDeclaration,BlockScope scope) {
91 public boolean visit(TypeDeclaration memberTypeDeclaration,ClassScope scope) {
92 typeStack.push(memberTypeDeclaration);
93 ajAnnotations = new AspectJAnnotations(memberTypeDeclaration.annotations);
94 checkTypeDeclaration(memberTypeDeclaration);
98 public void endVisit(TypeDeclaration memberTypeDeclaration,ClassScope scope) {
102 public boolean visit(TypeDeclaration typeDeclaration, CompilationUnitScope scope) {
103 typeStack.push(typeDeclaration);
104 ajAnnotations = new AspectJAnnotations(typeDeclaration.annotations);
105 checkTypeDeclaration(typeDeclaration);
109 public void endVisit(TypeDeclaration typeDeclaration,CompilationUnitScope scope) {
113 private void checkTypeDeclaration(TypeDeclaration typeDecl) {
114 ContextToken tok = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.VALIDATING_AT_ASPECTJ_ANNOTATIONS, typeDecl.name);
115 if (!(typeDecl instanceof AspectDeclaration)) {
116 if (ajAnnotations.hasAspectAnnotation) {
117 validateAspectDeclaration(typeDecl);
119 // check that class doesn't extend aspect
120 TypeReference parentRef = typeDecl.superclass;
121 if (parentRef != null) {
122 TypeBinding parentBinding = parentRef.resolvedType;
123 if (parentBinding instanceof SourceTypeBinding) {
124 SourceTypeBinding parentSTB = (SourceTypeBinding) parentBinding;
125 if (parentSTB.scope != null) {
126 TypeDeclaration parentDecl = parentSTB.scope.referenceContext;
127 if (isAspect(parentDecl)) {
128 typeDecl.scope.problemReporter().signalError(typeDecl.sourceStart,typeDecl.sourceEnd,"a class cannot extend an aspect");
135 // check that aspect doesn't have @Aspect annotation, we've already added on ourselves.
136 if (ajAnnotations.hasMultipleAspectAnnotations) {
137 typeDecl.scope.problemReporter().signalError(
138 typeDecl.sourceStart,
140 "aspects cannot have @Aspect annotation"
144 CompilationAndWeavingContext.leavingPhase(tok);
147 public boolean visit(MethodDeclaration methodDeclaration, ClassScope scope) {
148 ContextToken tok = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.VALIDATING_AT_ASPECTJ_ANNOTATIONS, methodDeclaration.selector);
149 ajAnnotations = new AspectJAnnotations(methodDeclaration.annotations);
150 if (!methodDeclaration.getClass().equals(AjMethodDeclaration.class)) {
151 // simply test for innapropriate use of annotations on code-style members
152 if (methodDeclaration instanceof PointcutDeclaration) {
153 if (ajAnnotations.hasMultiplePointcutAnnotations ||
154 ajAnnotations.hasAdviceAnnotation ||
155 ajAnnotations.hasAspectAnnotation ||
156 ajAnnotations.hasAdviceNameAnnotation) {
157 methodDeclaration.scope.problemReporter().signalError(
158 methodDeclaration.sourceStart,
159 methodDeclaration.sourceEnd,
160 "@AspectJ annotations cannot be declared on this aspect member");
162 } else if (methodDeclaration instanceof AdviceDeclaration) {
163 if (ajAnnotations.hasMultipleAdviceAnnotations ||
164 ajAnnotations.hasAspectAnnotation ||
165 ajAnnotations.hasPointcutAnnotation) {
166 methodDeclaration.scope.problemReporter().signalError(
167 methodDeclaration.sourceStart,
168 methodDeclaration.sourceEnd,
169 "Only @AdviceName AspectJ annotation allowed on advice");
172 if (ajAnnotations.hasAspectJAnnotations()) {
173 methodDeclaration.scope.problemReporter().signalError(
174 methodDeclaration.sourceStart,
175 methodDeclaration.sourceEnd,
176 "@AspectJ annotations cannot be declared on this aspect member");
179 CompilationAndWeavingContext.leavingPhase(tok);
183 if (ajAnnotations.hasAdviceAnnotation) {
184 validateAdvice(methodDeclaration);
185 } else if (ajAnnotations.hasPointcutAnnotation) {
186 convertToPointcutDeclaration(methodDeclaration,scope);
188 CompilationAndWeavingContext.leavingPhase(tok);
192 private boolean isAspectJAnnotation(Annotation ann) {
193 if (ann.resolvedType == null) return false;
194 char[] sig = ann.resolvedType.signature();
195 return CharOperation.contains(orgAspectJLangAnnotation, sig);
198 private boolean insideAspect() {
199 if (typeStack.empty()) return false;
200 TypeDeclaration typeDecl = (TypeDeclaration) typeStack.peek();
201 return isAspect(typeDecl);
204 private boolean isAspect(TypeDeclaration typeDecl) {
205 if (typeDecl instanceof AspectDeclaration) return true;
206 return new AspectJAnnotations(typeDecl.annotations).hasAspectAnnotation;
210 * nested aspect must be static
211 * cannot extend a concrete aspect
212 * pointcut in perclause must be good.
214 private void validateAspectDeclaration(TypeDeclaration typeDecl) {
215 if (typeStack.size() > 1) {
216 // it's a nested aspect
217 if (!Modifier.isStatic(typeDecl.modifiers)) {
218 typeDecl.scope.problemReporter().signalError(typeDecl.sourceStart, typeDecl.sourceEnd, "inner aspects must be static");
223 SourceTypeBinding binding = typeDecl.binding;
224 if (binding != null) {
225 if (binding.isEnum() || binding.isInterface() || binding.isAnnotationType()) {
226 typeDecl.scope.problemReporter().signalError(typeDecl.sourceStart,typeDecl.sourceEnd,"only classes can have an @Aspect annotation");
230 TypeReference parentRef = typeDecl.superclass;
231 if (parentRef != null) {
232 TypeBinding parentBinding = parentRef.resolvedType;
233 if (parentBinding instanceof SourceTypeBinding) {
234 SourceTypeBinding parentSTB = (SourceTypeBinding) parentBinding;
235 TypeDeclaration parentDecl = parentSTB.scope.referenceContext;
236 if (isAspect(parentDecl) && !Modifier.isAbstract(parentDecl.modifiers)) {
237 typeDecl.scope.problemReporter().signalError(typeDecl.sourceStart,typeDecl.sourceEnd,"cannot extend a concrete aspect");
242 Annotation aspectAnnotation = ajAnnotations.aspectAnnotation;
244 int[] pcLoc = new int[2];
245 String perClause = getStringLiteralFor("value", aspectAnnotation, pcLoc);
246 AspectDeclaration aspectDecl = new AspectDeclaration(typeDecl.compilationResult);
249 if (perClause != null && !perClause.equals("")) {
250 ISourceContext context = new EclipseSourceContext(unit.compilationResult,pcLoc[0]);
251 Pointcut pc = new PatternParser(perClause,context).maybeParsePerClause();
252 FormalBinding[] bindings = new FormalBinding[0];
253 if (pc != null) pc.resolve(new EclipseScope(bindings,typeDecl.scope));
255 } catch(ParserException pEx) {
256 typeDecl.scope.problemReporter().parseError(
257 pcLoc[0] + pEx.getLocation().getStart(),
258 pcLoc[0] + pEx.getLocation().getEnd() ,
260 perClause.toCharArray(),
262 new String[] {pEx.getMessage()});
267 * 1) Advice must be public
268 * 2) Advice must have a void return type if not around advice
269 * 3) Advice must not have any other @AspectJ annotations
270 * 4) After throwing advice must declare the thrown formal
271 * 5) After returning advice must declare the returning formal
273 private void validateAdvice(MethodDeclaration methodDeclaration) {
275 if (!insideAspect()) {
276 methodDeclaration.scope.problemReporter().signalError(methodDeclaration.sourceStart,
277 methodDeclaration.sourceEnd,
278 "Advice must be declared inside an aspect type");
281 if (!Modifier.isPublic(methodDeclaration.modifiers)) {
282 methodDeclaration.scope.problemReporter()
283 .signalError(methodDeclaration.sourceStart,methodDeclaration.sourceEnd,"advice must be public");
286 if (ajAnnotations.hasMultipleAdviceAnnotations) {
287 methodDeclaration.scope.problemReporter().disallowedTargetForAnnotation(ajAnnotations.duplicateAdviceAnnotation);
289 if (ajAnnotations.hasPointcutAnnotation) {
290 methodDeclaration.scope.problemReporter().disallowedTargetForAnnotation(ajAnnotations.pointcutAnnotation);
292 if (ajAnnotations.hasAspectAnnotation) {
293 methodDeclaration.scope.problemReporter().disallowedTargetForAnnotation(ajAnnotations.aspectAnnotation);
295 if (ajAnnotations.hasAdviceNameAnnotation) {
296 methodDeclaration.scope.problemReporter().disallowedTargetForAnnotation(ajAnnotations.adviceNameAnnotation);
299 if (ajAnnotations.adviceKind != AdviceKind.Around) {
300 ensureVoidReturnType(methodDeclaration);
303 if (ajAnnotations.adviceKind == AdviceKind.AfterThrowing) {
304 int[] throwingLocation = new int[2];
305 String thrownFormal = getStringLiteralFor("throwing",ajAnnotations.adviceAnnotation,throwingLocation);
306 if (thrownFormal != null) {
307 Argument[] arguments = methodDeclaration.arguments;
308 if (arguments != null && arguments.length > 0) {
309 Argument lastArgument = arguments[arguments.length - 1];
310 if (!thrownFormal.equals(new String(lastArgument.name))) {
311 methodDeclaration.scope.problemReporter()
312 .signalError(methodDeclaration.sourceStart,methodDeclaration.sourceEnd,"throwing formal '" + thrownFormal + "' must be declared as the last parameter in the advice signature");
315 methodDeclaration.scope.problemReporter()
316 .signalError(methodDeclaration.sourceStart,methodDeclaration.sourceEnd,"throwing formal '" + thrownFormal + "' must be declared as the last parameter in the advice signature");
321 if (ajAnnotations.adviceKind == AdviceKind.AfterReturning) {
322 int[] throwingLocation = new int[2];
323 String returningFormal = getStringLiteralFor("returning",ajAnnotations.adviceAnnotation,throwingLocation);
324 if (returningFormal != null) {
325 Argument[] arguments = methodDeclaration.arguments;
326 if (arguments != null && arguments.length > 0) {
327 Argument lastArgument = arguments[arguments.length - 1];
328 if (!returningFormal.equals(new String(lastArgument.name))) {
329 methodDeclaration.scope.problemReporter()
330 .signalError(methodDeclaration.sourceStart,methodDeclaration.sourceEnd,"returning formal '" + returningFormal + "' must be declared as the last parameter in the advice signature");
333 methodDeclaration.scope.problemReporter()
334 .signalError(methodDeclaration.sourceStart,methodDeclaration.sourceEnd,"returning formal '" + returningFormal + "' must be declared as the last parameter in the advice signature");
339 resolveAndSetPointcut(methodDeclaration, ajAnnotations.adviceAnnotation);
343 private void resolveAndSetPointcut(MethodDeclaration methodDeclaration, Annotation adviceAnn) {
344 int[] pcLocation = new int[2];
345 String pointcutExpression = getStringLiteralFor("pointcut",adviceAnn,pcLocation);
346 if (pointcutExpression == null) pointcutExpression = getStringLiteralFor("value",adviceAnn,pcLocation);
348 ISourceContext context = new EclipseSourceContext(unit.compilationResult,pcLocation[0]);
349 Pointcut pc = new PatternParser(pointcutExpression,context).parsePointcut();
350 FormalBinding[] bindings = buildFormalAdviceBindingsFrom(methodDeclaration);
351 pc.resolve(new EclipseScope(bindings,methodDeclaration.scope));
352 EclipseFactory factory = EclipseFactory.fromScopeLookupEnvironment(methodDeclaration.scope);
353 // now create a ResolvedPointcutDefinition,make an attribute out of it, and add it to the method
354 UnresolvedType[] paramTypes = new UnresolvedType[bindings.length];
355 for (int i = 0; i < paramTypes.length; i++) paramTypes[i] = bindings[i].getType();
356 ResolvedPointcutDefinition resPcutDef =
357 new ResolvedPointcutDefinition(
358 factory.fromBinding(((TypeDeclaration)typeStack.peek()).binding),
359 methodDeclaration.modifiers,
364 AjAttribute attr = new AjAttribute.PointcutDeclarationAttribute(resPcutDef);
365 ((AjMethodDeclaration)methodDeclaration).addAttribute(new EclipseAttributeAdapter(attr));
366 } catch(ParserException pEx) {
367 methodDeclaration.scope.problemReporter().parseError(
368 pcLocation[0] + pEx.getLocation().getStart(),
369 pcLocation[0] + pEx.getLocation().getEnd() ,
371 pointcutExpression.toCharArray(),
373 new String[] {pEx.getMessage()});
377 private void ensureVoidReturnType(MethodDeclaration methodDeclaration) {
378 boolean returnsVoid = true;
379 if ((methodDeclaration.returnType instanceof SingleTypeReference)) {
380 SingleTypeReference retType = (SingleTypeReference) methodDeclaration.returnType;
381 if (!CharOperation.equals(voidType,retType.token)) {
388 methodDeclaration.scope.problemReporter().signalError(methodDeclaration.returnType.sourceStart,
389 methodDeclaration.returnType.sourceEnd,
390 "This advice must return void");
394 private FormalBinding[] buildFormalAdviceBindingsFrom(MethodDeclaration mDecl) {
395 if (mDecl.arguments == null) return new FormalBinding[0];
396 EclipseFactory factory = EclipseFactory.fromScopeLookupEnvironment(mDecl.scope);
397 String extraArgName = maybeGetExtraArgName();
398 if (extraArgName == null) extraArgName = "";
399 FormalBinding[] ret = new FormalBinding[mDecl.arguments.length];
400 for (int i = 0; i < mDecl.arguments.length; i++) {
401 Argument arg = mDecl.arguments[i];
402 String name = new String(arg.name);
403 TypeBinding argTypeBinding = mDecl.binding.parameters[i];
404 UnresolvedType type = factory.fromBinding(argTypeBinding);
405 if (CharOperation.equals(joinPoint,argTypeBinding.signature()) ||
406 CharOperation.equals(joinPointStaticPart,argTypeBinding.signature()) ||
407 CharOperation.equals(joinPointEnclosingStaticPart,argTypeBinding.signature()) ||
408 CharOperation.equals(proceedingJoinPoint,argTypeBinding.signature()) ||
409 name.equals(extraArgName)) {
410 ret[i] = new FormalBinding.ImplicitFormalBinding(type,name,i);
412 ret[i] = new FormalBinding(type, name, i, arg.sourceStart, arg.sourceEnd, "unknown");
418 private String maybeGetExtraArgName() {
419 String argName = null;
420 if (ajAnnotations.adviceKind == AdviceKind.AfterReturning) {
421 argName = getStringLiteralFor("returning",ajAnnotations.adviceAnnotation,new int[2]);
422 } else if (ajAnnotations.adviceKind == AdviceKind.AfterThrowing) {
423 argName = getStringLiteralFor("throwing",ajAnnotations.adviceAnnotation,new int[2]);
428 private String getStringLiteralFor(String memberName, Annotation inAnnotation, int[] location) {
429 if (inAnnotation instanceof SingleMemberAnnotation && memberName.equals("value")) {
430 SingleMemberAnnotation sma = (SingleMemberAnnotation) inAnnotation;
431 if (sma.memberValue instanceof StringLiteral) {
432 StringLiteral sv = (StringLiteral) sma.memberValue;
433 location[0] = sv.sourceStart;
434 location[1] = sv.sourceEnd;
435 return new String(sv.source());
438 if (! (inAnnotation instanceof NormalAnnotation)) return null;
439 NormalAnnotation ann = (NormalAnnotation) inAnnotation;
440 MemberValuePair[] mvps = ann.memberValuePairs;
441 if (mvps == null) return null;
442 for (int i = 0; i < mvps.length; i++) {
443 if (CharOperation.equals(memberName.toCharArray(),mvps[i].name)) {
444 if (mvps[i].value instanceof StringLiteral) {
445 StringLiteral sv = (StringLiteral) mvps[i].value;
446 location[0] = sv.sourceStart;
447 location[1] = sv.sourceEnd;
448 return new String(sv.source());
455 private void convertToPointcutDeclaration(MethodDeclaration methodDeclaration, ClassScope scope) {
456 TypeDeclaration typeDecl = (TypeDeclaration) typeStack.peek();
457 if (typeDecl.binding != null) {
458 if (!typeDecl.binding.isClass()) {
459 methodDeclaration.scope.problemReporter()
460 .signalError(methodDeclaration.sourceStart,methodDeclaration.sourceEnd,"pointcuts can only be declared in a class or an aspect");
464 if (methodDeclaration.thrownExceptions != null && methodDeclaration.thrownExceptions.length > 0) {
465 methodDeclaration.scope.problemReporter()
466 .signalError(methodDeclaration.sourceStart,methodDeclaration.sourceEnd,"pointcuts cannot throw exceptions!");
469 PointcutDeclaration pcDecl = new PointcutDeclaration(unit.compilationResult);
470 copyAllFields(methodDeclaration,pcDecl);
472 if (ajAnnotations.hasAdviceAnnotation) {
473 methodDeclaration.scope.problemReporter().disallowedTargetForAnnotation(ajAnnotations.adviceAnnotation);
475 if (ajAnnotations.hasAspectAnnotation) {
476 methodDeclaration.scope.problemReporter().disallowedTargetForAnnotation(ajAnnotations.aspectAnnotation);
478 if (ajAnnotations.hasAdviceNameAnnotation) {
479 methodDeclaration.scope.problemReporter().disallowedTargetForAnnotation(ajAnnotations.adviceNameAnnotation);
482 boolean containsIfPcd = false;
483 int[] pcLocation = new int[2];
484 String pointcutExpression = getStringLiteralFor("value",ajAnnotations.pointcutAnnotation,pcLocation);
486 ISourceContext context = new EclipseSourceContext(unit.compilationResult,pcLocation[0]);
487 Pointcut pc = new PatternParser(pointcutExpression,context).parsePointcut();
488 pcDecl.pointcutDesignator = new PointcutDesignator(pc);
489 pcDecl.setGenerateSyntheticPointcutMethod();
490 TypeDeclaration onType = (TypeDeclaration) typeStack.peek();
491 pcDecl.postParse(onType);
492 // EclipseFactory factory = EclipseFactory.fromScopeLookupEnvironment(methodDeclaration.scope);
493 // int argsLength = methodDeclaration.arguments == null ? 0 : methodDeclaration.arguments.length;
494 FormalBinding[] bindings = buildFormalAdviceBindingsFrom(methodDeclaration);
495 // FormalBinding[] bindings = new FormalBinding[argsLength];
496 // for (int i = 0, len = bindings.length; i < len; i++) {
497 // Argument arg = methodDeclaration.arguments[i];
498 // String name = new String(arg.name);
499 // UnresolvedType type = factory.fromBinding(methodDeclaration.binding.parameters[i]);
500 // bindings[i] = new FormalBinding(type, name, i, arg.sourceStart, arg.sourceEnd, "unknown");
502 swap(onType,methodDeclaration,pcDecl);
503 pc.resolve(new EclipseScope(bindings,methodDeclaration.scope));
504 HasIfPCDVisitor ifFinder = new HasIfPCDVisitor();
505 pc.traverse(ifFinder, null);
506 containsIfPcd = ifFinder.containsIfPcd;
507 } catch(ParserException pEx) {
508 methodDeclaration.scope.problemReporter().parseError(
509 pcLocation[0] + pEx.getLocation().getStart(),
510 pcLocation[0] + pEx.getLocation().getEnd() ,
512 pointcutExpression.toCharArray(),
514 new String[] {pEx.getMessage()});
517 boolean returnsVoid = false;
518 boolean returnsBoolean = false;
519 if ((methodDeclaration.returnType instanceof SingleTypeReference)) {
520 SingleTypeReference retType = (SingleTypeReference) methodDeclaration.returnType;
521 if (CharOperation.equals(voidType,retType.token)) returnsVoid = true;
522 if (CharOperation.equals(booleanType,retType.token)) returnsBoolean = true;
524 if (!returnsVoid && !containsIfPcd) {
525 methodDeclaration.scope.problemReporter().signalError(methodDeclaration.returnType.sourceStart,
526 methodDeclaration.returnType.sourceEnd,
527 "Methods annotated with @Pointcut must return void unless the pointcut contains an if() expression");
529 if (!returnsBoolean && containsIfPcd) {
530 methodDeclaration.scope.problemReporter().signalError(methodDeclaration.returnType.sourceStart,
531 methodDeclaration.returnType.sourceEnd,
532 "Methods annotated with @Pointcut must return boolean when the pointcut contains an if() expression");
535 if (methodDeclaration.statements != null && methodDeclaration.statements.length > 0 && !containsIfPcd) {
536 methodDeclaration.scope.problemReporter().signalError(methodDeclaration.returnType.sourceStart,
537 methodDeclaration.returnType.sourceEnd,
538 "Pointcuts without an if() expression should have an empty method body");
542 private void copyAllFields(MethodDeclaration from, MethodDeclaration to) {
543 to.annotations = from.annotations;
544 to.arguments = from.arguments;
545 to.binding = from.binding;
547 to.bodyEnd = from.bodyEnd;
548 to.bodyStart = from.bodyStart;
549 to.declarationSourceEnd = from.declarationSourceEnd;
550 to.declarationSourceStart = from.declarationSourceStart;
551 to.errorInSignature = from.errorInSignature;
552 to.explicitDeclarations = from.explicitDeclarations;
553 to.ignoreFurtherInvestigation = from.ignoreFurtherInvestigation;
554 to.javadoc = from.javadoc;
555 to.modifiers = from.modifiers;
556 to.modifiersSourceStart = from.modifiersSourceStart;
557 to.needFreeReturn = from.needFreeReturn;
558 to.returnType = from.returnType;
559 to.scope = from.scope;
560 to.selector = from.selector;
561 to.sourceEnd = from.sourceEnd;
562 to.sourceStart = from.sourceStart;
563 to.statements = from.statements;
564 to.thrownExceptions = from.thrownExceptions;
565 to.typeParameters = from.typeParameters;
568 private void swap(TypeDeclaration inType, MethodDeclaration thisDeclaration, MethodDeclaration forThatDeclaration) {
569 for (int i = 0; i < inType.methods.length; i++) {
570 if (inType.methods[i] == thisDeclaration) {
571 inType.methods[i] = forThatDeclaration;
577 private static class AspectJAnnotations {
578 boolean hasAdviceAnnotation = false;
579 boolean hasPointcutAnnotation = false;
580 boolean hasAspectAnnotation = false;
581 boolean hasAdviceNameAnnotation = false;
583 boolean hasMultipleAdviceAnnotations = false;
584 boolean hasMultiplePointcutAnnotations = false;
585 boolean hasMultipleAspectAnnotations = false;
587 AdviceKind adviceKind = null;
588 Annotation adviceAnnotation = null;
589 Annotation pointcutAnnotation = null;
590 Annotation aspectAnnotation = null;
591 Annotation adviceNameAnnotation = null;
593 Annotation duplicateAdviceAnnotation = null;
594 Annotation duplicatePointcutAnnotation = null;
595 Annotation duplicateAspectAnnotation = null;
597 public AspectJAnnotations(Annotation[] annotations) {
598 if (annotations == null) return;
599 for (int i = 0; i < annotations.length; i++) {
600 if (annotations[i].resolvedType == null) continue; // user messed up annotation declaration
601 char[] sig = annotations[i].resolvedType.signature();
602 if (CharOperation.equals(afterAdviceSig,sig)) {
603 adviceKind = AdviceKind.After;
604 addAdviceAnnotation(annotations[i]);
605 } else if (CharOperation.equals(afterReturningAdviceSig,sig)) {
606 adviceKind = AdviceKind.AfterReturning;
607 addAdviceAnnotation(annotations[i]);
608 } else if (CharOperation.equals(afterThrowingAdviceSig,sig)) {
609 adviceKind = AdviceKind.AfterThrowing;
610 addAdviceAnnotation(annotations[i]);
611 } else if (CharOperation.equals(beforeAdviceSig,sig)) {
612 adviceKind = AdviceKind.Before;
613 addAdviceAnnotation(annotations[i]);
614 } else if (CharOperation.equals(aroundAdviceSig,sig)) {
615 adviceKind = AdviceKind.Around;
616 addAdviceAnnotation(annotations[i]);
617 } else if (CharOperation.equals(adviceNameSig,sig)) {
618 hasAdviceNameAnnotation = true;
619 adviceNameAnnotation = annotations[i];
620 } else if (CharOperation.equals(aspectSig,sig)) {
621 if (hasAspectAnnotation) {
622 hasMultipleAspectAnnotations = true;
623 duplicateAspectAnnotation = annotations[i];
625 hasAspectAnnotation = true;
626 aspectAnnotation = annotations[i];
628 } else if (CharOperation.equals(pointcutSig,sig)) {
629 if (hasPointcutAnnotation) {
630 hasMultiplePointcutAnnotations = true;
631 duplicatePointcutAnnotation = annotations[i];
633 hasPointcutAnnotation = true;
634 pointcutAnnotation = annotations[i];
641 public boolean hasAspectJAnnotations() {
642 return hasAdviceAnnotation || hasPointcutAnnotation || hasAdviceNameAnnotation || hasAspectAnnotation;
645 private void addAdviceAnnotation(Annotation annotation) {
646 if (!hasAdviceAnnotation) {
647 hasAdviceAnnotation = true;
648 adviceAnnotation = annotation;
650 hasMultipleAdviceAnnotations = true;
651 duplicateAdviceAnnotation = annotation;
656 private static class HasIfPCDVisitor extends AbstractPatternNodeVisitor {
657 public boolean containsIfPcd = false;
659 public Object visit(IfPointcut node, Object data) {
660 containsIfPcd = true;