diff options
author | aclement <aclement> | 2008-12-10 05:00:55 +0000 |
---|---|---|
committer | aclement <aclement> | 2008-12-10 05:00:55 +0000 |
commit | 44c40113a96fa4238c8f5dbed5242f8054a757ab (patch) | |
tree | 1448820f709edb0f5cd432a02fb2b5e12712c614 /org.aspectj.matcher/src | |
parent | da08b5a5c309ea75fe64c5394bf9e2d88268aef5 (diff) | |
download | aspectj-44c40113a96fa4238c8f5dbed5242f8054a757ab.tar.gz aspectj-44c40113a96fa4238c8f5dbed5242f8054a757ab.zip |
split weaving/matching: pointcut matching tests
Diffstat (limited to 'org.aspectj.matcher/src')
5 files changed, 1508 insertions, 3 deletions
diff --git a/org.aspectj.matcher/src/org/aspectj/weaver/internal/tools/StandardPointcutExpressionImpl.java b/org.aspectj.matcher/src/org/aspectj/weaver/internal/tools/StandardPointcutExpressionImpl.java new file mode 100644 index 000000000..2459366f0 --- /dev/null +++ b/org.aspectj.matcher/src/org/aspectj/weaver/internal/tools/StandardPointcutExpressionImpl.java @@ -0,0 +1,374 @@ +/* ******************************************************************* + * Copyright (c) 2004 IBM Corporation. + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * ******************************************************************/ +package org.aspectj.weaver.internal.tools; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Member; +import java.lang.reflect.Method; + +import org.aspectj.weaver.ResolvedMember; +import org.aspectj.weaver.ResolvedType; +import org.aspectj.weaver.Shadow; +import org.aspectj.weaver.World; +import org.aspectj.weaver.ast.Literal; +import org.aspectj.weaver.ast.Test; +import org.aspectj.weaver.patterns.AbstractPatternNodeVisitor; +import org.aspectj.weaver.patterns.AnnotationPointcut; +import org.aspectj.weaver.patterns.ArgsAnnotationPointcut; +import org.aspectj.weaver.patterns.ArgsPointcut; +import org.aspectj.weaver.patterns.CflowPointcut; +import org.aspectj.weaver.patterns.ExposedState; +import org.aspectj.weaver.patterns.IfPointcut; +import org.aspectj.weaver.patterns.NotAnnotationTypePattern; +import org.aspectj.weaver.patterns.NotPointcut; +import org.aspectj.weaver.patterns.Pointcut; +import org.aspectj.weaver.patterns.ThisOrTargetAnnotationPointcut; +import org.aspectj.weaver.patterns.ThisOrTargetPointcut; +import org.aspectj.weaver.patterns.WithinAnnotationPointcut; +import org.aspectj.weaver.patterns.WithinCodeAnnotationPointcut; +import org.aspectj.weaver.reflect.ReflectionFastMatchInfo; +import org.aspectj.weaver.reflect.ReflectionShadow; +import org.aspectj.weaver.reflect.ShadowMatchImpl; +import org.aspectj.weaver.reflect.StandardShadow; +import org.aspectj.weaver.tools.DefaultMatchingContext; +import org.aspectj.weaver.tools.MatchingContext; +import org.aspectj.weaver.tools.PointcutParameter; +import org.aspectj.weaver.tools.ShadowMatch; +import org.aspectj.weaver.tools.StandardPointcutExpression; + +/** + * Map from weaver.tools interface to internal Pointcut implementation... + */ +public class StandardPointcutExpressionImpl implements StandardPointcutExpression { + + private World world; + private Pointcut pointcut; + private String expression; + private PointcutParameter[] parameters; + private MatchingContext matchContext = new DefaultMatchingContext(); + + public StandardPointcutExpressionImpl(Pointcut pointcut, String expression, PointcutParameter[] params, World inWorld) { + this.pointcut = pointcut; + this.expression = expression; + this.world = inWorld; + this.parameters = params; + if (this.parameters == null) + this.parameters = new PointcutParameter[0]; + } + + public Pointcut getUnderlyingPointcut() { + return this.pointcut; + } + + /* + * (non-Javadoc) + * + * @see org.aspectj.weaver.tools.PointcutExpression#setMatchingContext(org.aspectj.weaver.tools.MatchingContext) + */ + public void setMatchingContext(MatchingContext aMatchContext) { + this.matchContext = aMatchContext; + } + + public boolean couldMatchJoinPointsInType(Class aClass) { + ResolvedType matchType = world.resolve(aClass.getName()); + ReflectionFastMatchInfo info = new ReflectionFastMatchInfo(matchType, null, this.matchContext); + return pointcut.fastMatch(info).maybeTrue(); + } + + public boolean mayNeedDynamicTest() { + HasPossibleDynamicContentVisitor visitor = new HasPossibleDynamicContentVisitor(); + pointcut.traverse(visitor, null); + return visitor.hasDynamicContent(); + } + + private ExposedState getExposedState() { + return new ExposedState(parameters.length); + } + + public ShadowMatch matchesMethodExecution(Method aMethod) { + return matchesExecution(aMethod); + } + + public ShadowMatch matchesMethodExecution(ResolvedMember aMethod) { + return matchesExecution(aMethod); + } + + public ShadowMatch matchesConstructorExecution(Constructor aConstructor) { + return matchesExecution(aConstructor); + } + + private ShadowMatch matchesExecution(Member aMember) { + Shadow s = ReflectionShadow.makeExecutionShadow(world, aMember, this.matchContext); + ShadowMatchImpl sm = getShadowMatch(s); + sm.setSubject(aMember); + sm.setWithinCode(null); + sm.setWithinType(aMember.getDeclaringClass()); + return sm; + } + + private ShadowMatch matchesExecution(ResolvedMember aMember) { + Shadow s = StandardShadow.makeExecutionShadow(world, aMember, this.matchContext); + ShadowMatchImpl sm = getShadowMatch(s); + // sm.setSubject(aMember); + // sm.setWithinCode(null); + // sm.setWithinType(aMember.getDeclaringClass()); + return sm; + } + + public ShadowMatch matchesStaticInitialization(Class aClass) { + Shadow s = ReflectionShadow.makeStaticInitializationShadow(world, aClass, this.matchContext); + ShadowMatchImpl sm = getShadowMatch(s); + sm.setSubject(null); + sm.setWithinCode(null); + sm.setWithinType(aClass); + return sm; + } + + public ShadowMatch matchesStaticInitialization(ResolvedType type) { + Shadow s = StandardShadow.makeStaticInitializationShadow(world, type, this.matchContext); + ShadowMatchImpl sm = getShadowMatch(s); + sm.setSubject(null); + sm.setWithinCode(null); + // sm.setWithinType(aClass); + return sm; + } + + public ShadowMatch matchesAdviceExecution(Method aMethod) { + Shadow s = ReflectionShadow.makeAdviceExecutionShadow(world, aMethod, this.matchContext); + ShadowMatchImpl sm = getShadowMatch(s); + sm.setSubject(aMethod); + sm.setWithinCode(null); + sm.setWithinType(aMethod.getDeclaringClass()); + return sm; + } + + public ShadowMatch matchesInitialization(Constructor aConstructor) { + Shadow s = ReflectionShadow.makeInitializationShadow(world, aConstructor, this.matchContext); + ShadowMatchImpl sm = getShadowMatch(s); + sm.setSubject(aConstructor); + sm.setWithinCode(null); + sm.setWithinType(aConstructor.getDeclaringClass()); + return sm; + } + + public ShadowMatch matchesPreInitialization(Constructor aConstructor) { + Shadow s = ReflectionShadow.makePreInitializationShadow(world, aConstructor, this.matchContext); + ShadowMatchImpl sm = getShadowMatch(s); + sm.setSubject(aConstructor); + sm.setWithinCode(null); + sm.setWithinType(aConstructor.getDeclaringClass()); + return sm; + } + + public ShadowMatch matchesMethodCall(Method aMethod, Member withinCode) { + Shadow s = ReflectionShadow.makeCallShadow(world, aMethod, withinCode, this.matchContext); + ShadowMatchImpl sm = getShadowMatch(s); + sm.setSubject(aMethod); + sm.setWithinCode(withinCode); + sm.setWithinType(withinCode.getDeclaringClass()); + return sm; + } + + public ShadowMatch matchesMethodCall(Method aMethod, Class callerType) { + Shadow s = ReflectionShadow.makeCallShadow(world, aMethod, callerType, this.matchContext); + ShadowMatchImpl sm = getShadowMatch(s); + sm.setSubject(aMethod); + sm.setWithinCode(null); + sm.setWithinType(callerType); + return sm; + } + + public ShadowMatch matchesConstructorCall(Constructor aConstructor, Class callerType) { + Shadow s = ReflectionShadow.makeCallShadow(world, aConstructor, callerType, this.matchContext); + ShadowMatchImpl sm = getShadowMatch(s); + sm.setSubject(aConstructor); + sm.setWithinCode(null); + sm.setWithinType(callerType); + return sm; + } + + public ShadowMatch matchesConstructorCall(Constructor aConstructor, Member withinCode) { + Shadow s = ReflectionShadow.makeCallShadow(world, aConstructor, withinCode, this.matchContext); + ShadowMatchImpl sm = getShadowMatch(s); + sm.setSubject(aConstructor); + sm.setWithinCode(withinCode); + sm.setWithinType(withinCode.getDeclaringClass()); + return sm; + } + + public ShadowMatch matchesHandler(Class exceptionType, Class handlingType) { + Shadow s = ReflectionShadow.makeHandlerShadow(world, exceptionType, handlingType, this.matchContext); + ShadowMatchImpl sm = getShadowMatch(s); + sm.setSubject(null); + sm.setWithinCode(null); + sm.setWithinType(handlingType); + return sm; + } + + public ShadowMatch matchesHandler(Class exceptionType, Member withinCode) { + Shadow s = ReflectionShadow.makeHandlerShadow(world, exceptionType, withinCode, this.matchContext); + ShadowMatchImpl sm = getShadowMatch(s); + sm.setSubject(null); + sm.setWithinCode(withinCode); + sm.setWithinType(withinCode.getDeclaringClass()); + return sm; + } + + public ShadowMatch matchesFieldGet(Field aField, Class withinType) { + Shadow s = ReflectionShadow.makeFieldGetShadow(world, aField, withinType, this.matchContext); + ShadowMatchImpl sm = getShadowMatch(s); + sm.setSubject(aField); + sm.setWithinCode(null); + sm.setWithinType(withinType); + return sm; + } + + public ShadowMatch matchesFieldGet(Field aField, Member withinCode) { + Shadow s = ReflectionShadow.makeFieldGetShadow(world, aField, withinCode, this.matchContext); + ShadowMatchImpl sm = getShadowMatch(s); + sm.setSubject(aField); + sm.setWithinCode(withinCode); + sm.setWithinType(withinCode.getDeclaringClass()); + return sm; + } + + public ShadowMatch matchesFieldSet(Field aField, Class withinType) { + Shadow s = ReflectionShadow.makeFieldSetShadow(world, aField, withinType, this.matchContext); + ShadowMatchImpl sm = getShadowMatch(s); + sm.setSubject(aField); + sm.setWithinCode(null); + sm.setWithinType(withinType); + return sm; + } + + public ShadowMatch matchesFieldSet(Field aField, Member withinCode) { + Shadow s = ReflectionShadow.makeFieldSetShadow(world, aField, withinCode, this.matchContext); + ShadowMatchImpl sm = getShadowMatch(s); + sm.setSubject(aField); + sm.setWithinCode(withinCode); + sm.setWithinType(withinCode.getDeclaringClass()); + return sm; + } + + private ShadowMatchImpl getShadowMatch(Shadow forShadow) { + org.aspectj.util.FuzzyBoolean match = pointcut.match(forShadow); + Test residueTest = Literal.TRUE; + ExposedState state = getExposedState(); + if (match.maybeTrue()) { + residueTest = pointcut.findResidue(forShadow, state); + } + ShadowMatchImpl sm = new ShadowMatchImpl(match, residueTest, state, parameters); + sm.setMatchingContext(this.matchContext); + return sm; + } + + /* + * (non-Javadoc) + * + * @see org.aspectj.weaver.tools.PointcutExpression#getPointcutExpression() + */ + public String getPointcutExpression() { + return expression; + } + + private static class HasPossibleDynamicContentVisitor extends AbstractPatternNodeVisitor { + private boolean hasDynamicContent = false; + + public boolean hasDynamicContent() { + return hasDynamicContent; + } + + public Object visit(WithinAnnotationPointcut node, Object data) { + hasDynamicContent = true; + return null; + } + + public Object visit(WithinCodeAnnotationPointcut node, Object data) { + hasDynamicContent = true; + return null; + } + + public Object visit(AnnotationPointcut node, Object data) { + hasDynamicContent = true; + return null; + } + + public Object visit(ArgsAnnotationPointcut node, Object data) { + hasDynamicContent = true; + return null; + } + + public Object visit(ArgsPointcut node, Object data) { + hasDynamicContent = true; + return null; + } + + public Object visit(CflowPointcut node, Object data) { + hasDynamicContent = true; + return null; + } + + public Object visit(IfPointcut node, Object data) { + hasDynamicContent = true; + return null; + } + + public Object visit(NotAnnotationTypePattern node, Object data) { + return node.getNegatedPattern().accept(this, data); + } + + public Object visit(NotPointcut node, Object data) { + return node.getNegatedPointcut().accept(this, data); + } + + public Object visit(ThisOrTargetAnnotationPointcut node, Object data) { + hasDynamicContent = true; + return null; + } + + public Object visit(ThisOrTargetPointcut node, Object data) { + hasDynamicContent = true; + return null; + } + + } + + public static class Handler implements Member { + + private Class decClass; + private Class exType; + + public Handler(Class decClass, Class exType) { + this.decClass = decClass; + this.exType = exType; + } + + public int getModifiers() { + return 0; + } + + public Class getDeclaringClass() { + return decClass; + } + + public String getName() { + return null; + } + + public Class getHandledExceptionType() { + return exType; + } + + public boolean isSynthetic() { + return false; + } + } +} diff --git a/org.aspectj.matcher/src/org/aspectj/weaver/patterns/PatternParser.java b/org.aspectj.matcher/src/org/aspectj/weaver/patterns/PatternParser.java index 75929e7a1..4c714b90c 100644 --- a/org.aspectj.matcher/src/org/aspectj/weaver/patterns/PatternParser.java +++ b/org.aspectj.matcher/src/org/aspectj/weaver/patterns/PatternParser.java @@ -27,8 +27,8 @@ import org.aspectj.weaver.Member; import org.aspectj.weaver.MemberKind; import org.aspectj.weaver.Shadow; import org.aspectj.weaver.UnresolvedType; +import org.aspectj.weaver.World; import org.aspectj.weaver.internal.tools.PointcutDesignatorHandlerBasedPointcut; -import org.aspectj.weaver.reflect.ReflectionWorld; import org.aspectj.weaver.tools.ContextBasedMatcher; import org.aspectj.weaver.tools.PointcutDesignatorHandler; @@ -43,7 +43,7 @@ public class PatternParser { /** extension handlers used in weaver tools API only */ private Set pointcutDesignatorHandlers = Collections.EMPTY_SET; - private ReflectionWorld world; + private World world; /** * Constructor for PatternParser. @@ -55,7 +55,7 @@ public class PatternParser { } /** only used by weaver tools API */ - public void setPointcutDesignatorHandlers(Set handlers, ReflectionWorld world) { + public void setPointcutDesignatorHandlers(Set handlers, World world) { this.pointcutDesignatorHandlers = handlers; this.world = world; } diff --git a/org.aspectj.matcher/src/org/aspectj/weaver/reflect/StandardShadow.java b/org.aspectj.matcher/src/org/aspectj/weaver/reflect/StandardShadow.java new file mode 100644 index 000000000..8e741b6c9 --- /dev/null +++ b/org.aspectj.matcher/src/org/aspectj/weaver/reflect/StandardShadow.java @@ -0,0 +1,414 @@ +/* ******************************************************************* + * Copyright (c) 2005 Contributors. + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution and is available at + * http://eclipse.org/legal/epl-v10.html + * + * Contributors: + * Adrian Colyer Initial implementation + * ******************************************************************/ +package org.aspectj.weaver.reflect; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.HashMap; +import java.util.Map; + +import org.aspectj.bridge.ISourceLocation; +import org.aspectj.weaver.Member; +import org.aspectj.weaver.ResolvedMember; +import org.aspectj.weaver.ResolvedMemberImpl; +import org.aspectj.weaver.ResolvedType; +import org.aspectj.weaver.Shadow; +import org.aspectj.weaver.UnresolvedType; +import org.aspectj.weaver.World; +import org.aspectj.weaver.ast.Var; +import org.aspectj.weaver.tools.MatchingContext; + +/** + * @author colyer + * + */ +public class StandardShadow extends Shadow { + + private final World world; + private final ResolvedType enclosingType; + private final ResolvedMember enclosingMember; + private final MatchingContext matchContext; + private Var thisVar = null; + private Var targetVar = null; + private Var[] argsVars = null; + private Var atThisVar = null; + private Var atTargetVar = null; + private Map atArgsVars = new HashMap(); + private Map withinAnnotationVar = new HashMap(); + private Map withinCodeAnnotationVar = new HashMap(); + private Map annotationVar = new HashMap(); + private AnnotationFinder annotationFinder; + + public static Shadow makeExecutionShadow(World inWorld, java.lang.reflect.Member forMethod, MatchingContext withContext) { + Kind kind = (forMethod instanceof Method) ? Shadow.MethodExecution : Shadow.ConstructorExecution; + Member signature = ReflectionBasedReferenceTypeDelegateFactory.createResolvedMember(forMethod, inWorld); + ResolvedType enclosingType = signature.getDeclaringType().resolve(inWorld); + return new StandardShadow(inWorld, kind, signature, null, enclosingType, null, withContext); + } + + public static Shadow makeExecutionShadow(World inWorld, ResolvedMember forMethod, MatchingContext withContext) { + Kind kind = forMethod.getName().equals("<init>") ? Shadow.ConstructorExecution : Shadow.MethodExecution; + // Member signature = ReflectionBasedReferenceTypeDelegateFactory.createResolvedMember(forMethod, inWorld); + // ResolvedType enclosingType = signature.getDeclaringType().resolve(inWorld); + return new StandardShadow(inWorld, kind, forMethod, null, (ResolvedType) forMethod.getDeclaringType(), null, withContext); + } + + public static Shadow makeAdviceExecutionShadow(World inWorld, java.lang.reflect.Method forMethod, MatchingContext withContext) { + Kind kind = Shadow.AdviceExecution; + Member signature = ReflectionBasedReferenceTypeDelegateFactory.createResolvedAdviceMember(forMethod, inWorld); + ResolvedType enclosingType = signature.getDeclaringType().resolve(inWorld); + return new StandardShadow(inWorld, kind, signature, null, enclosingType, null, withContext); + } + + public static Shadow makeCallShadow(World inWorld, java.lang.reflect.Member aMember, java.lang.reflect.Member withinCode, + MatchingContext withContext) { + Shadow enclosingShadow = makeExecutionShadow(inWorld, withinCode, withContext); + Member signature = ReflectionBasedReferenceTypeDelegateFactory.createResolvedMember(aMember, inWorld); + ResolvedMember enclosingMember = ReflectionBasedReferenceTypeDelegateFactory.createResolvedMember(withinCode, inWorld); + ResolvedType enclosingType = enclosingMember.getDeclaringType().resolve(inWorld); + Kind kind = aMember instanceof Method ? Shadow.MethodCall : Shadow.ConstructorCall; + return new StandardShadow(inWorld, kind, signature, enclosingShadow, enclosingType, enclosingMember, withContext); + } + + public static Shadow makeCallShadow(World inWorld, java.lang.reflect.Member aMember, Class thisClass, + MatchingContext withContext) { + Shadow enclosingShadow = makeStaticInitializationShadow(inWorld, thisClass, withContext); + Member signature = ReflectionBasedReferenceTypeDelegateFactory.createResolvedMember(aMember, inWorld); + ResolvedMember enclosingMember = ReflectionBasedReferenceTypeDelegateFactory.createStaticInitMember(thisClass, inWorld); + ResolvedType enclosingType = enclosingMember.getDeclaringType().resolve(inWorld); + Kind kind = aMember instanceof Method ? Shadow.MethodCall : Shadow.ConstructorCall; + return new StandardShadow(inWorld, kind, signature, enclosingShadow, enclosingType, enclosingMember, withContext); + } + + public static Shadow makeStaticInitializationShadow(World inWorld, Class forType, MatchingContext withContext) { + Member signature = ReflectionBasedReferenceTypeDelegateFactory.createStaticInitMember(forType, inWorld); + ResolvedType enclosingType = signature.getDeclaringType().resolve(inWorld); + Kind kind = Shadow.StaticInitialization; + return new StandardShadow(inWorld, kind, signature, null, enclosingType, null, withContext); + } + + public static Shadow makeStaticInitializationShadow(World inWorld, ResolvedType forType, MatchingContext withContext) { + ResolvedMember[] members = forType.getDeclaredMethods(); + int clinit = -1; + for (int i = 0; i < members.length && clinit == -1; i++) { + System.out.println(members[i]); + if (members[i].getName().equals("<clinit>")) { + clinit = i; + } + } + // Member signature = ReflectionBasedReferenceTypeDelegateFactory.createStaticInitMember(forType, inWorld); + Kind kind = Shadow.StaticInitialization; + if (clinit == -1) { + Member clinitMember = new ResolvedMemberImpl(org.aspectj.weaver.Member.STATIC_INITIALIZATION, forType, Modifier.STATIC, + ResolvedType.VOID, "<clinit>", new UnresolvedType[0], new UnresolvedType[0]); + return new StandardShadow(inWorld, kind, clinitMember, null, forType, null, withContext); + } else { + return new StandardShadow(inWorld, kind, members[clinit], null, forType, null, withContext); + } + } + + public static Shadow makePreInitializationShadow(World inWorld, Constructor forConstructor, MatchingContext withContext) { + Kind kind = Shadow.PreInitialization; + Member signature = ReflectionBasedReferenceTypeDelegateFactory.createResolvedMember(forConstructor, inWorld); + ResolvedType enclosingType = signature.getDeclaringType().resolve(inWorld); + return new StandardShadow(inWorld, kind, signature, null, enclosingType, null, withContext); + } + + public static Shadow makeInitializationShadow(World inWorld, Constructor forConstructor, MatchingContext withContext) { + Kind kind = Shadow.Initialization; + Member signature = ReflectionBasedReferenceTypeDelegateFactory.createResolvedMember(forConstructor, inWorld); + ResolvedType enclosingType = signature.getDeclaringType().resolve(inWorld); + return new StandardShadow(inWorld, kind, signature, null, enclosingType, null, withContext); + } + + public static Shadow makeHandlerShadow(World inWorld, Class exceptionType, Class withinType, MatchingContext withContext) { + Kind kind = Shadow.ExceptionHandler; + Shadow enclosingShadow = makeStaticInitializationShadow(inWorld, withinType, withContext); + Member signature = ReflectionBasedReferenceTypeDelegateFactory.createHandlerMember(exceptionType, withinType, inWorld); + ResolvedMember enclosingMember = ReflectionBasedReferenceTypeDelegateFactory.createStaticInitMember(withinType, inWorld); + ResolvedType enclosingType = enclosingMember.getDeclaringType().resolve(inWorld); + return new StandardShadow(inWorld, kind, signature, enclosingShadow, enclosingType, enclosingMember, withContext); + } + + public static Shadow makeHandlerShadow(World inWorld, Class exceptionType, java.lang.reflect.Member withinCode, + MatchingContext withContext) { + Kind kind = Shadow.ExceptionHandler; + Shadow enclosingShadow = makeExecutionShadow(inWorld, withinCode, withContext); + Member signature = ReflectionBasedReferenceTypeDelegateFactory.createHandlerMember(exceptionType, withinCode + .getDeclaringClass(), inWorld); + ResolvedMember enclosingMember = ReflectionBasedReferenceTypeDelegateFactory.createResolvedMember(withinCode, inWorld); + ResolvedType enclosingType = enclosingMember.getDeclaringType().resolve(inWorld); + return new StandardShadow(inWorld, kind, signature, enclosingShadow, enclosingType, enclosingMember, withContext); + } + + public static Shadow makeFieldGetShadow(World inWorld, Field forField, Class callerType, MatchingContext withContext) { + Shadow enclosingShadow = makeStaticInitializationShadow(inWorld, callerType, withContext); + Member signature = ReflectionBasedReferenceTypeDelegateFactory.createResolvedField(forField, inWorld); + ResolvedMember enclosingMember = ReflectionBasedReferenceTypeDelegateFactory.createStaticInitMember(callerType, inWorld); + ResolvedType enclosingType = enclosingMember.getDeclaringType().resolve(inWorld); + Kind kind = Shadow.FieldGet; + return new StandardShadow(inWorld, kind, signature, enclosingShadow, enclosingType, enclosingMember, withContext); + } + + public static Shadow makeFieldGetShadow(World inWorld, Field forField, java.lang.reflect.Member inMember, + MatchingContext withContext) { + Shadow enclosingShadow = makeExecutionShadow(inWorld, inMember, withContext); + Member signature = ReflectionBasedReferenceTypeDelegateFactory.createResolvedField(forField, inWorld); + ResolvedMember enclosingMember = ReflectionBasedReferenceTypeDelegateFactory.createResolvedMember(inMember, inWorld); + ResolvedType enclosingType = enclosingMember.getDeclaringType().resolve(inWorld); + Kind kind = Shadow.FieldGet; + return new StandardShadow(inWorld, kind, signature, enclosingShadow, enclosingType, enclosingMember, withContext); + } + + public static Shadow makeFieldSetShadow(World inWorld, Field forField, Class callerType, MatchingContext withContext) { + Shadow enclosingShadow = makeStaticInitializationShadow(inWorld, callerType, withContext); + Member signature = ReflectionBasedReferenceTypeDelegateFactory.createResolvedField(forField, inWorld); + ResolvedMember enclosingMember = ReflectionBasedReferenceTypeDelegateFactory.createStaticInitMember(callerType, inWorld); + ResolvedType enclosingType = enclosingMember.getDeclaringType().resolve(inWorld); + Kind kind = Shadow.FieldSet; + return new StandardShadow(inWorld, kind, signature, enclosingShadow, enclosingType, enclosingMember, withContext); + } + + public static Shadow makeFieldSetShadow(World inWorld, Field forField, java.lang.reflect.Member inMember, + MatchingContext withContext) { + Shadow enclosingShadow = makeExecutionShadow(inWorld, inMember, withContext); + Member signature = ReflectionBasedReferenceTypeDelegateFactory.createResolvedField(forField, inWorld); + ResolvedMember enclosingMember = ReflectionBasedReferenceTypeDelegateFactory.createResolvedMember(inMember, inWorld); + ResolvedType enclosingType = enclosingMember.getDeclaringType().resolve(inWorld); + Kind kind = Shadow.FieldSet; + return new StandardShadow(inWorld, kind, signature, enclosingShadow, enclosingType, enclosingMember, withContext); + } + + public StandardShadow(World world, Kind kind, Member signature, Shadow enclosingShadow, ResolvedType enclosingType, + ResolvedMember enclosingMember, MatchingContext withContext) { + super(kind, signature, enclosingShadow); + this.world = world; + this.enclosingType = enclosingType; + this.enclosingMember = enclosingMember; + this.matchContext = withContext; + if (world instanceof IReflectionWorld) { + this.annotationFinder = ((IReflectionWorld) world).getAnnotationFinder(); + } + } + + /* + * (non-Javadoc) + * + * @see org.aspectj.weaver.Shadow#getIWorld() + */ + public World getIWorld() { + return world; + } + + /* + * (non-Javadoc) + * + * @see org.aspectj.weaver.Shadow#getThisVar() + */ + public Var getThisVar() { + if (thisVar == null && hasThis()) { + thisVar = ReflectionVar.createThisVar(getThisType().resolve(world), this.annotationFinder); + } + return thisVar; + } + + /* + * (non-Javadoc) + * + * @see org.aspectj.weaver.Shadow#getTargetVar() + */ + public Var getTargetVar() { + if (targetVar == null && hasTarget()) { + targetVar = ReflectionVar.createTargetVar(getThisType().resolve(world), this.annotationFinder); + } + return targetVar; + } + + /* + * (non-Javadoc) + * + * @see org.aspectj.weaver.Shadow#getEnclosingType() + */ + public UnresolvedType getEnclosingType() { + return this.enclosingType; + } + + /* + * (non-Javadoc) + * + * @see org.aspectj.weaver.Shadow#getArgVar(int) + */ + public Var getArgVar(int i) { + if (argsVars == null) { + this.argsVars = new Var[this.getArgCount()]; + for (int j = 0; j < this.argsVars.length; j++) { + this.argsVars[j] = ReflectionVar.createArgsVar(getArgType(j).resolve(world), j, this.annotationFinder); + } + } + if (i < argsVars.length) { + return argsVars[i]; + } else { + return null; + } + } + + /* + * (non-Javadoc) + * + * @see org.aspectj.weaver.Shadow#getThisJoinPointVar() + */ + public Var getThisJoinPointVar() { + // TODO Auto-generated method stub + return null; + } + + /* + * (non-Javadoc) + * + * @see org.aspectj.weaver.Shadow#getThisJoinPointStaticPartVar() + */ + public Var getThisJoinPointStaticPartVar() { + // TODO Auto-generated method stub + return null; + } + + /* + * (non-Javadoc) + * + * @see org.aspectj.weaver.Shadow#getThisEnclosingJoinPointStaticPartVar() + */ + public Var getThisEnclosingJoinPointStaticPartVar() { + // TODO Auto-generated method stub + return null; + } + + /* + * (non-Javadoc) + * + * @see org.aspectj.weaver.Shadow#getKindedAnnotationVar(org.aspectj.weaver.UnresolvedType) + */ + public Var getKindedAnnotationVar(UnresolvedType forAnnotationType) { + ResolvedType annType = forAnnotationType.resolve(world); + if (annotationVar.get(annType) == null) { + Var v = ReflectionVar.createAtAnnotationVar(annType, this.annotationFinder); + annotationVar.put(annType, v); + } + return (Var) annotationVar.get(annType); + } + + /* + * (non-Javadoc) + * + * @see org.aspectj.weaver.Shadow#getWithinAnnotationVar(org.aspectj.weaver.UnresolvedType) + */ + public Var getWithinAnnotationVar(UnresolvedType forAnnotationType) { + ResolvedType annType = forAnnotationType.resolve(world); + if (withinAnnotationVar.get(annType) == null) { + Var v = ReflectionVar.createWithinAnnotationVar(annType, this.annotationFinder); + withinAnnotationVar.put(annType, v); + } + return (Var) withinAnnotationVar.get(annType); + } + + /* + * (non-Javadoc) + * + * @see org.aspectj.weaver.Shadow#getWithinCodeAnnotationVar(org.aspectj.weaver.UnresolvedType) + */ + public Var getWithinCodeAnnotationVar(UnresolvedType forAnnotationType) { + ResolvedType annType = forAnnotationType.resolve(world); + if (withinCodeAnnotationVar.get(annType) == null) { + Var v = ReflectionVar.createWithinCodeAnnotationVar(annType, this.annotationFinder); + withinCodeAnnotationVar.put(annType, v); + } + return (Var) withinCodeAnnotationVar.get(annType); + } + + /* + * (non-Javadoc) + * + * @see org.aspectj.weaver.Shadow#getThisAnnotationVar(org.aspectj.weaver.UnresolvedType) + */ + public Var getThisAnnotationVar(UnresolvedType forAnnotationType) { + if (atThisVar == null) { + atThisVar = ReflectionVar.createThisAnnotationVar(forAnnotationType.resolve(world), this.annotationFinder); + } + return atThisVar; + } + + /* + * (non-Javadoc) + * + * @see org.aspectj.weaver.Shadow#getTargetAnnotationVar(org.aspectj.weaver.UnresolvedType) + */ + public Var getTargetAnnotationVar(UnresolvedType forAnnotationType) { + if (atTargetVar == null) { + atTargetVar = ReflectionVar.createTargetAnnotationVar(forAnnotationType.resolve(world), this.annotationFinder); + } + return atTargetVar; + } + + /* + * (non-Javadoc) + * + * @see org.aspectj.weaver.Shadow#getArgAnnotationVar(int, org.aspectj.weaver.UnresolvedType) + */ + public Var getArgAnnotationVar(int i, UnresolvedType forAnnotationType) { + ResolvedType annType = forAnnotationType.resolve(world); + if (atArgsVars.get(annType) == null) { + Var[] vars = new Var[getArgCount()]; + atArgsVars.put(annType, vars); + } + Var[] vars = (Var[]) atArgsVars.get(annType); + if (i > (vars.length - 1)) + return null; + if (vars[i] == null) { + vars[i] = ReflectionVar.createArgsAnnotationVar(annType, i, this.annotationFinder); + } + return vars[i]; + } + + /* + * (non-Javadoc) + * + * @see org.aspectj.weaver.Shadow#getEnclosingCodeSignature() + */ + public Member getEnclosingCodeSignature() { + // XXX this code is copied from BcelShadow with one minor change... + if (getKind().isEnclosingKind()) { + return getSignature(); + } else if (getKind() == Shadow.PreInitialization) { + // PreInit doesn't enclose code but its signature + // is correctly the signature of the ctor. + return getSignature(); + } else if (enclosingShadow == null) { + return this.enclosingMember; + } else { + return enclosingShadow.getSignature(); + } + } + + /* + * (non-Javadoc) + * + * @see org.aspectj.weaver.Shadow#getSourceLocation() + */ + public ISourceLocation getSourceLocation() { + return null; + } + + public MatchingContext getMatchingContext() { + return this.matchContext; + } +} diff --git a/org.aspectj.matcher/src/org/aspectj/weaver/tools/StandardPointcutExpression.java b/org.aspectj.matcher/src/org/aspectj/weaver/tools/StandardPointcutExpression.java new file mode 100644 index 000000000..3d5534944 --- /dev/null +++ b/org.aspectj.matcher/src/org/aspectj/weaver/tools/StandardPointcutExpression.java @@ -0,0 +1,233 @@ +/* ******************************************************************* + * Copyright (c) 2004 IBM Corporation. + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * ******************************************************************/ + +package org.aspectj.weaver.tools; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Member; +import java.lang.reflect.Method; + +import org.aspectj.weaver.ResolvedMember; +import org.aspectj.weaver.ResolvedType; + +/** + * Represents an AspectJ pointcut expression and provides convenience methods to determine whether or not the pointcut matches join + * points specified in terms of the java.lang.reflect interfaces. + */ +public interface StandardPointcutExpression { + + /** + * Set the matching context to be used for subsequent calls to match. + * + * @see MatchingContext + */ + void setMatchingContext(MatchingContext aMatchContext); + + /** + * Determine whether or not this pointcut could ever match a join point in the given class. + * + * @param aClass the candidate class + * @return true iff this pointcut <i>may</i> match a join point within(aClass), and false otherwise + */ + boolean couldMatchJoinPointsInType(Class aClass); + + /** + * Returns true iff this pointcut contains any expression that might necessitate a dynamic test at some join point (e.g. args) + */ + boolean mayNeedDynamicTest(); + + /** + * Determine whether or not this pointcut matches the execution of a given method. + * + * @param aMethod the method being executed + * @return a ShadowMatch indicating whether the pointcut always, sometimes, or never matches join points representing the + * execution of the method. + */ + ShadowMatch matchesMethodExecution(Method aMethod); + + /** + * Determine whether or not this pointcut matches the execution of a given method. + * + * @param aMethod the method being executed + * @return a ShadowMatch indicating whether the pointcut always, sometimes, or never matches join points representing the + * execution of the method. + */ + ShadowMatch matchesMethodExecution(ResolvedMember aMethod); + + /** + * Determine whether or not this pointcut matches the execution of a given constructor. + * + * @param aConstructor the constructor being executed + * @return a ShadowMatch indicating whether the pointcut always, sometimes, or never matches join points representing the + * execution of the constructor. + */ + ShadowMatch matchesConstructorExecution(Constructor aConstructor); + + /** + * Determine whether or not this pointcut matches the static initialization of the given class. + * + * @param aClass the class being statically initialized + * @return a ShadowMatch indicating whether the pointcut always, sometimes, or never matchs join points representing the static + * initialization of the given type + */ + ShadowMatch matchesStaticInitialization(Class aClass); + + /** + * Determine whether or not this pointcut matches the static initialization of the given class. + * + * @param aClass the class being statically initialized + * @return a ShadowMatch indicating whether the pointcut always, sometimes, or never matchs join points representing the static + * initialization of the given type + */ + ShadowMatch matchesStaticInitialization(ResolvedType type); + + /** + * Determine whether or not this pointcut matches the execution of a given piece of advice. + * + * @param anAdviceMethod a method representing the advice being executed + * @return a ShadowMatch indicating whether the pointcut always, sometimes, or never matches join points representing the + * execution of the advice. + */ + ShadowMatch matchesAdviceExecution(Method anAdviceMethod); + + /** + * Determine whether or not this pointcut matches the initialization of an object initiated by a call to the given constructor. + * + * @param aConstructor the constructor initiating the initialization + * @return a ShadowMatch indicating whether the pointcut always, sometimes, or never matches join points representing + * initialization via the given constructor. + */ + ShadowMatch matchesInitialization(Constructor aConstructor); + + /** + * Determine whether or not this pointcut matches the pre-initialization of an object initiated by a call to the given + * constructor. + * + * @param aConstructor the constructor initiating the initialization + * @return a ShadowMatch indicating whether the pointcut always, sometimes, or never matches join points representing + * pre-initialization via the given constructor. + */ + ShadowMatch matchesPreInitialization(Constructor aConstructor); + + /** + * Determine whether or not this pointcut matches a method call to the given method, made during the execution of the given + * method or constructor. + * + * @param aMethod the method being called + * @param withinCode the Method or Constructor from within which the call is made + * @return a ShadowMatch indicating whether the pointcut always, sometimes, or never matches join points representing a call to + * this method during the execution of the given member. + */ + ShadowMatch matchesMethodCall(Method aMethod, Member withinCode); + + /** + * Determine whether or not this pointcut matches a method call to the given method, made outside of the scope of any method or + * constructor, but within the callerType (for example, during static initialization of the type). + * + * @param aMethod the method being called + * @param callerType the declared type of the caller + * @param receiverType the declared type of the recipient of the call + * @return a ShadowMatch indicating whether the pointcut always, sometimes, or never matches join points representing a call to + * this method during the execution of the given member. + */ + ShadowMatch matchesMethodCall(Method aMethod, Class callerType); + + /** + * Determine whether or not this pointcut matches a method call to the given constructor, made during the execution of the given + * method or constructor. + * + * @param aConstructor the constructor being called + * @param withinCode the Method or Constructor from within which the call is made + * @return a ShadowMatch indicating whether the pointcut always, sometimes, or never matches join points representing a call to + * this constructor during the execution of the given member. + */ + ShadowMatch matchesConstructorCall(Constructor aConstructor, Member withinCode); + + /** + * Determine whether or not this pointcut matches a method call to the given constructor, made outside of the scope of any + * method or constructor, but within the callerType. + * + * @param aConstructor the cosstructor being called + * @param callerType the declared type of the caller + * @return a ShadowMatch indicating whether the pointcut always, sometimes, or never matches join points representing a call to + * this constructor during the execution of the given member. + */ + ShadowMatch matchesConstructorCall(Constructor aConstructor, Class callerType); + + /** + * Determine whether or not this pointcut matches the execution of a given exception handler within the given method or + * constructor + * + * @param exceptionType the static type of the exception being handled + * @param withinCode the method or constructor in which the catch block is declared + * @return a ShadowMatch indicating whether the pointcut always, sometimes, or never matches join points representing the + * handling of the given exception + */ + ShadowMatch matchesHandler(Class exceptionType, Member withinCode); + + /** + * Determine whether or not this pointcut matches the execution of a given exception handler outside of the scope of any method + * or constructor, but within the handling type. + * + * @param exceptionType the static type of the exception being handled + * @param handlingType the type in which the handler block is executing + * @return a ShadowMatch indicating whether the pointcut always, sometimes, or never matches join points representing the + * handling of the given exception + */ + ShadowMatch matchesHandler(Class exceptionType, Class handlingType); + + /** + * Determine whether or not this pointcut matches a set of the given field from within the given method or constructor. + * + * @param aField the field being updated + * @param withinCode the Method or Constructor owning the call site + * @return a ShadowMatch indicating whether the pointcut always, sometimes, or never matches field set join points for the given + * field and call site. + */ + ShadowMatch matchesFieldSet(Field aField, Member withinCode); + + /** + * Determine whether or not this pointcut matches a set of the given field outside of the scope of any method or constructor, + * but within the given type (for example, during static initialization). + * + * @param aField the field being updated + * @param withinType the type owning the call site + * @return a ShadowMatch indicating whether the pointcut always, sometimes, or never matches field set join points for the given + * field and call site. + */ + ShadowMatch matchesFieldSet(Field aField, Class withinType); + + /** + * Determine whether or not this pointcut matches a get of the given field from within the given method or constructor. + * + * @param aField the field being updated + * @param withinCode the Method or Constructor owning the call site + * @return a ShadowMatch indicating whether the pointcut always, sometimes, or never matches field get join points for the given + * field and call site. + */ + ShadowMatch matchesFieldGet(Field aField, Member withinCode); + + /** + * Determine whether or not this pointcut matches a get of the given field outside of the scope of any method or constructor, + * but within the given type (for example, during static initialization). + * + * @param aField the field being accessed + * @param withinType the type owning the call site + * @return a ShadowMatch indicating whether the pointcut always, sometimes, or never matches field get join points for the given + * field and call site. + */ + ShadowMatch matchesFieldGet(Field aField, Class withinType); + + /** + * Return a string representation of this pointcut expression. + */ + String getPointcutExpression(); +} diff --git a/org.aspectj.matcher/src/org/aspectj/weaver/tools/StandardPointcutParser.java b/org.aspectj.matcher/src/org/aspectj/weaver/tools/StandardPointcutParser.java new file mode 100644 index 000000000..eee063f0f --- /dev/null +++ b/org.aspectj.matcher/src/org/aspectj/weaver/tools/StandardPointcutParser.java @@ -0,0 +1,484 @@ +/******************************************************************************* + * Copyright (c) 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.aspectj.weaver.tools; + +import java.io.File; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Properties; +import java.util.Set; + +import org.aspectj.bridge.IMessageHandler; +import org.aspectj.bridge.ISourceLocation; +import org.aspectj.bridge.SourceLocation; +import org.aspectj.weaver.BindingScope; +import org.aspectj.weaver.IHasPosition; +import org.aspectj.weaver.ISourceContext; +import org.aspectj.weaver.IntMap; +import org.aspectj.weaver.ResolvedType; +import org.aspectj.weaver.Shadow; +import org.aspectj.weaver.UnresolvedType; +import org.aspectj.weaver.World; +import org.aspectj.weaver.internal.tools.StandardPointcutExpressionImpl; +import org.aspectj.weaver.internal.tools.TypePatternMatcherImpl; +import org.aspectj.weaver.patterns.AndPointcut; +import org.aspectj.weaver.patterns.CflowPointcut; +import org.aspectj.weaver.patterns.FormalBinding; +import org.aspectj.weaver.patterns.IScope; +import org.aspectj.weaver.patterns.KindedPointcut; +import org.aspectj.weaver.patterns.NotPointcut; +import org.aspectj.weaver.patterns.OrPointcut; +import org.aspectj.weaver.patterns.ParserException; +import org.aspectj.weaver.patterns.PatternParser; +import org.aspectj.weaver.patterns.Pointcut; +import org.aspectj.weaver.patterns.SimpleScope; +import org.aspectj.weaver.patterns.ThisOrTargetAnnotationPointcut; +import org.aspectj.weaver.patterns.ThisOrTargetPointcut; +import org.aspectj.weaver.patterns.TypePattern; +import org.aspectj.weaver.reflect.PointcutParameterImpl; +import org.aspectj.weaver.reflect.ReflectionWorld; + +/** + * A PointcutParser can be used to build PointcutExpressions for a user-defined subset of AspectJ's pointcut language + */ +public class StandardPointcutParser { + + private World world; + private final Set supportedPrimitives; + private final Set pointcutDesignators = new HashSet(); + + /** + * @return a Set containing every PointcutPrimitive except if, cflow, and cflowbelow (useful for passing to PointcutParser + * constructor). + */ + public static Set getAllSupportedPointcutPrimitives() { + Set primitives = new HashSet(); + primitives.add(PointcutPrimitive.ADVICE_EXECUTION); + primitives.add(PointcutPrimitive.ARGS); + primitives.add(PointcutPrimitive.CALL); + primitives.add(PointcutPrimitive.EXECUTION); + primitives.add(PointcutPrimitive.GET); + primitives.add(PointcutPrimitive.HANDLER); + primitives.add(PointcutPrimitive.INITIALIZATION); + primitives.add(PointcutPrimitive.PRE_INITIALIZATION); + primitives.add(PointcutPrimitive.SET); + primitives.add(PointcutPrimitive.STATIC_INITIALIZATION); + primitives.add(PointcutPrimitive.TARGET); + primitives.add(PointcutPrimitive.THIS); + primitives.add(PointcutPrimitive.WITHIN); + primitives.add(PointcutPrimitive.WITHIN_CODE); + primitives.add(PointcutPrimitive.AT_ANNOTATION); + primitives.add(PointcutPrimitive.AT_THIS); + primitives.add(PointcutPrimitive.AT_TARGET); + primitives.add(PointcutPrimitive.AT_ARGS); + primitives.add(PointcutPrimitive.AT_WITHIN); + primitives.add(PointcutPrimitive.AT_WITHINCODE); + primitives.add(PointcutPrimitive.REFERENCE); + + return primitives; + } + + /** + * Returns a pointcut parser that can parse the full AspectJ pointcut language with the following exceptions: + * <ul> + * <li>The <code>if, cflow, and cflowbelow</code> pointcut designators are not supported + * <li>Pointcut expressions must be self-contained :- they cannot contain references to other named pointcuts + * <li>The pointcut expression must be anonymous with no formals allowed. + * </ul> + * <p> + * When resolving types in pointcut expressions, the context classloader is used to find types. + * </p> + */ + public static StandardPointcutParser getPointcutParserSupportingAllPrimitives(World world) { + StandardPointcutParser p = new StandardPointcutParser(world); + return p; + } + + /** + * Returns a pointcut parser that can parse pointcut expressions built from a user-defined subset of AspectJ's supported + * pointcut primitives. The following restrictions apply: + * <ul> + * <li>The <code>if, cflow, and cflowbelow</code> pointcut designators are not supported + * <li>Pointcut expressions must be self-contained :- they cannot contain references to other named pointcuts + * <li>The pointcut expression must be anonymous with no formals allowed. + * </ul> + * <p> + * When resolving types in pointcut expressions, the given classloader is used to find types. + * </p> + * + * @param supportedPointcutKinds a set of PointcutPrimitives this parser should support + * @throws UnsupportedOperationException if the set contains if, cflow, or cflow below + */ + public static StandardPointcutParser getPointcutParserSupportingSpecifiedPrimitives(Set supportedPointcutKinds, World world) { + StandardPointcutParser p = new StandardPointcutParser(supportedPointcutKinds, world); + return p; + } + + /** + * Create a pointcut parser that can parse the full AspectJ pointcut language with the following exceptions: + * <ul> + * <li>The <code>if, cflow, and cflowbelow</code> pointcut designators are not supported + * <li>Pointcut expressions must be self-contained :- they cannot contain references to other named pointcuts + * <li>The pointcut expression must be anonymous with no formals allowed. + * </ul> + */ + protected StandardPointcutParser(World world) { + supportedPrimitives = getAllSupportedPointcutPrimitives(); + this.world = world; + } + + /** + * Create a pointcut parser that can parse pointcut expressions built from a user-defined subset of AspectJ's supported pointcut + * primitives. The following restrictions apply: + * <ul> + * <li>The <code>if, cflow, and cflowbelow</code> pointcut designators are not supported + * <li>Pointcut expressions must be self-contained :- they cannot contain references to other named pointcuts + * <li>The pointcut expression must be anonymous with no formals allowed. + * </ul> + * + * @param supportedPointcutKinds a set of PointcutPrimitives this parser should support + * @throws UnsupportedOperationException if the set contains if, cflow, or cflow below + */ + private StandardPointcutParser(Set/* <PointcutPrimitives> */supportedPointcutKinds, World world) { + supportedPrimitives = supportedPointcutKinds; + for (Iterator iter = supportedPointcutKinds.iterator(); iter.hasNext();) { + PointcutPrimitive element = (PointcutPrimitive) iter.next(); + if ((element == PointcutPrimitive.IF) || (element == PointcutPrimitive.CFLOW) + || (element == PointcutPrimitive.CFLOW_BELOW)) { + throw new UnsupportedOperationException("Cannot handle if, cflow, and cflowbelow primitives"); + } + } + this.world = world; + } + + // /** + // * Set the lint properties for this parser from the given resource on the classpath. + // * + // * @param resourcePath path to a file containing aspectj lint properties + // */ + // public void setLintProperties(String resourcePath) throws IOException { + // URL url = this.classLoaderReference.getClassLoader().getResource(resourcePath); + // InputStream is = url.openStream(); + // Properties p = new Properties(); + // p.load(is); + // setLintProperties(p); + // } + + /** + * Set the lint properties for this parser from the given properties set. + * + * @param properties + */ + public void setLintProperties(Properties properties) { + getWorld().getLint().setFromProperties(properties); + } + + /** + * Register a new pointcut designator handler with this parser. This provides an extension mechansim for the integration of + * domain-specific pointcut designators with the AspectJ pointcut language. + * + * @param designatorHandler + */ + public void registerPointcutDesignatorHandler(PointcutDesignatorHandler designatorHandler) { + this.pointcutDesignators.add(designatorHandler); + if (world != null) + world.registerPointcutHandler(designatorHandler); + } + + /** + * Create a pointcut parameter of the given name and type. + * + * @param name + * @param type + * @return + */ + public PointcutParameter createPointcutParameter(String name, Class type) { + return new PointcutParameterImpl(name, type); + } + + /** + * Parse the given pointcut expression. A global scope is assumed for resolving any type references, and the pointcut must + * contain no formals (variables to be bound). + * + * @throws UnsupportedPointcutPrimitiveException if the parser encounters a primitive pointcut expression of a kind not + * supported by this PointcutParser. + * @throws IllegalArgumentException if the expression is not a well-formed pointcut expression + */ + public StandardPointcutExpression parsePointcutExpression(String expression) throws UnsupportedPointcutPrimitiveException, + IllegalArgumentException { + return parsePointcutExpression(expression, null, new PointcutParameter[0]); + } + + /** + * Parse the given pointcut expression. The pointcut is resolved as if it had been declared inside the inScope class (this + * allows the pointcut to contain unqualified references to other pointcuts declared in the same type for example). The pointcut + * may contain zero or more formal parameters to be bound at matched join points. + * + * @throws UnsupportedPointcutPrimitiveException if the parser encounters a primitive pointcut expression of a kind not + * supported by this PointcutParser. + * @throws IllegalArgumentException if the expression is not a well-formed pointcut expression + */ + public StandardPointcutExpression parsePointcutExpression(String expression, Class inScope, PointcutParameter[] formalParameters) + throws UnsupportedPointcutPrimitiveException, IllegalArgumentException { + StandardPointcutExpressionImpl pcExpr = null; + try { + Pointcut pc = resolvePointcutExpression(expression, inScope, formalParameters); + pc = concretizePointcutExpression(pc, inScope, formalParameters); + validateAgainstSupportedPrimitives(pc, expression); // again, because we have now followed any ref'd pcuts + pcExpr = new StandardPointcutExpressionImpl(pc, expression, formalParameters, getWorld()); + } catch (ParserException pEx) { + throw new IllegalArgumentException(buildUserMessageFromParserException(expression, pEx)); + } catch (ReflectionWorld.ReflectionWorldException rwEx) { + throw new IllegalArgumentException(rwEx.getMessage()); + } + return pcExpr; + } + + protected Pointcut resolvePointcutExpression(String expression, Class inScope, PointcutParameter[] formalParameters) { + try { + PatternParser parser = new PatternParser(expression); + parser.setPointcutDesignatorHandlers(pointcutDesignators, world); + Pointcut pc = parser.parsePointcut(); + validateAgainstSupportedPrimitives(pc, expression); + IScope resolutionScope = buildResolutionScope((inScope == null ? Object.class : inScope), formalParameters); + pc = pc.resolve(resolutionScope); + return pc; + } catch (ParserException pEx) { + throw new IllegalArgumentException(buildUserMessageFromParserException(expression, pEx)); + } + } + + protected Pointcut concretizePointcutExpression(Pointcut pc, Class inScope, PointcutParameter[] formalParameters) { + ResolvedType declaringTypeForResolution = null; + if (inScope != null) { + declaringTypeForResolution = getWorld().resolve(inScope.getName()); + } else { + declaringTypeForResolution = ResolvedType.OBJECT.resolve(getWorld()); + } + IntMap arity = new IntMap(formalParameters.length); + for (int i = 0; i < formalParameters.length; i++) { + arity.put(i, i); + } + return pc.concretize(declaringTypeForResolution, declaringTypeForResolution, arity); + } + + /** + * Parse the given aspectj type pattern, and return a matcher that can be used to match types using it. + * + * @param typePattern an aspectj type pattern + * @return a type pattern matcher that matches using the given pattern + * @throws IllegalArgumentException if the type pattern cannot be successfully parsed. + */ + public TypePatternMatcher parseTypePattern(String typePattern) throws IllegalArgumentException { + try { + TypePattern tp = new PatternParser(typePattern).parseTypePattern(); + tp.resolve(world); + return new TypePatternMatcherImpl(tp, world); + } catch (ParserException pEx) { + throw new IllegalArgumentException(buildUserMessageFromParserException(typePattern, pEx)); + } catch (ReflectionWorld.ReflectionWorldException rwEx) { + throw new IllegalArgumentException(rwEx.getMessage()); + } + } + + private World getWorld() { + return world; + } + + /* for testing */ + Set getSupportedPrimitives() { + return supportedPrimitives; + } + + /* for testing */ + IMessageHandler setCustomMessageHandler(IMessageHandler aHandler) { + IMessageHandler current = getWorld().getMessageHandler(); + getWorld().setMessageHandler(aHandler); + return current; + } + + private IScope buildResolutionScope(Class inScope, PointcutParameter[] formalParameters) { + if (formalParameters == null) + formalParameters = new PointcutParameter[0]; + FormalBinding[] formalBindings = new FormalBinding[formalParameters.length]; + for (int i = 0; i < formalBindings.length; i++) { + formalBindings[i] = new FormalBinding(toUnresolvedType(formalParameters[i].getType()), formalParameters[i].getName(), i); + } + if (inScope == null) { + return new SimpleScope(getWorld(), formalBindings); + } else { + ResolvedType inType = getWorld().resolve(inScope.getName()); + ISourceContext sourceContext = new ISourceContext() { + public ISourceLocation makeSourceLocation(IHasPosition position) { + return new SourceLocation(new File(""), 0); + } + + public ISourceLocation makeSourceLocation(int line, int offset) { + return new SourceLocation(new File(""), line); + } + + public int getOffset() { + return 0; + } + + public void tidy() { + } + }; + return new BindingScope(inType, sourceContext, formalBindings); + } + } + + private UnresolvedType toUnresolvedType(Class clazz) { + if (clazz.isArray()) { + return UnresolvedType.forSignature(clazz.getName().replace('.', '/')); + } else { + return UnresolvedType.forName(clazz.getName()); + } + } + + private void validateAgainstSupportedPrimitives(Pointcut pc, String expression) { + switch (pc.getPointcutKind()) { + case Pointcut.AND: + validateAgainstSupportedPrimitives(((AndPointcut) pc).getLeft(), expression); + validateAgainstSupportedPrimitives(((AndPointcut) pc).getRight(), expression); + break; + case Pointcut.ARGS: + if (!supportedPrimitives.contains(PointcutPrimitive.ARGS)) + throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.ARGS); + break; + case Pointcut.CFLOW: + CflowPointcut cfp = (CflowPointcut) pc; + if (cfp.isCflowBelow()) { + throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.CFLOW_BELOW); + } else { + throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.CFLOW); + } + case Pointcut.HANDLER: + if (!supportedPrimitives.contains(PointcutPrimitive.HANDLER)) + throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.HANDLER); + break; + case Pointcut.IF: + case Pointcut.IF_FALSE: + case Pointcut.IF_TRUE: + throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.IF); + case Pointcut.KINDED: + validateKindedPointcut(((KindedPointcut) pc), expression); + break; + case Pointcut.NOT: + validateAgainstSupportedPrimitives(((NotPointcut) pc).getNegatedPointcut(), expression); + break; + case Pointcut.OR: + validateAgainstSupportedPrimitives(((OrPointcut) pc).getLeft(), expression); + validateAgainstSupportedPrimitives(((OrPointcut) pc).getRight(), expression); + break; + case Pointcut.THIS_OR_TARGET: + boolean isThis = ((ThisOrTargetPointcut) pc).isThis(); + if (isThis && !supportedPrimitives.contains(PointcutPrimitive.THIS)) { + throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.THIS); + } else if (!supportedPrimitives.contains(PointcutPrimitive.TARGET)) { + throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.TARGET); + } + break; + case Pointcut.WITHIN: + if (!supportedPrimitives.contains(PointcutPrimitive.WITHIN)) + throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.WITHIN); + break; + case Pointcut.WITHINCODE: + if (!supportedPrimitives.contains(PointcutPrimitive.WITHIN_CODE)) + throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.WITHIN_CODE); + break; + case Pointcut.ATTHIS_OR_TARGET: + isThis = ((ThisOrTargetAnnotationPointcut) pc).isThis(); + if (isThis && !supportedPrimitives.contains(PointcutPrimitive.AT_THIS)) { + throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.AT_THIS); + } else if (!supportedPrimitives.contains(PointcutPrimitive.AT_TARGET)) { + throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.AT_TARGET); + } + break; + case Pointcut.ATARGS: + if (!supportedPrimitives.contains(PointcutPrimitive.AT_ARGS)) + throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.AT_ARGS); + break; + case Pointcut.ANNOTATION: + if (!supportedPrimitives.contains(PointcutPrimitive.AT_ANNOTATION)) + throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.AT_ANNOTATION); + break; + case Pointcut.ATWITHIN: + if (!supportedPrimitives.contains(PointcutPrimitive.AT_WITHIN)) + throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.AT_WITHIN); + break; + case Pointcut.ATWITHINCODE: + if (!supportedPrimitives.contains(PointcutPrimitive.AT_WITHINCODE)) + throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.AT_WITHINCODE); + break; + case Pointcut.REFERENCE: + if (!supportedPrimitives.contains(PointcutPrimitive.REFERENCE)) + throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.REFERENCE); + break; + case Pointcut.USER_EXTENSION: + // always ok... + break; + case Pointcut.NONE: // deliberate fall-through + default: + throw new IllegalArgumentException("Unknown pointcut kind: " + pc.getPointcutKind()); + } + } + + private void validateKindedPointcut(KindedPointcut pc, String expression) { + Shadow.Kind kind = pc.getKind(); + if ((kind == Shadow.MethodCall) || (kind == Shadow.ConstructorCall)) { + if (!supportedPrimitives.contains(PointcutPrimitive.CALL)) + throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.CALL); + } else if ((kind == Shadow.MethodExecution) || (kind == Shadow.ConstructorExecution)) { + if (!supportedPrimitives.contains(PointcutPrimitive.EXECUTION)) + throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.EXECUTION); + } else if (kind == Shadow.AdviceExecution) { + if (!supportedPrimitives.contains(PointcutPrimitive.ADVICE_EXECUTION)) + throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.ADVICE_EXECUTION); + } else if (kind == Shadow.FieldGet) { + if (!supportedPrimitives.contains(PointcutPrimitive.GET)) + throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.GET); + } else if (kind == Shadow.FieldSet) { + if (!supportedPrimitives.contains(PointcutPrimitive.SET)) + throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.SET); + } else if (kind == Shadow.Initialization) { + if (!supportedPrimitives.contains(PointcutPrimitive.INITIALIZATION)) + throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.INITIALIZATION); + } else if (kind == Shadow.PreInitialization) { + if (!supportedPrimitives.contains(PointcutPrimitive.PRE_INITIALIZATION)) + throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.PRE_INITIALIZATION); + } else if (kind == Shadow.StaticInitialization) { + if (!supportedPrimitives.contains(PointcutPrimitive.STATIC_INITIALIZATION)) + throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.STATIC_INITIALIZATION); + } + } + + private String buildUserMessageFromParserException(String pc, ParserException ex) { + StringBuffer msg = new StringBuffer(); + msg.append("Pointcut is not well-formed: expecting '"); + msg.append(ex.getMessage()); + msg.append("'"); + IHasPosition location = ex.getLocation(); + msg.append(" at character position "); + msg.append(location.getStart()); + msg.append("\n"); + msg.append(pc); + msg.append("\n"); + for (int i = 0; i < location.getStart(); i++) { + msg.append(" "); + } + for (int j = location.getStart(); j <= location.getEnd(); j++) { + msg.append("^"); + } + msg.append("\n"); + return msg.toString(); + } +} |