package org.aspectj.weaver;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.aspectj.weaver.AjAttribute.WeaverVersionInfo;
import org.aspectj.weaver.patterns.Declare;
import org.aspectj.weaver.patterns.DeclareAnnotation;
import org.aspectj.weaver.patterns.DeclareErrorOrWarning;
import org.aspectj.weaver.patterns.DeclareParents;
import org.aspectj.weaver.patterns.DeclarePrecedence;
import org.aspectj.weaver.patterns.DeclareSoft;
import org.aspectj.weaver.patterns.DeclareTypeErrorOrWarning;
import org.aspectj.weaver.patterns.PerClause;
import org.aspectj.weaver.patterns.Pointcut;
import org.aspectj.weaver.patterns.PointcutRewriter;
public class CrosscuttingMembers {
private final ResolvedType inAspect;
private final World world;
private PerClause perClause;
private List<ShadowMunger> shadowMungers = new ArrayList<ShadowMunger>(4);
private List<ConcreteTypeMunger> typeMungers = new ArrayList<ConcreteTypeMunger>(4);
private List<ConcreteTypeMunger> lateTypeMungers = new ArrayList<ConcreteTypeMunger>(0);
private Set<DeclareParents> declareParents = new HashSet<DeclareParents>();
private Set<DeclareSoft> declareSofts = new HashSet<DeclareSoft>();
private List<Declare> declareDominates = new ArrayList<Declare>(4);
private Set<DeclareAnnotation> declareAnnotationsOnType = new LinkedHashSet<DeclareAnnotation>();
private Set<DeclareAnnotation> declareAnnotationsOnField = new LinkedHashSet<DeclareAnnotation>();
private Set<DeclareAnnotation> declareAnnotationsOnMethods = new LinkedHashSet<DeclareAnnotation>();
private Set<DeclareTypeErrorOrWarning> declareTypeEow = new HashSet<DeclareTypeErrorOrWarning>();
private boolean shouldConcretizeIfNeeded = true;
public CrosscuttingMembers(ResolvedType inAspect, boolean shouldConcretizeIfNeeded) {
this.inAspect = inAspect;
world = inAspect.getWorld();
this.shouldConcretizeIfNeeded = shouldConcretizeIfNeeded;
}
private final Hashtable<String, Object> cflowFields = new Hashtable<String, Object>();
private final Hashtable<String, Object> cflowBelowFields = new Hashtable<String, Object>();
public void addConcreteShadowMunger(ShadowMunger m) {
shadowMungers.add(m);
}
public void addShadowMungers(Collection<ShadowMunger> c) {
for (ShadowMunger munger : c) {
addShadowMunger(munger);
}
}
private void addShadowMunger(ShadowMunger m) {
if (inAspect.isAbstract()) {
return;
}
addConcreteShadowMunger(m.concretize(inAspect, world, perClause));
}
public void addTypeMungers(Collection<ConcreteTypeMunger> c) {
typeMungers.addAll(c);
}
public void addTypeMunger(ConcreteTypeMunger m) {
if (m == null) {
throw new Error("FIXME AV - should not happen or what ?");
}
typeMungers.add(m);
}
public void addLateTypeMungers(Collection<ConcreteTypeMunger> c) {
lateTypeMungers.addAll(c);
}
public void addLateTypeMunger(ConcreteTypeMunger m) {
lateTypeMungers.add(m);
}
public void addDeclares(Collection<Declare> declares) {
for (Declare declare : declares) {
addDeclare(declare);
}
}
public void addDeclare(Declare declare) {
if (declare instanceof DeclareErrorOrWarning) {
ShadowMunger m = new Checker((DeclareErrorOrWarning) declare);
m.setDeclaringType(declare.getDeclaringType());
addShadowMunger(m);
} else if (declare instanceof DeclarePrecedence) {
declareDominates.add(declare);
} else if (declare instanceof DeclareParents) {
DeclareParents dp = (DeclareParents) declare;
exposeTypes(dp.getParents().getExactTypes());
declareParents.add(dp);
} else if (declare instanceof DeclareSoft) {
DeclareSoft d = (DeclareSoft) declare;
ShadowMunger m = Advice.makeSoftener(world, d.getPointcut(), d.getException(), inAspect, d);
m.setDeclaringType(d.getDeclaringType());
Pointcut concretePointcut = d.getPointcut().concretize(inAspect, d.getDeclaringType(), 0, m);
m.pointcut = concretePointcut;
declareSofts.add(new DeclareSoft(d.getException(), concretePointcut));
addConcreteShadowMunger(m);
} else if (declare instanceof DeclareAnnotation) {
DeclareAnnotation da = (DeclareAnnotation) declare;
if (da.getAspect() == null) {
da.setAspect(inAspect);
}
if (da.isDeclareAtType()) {
declareAnnotationsOnType.add(da);
} else if (da.isDeclareAtField()) {
declareAnnotationsOnField.add(da);
} else if (da.isDeclareAtMethod() || da.isDeclareAtConstuctor()) {
declareAnnotationsOnMethods.add(da);
}
} else if (declare instanceof DeclareTypeErrorOrWarning) {
declareTypeEow.add((DeclareTypeErrorOrWarning) declare);
} else {
throw new RuntimeException("unimplemented");
}
}
public void exposeTypes(List<UnresolvedType> typesToExpose) {
for (UnresolvedType typeToExpose : typesToExpose) {
exposeType(typeToExpose);
}
}
public void exposeType(UnresolvedType typeToExpose) {
if (ResolvedType.isMissing(typeToExpose)) {
return;
}
if (typeToExpose.isParameterizedType() || typeToExpose.isRawType()) {
if (typeToExpose instanceof ResolvedType) {
typeToExpose = ((ResolvedType) typeToExpose).getGenericType();
} else {
typeToExpose = UnresolvedType.forSignature(typeToExpose.getErasureSignature());
}
}
String signatureToLookFor = typeToExpose.getSignature();
for (Iterator<ConcreteTypeMunger> iterator = typeMungers.iterator(); iterator.hasNext();) {
ConcreteTypeMunger cTM = iterator.next();
ResolvedTypeMunger rTM = cTM.getMunger();
if (rTM != null && rTM instanceof ExposeTypeMunger) {
String exposedType = ((ExposeTypeMunger) rTM).getExposedTypeSignature();
if (exposedType.equals(signatureToLookFor)) {
return;
}
}
}
addTypeMunger(world.getWeavingSupport().concreteTypeMunger(new ExposeTypeMunger(typeToExpose), inAspect));
}
public void addPrivilegedAccesses(Collection<ResolvedMember> accessedMembers) {
int version = inAspect.getCompilerVersion();
for (ResolvedMember member : accessedMembers) {
ResolvedMember resolvedMember = world.resolve(member);
if (resolvedMember == null) {
resolvedMember = member;
if (resolvedMember.hasBackingGenericMember()) {
resolvedMember = resolvedMember.getBackingGenericMember();
}
} else {
UnresolvedType unresolvedDeclaringType = member.getDeclaringType().getRawType();
UnresolvedType resolvedDeclaringType = resolvedMember.getDeclaringType().getRawType();
if (!unresolvedDeclaringType.equals(resolvedDeclaringType)) {
resolvedMember = member;
}
}
PrivilegedAccessMunger privilegedAccessMunger = new PrivilegedAccessMunger(resolvedMember,
version >= WeaverVersionInfo.WEAVER_VERSION_AJ169);
ConcreteTypeMunger concreteTypeMunger = world.getWeavingSupport().concreteTypeMunger(privilegedAccessMunger, inAspect);
addTypeMunger(concreteTypeMunger);
}
}
public Collection<ShadowMunger> getCflowEntries() {
List<ShadowMunger> ret = new ArrayList<ShadowMunger>();
for (ShadowMunger m : shadowMungers) {
if (m instanceof Advice) {
Advice a = (Advice) m;
if (a.getKind().isCflow()) {
ret.add(a);
}
}
}
return ret;
}
public boolean replaceWith(CrosscuttingMembers other, boolean careAboutShadowMungers) {
boolean changed = false;
if (careAboutShadowMungers) {
if (perClause == null || !perClause.equals(other.perClause)) {
changed = true;
perClause = other.perClause;
}
}
if (careAboutShadowMungers) {
Set<ShadowMunger> theseShadowMungers = new HashSet<ShadowMunger>();
Set<ShadowMunger> theseInlinedAroundMungers = new HashSet<ShadowMunger>();
for (ShadowMunger munger : shadowMungers) {
if (munger instanceof Advice) {
Advice adviceMunger = (Advice) munger;
if (!world.isXnoInline() && adviceMunger.getKind().equals(AdviceKind.Around)) {
theseInlinedAroundMungers.add(adviceMunger);
} else {
theseShadowMungers.add(adviceMunger);
}
} else {
theseShadowMungers.add(munger);
}
}
Set<ShadowMunger> tempSet = new HashSet<ShadowMunger>();
tempSet.addAll(other.shadowMungers);
Set<ShadowMunger> otherShadowMungers = new HashSet<ShadowMunger>();
Set<ShadowMunger> otherInlinedAroundMungers = new HashSet<ShadowMunger>();
for (ShadowMunger munger : tempSet) {
if (munger instanceof Advice) {
Advice adviceMunger = (Advice) munger;
if (!world.isXnoInline() && adviceMunger.getKind().equals(AdviceKind.Around)) {
otherInlinedAroundMungers.add(rewritePointcutInMunger(adviceMunger));
} else {
otherShadowMungers.add(rewritePointcutInMunger(adviceMunger));
}
} else {
otherShadowMungers.add(rewritePointcutInMunger(munger));
}
}
if (!theseShadowMungers.equals(otherShadowMungers)) {
changed = true;
}
if (!equivalent(theseInlinedAroundMungers, otherInlinedAroundMungers)) {
changed = true;
}
if (!changed) {
for (ShadowMunger munger : shadowMungers) {
int i = other.shadowMungers.indexOf(munger);
ShadowMunger otherMunger = other.shadowMungers.get(i);
if (munger instanceof Advice) {
((Advice) otherMunger).setHasMatchedSomething(((Advice) munger).hasMatchedSomething());
}
}
}
shadowMungers = other.shadowMungers;
}
Set<Object> theseTypeMungers = new HashSet<Object>();
Set<Object> otherTypeMungers = new HashSet<Object>();
if (!careAboutShadowMungers) {
for (Iterator<ConcreteTypeMunger> iter = typeMungers.iterator(); iter.hasNext();) {
Object o = iter.next();
if (o instanceof ConcreteTypeMunger) {
ConcreteTypeMunger typeMunger = (ConcreteTypeMunger) o;
if (!typeMunger.existsToSupportShadowMunging()) {
theseTypeMungers.add(typeMunger);
}
} else {
theseTypeMungers.add(o);
}
}
for (Iterator<ConcreteTypeMunger> iter = other.typeMungers.iterator(); iter.hasNext();) {
Object o = iter.next();
if (o instanceof ConcreteTypeMunger) {
ConcreteTypeMunger typeMunger = (ConcreteTypeMunger) o;
if (!typeMunger.existsToSupportShadowMunging()) {
otherTypeMungers.add(typeMunger);
}
} else {
otherTypeMungers.add(o);
}
}
} else {
theseTypeMungers.addAll(typeMungers);
otherTypeMungers.addAll(other.typeMungers);
}
if (theseTypeMungers.size() != otherTypeMungers.size()) {
changed = true;
typeMungers = other.typeMungers;
} else {
boolean shouldOverwriteThis = false;
boolean foundInequality = false;
for (Iterator<Object> iter = theseTypeMungers.iterator(); iter.hasNext() && !foundInequality;) {
Object thisOne = iter.next();
boolean foundInOtherSet = false;
for (Object otherOne : otherTypeMungers) {
if (thisOne instanceof ConcreteTypeMunger) {
if (((ConcreteTypeMunger) thisOne).shouldOverwrite()) {
shouldOverwriteThis = true;
}
}
if (thisOne instanceof ConcreteTypeMunger && otherOne instanceof ConcreteTypeMunger) {
if (((ConcreteTypeMunger) thisOne).equivalentTo(otherOne)) {
foundInOtherSet = true;
} else if (thisOne.equals(otherOne)) {
foundInOtherSet = true;
}
} else {
if (thisOne.equals(otherOne)) {
foundInOtherSet = true;
}
}
}
if (!foundInOtherSet) {
foundInequality = true;
}
}
if (foundInequality) {
changed = true;
}
if (shouldOverwriteThis) {
typeMungers = other.typeMungers;
}
}
if (!lateTypeMungers.equals(other.lateTypeMungers)) {
changed = true;
lateTypeMungers = other.lateTypeMungers;
}
if (!declareDominates.equals(other.declareDominates)) {
changed = true;
declareDominates = other.declareDominates;
}
if (!declareParents.equals(other.declareParents)) {
if (!careAboutShadowMungers) {
Set<DeclareParents> trimmedThis = new HashSet<DeclareParents>();
for (Iterator<DeclareParents> iterator = declareParents.iterator(); iterator.hasNext();) {
DeclareParents decp = iterator.next();
if (!decp.isMixin()) {
trimmedThis.add(decp);
}
}
Set<DeclareParents> trimmedOther = new HashSet<DeclareParents>();
for (Iterator<DeclareParents> iterator = other.declareParents.iterator(); iterator.hasNext();) {
DeclareParents decp = iterator.next();
if (!decp.isMixin()) {
trimmedOther.add(decp);
}
}
if (!trimmedThis.equals(trimmedOther)) {
changed = true;
declareParents = other.declareParents;
}
} else {
changed = true;
declareParents = other.declareParents;
}
}
if (!declareSofts.equals(other.declareSofts)) {
changed = true;
declareSofts = other.declareSofts;
}
if (!declareAnnotationsOnType.equals(other.declareAnnotationsOnType)) {
changed = true;
declareAnnotationsOnType = other.declareAnnotationsOnType;
}
if (!declareAnnotationsOnField.equals(other.declareAnnotationsOnField)) {
changed = true;
declareAnnotationsOnField = other.declareAnnotationsOnField;
}
if (!declareAnnotationsOnMethods.equals(other.declareAnnotationsOnMethods)) {
changed = true;
declareAnnotationsOnMethods = other.declareAnnotationsOnMethods;
}
if (!declareTypeEow.equals(other.declareTypeEow)) {
changed = true;
declareTypeEow = other.declareTypeEow;
}
return changed;
}
private boolean equivalent(Set<ShadowMunger> theseInlinedAroundMungers, Set<ShadowMunger> otherInlinedAroundMungers) {
if (theseInlinedAroundMungers.size() != otherInlinedAroundMungers.size()) {
return false;
}
for (Iterator<ShadowMunger> iter = theseInlinedAroundMungers.iterator(); iter.hasNext();) {
Advice thisAdvice = (Advice) iter.next();
boolean foundIt = false;
for (Iterator<ShadowMunger> iterator = otherInlinedAroundMungers.iterator(); iterator.hasNext();) {
Advice otherAdvice = (Advice) iterator.next();
if (thisAdvice.equals(otherAdvice)) {
if (thisAdvice.getSignature() instanceof ResolvedMemberImpl) {
if (((ResolvedMemberImpl) thisAdvice.getSignature()).isEquivalentTo(otherAdvice.getSignature())) {
foundIt = true;
continue;
}
}
return false;
}
}
if (!foundIt) {
return false;
}
}
return true;
}
private ShadowMunger rewritePointcutInMunger(ShadowMunger munger) {
PointcutRewriter pr = new PointcutRewriter();
Pointcut p = munger.getPointcut();
Pointcut newP = pr.rewrite(p);
if (p.m_ignoreUnboundBindingForNames.length != 0) {
newP.m_ignoreUnboundBindingForNames = p.m_ignoreUnboundBindingForNames;
}
munger.setPointcut(newP);
return munger;
}
public void setPerClause(PerClause perClause) {
if (shouldConcretizeIfNeeded) {
this.perClause = perClause.concretize(inAspect);
} else {
this.perClause = perClause;
}
}
public List<Declare> getDeclareDominates() {
return declareDominates;
}
public Collection<DeclareParents> getDeclareParents() {
return declareParents;
}
public Collection<DeclareSoft> getDeclareSofts() {
return declareSofts;
}
public List<ShadowMunger> getShadowMungers() {
return shadowMungers;
}
public List<ConcreteTypeMunger> getTypeMungers() {
return typeMungers;
}
public List<ConcreteTypeMunger> getLateTypeMungers() {
return lateTypeMungers;
}
public Collection<DeclareAnnotation> getDeclareAnnotationOnTypes() {
return declareAnnotationsOnType;
}
public Collection<DeclareAnnotation> getDeclareAnnotationOnFields() {
return declareAnnotationsOnField;
}
public Collection<DeclareAnnotation> getDeclareAnnotationOnMethods() {
return declareAnnotationsOnMethods;
}
public Collection<DeclareTypeErrorOrWarning> getDeclareTypeErrorOrWarning() {
return declareTypeEow;
}
public Map<String, Object> getCflowBelowFields() {
return cflowBelowFields;
}
public Map<String, Object> getCflowFields() {
return cflowFields;
}
public void clearCaches() {
cflowFields.clear();
cflowBelowFields.clear();
}
}