/* ******************************************************************* * 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 v 2.0 * which accompanies this distribution and is available at * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.txt * * ******************************************************************/ 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.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.ReflectionWorld; import org.aspectj.weaver.reflect.ShadowMatchImpl; import org.aspectj.weaver.tools.DefaultMatchingContext; import org.aspectj.weaver.tools.MatchingContext; import org.aspectj.weaver.tools.PointcutExpression; import org.aspectj.weaver.tools.PointcutParameter; import org.aspectj.weaver.tools.ShadowMatch; /** * Map from weaver.tools interface to internal Pointcut implementation... */ public class PointcutExpressionImpl implements PointcutExpression { private final static boolean MATCH_INFO = false; private World world; private Pointcut pointcut; private String expression; private PointcutParameter[] parameters; private MatchingContext matchContext = new DefaultMatchingContext(); public PointcutExpressionImpl(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()); if (matchType.isMissing() && (world instanceof ReflectionWorld)) { // Class is a generated class that cannot be 'looked up' via getResource. // For example a proxy or lambda. // Use the class itself in this case matchType = ((ReflectionWorld)world).resolveUsingClass(aClass); } ReflectionFastMatchInfo info = new ReflectionFastMatchInfo(matchType, null, this.matchContext, world); boolean couldMatch = pointcut.fastMatch(info).maybeTrue(); if (MATCH_INFO) { System.out.println("MATCHINFO: fast match for '" + this.expression + "' against '" + aClass.getName() + "': " + couldMatch); } return couldMatch; } 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) { ShadowMatch match = matchesExecution(aMethod); if (MATCH_INFO && match.maybeMatches()) { System.out.println("MATCHINFO: method execution match on '" + aMethod + "' for '" + this.expression + "': " + (match.alwaysMatches() ? "YES" : "MAYBE")); } return match; } public ShadowMatch matchesConstructorExecution(Constructor aConstructor) { ShadowMatch match = matchesExecution(aConstructor); if (MATCH_INFO && match.maybeMatches()) { System.out.println("MATCHINFO: constructor execution match on '" + aConstructor + "' for '" + this.expression + "': " + (match.alwaysMatches() ? "YES" : "MAYBE")); } return match; } 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; } 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); if (MATCH_INFO && sm.maybeMatches()) { System.out.println("MATCHINFO: static initialization match on '" + aClass.getName() + "' for '" + this.expression + "': " + (sm.alwaysMatches() ? "YES" : "MAYBE")); } 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()); if (MATCH_INFO && sm.maybeMatches()) { System.out.println("MATCHINFO: advice execution match on '" + aMethod + "' for '" + this.expression + "': " + (sm.alwaysMatches() ? "YES" : "MAYBE")); } 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()); if (MATCH_INFO && sm.maybeMatches()) { System.out.println("MATCHINFO: initialization match on '" + aConstructor + "' for '" + this.expression + "': " + (sm.alwaysMatches() ? "YES" : "MAYBE")); } 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()); if (MATCH_INFO && sm.maybeMatches()) { System.out.println("MATCHINFO: preinitialization match on '" + aConstructor + "' for '" + this.expression + "': " + (sm.alwaysMatches() ? "YES" : "MAYBE")); } 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()); if (MATCH_INFO && sm.maybeMatches()) { System.out.println("MATCHINFO: method call match on '" + aMethod + "' withinCode='" + withinCode + "' for '" + this.expression + "': " + (sm.alwaysMatches() ? "YES" : "MAYBE")); } 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); if (MATCH_INFO && sm.maybeMatches()) { System.out.println("MATCHINFO: method call match on '" + aMethod + "' callerType='" + callerType.getName() + "' for '" + this.expression + "': " + (sm.alwaysMatches() ? "YES" : "MAYBE")); } 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); if (MATCH_INFO && sm.maybeMatches()) { System.out.println("MATCHINFO: constructor call match on '" + aConstructor + "' callerType='" + callerType.getName() + "' for '" + this.expression + "': " + (sm.alwaysMatches() ? "YES" : "MAYBE")); } 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()); if (MATCH_INFO && sm.maybeMatches()) { System.out.println("MATCHINFO: constructor call match on '" + aConstructor + "' withinCode='" + withinCode + "' for '" + this.expression + "': " + (sm.alwaysMatches() ? "YES" : "MAYBE")); } 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); if (MATCH_INFO && sm.maybeMatches()) { System.out.println("MATCHINFO: handler match on '" + exceptionType.getName() + "' handlingType='" + handlingType + "' for '" + this.expression + "': " + (sm.alwaysMatches() ? "YES" : "MAYBE")); } 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()); if (MATCH_INFO && sm.maybeMatches()) { System.out.println("MATCHINFO: handler match on '" + exceptionType.getName() + "' withinCode='" + withinCode + "' for '" + this.expression + "': " + (sm.alwaysMatches() ? "YES" : "MAYBE")); } 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); if (MATCH_INFO && sm.maybeMatches()) { System.out.println("MATCHINFO: field get match on '" + aField + "' withinType='" + withinType.getName() + "' for '" + this.expression + "': " + (sm.alwaysMatches() ? "YES" : "MAYBE")); } 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()); if (MATCH_INFO && sm.maybeMatches()) { System.out.println("MATCHINFO: field get match on '" + aField + "' withinCode='" + withinCode + "' for '" + this.expression + "': " + (sm.alwaysMatches() ? "YES" : "MAYBE")); } 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); if (MATCH_INFO && sm.maybeMatches()) { System.out.println("MATCHINFO: field set match on '" + aField + "' withinType='" + withinType.getName() + "' for '" + this.expression + "': " + (sm.alwaysMatches() ? "YES" : "MAYBE")); } 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()); if (MATCH_INFO && sm.maybeMatches()) { System.out.println("MATCHINFO: field set match on '" + aField + "' withinCode='" + withinCode + "' for '" + this.expression + "': " + (sm.alwaysMatches() ? "YES" : "MAYBE")); } 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; } @Override public Object visit(WithinAnnotationPointcut node, Object data) { hasDynamicContent = true; return null; } @Override public Object visit(WithinCodeAnnotationPointcut node, Object data) { hasDynamicContent = true; return null; } @Override public Object visit(AnnotationPointcut node, Object data) { hasDynamicContent = true; return null; } @Override public Object visit(ArgsAnnotationPointcut node, Object data) { hasDynamicContent = true; return null; } @Override public Object visit(ArgsPointcut node, Object data) { hasDynamicContent = true; return null; } @Override public Object visit(CflowPointcut node, Object data) { hasDynamicContent = true; return null; } @Override public Object visit(IfPointcut node, Object data) { hasDynamicContent = true; return null; } @Override public Object visit(NotAnnotationTypePattern node, Object data) { return node.getNegatedPattern().accept(this, data); } @Override public Object visit(NotPointcut node, Object data) { return node.getNegatedPointcut().accept(this, data); } @Override public Object visit(ThisOrTargetAnnotationPointcut node, Object data) { hasDynamicContent = true; return null; } @Override 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; } } }