diff options
author | Andy Clement <aclement@pivotal.io> | 2019-01-23 18:53:51 -0800 |
---|---|---|
committer | Andy Clement <aclement@pivotal.io> | 2019-01-23 18:53:51 -0800 |
commit | afaa961b294eca20fa9d54359c53a1de2d3c41fd (patch) | |
tree | 4b756f0f0dc4764cfcaeb200756de79cd4cdf56a /org.aspectj.matcher/src/main/java/org/aspectj/weaver/CrosscuttingMembers.java | |
parent | 74dcae875f1c89b7e3fa2ffa6b524a3c187a597e (diff) | |
download | aspectj-afaa961b294eca20fa9d54359c53a1de2d3c41fd.tar.gz aspectj-afaa961b294eca20fa9d54359c53a1de2d3c41fd.zip |
mavenized org.aspectj.matcher module - wip
Diffstat (limited to 'org.aspectj.matcher/src/main/java/org/aspectj/weaver/CrosscuttingMembers.java')
-rw-r--r-- | org.aspectj.matcher/src/main/java/org/aspectj/weaver/CrosscuttingMembers.java | 591 |
1 files changed, 591 insertions, 0 deletions
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/CrosscuttingMembers.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/CrosscuttingMembers.java new file mode 100644 index 000000000..8e41c0a82 --- /dev/null +++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/CrosscuttingMembers.java @@ -0,0 +1,591 @@ +/* ******************************************************************* + * 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 Eclipse Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * PARC initial implementation + * ******************************************************************/ +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; + +/** + * This holds on to all members that have an invasive effect outside of there own compilation unit. These members need to be all + * gathered up and in a world before any weaving can take place. + * + * They are also important in the compilation process and need to be gathered up before the inter-type declaration weaving stage + * (unsurprisingly). + * + * All members are concrete. + * + * @author Jim Hugunin + */ +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); + + // These are like declare parents type mungers + private Set<DeclareAnnotation> declareAnnotationsOnType = new LinkedHashSet<DeclareAnnotation>(); + private Set<DeclareAnnotation> declareAnnotationsOnField = new LinkedHashSet<DeclareAnnotation>(); + private Set<DeclareAnnotation> declareAnnotationsOnMethods = new LinkedHashSet<DeclareAnnotation>(); + // declareAnnotationsOnMethods includes constructors too + + 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 addConcreteShadowMungers(Collection c) { + // shadowMungers.addAll(c); + // } + + public void addConcreteShadowMunger(ShadowMunger m) { + // assert m is concrete + shadowMungers.add(m); + } + + public void addShadowMungers(Collection<ShadowMunger> c) { + for (ShadowMunger munger : c) { + addShadowMunger(munger); + } + } + + private void addShadowMunger(ShadowMunger m) { + if (inAspect.isAbstract()) { + return; // mungers for abstract aspects are not added + } + 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 ?");// return; + } + 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) { + // this is not extensible, oh well + 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; + // Ordered so that during concretization we can check the related + // munger + 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) { + // FIXME asc perf Possible Improvement. Investigate why this is + // called twice in a weave ? + 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()); + } + } + // Check we haven't already got a munger for this: + 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; // dont need to bother + } + } + } + addTypeMunger(world.getWeavingSupport().concreteTypeMunger(new ExposeTypeMunger(typeToExpose), inAspect)); + // ResolvedMember member = new ResolvedMemberImpl( + // Member.STATIC_INITIALIZATION, typeToExpose, 0, UnresolvedType.VOID, + // "<clinit>", UnresolvedType.NONE); + // addTypeMunger(world.concreteTypeMunger( + // new PrivilegedAccessMunger(member), inAspect)); + } + + public void addPrivilegedAccesses(Collection<ResolvedMember> accessedMembers) { + int version = inAspect.getCompilerVersion(); + for (ResolvedMember member : accessedMembers) { + // Looking it up ensures we get the annotations - the accessedMembers are just retrieved from the attribute and + // don't have that information + ResolvedMember resolvedMember = world.resolve(member); + + // pr333469 + // If the member is for an ITD (e.g. serialVersionUID) then during resolution we may resolve it on + // a supertype because it doesn't yet exist on the target. + // For example: MyList extends ArrayList<String> and the ITD is on MyList - after resolution it may be: + // ArrayList<String>.serialVersionUID, we need to avoid that happening + + if (resolvedMember == null) { + // can happen for ITDs - are there many privileged access ITDs?? + 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; + } + + /** + * Updates the records if something has changed. This is called at most twice, firstly whilst collecting ITDs and declares. At + * this point the CrosscuttingMembers we're comparing ourselves with doesn't know about shadowmungers. Therefore a straight + * comparison with the existing list of shadowmungers would return that something has changed even though it might not have, so + * in this first round we ignore the shadowMungers. The second time this is called is whilst we're preparing to weave. At this + * point we know everything in the system and so we're able to compare the shadowMunger list. (see bug 129163) + * + * @param other + * @param careAboutShadowMungers + * @return true if something has changed since the last time this method was called, false otherwise + */ + public boolean replaceWith(CrosscuttingMembers other, boolean careAboutShadowMungers) { + boolean changed = false; + + if (careAboutShadowMungers) { + if (perClause == null || !perClause.equals(other.perClause)) { + changed = true; + perClause = other.perClause; + } + } + + // XXX all of the below should be set equality rather than list equality + // System.err.println("old: " + shadowMungers + " new: " + + // other.shadowMungers); + + if (careAboutShadowMungers) { + // bug 129163: use set equality rather than list equality + Set<ShadowMunger> theseShadowMungers = new HashSet<ShadowMunger>(); + Set<ShadowMunger> theseInlinedAroundMungers = new HashSet<ShadowMunger>(); + for (ShadowMunger munger : shadowMungers) { + if (munger instanceof Advice) { + Advice adviceMunger = (Advice) munger; + // bug 154054: if we're around advice that has been inlined + // then we need to do more checking than existing equals + // methods allow + 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; + // bug 154054: if we're around advice that has been inlined + // then we need to do more checking than existing equals + // methods allow + 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; + } + + // bug 158573 - if there are no changes then preserve whether + // or not a particular shadowMunger has matched something. + 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()); + } + } + } + // replace the existing list of shadowmungers with the + // new ones in case anything like the sourcelocation has + // changed, however, don't want this flagged as a change + // which will force a full build - bug 134541 + shadowMungers = other.shadowMungers; + } + + // bug 129163: use set equality rather than list equality and + // if we dont care about shadow mungers then ignore those + // typeMungers which are created to help with the implementation + // of 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); + } + + // initial go at equivalence logic rather than set compare (see + // pr133532) + 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) { + // System.out.println("type munger change"); + changed = true; + } + if (shouldOverwriteThis) { + typeMungers = other.typeMungers; + } + } + // if (!theseTypeMungers.equals(otherTypeMungers)) { + // changed = true; + // 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)) { + // Are the differences just because of a mixin? These are not created until weave time so should be gotten rid of for + // the up front comparison + if (!careAboutShadowMungers) { + // this means we are in front end compilation and if the differences are purely mixin parents, we can continue OK + 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; + } + + // DECAT for when attempting to replace an aspect + 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) { + // *sigh* dirty fix for dirty hacky implementation pr149305 + 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; + } + + /** + * includes declare @method and @constructor + */ + 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(); + } + +} |