/* *******************************************************************
* Copyright (c) 2005 IBM
* All rights reserved.
* This program and the accompanying materials are made available
* under the terms of the Common Public License v1.0
* which accompanies this distribution and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* Andy Clement initial implementation
* ******************************************************************/
package org.aspectj.weaver.patterns;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.aspectj.bridge.IMessage;
import org.aspectj.bridge.ISourceLocation;
import org.aspectj.bridge.Message;
import org.aspectj.util.FuzzyBoolean;
import org.aspectj.weaver.Advice;
import org.aspectj.weaver.AjcMemberMaker;
import org.aspectj.weaver.ISourceContext;
import org.aspectj.weaver.Member;
//import org.aspectj.weaver.PerTypeWithinTargetTypeMunger;
import org.aspectj.weaver.PerTypeWithinTargetTypeMunger;
import org.aspectj.weaver.ResolvedTypeMunger;
import org.aspectj.weaver.ResolvedType;
import org.aspectj.weaver.Shadow;
import org.aspectj.weaver.VersionedDataInputStream;
import org.aspectj.weaver.World;
import org.aspectj.weaver.bcel.BcelAccessForInlineMunger;
import org.aspectj.weaver.ast.Expr;
import org.aspectj.weaver.ast.Literal;
import org.aspectj.weaver.ast.Test;
// PTWIMPL Represents a parsed pertypewithin()
public class PerTypeWithin extends PerClause {
private TypePattern typePattern;
// Any shadow could be considered within a pertypewithin() type pattern
private static final Set kindSet = new HashSet(Shadow.ALL_SHADOW_KINDS);
public TypePattern getTypePattern() {
return typePattern;
}
public PerTypeWithin(TypePattern p) {
this.typePattern = p;
}
public Object accept(PatternNodeVisitor visitor, Object data) {
return visitor.visit(this,data);
}
public Set couldMatchKinds() {
return kindSet;
}
public Pointcut parameterizeWith(Map typeVariableMap) {
PerTypeWithin ret = new PerTypeWithin(typePattern.parameterizeWith(typeVariableMap));
ret.copyLocationFrom(this);
return ret;
}
// -----
public FuzzyBoolean fastMatch(FastMatchInfo info) {
if (typePattern.annotationPattern instanceof AnyAnnotationTypePattern) {
return isWithinType(info.getType());
}
return FuzzyBoolean.MAYBE;
}
protected FuzzyBoolean matchInternal(Shadow shadow) {
ResolvedType enclosingType = shadow.getIWorld().resolve(shadow.getEnclosingType(),true);
if (enclosingType.isMissing()) {
//PTWIMPL ?? Add a proper message
IMessage msg = new Message(
"Cant find type pertypewithin matching...",
shadow.getSourceLocation(),true,new ISourceLocation[]{getSourceLocation()});
shadow.getIWorld().getMessageHandler().handleMessage(msg);
}
// See pr106554 - we can't put advice calls in an interface when the advice is defined
// in a pertypewithin aspect - the JPs only exist in the static initializer and can't
// call the localAspectOf() method.
if (enclosingType.isInterface()) return FuzzyBoolean.NO;
typePattern.resolve(shadow.getIWorld());
return isWithinType(enclosingType);
}
public void resolveBindings(IScope scope, Bindings bindings) {
typePattern = typePattern.resolveBindings(scope, bindings, false, false);
}
protected Test findResidueInternal(Shadow shadow, ExposedState state) {
Member ptwField = AjcMemberMaker.perTypeWithinField(shadow.getEnclosingType(),inAspect);
Expr myInstance =
Expr.makeCallExpr(AjcMemberMaker.perTypeWithinLocalAspectOf(shadow.getEnclosingType(),inAspect/*shadow.getEnclosingType()*/),
Expr.NONE,inAspect);
state.setAspectInstance(myInstance);
// this worked at one point
//Expr myInstance = Expr.makeFieldGet(ptwField,shadow.getEnclosingType().resolve(shadow.getIWorld()));//inAspect);
//state.setAspectInstance(myInstance);
// return Test.makeFieldGetCall(ptwField,null,Expr.NONE);
// cflowField, cflowCounterIsValidMethod, Expr.NONE
// This is what is in the perObject variant of this ...
// Expr myInstance =
// Expr.makeCallExpr(AjcMemberMaker.perTypeWithinAspectOfMethod(inAspect),
// new Expr[] {getVar(shadow)}, inAspect);
// state.setAspectInstance(myInstance);
// return Test.makeCall(AjcMemberMaker.perTypeWithinHasAspectMethod(inAspect),
// new Expr[] { getVar(shadow) });
//
return match(shadow).alwaysTrue()?Literal.TRUE:Literal.FALSE;
}
public PerClause concretize(ResolvedType inAspect) {
PerTypeWithin ret = new PerTypeWithin(typePattern);
ret.copyLocationFrom(this);
ret.inAspect = inAspect;
if (inAspect.isAbstract()) return ret;
World world = inAspect.getWorld();
SignaturePattern sigpat = new SignaturePattern(
Member.STATIC_INITIALIZATION,
ModifiersPattern.ANY,
TypePattern.ANY,
TypePattern.ANY,//typePattern,
NamePattern.ANY,
TypePatternList.ANY,
ThrowsPattern.ANY,
AnnotationTypePattern.ANY
);
Pointcut staticInitStar = new KindedPointcut(Shadow.StaticInitialization,sigpat);
Pointcut withinTp= new WithinPointcut(typePattern);
Pointcut andPcut = new AndPointcut(staticInitStar,withinTp);
// We want the pointcut to be 'staticinitialization(*) && within(<typepattern>' -
// we *cannot* shortcut this to staticinitialization(<typepattern>) because it
// doesnt mean the same thing.
// This munger will initialize the aspect instance field in the matched type
inAspect.crosscuttingMembers.addConcreteShadowMunger(Advice.makePerTypeWithinEntry(world, andPcut, inAspect));
ResolvedTypeMunger munger = new PerTypeWithinTargetTypeMunger(inAspect, ret);
inAspect.crosscuttingMembers.addTypeMunger(world.concreteTypeMunger(munger, inAspect));
//ATAJ: add a munger to add the aspectOf(..) to the @AJ aspects
if (inAspect.isAnnotationStyleAspect() && !inAspect.isAbstract()) {
inAspect.crosscuttingMembers.addLateTypeMunger(
inAspect.getWorld().makePerClauseAspect(inAspect, getKind())
);
}
//ATAJ inline around advice support - don't use a late munger to allow around inling for itself
if (inAspect.isAnnotationStyleAspect() && !inAspect.getWorld().isXnoInline()) {
inAspect.crosscuttingMembers.addTypeMunger(new BcelAccessForInlineMunger(inAspect));
}
return ret;
}
public void write(DataOutputStream s) throws IOException {
PERTYPEWITHIN.write(s);
typePattern.write(s);
writeLocation(s);
}
public static PerClause readPerClause(VersionedDataInputStream s, ISourceContext context) throws IOException {
PerClause ret = new PerTypeWithin(TypePattern.read(s, context));
ret.readLocation(context, s);
return ret;
}
public PerClause.Kind getKind() {
return PERTYPEWITHIN;
}
public String toString() {
return "pertypewithin("+typePattern+")";
}
public String toDeclarationString() {
return toString();
}
private FuzzyBoolean isWithinType(ResolvedType type) {
while (type != null) {
if (typePattern.matchesStatically(type)) {
return FuzzyBoolean.YES;
}
type = type.getDeclaringType();
}
return FuzzyBoolean.NO;
}
}