123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763 |
- /* *******************************************************************
- * Copyright (c) 2005 IBM Corporation Ltd
- * All rights reserved.
- * This program and the accompanying materials are made available
- * under the terms of the Eclipse Public License v 2.0
- * which accompanies this distribution and is available at
- * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.txt
- *
- * Contributors:
- * Adrian Colyer initial implementation
- * ******************************************************************/
- package org.aspectj.ajdt.internal.compiler.ast;
-
- import java.lang.reflect.Modifier;
- import java.util.ArrayList;
- import java.util.List;
- import java.util.Stack;
-
- import org.aspectj.ajdt.internal.compiler.lookup.EclipseFactory;
- import org.aspectj.ajdt.internal.compiler.lookup.EclipseScope;
- import org.aspectj.ajdt.internal.core.builder.EclipseSourceContext;
- import org.aspectj.bridge.context.CompilationAndWeavingContext;
- import org.aspectj.bridge.context.ContextToken;
- import org.aspectj.org.eclipse.jdt.core.compiler.CharOperation;
- import org.aspectj.org.eclipse.jdt.internal.compiler.ASTVisitor;
- import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Annotation;
- import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Argument;
- import org.aspectj.org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
- import org.aspectj.org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
- import org.aspectj.org.eclipse.jdt.internal.compiler.ast.MemberValuePair;
- import org.aspectj.org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
- import org.aspectj.org.eclipse.jdt.internal.compiler.ast.NameReference;
- import org.aspectj.org.eclipse.jdt.internal.compiler.ast.NormalAnnotation;
- import org.aspectj.org.eclipse.jdt.internal.compiler.ast.SingleMemberAnnotation;
- import org.aspectj.org.eclipse.jdt.internal.compiler.ast.SingleTypeReference;
- import org.aspectj.org.eclipse.jdt.internal.compiler.ast.StringLiteral;
- import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
- import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeReference;
- import org.aspectj.org.eclipse.jdt.internal.compiler.impl.Constant;
- import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.Binding;
- import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.BlockScope;
- import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ClassScope;
- import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope;
- import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
- import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.MethodScope;
- import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
- import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
- import org.aspectj.weaver.AdviceKind;
- import org.aspectj.weaver.AjAttribute;
- import org.aspectj.weaver.ISourceContext;
- import org.aspectj.weaver.ResolvedPointcutDefinition;
- import org.aspectj.weaver.UnresolvedType;
- import org.aspectj.weaver.patterns.AbstractPatternNodeVisitor;
- import org.aspectj.weaver.patterns.FormalBinding;
- import org.aspectj.weaver.patterns.IfPointcut;
- import org.aspectj.weaver.patterns.ParserException;
- import org.aspectj.weaver.patterns.PatternParser;
- import org.aspectj.weaver.patterns.Pointcut;
-
- public class ValidateAtAspectJAnnotationsVisitor extends ASTVisitor {
-
- private static final char[] beforeAdviceSig = "Lorg/aspectj/lang/annotation/Before;".toCharArray();
- private static final char[] afterAdviceSig = "Lorg/aspectj/lang/annotation/After;".toCharArray();
- private static final char[] afterReturningAdviceSig = "Lorg/aspectj/lang/annotation/AfterReturning;".toCharArray();
- private static final char[] afterThrowingAdviceSig = "Lorg/aspectj/lang/annotation/AfterThrowing;".toCharArray();
- private static final char[] aroundAdviceSig = "Lorg/aspectj/lang/annotation/Around;".toCharArray();
- private static final char[] pointcutSig = "Lorg/aspectj/lang/annotation/Pointcut;".toCharArray();
- private static final char[] aspectSig = "Lorg/aspectj/lang/annotation/Aspect;".toCharArray();
- private static final char[] declareParentsSig = "Lorg/aspectj/lang/annotation/DeclareParents;".toCharArray();
- private static final char[] adviceNameSig = "Lorg/aspectj/lang/annotation/AdviceName;".toCharArray();
- // private static final char[] orgAspectJLangAnnotation =
- // "org/aspectj/lang/annotation/".toCharArray();
- private static final char[] voidType = "void".toCharArray();
- private static final char[] booleanType = "boolean".toCharArray();
- private static final char[] joinPoint = "Lorg/aspectj/lang/JoinPoint;".toCharArray();
- private static final char[] joinPointStaticPart = "Lorg/aspectj/lang/JoinPoint$StaticPart;".toCharArray();
- private static final char[] joinPointEnclosingStaticPart = "Lorg/aspectj/lang/JoinPoint$EnclosingStaticPart;".toCharArray();
- private static final char[] proceedingJoinPoint = "Lorg/aspectj/lang/ProceedingJoinPoint;".toCharArray();
- // private static final char[][] adviceSigs = new char[][] {
- // beforeAdviceSig, afterAdviceSig, afterReturningAdviceSig,
- // afterThrowingAdviceSig, aroundAdviceSig };
-
- private final CompilationUnitDeclaration unit;
- private final Stack<TypeDeclaration> typeStack = new Stack<>();
- private AspectJAnnotations ajAnnotations;
-
- public ValidateAtAspectJAnnotationsVisitor(CompilationUnitDeclaration unit) {
- this.unit = unit;
- }
-
- public boolean visit(TypeDeclaration localTypeDeclaration, BlockScope scope) {
- typeStack.push(localTypeDeclaration);
- ajAnnotations = new AspectJAnnotations(localTypeDeclaration.annotations);
- checkTypeDeclaration(localTypeDeclaration);
- return true;
- }
-
- public void endVisit(TypeDeclaration localTypeDeclaration, BlockScope scope) {
- typeStack.pop();
- }
-
- public boolean visit(TypeDeclaration memberTypeDeclaration, ClassScope scope) {
- typeStack.push(memberTypeDeclaration);
- ajAnnotations = new AspectJAnnotations(memberTypeDeclaration.annotations);
- checkTypeDeclaration(memberTypeDeclaration);
- return true;
- }
-
- public void endVisit(TypeDeclaration memberTypeDeclaration, ClassScope scope) {
- typeStack.pop();
- }
-
- public boolean visit(TypeDeclaration typeDeclaration, CompilationUnitScope scope) {
- typeStack.push(typeDeclaration);
- ajAnnotations = new AspectJAnnotations(typeDeclaration.annotations);
- checkTypeDeclaration(typeDeclaration);
- return true;
- }
-
- public void endVisit(TypeDeclaration typeDeclaration, CompilationUnitScope scope) {
- typeStack.pop();
- }
-
- private void checkTypeDeclaration(TypeDeclaration typeDecl) {
- ContextToken tok = CompilationAndWeavingContext.enteringPhase(
- CompilationAndWeavingContext.VALIDATING_AT_ASPECTJ_ANNOTATIONS, typeDecl.name);
- if (!(typeDecl instanceof AspectDeclaration)) {
- if (ajAnnotations.hasAspectAnnotation) {
- validateAspectDeclaration(typeDecl);
- } else {
- // check that class doesn't extend aspect
- TypeReference parentRef = typeDecl.superclass;
- if (parentRef != null) {
- TypeBinding parentBinding = parentRef.resolvedType;
- if (parentBinding instanceof SourceTypeBinding) {
- SourceTypeBinding parentSTB = (SourceTypeBinding) parentBinding;
- if (parentSTB.scope != null) {
- TypeDeclaration parentDecl = parentSTB.scope.referenceContext;
- if (isAspect(parentDecl)) {
- typeDecl.scope.problemReporter().signalError(typeDecl.sourceStart, typeDecl.sourceEnd,
- "a class cannot extend an aspect");
- }
- }
- }
- }
- }
- } else {
- // check that aspect doesn't have @Aspect annotation, we've already
- // added on ourselves.
- if (ajAnnotations.hasMultipleAspectAnnotations) {
- typeDecl.scope.problemReporter().signalError(typeDecl.sourceStart, typeDecl.sourceEnd,
- "aspects cannot have @Aspect annotation");
- }
- }
- CompilationAndWeavingContext.leavingPhase(tok);
- }
-
- public boolean visit(FieldDeclaration fieldDeclaration, MethodScope scope) {
- ajAnnotations = new AspectJAnnotations(fieldDeclaration.annotations);
- if (ajAnnotations.hasDeclareParents && !insideAspect()) {
- scope.problemReporter().signalError(fieldDeclaration.sourceStart, fieldDeclaration.sourceEnd,
- "DeclareParents can only be used inside an aspect type");
- }
- return true;
- }
-
- public boolean visit(MethodDeclaration methodDeclaration, ClassScope scope) {
- if (methodDeclaration.hasErrors()) {
- return false;
- }
- ContextToken tok = CompilationAndWeavingContext.enteringPhase(
- CompilationAndWeavingContext.VALIDATING_AT_ASPECTJ_ANNOTATIONS, methodDeclaration.selector);
- ajAnnotations = new AspectJAnnotations(methodDeclaration.annotations);
- if (!methodDeclaration.getClass().equals(AjMethodDeclaration.class)) {
- // simply test for innapropriate use of annotations on code-style
- // members
- if (methodDeclaration instanceof PointcutDeclaration) {
- if (ajAnnotations.hasMultiplePointcutAnnotations || ajAnnotations.hasAdviceAnnotation
- || ajAnnotations.hasAspectAnnotation || ajAnnotations.hasAdviceNameAnnotation) {
- methodDeclaration.scope.problemReporter().signalError(methodDeclaration.sourceStart,
- methodDeclaration.sourceEnd, "@AspectJ annotations cannot be declared on this aspect member");
- }
- } else if (methodDeclaration instanceof AdviceDeclaration) {
- if (ajAnnotations.hasMultipleAdviceAnnotations || ajAnnotations.hasAspectAnnotation
- || ajAnnotations.hasPointcutAnnotation) {
- methodDeclaration.scope.problemReporter().signalError(methodDeclaration.sourceStart,
- methodDeclaration.sourceEnd, "Only @AdviceName AspectJ annotation allowed on advice");
- }
- } else {
- if (ajAnnotations.hasAspectJAnnotations()) {
- methodDeclaration.scope.problemReporter().signalError(methodDeclaration.sourceStart,
- methodDeclaration.sourceEnd, "@AspectJ annotations cannot be declared on this aspect member");
- }
- }
- CompilationAndWeavingContext.leavingPhase(tok);
- return false;
- }
-
- if (ajAnnotations.hasAdviceAnnotation) {
- validateAdvice(methodDeclaration);
- } else if (ajAnnotations.hasPointcutAnnotation) {
- convertToPointcutDeclaration(methodDeclaration, scope);
- }
- CompilationAndWeavingContext.leavingPhase(tok);
- return false;
- }
-
- // private boolean isAspectJAnnotation(Annotation ann) {
- // if (ann.resolvedType == null) return false;
- // char[] sig = ann.resolvedType.signature();
- // return CharOperation.contains(orgAspectJLangAnnotation, sig);
- // }
-
- private boolean insideAspect() {
- if (typeStack.empty())
- return false;
- TypeDeclaration typeDecl = (TypeDeclaration) typeStack.peek();
- return isAspect(typeDecl);
- }
-
- private boolean isAspect(TypeDeclaration typeDecl) {
- if (typeDecl instanceof AspectDeclaration)
- return true;
- return new AspectJAnnotations(typeDecl.annotations).hasAspectAnnotation;
- }
-
- /**
- * aspect must be public nested aspect must be static cannot extend a concrete aspect pointcut in perclause must be good.
- */
- private void validateAspectDeclaration(TypeDeclaration typeDecl) {
- if (typeStack.size() > 1) {
- // it's a nested aspect
- if (!Modifier.isStatic(typeDecl.modifiers)) {
- typeDecl.scope.problemReporter().signalError(typeDecl.sourceStart, typeDecl.sourceEnd,
- "inner aspects must be static");
- return;
- }
- }
-
- SourceTypeBinding binding = typeDecl.binding;
- if (binding != null) {
- if (binding.isEnum() || binding.isInterface() || binding.isAnnotationType()) {
- typeDecl.scope.problemReporter().signalError(typeDecl.sourceStart, typeDecl.sourceEnd,
- "only classes can have an @Aspect annotation");
- }
- }
-
- // FIXME AV - do we really want that
- // if (!Modifier.isPublic(typeDecl.modifiers)) {
- // typeDecl.scope.problemReporter().signalError(typeDecl.sourceStart,
- // typeDecl.sourceEnd,"@Aspect class must be public");
- // }
-
- TypeReference parentRef = typeDecl.superclass;
- if (parentRef != null) {
- TypeBinding parentBinding = parentRef.resolvedType;
- if (parentBinding instanceof SourceTypeBinding) {
- SourceTypeBinding parentSTB = (SourceTypeBinding) parentBinding;
- if (parentSTB.scope != null) { // scope is null if its a
- // binarytypebinding (in AJ
- // world, thats a subclass of
- // SourceTypeBinding)
- TypeDeclaration parentDecl = parentSTB.scope.referenceContext;
- if (isAspect(parentDecl) && !Modifier.isAbstract(parentDecl.modifiers)) {
- typeDecl.scope.problemReporter().signalError(typeDecl.sourceStart, typeDecl.sourceEnd,
- "cannot extend a concrete aspect");
- }
- }
- }
- }
-
- Annotation aspectAnnotation = ajAnnotations.aspectAnnotation;
-
- int[] pcLoc = new int[2];
- String perClause = getStringLiteralFor("value", aspectAnnotation, pcLoc);
- // AspectDeclaration aspectDecl = new
- // AspectDeclaration(typeDecl.compilationResult);
-
- try {
- if (perClause != null && !perClause.equals("")) {
- ISourceContext context = new EclipseSourceContext(unit.compilationResult, pcLoc[0]);
- Pointcut pc = new PatternParser(perClause, context).maybeParsePerClause();
- FormalBinding[] bindings = FormalBinding.NONE;
- if (pc != null)
- pc.resolve(new EclipseScope(bindings, typeDecl.scope));
- }
- } catch (ParserException pEx) {
- typeDecl.scope.problemReporter().parseError(pcLoc[0] + pEx.getLocation().getStart(),
- pcLoc[0] + pEx.getLocation().getEnd(), -1, perClause.toCharArray(), perClause,
- new String[] { pEx.getMessage() });
- }
- }
-
- /**
- * 1) Advice must be public 2) Advice must have a void return type if not around advice 3) Advice must not have any other @AspectJ
- * annotations 4) After throwing advice must declare the thrown formal 5) After returning advice must declare the returning
- * formal 6) Advice must not be static
- */
- private void validateAdvice(MethodDeclaration methodDeclaration) {
-
- if (!insideAspect()) {
- methodDeclaration.scope.problemReporter().signalError(methodDeclaration.sourceStart, methodDeclaration.sourceEnd,
- "Advice must be declared inside an aspect type");
- }
-
- if (!Modifier.isPublic(methodDeclaration.modifiers)) {
- methodDeclaration.scope.problemReporter().signalError(methodDeclaration.sourceStart, methodDeclaration.sourceEnd,
- "advice must be public");
- }
-
- if (Modifier.isStatic(methodDeclaration.modifiers)) {
- methodDeclaration.scope.problemReporter().signalError(methodDeclaration.sourceStart, methodDeclaration.sourceEnd,
- "advice can not be declared static");
- }
-
- if (ajAnnotations.hasMultipleAdviceAnnotations) {
- methodDeclaration.scope.problemReporter().disallowedTargetForAnnotation(ajAnnotations.duplicateAdviceAnnotation);
- }
- if (ajAnnotations.hasPointcutAnnotation) {
- methodDeclaration.scope.problemReporter().disallowedTargetForAnnotation(ajAnnotations.pointcutAnnotation);
- }
- if (ajAnnotations.hasAspectAnnotation) {
- methodDeclaration.scope.problemReporter().disallowedTargetForAnnotation(ajAnnotations.aspectAnnotation);
- }
- if (ajAnnotations.hasAdviceNameAnnotation) {
- methodDeclaration.scope.problemReporter().disallowedTargetForAnnotation(ajAnnotations.adviceNameAnnotation);
- }
-
- if (ajAnnotations.adviceKind != AdviceKind.Around) {
- ensureVoidReturnType(methodDeclaration);
- }
-
- if (ajAnnotations.adviceKind == AdviceKind.AfterThrowing) {
- int[] throwingLocation = new int[2];
- String thrownFormal = getStringLiteralFor("throwing", ajAnnotations.adviceAnnotation, throwingLocation);
- if (thrownFormal != null) {
- // Argument[] arguments = methodDeclaration.arguments;
- if (!toArgumentNames(methodDeclaration.arguments).contains(thrownFormal)) {
- methodDeclaration.scope.problemReporter().signalError(methodDeclaration.sourceStart,
- methodDeclaration.sourceEnd,
- "throwing formal '" + thrownFormal + "' must be declared as a parameter in the advice signature");
- }
- }
- }
-
- if (ajAnnotations.adviceKind == AdviceKind.AfterReturning) {
- int[] throwingLocation = new int[2];
- String returningFormal = getStringLiteralFor("returning", ajAnnotations.adviceAnnotation, throwingLocation);
- if (returningFormal != null) {
- if (!toArgumentNames(methodDeclaration.arguments).contains(returningFormal)) {
- methodDeclaration.scope.problemReporter().signalError(methodDeclaration.sourceStart,
- methodDeclaration.sourceEnd,
- "returning formal '" + returningFormal + "' must be declared as a parameter in the advice signature");
- }
- }
- }
-
- resolveAndSetPointcut(methodDeclaration, ajAnnotations.adviceAnnotation);
-
- }
-
- /**
- * Get the argument names as a string list
- *
- * @param arguments
- * @return argument names (possibly empty)
- */
- private List<String> toArgumentNames(Argument[] arguments) {
- List<String> names = new ArrayList<>();
- if (arguments == null) {
- return names;
- } else {
- for (Argument argument : arguments) {
- names.add(new String(argument.name));
- }
- return names;
- }
- }
-
- private void resolveAndSetPointcut(MethodDeclaration methodDeclaration, Annotation adviceAnn) {
- int[] pcLocation = new int[2];
- String pointcutExpression = getStringLiteralFor("pointcut", adviceAnn, pcLocation);
- if (pointcutExpression == null)
- pointcutExpression = getStringLiteralFor("value", adviceAnn, pcLocation);
- try {
- // +1 to give first char of pointcut string
- ISourceContext context = new EclipseSourceContext(unit.compilationResult, pcLocation[0] + 1);
- if (pointcutExpression == null) {
- methodDeclaration.scope.problemReporter().signalError(methodDeclaration.sourceStart,
- methodDeclaration.sourceEnd, "the advice annotation must specify a pointcut value");
- return;
- }
- PatternParser pp = new PatternParser(pointcutExpression, context);
- Pointcut pc = pp.parsePointcut();
- pp.checkEof();
- FormalBinding[] bindings = buildFormalAdviceBindingsFrom(methodDeclaration);
- pc.resolve(new EclipseScope(bindings, methodDeclaration.scope));
- EclipseFactory factory = EclipseFactory.fromScopeLookupEnvironment(methodDeclaration.scope);
- // now create a ResolvedPointcutDefinition,make an attribute out of
- // it, and add it to the method
- UnresolvedType[] paramTypes = new UnresolvedType[bindings.length];
- for (int i = 0; i < paramTypes.length; i++)
- paramTypes[i] = bindings[i].getType();
- ResolvedPointcutDefinition resPcutDef = new ResolvedPointcutDefinition(factory.fromBinding(((TypeDeclaration) typeStack
- .peek()).binding), methodDeclaration.modifiers, "anonymous", paramTypes, pc);
- AjAttribute attr = new AjAttribute.PointcutDeclarationAttribute(resPcutDef);
- ((AjMethodDeclaration) methodDeclaration).addAttribute(new EclipseAttributeAdapter(attr));
- } catch (ParserException pEx) {
- methodDeclaration.scope.problemReporter().parseError(pcLocation[0] + pEx.getLocation().getStart(),
- pcLocation[0] + pEx.getLocation().getEnd(), -1, pointcutExpression.toCharArray(), pointcutExpression,
- new String[] { pEx.getMessage() });
- }
- }
-
- private void ensureVoidReturnType(MethodDeclaration methodDeclaration) {
- boolean returnsVoid = true;
- if ((methodDeclaration.returnType instanceof SingleTypeReference)) {
- SingleTypeReference retType = (SingleTypeReference) methodDeclaration.returnType;
- if (!CharOperation.equals(voidType, retType.token)) {
- returnsVoid = false;
- }
- } else {
- returnsVoid = false;
- }
- if (!returnsVoid) {
- methodDeclaration.scope.problemReporter().signalError(methodDeclaration.returnType.sourceStart,
- methodDeclaration.returnType.sourceEnd, "This advice must return void");
- }
- }
-
- private FormalBinding[] buildFormalAdviceBindingsFrom(MethodDeclaration mDecl) {
- if (mDecl.arguments == null)
- return FormalBinding.NONE;
- if (mDecl.binding == null)
- return FormalBinding.NONE;
- EclipseFactory factory = EclipseFactory.fromScopeLookupEnvironment(mDecl.scope);
- String extraArgName = maybeGetExtraArgName();
- if (extraArgName == null)
- extraArgName = "";
- FormalBinding[] ret = new FormalBinding[mDecl.arguments.length];
- for (int i = 0; i < mDecl.arguments.length; i++) {
- Argument arg = mDecl.arguments[i];
- String name = new String(arg.name);
- TypeBinding argTypeBinding = mDecl.binding.parameters[i];
- UnresolvedType type = factory.fromBinding(argTypeBinding);
- if (CharOperation.equals(joinPoint, argTypeBinding.signature())
- || CharOperation.equals(joinPointStaticPart, argTypeBinding.signature())
- || CharOperation.equals(joinPointEnclosingStaticPart, argTypeBinding.signature())
- || CharOperation.equals(proceedingJoinPoint, argTypeBinding.signature()) || name.equals(extraArgName)) {
- ret[i] = new FormalBinding.ImplicitFormalBinding(type, name, i);
- } else {
- ret[i] = new FormalBinding(type, name, i, arg.sourceStart, arg.sourceEnd);
- }
- }
- return ret;
- }
-
- private String maybeGetExtraArgName() {
- String argName = null;
- if (ajAnnotations.adviceKind == AdviceKind.AfterReturning) {
- argName = getStringLiteralFor("returning", ajAnnotations.adviceAnnotation, new int[2]);
- } else if (ajAnnotations.adviceKind == AdviceKind.AfterThrowing) {
- argName = getStringLiteralFor("throwing", ajAnnotations.adviceAnnotation, new int[2]);
- }
- return argName;
- }
-
- private String getStringLiteralFor(String memberName, Annotation inAnnotation, int[] location) {
- if (inAnnotation instanceof SingleMemberAnnotation && memberName.equals("value")) {
- SingleMemberAnnotation sma = (SingleMemberAnnotation) inAnnotation;
- if (sma.memberValue instanceof StringLiteral) {
- StringLiteral sv = (StringLiteral) sma.memberValue;
- location[0] = sv.sourceStart;
- location[1] = sv.sourceEnd;
- return new String(sv.source());
- } else if (sma.memberValue instanceof NameReference
- && (((NameReference) sma.memberValue).binding instanceof FieldBinding)) {
- Binding b = ((NameReference) sma.memberValue).binding;
- Constant c = ((FieldBinding) b).constant();
- return c.stringValue();
- }
- }
- if (!(inAnnotation instanceof NormalAnnotation))
- return null;
- NormalAnnotation ann = (NormalAnnotation) inAnnotation;
- MemberValuePair[] mvps = ann.memberValuePairs;
- if (mvps == null)
- return null;
- for (MemberValuePair mvp : mvps) {
- if (CharOperation.equals(memberName.toCharArray(), mvp.name)) {
- if (mvp.value instanceof StringLiteral) {
- StringLiteral sv = (StringLiteral) mvp.value;
- location[0] = sv.sourceStart;
- location[1] = sv.sourceEnd;
- return new String(sv.source());
- }
- }
- }
- return null;
- }
-
- private void convertToPointcutDeclaration(MethodDeclaration methodDeclaration, ClassScope scope) {
- TypeDeclaration typeDecl = (TypeDeclaration) typeStack.peek();
- if (typeDecl.binding != null) {
- if (!typeDecl.binding.isClass()) {
- methodDeclaration.scope.problemReporter().signalError(methodDeclaration.sourceStart, methodDeclaration.sourceEnd,
- "pointcuts can only be declared in a class or an aspect");
- }
- }
-
- if (methodDeclaration.thrownExceptions != null && methodDeclaration.thrownExceptions.length > 0) {
- methodDeclaration.scope.problemReporter().signalError(methodDeclaration.sourceStart, methodDeclaration.sourceEnd,
- "pointcuts cannot throw exceptions!");
- }
-
- PointcutDeclaration pcDecl = new PointcutDeclaration(unit.compilationResult);
- copyAllFields(methodDeclaration, pcDecl);
-
- if (ajAnnotations.hasAdviceAnnotation) {
- methodDeclaration.scope.problemReporter().disallowedTargetForAnnotation(ajAnnotations.adviceAnnotation);
- }
- if (ajAnnotations.hasAspectAnnotation) {
- methodDeclaration.scope.problemReporter().disallowedTargetForAnnotation(ajAnnotations.aspectAnnotation);
- }
- if (ajAnnotations.hasAdviceNameAnnotation) {
- methodDeclaration.scope.problemReporter().disallowedTargetForAnnotation(ajAnnotations.adviceNameAnnotation);
- }
-
- boolean noValueSupplied = true;
- boolean containsIfPcd = false;
- boolean isIfTrueOrFalse = false;
- int[] pcLocation = new int[2];
- String pointcutExpression = getStringLiteralFor("value", ajAnnotations.pointcutAnnotation, pcLocation);
- try {
- ISourceContext context = new EclipseSourceContext(unit.compilationResult, pcLocation[0]);
- Pointcut pc = null;// abstract
- if (pointcutExpression == null || pointcutExpression.length() == 0) {
- noValueSupplied = true; // matches nothing pointcut
- } else {
- noValueSupplied = false;
- pc = new PatternParser(pointcutExpression, context).parsePointcut();
- if (pc instanceof IfPointcut) {
- if (((IfPointcut)pc).alwaysFalse() || ((IfPointcut)pc).alwaysTrue()) {
- isIfTrueOrFalse = true;
- }
- }
- }
- pcDecl.pointcutDesignator = (pc == null) ? null : new PointcutDesignator(pc);
- pcDecl.setGenerateSyntheticPointcutMethod();
- TypeDeclaration onType = (TypeDeclaration) typeStack.peek();
- pcDecl.postParse(onType);
- // EclipseFactory factory =
- // EclipseFactory.fromScopeLookupEnvironment
- // (methodDeclaration.scope);
- // int argsLength = methodDeclaration.arguments == null ? 0 :
- // methodDeclaration.arguments.length;
- FormalBinding[] bindings = buildFormalAdviceBindingsFrom(methodDeclaration);
- // FormalBinding[] bindings = new FormalBinding[argsLength];
- // for (int i = 0, len = bindings.length; i < len; i++) {
- // Argument arg = methodDeclaration.arguments[i];
- // String name = new String(arg.name);
- // UnresolvedType type =
- // factory.fromBinding(methodDeclaration.binding.parameters[i]);
- // bindings[i] = new FormalBinding(type, name, i, arg.sourceStart,
- // arg.sourceEnd, "unknown");
- // }
- swap(onType, methodDeclaration, pcDecl);
- if (pc != null) {
- // has an expression
- EclipseScope eScope = new EclipseScope(bindings, methodDeclaration.scope);
- char[] packageName = null;
- if (typeDecl.binding != null && typeDecl.binding.getPackage() != null) {
- packageName = typeDecl.binding.getPackage().readableName();
- }
- eScope.setLimitedImports(packageName);
- pc.resolve(eScope);
- HasIfPCDVisitor ifFinder = new HasIfPCDVisitor();
- pc.traverse(ifFinder, null);
- containsIfPcd = ifFinder.containsIfPcd;
- }
- } catch (ParserException pEx) {
- methodDeclaration.scope.problemReporter().parseError(pcLocation[0] + pEx.getLocation().getStart(),
- pcLocation[0] + pEx.getLocation().getEnd(), -1, pointcutExpression.toCharArray(), pointcutExpression,
- new String[] { pEx.getMessage() });
- }
-
- boolean returnsVoid = false;
- boolean returnsBoolean = false;
- if ((methodDeclaration.returnType instanceof SingleTypeReference)) {
- SingleTypeReference retType = (SingleTypeReference) methodDeclaration.returnType;
- if (CharOperation.equals(voidType, retType.token))
- returnsVoid = true;
- if (CharOperation.equals(booleanType, retType.token))
- returnsBoolean = true;
- }
- if (!returnsVoid && !containsIfPcd) {
- methodDeclaration.scope.problemReporter().signalError(methodDeclaration.returnType.sourceStart,
- methodDeclaration.returnType.sourceEnd,
- "Methods annotated with @Pointcut must return void unless the pointcut contains an if() expression");
- }
- if (!returnsBoolean && containsIfPcd && !isIfTrueOrFalse) {
- methodDeclaration.scope.problemReporter().signalError(methodDeclaration.returnType.sourceStart,
- methodDeclaration.returnType.sourceEnd,
- "Methods annotated with @Pointcut must return boolean when the pointcut contains an if() expression unless it is if(false) or if(true)");
- }
-
- if (methodDeclaration.statements != null && methodDeclaration.statements.length > 0 && !containsIfPcd) {
- methodDeclaration.scope.problemReporter()
- .signalError(methodDeclaration.returnType.sourceStart, methodDeclaration.returnType.sourceEnd,
- "Pointcuts without an if() expression should have an empty method body");
- }
-
- if (pcDecl.pointcutDesignator == null) {
- if (Modifier.isAbstract(methodDeclaration.modifiers) || noValueSupplied // this
- // is
- // a
- // matches
- // nothing
- // pointcut
- // those 2 checks makes sense for aop.xml concretization but NOT for
- // regular abstraction of pointcut
- // && returnsVoid
- // && (methodDeclaration.arguments == null ||
- // methodDeclaration.arguments.length == 0)) {
- ) {
- // fine
- } else {
- methodDeclaration.scope.problemReporter().signalError(methodDeclaration.returnType.sourceStart,
- methodDeclaration.returnType.sourceEnd,
- "Method annotated with @Pointcut() for abstract pointcut must be abstract");
- }
- } else if (Modifier.isAbstract(methodDeclaration.modifiers)) {
- methodDeclaration.scope.problemReporter().signalError(methodDeclaration.returnType.sourceStart,
- methodDeclaration.returnType.sourceEnd,
- "Method annotated with non abstract @Pointcut(\"" + pointcutExpression + "\") is abstract");
- }
- }
-
- private void copyAllFields(MethodDeclaration from, MethodDeclaration to) {
- to.annotations = from.annotations;
- to.arguments = from.arguments;
- to.binding = from.binding;
- to.bits = from.bits;
- to.bodyEnd = from.bodyEnd;
- to.bodyStart = from.bodyStart;
- to.declarationSourceEnd = from.declarationSourceEnd;
- to.declarationSourceStart = from.declarationSourceStart;
- to.explicitDeclarations = from.explicitDeclarations;
- to.ignoreFurtherInvestigation = from.ignoreFurtherInvestigation;
- to.javadoc = from.javadoc;
- to.modifiers = from.modifiers;
- to.modifiersSourceStart = from.modifiersSourceStart;
- to.returnType = from.returnType;
- to.scope = from.scope;
- to.selector = from.selector;
- to.sourceEnd = from.sourceEnd;
- to.sourceStart = from.sourceStart;
- to.statements = from.statements;
- to.thrownExceptions = from.thrownExceptions;
- to.typeParameters = from.typeParameters;
- }
-
- private void swap(TypeDeclaration inType, MethodDeclaration thisDeclaration, MethodDeclaration forThatDeclaration) {
- for (int i = 0; i < inType.methods.length; i++) {
- if (inType.methods[i] == thisDeclaration) {
- inType.methods[i] = forThatDeclaration;
- break;
- }
- }
- }
-
- private static class AspectJAnnotations {
- boolean hasAdviceAnnotation = false;
- boolean hasPointcutAnnotation = false;
- boolean hasAspectAnnotation = false;
- boolean hasAdviceNameAnnotation = false;
- boolean hasDeclareParents = false;
- boolean hasMultipleAdviceAnnotations = false;
- boolean hasMultiplePointcutAnnotations = false;
- boolean hasMultipleAspectAnnotations = false;
-
- AdviceKind adviceKind = null;
- Annotation adviceAnnotation = null;
- Annotation pointcutAnnotation = null;
- Annotation aspectAnnotation = null;
- Annotation adviceNameAnnotation = null;
-
- Annotation duplicateAdviceAnnotation = null;
- Annotation duplicatePointcutAnnotation = null;
- Annotation duplicateAspectAnnotation = null;
-
- public AspectJAnnotations(Annotation[] annotations) {
- if (annotations == null)
- return;
- for (Annotation annotation : annotations) {
- if (annotation.resolvedType == null)
- continue; // user messed up annotation declaration
- char[] sig = annotation.resolvedType.signature();
- if (CharOperation.equals(afterAdviceSig, sig)) {
- adviceKind = AdviceKind.After;
- addAdviceAnnotation(annotation);
- } else if (CharOperation.equals(afterReturningAdviceSig, sig)) {
- adviceKind = AdviceKind.AfterReturning;
- addAdviceAnnotation(annotation);
- } else if (CharOperation.equals(afterThrowingAdviceSig, sig)) {
- adviceKind = AdviceKind.AfterThrowing;
- addAdviceAnnotation(annotation);
- } else if (CharOperation.equals(beforeAdviceSig, sig)) {
- adviceKind = AdviceKind.Before;
- addAdviceAnnotation(annotation);
- } else if (CharOperation.equals(aroundAdviceSig, sig)) {
- adviceKind = AdviceKind.Around;
- addAdviceAnnotation(annotation);
- } else if (CharOperation.equals(adviceNameSig, sig)) {
- hasAdviceNameAnnotation = true;
- adviceNameAnnotation = annotation;
- } else if (CharOperation.equals(declareParentsSig, sig)) {
- hasDeclareParents = true;
- } else if (CharOperation.equals(aspectSig, sig)) {
- if (hasAspectAnnotation) {
- hasMultipleAspectAnnotations = true;
- duplicateAspectAnnotation = annotation;
- } else {
- hasAspectAnnotation = true;
- aspectAnnotation = annotation;
- }
- } else if (CharOperation.equals(pointcutSig, sig)) {
- if (hasPointcutAnnotation) {
- hasMultiplePointcutAnnotations = true;
- duplicatePointcutAnnotation = annotation;
- } else {
- hasPointcutAnnotation = true;
- pointcutAnnotation = annotation;
- }
-
- }
- }
- }
-
- public boolean hasAspectJAnnotations() {
- return hasAdviceAnnotation || hasPointcutAnnotation || hasAdviceNameAnnotation || hasAspectAnnotation;
- }
-
- private void addAdviceAnnotation(Annotation annotation) {
- if (!hasAdviceAnnotation) {
- hasAdviceAnnotation = true;
- adviceAnnotation = annotation;
- } else {
- hasMultipleAdviceAnnotations = true;
- duplicateAdviceAnnotation = annotation;
- }
- }
- }
-
- private static class HasIfPCDVisitor extends AbstractPatternNodeVisitor {
- public boolean containsIfPcd = false;
-
- public Object visit(IfPointcut node, Object data) {
- containsIfPcd = true;
- return data;
- }
- }
- }
|