/* *******************************************************************
* Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
* 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:
* PARC initial implementation
* ******************************************************************/
package org.aspectj.weaver.patterns;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import org.aspectj.util.FuzzyBoolean;
import org.aspectj.weaver.Advice;
import org.aspectj.weaver.AjcMemberMaker;
import org.aspectj.weaver.ISourceContext;
import org.aspectj.weaver.PerObjectInterfaceTypeMunger;
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.Test;
import org.aspectj.weaver.ast.Var;
public class PerObject extends PerClause {
private boolean isThis;
private Pointcut entry;
private static final Set thisKindSet = new HashSet(Shadow.ALL_SHADOW_KINDS);
private static final Set targetKindSet = new HashSet(Shadow.ALL_SHADOW_KINDS);
static {
for (Iterator iter = Shadow.ALL_SHADOW_KINDS.iterator(); iter.hasNext();) {
Shadow.Kind kind = (Shadow.Kind) iter.next();
if (kind.neverHasThis()) thisKindSet.remove(kind);
if (kind.neverHasTarget()) targetKindSet.remove(kind);
}
}
public PerObject(Pointcut entry, boolean isThis) {
this.entry = entry;
this.isThis = isThis;
}
public Object accept(PatternNodeVisitor visitor, Object data) {
return visitor.visit(this,data);
}
public Set couldMatchKinds() {
return isThis ? thisKindSet : targetKindSet;
}
// -----
public FuzzyBoolean fastMatch(FastMatchInfo type) {
return FuzzyBoolean.MAYBE;
}
protected FuzzyBoolean matchInternal(Shadow shadow) {
//System.err.println("matches " + this + " ? " + shadow + ", " + shadow.hasTarget());
//??? could probably optimize this better by testing could match
if (isThis) return FuzzyBoolean.fromBoolean(shadow.hasThis());
else return FuzzyBoolean.fromBoolean(shadow.hasTarget());
}
public void resolveBindings(IScope scope, Bindings bindings) {
// assert bindings == null;
entry.resolve(scope);
}
public Pointcut parameterizeWith(Map typeVariableMap) {
PerObject ret = new PerObject(entry.parameterizeWith(typeVariableMap),isThis);
ret.copyLocationFrom(this);
return ret;
}
private Var getVar(Shadow shadow) {
return isThis ? shadow.getThisVar() : shadow.getTargetVar();
}
protected Test findResidueInternal(Shadow shadow, ExposedState state) {
Expr myInstance =
Expr.makeCallExpr(AjcMemberMaker.perObjectAspectOfMethod(inAspect),
new Expr[] {getVar(shadow)}, inAspect);
state.setAspectInstance(myInstance);
return Test.makeCall(AjcMemberMaker.perObjectHasAspectMethod(inAspect),
new Expr[] { getVar(shadow) });
}
public PerClause concretize(ResolvedType inAspect) {
PerObject ret = new PerObject(entry, isThis);
ret.inAspect = inAspect;
if (inAspect.isAbstract()) return ret;
World world = inAspect.getWorld();
Pointcut concreteEntry = entry.concretize(inAspect, inAspect, 0, null);
//concreteEntry = new AndPointcut(this, concreteEntry);
//concreteEntry.state = Pointcut.CONCRETE;
inAspect.crosscuttingMembers.addConcreteShadowMunger(
Advice.makePerObjectEntry(world, concreteEntry, isThis, inAspect));
// FIXME AV - don't use lateMunger here due to test "inheritance, around advice and abstract pointcuts"
// see #75442 thread. Issue with weaving order.
ResolvedTypeMunger munger =
new PerObjectInterfaceTypeMunger(inAspect, concreteEntry);
inAspect.crosscuttingMembers.addLateTypeMunger(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 {
PEROBJECT.write(s);
entry.write(s);
s.writeBoolean(isThis);
writeLocation(s);
}
public static PerClause readPerClause(VersionedDataInputStream s, ISourceContext context) throws IOException {
PerClause ret = new PerObject(Pointcut.read(s, context), s.readBoolean());
ret.readLocation(context, s);
return ret;
}
public PerClause.Kind getKind() {
return PEROBJECT;
}
public boolean isThis() {
return isThis;
}
public String toString() {
return "per" + (isThis ? "this" : "target") +
"(" + entry + ")";
}
public String toDeclarationString() {
return toString();
}
public Pointcut getEntry() {
return entry;
}
}