@@ -0,0 +1,87 @@ | |||
Rewritten... | |||
[bcel] hundreds of classes removed, one class now represents groups of instructions rather than one class per instruction | |||
[bcel] verifier packaged separately purely for use by AspectJ tests, not delivered in aspectj packages now | |||
[weaver] optimized KindedAnnotationAccessVar - renamed to AnnotationAccessVar | |||
[weaver] simplified member/resolvedmember hierarchy - still more to do, trying to remove need for casts, we should *know* what we | |||
are dealing with at each point | |||
todo: | |||
[weaver] | |||
[bcel] remove notion of Gens entirely (LineNumberGen/LocalVariableGen) and switch fully to lighter way tags | |||
[weaver] activate 'assertGoodBody()' code through command line option to catch bugs in the field | |||
[weaver] is reweavable turned off when LTW? | |||
measure performance - lot of hash table things used to keep types lightweight unless they need the extra data - might be a better way? | |||
OPTIMIZE task tag marks places noticed on the way through where we could do better | |||
hierarchies to attack: | |||
ASTNode | |||
UnresolvedType (messy...) | |||
Member | |||
28th April | |||
Looking at LazyMethodGen.pack() - 12% of the cpu usage for what we are testing. pack() is quite tricky to make better, wonder if we | |||
can differentiate amongst targeters to speed things up? Also instructionHandle has 'attributes' - for no good reason that I can see | |||
Removed static in BranchHandle... | |||
Performance analysis, following: http://java.sun.com/developer/technicalArticles/Programming/perfanal/ | |||
Reveals of 5415 ticks (weaving rt.jar), we spend 25% of the time in WeaverAdapter.removeFromMap() ! | |||
- changed that code to a CharOpt comparison | |||
- further changed to null 'lastReturnedResult' when it is finished with, should reduce ongoing calls | |||
- want to removeFromMap() quickly if we can. we can't usually because we have rebuilt the char array because | |||
post weave we build a new UnwovenClassFile() - I've changed the code to copy across the charname which | |||
means we can do remove() rather than searching all keys because the char array is the same one as what was | |||
used for the key when it was put in. | |||
knocks 25seconds (was 1 minute, now 35s) off the weave time | |||
--- Deliverable sizes: aspectjweaver.jar | |||
1.6.0 = 1,907,848 bytes:1094 classes | |||
26Apr = 1,718,083:893 | |||
26Apr = 1,618,024:849 (verifier removed from delivered package) | |||
27Apr = 1,612,996:848 | |||
---------------- | |||
Finally have a loadtime weaving test | |||
see - d:\e312\eclipse\plugins | |||
ltwToolsProto.bat | |||
of the 20seconds it takes for 1925 classes, 1.81% is: | |||
org.aspectj.weaver.tools.WeavingAdaptor.weaveClass: 57.5% (1142 inclusive / 0 exclusive) | |||
org.aspectj.weaver.tools.WeavingAdaptor.getWovenBytes: 49.14% (976 inclusive / 0 exclusive) | |||
org.aspectj.weaver.bcel.BcelWeaver.weave: 48.94% (972 inclusive / 11 exclusive) | |||
org.aspectj.weaver.bcel.BcelWeaver.weaveAndNotify: 45.37% (901 inclusive / 0 exclusive) | |||
org.aspectj.weaver.bcel.BcelWeaver.getClassFilesFor: 22% (437 inclusive / 0 exclusive) | |||
org.aspectj.weaver.bcel.LazyClassGen.getJavaClassBytesIncludingReweavable: 22% (437 inclusive / 0 exclusive) | |||
org.aspectj.weaver.bcel.LazyClassGen.writeBack: 17.88% (355 inclusive / 4 exclusive) | |||
org.aspectj.weaver.bcel.LazyMethodGen.getMethod: 17.42% (346 inclusive / 0 exclusive) | |||
org.aspectj.weaver.bcel.LazyMethodGen.pack: 13.09% (260 inclusive / 3 exclusive) | |||
org.aspectj.weaver.bcel.LazyMethodGen.newPackBody: 8.36% (166 inclusive / 81 exclusive) | |||
org.aspectj.apache.bcel.generic.InstructionList.delete: 1.31% (26 inclusive / 1 exclusive) | |||
29Apr | |||
now the extra bytecode parse in UnwovenClassFile - can we get rid of it by using the ctor that supplies a classname? | |||
2may | |||
looked at the analysis and getSourceLocation() was being called a lot - wasn't sure why given I didn't use tjp in the advice - turns | |||
out a dummy xrefhandler is added in LTWWorld, and so all the guards to avoid doing anything if there is no xrefhandler are worthless. | |||
fixed. | |||
noticed ClassParser ctor messing about remembering if the source is a zip and wrapping a baos in a bufferedinputstream - added new | |||
ctor to avoid that and removed the zip nonsense | |||
2May = 1,588,317:841 but fails tests, buggerit | |||
@@ -10,7 +10,6 @@ | |||
* PARC initial implementation | |||
* ******************************************************************/ | |||
package org.aspectj.weaver; | |||
import java.io.IOException; | |||
@@ -18,15 +17,17 @@ import java.io.IOException; | |||
import org.aspectj.util.TypeSafeEnum; | |||
/** | |||
* The 5 kinds of advice in AspectJ. | |||
* The five kinds of advice in AspectJ. | |||
* | |||
* @author Erik Hilsdale | |||
* @author Jim Hugunin | |||
*/ | |||
public class AdviceKind extends TypeSafeEnum { | |||
private int precedence; | |||
private boolean isAfter; | |||
private boolean isCflow; | |||
public AdviceKind(String name, int key, int precedence, boolean isAfter, boolean isCflow) { | |||
super(name, key); | |||
this.precedence = precedence; | |||
@@ -114,4 +115,4 @@ public class AdviceKind extends TypeSafeEnum { | |||
return this == PerThisEntry || this == PerTargetEntry; | |||
} | |||
} | |||
} |
@@ -215,10 +215,16 @@ public abstract class AjAttribute { | |||
public static short WEAVER_VERSION_MAJOR_AJ150M4 = 3; | |||
public static short WEAVER_VERSION_MAJOR_AJ150 = 2; | |||
public static short WEAVER_VERSION_MINOR_AJ150 = 0; | |||
// These are the weaver major/minor numbers for AspectJ 1.6.0 | |||
public static short WEAVER_VERSION_MAJOR_AJ160M2 = 5; | |||
public static short WEAVER_VERSION_MAJOR_AJ160 = 4; | |||
public static short WEAVER_VERSION_MINOR_AJ160 = 0; | |||
// These are the weaver major/minor versions for *this* weaver | |||
private static short CURRENT_VERSION_MAJOR = WEAVER_VERSION_MAJOR_AJ150M4; | |||
private static short CURRENT_VERSION_MINOR = WEAVER_VERSION_MINOR_AJ150; | |||
private static short CURRENT_VERSION_MAJOR = WEAVER_VERSION_MAJOR_AJ160M2; | |||
private static short CURRENT_VERSION_MINOR = WEAVER_VERSION_MINOR_AJ160; | |||
public static final WeaverVersionInfo UNKNOWN = | |||
new WeaverVersionInfo(WEAVER_VERSION_MAJOR_UNKNOWN,WEAVER_VERSION_MINOR_UNKNOWN); |
@@ -252,9 +252,7 @@ public class AjcMemberMaker { | |||
public static ResolvedMember perSingletonAspectOfMethod(UnresolvedType declaringType) { | |||
return new ResolvedMemberImpl(Member.METHOD, | |||
declaringType, PUBLIC_STATIC, "aspectOf", | |||
"()" + declaringType.getSignature()); | |||
return new ResolvedMemberImpl(Member.METHOD, declaringType, PUBLIC_STATIC, "aspectOf", "()" + declaringType.getSignature()); | |||
} | |||
public static ResolvedMember perSingletonHasAspectMethod(UnresolvedType declaringType) { |
@@ -16,5 +16,6 @@ public interface AnnotatedElement { | |||
boolean hasAnnotation(UnresolvedType ofType); | |||
ResolvedType[] getAnnotationTypes(); | |||
// SomeType getAnnotation(UnresolvedType ofType); | |||
AnnotationX getAnnotationOfType(UnresolvedType ofType); | |||
} |
@@ -95,4 +95,27 @@ public class AnnotationAJ { | |||
sb.append("]"); | |||
return sb.toString(); | |||
} | |||
public boolean hasNamedValue(String n) { | |||
if (nvPairs==null) return false; | |||
for (int i=0;i<nvPairs.size();i++) { | |||
AnnotationNameValuePair pair = (AnnotationNameValuePair)nvPairs.get(i); | |||
if (pair.getName().equals(n)) return true; | |||
} | |||
return false; | |||
} | |||
/** | |||
* Return true if the annotation has a value with the specified name (n) and value (v) | |||
*/ | |||
public boolean hasNameValuePair(String n, String v) { | |||
if (nvPairs==null) return false; | |||
for (int i=0;i<nvPairs.size();i++) { | |||
AnnotationNameValuePair pair = (AnnotationNameValuePair)nvPairs.get(i); | |||
if (pair.getName().equals(n)) { | |||
if (pair.getValue().stringify().equals(v)) return true; | |||
} | |||
} | |||
return false; | |||
} | |||
} |
@@ -24,7 +24,7 @@ import org.aspectj.apache.bcel.classfile.annotation.EnumElementValueGen; | |||
/** | |||
* AnnotationX instances are holders for an annotation from either Bcel or | |||
* ASM. We have this holder so that types about the bcel weaver package | |||
* eclipse. We have this holder so that types about the bcel weaver package | |||
* can work with something not bytecode toolkit specific. | |||
*/ | |||
public class AnnotationX { | |||
@@ -32,9 +32,9 @@ public class AnnotationX { | |||
public static final AnnotationX[] NONE = new AnnotationX[0]; | |||
private AnnotationGen theRealBcelAnnotation; | |||
private AnnotationAJ theRealASMAnnotation; | |||
private AnnotationAJ theRealEclipseAnnotation; // OPTIMIZE push out into compiler, not ever used if purely binary weaving ? | |||
private int mode = -1; | |||
private final static int MODE_ASM = 1; | |||
private final static int MODE_ECLIPSE = 1; | |||
private final static int MODE_BCEL = 2; | |||
private ResolvedType signature = null; | |||
@@ -51,9 +51,9 @@ public class AnnotationX { | |||
} | |||
public AnnotationX(AnnotationAJ a,World world) { | |||
theRealASMAnnotation = a; | |||
signature = UnresolvedType.forSignature(theRealASMAnnotation.getTypeSignature()).resolve(world); | |||
mode= MODE_ASM; | |||
theRealEclipseAnnotation = a; | |||
signature = UnresolvedType.forSignature(theRealEclipseAnnotation.getTypeSignature()).resolve(world); | |||
mode= MODE_ECLIPSE; | |||
} | |||
public AnnotationGen getBcelAnnotation() { | |||
@@ -66,18 +66,18 @@ public class AnnotationX { | |||
public String toString() { | |||
if (mode==MODE_BCEL) return theRealBcelAnnotation.toString(); | |||
else return theRealASMAnnotation.toString(); | |||
else return theRealEclipseAnnotation.toString(); | |||
} | |||
public String getTypeName() { | |||
if (mode==MODE_BCEL) return theRealBcelAnnotation.getTypeName(); | |||
else return Utility.signatureToString(theRealASMAnnotation.getTypeSignature()); | |||
else return Utility.signatureToString(theRealEclipseAnnotation.getTypeSignature()); | |||
} | |||
public String getTypeSignature() { | |||
if (mode==MODE_BCEL) return theRealBcelAnnotation.getTypeSignature(); | |||
else return theRealASMAnnotation.getTypeSignature(); | |||
else return theRealEclipseAnnotation.getTypeSignature(); | |||
} | |||
@@ -176,7 +176,7 @@ public class AnnotationX { | |||
supportedTargets.add(ev.getEnumValueString()); | |||
} | |||
} else { | |||
List values = theRealASMAnnotation.getNameValuePairs(); | |||
List values = theRealEclipseAnnotation.getNameValuePairs(); | |||
AnnotationNameValuePair nvp = (AnnotationNameValuePair)values.get(0); | |||
ArrayAnnotationValue aav = (ArrayAnnotationValue)nvp.getValue(); | |||
AnnotationValue[] avs = aav.getValues(); | |||
@@ -203,7 +203,17 @@ public class AnnotationX { | |||
public void print(StringBuffer sb) { | |||
if (mode==MODE_BCEL) sb.append(theRealBcelAnnotation.toString()); | |||
else sb.append(theRealASMAnnotation.stringify()); | |||
else sb.append(theRealEclipseAnnotation.stringify()); | |||
} | |||
public boolean hasNameValuePair(String n, String v) { | |||
if (mode==MODE_BCEL) return theRealBcelAnnotation.hasNameValuePair(n,v); | |||
else return theRealEclipseAnnotation.hasNameValuePair(n,v); | |||
} | |||
public boolean hasNamedValue(String n) { | |||
if (mode==MODE_BCEL) return theRealBcelAnnotation.hasNamedValue(n); | |||
else return theRealEclipseAnnotation.hasNamedValue(n); | |||
} | |||
} |
@@ -0,0 +1,186 @@ | |||
/* ******************************************************************* | |||
* Copyright (c) 2008 Contributors | |||
* 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: | |||
* Andy Clement initial implementation | |||
* ******************************************************************/ | |||
package org.aspectj.weaver; | |||
import java.lang.reflect.Modifier; | |||
/** | |||
* Represents a resolved array type | |||
* | |||
* @author Andy Clement | |||
*/ | |||
public class ArrayReferenceType extends ReferenceType { | |||
private ResolvedType componentType; | |||
public ArrayReferenceType(String sig, String erasureSig, World world, ResolvedType componentType) { | |||
super(sig, erasureSig, world); | |||
this.componentType = componentType; | |||
} | |||
// These methods are from the original implementation when Array was a ResolvedType and not a ReferenceType | |||
public final ResolvedMember[] getDeclaredFields() { | |||
return ResolvedMember.NONE; | |||
} | |||
public final ResolvedMember[] getDeclaredMethods() { | |||
// ??? should this return clone? Probably not... | |||
// If it ever does, here is the code: | |||
// ResolvedMember cloneMethod = | |||
// new ResolvedMember(Member.METHOD,this,Modifier.PUBLIC,UnresolvedType.OBJECT,"clone",new UnresolvedType[]{}); | |||
// return new ResolvedMember[]{cloneMethod}; | |||
return ResolvedMember.NONE; | |||
} | |||
public final ResolvedType[] getDeclaredInterfaces() { | |||
return new ResolvedType[] { world.getCoreType(CLONEABLE), world.getCoreType(SERIALIZABLE) }; | |||
} | |||
public final ResolvedMember[] getDeclaredPointcuts() { | |||
return ResolvedMember.NONE; | |||
} | |||
public boolean hasAnnotation(UnresolvedType ofType) { | |||
return false; | |||
} | |||
public final ResolvedType getSuperclass() { | |||
return world.getCoreType(OBJECT); | |||
} | |||
public final boolean isAssignableFrom(ResolvedType o) { | |||
if (!o.isArray()) | |||
return false; | |||
if (o.getComponentType().isPrimitiveType()) { | |||
return o.equals(this); | |||
} else { | |||
return getComponentType().resolve(world).isAssignableFrom(o.getComponentType().resolve(world)); | |||
} | |||
} | |||
public boolean isAssignableFrom(ResolvedType o, boolean allowMissing) { | |||
return isAssignableFrom(o); | |||
} | |||
public final boolean isCoerceableFrom(ResolvedType o) { | |||
if (o.equals(UnresolvedType.OBJECT) || o.equals(UnresolvedType.SERIALIZABLE) || o.equals(UnresolvedType.CLONEABLE)) { | |||
return true; | |||
} | |||
if (!o.isArray()) | |||
return false; | |||
if (o.getComponentType().isPrimitiveType()) { | |||
return o.equals(this); | |||
} else { | |||
return getComponentType().resolve(world).isCoerceableFrom(o.getComponentType().resolve(world)); | |||
} | |||
} | |||
public final int getModifiers() { | |||
int mask = Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED; | |||
return (componentType.getModifiers() & mask) | Modifier.FINAL; | |||
} | |||
public UnresolvedType getComponentType() { | |||
return componentType; | |||
} | |||
public ResolvedType getResolvedComponentType() { | |||
return componentType; | |||
} | |||
public ISourceContext getSourceContext() { | |||
return getResolvedComponentType().getSourceContext(); | |||
} | |||
// Methods overridden from ReferenceType follow | |||
public TypeVariable[] getTypeVariables() { | |||
if (this.typeVariables == null && componentType.getTypeVariables() != null) { | |||
this.typeVariables = componentType.getTypeVariables(); | |||
for (int i = 0; i < this.typeVariables.length; i++) { | |||
this.typeVariables[i].resolve(world); | |||
} | |||
} | |||
return this.typeVariables; | |||
} | |||
public boolean isAnnotation() { | |||
return false; | |||
} | |||
public boolean isAnonymous() { | |||
return false; | |||
} | |||
public boolean isAnnotationStyleAspect() { | |||
return false; | |||
} | |||
public boolean isAspect() { | |||
return false; | |||
} | |||
public boolean isPrimitiveType() { | |||
return typeKind == TypeKind.PRIMITIVE; | |||
} | |||
public boolean isSimpleType() { | |||
return typeKind == TypeKind.SIMPLE; | |||
} | |||
public boolean isRawType() { | |||
return typeKind == TypeKind.RAW; | |||
} | |||
public boolean isGenericType() { | |||
return typeKind == TypeKind.GENERIC; | |||
} | |||
public boolean isParameterizedType() { | |||
return typeKind == TypeKind.PARAMETERIZED; | |||
} | |||
public boolean isTypeVariableReference() { | |||
return typeKind == TypeKind.TYPE_VARIABLE; | |||
} | |||
public boolean isGenericWildcard() { | |||
return typeKind == TypeKind.WILDCARD; | |||
} | |||
public boolean isEnum() { | |||
return false; | |||
} | |||
public boolean isNested() { | |||
return false; | |||
} | |||
public boolean isClass() { | |||
return false; | |||
} | |||
public boolean canAnnotationTargetType() { | |||
return false; | |||
} | |||
public AnnotationTargetKind[] getAnnotationTargetKinds() { | |||
return null; | |||
} | |||
public boolean isAnnotationWithRuntimeRetention() { | |||
return false; | |||
} | |||
} |
@@ -16,6 +16,7 @@ package org.aspectj.weaver; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
import org.aspectj.apache.bcel.classfile.Field; | |||
import org.aspectj.apache.bcel.classfile.Method; | |||
import org.aspectj.apache.bcel.classfile.Utility; | |||
import org.aspectj.apache.bcel.generic.Type; | |||
@@ -430,7 +431,7 @@ public class AsmRelationshipProvider { | |||
* the fields' type in order to locate it. Currently just fails silently if any of the lookup code | |||
* doesn't find anything... | |||
*/ | |||
public void addDeclareAnnotationRelationship(ISourceLocation sourceLocation, String typename,String fieldName) { | |||
public void addDeclareAnnotationRelationship(ISourceLocation sourceLocation, String typename,Field field) { | |||
if (!AsmManager.isCreatingModel()) return; | |||
String pkg = null; | |||
@@ -444,7 +445,7 @@ public class AsmRelationshipProvider { | |||
IProgramElement typeElem = AsmManager.getDefault().getHierarchy().findElementForType(pkg,type); | |||
if (typeElem == null) return; | |||
IProgramElement fieldElem = AsmManager.getDefault().getHierarchy().findElementForSignature(typeElem,IProgramElement.Kind.FIELD,fieldName); | |||
IProgramElement fieldElem = AsmManager.getDefault().getHierarchy().findElementForSignature(typeElem,IProgramElement.Kind.FIELD,field.getName()); | |||
if (fieldElem== null) return; | |||
String targetHandle = fieldElem.getHandleIdentifier(); |
@@ -1,29 +0,0 @@ | |||
/* ******************************************************************* | |||
* 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; | |||
/** | |||
* Exception to use inside the bcweaver. | |||
*/ | |||
public class BetaException extends RuntimeException { | |||
public BetaException() { | |||
super(); | |||
} | |||
public BetaException(String s) { | |||
super(s); | |||
} | |||
} |
@@ -13,6 +13,8 @@ | |||
package org.aspectj.weaver; | |||
import java.util.Map; | |||
import org.aspectj.bridge.ISourceLocation; | |||
import org.aspectj.util.PartialOrder; | |||
@@ -123,4 +125,6 @@ public abstract class ConcreteTypeMunger implements PartialOrder.PartialComparab | |||
if (munger==null) return false; | |||
return munger.isLateMunger(); | |||
} | |||
public abstract ConcreteTypeMunger parameterizeWith(Map parameterizationMap, World world); | |||
} |
@@ -14,8 +14,10 @@ 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.List; | |||
import java.util.Map; | |||
import java.util.Set; | |||
import org.aspectj.weaver.bcel.BcelAdvice; | |||
@@ -71,6 +73,10 @@ public class CrosscuttingMembers { | |||
this.shouldConcretizeIfNeeded = shouldConcretizeIfNeeded; | |||
} | |||
private Hashtable cflowFields = new Hashtable(); | |||
private Hashtable cflowBelowFields = new Hashtable(); | |||
// public void addConcreteShadowMungers(Collection c) { | |||
// shadowMungers.addAll(c); | |||
// } | |||
@@ -502,4 +508,17 @@ public class CrosscuttingMembers { | |||
return declareAnnotationsOnMethods; | |||
} | |||
public Map getCflowBelowFields() { | |||
return cflowBelowFields; | |||
} | |||
public Map getCflowFields() { | |||
return cflowFields; | |||
} | |||
public void clearCaches() { | |||
cflowFields.clear(); | |||
cflowBelowFields.clear(); | |||
} | |||
} |
@@ -78,13 +78,10 @@ public class CrosscuttingMembersSet { | |||
if (xcut == null) { | |||
members.put(aspectType, aspectType.collectCrosscuttingMembers(inWeavingPhase)); | |||
clearCaches(); | |||
CflowPointcut.clearCaches(aspectType); | |||
change = true; | |||
} else { | |||
if (xcut.replaceWith(aspectType.collectCrosscuttingMembers(inWeavingPhase),inWeavingPhase)) { | |||
clearCaches(); | |||
CflowPointcut.clearCaches(aspectType); | |||
change = true; | |||
} else { | |||
if (!AsmManager.getDefault().getHandleProvider().dependsOnLocation() |
@@ -0,0 +1,58 @@ | |||
/* ******************************************************************* | |||
* Copyright (c) 2007 Contributors | |||
* 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: | |||
* Linton Ye https://bugs.eclipse.org/bugs/show_bug.cgi?id=193065 | |||
* ******************************************************************/ | |||
package org.aspectj.weaver; | |||
import java.util.Collection; | |||
/** | |||
* <p> | |||
* This interface is introduced to support tools like PointcutDoctor. | |||
* </p> | |||
* <p> | |||
* A CustomMungerFactory is used to create ShadowMungers and/or | |||
* ConcreteTypeMungers so that an extender can extract extra information during | |||
* the weaving process. | |||
* </p> | |||
* <p> | |||
* A CustomMungerFactory is assigned to a weaver through its AjCompiler in | |||
* extenders' code, and gets invoked by the weaver right before the weaving | |||
* starts. The custom shadow/type mungers being created will be added into the | |||
* shadow/type munger list in the weaver and participate the weaving process. | |||
* For example, the match method of each custom shadow munger will be called | |||
* against each shadow. | |||
* </p> | |||
* @author lintonye | |||
* | |||
*/ | |||
public interface CustomMungerFactory { | |||
/** | |||
* @param aspectType | |||
* @return a Collection<ShadowMunger> of custom shadow mungers for the | |||
* given aspect | |||
*/ | |||
public Collection/* ShadowMunger */createCustomShadowMungers( | |||
ResolvedType aspectType); | |||
/** | |||
* @param aspectType | |||
* @return a Collection<ConcreteTypeMunger> of custom type mungers for the | |||
* given aspect | |||
*/ | |||
public Collection/* ConcreteTypeMunger */createCustomTypeMungers( | |||
ResolvedType aspectType); | |||
public Collection/* ShadowMunger */getAllCreatedCustomShadowMungers(); | |||
public Collection/* ConcreteTypeMunger */getAllCreatedCustomTypeMungers(); | |||
} |
@@ -16,6 +16,7 @@ import java.io.IOException; | |||
import java.util.Collection; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
import java.util.Map; | |||
import org.aspectj.bridge.ISourceLocation; | |||
import org.aspectj.weaver.AjAttribute.EffectiveSignatureAttribute; | |||
@@ -90,6 +91,10 @@ public class JoinPointSignature implements ResolvedMember { | |||
public ResolvedType[] getAnnotationTypes() { | |||
return realMember.getAnnotationTypes(); | |||
} | |||
public AnnotationX getAnnotationOfType(UnresolvedType ofType) { | |||
return realMember.getAnnotationOfType(ofType); | |||
} | |||
public void setAnnotationTypes(UnresolvedType[] annotationtypes) { | |||
realMember.setAnnotationTypes(annotationtypes); | |||
@@ -235,15 +240,7 @@ public class JoinPointSignature implements ResolvedMember { | |||
return realMember.resolve(world); | |||
} | |||
public int compareTo(Object other) { | |||
return realMember.compareTo(other); | |||
} | |||
public String toLongString() { | |||
return realMember.toLongString(); | |||
} | |||
public Kind getKind() { | |||
public MemberKind getKind() { | |||
return realMember.getKind(); | |||
} | |||
@@ -262,6 +259,14 @@ public class JoinPointSignature implements ResolvedMember { | |||
public UnresolvedType[] getParameterTypes() { | |||
return realMember.getParameterTypes(); | |||
} | |||
public AnnotationX[][] getParameterAnnotations() { | |||
return realMember.getParameterAnnotations(); | |||
} | |||
public ResolvedType[][] getParameterAnnotationTypes() { | |||
return realMember.getParameterAnnotationTypes(); | |||
} | |||
public String getSignature() { | |||
return realMember.getSignature(); | |||
@@ -279,18 +284,6 @@ public class JoinPointSignature implements ResolvedMember { | |||
return realMember.isCompatibleWith(am); | |||
} | |||
public boolean isProtected(World world) { | |||
return realMember.isProtected(world); | |||
} | |||
public boolean isStatic(World world) { | |||
return realMember.isStatic(world); | |||
} | |||
public boolean isStrict(World world) { | |||
return realMember.isStrict(world); | |||
} | |||
public boolean isStatic() { | |||
return realMember.isStatic(); | |||
} | |||
@@ -373,7 +366,7 @@ public class JoinPointSignature implements ResolvedMember { | |||
realMember.resetName(newName); | |||
} | |||
public void resetKind(Kind newKind) { | |||
public void resetKind(MemberKind newKind) { | |||
realMember.resetKind(newKind); | |||
} | |||
@@ -407,7 +400,11 @@ public class JoinPointSignature implements ResolvedMember { | |||
public void evictWeavingState() { realMember.evictWeavingState(); } | |||
public Member slimline() { | |||
return this; | |||
public ResolvedMember parameterizedWith(Map m, World w) { | |||
return realMember.parameterizedWith(m,w); | |||
} | |||
public String getAnnotationDefaultValue() { | |||
return realMember.getAnnotationDefaultValue(); | |||
} | |||
} |
@@ -128,6 +128,9 @@ public class Lint { | |||
public final Kind advisingSynchronizedMethods = new Kind("advisingSynchronizedMethods", | |||
"advice matching the synchronized method shadow ''{0}'' will be executed outside the lock rather than inside (compiler limitation)"); | |||
public final Kind mustWeaveXmlDefinedAspects = new Kind("mustWeaveXmlDefinedAspects", | |||
"XML Defined aspects must be woven in cases where cflow pointcuts are involved. Currently the include/exclude patterns exclude ''{0}''"); | |||
private static Trace trace = TraceFactory.getTraceFactory().getTrace(Lint.class); | |||
public Lint(World world) { |
@@ -13,71 +13,46 @@ | |||
* ******************************************************************/ | |||
package org.aspectj.weaver; | |||
import java.io.DataInputStream; | |||
import java.io.IOException; | |||
import java.util.Collection; | |||
import java.util.Iterator; | |||
import org.aspectj.util.TypeSafeEnum; | |||
public interface Member { | |||
public static class Kind extends TypeSafeEnum { | |||
public Kind(String name, int key) { super(name, key); } | |||
public static Kind read(DataInputStream s) throws IOException { | |||
int key = s.readByte(); | |||
switch(key) { | |||
case 1: return METHOD; | |||
case 2: return FIELD; | |||
case 3: return CONSTRUCTOR; | |||
case 4: return STATIC_INITIALIZATION; | |||
case 5: return POINTCUT; | |||
case 6: return ADVICE; | |||
case 7: return HANDLER; | |||
case 8: return MONITORENTER; | |||
case 9: return MONITOREXIT; | |||
} | |||
throw new BCException("weird kind " + key); | |||
} | |||
} | |||
public static final Member[] NONE = new Member[0]; | |||
public static final Kind METHOD = new Kind("METHOD", 1); | |||
public static final Kind FIELD = new Kind("FIELD", 2); | |||
public static final Kind CONSTRUCTOR = new Kind("CONSTRUCTOR", 3); | |||
public static final Kind STATIC_INITIALIZATION = new Kind("STATIC_INITIALIZATION", 4); | |||
public static final Kind POINTCUT = new Kind("POINTCUT", 5); | |||
public static final Kind ADVICE = new Kind("ADVICE", 6); | |||
public static final Kind HANDLER = new Kind("HANDLER", 7); | |||
public static final Kind MONITORENTER = new Kind("MONITORENTER", 8); | |||
public static final Kind MONITOREXIT = new Kind("MONITOREXIT", 9); | |||
public static final Member[] NONE = new Member[0]; | |||
public static final MemberKind METHOD = new MemberKind("METHOD", 1); | |||
public static final MemberKind FIELD = new MemberKind("FIELD", 2); | |||
public static final MemberKind CONSTRUCTOR = new MemberKind("CONSTRUCTOR", 3); | |||
public static final MemberKind STATIC_INITIALIZATION = new MemberKind("STATIC_INITIALIZATION", 4); | |||
public static final MemberKind POINTCUT = new MemberKind("POINTCUT", 5); | |||
public static final MemberKind ADVICE = new MemberKind("ADVICE", 6); | |||
public static final MemberKind HANDLER = new MemberKind("HANDLER", 7); | |||
public static final MemberKind MONITORENTER = new MemberKind("MONITORENTER", 8); | |||
public static final MemberKind MONITOREXIT = new MemberKind("MONITOREXIT", 9); | |||
public static final AnnotationX[][] NO_PARAMETER_ANNOTATIONXS = new AnnotationX[][]{}; | |||
public static final ResolvedType[][] NO_PARAMETER_ANNOTATION_TYPES = new ResolvedType[][]{}; | |||
public MemberKind getKind(); | |||
public ResolvedMember resolve(World world); | |||
public int compareTo(Object other); | |||
public String toLongString(); | |||
public Kind getKind(); | |||
public String getName(); | |||
public UnresolvedType getDeclaringType(); | |||
public UnresolvedType getReturnType(); | |||
public AnnotationX[] getAnnotations(); | |||
public UnresolvedType getReturnType(); | |||
public UnresolvedType getType(); | |||
public UnresolvedType getGenericReturnType(); | |||
public UnresolvedType[] getGenericParameterTypes(); | |||
public UnresolvedType getType(); | |||
public String getName(); | |||
public String[] getParameterNames(World world); | |||
public UnresolvedType[] getParameterTypes(); | |||
public UnresolvedType[] getGenericParameterTypes(); | |||
/** | |||
* Return full signature, including return type, e.g. "()LFastCar;" for a signature without the return type, | |||
* use getParameterSignature() - it is importnant to choose the right one in the face of covariance. | |||
* use getParameterSignature() - it is important to choose the right one in the face of covariance. | |||
*/ | |||
public String getSignature(); | |||
@@ -102,52 +77,25 @@ public interface Member { | |||
public UnresolvedType[] getExceptions(World world); | |||
public boolean isProtected(World world); | |||
public boolean isStatic(World world); | |||
public boolean isStrict(World world); | |||
public boolean isStatic(); | |||
public boolean isInterface(); | |||
public boolean isPrivate(); | |||
/** | |||
* Returns true iff the member is generic (NOT parameterized) | |||
* For example, a method declared in a generic type | |||
*/ | |||
public boolean canBeParameterized(); | |||
public int getCallsiteModifiers(); | |||
public String getExtractableName(); | |||
/** | |||
* If you want a sensible answer, resolve the member and call | |||
* hasAnnotation() on the ResolvedMember. | |||
*/ | |||
public boolean hasAnnotation(UnresolvedType ofType); | |||
/* (non-Javadoc) | |||
* @see org.aspectj.weaver.AnnotatedElement#getAnnotationTypes() | |||
*/ | |||
public ResolvedType[] getAnnotationTypes(); | |||
public AnnotationX[] getAnnotations(); | |||
// public AnnotationX[] getAnnotations(); | |||
public Collection/*ResolvedType*/getDeclaringTypes(World world); | |||
// ---- reflective thisJoinPoint stuff | |||
// ---- reflective thisJoinPoint related methods | |||
public String getSignatureMakerName(); | |||
public String getSignatureType(); | |||
public String getSignatureString(World world); | |||
public String[] getParameterNames(World world); | |||
public Member slimline(); | |||
} |
@@ -21,19 +21,26 @@ import java.util.Iterator; | |||
import java.util.List; | |||
public class MemberImpl implements Comparable, AnnotatedElement,Member { | |||
protected Kind kind; | |||
protected int modifiers; | |||
protected UnresolvedType declaringType; | |||
public class MemberImpl implements Comparable, Member { | |||
protected MemberKind kind; | |||
protected String name; | |||
protected UnresolvedType declaringType; | |||
protected int modifiers; | |||
protected UnresolvedType returnType; | |||
protected UnresolvedType[] parameterTypes; | |||
private final String signature; | |||
private String paramSignature; | |||
// OPTIMIZE move out of the member! | |||
private boolean reportedCantFindDeclaringType = false; | |||
private boolean reportedUnresolvableMember = false; | |||
public AnnotationX[] getAnnotations() { | |||
throw new IllegalStateException("Cannot answer getAnnotations() for MemberImpl "+this.toString()); | |||
} | |||
/** | |||
* All the signatures that a join point with this member as its signature has. | |||
@@ -43,7 +50,7 @@ public class MemberImpl implements Comparable, AnnotatedElement,Member { | |||
private JoinPointSignatureIterator joinPointSignatures = null; | |||
public MemberImpl( | |||
Kind kind, | |||
MemberKind kind, | |||
UnresolvedType declaringType, | |||
int modifiers, | |||
String name, | |||
@@ -53,6 +60,9 @@ public class MemberImpl implements Comparable, AnnotatedElement,Member { | |||
this.declaringType = declaringType; | |||
this.modifiers = modifiers; | |||
this.name = name; | |||
if (kind!=STATIC_INITIALIZATION && name!=null && name.equals("<clinit>")) { | |||
throw new RuntimeException("!"); | |||
} | |||
this.signature = signature; | |||
if (kind == FIELD) { | |||
this.returnType = UnresolvedType.forSignature(signature); | |||
@@ -68,7 +78,7 @@ public class MemberImpl implements Comparable, AnnotatedElement,Member { | |||
} | |||
public MemberImpl( | |||
Kind kind, | |||
MemberKind kind, | |||
UnresolvedType declaringType, | |||
int modifiers, | |||
UnresolvedType returnType, | |||
@@ -78,7 +88,11 @@ public class MemberImpl implements Comparable, AnnotatedElement,Member { | |||
super(); | |||
this.kind = kind; | |||
this.declaringType = declaringType; | |||
this.modifiers = modifiers; | |||
this.modifiers = modifiers; | |||
if (name!=null && name.equals("<clinit>") && kind!=STATIC_INITIALIZATION) { | |||
throw new RuntimeException("!"); | |||
} | |||
this.returnType = returnType; | |||
this.name = name; | |||
this.parameterTypes = parameterTypes; | |||
@@ -232,13 +246,7 @@ public class MemberImpl implements Comparable, AnnotatedElement,Member { | |||
private static MemberImpl field(String declaring, int mods, UnresolvedType ty, String name) { | |||
return new MemberImpl( | |||
FIELD, | |||
UnresolvedType.forName(declaring), | |||
mods, | |||
ty, | |||
name, | |||
UnresolvedType.NONE); | |||
return new MemberImpl(FIELD, UnresolvedType.forName(declaring), mods, ty, name, UnresolvedType.NONE); | |||
} | |||
public static MemberImpl method(UnresolvedType declTy, int mods, UnresolvedType rTy, String name, UnresolvedType[] paramTys) { | |||
@@ -270,107 +278,6 @@ public class MemberImpl implements Comparable, AnnotatedElement,Member { | |||
"(" + catchType.getSignature() + ")V"); | |||
} | |||
// ---- parsing methods | |||
/** Takes a string in this form: | |||
* | |||
* <blockquote><pre> | |||
* static? TypeName TypeName.Id | |||
* </pre></blockquote> | |||
* Pretty much just for testing, and as such should perhaps be moved. | |||
*/ | |||
public static MemberImpl fieldFromString(String str) { | |||
str = str.trim(); | |||
final int len = str.length(); | |||
int i = 0; | |||
int mods = 0; | |||
if (str.startsWith("static", i)) { | |||
mods = Modifier.STATIC; | |||
i += 6; | |||
while (Character.isWhitespace(str.charAt(i))) i++; | |||
} | |||
int start = i; | |||
while (! Character.isWhitespace(str.charAt(i))) i++; | |||
UnresolvedType retTy = UnresolvedType.forName(str.substring(start, i)); | |||
start = i; | |||
i = str.lastIndexOf('.'); | |||
UnresolvedType declaringTy = UnresolvedType.forName(str.substring(start, i).trim()); | |||
start = ++i; | |||
String name = str.substring(start, len).trim(); | |||
return new MemberImpl( | |||
FIELD, | |||
declaringTy, | |||
mods, | |||
retTy, | |||
name, | |||
UnresolvedType.NONE); | |||
} | |||
/** Takes a string in this form: | |||
* | |||
* <blockquote><pre> | |||
* (static|interface|private)? TypeName TypeName . Id ( TypeName , ...) | |||
* </pre></blockquote> | |||
* Pretty much just for testing, and as such should perhaps be moved. | |||
*/ | |||
public static Member methodFromString(String str) { | |||
str = str.trim(); | |||
// final int len = str.length(); | |||
int i = 0; | |||
int mods = 0; | |||
if (str.startsWith("static", i)) { | |||
mods = Modifier.STATIC; | |||
i += 6; | |||
} else if (str.startsWith("interface", i)) { | |||
mods = Modifier.INTERFACE; | |||
i += 9; | |||
} else if (str.startsWith("private", i)) { | |||
mods = Modifier.PRIVATE; | |||
i += 7; | |||
} | |||
while (Character.isWhitespace(str.charAt(i))) i++; | |||
int start = i; | |||
while (! Character.isWhitespace(str.charAt(i))) i++; | |||
UnresolvedType returnTy = UnresolvedType.forName(str.substring(start, i)); | |||
start = i; | |||
i = str.indexOf('(', i); | |||
i = str.lastIndexOf('.', i); | |||
UnresolvedType declaringTy = UnresolvedType.forName(str.substring(start, i).trim()); | |||
start = ++i; | |||
i = str.indexOf('(', i); | |||
String name = str.substring(start, i).trim(); | |||
start = ++i; | |||
i = str.indexOf(')', i); | |||
String[] paramTypeNames = parseIds(str.substring(start, i).trim()); | |||
return method(declaringTy, mods, returnTy, name, UnresolvedType.forNames(paramTypeNames)); | |||
} | |||
private static String[] parseIds(String str) { | |||
if (str.length() == 0) return ZERO_STRINGS; | |||
List l = new ArrayList(); | |||
int start = 0; | |||
while (true) { | |||
int i = str.indexOf(',', start); | |||
if (i == -1) { | |||
l.add(str.substring(start).trim()); | |||
break; | |||
} | |||
l.add(str.substring(start, i).trim()); | |||
start = i+1; | |||
} | |||
return (String[]) l.toArray(new String[l.size()]); | |||
} | |||
private static final String[] ZERO_STRINGS = new String[0]; | |||
// ---- things we know without resolution | |||
@@ -433,62 +340,32 @@ public class MemberImpl implements Comparable, AnnotatedElement,Member { | |||
return buf.toString(); | |||
} | |||
// Overridden by subclasses - a method can be advice | |||
public MemberKind getKind() { | |||
return kind; | |||
} | |||
/* (non-Javadoc) | |||
* @see org.aspectj.weaver.Member#toLongString() | |||
*/ | |||
public String toLongString() { | |||
StringBuffer buf = new StringBuffer(); | |||
buf.append(kind); | |||
buf.append(' '); | |||
if (modifiers != 0) { | |||
buf.append(Modifier.toString(modifiers)); | |||
buf.append(' '); | |||
} | |||
buf.append(toString()); | |||
buf.append(" <"); | |||
buf.append(signature); | |||
buf.append(" >"); | |||
return buf.toString(); | |||
} | |||
/* (non-Javadoc) | |||
* @see org.aspectj.weaver.Member#getKind() | |||
*/ | |||
public Kind getKind() { return kind; } | |||
/* (non-Javadoc) | |||
* @see org.aspectj.weaver.Member#getDeclaringType() | |||
*/ | |||
public UnresolvedType getDeclaringType() { return declaringType; } | |||
/* (non-Javadoc) | |||
* @see org.aspectj.weaver.Member#getReturnType() | |||
*/ | |||
public UnresolvedType getReturnType() { return returnType; } | |||
public UnresolvedType getGenericReturnType() { return getReturnType(); } | |||
public UnresolvedType[] getGenericParameterTypes() { return getParameterTypes(); } | |||
/* (non-Javadoc) | |||
* @see org.aspectj.weaver.Member#getType() | |||
*/ | |||
public UnresolvedType getType() { return returnType; } | |||
/* (non-Javadoc) | |||
* @see org.aspectj.weaver.Member#getName() | |||
*/ | |||
public String getName() { return name; } | |||
/* (non-Javadoc) | |||
* @see org.aspectj.weaver.Member#getParameterTypes() | |||
*/ | |||
public UnresolvedType getType() { | |||
return returnType; | |||
} | |||
public String getName() { | |||
return name; | |||
} | |||
public UnresolvedType[] getParameterTypes() { return parameterTypes; } | |||
/* (non-Javadoc) | |||
* @see org.aspectj.weaver.Member#getSignature() | |||
*/ | |||
public String getSignature() { return signature; } | |||
public int getArity() { return parameterTypes.length; } | |||
/* (non-Javadoc) | |||
* @see org.aspectj.weaver.Member#getParameterSignature() | |||
*/ | |||
public String getParameterSignature() { | |||
if (paramSignature != null) return paramSignature; | |||
StringBuffer sb = new StringBuffer(); | |||
@@ -535,9 +412,6 @@ public class MemberImpl implements Comparable, AnnotatedElement,Member { | |||
return resolved.getModifiers(); | |||
} | |||
/* (non-Javadoc) | |||
* @see org.aspectj.weaver.Member#getExceptions(org.aspectj.weaver.World) | |||
*/ | |||
public UnresolvedType[] getExceptions(World world) { | |||
ResolvedMember resolved = resolve(world); | |||
if (resolved == null) { | |||
@@ -546,57 +420,23 @@ public class MemberImpl implements Comparable, AnnotatedElement,Member { | |||
} | |||
return resolved.getExceptions(); | |||
} | |||
/* (non-Javadoc) | |||
* @see org.aspectj.weaver.Member#isProtected(org.aspectj.weaver.World) | |||
*/ | |||
public final boolean isProtected(World world) { | |||
return Modifier.isProtected(resolve(world).getModifiers()); | |||
} | |||
/* (non-Javadoc) | |||
* @see org.aspectj.weaver.Member#isStatic(org.aspectj.weaver.World) | |||
*/ | |||
public final boolean isStatic(World world) { | |||
return Modifier.isStatic(resolve(world).getModifiers()); | |||
} | |||
/* (non-Javadoc) | |||
* @see org.aspectj.weaver.Member#isStrict(org.aspectj.weaver.World) | |||
*/ | |||
public final boolean isStrict(World world) { | |||
return Modifier.isStrict(resolve(world).getModifiers()); | |||
} | |||
/* (non-Javadoc) | |||
* @see org.aspectj.weaver.Member#isStatic() | |||
*/ | |||
public final boolean isStatic() { | |||
return Modifier.isStatic(modifiers); | |||
} | |||
/* (non-Javadoc) | |||
* @see org.aspectj.weaver.Member#isInterface() | |||
*/ | |||
public final boolean isInterface() { | |||
return Modifier.isInterface(modifiers); // this is kinda weird | |||
return Modifier.isInterface(modifiers); | |||
} | |||
/* (non-Javadoc) | |||
* @see org.aspectj.weaver.Member#isPrivate() | |||
*/ | |||
public final boolean isPrivate() { | |||
return Modifier.isPrivate(modifiers); | |||
} | |||
/* (non-Javadoc) | |||
* @see org.aspectj.weaver.Member#canBeParameterized() | |||
*/ | |||
public boolean canBeParameterized() { | |||
return false; | |||
} | |||
/* (non-Javadoc) | |||
* @see org.aspectj.weaver.Member#getCallsiteModifiers() | |||
*/ | |||
public final int getCallsiteModifiers() { | |||
return modifiers & ~ Modifier.INTERFACE; | |||
} | |||
@@ -605,46 +445,19 @@ public class MemberImpl implements Comparable, AnnotatedElement,Member { | |||
return modifiers; | |||
} | |||
/* (non-Javadoc) | |||
* @see org.aspectj.weaver.Member#getExtractableName() | |||
*/ | |||
public final String getExtractableName() { | |||
if (name.equals("<init>")) return "init$"; | |||
else if (name.equals("<clinit>")) return "clinit$"; | |||
if (kind==CONSTRUCTOR/*name.equals("<init>")*/) return "init$"; | |||
else if (kind==STATIC_INITIALIZATION/*name.equals("<clinit>")*/) return "clinit$"; | |||
else return name; | |||
} | |||
/* (non-Javadoc) | |||
* @see org.aspectj.weaver.Member#hasAnnotation(org.aspectj.weaver.UnresolvedType) | |||
*/ | |||
public boolean hasAnnotation(UnresolvedType ofType) { | |||
throw new UnsupportedOperationException("You should resolve this member and call hasAnnotation() on the result..."); | |||
} | |||
/* (non-Javadoc) | |||
* @see org.aspectj.weaver.AnnotatedElement#getAnnotationTypes() | |||
*/ | |||
/* (non-Javadoc) | |||
* @see org.aspectj.weaver.Member#getAnnotationTypes() | |||
*/ | |||
public ResolvedType[] getAnnotationTypes() { | |||
throw new UnsupportedOperationException("You should resolve this member and call hasAnnotation() on the result..."); | |||
} | |||
/* (non-Javadoc) | |||
* @see org.aspectj.weaver.Member#getAnnotations() | |||
*/ | |||
public AnnotationX[] getAnnotations() { | |||
throw new UnsupportedOperationException("You should resolve this member '"+this+"' and call getAnnotations() on the result..."); | |||
} | |||
// public AnnotationX[] getAnnotations() { | |||
// throw new UnsupportedOperationException("You should resolve this member '"+this+"' and call getAnnotations() on the result..."); | |||
// } | |||
// ---- fields 'n' stuff | |||
/* (non-Javadoc) | |||
* @see org.aspectj.weaver.Member#getDeclaringTypes(org.aspectj.weaver.World) | |||
*/ | |||
public Collection/*ResolvedType*/ getDeclaringTypes(World world) { | |||
ResolvedType myType = getDeclaringType().resolve(world); | |||
Collection ret = new HashSet(); | |||
@@ -701,9 +514,9 @@ public class MemberImpl implements Comparable, AnnotatedElement,Member { | |||
* @see org.aspectj.weaver.Member#getSignatureMakerName() | |||
*/ | |||
public String getSignatureMakerName() { | |||
if (getName().equals("<clinit>")) return "makeInitializerSig"; | |||
// if (getName().equals("<clinit>")) return "makeInitializerSig"; | |||
Kind kind = getKind(); | |||
MemberKind kind = getKind(); | |||
if (kind == METHOD) { | |||
return "makeMethodSig"; | |||
} else if (kind == CONSTRUCTOR) { | |||
@@ -732,8 +545,8 @@ public class MemberImpl implements Comparable, AnnotatedElement,Member { | |||
* @see org.aspectj.weaver.Member#getSignatureType() | |||
*/ | |||
public String getSignatureType() { | |||
Kind kind = getKind(); | |||
if (getName().equals("<clinit>")) return "org.aspectj.lang.reflect.InitializerSignature"; | |||
MemberKind kind = getKind(); | |||
// if (getName().equals("<clinit>")) return "org.aspectj.lang.reflect.InitializerSignature"; | |||
if (kind == METHOD) { | |||
return "org.aspectj.lang.reflect.MethodSignature"; | |||
@@ -761,8 +574,8 @@ public class MemberImpl implements Comparable, AnnotatedElement,Member { | |||
*/ | |||
public String getSignatureString(World world) { | |||
if (getName().equals("<clinit>")) return getStaticInitializationSignatureString(world); | |||
Kind kind = getKind(); | |||
// | |||
MemberKind kind = getKind(); | |||
if (kind == METHOD) { | |||
return getMethodSignatureString(world); | |||
} else if (kind == CONSTRUCTOR) { | |||
@@ -902,7 +715,7 @@ public class MemberImpl implements Comparable, AnnotatedElement,Member { | |||
} | |||
protected String makeString(int i) { | |||
return Integer.toString(i, 16); //??? expensive | |||
return Integer.toString(i, 16); | |||
} | |||
@@ -982,9 +795,5 @@ public class MemberImpl implements Comparable, AnnotatedElement,Member { | |||
} | |||
} | |||
public Member slimline() { | |||
return this; | |||
} | |||
} | |||
@@ -0,0 +1,37 @@ | |||
/* ******************************************************************* | |||
* 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.io.DataInputStream; | |||
import java.io.IOException; | |||
import org.aspectj.util.TypeSafeEnum; | |||
public class MemberKind extends TypeSafeEnum { | |||
public MemberKind(String name, int key) { super(name, key); } | |||
public static MemberKind read(DataInputStream s) throws IOException { | |||
int key = s.readByte(); | |||
switch(key) { | |||
case 1: return Member.METHOD; | |||
case 2: return Member.FIELD; | |||
case 3: return Member.CONSTRUCTOR; | |||
case 4: return Member.STATIC_INITIALIZATION; | |||
case 5: return Member.POINTCUT; | |||
case 6: return Member.ADVICE; | |||
case 7: return Member.HANDLER; | |||
case 8: return Member.MONITORENTER; | |||
case 9: return Member.MONITOREXIT; | |||
} | |||
throw new BCException("weird kind " + key); | |||
} | |||
} |
@@ -104,7 +104,7 @@ public class NameMangler { | |||
} | |||
public static String itdAtDeclareParentsField(UnresolvedType aspectType, UnresolvedType itdType) { | |||
return makeName(aspectType.getNameAsIdentifier(), itdType.getNameAsIdentifier()); | |||
return makeName("instance",aspectType.getNameAsIdentifier(), itdType.getNameAsIdentifier()); | |||
} | |||
public static String privilegedAccessMethodForMethod(String name, UnresolvedType objectType, UnresolvedType aspectType) { | |||
@@ -358,15 +358,14 @@ public class NameMangler { | |||
return enclosingType.getName() + "$AjcClosure" + index; | |||
} | |||
public static String aroundCallbackMethodName( | |||
Member shadowSig, | |||
LazyClassGen enclosingType) | |||
{ | |||
String ret = | |||
shadowSig.getExtractableName() | |||
+ "_aroundBody" | |||
+ enclosingType.getNewGeneratedNameTag(); | |||
return ret; | |||
public static String aroundCallbackMethodName(Member shadowSig, LazyClassGen enclosingType) { | |||
StringBuffer ret = new StringBuffer(); | |||
ret.append(shadowSig.getExtractableName()).append("_aroundBody").append(enclosingType.getNewGeneratedNameTag()); | |||
// String ret = | |||
// shadowSig.getExtractableName() | |||
// + "_aroundBody" | |||
// + enclosingType.getNewGeneratedNameTag(); | |||
return ret.toString(); | |||
} | |||
public static String proceedMethodName(String adviceMethodName) { |
@@ -16,6 +16,7 @@ package org.aspectj.weaver; | |||
import java.io.DataOutputStream; | |||
import java.io.IOException; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.Set; | |||
import org.aspectj.bridge.ISourceLocation; | |||
@@ -94,6 +95,14 @@ public class NewFieldTypeMunger extends ResolvedTypeMunger { | |||
return nftm; | |||
} | |||
public ResolvedTypeMunger parameterizeWith(Map m, World w) { | |||
ResolvedMember parameterizedSignature = getSignature().parameterizedWith(m,w); | |||
NewFieldTypeMunger nftm = new NewFieldTypeMunger(parameterizedSignature,getSuperMethodsCalled(),typeVariableAliases); | |||
nftm.setDeclaredSignature(getSignature()); | |||
nftm.setSourceLocation(getSourceLocation()); | |||
return nftm; | |||
} | |||
public boolean equals(Object other) { | |||
if (! (other instanceof NewFieldTypeMunger)) return false; | |||
NewFieldTypeMunger o = (NewFieldTypeMunger) other; |
@@ -16,11 +16,14 @@ package org.aspectj.weaver; | |||
import java.io.DataOutputStream; | |||
import java.io.IOException; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.Set; | |||
import org.aspectj.bridge.ISourceLocation; | |||
public class NewMethodTypeMunger extends ResolvedTypeMunger { | |||
public NewMethodTypeMunger( | |||
ResolvedMember signature, | |||
Set superMethodsCalled, | |||
@@ -128,5 +131,13 @@ public class NewMethodTypeMunger extends ResolvedTypeMunger { | |||
result = 37*result + ((typeVariableAliases == null) ? 0 : typeVariableAliases.hashCode()); | |||
return result; | |||
} | |||
public ResolvedTypeMunger parameterizeWith(Map m, World w) { | |||
ResolvedMember parameterizedSignature = getSignature().parameterizedWith(m,w); | |||
NewMethodTypeMunger nmtm = new NewMethodTypeMunger(parameterizedSignature,getSuperMethodsCalled(),typeVariableAliases); | |||
nmtm.setDeclaredSignature(getSignature()); | |||
nmtm.setSourceLocation(getSourceLocation()); | |||
return nmtm; | |||
} | |||
} |
@@ -65,6 +65,7 @@ public class ReferenceType extends ResolvedType { | |||
ResolvedMember[] parameterizedPointcuts = null; | |||
ResolvedType[] parameterizedInterfaces = null; | |||
Collection parameterizedDeclares = null; | |||
Collection parameterizedTypeMungers = null; | |||
//??? should set delegate before any use | |||
public ReferenceType(String signature, World world) { | |||
@@ -127,11 +128,11 @@ public class ReferenceType extends ResolvedType { | |||
typeKind=TypeKind.GENERIC; | |||
} | |||
public final boolean isClass() { | |||
public boolean isClass() { | |||
return delegate.isClass(); | |||
} | |||
public final boolean isGenericType() { | |||
public boolean isGenericType() { | |||
return !isParameterizedType() && !isRawType() && delegate.isGeneric(); | |||
} | |||
@@ -147,6 +148,7 @@ public class ReferenceType extends ResolvedType { | |||
public void addAnnotation(AnnotationX annotationX) { | |||
delegate.addAnnotation(annotationX); | |||
} | |||
public boolean hasAnnotation(UnresolvedType ofType) { | |||
return delegate.hasAnnotation(ofType); | |||
} | |||
@@ -200,7 +202,7 @@ public class ReferenceType extends ResolvedType { | |||
} | |||
// true iff the statement "this = (ThisType) other" would compile | |||
public final boolean isCoerceableFrom(ResolvedType o) { | |||
public boolean isCoerceableFrom(ResolvedType o) { | |||
ResolvedType other = o.resolve(world); | |||
if (this.isAssignableFrom(other) || other.isAssignableFrom(this)) { | |||
@@ -272,12 +274,12 @@ public class ReferenceType extends ResolvedType { | |||
return false; | |||
} | |||
public final boolean isAssignableFrom(ResolvedType other) { | |||
public boolean isAssignableFrom(ResolvedType other) { | |||
return isAssignableFrom(other,false); | |||
} | |||
// true iff the statement "this = other" would compile. | |||
public final boolean isAssignableFrom(ResolvedType other,boolean allowMissing) { | |||
public boolean isAssignableFrom(ResolvedType other,boolean allowMissing) { | |||
if (other.isPrimitiveType()) { | |||
if (!world.isInJava5Mode()) return false; | |||
if (ResolvedType.validBoxing.contains(this.getSignature()+other.getSignature())) return true; | |||
@@ -596,7 +598,28 @@ public class ReferenceType extends ResolvedType { | |||
return declares; | |||
} | |||
protected Collection getTypeMungers() { return delegate.getTypeMungers(); } | |||
protected Collection getTypeMungers() { | |||
return delegate.getTypeMungers(); | |||
} | |||
// GENERICITDFIX | |||
//// Map parameterizationMap = getAjMemberParameterizationMap(); | |||
// | |||
// // if (parameterizedTypeMungers != null) return parameterizedTypeMungers; | |||
// Collection ret = null; | |||
// if (ajMembersNeedParameterization()) { | |||
// Collection genericDeclares = delegate.getTypeMungers(); | |||
// parameterizedTypeMungers = new ArrayList(); | |||
// Map parameterizationMap = getAjMemberParameterizationMap(); | |||
// for (Iterator iter = genericDeclares.iterator(); iter.hasNext();) { | |||
// ConcreteTypeMunger munger = (ConcreteTypeMunger)iter.next(); | |||
// parameterizedTypeMungers.add(munger.parameterizeWith(parameterizationMap,world)); | |||
// } | |||
// ret = parameterizedTypeMungers; | |||
// } else { | |||
// ret = delegate.getTypeMungers(); | |||
// } | |||
// return ret; | |||
// } | |||
protected Collection getPrivilegedAccesses() { return delegate.getPrivilegedAccesses(); } | |||
@@ -17,8 +17,8 @@ import java.util.Collection; | |||
import org.aspectj.weaver.patterns.PerClause; | |||
/** | |||
* Abstraction over a type. Abstract implementation provided by | |||
* AbstractReferenceTypeDelegate. | |||
* Abstraction over a type - a reference type is Object and a descendant of Object, other types (int/etc) are | |||
* considered primitive types. Abstract implementation provided by AbstractReferenceTypeDelegate. | |||
*/ | |||
public interface ReferenceTypeDelegate { | |||
@@ -16,6 +16,7 @@ package org.aspectj.weaver; | |||
import java.io.DataOutputStream; | |||
import java.io.IOException; | |||
import java.util.List; | |||
import java.util.Map; | |||
import org.aspectj.bridge.ISourceLocation; | |||
@@ -33,6 +34,19 @@ public interface ResolvedMember extends Member, AnnotatedElement, TypeVariableDe | |||
public ShadowMunger getAssociatedShadowMunger(); | |||
public AnnotationX[][] getParameterAnnotations(); | |||
public ResolvedType[][] getParameterAnnotationTypes(); | |||
public String getAnnotationDefaultValue(); | |||
public AnnotationX[] getAnnotations(); | |||
/** | |||
* Returns true iff the member is generic (NOT parameterized) | |||
* For example, a method declared in a generic type | |||
*/ | |||
public boolean canBeParameterized(); | |||
// ??? true or false? | |||
public boolean isAjSynthetic(); | |||
@@ -154,9 +168,11 @@ public interface ResolvedMember extends Member, AnnotatedElement, TypeVariableDe | |||
public boolean matches(ResolvedMember aCandidateMatch); | |||
public void resetName(String newName); | |||
public void resetKind(Kind newKind); | |||
public void resetKind(MemberKind newKind); | |||
public void resetModifiers(int newModifiers); | |||
public void resetReturnTypeToObjectArray(); | |||
public void evictWeavingState(); | |||
public ResolvedMember parameterizedWith(Map m, World w); | |||
} |
@@ -40,7 +40,7 @@ public class ResolvedMemberImpl extends MemberImpl implements IHasPosition, Anno | |||
public static boolean showParameterNames = true; | |||
private String[] parameterNames = null; | |||
protected UnresolvedType[] checkedExceptions = UnresolvedType.NONE; | |||
protected UnresolvedType[] checkedExceptions = UnresolvedType.NONE; // OPTIMIZE unpack on demand | |||
// private boolean isAjSynthetic = false; | |||
protected int start, end; | |||
protected ISourceContext sourceContext = null; | |||
@@ -67,6 +67,8 @@ public class ResolvedMemberImpl extends MemberImpl implements IHasPosition, Anno | |||
// protected ResolvedMember backingGenericMember = null; | |||
protected Set annotationTypes = null; | |||
protected ResolvedType[][] parameterAnnotationTypes = null; | |||
// Some members are 'created' to represent other things (for example ITDs). These | |||
// members have their annotations stored elsewhere, and this flag indicates that is | |||
// the case. It is up to the caller to work out where that is! | |||
@@ -89,7 +91,7 @@ public class ResolvedMemberImpl extends MemberImpl implements IHasPosition, Anno | |||
//XXX deprecate this in favor of the constructor below | |||
public ResolvedMemberImpl( | |||
Kind kind, | |||
MemberKind kind, | |||
UnresolvedType declaringType, | |||
int modifiers, | |||
UnresolvedType returnType, | |||
@@ -102,7 +104,7 @@ public class ResolvedMemberImpl extends MemberImpl implements IHasPosition, Anno | |||
public ResolvedMemberImpl( | |||
Kind kind, | |||
MemberKind kind, | |||
UnresolvedType declaringType, | |||
int modifiers, | |||
UnresolvedType returnType, | |||
@@ -115,7 +117,7 @@ public class ResolvedMemberImpl extends MemberImpl implements IHasPosition, Anno | |||
} | |||
public ResolvedMemberImpl( | |||
Kind kind, | |||
MemberKind kind, | |||
UnresolvedType declaringType, | |||
int modifiers, | |||
UnresolvedType returnType, | |||
@@ -133,7 +135,7 @@ public class ResolvedMemberImpl extends MemberImpl implements IHasPosition, Anno | |||
} | |||
public ResolvedMemberImpl( | |||
Kind kind, | |||
MemberKind kind, | |||
UnresolvedType declaringType, | |||
int modifiers, | |||
String name, | |||
@@ -339,11 +341,16 @@ public class ResolvedMemberImpl extends MemberImpl implements IHasPosition, Anno | |||
if (annotationTypes == null) return null; | |||
return (ResolvedType[])annotationTypes.toArray(new ResolvedType[]{}); | |||
} | |||
public AnnotationX getAnnotationOfType(UnresolvedType ofType) { | |||
throw new UnsupportedOperationException("You should resolve this member and call getAnnotationOfType() on the result..."); | |||
} | |||
public AnnotationX[] getAnnotations() { | |||
if ((bits&HAS_BACKING_GENERIC_MEMBER)!=0 && metaInfo.backingGenericMember!=null) return metaInfo.backingGenericMember.getAnnotations(); | |||
// if (backingGenericMember != null) return backingGenericMember.getAnnotations(); | |||
return super.getAnnotations(); | |||
// return super.getAnnotations(); | |||
throw new IllegalStateException("Unable to answer getAnnotations() for "+this.toString()); | |||
} | |||
public void setAnnotationTypes(UnresolvedType[] annotationtypes) { | |||
@@ -354,6 +361,16 @@ public class ResolvedMemberImpl extends MemberImpl implements IHasPosition, Anno | |||
} | |||
} | |||
public ResolvedType[][] getParameterAnnotationTypes() { | |||
if (parameterAnnotationTypes == null) return null; | |||
return parameterAnnotationTypes; | |||
} | |||
public AnnotationX[][] getParameterAnnotations() { | |||
if (hasBackingGenericMember()) return getBackingGenericMember().getParameterAnnotations(); | |||
throw new IllegalStateException("Only a resolvedmember with backing generic member can answer this. Member="+toString()); | |||
} | |||
public void addAnnotation(AnnotationX annotation) { | |||
// FIXME asc only allows for annotation types, not instances - should it? | |||
if (annotationTypes == null) annotationTypes = new HashSet(); | |||
@@ -441,7 +458,7 @@ public class ResolvedMemberImpl extends MemberImpl implements IHasPosition, Anno | |||
public static ResolvedMemberImpl readResolvedMember(VersionedDataInputStream s, ISourceContext sourceContext) throws IOException { | |||
ResolvedMemberImpl m = new ResolvedMemberImpl(Kind.read(s), UnresolvedType.read(s), s.readInt(), | |||
ResolvedMemberImpl m = new ResolvedMemberImpl(MemberKind.read(s), UnresolvedType.read(s), s.readInt(), | |||
s.readUTF(), s.readUTF()); | |||
m.checkedExceptions = UnresolvedType.readArray(s); | |||
@@ -704,6 +721,68 @@ public class ResolvedMemberImpl extends MemberImpl implements IHasPosition, Anno | |||
return ret; | |||
} | |||
/** | |||
* Replace occurrences of type variables in the signature with values contained in the map. The map is of the form A=String,B=Integer and | |||
* so a signature List<A> Foo.m(B i) {} would become List<String> Foo.m(Integer i) {} | |||
*/ | |||
public ResolvedMember parameterizedWith(Map m, World w) { | |||
// if (//isParameterized && <-- might need this bit... | |||
// !getDeclaringType().isGenericType()) { | |||
// throw new IllegalStateException("Can't ask to parameterize a member of non-generic type: "+getDeclaringType()+" kind("+getDeclaringType().typeKind+")"); | |||
// } | |||
declaringType = declaringType.resolve(w); | |||
if (declaringType.isRawType()) declaringType = ((ResolvedType)declaringType).getGenericType(); | |||
TypeVariable[] typeVariables = getDeclaringType().getTypeVariables(); | |||
// if (isParameterized && (typeVariables.length != typeParameters.length)) { | |||
// throw new IllegalStateException("Wrong number of type parameters supplied"); | |||
// } | |||
// Map typeMap = new HashMap(); | |||
// boolean typeParametersSupplied = typeParameters!=null && typeParameters.length>0; | |||
// if (typeVariables!=null) { | |||
// // If no 'replacements' were supplied in the typeParameters array then collapse | |||
// // type variables to their first bound. | |||
// for (int i = 0; i < typeVariables.length; i++) { | |||
// UnresolvedType ut = (!typeParametersSupplied?typeVariables[i].getFirstBound():typeParameters[i]); | |||
// typeMap.put(typeVariables[i].getName(),ut); | |||
// } | |||
// } | |||
// // For ITDs on generic types that use type variables from the target type, the aliases | |||
// // record the alternative names used throughout the ITD expression that must map to | |||
// // the same value as the type variables real name. | |||
// if (aliases!=null) { | |||
// int posn = 0; | |||
// for (Iterator iter = aliases.iterator(); iter.hasNext();) { | |||
// String typeVariableAlias = (String) iter.next(); | |||
// typeMap.put(typeVariableAlias,(!typeParametersSupplied?typeVariables[posn].getFirstBound():typeParameters[posn])); | |||
// posn++; | |||
// } | |||
// } | |||
UnresolvedType parameterizedReturnType = parameterize(getGenericReturnType(),m,true,w); | |||
UnresolvedType[] parameterizedParameterTypes = new UnresolvedType[getGenericParameterTypes().length]; | |||
UnresolvedType[] genericParameterTypes = getGenericParameterTypes(); | |||
for (int i = 0; i < parameterizedParameterTypes.length; i++) { | |||
parameterizedParameterTypes[i] = | |||
parameterize(genericParameterTypes[i], m,true,w); | |||
} | |||
ResolvedMemberImpl ret = new ResolvedMemberImpl( | |||
getKind(), | |||
declaringType, | |||
getModifiers(), | |||
parameterizedReturnType, | |||
getName(), | |||
parameterizedParameterTypes, | |||
getExceptions(), | |||
this | |||
); | |||
ret.setTypeVariables(getTypeVariables()); | |||
ret.setSourceContext(getSourceContext()); | |||
ret.setPosition(getStart(),getEnd()); | |||
ret.setParameterNames(getParameterNames()); | |||
return ret; | |||
} | |||
public void setTypeVariables(TypeVariable[] tvars) { | |||
typeVariables = tvars; | |||
} | |||
@@ -713,6 +792,10 @@ public class ResolvedMemberImpl extends MemberImpl implements IHasPosition, Anno | |||
} | |||
protected UnresolvedType parameterize(UnresolvedType aType, Map typeVariableMap, boolean inParameterizedType) { | |||
return parameterize(aType,typeVariableMap,inParameterizedType,null); | |||
} | |||
protected UnresolvedType parameterize(UnresolvedType aType, Map typeVariableMap, boolean inParameterizedType,World w) { | |||
if (aType instanceof TypeVariableReference) { | |||
String variableName = ((TypeVariableReference)aType).getTypeVariable().getName(); | |||
if (!typeVariableMap.containsKey(variableName)) { | |||
@@ -721,7 +804,15 @@ public class ResolvedMemberImpl extends MemberImpl implements IHasPosition, Anno | |||
return (UnresolvedType) typeVariableMap.get(variableName); | |||
} else if (aType.isParameterizedType()) { | |||
if (inParameterizedType) { | |||
if (aType instanceof UnresolvedType) aType= aType.resolve(((ResolvedType)getDeclaringType()).getWorld()); | |||
// if (!(getDeclaringType() instanceof ResolvedType)) { | |||
// int stop = 1; | |||
// } | |||
if (aType instanceof UnresolvedType) { | |||
if (w!=null) aType = aType.resolve(w); | |||
else { | |||
aType= aType.resolve(((ResolvedType)getDeclaringType()).getWorld()); | |||
} | |||
} | |||
return aType.parameterize(typeVariableMap); | |||
} else { | |||
return aType.getRawType(); | |||
@@ -806,7 +897,7 @@ public class ResolvedMemberImpl extends MemberImpl implements IHasPosition, Anno | |||
* using this method - this is safe. | |||
*/ | |||
public void resetName(String newName) {this.name = newName;} | |||
public void resetKind(Kind newKind) {this.kind=newKind; } | |||
public void resetKind(MemberKind newKind) {this.kind=newKind; } | |||
public void resetModifiers(int newModifiers) {this.modifiers=newModifiers;} | |||
public void resetReturnTypeToObjectArray() { | |||
@@ -854,7 +945,7 @@ public class ResolvedMemberImpl extends MemberImpl implements IHasPosition, Anno | |||
StringBuffer sig = new StringBuffer(); | |||
UnresolvedType[] myParameterTypes = getGenericParameterTypes(); | |||
for (int i = 0; i < myParameterTypes.length; i++) { | |||
appendSigWithTypeVarBoundsRemoved(myParameterTypes[i], sig); | |||
appendSigWithTypeVarBoundsRemoved(myParameterTypes[i], sig, new HashSet()); | |||
} | |||
myParameterSignatureWithBoundsRemoved = sig.toString(); | |||
return myParameterSignatureWithBoundsRemoved; | |||
@@ -878,14 +969,21 @@ public class ResolvedMemberImpl extends MemberImpl implements IHasPosition, Anno | |||
// does NOT produce a meaningful java signature, but does give a unique string suitable for | |||
// comparison. | |||
private void appendSigWithTypeVarBoundsRemoved(UnresolvedType aType, StringBuffer toBuffer) { | |||
public static void appendSigWithTypeVarBoundsRemoved(UnresolvedType aType, StringBuffer toBuffer, Set alreadyUsedTypeVars) { | |||
if (aType.isTypeVariableReference()) { | |||
toBuffer.append("T;"); | |||
// pr204505 | |||
if (alreadyUsedTypeVars.contains(aType)) { | |||
toBuffer.append("..."); | |||
} else { | |||
alreadyUsedTypeVars.add(aType); | |||
appendSigWithTypeVarBoundsRemoved(aType.getUpperBound(), toBuffer, alreadyUsedTypeVars); | |||
} | |||
// toBuffer.append("T;"); | |||
} else if (aType.isParameterizedType()) { | |||
toBuffer.append(aType.getRawType().getSignature()); | |||
toBuffer.append("<"); | |||
for (int i = 0; i < aType.getTypeParameters().length; i++) { | |||
appendSigWithTypeVarBoundsRemoved(aType.getTypeParameters()[i], toBuffer); | |||
appendSigWithTypeVarBoundsRemoved(aType.getTypeParameters()[i], toBuffer, alreadyUsedTypeVars); | |||
} | |||
toBuffer.append(">;"); | |||
} else { | |||
@@ -982,5 +1080,9 @@ public class ResolvedMemberImpl extends MemberImpl implements IHasPosition, Anno | |||
} | |||
public void evictWeavingState() { } | |||
public String getAnnotationDefaultValue() { | |||
throw new UnsupportedOperationException("You should resolve this member and call getAnnotationDefaultValue() on the result..."); | |||
} | |||
} | |||
@@ -39,6 +39,9 @@ public abstract class ResolvedType extends UnresolvedType implements AnnotatedEl | |||
public static final ResolvedType[] EMPTY_RESOLVED_TYPE_ARRAY = new ResolvedType[0]; | |||
public static final String PARAMETERIZED_TYPE_IDENTIFIER = "P"; | |||
// Set during a type pattern match call - this currently used to hold the annotations | |||
// that may be attached to a type when it used as a parameter | |||
public ResolvedType[] temporaryAnnotationTypes; | |||
private ResolvedType[] resolvedTypeParams; | |||
private String binaryPath; | |||
@@ -113,6 +116,10 @@ public abstract class ResolvedType extends UnresolvedType implements AnnotatedEl | |||
return EMPTY_RESOLVED_TYPE_ARRAY; | |||
} | |||
public AnnotationX getAnnotationOfType(UnresolvedType ofType) { | |||
return null; | |||
} | |||
public final UnresolvedType getSuperclass(World world) { | |||
return getSuperclass(); | |||
} | |||
@@ -286,7 +293,9 @@ public abstract class ResolvedType extends UnresolvedType implements AnnotatedEl | |||
boolean shouldSkip = false; | |||
for (int j = 0; j < rtx.interTypeMungers.size(); j++) { | |||
ConcreteTypeMunger munger = (ConcreteTypeMunger) rtx.interTypeMungers.get(j); | |||
if (munger.getMunger()!=null && munger.getMunger().getKind() == ResolvedTypeMunger.Parent) { | |||
if (munger.getMunger()!=null && munger.getMunger().getKind() == ResolvedTypeMunger.Parent | |||
&& ((NewParentTypeMunger)munger.getMunger()).getNewParent().equals(iface) // pr171953 | |||
) { | |||
shouldSkip = true; | |||
break; | |||
} | |||
@@ -506,7 +515,9 @@ public abstract class ResolvedType extends UnresolvedType implements AnnotatedEl | |||
crosscuttingMembers = new CrosscuttingMembers(this,shouldConcretizeIfNeeded); | |||
crosscuttingMembers.setPerClause(getPerClause()); | |||
crosscuttingMembers.addShadowMungers(collectShadowMungers()); | |||
crosscuttingMembers.addTypeMungers(getTypeMungers()); | |||
// GENERICITDFIX | |||
// crosscuttingMembers.addTypeMungers(collectTypeMungers()); | |||
crosscuttingMembers.addTypeMungers(getTypeMungers()); | |||
//FIXME AV - skip but needed ?? or ?? crosscuttingMembers.addLateTypeMungers(getLateTypeMungers()); | |||
crosscuttingMembers.addDeclares(collectDeclares(!this.doesNotExposeShadowMungers())); | |||
crosscuttingMembers.addPrivilegedAccesses(getPrivilegedAccesses()); | |||
@@ -516,6 +527,41 @@ public abstract class ResolvedType extends UnresolvedType implements AnnotatedEl | |||
return crosscuttingMembers; | |||
} | |||
public final Collection collectTypeMungers() { | |||
if (! this.isAspect() ) return Collections.EMPTY_LIST; | |||
ArrayList ret = new ArrayList(); | |||
//if (this.isAbstract()) { | |||
// for (Iterator i = getDeclares().iterator(); i.hasNext();) { | |||
// Declare dec = (Declare) i.next(); | |||
// if (!dec.isAdviceLike()) ret.add(dec); | |||
// } | |||
// | |||
// if (!includeAdviceLike) return ret; | |||
if (!this.isAbstract()) { | |||
final Iterators.Filter dupFilter = Iterators.dupFilter(); | |||
Iterators.Getter typeGetter = new Iterators.Getter() { | |||
public Iterator get(Object o) { | |||
return | |||
dupFilter.filter( | |||
((ResolvedType)o).getDirectSupertypes()); | |||
} | |||
}; | |||
Iterator typeIterator = Iterators.recur(this, typeGetter); | |||
while (typeIterator.hasNext()) { | |||
ResolvedType ty = (ResolvedType) typeIterator.next(); | |||
for (Iterator i = ty.getTypeMungers().iterator(); i.hasNext();) { | |||
ConcreteTypeMunger dec = (ConcreteTypeMunger) i.next(); | |||
ret.add(dec); | |||
} | |||
} | |||
} | |||
return ret; | |||
} | |||
public final Collection collectDeclares(boolean includeAdviceLike) { | |||
if (! this.isAspect() ) return Collections.EMPTY_LIST; | |||
@@ -802,7 +848,7 @@ public abstract class ResolvedType extends UnresolvedType implements AnnotatedEl | |||
// ---- types | |||
public static ResolvedType makeArray(ResolvedType type, int dim) { | |||
if (dim == 0) return type; | |||
ResolvedType array = new Array("[" + type.getSignature(),"["+type.getErasureSignature(),type.getWorld(),type); | |||
ResolvedType array = new ArrayReferenceType("[" + type.getSignature(),"["+type.getErasureSignature(),type.getWorld(),type); | |||
return makeArray(array,dim-1); | |||
} | |||
@@ -1159,6 +1205,9 @@ public abstract class ResolvedType extends UnresolvedType implements AnnotatedEl | |||
protected void collectInterTypeMungers(List collector) { | |||
for (Iterator iter = getDirectSupertypes(); iter.hasNext();) { | |||
ResolvedType superType = (ResolvedType) iter.next(); | |||
if (superType == null) { | |||
throw new BCException("UnexpectedProblem: a supertype in the hierarchy for " + this.getName() + " is null"); | |||
} | |||
superType.collectInterTypeMungers(collector); | |||
} | |||
@@ -1478,6 +1527,22 @@ public abstract class ResolvedType extends UnresolvedType implements AnnotatedEl | |||
//??? returning too soon | |||
private boolean compareToExistingMembers(ConcreteTypeMunger munger, Iterator existingMembers) { | |||
ResolvedMember sig = munger.getSignature(); | |||
ResolvedType declaringAspectType = munger.getAspectType(); | |||
// if (declaringAspectType.isRawType()) declaringAspectType = declaringAspectType.getGenericType(); | |||
// if (declaringAspectType.isGenericType()) { | |||
// | |||
// ResolvedType genericOnType = getWorld().resolve(sig.getDeclaringType()).getGenericType(); | |||
// ConcreteTypeMunger ctm = munger.parameterizedFor(discoverActualOccurrenceOfTypeInHierarchy(genericOnType)); | |||
// sig = ctm.getSignature(); // possible sig change when type | |||
// } | |||
// if (munger.getMunger().hasTypeVariableAliases()) { | |||
// ResolvedType genericOnType = | |||
// getWorld().resolve(sig.getDeclaringType()).getGenericType(); | |||
// ConcreteTypeMunger ctm = | |||
// munger.parameterizedFor(discoverActualOccurrenceOfTypeInHierarchy(genericOnType)); | |||
// sig = ctm.getSignature(); // possible sig change when type parameters filled in | |||
// } | |||
while (existingMembers.hasNext()) { | |||
ResolvedMember existingMember = (ResolvedMember)existingMembers.next(); | |||
@@ -1506,12 +1571,34 @@ public abstract class ResolvedType extends UnresolvedType implements AnnotatedEl | |||
// FIXME this whole method seems very hokey - unaware of covariance/varargs/bridging - it | |||
// could do with a rewrite ! | |||
boolean sameReturnTypes = (existingMember.getReturnType().equals(sig.getReturnType())); | |||
if (sameReturnTypes) | |||
getWorld().getMessageHandler().handleMessage( | |||
MessageUtil.error(WeaverMessages.format(WeaverMessages.ITD_MEMBER_CONFLICT,munger.getAspectType().getName(), | |||
existingMember), | |||
munger.getSourceLocation()) | |||
); | |||
if (sameReturnTypes) { | |||
// pr206732 - if the existingMember is due to a previous application of this same ITD (which can | |||
// happen if this is a binary type being brought in from the aspectpath). The 'better' fix is | |||
// to recognize it is from the aspectpath at a higher level and dont do this, but that is rather | |||
// more work. | |||
boolean isDuplicateOfPreviousITD = false; | |||
ResolvedType declaringRt = existingMember.getDeclaringType().resolve(world); | |||
WeaverStateInfo wsi = declaringRt.getWeaverState(); | |||
if (wsi!=null) { | |||
List mungersAffectingThisType = wsi.getTypeMungers(declaringRt); | |||
if (mungersAffectingThisType!=null) { | |||
for (Iterator iterator = mungersAffectingThisType.iterator(); iterator.hasNext() && !isDuplicateOfPreviousITD;) { | |||
ConcreteTypeMunger ctMunger = (ConcreteTypeMunger) iterator.next(); | |||
// relatively crude check - is the ITD for the same as the existingmember and does it come from the same aspect | |||
if (ctMunger.getSignature().equals(existingMember) && ctMunger.aspectType.equals(munger.getAspectType())) { | |||
isDuplicateOfPreviousITD=true; | |||
} | |||
} | |||
} | |||
} | |||
if (!isDuplicateOfPreviousITD) { | |||
getWorld().getMessageHandler().handleMessage( | |||
MessageUtil.error(WeaverMessages.format(WeaverMessages.ITD_MEMBER_CONFLICT,munger.getAspectType().getName(), | |||
existingMember), | |||
munger.getSourceLocation()) | |||
); | |||
} | |||
} | |||
} | |||
} else if (isDuplicateMemberWithinTargetType(existingMember,this,sig)) { | |||
getWorld().getMessageHandler().handleMessage( | |||
@@ -2042,7 +2129,7 @@ public abstract class ResolvedType extends UnresolvedType implements AnnotatedEl | |||
} | |||
for (int i = 0; i < typeParameters.length; i++) { | |||
UnresolvedType aType = (ResolvedType)typeParameters[i]; | |||
ResolvedType aType = (ResolvedType)typeParameters[i]; | |||
if (aType.isTypeVariableReference() && | |||
// assume the worst - if its definetly not a type declared one, it could be anything | |||
((TypeVariableReference)aType).getTypeVariable().getDeclaringElementKind()!=TypeVariable.TYPE) { |
@@ -26,6 +26,7 @@ import java.util.Collections; | |||
import java.util.HashSet; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.Set; | |||
import org.aspectj.bridge.ISourceLocation; | |||
@@ -68,6 +69,17 @@ public abstract class ResolvedTypeMunger { | |||
if (declaringType.isRawType()) throw new IllegalStateException("Use generic type, not raw type"); | |||
if (declaringType.isParameterizedType()) throw new IllegalStateException("Use generic type, not parameterized type"); | |||
} | |||
// boolean aChangeOccurred = false; | |||
// | |||
// UnresolvedType rt = signature.getReturnType(); | |||
// if (rt.isParameterizedType() || rt.isGenericType()) {rt = rt.getRawType();aChangeOccurred=true;} | |||
// UnresolvedType[] pt = signature.getParameterTypes(); | |||
// for (int i = 0; i < pt.length; i++) { | |||
// if (pt[i].isParameterizedType() || pt[i].isGenericType()) { pt[i] = pt[i].getRawType();aChangeOccurred=true;} | |||
// } | |||
// if (aChangeOccurred) { | |||
// this.signature = new ResolvedMemberImpl(signature.getKind(),signature.getDeclaringType(),signature.getModifiers(),rt,signature.getName(),pt,signature.getExceptions()); | |||
// } | |||
} | |||
public void setSourceLocation(ISourceLocation isl) { | |||
@@ -424,5 +436,9 @@ public abstract class ResolvedTypeMunger { | |||
public boolean existsToSupportShadowMunging() { | |||
return false; | |||
} | |||
public ResolvedTypeMunger parameterizeWith(Map m, World w) { | |||
throw new BCException("Dont call parameterizeWith() on a type munger of this kind: "+this.getClass()); | |||
} | |||
} |
@@ -44,7 +44,7 @@ import org.aspectj.weaver.bcel.BcelAdvice; | |||
public abstract class Shadow { | |||
// every Shadow has a unique id, doesn't matter if it wraps... | |||
private static int nextShadowID = 100; // easier to spot than zero. | |||
private static int nextShadowID = 100; // easier to spot than zero. // OPTIMIZE is this a bug? static? | |||
private final Kind kind; | |||
private final Member signature; | |||
@@ -187,6 +187,18 @@ public abstract class Shadow { | |||
return getSignature() | |||
.getParameterTypes().length; | |||
} | |||
/** | |||
* Return name of the argument at position 'i' at this shadow. This does not | |||
* make sense for all shadows - but can be useful in the case of, for example, | |||
* method-execution. | |||
* @return null if it cannot be determined | |||
*/ | |||
public String getArgName(int i,World w) { | |||
String [] names = getSignature().getParameterNames(w); | |||
if (names==null || i>=names.length) return null; | |||
return names[i]; | |||
} | |||
public abstract UnresolvedType getEnclosingType(); | |||
@@ -732,7 +744,29 @@ public abstract class Shadow { | |||
} | |||
public String toResolvedString(World world) { | |||
return getKind() + "(" + world.resolve(getSignature()).toGenericString() + ")"; | |||
StringBuffer sb = new StringBuffer(); | |||
sb.append(getKind()); | |||
sb.append("("); | |||
Member m = getSignature(); | |||
if (m==null) { | |||
sb.append("<<missing signature>>"); | |||
} else { | |||
ResolvedMember rm = world.resolve(m); | |||
if (rm==null) { | |||
sb.append("<<unresolvableMember:").append(m).append(">>"); | |||
} else { | |||
String genString = rm.toGenericString(); | |||
if (genString==null) { | |||
sb.append("<<unableToGetGenericStringFor:").append(rm).append(">>"); | |||
} else { | |||
sb.append(genString); | |||
} | |||
} | |||
} | |||
sb.append(")"); | |||
return sb.toString(); | |||
// was: return getKind() + "(" + world.resolve(getSignature()).toGenericString() + ")"; | |||
} | |||
/** |
@@ -10,7 +10,6 @@ | |||
* PARC initial implementation | |||
* ******************************************************************/ | |||
package org.aspectj.weaver; | |||
import java.io.File; | |||
@@ -42,10 +41,9 @@ import org.aspectj.weaver.patterns.Pointcut; | |||
* which may modify state. | |||
* Then implement is called. | |||
*/ | |||
public abstract class ShadowMunger implements PartialOrder.PartialComparable, IHasPosition { | |||
protected Pointcut pointcut; | |||
protected Pointcut pointcut; | |||
// these three fields hold the source location of this munger | |||
protected int start, end; | |||
protected ISourceContext sourceContext; | |||
@@ -62,6 +60,7 @@ public abstract class ShadowMunger implements PartialOrder.PartialComparable, IH | |||
this.end = end; | |||
this.sourceContext = sourceContext; | |||
} | |||
public abstract ShadowMunger concretize(ResolvedType fromType, World world, PerClause clause); | |||
@@ -102,8 +102,8 @@ public class TypeFactory { | |||
// (see pr122458) It is possible for a parameterized type to have *no* type parameters visible in its signature. | |||
// This happens for an inner type of a parameterized type which simply inherits the type parameters | |||
// of its parent. In this case it is parameterized but theres no < in the signature. | |||
int startOfParams = signature.indexOf('<'); | |||
if (startOfParams==-1) { | |||
// Should be an inner type of a parameterized type - could assert there is a '$' in the signature.... | |||
String signatureErasure = "L" + signature.substring(1); | |||
@@ -123,7 +123,7 @@ public class TypeFactory { | |||
// the type parameters of interest are only those that apply to the 'last type' in the signature | |||
// if the signature is 'PMyInterface<String>$MyOtherType;' then there are none... | |||
String lastType = null; | |||
int nestedTypePosition = signature.indexOf("$"); | |||
int nestedTypePosition = signature.indexOf("$", endOfParams); // don't look for $ INSIDE the parameters | |||
if (nestedTypePosition!=-1) lastType = signature.substring(nestedTypePosition+1); | |||
else lastType = new String(signature); | |||
startOfParams = lastType.indexOf("<"); | |||
@@ -132,7 +132,6 @@ public class TypeFactory { | |||
if (startOfParams!=-1) { | |||
typeParams = createTypeParams(lastType.substring(startOfParams +1, endOfParams)); | |||
} | |||
return new UnresolvedType(signature,signatureErasure,typeParams); | |||
} | |||
// can't replace above with convertSigToType - leads to stackoverflow |
@@ -70,7 +70,7 @@ public class TypeVariableReferenceType extends BoundedReferenceType implements T | |||
public UnresolvedType parameterize(Map typeBindings) { | |||
UnresolvedType ut = (UnresolvedType) typeBindings.get(getName()); | |||
if (ut!=null) return ut; | |||
if (ut!=null) return world.resolve(ut); | |||
return this; | |||
} | |||
@@ -26,7 +26,7 @@ import org.aspectj.weaver.tools.Traceable; | |||
/** | |||
* A UnresolvedType represents a type to the weaver. It has a basic signature that knows | |||
* nothing about type variables, type parameters, etc.. TypeXs are resolved in some World | |||
* nothing about type variables, type parameters, etc.. UnresolvedTypes are resolved in some World | |||
* (a repository of types). When a UnresolvedType is resolved it turns into a | |||
* ResolvedType which may be a primitive type, an array type or a ReferenceType. | |||
* ReferenceTypes may refer to simple, generic, parameterized or type-variable | |||
@@ -121,8 +121,8 @@ public class UnresolvedType implements Traceable, TypeVariableDeclaringElement { | |||
// this doesn't belong here and will get moved to ResolvedType later in the refactoring | |||
public static final String MISSING_NAME = "@missing@"; | |||
// OPTIMIZE I dont think you can ask something unresolved what kind of type it is, how can it always know? Push down into resolvedtype | |||
// that will force references to resolvedtypes to be correct rather than relying on unresolvedtypes to answer questions | |||
protected TypeKind typeKind = TypeKind.SIMPLE; // what kind of type am I? | |||
/** | |||
@@ -217,6 +217,7 @@ public class UnresolvedType implements Traceable, TypeVariableDeclaringElement { | |||
* that are type variable references are replaced by their matching type variable | |||
* binding. | |||
*/ | |||
// OPTIMIZE methods like this just allow callers to be lazy and not ensure they are working with the right (resolved) subtype | |||
public UnresolvedType parameterize(Map typeBindings) { | |||
throw new UnsupportedOperationException("unable to parameterize unresolved type: " + signature); | |||
} | |||
@@ -308,6 +309,7 @@ public class UnresolvedType implements Traceable, TypeVariableDeclaringElement { | |||
* @param name the java language type name in question. | |||
* @return a type object representing that java language type. | |||
*/ | |||
// OPTIMIZE change users of this to use forSignature, especially for simple cases | |||
public static UnresolvedType forName(String name) { | |||
return forSignature(nameToSignature(name)); | |||
} | |||
@@ -464,7 +466,7 @@ public class UnresolvedType implements Traceable, TypeVariableDeclaringElement { | |||
/** | |||
* Returns the name of this type in java language form (e.g. java.lang.Thread or boolean[]). | |||
* This produces a more esthetically pleasing string than {@link java.lang.Class#getName()}. | |||
* This produces a more aesthetically pleasing string than {@link java.lang.Class#getName()}. | |||
* | |||
* @return the java language name of this type. | |||
*/ | |||
@@ -664,7 +666,7 @@ public class UnresolvedType implements Traceable, TypeVariableDeclaringElement { | |||
// ---- helpers | |||
public static String signatureToName(String signature) { | |||
private static String signatureToName(String signature) { | |||
switch (signature.charAt(0)) { | |||
case 'B': return "byte"; | |||
case 'C': return "char"; | |||
@@ -856,7 +858,7 @@ public class UnresolvedType implements Traceable, TypeVariableDeclaringElement { | |||
} | |||
public UnresolvedType[] getTypeParameters() { | |||
return typeParameters == null ? new UnresolvedType[0] : typeParameters; | |||
return typeParameters == null ? UnresolvedType.NONE : typeParameters; | |||
} | |||
/** | |||
@@ -905,6 +907,7 @@ public class UnresolvedType implements Traceable, TypeVariableDeclaringElement { | |||
* from a generic method/ctor rather than a type variable from a generic type. | |||
* Only subclasses know the answer... | |||
*/ | |||
// OPTIMIZE don't allow this to be called, the caller must have a resolved entity | |||
public boolean isParameterizedWithAMemberTypeVariable() { | |||
throw new RuntimeException("I dont know - you should ask a resolved version of me: "+this); | |||
} |
@@ -146,6 +146,10 @@ public class WeaverMessages { | |||
public static final String INCORRECT_TARGET_FOR_DECLARE_ANNOTATION = "incorrectTargetForDeclareAnnotation"; | |||
public static final String NO_MATCH_BECAUSE_SOURCE_RETENTION = "noMatchBecauseSourceRetention"; | |||
// Annotation Value messages | |||
public static final String INVALID_ANNOTATION_VALUE = "invalidAnnotationValue"; | |||
public static final String UNKNOWN_ANNOTATION_VALUE = "unknownAnnotationValue"; | |||
// < Java5 messages | |||
public static final String ATANNOTATION_ONLY_SUPPORTED_AT_JAVA5_LEVEL = "atannotationNeedsJava5"; | |||
public static final String ATWITHIN_ONLY_SUPPORTED_AT_JAVA5_LEVEL = "atwithinNeedsJava5"; |
@@ -1,84 +0,0 @@ | |||
/* ******************************************************************* | |||
* Copyright (c) 2004 IBM Corporation and others. | |||
* 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: | |||
* Andy Clement initial implementation | |||
* ******************************************************************/ | |||
package org.aspectj.weaver; | |||
import org.aspectj.util.FuzzyBoolean; | |||
/** | |||
* Records stats about the weaver. Information like 'how many types are dismissed during fast match' that | |||
* may be useful for trying to tune pointcuts. Not publicised. | |||
*/ | |||
public class WeaverMetrics { | |||
// Level 1 of matching is at the type level, which types can be dismissed? | |||
public static int fastMatchOnTypeAttempted = 0; | |||
public static int fastMatchOnTypeTrue = 0; | |||
public static int fastMatchOnTypeFalse = 0; | |||
// Level 2 of matching is fast matching on the shadows in the remaining types | |||
public static int fastMatchOnShadowsAttempted = 0; | |||
public static int fastMatchOnShadowsTrue = 0; | |||
public static int fastMatchOnShadowsFalse = 0; | |||
// Level 3 of matching is slow matching on the shadows (more shadows than were fast matched on!) | |||
public static int matchTrue = 0; | |||
public static int matchAttempted = 0; | |||
public static void reset() { | |||
fastMatchOnShadowsAttempted = 0; | |||
fastMatchOnShadowsTrue = 0; | |||
fastMatchOnShadowsFalse = 0; | |||
fastMatchOnTypeAttempted = 0; | |||
fastMatchOnTypeTrue = 0; | |||
fastMatchOnTypeFalse = 0; | |||
matchTrue = 0; | |||
matchAttempted = 0; | |||
} | |||
public static void dumpInfo() { | |||
System.err.println("Match summary:"); | |||
int fastMatchOnTypeMaybe = (fastMatchOnTypeAttempted-fastMatchOnTypeTrue-fastMatchOnTypeFalse); | |||
System.err.print("At the type level, we attempted #"+fastMatchOnTypeAttempted+" fast matches:"); | |||
System.err.println(" YES/NO/MAYBE = "+fastMatchOnTypeTrue+"/"+fastMatchOnTypeFalse+"/"+fastMatchOnTypeMaybe); | |||
int fastMatchMaybe = (fastMatchOnShadowsAttempted-fastMatchOnShadowsFalse-fastMatchOnShadowsTrue); | |||
System.err.print("Within those #"+(fastMatchOnTypeTrue+fastMatchOnTypeMaybe)+" possible types, "); | |||
System.err.print("we fast matched on #"+fastMatchOnShadowsAttempted+" shadows:"); | |||
System.err.println(" YES/NO/MAYBE = "+fastMatchOnShadowsTrue+"/"+fastMatchOnShadowsFalse+"/"+fastMatchMaybe); | |||
System.err.println("Shadow (non-fast) matches attempted #"+matchAttempted+" of which "+matchTrue+" successful"); | |||
} | |||
public static void recordFastMatchTypeResult(FuzzyBoolean fb) { | |||
fastMatchOnTypeAttempted++; | |||
if (fb.alwaysTrue()) fastMatchOnTypeTrue++; | |||
if (fb.alwaysFalse()) fastMatchOnTypeFalse++; | |||
} | |||
public static void recordFastMatchResult(FuzzyBoolean fb) { | |||
fastMatchOnShadowsAttempted++; | |||
if (fb.alwaysTrue()) fastMatchOnShadowsTrue++; | |||
if (fb.alwaysFalse()) fastMatchOnShadowsFalse++; | |||
} | |||
public static void recordMatchResult(boolean b) { | |||
matchAttempted++; | |||
if (b) matchTrue++; | |||
} | |||
} |
@@ -139,7 +139,7 @@ public class WeaverStateInfo { | |||
readAnyReweavableData(wsi,s); | |||
return wsi; | |||
} | |||
throw new RuntimeException("bad WeaverState.Kind: " + b); | |||
throw new RuntimeException("bad WeaverState.Kind: " + b+". File was :"+(context==null?"unknown":context.makeSourceLocation(0,0).toString())); | |||
} | |||
@@ -17,13 +17,17 @@ package org.aspectj.weaver; | |||
import java.lang.ref.ReferenceQueue; | |||
import java.lang.ref.SoftReference; | |||
import java.lang.ref.WeakReference; | |||
import java.util.AbstractMap; | |||
import java.util.ArrayList; | |||
import java.util.Collections; | |||
import java.util.HashMap; | |||
import java.util.HashSet; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.Properties; | |||
import java.util.Set; | |||
import java.util.WeakHashMap; | |||
import org.aspectj.asm.IHierarchy; | |||
import org.aspectj.bridge.IMessageHandler; | |||
@@ -38,9 +42,9 @@ import org.aspectj.weaver.patterns.DeclarePrecedence; | |||
import org.aspectj.weaver.patterns.PerClause; | |||
import org.aspectj.weaver.patterns.Pointcut; | |||
import org.aspectj.weaver.reflect.ReflectionBasedReferenceTypeDelegate; | |||
import org.aspectj.weaver.tools.PointcutDesignatorHandler; | |||
import org.aspectj.weaver.tools.Trace; | |||
import org.aspectj.weaver.tools.TraceFactory; | |||
import java.util.*; | |||
/** | |||
* A World is a collection of known types and crosscutting members. | |||
@@ -58,6 +62,9 @@ public abstract class World implements Dump.INode { | |||
/** The heart of the world, a map from type signatures to resolved types */ | |||
protected TypeMap typeMap = new TypeMap(this); // Signature to ResolvedType | |||
/** New pointcut designators this world supports */ | |||
private Set pointcutDesignators; | |||
// see pr145963 | |||
/** Should we create the hierarchy for binary classes and aspects*/ | |||
public static boolean createInjarHierarchy = true; | |||
@@ -111,6 +118,7 @@ public abstract class World implements Dump.INode { | |||
private boolean runMinimalMemory = false; | |||
private boolean shouldPipelineCompilation = true; | |||
protected boolean bcelRepositoryCaching = xsetBCEL_REPOSITORY_CACHING_DEFAULT.equalsIgnoreCase("true"); | |||
private boolean goforit = false; // TODO better name | |||
private boolean completeBinaryTypes = false; | |||
public boolean forDEBUG_structuralChangesCode = false; | |||
public boolean forDEBUG_bridgingCode = false; | |||
@@ -265,7 +273,7 @@ public abstract class World implements Dump.INode { | |||
if (ty.isArray()) { | |||
ResolvedType componentType = resolve(ty.getComponentType(),allowMissing); | |||
//String brackets = signature.substring(0,signature.lastIndexOf("[")+1); | |||
ret = new ResolvedType.Array(signature, "["+componentType.getErasureSignature(), | |||
ret = new ArrayReferenceType(signature, "["+componentType.getErasureSignature(), | |||
this, | |||
componentType); | |||
} else { | |||
@@ -788,6 +796,8 @@ public abstract class World implements Dump.INode { | |||
public Properties getExtraConfiguration() { | |||
return extraConfiguration; | |||
} | |||
public final static String xsetWEAVE_JAVA_PACKAGES = "weaveJavaPackages"; // default false - controls LTW | |||
public final static String xsetWEAVE_JAVAX_PACKAGES = "weaveJavaxPackages"; // default false - controls LTW | |||
public final static String xsetCAPTURE_ALL_CONTEXT = "captureAllContext"; // default false | |||
public final static String xsetACTIVATE_LIGHTWEIGHT_DELEGATES = "activateLightweightDelegates"; // default true | |||
public final static String xsetRUN_MINIMAL_MEMORY ="runMinimalMemory"; // default true | |||
@@ -799,6 +809,7 @@ public abstract class World implements Dump.INode { | |||
public final static String xsetCOMPLETE_BINARY_TYPES = "completeBinaryTypes"; | |||
public final static String xsetCOMPLETE_BINARY_TYPES_DEFAULT = "false"; | |||
public final static String xsetBCEL_REPOSITORY_CACHING_DEFAULT = "true"; | |||
public final static String xsetGO_FOR_IT = "goforit"; | |||
public boolean isInJava5Mode() { | |||
return behaveInJava5Way; | |||
@@ -817,7 +828,6 @@ public abstract class World implements Dump.INode { | |||
public boolean isJoinpointArrayConstructionEnabled() { | |||
return optionalJoinpoint_ArrayConstruction; | |||
} | |||
public boolean isJoinpointSynchronizationEnabled() { | |||
return optionalJoinpoint_Synchronization; | |||
} | |||
@@ -856,7 +866,7 @@ public abstract class World implements Dump.INode { | |||
private Map /* String -> ResolvedType */ tMap = new HashMap(); | |||
// Map of types that may be ejected from the cache if we need space | |||
private Map expendableMap = new SoftHashMap(); | |||
private Map expendableMap = Collections.synchronizedMap(new WeakHashMap());//new SoftHashMap(); | |||
public static class SoftHashMap extends AbstractMap { | |||
private Map map; | |||
@@ -1020,16 +1030,32 @@ public abstract class World implements Dump.INode { | |||
String key = (String) iter.next(); | |||
ResolvedType type = (ResolvedType)tMap.get(key); | |||
if (type==null) continue;//throw new RuntimeException("Unexpected!! "+key); | |||
if (type.isAspect() ) continue; | |||
if (type.isAspect() || (type.getSuperclass()!=null && type.getSuperclass().isAspect())) continue; | |||
if (type.equals(UnresolvedType.OBJECT)) continue; | |||
if (type.isPrimitiveType()) continue; | |||
List typeMungers = type.getInterTypeMungers(); | |||
if (typeMungers==null || typeMungers.size()==0) { | |||
// demote - we can recover this | |||
tMap.remove(key); | |||
// didnt achieve anything... | |||
// // force the data out of memory - this may not happen if a bcel object type was loaded for | |||
// // something not necessarily being woven as that will never go through the lifecycle states | |||
// ReferenceTypeDelegate delly = ((ReferenceType)type).getDelegate(); | |||
// if (delly instanceof BcelObjectType) { | |||
// ((BcelObjectType)delly).weavingCompleted(); | |||
// // that shouldnt be weavingCompleted, but it will do for now... | |||
// } | |||
// extreme demotion if you dont use these next two lines! | |||
// if (memoryProfiling) expendableMap.put(key,new SoftReference(type,rq)); | |||
// else expendableMap.put(key,new SoftReference(type)); | |||
if (policy==USE_WEAK_REFS) { | |||
if (memoryProfiling) expendableMap.put(key,new WeakReference(type,rq)); | |||
else expendableMap.put(key,new WeakReference(type)); | |||
} else if (policy==USE_SOFT_REFS) { | |||
if (memoryProfiling) expendableMap.put(key,new SoftReference(type,rq)); | |||
else expendableMap.put(key,new SoftReference(type)); | |||
} else { | |||
expendableMap.put(key,type); | |||
} | |||
count++; | |||
} | |||
} | |||
@@ -1140,11 +1166,11 @@ public abstract class World implements Dump.INode { | |||
public int hardSize() { | |||
return tMap.size(); | |||
} | |||
} | |||
} | |||
public void demote() { | |||
typeMap.demote(); | |||
} | |||
} | |||
/** Reference types we don't intend to weave may be ejected from | |||
* the cache if we need the space. | |||
@@ -1157,7 +1183,6 @@ public abstract class World implements Dump.INode { | |||
(!type.isPrimitiveType()) | |||
); | |||
} | |||
/** | |||
* This class is used to compute and store precedence relationships between | |||
@@ -1290,6 +1315,10 @@ public abstract class World implements Dump.INode { | |||
if (!bcelRepositoryCaching) { | |||
getMessageHandler().handleMessage(MessageUtil.info("[bcelRepositoryCaching=false] AspectJ will not use a bcel cache for class information")); | |||
} | |||
s = p.getProperty(xsetGO_FOR_IT,"false"); | |||
goforit = s.equalsIgnoreCase("true"); | |||
s = p.getProperty(xsetPIPELINE_COMPILATION,xsetPIPELINE_COMPILATION_DEFAULT); | |||
shouldPipelineCompilation = s.equalsIgnoreCase("true"); | |||
@@ -1321,6 +1350,11 @@ public abstract class World implements Dump.INode { | |||
ensureAdvancedConfigurationProcessed(); | |||
return runMinimalMemory; | |||
} | |||
public boolean shouldGoForIt() { | |||
ensureAdvancedConfigurationProcessed(); | |||
return goforit; | |||
} | |||
public boolean shouldPipelineCompilation() { | |||
ensureAdvancedConfigurationProcessed(); | |||
@@ -1353,4 +1387,25 @@ public abstract class World implements Dump.INode { | |||
public boolean isASMAround() { | |||
return isASMAround; | |||
} | |||
// | |||
// public ResolvedType[] getAllTypes() { | |||
// return typeMap.getAllTypes(); | |||
// } | |||
/** | |||
* Register a new pointcut designator handler with the world - this can be used by any pointcut parsers attached | |||
* to the world. | |||
* | |||
* @param designatorHandler handler for the new pointcut | |||
*/ | |||
public void registerPointcutHandler(PointcutDesignatorHandler designatorHandler) { | |||
if (pointcutDesignators == null) pointcutDesignators = new HashSet(); | |||
pointcutDesignators.add(designatorHandler); | |||
} | |||
public Set getRegisteredPointcutHandlers() { | |||
if (pointcutDesignators == null) return Collections.EMPTY_SET; | |||
return pointcutDesignators; | |||
} | |||
} |
@@ -41,4 +41,5 @@ cantFindTypeAffectingJPMatch = warning | |||
unorderedAdviceAtShadow=ignore | |||
swallowedExceptionInCatchBlock=ignore | |||
calculatingSerialVersionUID=ignore | |||
advisingSynchronizedMethods=warning | |||
advisingSynchronizedMethods=warning | |||
mustWeaveXmlDefinedAspects=warning |
@@ -15,11 +15,11 @@ package org.aspectj.weaver.ast; | |||
public class Not extends Test { | |||
Test body; | |||
Test test; | |||
public Not(Test left) { | |||
public Not(Test test) { | |||
super(); | |||
this.body = left; | |||
this.test = test; | |||
} | |||
public void accept(ITestVisitor v) { | |||
@@ -27,17 +27,17 @@ public class Not extends Test { | |||
} | |||
public Test getBody() { | |||
return body; | |||
return test; | |||
} | |||
public String toString() { | |||
return "!" + body; | |||
return "!" + test; | |||
} | |||
public boolean equals(Object other) { | |||
if (other instanceof Not) { | |||
Not o = (Not) other; | |||
return o.body.equals(body); | |||
return o.test.equals(test); | |||
} else { | |||
return false; | |||
} |
@@ -15,21 +15,20 @@ package org.aspectj.weaver.ast; | |||
import org.aspectj.weaver.ResolvedType; | |||
public class Var extends Expr { | |||
ResolvedType type; | |||
ResolvedType variableType; | |||
public Var(ResolvedType type) { | |||
public Var(ResolvedType variableType) { | |||
super(); | |||
this.type = type; | |||
this.variableType = variableType; | |||
} | |||
public ResolvedType getType() { | |||
return type; | |||
return variableType; | |||
} | |||
public String toString() { | |||
return "(Var " + type + ")"; | |||
return "(Var " + variableType + ")"; | |||
} | |||
public void accept(IExprVisitor v) { |
@@ -1,5 +1,5 @@ | |||
/* ******************************************************************* | |||
* Copyright (c) 2005 IBM | |||
* Copyright (c) 2005-2008 Contributors | |||
* All rights reserved. | |||
* This program and the accompanying materials are made available | |||
* under the terms of the Eclipse Public License v1.0 | |||
@@ -10,7 +10,6 @@ | |||
* Andy Clement initial implementation | |||
* ******************************************************************/ | |||
package org.aspectj.weaver.bcel; | |||
import org.aspectj.apache.bcel.Constants; | |||
@@ -26,149 +25,119 @@ import org.aspectj.weaver.Shadow; | |||
import org.aspectj.weaver.UnresolvedType; | |||
import org.aspectj.weaver.Shadow.Kind; | |||
/** | |||
* Represents access to an annotation on an element, relating to some 'kinded' pointcut. | |||
* Depending on the kind of pointcut the element might be a field or a method or a ... | |||
* Represents access to an annotation on an element, relating to some kinded pointcut. | |||
* Depending on the kind of pointcut the element might be a field or a method and the code | |||
* generators in here can retrieve the annotation from the element. | |||
*/ | |||
public class KindedAnnotationAccessVar extends BcelVar { | |||
public class AnnotationAccessVar extends BcelVar { | |||
private Kind kind; // What kind of shadow are we at? | |||
private UnresolvedType containingType; // The type upon which we want to ask for 'member' | |||
private Member member; // For method call/execution and field get/set contains the member that has the annotation | |||
private Kind kind; // What kind of shadow are we at? | |||
private UnresolvedType containingType; // The type upon which we want to ask for 'member' | |||
private Member member; // Holds the member that has the annotations (for method/field join points) | |||
public KindedAnnotationAccessVar(Kind kind, ResolvedType type,UnresolvedType theTargetIsStoredHere,Member sig) { | |||
super(type,0); | |||
public AnnotationAccessVar(Kind kind, ResolvedType annotationType, UnresolvedType theTargetIsStoredHere, Member sig) { | |||
super(annotationType,0); | |||
this.kind = kind; | |||
this.containingType = theTargetIsStoredHere; | |||
this.member = sig; | |||
} | |||
public String toString() { | |||
return "KindedAnnotationAccessVar(" + getType() +")"; | |||
return "AnnotationAccessVar(" + getType() +")"; | |||
} | |||
public Instruction createLoad(InstructionFactory fact) { | |||
throw new RuntimeException("unimplemented"); | |||
throw new IllegalStateException("unimplemented"); | |||
} | |||
public Instruction createStore(InstructionFactory fact) { | |||
throw new RuntimeException("unimplemented"); | |||
throw new IllegalStateException("unimplemented"); | |||
} | |||
public InstructionList createCopyFrom(InstructionFactory fact, int oldSlot) { | |||
throw new RuntimeException("unimplemented"); | |||
throw new IllegalStateException("unimplemented"); | |||
} | |||
public void appendLoad(InstructionList il, InstructionFactory fact) { | |||
il.append(createLoadInstructions(getType(), fact)); | |||
} | |||
// FIXME asc Refactor all this stuff - there is a lot of commonality | |||
public InstructionList createLoadInstructions(ResolvedType toType, InstructionFactory fact) { | |||
// FIXME asc Decide on whether we ought to build an exception handler for the NoSuchMethodException that can be thrown | |||
// by getDeclaredMethod()... right now we don't but no-one seems to care... | |||
// LocalVariableGen var_ex = mg.addLocalVariable("ex",Type.getType("Ljava.io.IOException;"),null,null); | |||
// int var_ex_slot = var_ex.getIndex(); | |||
// | |||
// InstructionHandle handler = il.append(new ASTORE(var_ex_slot)); | |||
// var_ex.setStart(handler); | |||
// var_ex.setEnd(il.append(InstructionConstants.RETURN)); | |||
// | |||
// mg.addExceptionHandler(try_start, try_end, handler, | |||
// new ObjectType("java.io.IOException")); | |||
public void appendLoadAndConvert(InstructionList il, InstructionFactory fact, ResolvedType toType) { | |||
il.append(createLoadInstructions(toType, fact)); | |||
} | |||
public void insertLoad(InstructionList il, InstructionFactory fact) { | |||
il.insert(createLoadInstructions(getType(), fact)); | |||
} | |||
private InstructionList createLoadInstructions(ResolvedType toType, InstructionFactory fact) { | |||
InstructionList il = new InstructionList(); | |||
Type jlClass = BcelWorld.makeBcelType(UnresolvedType.JAVA_LANG_CLASS); | |||
Type jlString = BcelWorld.makeBcelType(UnresolvedType.forSignature("Ljava.lang.String;")); | |||
Type jlClassArray = BcelWorld.makeBcelType(UnresolvedType.forSignature("[Ljava.lang.Class;")); | |||
Type jlClassArray = BcelWorld.makeBcelType(UnresolvedType.forSignature("[Ljava.lang.Class;")); | |||
Type jlaAnnotation = BcelWorld.makeBcelType(UnresolvedType.forSignature("Ljava.lang.annotation.Annotation;")); | |||
Instruction pushConstant = fact.createConstant(new ObjectType(toType.getName())); | |||
if (kind==Shadow.MethodCall || kind==Shadow.MethodExecution || | |||
kind==Shadow.PreInitialization || kind==Shadow.Initialization || | |||
kind==Shadow.ConstructorCall || kind==Shadow.ConstructorExecution || | |||
kind==Shadow.AdviceExecution || | |||
// annotations for fieldset/fieldget when an ITD is involved are stored against a METHOD | |||
((kind==Shadow.FieldGet || kind==Shadow.FieldSet) && member.getKind()==Member.METHOD)) { | |||
((kind==Shadow.FieldGet || kind==Shadow.FieldSet) && member.getKind()==Member.METHOD)) { | |||
Type jlrMethod = BcelWorld.makeBcelType(UnresolvedType.forSignature("Ljava.lang.reflect.Method;")); | |||
// Calls getClass | |||
// Variant (1) Use the target directly | |||
il.append(fact.createConstant(BcelWorld.makeBcelType(containingType))); | |||
// Variant (2) Ask the target for its class (could give a different answer at runtime) | |||
// il.append(target.createLoad(fact)); | |||
// il.append(fact.createInvoke("java/lang/Object","getClass",jlClass,new Type[]{},Constants.INVOKEVIRTUAL)); | |||
// il.append(fact.createConstant(new ObjectType(toType.getClassName()))); | |||
if (kind==Shadow.MethodCall || kind==Shadow.MethodExecution || kind==Shadow.AdviceExecution || | |||
Type[] paramTypes = BcelWorld.makeBcelTypes(member.getParameterTypes()); | |||
il.append(fact.createConstant(BcelWorld.makeBcelType(containingType))); | |||
if (kind==Shadow.MethodCall || kind==Shadow.MethodExecution || kind==Shadow.AdviceExecution || | |||
// annotations for fieldset/fieldget when an ITD is involved are stored against a METHOD | |||
((kind==Shadow.FieldGet || kind==Shadow.FieldSet) && member.getKind()==Member.METHOD) || | |||
((kind==Shadow.ConstructorCall || kind==Shadow.ConstructorExecution) && member.getKind()==Member.METHOD)) { | |||
il.append(fact.createConstant(member.getName())); | |||
Type[] paramTypes = null; | |||
paramTypes = BcelWorld.makeBcelTypes(member.getParameterTypes()); | |||
buildArray(il,fact,jlClass,paramTypes,1); | |||
// Calls getDeclaredMethod | |||
il.append(fact.createInvoke("java/lang/Class","getDeclaredMethod",jlrMethod,new Type[]{jlString,jlClassArray},Constants.INVOKEVIRTUAL)); | |||
// FIXME asc perf Cache the result of getDeclaredMethod() and use it | |||
// again for other annotations on the same signature at this join point | |||
// Calls getAnnotation | |||
String ss = toType.getName(); | |||
il.append(fact.createConstant(new ObjectType(toType.getName()))); | |||
il.append(fact.createInvoke("java/lang/reflect/Method","getAnnotation",jlaAnnotation,new Type[]{jlClass},Constants.INVOKEVIRTUAL)); | |||
il.append(Utility.createConversion(fact,jlaAnnotation,BcelWorld.makeBcelType(toType))); | |||
} else { // init/preinit/ctor-call/ctor-exec | |||
Type[] paramTypes = BcelWorld.makeBcelTypes(member.getParameterTypes()); | |||
buildArray(il,fact,jlClass,paramTypes,1); | |||
Type jlrCtor = BcelWorld.makeBcelType(UnresolvedType.forSignature("Ljava.lang.reflect.Constructor;")); | |||
il.append(fact.createInvoke("java/lang/Class","getDeclaredConstructor",jlrCtor,new Type[]{jlClassArray},Constants.INVOKEVIRTUAL)); | |||
// !!! OPTIMIZATION: Cache the result of getDeclaredMethod() and use it | |||
// again for other annotations on the same signature at this join point | |||
// Calls getAnnotation | |||
String ss = toType.getName(); | |||
il.append(fact.createConstant(new ObjectType(toType.getName()))); | |||
il.append(fact.createInvoke("java/lang/reflect/Constructor","getAnnotation",jlaAnnotation,new Type[]{jlClass},Constants.INVOKEVIRTUAL)); | |||
il.append(Utility.createConversion(fact,jlaAnnotation,BcelWorld.makeBcelType(toType))); | |||
} | |||
} else if (kind == Shadow.FieldSet || kind == Shadow.FieldGet) { | |||
il.append(fact.createConstant(member.getName())); | |||
buildArray(il,fact,jlClass,paramTypes,1); | |||
// OPTIMIZE cache result of getDeclaredMethod and getAnnotation? Might be able to use it again if someone else needs the same annotations? | |||
il.append(fact.createInvoke("java/lang/Class","getDeclaredMethod",jlrMethod,new Type[]{jlString,jlClassArray},Constants.INVOKEVIRTUAL)); | |||
il.append(pushConstant);//fact.createConstant(new ObjectType(toType.getName()))); | |||
il.append(fact.createInvoke("java/lang/reflect/Method","getAnnotation",jlaAnnotation,new Type[]{jlClass},Constants.INVOKEVIRTUAL)); | |||
} else { // init/preinit/ctor-call/ctor-exec | |||
buildArray(il,fact,jlClass,paramTypes,1); | |||
Type jlrCtor = BcelWorld.makeBcelType(UnresolvedType.forSignature("Ljava.lang.reflect.Constructor;")); | |||
// OPTIMIZE cache result of getDeclaredConstructor and getAnnotation? Might be able to use it again if someone else needs the same annotations? | |||
il.append(fact.createInvoke("java/lang/Class","getDeclaredConstructor",jlrCtor,new Type[]{jlClassArray},Constants.INVOKEVIRTUAL)); | |||
il.append(pushConstant); | |||
il.append(fact.createInvoke("java/lang/reflect/Constructor","getAnnotation",jlaAnnotation,new Type[]{jlClass},Constants.INVOKEVIRTUAL)); | |||
} | |||
} else if (kind == Shadow.FieldSet || kind == Shadow.FieldGet) { | |||
Type jlrField = BcelWorld.makeBcelType(UnresolvedType.forSignature("Ljava.lang.reflect.Field;")); | |||
il.append(fact.createConstant(BcelWorld.makeBcelType(containingType))); // Stick the target on the stack | |||
il.append(fact.createConstant(member.getName())); // Stick what we are after on the stack | |||
il.append(fact.createInvoke("java/lang/Class","getDeclaredField",jlrField,new Type[]{jlString},Constants.INVOKEVIRTUAL)); | |||
String ss = toType.getName(); | |||
il.append(fact.createConstant(new ObjectType(toType.getName()))); | |||
il.append(fact.createInvoke("java/lang/reflect/Field","getAnnotation",jlaAnnotation,new Type[]{jlClass},Constants.INVOKEVIRTUAL)); | |||
il.append(Utility.createConversion(fact,jlaAnnotation,BcelWorld.makeBcelType(toType))); | |||
} else if (kind == Shadow.StaticInitialization || kind==Shadow.ExceptionHandler) { | |||
il.append(pushConstant); | |||
il.append(fact.createInvoke("java/lang/reflect/Field","getAnnotation",jlaAnnotation,new Type[]{jlClass},Constants.INVOKEVIRTUAL)); | |||
} else if (kind == Shadow.StaticInitialization || kind==Shadow.ExceptionHandler) { | |||
il.append(fact.createConstant(BcelWorld.makeBcelType(containingType))); | |||
String ss = toType.getName(); | |||
il.append(fact.createConstant(new ObjectType(toType.getName()))); | |||
il.append(fact.createInvoke("java/lang/Class","getAnnotation",jlaAnnotation,new Type[]{jlClass},Constants.INVOKEVIRTUAL)); | |||
il.append(Utility.createConversion(fact,jlaAnnotation,BcelWorld.makeBcelType(toType))); | |||
il.append(pushConstant); | |||
il.append(fact.createInvoke("java/lang/Class","getAnnotation",jlaAnnotation,new Type[]{jlClass},Constants.INVOKEVIRTUAL)); | |||
} else { | |||
throw new RuntimeException("Don't understand this kind "+kind); | |||
throw new RuntimeException("Don't understand this kind "+kind); | |||
} | |||
il.append(Utility.createConversion(fact,jlaAnnotation,BcelWorld.makeBcelType(toType))); | |||
return il; | |||
} | |||
private void buildArray(InstructionList il, InstructionFactory fact, Type arrayElementType, Type[] arrayEntries,int dim) { | |||
il.append(fact.createConstant(new Integer(arrayEntries==null?0:arrayEntries.length))); | |||
il.append(fact.createConstant(Integer.valueOf(arrayEntries==null?0:arrayEntries.length))); | |||
il.append(fact.createNewArray(arrayElementType,(short)dim)); | |||
if (arrayEntries == null) return; | |||
for (int i = 0; i < arrayEntries.length; i++) { | |||
il.append(InstructionFactory.createDup(1)); | |||
il.append(fact.createConstant(new Integer(i))); | |||
il.append(fact.createConstant(Integer.valueOf(i))); | |||
switch (arrayEntries[i].getType()) { | |||
case Constants.T_ARRAY: | |||
il.append(fact.createConstant(new ObjectType(arrayEntries[i].getSignature()))); | |||
@@ -188,16 +157,4 @@ public class KindedAnnotationAccessVar extends BcelVar { | |||
} | |||
} | |||
public void appendLoadAndConvert( | |||
InstructionList il, | |||
InstructionFactory fact, | |||
ResolvedType toType) { | |||
il.append(createLoadInstructions(toType, fact)); | |||
} | |||
public void insertLoad(InstructionList il, InstructionFactory fact) { | |||
il.insert(createLoadInstructions(getType(), fact)); | |||
} | |||
} |
@@ -17,6 +17,7 @@ import java.util.Collections; | |||
import java.util.Comparator; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
import java.util.StringTokenizer; | |||
import org.aspectj.apache.bcel.Constants; | |||
import org.aspectj.apache.bcel.classfile.Attribute; | |||
@@ -74,9 +75,7 @@ import org.aspectj.weaver.patterns.SimpleScope; | |||
import org.aspectj.weaver.patterns.TypePattern; | |||
/** | |||
* Annotation defined aspect reader. | |||
* <p/> | |||
* It reads the Java 5 annotations and turns them into AjAttributes | |||
* Annotation defined aspect reader. Reads the Java 5 annotations and turns them into AjAttributes | |||
* | |||
* @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a> | |||
*/ | |||
@@ -85,6 +84,7 @@ public class AtAjAttributes { | |||
private final static List EMPTY_LIST = new ArrayList(); | |||
private final static String[] EMPTY_STRINGS = new String[0]; | |||
private final static String VALUE = "value"; | |||
private final static String ARGNAMES = "argNames"; | |||
private final static String POINTCUT = "pointcut"; | |||
private final static String THROWING = "throwing"; | |||
private final static String RETURNING = "returning"; | |||
@@ -92,8 +92,6 @@ public class AtAjAttributes { | |||
/** | |||
* A struct that allows to add extra arguments without always breaking the API | |||
* | |||
* @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a> | |||
*/ | |||
private static class AjAttributeStruct { | |||
@@ -124,11 +122,9 @@ public class AtAjAttributes { | |||
*/ | |||
private static class AjAttributeMethodStruct extends AjAttributeStruct { | |||
/** | |||
* Argument names as they appear in the SOURCE code, ordered, and lazyly populated | |||
* Used to do formal binding | |||
*/ | |||
// argument names used for formal binding | |||
private String[] m_argumentNamesLazy = null; | |||
public String unparsedArgumentNames = null; // Set only if discovered as argNames attribute of annotation | |||
final Method method; | |||
final BcelMethod bMethod; | |||
@@ -141,7 +137,7 @@ public class AtAjAttributes { | |||
public String[] getArgumentNames() { | |||
if (m_argumentNamesLazy == null) { | |||
m_argumentNamesLazy = getMethodArgumentNamesAsInSource(method); | |||
m_argumentNamesLazy = getMethodArgumentNames(method,unparsedArgumentNames,this); | |||
} | |||
return m_argumentNamesLazy; | |||
} | |||
@@ -149,8 +145,6 @@ public class AtAjAttributes { | |||
/** | |||
* A struct when we read @AJ on field | |||
* | |||
* @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a> | |||
*/ | |||
private static class AjAttributeFieldStruct extends AjAttributeStruct { | |||
@@ -184,15 +178,19 @@ public class AtAjAttributes { | |||
* @return list of AjAttributes | |||
*/ | |||
public static List readAj5ClassAttributes(JavaClass javaClass, ReferenceType type, ISourceContext context, IMessageHandler msgHandler, boolean isCodeStyleAspect) { | |||
//FIXME AV - 1.5 feature limitation, kick after implemented | |||
try { | |||
Constant[] cpool = javaClass.getConstantPool().getConstantPool(); | |||
for (int i = 0; i < cpool.length; i++) { | |||
Constant constant = cpool[i]; | |||
if (constant != null && constant.getTag() == Constants.CONSTANT_Utf8) { | |||
if (!javaClass.getClassName().startsWith("org.aspectj.lang.annotation")) { | |||
ConstantUtf8 constantUtf8 = (ConstantUtf8) constant; | |||
if ("Lorg/aspectj/lang/annotation/DeclareAnnotation;".equals(constantUtf8.getBytes())) { | |||
boolean ignoreThisClass = javaClass.getClassName().charAt(0)=='o' && javaClass.getClassName().startsWith("org.aspectj.lang.annotation"); | |||
if (ignoreThisClass) return EMPTY_LIST; | |||
boolean containsPointcut = false; | |||
boolean containsAnnotationClassReference = false; | |||
Constant[] cpool = javaClass.getConstantPool().getConstantPool(); | |||
for (int i = 0; i < cpool.length; i++) { | |||
Constant constant = cpool[i]; | |||
if (constant != null && constant.getTag() == Constants.CONSTANT_Utf8) { | |||
String constantValue = ((ConstantUtf8)constant).getBytes(); | |||
if (constantValue.length()>28 && constantValue.charAt(1)=='o') { | |||
if (constantValue.startsWith("Lorg/aspectj/lang/annotation")) { | |||
containsAnnotationClassReference=true; | |||
if ("Lorg/aspectj/lang/annotation/DeclareAnnotation;".equals(constantValue)) { | |||
msgHandler.handleMessage( | |||
new Message( | |||
"Found @DeclareAnnotation while current release does not support it (see '" + type.getName() + "')", | |||
@@ -202,13 +200,14 @@ public class AtAjAttributes { | |||
) | |||
); | |||
} | |||
} | |||
if ("Lorg/aspectj/lang/annotation/Pointcut;".equals(constantValue)) { | |||
containsPointcut=true; | |||
} | |||
} | |||
} | |||
} | |||
} catch (Throwable t) { | |||
; | |||
} | |||
if (!containsAnnotationClassReference) return EMPTY_LIST; | |||
AjAttributeStruct struct = new AjAttributeStruct(type, context, msgHandler); | |||
Attribute[] attributes = javaClass.getAttributes(); | |||
@@ -219,7 +218,7 @@ public class AtAjAttributes { | |||
Attribute attribute = attributes[i]; | |||
if (acceptAttribute(attribute)) { | |||
RuntimeAnnotations rvs = (RuntimeAnnotations) attribute; | |||
// we don't need to look for several attribute occurence since it cannot happen as per JSR175 | |||
// we don't need to look for several attribute occurrences since it cannot happen as per JSR175 | |||
if (!isCodeStyleAspect && !javaClass.isInterface()) { | |||
hasAtAspectAnnotation = handleAspectAnnotation(rvs, struct); | |||
//TODO AV - if put outside the if isCodeStyleAspect then we would enable mix style | |||
@@ -245,11 +244,10 @@ public class AtAjAttributes { | |||
} | |||
// the following block will not detect @Pointcut in non @Aspect types for optimization purpose | |||
if (!hasAtAspectAnnotation) { | |||
if (!hasAtAspectAnnotation && !containsPointcut) { | |||
return EMPTY_LIST; | |||
} | |||
//FIXME AV - turn on when ajcMightHaveAspect | |||
// if (hasAtAspectAnnotation && type.isInterface()) { | |||
// msgHandler.handleMessage( | |||
@@ -282,31 +280,35 @@ public class AtAjAttributes { | |||
// we need to gather the @AJ pointcut right now and not at method level annotation extraction time | |||
// in order to be able to resolve the pointcut references later on | |||
// we don't need to look in super class, the pointcut reference in the grammar will do it | |||
for (int i = 0; i < javaClass.getMethods().length; i++) { | |||
Method method = javaClass.getMethods()[i]; | |||
if (method.getName().startsWith(NameMangler.PREFIX)) continue; // already dealt with by ajc... | |||
//FIXME alex optimize, this method struct will gets recreated for advice extraction | |||
AjAttributeMethodStruct mstruct = new AjAttributeMethodStruct(method, null, type, context, msgHandler);//FIXME AVASM | |||
AjAttributeMethodStruct mstruct = null; | |||
boolean processedPointcut = false; | |||
Attribute[] mattributes = method.getAttributes(); | |||
for (int j = 0; j < mattributes.length; j++) { | |||
Attribute mattribute = mattributes[j]; | |||
if (acceptAttribute(mattribute)) { | |||
RuntimeAnnotations mrvs = (RuntimeAnnotations) mattribute; | |||
handlePointcutAnnotation(mrvs, mstruct); | |||
if (mstruct==null) mstruct = new AjAttributeMethodStruct(method, null, type, context, msgHandler);//FIXME AVASM | |||
processedPointcut = handlePointcutAnnotation((RuntimeAnnotations) mattribute, mstruct); | |||
// there can only be one RuntimeVisible bytecode attribute | |||
break; | |||
} | |||
} | |||
// FIXME asc should check we aren't adding multiple versions... will do once I get the tests passing again... | |||
struct.ajAttributes.add(new AjAttribute.WeaverVersionInfo()); | |||
struct.ajAttributes.addAll(mstruct.ajAttributes); | |||
if (processedPointcut) { | |||
// FIXME asc should check we aren't adding multiple versions... will do once I get the tests passing again... | |||
struct.ajAttributes.add(new AjAttribute.WeaverVersionInfo()); | |||
struct.ajAttributes.addAll(mstruct.ajAttributes); | |||
} | |||
} | |||
// code style declare error / warning / implements / parents are field attributes | |||
for (int i = 0; i < javaClass.getFields().length; i++) { | |||
Field field = javaClass.getFields()[i]; | |||
Field[] fs = javaClass.getFields(); | |||
for (int i = 0; i < fs.length; i++) { | |||
Field field = fs[i]; | |||
if (field.getName().startsWith(NameMangler.PREFIX)) continue; // already dealt with by ajc... | |||
//FIXME alex optimize, this method struct will gets recreated for advice extraction | |||
AjAttributeFieldStruct fstruct = new AjAttributeFieldStruct(field, null, type, context, msgHandler); | |||
@@ -742,28 +744,27 @@ public class AtAjAttributes { | |||
for (int i = 0; i < methods.length; i++) { | |||
ResolvedMember method = (ResolvedMember)methods[i]; | |||
if (method.isAbstract()) { | |||
if (defaultImplClassName == null) { | |||
// non marker interface with no default impl provided | |||
reportError("@DeclareParents: used with a non marker interface and no defaultImpl=\"...\" provided", struct); | |||
return false; | |||
} | |||
// moved to be detected at weave time if the target doesnt implement the methods | |||
// if (defaultImplClassName == null) { | |||
// // non marker interface with no default impl provided | |||
// reportError("@DeclareParents: used with a non marker interface and no defaultImpl=\"...\" provided", struct); | |||
// return false; | |||
// } | |||
hasAtLeastOneMethod = true; | |||
struct.ajAttributes.add( | |||
new AjAttribute.TypeMunger( | |||
new MethodDelegateTypeMunger( | |||
method, | |||
struct.enclosingType, | |||
defaultImplClassName, | |||
typePattern | |||
) | |||
) | |||
); | |||
MethodDelegateTypeMunger mdtm = | |||
new MethodDelegateTypeMunger( | |||
method, | |||
struct.enclosingType, | |||
defaultImplClassName, | |||
typePattern | |||
); | |||
mdtm.setSourceLocation(struct.enclosingType.getSourceLocation()); | |||
struct.ajAttributes.add(new AjAttribute.TypeMunger(mdtm)); | |||
} | |||
} | |||
// successfull so far, we thus need a bcel type munger to have | |||
// a field hosting the mixin in the target type | |||
if (hasAtLeastOneMethod) { | |||
if (hasAtLeastOneMethod && defaultImplClassName!=null) { | |||
struct.ajAttributes.add( | |||
new AjAttribute.TypeMunger( | |||
new MethodDelegateTypeMunger.FieldHostTypeMunger( | |||
@@ -802,6 +803,10 @@ public class AtAjAttributes { | |||
ElementNameValuePairGen beforeAdvice = getAnnotationElement(before, VALUE); | |||
if (beforeAdvice != null) { | |||
// this/target/args binding | |||
String argumentNames = getArgNamesValue(before); | |||
if (argumentNames!=null) { | |||
struct.unparsedArgumentNames = argumentNames; | |||
} | |||
FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0]; | |||
try { | |||
bindings = extractBindings(struct); | |||
@@ -859,6 +864,10 @@ public class AtAjAttributes { | |||
if (afterAdvice != null) { | |||
// this/target/args binding | |||
FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0]; | |||
String argumentNames = getArgNamesValue(after); | |||
if (argumentNames!=null) { | |||
struct.unparsedArgumentNames = argumentNames; | |||
} | |||
try { | |||
bindings = extractBindings(struct); | |||
} catch (UnreadableDebugInfoException unreadableDebugInfoException) { | |||
@@ -948,7 +957,10 @@ public class AtAjAttributes { | |||
} | |||
} | |||
} | |||
String argumentNames = getArgNamesValue(after); | |||
if (argumentNames!=null) { | |||
struct.unparsedArgumentNames = argumentNames; | |||
} | |||
// this/target/args binding | |||
// exclude the return binding from the pointcut binding since it is an extraArg binding | |||
FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0]; | |||
@@ -1045,7 +1057,10 @@ public class AtAjAttributes { | |||
} | |||
} | |||
} | |||
String argumentNames = getArgNamesValue(after); | |||
if (argumentNames!=null) { | |||
struct.unparsedArgumentNames = argumentNames; | |||
} | |||
// this/target/args binding | |||
// exclude the throwned binding from the pointcut binding since it is an extraArg binding | |||
FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0]; | |||
@@ -1106,7 +1121,11 @@ public class AtAjAttributes { | |||
if (around != null) { | |||
ElementNameValuePairGen aroundAdvice = getAnnotationElement(around, VALUE); | |||
if (aroundAdvice != null) { | |||
// this/target/args binding | |||
// this/target/args binding | |||
String argumentNames = getArgNamesValue(around); | |||
if (argumentNames!=null) { | |||
struct.unparsedArgumentNames = argumentNames; | |||
} | |||
FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0]; | |||
try { | |||
bindings = extractBindings(struct); | |||
@@ -1154,83 +1173,93 @@ public class AtAjAttributes { | |||
* | |||
* @param runtimeAnnotations | |||
* @param struct | |||
* @return true if a pointcut was handled | |||
*/ | |||
private static void handlePointcutAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeMethodStruct struct) { | |||
private static boolean handlePointcutAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeMethodStruct struct) { | |||
AnnotationGen pointcut = getAnnotation(runtimeAnnotations, AjcMemberMaker.POINTCUT_ANNOTATION); | |||
if (pointcut != null) { | |||
ElementNameValuePairGen pointcutExpr = getAnnotationElement(pointcut, VALUE); | |||
// semantic check: the method must return void, or be "public static boolean" for if() support | |||
if (!(Type.VOID.equals(struct.method.getReturnType()) | |||
|| (Type.BOOLEAN.equals(struct.method.getReturnType()) && struct.method.isStatic() && struct.method.isPublic()))) { | |||
reportWarning("Found @Pointcut on a method not returning 'void' or not 'public static boolean'", struct); | |||
;//no need to stop | |||
} | |||
if (pointcut==null) return false; | |||
ElementNameValuePairGen pointcutExpr = getAnnotationElement(pointcut, VALUE); | |||
// semantic check: the method must not throw anything | |||
if (struct.method.getExceptionTable() != null) { | |||
reportWarning("Found @Pointcut on a method throwing exception", struct); | |||
;// no need to stop | |||
} | |||
// semantic check: the method must return void, or be "public static boolean" for if() support | |||
if (!(Type.VOID.equals(struct.method.getReturnType()) | |||
|| (Type.BOOLEAN.equals(struct.method.getReturnType()) && struct.method.isStatic() && struct.method.isPublic()))) { | |||
reportWarning("Found @Pointcut on a method not returning 'void' or not 'public static boolean'", struct); | |||
;//no need to stop | |||
} | |||
// this/target/args binding | |||
final IScope binding; | |||
try { | |||
// semantic check: the method must not throw anything | |||
if (struct.method.getExceptionTable() != null) { | |||
reportWarning("Found @Pointcut on a method throwing exception", struct); | |||
;// no need to stop | |||
} | |||
String argumentNames = getArgNamesValue(pointcut); | |||
if (argumentNames!=null) { | |||
struct.unparsedArgumentNames = argumentNames; | |||
} | |||
// this/target/args binding | |||
final IScope binding; | |||
try { | |||
if (struct.method.isAbstract()) { | |||
binding = null; | |||
} else { | |||
binding = new BindingScope( | |||
struct.enclosingType, | |||
struct.context, | |||
extractBindings(struct) | |||
struct.enclosingType, | |||
struct.context, | |||
extractBindings(struct) | |||
); | |||
} catch (UnreadableDebugInfoException e) { | |||
return; | |||
} | |||
} | |||
} catch (UnreadableDebugInfoException e) { | |||
return false; | |||
} | |||
UnresolvedType[] argumentTypes = new UnresolvedType[struct.method.getArgumentTypes().length]; | |||
for (int i = 0; i < argumentTypes.length; i++) { | |||
argumentTypes[i] = UnresolvedType.forSignature(struct.method.getArgumentTypes()[i].getSignature()); | |||
} | |||
UnresolvedType[] argumentTypes = new UnresolvedType[struct.method.getArgumentTypes().length]; | |||
for (int i = 0; i < argumentTypes.length; i++) { | |||
argumentTypes[i] = UnresolvedType.forSignature(struct.method.getArgumentTypes()[i].getSignature()); | |||
} | |||
Pointcut pc = null; | |||
if (struct.method.isAbstract()) { | |||
if ((pointcutExpr != null && isNullOrEmpty(pointcutExpr.getValue().stringifyValue())) | |||
|| pointcutExpr == null) { | |||
// abstract pointcut | |||
// leave pc = null | |||
} else { | |||
reportError("Found defined @Pointcut on an abstract method", struct); | |||
return;//stop | |||
} | |||
Pointcut pc = null; | |||
if (struct.method.isAbstract()) { | |||
if ((pointcutExpr != null && isNullOrEmpty(pointcutExpr.getValue().stringifyValue())) | |||
|| pointcutExpr == null) { | |||
// abstract pointcut | |||
// leave pc = null | |||
} else { | |||
if (pointcutExpr==null || (pointcutExpr != null && isNullOrEmpty(pointcutExpr.getValue().stringifyValue()))) { | |||
// the matches nothing pointcut (125475/125480) - perhaps not as cleanly supported as it could be. | |||
} else { | |||
if (pointcutExpr != null) { | |||
// use a LazyResolvedPointcutDefinition so that the pointcut is resolved lazily | |||
// since for it to be resolved, we will need other pointcuts to be registered as well | |||
pc = parsePointcut(pointcutExpr.getValue().stringifyValue(), struct, true); | |||
if (pc == null) return;//parse error | |||
pc.setLocation(struct.context, -1, -1);//FIXME AVASM !! bMethod is null here.. | |||
} else { | |||
reportError("Found undefined @Pointcut on a non-abstract method", struct); | |||
return; | |||
} | |||
} | |||
reportError("Found defined @Pointcut on an abstract method", struct); | |||
return false;//stop | |||
} | |||
// do not resolve binding now but lazily | |||
struct.ajAttributes.add( | |||
new AjAttribute.PointcutDeclarationAttribute( | |||
new LazyResolvedPointcutDefinition( | |||
struct.enclosingType, | |||
struct.method.getModifiers(), | |||
struct.method.getName(), | |||
argumentTypes, | |||
UnresolvedType.forSignature(struct.method.getReturnType().getSignature()), | |||
pc,//can be null for abstract pointcut | |||
binding | |||
) | |||
) | |||
); | |||
} else { | |||
if (pointcutExpr==null || (pointcutExpr != null && isNullOrEmpty(pointcutExpr.getValue().stringifyValue()))) { | |||
// the matches nothing pointcut (125475/125480) - perhaps not as cleanly supported as it could be. | |||
} else { | |||
if (pointcutExpr != null) { | |||
// use a LazyResolvedPointcutDefinition so that the pointcut is resolved lazily | |||
// since for it to be resolved, we will need other pointcuts to be registered as well | |||
pc = parsePointcut(pointcutExpr.getValue().stringifyValue(), struct, true); | |||
if (pc == null) return false;//parse error | |||
pc.setLocation(struct.context, -1, -1);//FIXME AVASM !! bMethod is null here.. | |||
} else { | |||
reportError("Found undefined @Pointcut on a non-abstract method", struct); | |||
return false; | |||
} | |||
} | |||
} | |||
// do not resolve binding now but lazily | |||
struct.ajAttributes.add( | |||
new AjAttribute.PointcutDeclarationAttribute( | |||
new LazyResolvedPointcutDefinition( | |||
struct.enclosingType, | |||
struct.method.getModifiers(), | |||
struct.method.getName(), | |||
argumentTypes, | |||
UnresolvedType.forSignature(struct.method.getReturnType().getSignature()), | |||
pc,//can be null for abstract pointcut | |||
binding // can be null for abstract pointcut | |||
) | |||
) | |||
); | |||
return true; | |||
} | |||
/** | |||
@@ -1492,15 +1521,37 @@ public class AtAjAttributes { | |||
} | |||
return null; | |||
} | |||
/** | |||
* Return the argNames set for an annotation or null if it is not specified. | |||
*/ | |||
private static String getArgNamesValue(AnnotationGen anno) { | |||
for (Iterator iterator1 = anno.getValues().iterator(); iterator1.hasNext();) { | |||
ElementNameValuePairGen element = (ElementNameValuePairGen) iterator1.next(); | |||
if (ARGNAMES.equals(element.getNameString())) { | |||
return element.getValue().stringifyValue(); | |||
} | |||
} | |||
return null; | |||
} | |||
private static String lastbit(String fqname) { | |||
int i = fqname.lastIndexOf("."); | |||
if (i==-1) return fqname; else return fqname.substring(i+1); | |||
} | |||
/** | |||
* Extract the method argument names as in source from debug info | |||
* returns an empty array upon inconsistency | |||
* Extract the method argument names. First we try the debug info attached | |||
* to the method (the LocalVariableTable) - if we cannot find that we look | |||
* to use the argNames value that may have been supplied on the associated | |||
* annotation. If that fails we just don't know and return an empty string. | |||
* | |||
* @param method | |||
* @return method arg names as in source | |||
* @param argNamesFromAnnotation | |||
* @param methodStruct | |||
* @return method argument names | |||
*/ | |||
private static String[] getMethodArgumentNamesAsInSource(Method method) { | |||
private static String[] getMethodArgumentNames(Method method, String argNamesFromAnnotation, AjAttributeMethodStruct methodStruct) { | |||
if (method.getArgumentTypes().length == 0) { | |||
return EMPTY_STRINGS; | |||
} | |||
@@ -1517,6 +1568,28 @@ public class AtAjAttributes { | |||
} | |||
} | |||
} | |||
} else { | |||
// No debug info, do we have an annotation value we can rely on? | |||
if (argNamesFromAnnotation!=null) { | |||
StringTokenizer st = new StringTokenizer(argNamesFromAnnotation," ,"); | |||
List args = new ArrayList(); | |||
while (st.hasMoreTokens()) { args.add(st.nextToken());} | |||
if (args.size()!=method.getArgumentTypes().length) { | |||
StringBuffer shortString = new StringBuffer().append(lastbit(method.getReturnType().toString())).append(" ").append(method.getName()); | |||
if (method.getArgumentTypes().length>0) { | |||
shortString.append("("); | |||
for (int i =0; i<method.getArgumentTypes().length;i++) { | |||
shortString.append(lastbit(method.getArgumentTypes()[i].toString())); | |||
if ((i+1)<method.getArgumentTypes().length) shortString.append(","); | |||
} | |||
shortString.append(")"); | |||
} | |||
reportError("argNames annotation value does not specify the right number of argument names for the method '"+shortString.toString()+"'",methodStruct); | |||
return EMPTY_STRINGS; | |||
} | |||
return (String[])args.toArray(new String[]{}); | |||
} | |||
} | |||
if (arguments.size() != method.getArgumentTypes().length) { | |||
@@ -1619,7 +1692,7 @@ public class AtAjAttributes { | |||
private Pointcut m_lazyPointcut = null; | |||
public LazyResolvedPointcutDefinition(ResolvedType declaringType, int modifiers, String name, | |||
public LazyResolvedPointcutDefinition(UnresolvedType declaringType, int modifiers, String name, | |||
UnresolvedType[] parameterTypes, UnresolvedType returnType, | |||
Pointcut pointcut, IScope binding) { | |||
super(declaringType, modifiers, name, parameterTypes, returnType, null); |
@@ -11,14 +11,8 @@ | |||
*******************************************************************************/ | |||
package org.aspectj.weaver.bcel; | |||
import java.util.HashMap; | |||
import java.util.HashSet; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.Set; | |||
import org.aspectj.apache.bcel.Constants; | |||
import org.aspectj.apache.bcel.classfile.ConstantPool; | |||
import org.aspectj.apache.bcel.generic.FieldInstruction; | |||
import org.aspectj.apache.bcel.generic.Instruction; | |||
import org.aspectj.apache.bcel.generic.InstructionConstants; | |||
@@ -26,7 +20,6 @@ import org.aspectj.apache.bcel.generic.InstructionFactory; | |||
import org.aspectj.apache.bcel.generic.InstructionHandle; | |||
import org.aspectj.apache.bcel.generic.InstructionList; | |||
import org.aspectj.apache.bcel.generic.InvokeInstruction; | |||
import org.aspectj.apache.bcel.classfile.ConstantPool; | |||
import org.aspectj.apache.bcel.generic.Type; | |||
import org.aspectj.weaver.AjAttribute; | |||
import org.aspectj.weaver.AjcMemberMaker; | |||
@@ -37,6 +30,13 @@ import org.aspectj.weaver.ResolvedType; | |||
import org.aspectj.weaver.Shadow; | |||
import org.aspectj.weaver.UnresolvedType; | |||
import java.util.HashMap; | |||
import java.util.HashSet; | |||
import java.util.Iterator; | |||
import java.util.Map; | |||
import java.util.Set; | |||
import java.util.List; | |||
/** | |||
* Looks for all access to method or field that are not public within the body of the around advices and replace | |||
* the invocations to a wrapper call so that the around advice can further be inlined. | |||
@@ -257,11 +257,11 @@ public class BcelAccessForInlineMunger extends BcelTypeMunger { | |||
// flag it synthetic, AjSynthetic | |||
method.makeSynthetic(); | |||
method.addAttribute( | |||
BcelAttributes.bcelAttribute(new AjAttribute.AjSynthetic(), m_aspectGen.getConstantPool()) | |||
Utility.bcelAttribute(new AjAttribute.AjSynthetic(), m_aspectGen.getConstantPool()) | |||
); | |||
// flag the effective signature, so that we can deobfuscate the signature to apply method call pointcut | |||
method.addAttribute( | |||
BcelAttributes.bcelAttribute( | |||
Utility.bcelAttribute( | |||
new AjAttribute.EffectiveSignatureAttribute(resolvedMember, Shadow.MethodCall, false), | |||
m_aspectGen.getConstantPool() | |||
) | |||
@@ -318,11 +318,11 @@ public class BcelAccessForInlineMunger extends BcelTypeMunger { | |||
// flag it synthetic, AjSynthetic | |||
method.makeSynthetic(); | |||
method.addAttribute( | |||
BcelAttributes.bcelAttribute(new AjAttribute.AjSynthetic(), m_aspectGen.getConstantPool()) | |||
Utility.bcelAttribute(new AjAttribute.AjSynthetic(), m_aspectGen.getConstantPool()) | |||
); | |||
// flag the effective signature, so that we can deobfuscate the signature to apply method call pointcut | |||
method.addAttribute( | |||
BcelAttributes.bcelAttribute( | |||
Utility.bcelAttribute( | |||
new AjAttribute.EffectiveSignatureAttribute(resolvedMember, Shadow.MethodCall, false), | |||
m_aspectGen.getConstantPool() | |||
) | |||
@@ -380,11 +380,11 @@ public class BcelAccessForInlineMunger extends BcelTypeMunger { | |||
// flag it synthetic, AjSynthetic | |||
method.makeSynthetic(); | |||
method.addAttribute( | |||
BcelAttributes.bcelAttribute(new AjAttribute.AjSynthetic(), m_aspectGen.getConstantPool()) | |||
Utility.bcelAttribute(new AjAttribute.AjSynthetic(), m_aspectGen.getConstantPool()) | |||
); | |||
// flag the effective signature, so that we can deobfuscate the signature to apply method call pointcut | |||
method.addAttribute( | |||
BcelAttributes.bcelAttribute( | |||
Utility.bcelAttribute( | |||
new AjAttribute.EffectiveSignatureAttribute(resolvedMember, Shadow.FieldGet, false), | |||
m_aspectGen.getConstantPool() | |||
) | |||
@@ -438,11 +438,11 @@ public class BcelAccessForInlineMunger extends BcelTypeMunger { | |||
// flag it synthetic, AjSynthetic | |||
method.makeSynthetic(); | |||
method.addAttribute( | |||
BcelAttributes.bcelAttribute(new AjAttribute.AjSynthetic(), m_aspectGen.getConstantPool()) | |||
Utility.bcelAttribute(new AjAttribute.AjSynthetic(), m_aspectGen.getConstantPool()) | |||
); | |||
// flag the effective signature, so that we can deobfuscate the signature to apply method call pointcut | |||
method.addAttribute( | |||
BcelAttributes.bcelAttribute( | |||
Utility.bcelAttribute( | |||
new AjAttribute.EffectiveSignatureAttribute(resolvedMember, Shadow.FieldSet, false), | |||
m_aspectGen.getConstantPool() | |||
) |
@@ -67,20 +67,9 @@ public class BcelAdvice extends Advice { | |||
Member signature, | |||
ResolvedType concreteAspect) | |||
{ | |||
super(attribute, pointcut, (signature==null?null:signature.slimline())); | |||
super(attribute, pointcut,shrink(attribute.getKind(),concreteAspect,signature));// (signature==null?null:signature.slimline())); | |||
this.concreteAspect = concreteAspect; | |||
} | |||
// !!! must only be used for testing | |||
public BcelAdvice(AdviceKind kind, Pointcut pointcut, Member signature, | |||
int extraArgumentFlags, | |||
int start, int end, ISourceContext sourceContext, ResolvedType concreteAspect) | |||
{ | |||
this(new AjAttribute.AdviceAttribute(kind, pointcut, extraArgumentFlags, start, end, sourceContext), | |||
pointcut, (signature==null?null:signature.slimline()), concreteAspect); | |||
thrownExceptions = Collections.EMPTY_LIST; //!!! interaction with unit tests | |||
} | |||
/** | |||
* We don't always need to represent the signature with a heavyweight BcelMethod object - only if its around advice | |||
* and inlining is active | |||
@@ -105,6 +94,15 @@ public class BcelAdvice extends Advice { | |||
} | |||
return m; | |||
} | |||
// !!! must only be used for testing | |||
public BcelAdvice(AdviceKind kind, Pointcut pointcut, Member signature, | |||
int extraArgumentFlags, | |||
int start, int end, ISourceContext sourceContext, ResolvedType concreteAspect) | |||
{ | |||
this(new AjAttribute.AdviceAttribute(kind, pointcut, extraArgumentFlags, start, end, sourceContext), | |||
pointcut, signature, concreteAspect); | |||
thrownExceptions = Collections.EMPTY_LIST; //!!! interaction with unit tests | |||
} | |||
// ---- implementations of ShadowMunger's methods | |||
@@ -211,7 +209,6 @@ public class BcelAdvice extends Advice { | |||
if (concreteAspect.getWorld().isXnoInline()) return false; | |||
//System.err.println("isWoven? " + ((BcelObjectType)concreteAspect).getLazyClassGen().getWeaverState()); | |||
// if (BcelWorld.getBcelObjectType(concreteAspect).getJavaClass()==null) return true; // been evicted... CUSTARD | |||
return BcelWorld.getBcelObjectType(concreteAspect).getLazyClassGen().isWoven(); | |||
} | |||
@@ -721,7 +718,7 @@ public class BcelAdvice extends Advice { | |||
protected void suppressLintWarnings(World inWorld) { | |||
if (suppressedLintKinds == null) { | |||
if (signature instanceof BcelMethod) { | |||
this.suppressedLintKinds = Utility.getSuppressedWarnings(signature.getAnnotations(), inWorld.getLint()); | |||
this.suppressedLintKinds = Utility.getSuppressedWarnings(((BcelMethod)signature).getAnnotations(), inWorld.getLint()); | |||
} else { | |||
this.suppressedLintKinds = Collections.EMPTY_LIST; | |||
} |
@@ -18,7 +18,6 @@ import java.util.List; | |||
import org.aspectj.apache.bcel.classfile.Attribute; | |||
import org.aspectj.apache.bcel.classfile.Unknown; | |||
import org.aspectj.apache.bcel.classfile.ConstantPool; | |||
import org.aspectj.weaver.AjAttribute; | |||
import org.aspectj.weaver.BCException; | |||
import org.aspectj.weaver.ISourceContext; | |||
@@ -28,16 +27,50 @@ import org.aspectj.weaver.AjAttribute.WeaverVersionInfo; | |||
// this is a class o' static methods for reading attributes. It's pretty much a bridge from | |||
// bcel to AjAttribute. | |||
// OPTIMIZE move the contents of this class to bcel Utility | |||
class BcelAttributes { | |||
/** | |||
* Process an array of Bcel attributes - looking for those with the name prefix org.aspectj.weaver. The returned | |||
* list contains the AspectJ attributes identified and unpacked to 'AjAttribute' objects. | |||
*/ | |||
public static List readAjAttributes(String classname,Attribute[] as, ISourceContext context, | |||
World w,AjAttribute.WeaverVersionInfo version) { | |||
// public static List readAjAttributes(String classname,List as, ISourceContext context, | |||
// World w, AjAttribute.WeaverVersionInfo version) { | |||
// List l = new ArrayList(); | |||
// | |||
// // first pass, look for version | |||
// List forSecondPass = new ArrayList(); | |||
// for (int i = as.size() - 1; i >= 0; i--) { | |||
// Attribute a = (Attribute)as.get(i); | |||
// if (a instanceof Unknown) { | |||
// Unknown u = (Unknown) a; | |||
// String name = u.getName(); | |||
// if (name.charAt(0)=='o') { // 'o'rg.aspectj | |||
// if (name.startsWith(AjAttribute.AttributePrefix)) { | |||
// if (name.endsWith(WeaverVersionInfo.AttributeName)) { | |||
// version = (AjAttribute.WeaverVersionInfo)AjAttribute.read(version,name,u.getBytes(),context,w); | |||
// if (version.getMajorVersion() > WeaverVersionInfo.getCurrentWeaverMajorVersion()) { | |||
// throw new BCException("Unable to continue, this version of AspectJ supports classes built with weaver version "+ | |||
// WeaverVersionInfo.toCurrentVersionString()+" but the class "+classname+" is version "+version.toString()); | |||
// } | |||
// } | |||
// forSecondPass.add(a); | |||
// } | |||
// } | |||
// } | |||
// } | |||
// for (int i = forSecondPass.size()-1; i >= 0; i--) { | |||
// Unknown a = (Unknown)forSecondPass.get(i); | |||
// String name = a.getName(); | |||
// AjAttribute attr = AjAttribute.read(version,name,a.getBytes(),context,w); | |||
// if (attr!=null) l.add(attr); | |||
// } | |||
// return l; | |||
// } | |||
public static List readAjAttributes(String classname, Attribute[] as, ISourceContext context, World w, AjAttribute.WeaverVersionInfo version) { | |||
List l = new ArrayList(); | |||
// first pass, look for version | |||
List forSecondPass = new ArrayList(); | |||
for (int i = as.length - 1; i >= 0; i--) { | |||
@@ -45,37 +78,34 @@ class BcelAttributes { | |||
if (a instanceof Unknown) { | |||
Unknown u = (Unknown) a; | |||
String name = u.getName(); | |||
if (name.charAt(0)=='o') { // 'o'rg.aspectj | |||
if (name.charAt(0) == 'o') { // 'o'rg.aspectj | |||
if (name.startsWith(AjAttribute.AttributePrefix)) { | |||
if (name.endsWith(WeaverVersionInfo.AttributeName)) { | |||
version = (AjAttribute.WeaverVersionInfo)AjAttribute.read(version,name,u.getBytes(),context,w); | |||
if (version.getMajorVersion() > WeaverVersionInfo.getCurrentWeaverMajorVersion()) { | |||
throw new BCException("Unable to continue, this version of AspectJ supports classes built with weaver version "+ | |||
WeaverVersionInfo.toCurrentVersionString()+" but the class "+classname+" is version "+version.toString()); | |||
version = (AjAttribute.WeaverVersionInfo) AjAttribute.read(version, name, u.getBytes(), context, w); | |||
if (version.getMajorVersion() > WeaverVersionInfo | |||
.getCurrentWeaverMajorVersion()) { | |||
throw new BCException( | |||
"Unable to continue, this version of AspectJ supports classes built with weaver version " | |||
+ WeaverVersionInfo | |||
.toCurrentVersionString() | |||
+ " but the class " | |||
+ classname | |||
+ " is version " | |||
+ version.toString()); | |||
} | |||
} | |||
} | |||
forSecondPass.add(a); | |||
} | |||
} | |||
} | |||
} | |||
for (int i = forSecondPass.size()-1; i >= 0; i--) { | |||
Unknown a = (Unknown)forSecondPass.get(i); | |||
for (int i = forSecondPass.size() - 1; i >= 0; i--) { | |||
Unknown a = (Unknown) forSecondPass.get(i); | |||
String name = a.getName(); | |||
AjAttribute attr = AjAttribute.read(version,name,a.getBytes(),context,w); | |||
if (attr!=null) l.add(attr); | |||
AjAttribute attr = AjAttribute.read(version, name, a.getBytes(), context, w); | |||
if (attr != null) l.add(attr); | |||
} | |||
return l; | |||
} | |||
public static Attribute bcelAttribute(AjAttribute a, ConstantPool pool) { | |||
int nameIndex = pool.addUtf8(a.getNameString()); | |||
byte[] bytes = a.getBytes(); | |||
int length = bytes.length; | |||
return new Unknown(nameIndex, length, bytes, pool); | |||
} | |||
} |
@@ -88,4 +88,8 @@ public class BcelCflowCounterFieldAdder extends BcelTypeMunger { | |||
return true; | |||
} | |||
public String toString() { | |||
return "(BcelTypeMunger: CflowField "+cflowCounterField.getDeclaringType().getName()+" "+cflowCounterField.getName()+")"; | |||
} | |||
} |
@@ -80,7 +80,6 @@ import org.aspectj.weaver.Shadow; | |||
import org.aspectj.weaver.ShadowMunger; | |||
import org.aspectj.weaver.UnresolvedType; | |||
import org.aspectj.weaver.WeaverMessages; | |||
import org.aspectj.weaver.WeaverMetrics; | |||
import org.aspectj.weaver.WeaverStateInfo; | |||
import org.aspectj.weaver.World; | |||
import org.aspectj.weaver.patterns.DeclareAnnotation; | |||
@@ -88,9 +87,6 @@ import org.aspectj.weaver.patterns.ExactTypePattern; | |||
import org.aspectj.weaver.tools.Trace; | |||
import org.aspectj.weaver.tools.TraceFactory; | |||
import com.sun.org.apache.bcel.internal.generic.BranchInstruction; | |||
import com.sun.org.apache.bcel.internal.generic.GOTO; | |||
import com.sun.org.apache.bcel.internal.generic.GOTO_W; | |||
class BcelClassWeaver implements IClassWeaver { | |||
@@ -821,8 +817,9 @@ class BcelClassWeaver implements IClassWeaver { | |||
if (annotationsToAdd==null) annotationsToAdd = new ArrayList(); | |||
AnnotationGen a = decaM.getAnnotationX().getBcelAnnotation(); | |||
AnnotationGen ag = new AnnotationGen(a,clazz.getConstantPool(),true); | |||
annotationsToAdd.add(ag); | |||
//CUSTARD superfluous? | |||
//AnnotationGen ag = new AnnotationGen(a,clazz.getConstantPool(),true); | |||
annotationsToAdd.add(a); | |||
mg.addAnnotation(decaM.getAnnotationX()); | |||
AsmRelationshipProvider.getDefault().addDeclareAnnotationRelationship(decaM.getSourceLocation(),clazz.getName(),mg.getMethod()); | |||
@@ -1002,7 +999,7 @@ class BcelClassWeaver implements IClassWeaver { | |||
while (!worthRetrying.isEmpty() && modificationOccured) { | |||
modificationOccured = false; | |||
List forRemoval = new ArrayList(); | |||
for (Iterator iter2 = worthRetrying.iterator(); iter.hasNext();) { | |||
for (Iterator iter2 = worthRetrying.iterator(); iter2.hasNext();) { | |||
DeclareAnnotation decaF = (DeclareAnnotation) iter2.next(); | |||
if (decaF.matches(itdIsActually,world)) { | |||
LazyMethodGen annotationHolder = locateAnnotationHolderForFieldMunger(clazz,fieldMunger); | |||
@@ -1055,7 +1052,7 @@ class BcelClassWeaver implements IClassWeaver { | |||
while (!worthRetrying.isEmpty() && modificationOccured) { | |||
modificationOccured = false; | |||
List forRemoval = new ArrayList(); | |||
for (Iterator iter2 = worthRetrying.iterator(); iter.hasNext();) { | |||
for (Iterator iter2 = worthRetrying.iterator(); iter2.hasNext();) { | |||
DeclareAnnotation decaMC = (DeclareAnnotation) iter2.next(); | |||
if (decaMC.matches(unMangledInterMethod,world)) { | |||
LazyMethodGen annotationHolder = locateAnnotationHolderForFieldMunger(clazz,methodctorMunger); | |||
@@ -1074,7 +1071,7 @@ class BcelClassWeaver implements IClassWeaver { | |||
return isChanged; | |||
} | |||
private boolean dontAddTwice(DeclareAnnotation decaF, AnnotationX[] dontAddMeTwice){ | |||
private boolean dontAddTwice(DeclareAnnotation decaF, AnnotationX [] dontAddMeTwice){ | |||
for (int i = 0; i < dontAddMeTwice.length; i++){ | |||
AnnotationX ann = dontAddMeTwice[i]; | |||
if (ann != null && decaF.getAnnotationX().getTypeName().equals(ann.getTypeName())){ | |||
@@ -1162,7 +1159,7 @@ class BcelClassWeaver implements IClassWeaver { | |||
} | |||
} | |||
AsmRelationshipProvider.getDefault().addDeclareAnnotationRelationship(decaF.getSourceLocation(),clazz.getName(),aBcelField.getName()); | |||
AsmRelationshipProvider.getDefault().addDeclareAnnotationRelationship(decaF.getSourceLocation(),clazz.getName(),aBcelField.getFieldAsIs()); | |||
reportFieldAnnotationWeavingMessage(clazz, fields, fieldCounter, decaF); | |||
isChanged = true; | |||
modificationOccured = true; | |||
@@ -1190,7 +1187,7 @@ class BcelClassWeaver implements IClassWeaver { | |||
continue; // skip this one... | |||
} | |||
aBcelField.addAnnotation(decaF.getAnnotationX()); | |||
AsmRelationshipProvider.getDefault().addDeclareAnnotationRelationship(decaF.getSourceLocation(),clazz.getName(),aBcelField.getName()); | |||
AsmRelationshipProvider.getDefault().addDeclareAnnotationRelationship(decaF.getSourceLocation(),clazz.getName(),aBcelField.getFieldAsIs()); | |||
isChanged = true; | |||
modificationOccured = true; | |||
forRemoval.add(decaF); | |||
@@ -1301,7 +1298,7 @@ class BcelClassWeaver implements IClassWeaver { | |||
reportedProblems.add(uniqueID); | |||
reportedProblems.add(new Integer(itdfieldsig.hashCode()*deca.hashCode())); | |||
world.getLint().elementAlreadyAnnotated.signal( | |||
new String[]{rm.toString(),deca.getAnnotationTypeX().toString()}, | |||
new String[]{itdfieldsig.toString(),deca.getAnnotationTypeX().toString()}, | |||
rm.getSourceLocation(),new ISourceLocation[]{deca.getSourceLocation()}); | |||
} | |||
} | |||
@@ -1537,10 +1534,10 @@ class BcelClassWeaver implements IClassWeaver { | |||
// ignore | |||
} else if (targeter instanceof LineNumberTag) { | |||
// ignore | |||
} else if (targeter instanceof InstructionBranch && ((InstructionBranch)targeter).isGoto()) { | |||
// move it... | |||
targeter.updateTarget(element, monitorExitBlockStart); | |||
} else if (targeter instanceof BranchInstruction) { | |||
// } else if (targeter instanceof InstructionBranch && ((InstructionBranch)targeter).isGoto()) { | |||
// // move it... | |||
// targeter.updateTarget(element, monitorExitBlockStart); | |||
} else if (targeter instanceof InstructionBranch) { | |||
// move it | |||
targeter.updateTarget(element, monitorExitBlockStart); | |||
} else { | |||
@@ -1717,10 +1714,10 @@ class BcelClassWeaver implements IClassWeaver { | |||
// ignore | |||
} else if (targeter instanceof LineNumberTag) { | |||
// ignore | |||
} else if (targeter instanceof GOTO || targeter instanceof GOTO_W) { | |||
// move it... | |||
targeter.updateTarget(element, monitorExitBlockStart); | |||
} else if (targeter instanceof BranchInstruction) { | |||
// } else if (targeter instanceof GOTO || targeter instanceof GOTO_W) { | |||
// // move it... | |||
// targeter.updateTarget(element, monitorExitBlockStart); | |||
} else if (targeter instanceof InstructionBranch) { | |||
// move it | |||
targeter.updateTarget(element, monitorExitBlockStart); | |||
} else { | |||
@@ -1825,9 +1822,9 @@ class BcelClassWeaver implements IClassWeaver { | |||
// ignore | |||
} else if (targeter instanceof LineNumberTag) { | |||
// ignore | |||
} else if (targeter instanceof InstructionBranch && ((InstructionBranch)targeter).isGoto()) { | |||
// move it... | |||
targeter.updateTarget(element, monitorExitBlockStart); | |||
// } else if (targeter instanceof GOTO || targeter instanceof GOTO_W) { | |||
// // move it... | |||
// targeter.updateTarget(element, monitorExitBlockStart); | |||
} else if (targeter instanceof InstructionBranch) { | |||
// move it | |||
targeter.updateTarget(element, monitorExitBlockStart); | |||
@@ -1900,6 +1897,8 @@ class BcelClassWeaver implements IClassWeaver { | |||
{ | |||
Instruction fresh = Utility.copyInstruction(src.getInstruction()); | |||
InstructionHandle dest; | |||
// OPTIMIZE optimize this stuff? | |||
if (fresh.isConstantPoolInstruction()) { | |||
// need to reset index to go to new constant pool. This is totally | |||
// a computation leak... we're testing this LOTS of times. Sigh. | |||
@@ -2605,9 +2604,14 @@ class BcelClassWeaver implements IClassWeaver { | |||
// sets of synthetics aren't join points in 1.1 | |||
return; | |||
} else { | |||
match( | |||
BcelShadow.makeFieldSet(world, mg, ih, enclosingShadow), | |||
shadowAccumulator); | |||
// Fix for bug 172107 (similar the "get" fix for bug 109728) | |||
BcelShadow bs= | |||
BcelShadow.makeFieldSet(world, resolvedField, mg, ih, enclosingShadow); | |||
String cname = fi.getClassName(cpg); | |||
if (!resolvedField.getDeclaringType().getName().equals(cname)) { | |||
bs.setActualTargetType(cname); | |||
} | |||
match(bs, shadowAccumulator); | |||
} | |||
} | |||
@@ -2774,14 +2778,11 @@ class BcelClassWeaver implements IClassWeaver { | |||
ShadowMunger munger = (ShadowMunger)i.next(); | |||
ContextToken mungerMatchToken = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.MATCHING_POINTCUT, munger.getPointcut()); | |||
if (munger.match(shadow, world)) { | |||
WeaverMetrics.recordMatchResult(true);// Could pass: munger | |||
shadow.addMunger(munger); | |||
isMatched = true; | |||
if (shadow.getKind() == Shadow.StaticInitialization) { | |||
clazz.warnOnAddedStaticInitializer(shadow,munger.getSourceLocation()); | |||
} | |||
} else { | |||
WeaverMetrics.recordMatchResult(false); // Could pass: munger | |||
} | |||
CompilationAndWeavingContext.leavingPhase(mungerMatchToken); | |||
} |
@@ -10,7 +10,6 @@ | |||
* PARC initial implementation | |||
* ******************************************************************/ | |||
package org.aspectj.weaver.bcel; | |||
import java.util.Collections; | |||
@@ -36,7 +35,6 @@ import org.aspectj.weaver.World; | |||
import org.aspectj.weaver.AjAttribute.WeaverVersionInfo; | |||
import org.aspectj.weaver.bcel.BcelGenericSignatureToTypeXConverter.GenericSignatureFormatException; | |||
final class BcelField extends ResolvedMemberImpl { | |||
private static int AccSynthetic = 0x1000; | |||
@@ -56,7 +54,7 @@ final class BcelField extends ResolvedMemberImpl { | |||
super( | |||
FIELD, | |||
declaringType.getResolvedTypeX(), | |||
field.getAccessFlags(), | |||
field.getModifiers(), | |||
field.getName(), | |||
field.getSignature()); | |||
this.field = field; | |||
@@ -72,7 +70,7 @@ final class BcelField extends ResolvedMemberImpl { | |||
* constructed at runtime (so there is no .class file to retrieve). | |||
*/ | |||
BcelField(String declaringTypeName, Field field,World world) { | |||
super(FIELD,UnresolvedType.forName(declaringTypeName),field.getAccessFlags(),field.getName(),field.getSignature()); | |||
super(FIELD,UnresolvedType.forName(declaringTypeName),field.getModifiers(),field.getName(),field.getSignature()); | |||
this.field = field; | |||
this.world = world; | |||
this.bcelObjectType = null; |
@@ -255,11 +255,13 @@ public class BcelGenericSignatureToTypeXConverter { | |||
ReferenceType rt = (ReferenceType) aTypeX; | |||
TypeVariable[] typeVars = rt.getTypeVariables(); | |||
for (int i = 0; i < typeVars.length; i++) { | |||
if (typeVars[i].getUpperBound() instanceof FTPHolder) { | |||
Signature.FormalTypeParameter key = ((FTPHolder) typeVars[i].getUpperBound()).ftpToBeSubstituted; | |||
typeVars[i].setUpperBound((UnresolvedType)typeVariableResolutions.get(key)); | |||
} | |||
if (typeVars != null) { | |||
for (int i = 0; i < typeVars.length; i++) { | |||
if (typeVars[i].getUpperBound() instanceof FTPHolder) { | |||
Signature.FormalTypeParameter key = ((FTPHolder) typeVars[i].getUpperBound()).ftpToBeSubstituted; | |||
typeVars[i].setUpperBound((UnresolvedType) typeVariableResolutions.get(key)); | |||
} | |||
} | |||
} | |||
} | |||
@@ -10,7 +10,6 @@ | |||
* PARC initial implementation | |||
* ******************************************************************/ | |||
package org.aspectj.weaver.bcel; | |||
import java.lang.reflect.Modifier; | |||
@@ -19,6 +18,7 @@ import java.util.HashSet; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
import org.aspectj.apache.bcel.classfile.AnnotationDefault; | |||
import org.aspectj.apache.bcel.classfile.Attribute; | |||
import org.aspectj.apache.bcel.classfile.ExceptionTable; | |||
import org.aspectj.apache.bcel.classfile.GenericSignatureParser; | |||
@@ -31,13 +31,14 @@ import org.aspectj.apache.bcel.classfile.Method; | |||
import org.aspectj.apache.bcel.classfile.Signature; | |||
import org.aspectj.apache.bcel.classfile.Signature.TypeVariableSignature; | |||
import org.aspectj.apache.bcel.classfile.annotation.AnnotationGen; | |||
import org.aspectj.apache.bcel.classfile.annotation.ElementNameValuePairGen; | |||
import org.aspectj.bridge.ISourceLocation; | |||
import org.aspectj.bridge.SourceLocation; | |||
import org.aspectj.weaver.AjAttribute; | |||
import org.aspectj.weaver.AnnotationX; | |||
import org.aspectj.weaver.BCException; | |||
import org.aspectj.weaver.ISourceContext; | |||
import org.aspectj.weaver.Member; | |||
import org.aspectj.weaver.MemberKind; | |||
import org.aspectj.weaver.ResolvedMemberImpl; | |||
import org.aspectj.weaver.ResolvedPointcutDefinition; | |||
import org.aspectj.weaver.ResolvedType; | |||
@@ -52,15 +53,14 @@ public final class BcelMethod extends ResolvedMemberImpl { | |||
private Method method; | |||
// private AjAttribute.MethodDeclarationLineNumberAttribute declarationLineNumber; | |||
// private World world; | |||
private BcelObjectType bcelObjectType; | |||
public Member slimline() { | |||
if (!bcelObjectType.getWorld().isXnoInline()) return this; | |||
ResolvedMemberImpl mi = new ResolvedMemberImpl(kind,declaringType,modifiers,returnType,name,parameterTypes); | |||
mi.setParameterNames(getParameterNames()); | |||
return mi; | |||
} | |||
// public Member slimline() { | |||
// if (!bcelObjectType.getWorld().isXnoInline()) return this; | |||
// ResolvedMemberImpl mi = new ResolvedMemberImpl(kind,declaringType,modifiers,returnType,name,parameterTypes); | |||
// mi.setParameterNames(getParameterNames()); | |||
// return mi; | |||
// } | |||
// private AnnotationX[] annotations = null; | |||
// private UnresolvedType genericReturnType = null; | |||
@@ -75,6 +75,7 @@ public final class BcelMethod extends ResolvedMemberImpl { | |||
private static final String MAPKEY_GENERIC_PARAM_TYPES ="genericParameterTypes"; | |||
private static final String MAPKEY_ANNOTATIONS ="annotations"; | |||
private static final String MAPKEY_MD_LINE_NUMBER_ATTRIBUTE="mdLineNumberAttribute"; | |||
private AnnotationX[][] parameterAnnotations = null; | |||
// private AjAttribute.EffectiveSignatureAttribute effectiveSignature; | |||
// private ShadowMunger associatedShadowMunger; | |||
@@ -109,13 +110,12 @@ public final class BcelMethod extends ResolvedMemberImpl { | |||
(method.getName().equals("<clinit>") ? STATIC_INITIALIZATION : METHOD), | |||
declaringType.getResolvedTypeX(), | |||
declaringType.isInterface() | |||
? method.getAccessFlags() | Modifier.INTERFACE | |||
: method.getAccessFlags(), | |||
method.getName(), | |||
? method.getModifiers() | Modifier.INTERFACE | |||
: method.getModifiers(), | |||
method.getName(), | |||
method.getSignature()); | |||
this.method = method; | |||
this.sourceContext = declaringType.getResolvedTypeX().getSourceContext(); | |||
//this.world = declaringType.getResolvedTypeX().getWorld(); | |||
this.bcelObjectType = declaringType; | |||
unpackJavaAttributes(); | |||
unpackAjAttributes(bcelObjectType.getWorld()); | |||
@@ -152,6 +152,41 @@ public final class BcelMethod extends ResolvedMemberImpl { | |||
LocalVariableTable varTable = method.getLocalVariableTable(); | |||
int len = getArity(); | |||
if (varTable == null) { | |||
// do we have an annotation with the argNames value specified... | |||
if (hasAnnotations()) { | |||
AnnotationX[] axs = getAnnotations(); | |||
for (int i = 0; i < axs.length; i++) { | |||
AnnotationX annotationX = axs[i]; | |||
String typename = annotationX.getTypeName(); | |||
if (typename.equals("org.aspectj.lang.annotation.Pointcut") || | |||
typename.equals("org.aspectj.lang.annotation.Before") || | |||
typename.equals("org.aspectj.lang.annotation.Around") || | |||
typename.startsWith("org.aspectj.lang.annotation.After")) { | |||
AnnotationGen a = annotationX.getBcelAnnotation(); | |||
if (a!=null) { | |||
List values = a.getValues(); | |||
for (Iterator iterator = values.iterator(); iterator | |||
.hasNext();) { | |||
ElementNameValuePairGen nvPair = (ElementNameValuePairGen) iterator.next(); | |||
if (nvPair.getNameString().equals("argNames")) { | |||
String argNames = nvPair.getValue().stringifyValue(); | |||
StringTokenizer argNameTokenizer = new StringTokenizer(argNames," ,"); | |||
List argsList = new ArrayList(); | |||
while (argNameTokenizer.hasMoreTokens()) { | |||
argsList.add(argNameTokenizer.nextToken()); | |||
} | |||
int requiredCount = getParameterTypes().length; | |||
while (argsList.size()<requiredCount) { | |||
argsList.add("arg"+argsList.size()); | |||
} | |||
setParameterNames((String[])argsList.toArray(new String[]{})); | |||
return; | |||
} | |||
} | |||
} | |||
} | |||
} | |||
} | |||
setParameterNames(Utility.makeArgNames(len)); | |||
} else { | |||
UnresolvedType[] paramTypes = getParameterTypes(); | |||
@@ -228,6 +263,18 @@ public final class BcelMethod extends ResolvedMemberImpl { | |||
return null; | |||
} | |||
public String getAnnotationDefaultValue() { | |||
Attribute[] attrs = method.getAttributes(); | |||
for (int i = 0; i < attrs.length; i++) { | |||
Attribute attribute = attrs[i]; | |||
if (attribute.getName().equals("AnnotationDefault")) { | |||
AnnotationDefault def = (AnnotationDefault)attribute; | |||
return def.getElementValue().stringifyValue(); | |||
} | |||
} | |||
return null; | |||
} | |||
// for testing - use with the method above | |||
public String[] getAttributeNames(boolean onlyIncludeAjOnes) { | |||
Attribute[] as = method.getAttributes(); | |||
@@ -304,7 +351,7 @@ public final class BcelMethod extends ResolvedMemberImpl { | |||
return ret; | |||
} | |||
public Kind getKind() { | |||
public MemberKind getKind() { | |||
if ((bitflags&HAS_ASSOCIATED_SHADOWMUNGER)!=0) { | |||
return ADVICE; | |||
} else { | |||
@@ -313,7 +360,7 @@ public final class BcelMethod extends ResolvedMemberImpl { | |||
} | |||
public boolean hasAnnotation(UnresolvedType ofType) { | |||
ensureAnnotationTypesRetrieved(); | |||
ensureAnnotationsRetrieved(); | |||
for (Iterator iter = annotationTypes.iterator(); iter.hasNext();) { | |||
ResolvedType aType = (ResolvedType) iter.next(); | |||
if (aType.equals(ofType)) return true; | |||
@@ -322,7 +369,7 @@ public final class BcelMethod extends ResolvedMemberImpl { | |||
} | |||
public AnnotationX[] getAnnotations() { | |||
ensureAnnotationTypesRetrieved(); | |||
ensureAnnotationsRetrieved(); | |||
if ((bitflags&HAS_ANNOTATIONS)!=0) { | |||
return (AnnotationX[])metaData.get(MAPKEY_ANNOTATIONS); | |||
} else { | |||
@@ -332,14 +379,24 @@ public final class BcelMethod extends ResolvedMemberImpl { | |||
} | |||
public ResolvedType[] getAnnotationTypes() { | |||
ensureAnnotationTypesRetrieved(); | |||
ensureAnnotationsRetrieved(); | |||
ResolvedType[] ret = new ResolvedType[annotationTypes.size()]; | |||
annotationTypes.toArray(ret); | |||
return ret; | |||
} | |||
public AnnotationX getAnnotationOfType(UnresolvedType ofType) { | |||
ensureAnnotationsRetrieved(); | |||
if ((bitflags&HAS_ANNOTATIONS)==0) return null; | |||
AnnotationX[] annos = (AnnotationX[])metaData.get(MAPKEY_ANNOTATIONS); | |||
for (int i=0; i<annos.length; i++) { | |||
if (annos[i].getTypeName().equals(ofType.getName())) return annos[i]; | |||
} | |||
return null; | |||
} | |||
public void addAnnotation(AnnotationX annotation) { | |||
ensureAnnotationTypesRetrieved(); | |||
ensureAnnotationsRetrieved(); | |||
if ((bitflags&HAS_ANNOTATIONS)==0) { | |||
AnnotationX[] ret = new AnnotationX[1]; | |||
ret[0]=annotation; | |||
@@ -365,7 +422,7 @@ public final class BcelMethod extends ResolvedMemberImpl { | |||
// FIXME CUSTARD | |||
} | |||
private void ensureAnnotationTypesRetrieved() { | |||
private void ensureAnnotationsRetrieved() { | |||
if (method == null) return; // must be ok, we have evicted it | |||
if ((bitflags&HAVE_DETERMINED_ANNOTATIONS)!=0) return; | |||
bitflags|=HAVE_DETERMINED_ANNOTATIONS; | |||
@@ -387,6 +444,39 @@ public final class BcelMethod extends ResolvedMemberImpl { | |||
// } | |||
} | |||
private void ensureParameterAnnotationsRetrieved() { | |||
if (method == null) return; // must be ok, we have evicted it | |||
AnnotationGen[][] pAnns = method.getParameterAnnotations(); | |||
if (parameterAnnotationTypes==null || pAnns.length!=parameterAnnotationTypes.length) { | |||
if (pAnns == Method.NO_PARAMETER_ANNOTATIONS) { | |||
parameterAnnotationTypes = BcelMethod.NO_PARAMETER_ANNOTATION_TYPES; | |||
parameterAnnotations = BcelMethod.NO_PARAMETER_ANNOTATIONXS; | |||
} else { | |||
AnnotationGen annos[][] = method.getParameterAnnotations(); | |||
parameterAnnotations = new AnnotationX[annos.length][]; | |||
parameterAnnotationTypes = new ResolvedType[annos.length][]; | |||
for (int i=0;i<annos.length;i++) { | |||
parameterAnnotations[i] = new AnnotationX[annos[i].length]; | |||
parameterAnnotationTypes[i] = new ResolvedType[annos[i].length]; | |||
for (int j=0;j<annos[i].length;j++) { | |||
parameterAnnotations[i][j] = new AnnotationX(annos[i][j],bcelObjectType.getWorld()); | |||
parameterAnnotationTypes[i][j] = bcelObjectType.getWorld().resolve(UnresolvedType.forSignature(annos[i][j].getTypeSignature())); | |||
} | |||
} | |||
} | |||
} | |||
} | |||
public AnnotationX[][] getParameterAnnotations() { | |||
ensureParameterAnnotationsRetrieved(); | |||
return parameterAnnotations; | |||
} | |||
public ResolvedType[][] getParameterAnnotationTypes() { | |||
ensureParameterAnnotationsRetrieved(); | |||
return parameterAnnotationTypes; | |||
} | |||
/** | |||
* A method can be parameterized if it has one or more generic | |||
@@ -406,6 +496,9 @@ public final class BcelMethod extends ResolvedMemberImpl { | |||
// return genericParameterTypes; | |||
} | |||
/** | |||
* Return the parameterized/generic return type or the normal return type if the method is not generic. | |||
*/ | |||
public UnresolvedType getGenericReturnType() { | |||
unpackGenericSignature(); | |||
if ((bitflags&HAS_GENERIC_RETPARAM_TYPES)==0) return getReturnType(); | |||
@@ -507,7 +600,8 @@ public final class BcelMethod extends ResolvedMemberImpl { | |||
if (method != null) { | |||
unpackGenericSignature(); | |||
unpackJavaAttributes(); | |||
ensureAnnotationTypesRetrieved(); | |||
ensureAnnotationsRetrieved(); | |||
ensureParameterAnnotationsRetrieved(); | |||
determineParameterNames(); | |||
// this.sourceContext = SourceContextImpl.UNKNOWN_SOURCE_CONTEXT; | |||
method = null; | |||
@@ -567,4 +661,4 @@ public final class BcelMethod extends ResolvedMemberImpl { | |||
o.getMethod().getCode().getCodeString()); | |||
} | |||
} | |||
} |
@@ -31,6 +31,7 @@ import org.aspectj.apache.bcel.classfile.annotation.AnnotationGen; | |||
import org.aspectj.apache.bcel.classfile.annotation.ArrayElementValueGen; | |||
import org.aspectj.apache.bcel.classfile.annotation.ElementNameValuePairGen; | |||
import org.aspectj.apache.bcel.classfile.annotation.ElementValueGen; | |||
import org.aspectj.apache.bcel.classfile.annotation.EnumElementValueGen; | |||
import org.aspectj.bridge.IMessageHandler; | |||
import org.aspectj.weaver.AbstractReferenceTypeDelegate; | |||
import org.aspectj.weaver.AjAttribute; | |||
@@ -148,13 +149,10 @@ public class BcelObjectType extends AbstractReferenceTypeDelegate { | |||
// ((SourceContextImpl)sourceContext).setSourceFileName(javaClass.getSourceFileName()); | |||
// } | |||
setSourcefilename(javaClass.getSourceFileName()); | |||
} | |||
// repeat initialization | |||
public void setJavaClass(JavaClass newclass) { | |||
// if (this.getResolvedTypeX().isAspect()) | |||
// new RuntimeException("bcot: "+this.hashCode()+" Set javaclass for aspect").printStackTrace(); | |||
this.javaClass = newclass; | |||
resetState(); | |||
initializeFromJavaclass(); | |||
@@ -166,7 +164,7 @@ public class BcelObjectType extends AbstractReferenceTypeDelegate { | |||
isAnnotation = javaClass.isAnnotation(); | |||
isAnonymous = javaClass.isAnonymous(); | |||
isNested = javaClass.isNested(); | |||
modifiers = javaClass.getAccessFlags(); | |||
modifiers = javaClass.getModifiers(); | |||
superclassName = javaClass.getSuperclassName(); | |||
className = javaClass.getClassName(); | |||
cachedGenericClassTypeSignature = null; | |||
@@ -201,7 +199,7 @@ public class BcelObjectType extends AbstractReferenceTypeDelegate { | |||
ResolvedType res = getResolvedTypeX().getWorld().resolve(UnresolvedType.forSignature(superclassSignature)); | |||
return res; | |||
} | |||
public World getWorld() { | |||
return getResolvedTypeX().getWorld(); | |||
} | |||
@@ -482,7 +480,7 @@ public class BcelObjectType extends AbstractReferenceTypeDelegate { | |||
public LazyClassGen getLazyClassGen() { | |||
LazyClassGen ret = lazyClassGen; | |||
if (ret == null) { | |||
// System.err.println("creating lazy class gen for: " + this); | |||
//System.err.println("creating lazy class gen for: " + this); | |||
ret = new LazyClassGen(this); | |||
//ret.print(System.err); | |||
//System.err.println("made LCG from : " + this.getJavaClass().getSuperclassName ); | |||
@@ -583,8 +581,8 @@ public class BcelObjectType extends AbstractReferenceTypeDelegate { | |||
List values = ax.getBcelAnnotation().getValues(); | |||
for (Iterator it = values.iterator(); it.hasNext();) { | |||
ElementNameValuePairGen element = (ElementNameValuePairGen) it.next(); | |||
ElementValueGen v = element.getValue(); | |||
retentionPolicy = v.stringifyValue(); | |||
EnumElementValueGen v = (EnumElementValueGen)element.getValue(); | |||
retentionPolicy = v.getEnumValueString(); | |||
return retentionPolicy; | |||
} | |||
} | |||
@@ -619,7 +617,7 @@ public class BcelObjectType extends AbstractReferenceTypeDelegate { | |||
ElementValueGen[] evs = arrayValue.getElementValuesArray(); | |||
if (evs!=null) { | |||
for (int j = 0; j < evs.length; j++) { | |||
String targetKind = evs[j].stringifyValue(); | |||
String targetKind = ((EnumElementValueGen)evs[j]).getEnumValueString(); | |||
if (targetKind.equals("ANNOTATION_TYPE")) { targetKinds.add(AnnotationTargetKind.ANNOTATION_TYPE); | |||
} else if (targetKind.equals("CONSTRUCTOR")) { targetKinds.add(AnnotationTargetKind.CONSTRUCTOR); | |||
} else if (targetKind.equals("FIELD")) { targetKinds.add(AnnotationTargetKind.FIELD); | |||
@@ -783,7 +781,6 @@ public class BcelObjectType extends AbstractReferenceTypeDelegate { | |||
public void evictWeavingState() { | |||
// Can't chuck all this away | |||
// if (getResolvedTypeX().isAspect()) System.err.println("Eviction of "+getResolvedTypeX().getName()); | |||
if (getResolvedTypeX().getWorld().couldIncrementalCompileFollow()) return; | |||
if (javaClass != null) { | |||
@@ -805,16 +802,12 @@ public class BcelObjectType extends AbstractReferenceTypeDelegate { | |||
weaverState.setReweavable(false); | |||
weaverState.setUnwovenClassFileData(null); | |||
} | |||
for (int i = methods.length - 1; i >= 0; i--) { methods[i].evictWeavingState();} | |||
for (int i = methods.length - 1; i >= 0; i--) methods[i].evictWeavingState(); | |||
for (int i = fields.length - 1; i >= 0; i--) fields[i].evictWeavingState(); | |||
// if (getResolvedTypeX().isAspect()) System.err.println("nulling jc for "+getResolvedTypeX().getName()); | |||
javaClass = null; | |||
// setSourceContext(SourceContextImpl.UNKNOWN_SOURCE_CONTEXT); // bit naughty | |||
// interfaces=null; // force reinit - may get us the right instances! | |||
// superClass=null; | |||
// if this is a class, make sure aspects are re-evicted if necessary | |||
// if (!getResolvedTypeX().isAspect()) getWorld().ensureAspectsEvicted(); | |||
} | |||
} | |||
@@ -584,7 +584,7 @@ public class BcelPerClauseAspectAdder extends BcelTypeMunger { | |||
methodGen.makeSynthetic(); | |||
} | |||
methodGen.addAttribute( | |||
BcelAttributes.bcelAttribute( | |||
Utility.bcelAttribute( | |||
new AjAttribute.AjSynthetic(), | |||
methodGen.getEnclosingClass().getConstantPool() | |||
) |
@@ -43,7 +43,9 @@ import org.aspectj.apache.bcel.generic.MULTIANEWARRAY; | |||
import org.aspectj.apache.bcel.generic.ObjectType; | |||
import org.aspectj.apache.bcel.generic.TargetLostException; | |||
import org.aspectj.apache.bcel.generic.Type; | |||
import org.aspectj.bridge.IMessage; | |||
import org.aspectj.bridge.ISourceLocation; | |||
import org.aspectj.bridge.MessageUtil; | |||
import org.aspectj.weaver.Advice; | |||
import org.aspectj.weaver.AdviceKind; | |||
import org.aspectj.weaver.AjcMemberMaker; | |||
@@ -51,6 +53,7 @@ import org.aspectj.weaver.BCException; | |||
import org.aspectj.weaver.IntMap; | |||
import org.aspectj.weaver.Member; | |||
import org.aspectj.weaver.MemberImpl; | |||
import org.aspectj.weaver.MemberKind; | |||
import org.aspectj.weaver.NameMangler; | |||
import org.aspectj.weaver.NewConstructorTypeMunger; | |||
import org.aspectj.weaver.NewFieldTypeMunger; | |||
@@ -127,7 +130,6 @@ public class BcelShadow extends Shadow { | |||
private ShadowRange range; | |||
private final BcelWorld world; | |||
private final LazyMethodGen enclosingMethod; | |||
// private boolean fallsThrough; //XXX not used anymore | |||
// SECRETAPI - for testing, this will tell us if the optimization succeeded *on the last shadow processed* | |||
public static boolean appliedLazyTjpOptimization; | |||
@@ -136,24 +138,15 @@ public class BcelShadow extends Shadow { | |||
// from the signature (pr109728) (1.4 declaring type issue) | |||
private String actualInstructionTargetType; | |||
// ---- initialization | |||
/** | |||
* This generates an unassociated shadow, rooted in a particular method but not rooted | |||
* This generates an unassociated shadow, rooted in a particular method but not rooted | |||
* to any particular point in the code. It should be given to a rooted ShadowRange | |||
* in the {@link ShadowRange#associateWithShadow(BcelShadow)} method. | |||
*/ | |||
public BcelShadow( | |||
BcelWorld world, | |||
Kind kind, | |||
Member signature, | |||
LazyMethodGen enclosingMethod, | |||
BcelShadow enclosingShadow) | |||
{ | |||
public BcelShadow(BcelWorld world, Kind kind, Member signature, LazyMethodGen enclosingMethod, BcelShadow enclosingShadow) { | |||
super(kind, signature, enclosingShadow); | |||
this.world = world; | |||
this.enclosingMethod = enclosingMethod; | |||
// fallsThrough = kind.argsOnStack(); | |||
} | |||
// ---- copies all state, including Shadow's mungers... | |||
@@ -178,8 +171,6 @@ public class BcelShadow extends Shadow { | |||
return world; | |||
} | |||
private void deleteNewAndDup() { | |||
final ConstantPool cpg = getEnclosingClass().getConstantPool(); | |||
int depth = 1; | |||
@@ -976,6 +967,7 @@ public class BcelShadow extends Shadow { | |||
public static BcelShadow makeFieldSet( | |||
BcelWorld world, | |||
ResolvedMember field, | |||
LazyMethodGen enclosingMethod, | |||
InstructionHandle setHandle, | |||
BcelShadow enclosingShadow) | |||
@@ -985,9 +977,10 @@ public class BcelShadow extends Shadow { | |||
new BcelShadow( | |||
world, | |||
FieldSet, | |||
BcelWorld.makeFieldJoinPointSignature( | |||
enclosingMethod.getEnclosingClass(), | |||
(FieldInstruction) setHandle.getInstruction()), | |||
field, | |||
// BcelWorld.makeFieldJoinPointSignature( | |||
// enclosingMethod.getEnclosingClass(), | |||
// (FieldInstruction) setHandle.getInstruction()), | |||
enclosingMethod, | |||
enclosingShadow); | |||
ShadowRange r = new ShadowRange(body); | |||
@@ -1529,7 +1522,7 @@ public class BcelShadow extends Shadow { | |||
} | |||
} | |||
protected Member getRelevantMember(Member foundMember, Member relevantMember, ResolvedType relevantType){ | |||
protected ResolvedMember getRelevantMember(ResolvedMember foundMember, Member relevantMember, ResolvedType relevantType){ | |||
if (foundMember != null){ | |||
return foundMember; | |||
} | |||
@@ -1567,7 +1560,7 @@ public class BcelShadow extends Shadow { | |||
return foundMember; | |||
} | |||
protected ResolvedType [] getAnnotations(Member foundMember, Member relevantMember, ResolvedType relevantType){ | |||
protected ResolvedType [] getAnnotations(ResolvedMember foundMember, Member relevantMember, ResolvedType relevantType){ | |||
if (foundMember == null){ | |||
// check the ITD'd dooberries | |||
List mungers = relevantType.resolve(world).getInterTypeMungers(); | |||
@@ -1606,27 +1599,30 @@ public class BcelShadow extends Shadow { | |||
// by determining what "kind" of shadow we are, we can find out the | |||
// annotations on the appropriate element (method, field, constructor, type). | |||
// Then create one BcelVar entry in the map for each annotation, keyed by | |||
// annotation type (UnresolvedType). | |||
// annotation type. | |||
// FIXME asc Refactor this code, there is duplication | |||
ResolvedType[] annotations = null; | |||
Member relevantMember = getSignature(); | |||
ResolvedType relevantType = relevantMember.getDeclaringType().resolve(world); | |||
if (relevantType.isRawType() || relevantType.isParameterizedType()) relevantType = relevantType.getGenericType(); | |||
// Member relevantMember = getSignature(); | |||
Member shadowSignature = getSignature(); | |||
Member annotationHolder = getSignature(); | |||
ResolvedType relevantType = shadowSignature.getDeclaringType().resolve(world); | |||
if (relevantType.isRawType() || relevantType.isParameterizedType()) relevantType = relevantType.getGenericType(); | |||
if (getKind() == Shadow.StaticInitialization) { | |||
annotations = relevantType.resolve(world).getAnnotationTypes(); | |||
} else if (getKind() == Shadow.MethodCall || getKind() == Shadow.ConstructorCall) { | |||
Member foundMember = findMethod2(relevantType.resolve(world).getDeclaredMethods(),getSignature()); | |||
annotations = getAnnotations(foundMember, relevantMember, relevantType); | |||
relevantMember = getRelevantMember(foundMember,relevantMember,relevantType); | |||
relevantType = relevantMember.getDeclaringType().resolve(world); | |||
ResolvedMember foundMember = findMethod2(relevantType.resolve(world).getDeclaredMethods(),getSignature()); | |||
annotations = getAnnotations(foundMember, shadowSignature, relevantType); | |||
annotationHolder = getRelevantMember(foundMember,shadowSignature,relevantType); | |||
relevantType = annotationHolder.getDeclaringType().resolve(world); | |||
} else if (getKind() == Shadow.FieldSet || getKind() == Shadow.FieldGet) { | |||
relevantMember = findField(relevantType.getDeclaredFields(),getSignature()); | |||
annotationHolder = findField(relevantType.getDeclaredFields(),getSignature()); | |||
if (relevantMember==null) { | |||
if (annotationHolder==null) { | |||
// check the ITD'd dooberries | |||
List mungers = relevantType.resolve(world).getInterTypeMungers(); | |||
for (Iterator iter = mungers.iterator(); iter.hasNext();) { | |||
@@ -1638,21 +1634,21 @@ public class BcelShadow extends Shadow { | |||
ResolvedMember rmm = findMethod(typeMunger.getAspectType(),ajcMethod); | |||
if (fakerm.equals(getSignature())) { | |||
relevantType = typeMunger.getAspectType(); | |||
relevantMember = rmm; | |||
annotationHolder = rmm; | |||
} | |||
} | |||
} | |||
} | |||
annotations = relevantMember.getAnnotationTypes(); | |||
annotations = ((ResolvedMember)annotationHolder).getAnnotationTypes(); | |||
} else if (getKind() == Shadow.MethodExecution || getKind() == Shadow.ConstructorExecution || | |||
getKind() == Shadow.AdviceExecution) { | |||
//ResolvedMember rm[] = relevantType.getDeclaredMethods(); | |||
Member foundMember = findMethod2(relevantType.getDeclaredMethods(),getSignature()); | |||
ResolvedMember foundMember = findMethod2(relevantType.getDeclaredMethods(),getSignature()); | |||
annotations = getAnnotations(foundMember, relevantMember, relevantType); | |||
relevantMember = foundMember; | |||
relevantMember = getRelevantMember(foundMember, relevantMember,relevantType); | |||
annotations = getAnnotations(foundMember, shadowSignature, relevantType); | |||
annotationHolder = foundMember; | |||
annotationHolder = getRelevantMember(foundMember, annotationHolder,relevantType); | |||
} else if (getKind() == Shadow.ExceptionHandler) { | |||
relevantType = getSignature().getParameterTypes()[0].resolve(world); | |||
@@ -1670,7 +1666,7 @@ public class BcelShadow extends Shadow { | |||
for (int i = 0; i < annotations.length; i++) { | |||
ResolvedType aTX = annotations[i]; | |||
KindedAnnotationAccessVar kaav = new KindedAnnotationAccessVar(getKind(),aTX.resolve(world),relevantType,relevantMember); | |||
AnnotationAccessVar kaav = new AnnotationAccessVar(getKind(),aTX.resolve(world),relevantType,annotationHolder); | |||
kindedAnnotationVars.put(aTX,kaav); | |||
} | |||
} | |||
@@ -1718,7 +1714,7 @@ public class BcelShadow extends Shadow { | |||
for (int i = 0; i < annotations.length; i++) { | |||
ResolvedType ann = annotations[i]; | |||
Kind k = Shadow.StaticInitialization; | |||
withinAnnotationVars.put(ann,new KindedAnnotationAccessVar(k,ann,getEnclosingType(),null)); | |||
withinAnnotationVars.put(ann,new AnnotationAccessVar(k,ann,getEnclosingType(),null)); | |||
} | |||
} | |||
@@ -1733,7 +1729,7 @@ public class BcelShadow extends Shadow { | |||
Kind k = (getEnclosingMethod().getMemberView().getKind()==Member.CONSTRUCTOR? | |||
Shadow.ConstructorExecution:Shadow.MethodExecution); | |||
withincodeAnnotationVars.put(ann, | |||
new KindedAnnotationAccessVar(k,ann,getEnclosingType(),getEnclosingCodeSignature())); | |||
new AnnotationAccessVar(k,ann,getEnclosingType(),getEnclosingCodeSignature())); | |||
} | |||
} | |||
@@ -1767,36 +1763,49 @@ public class BcelShadow extends Shadow { | |||
* advice specified one. | |||
*/ | |||
public void weaveAfterReturning(BcelAdvice munger) { | |||
List returns = findReturnInstructions(); | |||
boolean hasReturnInstructions = !returns.isEmpty(); | |||
// list of instructions that handle the actual return from the join point | |||
InstructionList retList = new InstructionList(); | |||
// variable that holds the return value | |||
BcelVar returnValueVar = null; | |||
if (hasReturnInstructions) { | |||
returnValueVar = generateReturnInstructions(returns,retList); | |||
} else { | |||
// we need at least one instruction, as the target for jumps | |||
retList.append(InstructionConstants.NOP); | |||
} | |||
// list of instructions for dispatching to the advice itself | |||
InstructionList advice = getAfterReturningAdviceDispatchInstructions( | |||
munger, retList.getStart()); | |||
if (hasReturnInstructions) { | |||
InstructionHandle gotoTarget = advice.getStart(); | |||
for (Iterator i = returns.iterator(); i.hasNext();) { | |||
InstructionHandle ih = (InstructionHandle) i.next(); | |||
retargetReturnInstruction(munger.hasExtraParameter(), returnValueVar, gotoTarget, ih); | |||
} | |||
} | |||
range.append(advice); | |||
range.append(retList); | |||
try { | |||
List returns = findReturnInstructions(); | |||
boolean hasReturnInstructions = !returns.isEmpty(); | |||
// list of instructions that handle the actual return from the join point | |||
InstructionList retList = new InstructionList(); | |||
// variable that holds the return value | |||
BcelVar returnValueVar = null; | |||
if (hasReturnInstructions) { | |||
returnValueVar = generateReturnInstructions(returns,retList); | |||
} else { | |||
// we need at least one instruction, as the target for jumps | |||
retList.append(InstructionConstants.NOP); | |||
} | |||
// list of instructions for dispatching to the advice itself | |||
InstructionList advice = getAfterReturningAdviceDispatchInstructions( | |||
munger, retList.getStart()); | |||
if (hasReturnInstructions) { | |||
InstructionHandle gotoTarget = advice.getStart(); | |||
for (Iterator i = returns.iterator(); i.hasNext();) { | |||
InstructionHandle ih = (InstructionHandle) i.next(); | |||
retargetReturnInstruction(munger.hasExtraParameter(), returnValueVar, gotoTarget, ih); | |||
} | |||
} | |||
range.append(advice); | |||
range.append(retList); | |||
} catch (RuntimeException e) { | |||
StringBuffer sb = new StringBuffer(); | |||
sb.append("Unexpected runtime exception occurred in BcelShadow.weaveAfterReturning()\n"); | |||
sb.append("shadow is '"+toString()+"'\n"); | |||
sb.append("method is '"+enclosingMethod+"'\n"); | |||
sb.append("enclosing shadow is '"+enclosingShadow+"'\n"); | |||
sb.append("range is '"+range+"'\n"); | |||
sb.append("munger is '"+munger+"'\n"); | |||
IMessage m = MessageUtil.abort(sb.toString(), e); | |||
world.getMessageHandler().handleMessage(m); | |||
throw e; | |||
} | |||
} | |||
/** | |||
@@ -2366,7 +2375,17 @@ public class BcelShadow extends Shadow { | |||
extraParamOffset += thisJoinPointVar.getType().getSize(); | |||
} | |||
Type[] adviceParameterTypes = adviceMethod.getArgumentTypes(); | |||
// We use the munger signature here because it allows for any parameterization of the mungers pointcut that | |||
// may have occurred ie. if the pointcut is p(T t) in the super aspect and that has become p(Foo t) in the sub aspect | |||
// then here the munger signature will have 'Foo' as an argument in it whilst the adviceMethod argument type will be 'Object' - since | |||
// it represents the advice method in the superaspect which uses the erasure of the type variable p(Object t) - see pr174449. | |||
Type[] adviceParameterTypes = | |||
BcelWorld.makeBcelTypes(munger.getSignature().getParameterTypes()); | |||
// adviceMethod.getArgumentTypes(); | |||
adviceMethod.getArgumentTypes(); // forces initialization ... dont like this but seems to be required for some tests to pass, I think that means | |||
// there is a LazyMethodGen method that is not correctly setup to call initialize() when it is invoked - but I dont have | |||
// time right now to discover which | |||
Type[] extractedMethodParameterTypes = extractedMethod.getArgumentTypes(); | |||
Type[] parameterTypes = | |||
new Type[extractedMethodParameterTypes.length | |||
@@ -2500,7 +2519,7 @@ public class BcelShadow extends Shadow { | |||
// call to the extracted method. | |||
// inlining support for code style aspects | |||
if (!munger.getConcreteAspect().isAnnotationStyleAspect()) { | |||
if (!munger.getDeclaringType().isAnnotationStyleAspect()) { | |||
String proceedName = | |||
NameMangler.proceedMethodName(munger.getSignature().getName()); | |||
@@ -3057,7 +3076,7 @@ public class BcelShadow extends Shadow { | |||
if (munger.getConcreteAspect()!=null && munger.getConcreteAspect().isAnnotationStyleAspect() | |||
&& munger.getDeclaringAspect()!=null && munger.getDeclaringAspect().resolve(world).isAnnotationStyleAspect()) { | |||
// stick the bitflags on the stack and call the variant of linkClosureAndJoinPoint that takes an int | |||
closureInstantiation.append(fact.createConstant(new Integer(bitflags))); | |||
closureInstantiation.append(fact.createConstant(Integer.valueOf(bitflags))); | |||
closureInstantiation.append(Utility.createInvoke( | |||
getFactory(), | |||
getWorld(), | |||
@@ -3428,12 +3447,12 @@ public class BcelShadow extends Shadow { | |||
if (targetVar != null && targetVar != thisVar) { | |||
UnresolvedType targetType = getTargetType(); | |||
targetType = ensureTargetTypeIsCorrect(targetType); | |||
// see pr109728 - this fixes the case when the declaring class is sometype 'X' but the getfield | |||
// see pr109728,pr229910 - this fixes the case when the declaring class is sometype 'X' but the (gs)etfield | |||
// in the bytecode refers to a subtype of 'X'. This makes sure we use the type originally | |||
// mentioned in the fieldget instruction as the method parameter and *not* the type upon which the | |||
// field is declared because when the instructions are extracted into the new around body, | |||
// they will still refer to the subtype. | |||
if (getKind()==FieldGet && getActualTargetType()!=null && | |||
if ((getKind()==FieldGet || getKind()==FieldSet) && getActualTargetType()!=null && | |||
!getActualTargetType().equals(targetType.getName())) { | |||
targetType = UnresolvedType.forName(getActualTargetType()).resolve(world); | |||
} |
@@ -17,6 +17,7 @@ package org.aspectj.weaver.bcel; | |||
import java.lang.reflect.Modifier; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.Set; | |||
import org.aspectj.apache.bcel.Constants; | |||
@@ -332,25 +333,24 @@ public class BcelTypeMunger extends ConcreteTypeMunger { | |||
*/ | |||
private boolean enforceDecpRule4_compatibleReturnTypes(BcelClassWeaver weaver, ResolvedMember superMethod, LazyMethodGen subMethod) { | |||
boolean cont = true; | |||
String superReturnTypeSig = superMethod.getReturnType().getSignature(); | |||
String subReturnTypeSig = subMethod.getReturnType().getSignature(); | |||
superReturnTypeSig = superReturnTypeSig.replace('.','/'); | |||
subReturnTypeSig = subReturnTypeSig.replace('.','/'); | |||
if (!superReturnTypeSig.equals(subReturnTypeSig)) { | |||
// Allow for covariance - wish I could test this (need Java5...) | |||
String superReturnTypeSig = superMethod.getGenericReturnType().getSignature(); // eg. Pjava/util/Collection<LFoo;> | |||
String subReturnTypeSig = subMethod.getGenericReturnTypeSignature(); | |||
superReturnTypeSig = superReturnTypeSig.replace('.', '/'); | |||
subReturnTypeSig = subReturnTypeSig.replace('.', '/'); | |||
if (!superReturnTypeSig.equals(subReturnTypeSig)) { | |||
// Check for covariance | |||
ResolvedType subType = weaver.getWorld().resolve(subMethod.getReturnType()); | |||
ResolvedType superType = weaver.getWorld().resolve(superMethod.getReturnType()); | |||
if (!superType.isAssignableFrom(subType)) { | |||
ISourceLocation sloc = subMethod.getSourceLocation(); | |||
weaver.getWorld().getMessageHandler().handleMessage(MessageUtil.error( | |||
"The return type is incompatible with "+superMethod.getDeclaringType()+"."+superMethod.getName()+superMethod.getParameterSignature(), | |||
subMethod.getSourceLocation())); | |||
"The return type is incompatible with " + superMethod.getDeclaringType() + "." + superMethod.getName() | |||
+ superMethod.getParameterSignature(), subMethod.getSourceLocation())); | |||
// this just might be a better error message... | |||
// "The return type '"+subReturnTypeSig+"' is incompatible with the overridden method "+superMethod.getDeclaringType()+"."+ | |||
// superMethod.getName()+superMethod.getParameterSignature()+" which returns '"+superReturnTypeSig+"'", | |||
cont=false; | |||
} | |||
} | |||
} | |||
return cont; | |||
} | |||
@@ -379,11 +379,14 @@ public class BcelTypeMunger extends ConcreteTypeMunger { | |||
} | |||
/** | |||
* Search the specified type for a particular method - do not use the return value in the comparison as it is not | |||
* considered for overriding. | |||
*/ | |||
private LazyMethodGen findMatchingMethod(LazyClassGen newParentTarget, ResolvedMember m) { | |||
LazyMethodGen found = null; | |||
// Search the type for methods overriding super methods (methods that come from the new parent) | |||
// Don't use the return value in the comparison as overriding doesnt | |||
for (Iterator i = newParentTarget.getMethodGens().iterator(); i.hasNext() && found==null;) { | |||
List methodGens = newParentTarget.getMethodGens(); | |||
for (Iterator i = methodGens.iterator(); i.hasNext() && found == null;) { | |||
LazyMethodGen gen = (LazyMethodGen) i.next(); | |||
if (gen.getName().equals(m.getName()) && | |||
gen.getParameterSignature().equals(m.getParameterSignature())) { | |||
@@ -1088,6 +1091,27 @@ public class BcelTypeMunger extends ConcreteTypeMunger { | |||
clazz.addMethodGen(bridgeMethod); | |||
} | |||
// Unlike toString() on a member, this does not include the declaring type | |||
private String stringifyMember(ResolvedMember member) { | |||
StringBuffer buf = new StringBuffer(); | |||
buf.append(member.getReturnType().getName()); | |||
buf.append(' '); | |||
buf.append(member.getName()); | |||
if (member.getKind() != Member.FIELD) { | |||
buf.append("("); | |||
UnresolvedType[] params = member.getParameterTypes(); | |||
if (params.length != 0) { | |||
buf.append(params[0]); | |||
for (int i=1, len = params.length; i < len; i++) { | |||
buf.append(", "); | |||
buf.append(params[i].getName()); | |||
} | |||
} | |||
buf.append(")"); | |||
} | |||
return buf.toString(); | |||
} | |||
private boolean mungeMethodDelegate(BcelClassWeaver weaver, MethodDelegateTypeMunger munger) { | |||
ResolvedMember introduced = munger.getSignature(); | |||
@@ -1103,6 +1127,34 @@ public class BcelTypeMunger extends ConcreteTypeMunger { | |||
boolean shouldApply = munger.matches(weaver.getLazyClassGen().getType(), aspectType); | |||
if (shouldApply) { | |||
// If no implementation class was specified, the intention was that the types matching the pattern | |||
// already implemented the interface, let's check that now! | |||
if (munger.getImplClassName()==null) { | |||
boolean isOK = false; | |||
List/*LazyMethodGen*/ existingMethods = gen.getMethodGens(); | |||
for (Iterator i = existingMethods.iterator(); i.hasNext() && !isOK;) { | |||
LazyMethodGen m = (LazyMethodGen) i.next(); | |||
if (m.getName().equals(introduced.getName()) && | |||
m.getParameterSignature().equals(introduced.getParameterSignature()) && | |||
m.getReturnType().equals(introduced.getReturnType())) { | |||
isOK = true; | |||
} | |||
} | |||
if (!isOK) { | |||
// the class does not implement this method, they needed to supply a default impl class | |||
IMessage msg = new Message("@DeclareParents: No defaultImpl was specified but the type '"+gen.getName()+ | |||
"' does not implement the method '"+stringifyMember(introduced)+"' defined on the interface '"+introduced.getDeclaringType()+"'", | |||
weaver.getLazyClassGen().getType().getSourceLocation(),true,new ISourceLocation[]{munger.getSourceLocation()}); | |||
weaver.getWorld().getMessageHandler().handleMessage(msg); | |||
return false; | |||
} | |||
return true; | |||
} | |||
LazyMethodGen mg = new LazyMethodGen( | |||
introduced.getModifiers() - Modifier.ABSTRACT, | |||
BcelWorld.makeBcelType(introduced.getReturnType()), | |||
@@ -1666,6 +1718,10 @@ public class BcelTypeMunger extends ConcreteTypeMunger { | |||
return new BcelTypeMunger(munger.parameterizedFor(target),aspectType); | |||
} | |||
public ConcreteTypeMunger parameterizeWith(Map m, World w) { | |||
return new BcelTypeMunger(munger.parameterizeWith(m,w),aspectType); | |||
} | |||
/** | |||
* Returns a list of type variable aliases used in this munger. For example, if the | |||
* ITD is 'int I<A,B>.m(List<A> las,List<B> lbs) {}' then this returns a list containing |
@@ -64,25 +64,24 @@ import org.aspectj.weaver.AsmRelationshipProvider; | |||
import org.aspectj.weaver.BCException; | |||
import org.aspectj.weaver.ConcreteTypeMunger; | |||
import org.aspectj.weaver.CrosscuttingMembersSet; | |||
import org.aspectj.weaver.CustomMungerFactory; | |||
import org.aspectj.weaver.IClassFileProvider; | |||
import org.aspectj.weaver.IWeaveRequestor; | |||
import org.aspectj.weaver.IWeaver; | |||
import org.aspectj.weaver.NewParentTypeMunger; | |||
import org.aspectj.weaver.ReferenceType; | |||
import org.aspectj.weaver.ReferenceTypeDelegate; | |||
import org.aspectj.weaver.ResolvedTypeMunger; | |||
import org.aspectj.weaver.ResolvedType; | |||
import org.aspectj.weaver.ResolvedTypeMunger; | |||
import org.aspectj.weaver.Shadow; | |||
import org.aspectj.weaver.ShadowMunger; | |||
import org.aspectj.weaver.UnresolvedType; | |||
import org.aspectj.weaver.WeaverMessages; | |||
import org.aspectj.weaver.WeaverMetrics; | |||
import org.aspectj.weaver.WeaverStateInfo; | |||
import org.aspectj.weaver.World; | |||
import org.aspectj.weaver.patterns.AndPointcut; | |||
import org.aspectj.weaver.patterns.BindingAnnotationTypePattern; | |||
import org.aspectj.weaver.patterns.BindingTypePattern; | |||
import org.aspectj.weaver.patterns.CflowPointcut; | |||
import org.aspectj.weaver.patterns.ConcreteCflowPointcut; | |||
import org.aspectj.weaver.patterns.DeclareAnnotation; | |||
import org.aspectj.weaver.patterns.DeclareParents; | |||
@@ -113,7 +112,6 @@ public class BcelWeaver implements IWeaver { | |||
public BcelWeaver(BcelWorld world) { | |||
super(); | |||
if (trace.isTraceEnabled()) trace.enter("<init>",this,world); | |||
WeaverMetrics.reset(); | |||
this.world = world; | |||
this.xcutSet = world.getCrosscuttingMembersSet(); | |||
if (trace.isTraceEnabled()) trace.exit("<init>"); | |||
@@ -138,6 +136,7 @@ public class BcelWeaver implements IWeaver { | |||
private List declareParentsList = null; // setup by prepareForWeave | |||
private ZipOutputStream zipOutputStream; | |||
private CustomMungerFactory customMungerFactory; | |||
// ---- | |||
@@ -192,8 +191,6 @@ public class BcelWeaver implements IWeaver { | |||
wsi.getUnwovenClassFileData(wovenJavaClass.getBytes())); | |||
world.storeClass(unwovenJavaClass); | |||
classType.setJavaClass(unwovenJavaClass); | |||
if (world.isRunMinimalMemory() && world.isXnoInline()) | |||
classType.evictWeavingState(); // CUSTARD | |||
// classType.setJavaClass(Utility.makeJavaClass(classType.getJavaClass().getFileName(), wsi.getUnwovenClassFileData(classType.getJavaClass().getBytes()))); | |||
} | |||
@@ -201,6 +198,14 @@ public class BcelWeaver implements IWeaver { | |||
//=> mainly for nothing for LTW - pbly for something in incremental build... | |||
xcutSet.addOrReplaceAspect(type); | |||
if (trace.isTraceEnabled()) trace.exit("addLibraryAspect",type); | |||
if (type.getSuperclass().isAspect()) { | |||
// If the supertype includes ITDs and the user has not included that aspect in the aop.xml, they will | |||
// not get picked up, which can give unusual behaviour! See bug 223094 | |||
// This change causes us to pick up the super aspect regardless of what was said in the aop.xml - giving | |||
// predictable behaviour. If the user also supplied it, there will be no problem other than the second | |||
// addition overriding the first | |||
addLibraryAspect(type.getSuperclass().getName()); | |||
} | |||
return type; | |||
} else { | |||
// FIXME AV - better warning upon no such aspect from aop.xml | |||
@@ -463,7 +468,6 @@ public class BcelWeaver implements IWeaver { | |||
if (trace.isTraceEnabled()) trace.enter("prepareForWeave",this); | |||
needToReweaveWorld = xcutSet.hasChangedSinceLastReset(); | |||
CflowPointcut.clearCaches(); | |||
// update mungers | |||
for (Iterator i = addedClasses.iterator(); i.hasNext(); ) { | |||
@@ -490,6 +494,8 @@ public class BcelWeaver implements IWeaver { | |||
typeMungerList = xcutSet.getTypeMungers(); | |||
lateTypeMungerList = xcutSet.getLateTypeMungers(); | |||
declareParentsList = xcutSet.getDeclareParents(); | |||
addCustomMungers(); | |||
// The ordering here used to be based on a string compare on toString() for the two mungers - | |||
// that breaks for the @AJ style where advice names aren't programmatically generated. So we | |||
@@ -521,6 +527,30 @@ public class BcelWeaver implements IWeaver { | |||
if (trace.isTraceEnabled()) trace.exit("prepareForWeave"); | |||
} | |||
private void addCustomMungers() { | |||
if (customMungerFactory != null) { | |||
for (Iterator i = addedClasses.iterator(); i.hasNext();) { | |||
UnwovenClassFile jc = (UnwovenClassFile) i.next(); | |||
String name = jc.getClassName(); | |||
ResolvedType type = world.resolve(name); | |||
if (type.isAspect()) { | |||
Collection/*ShadowMunger*/ shadowMungers = customMungerFactory.createCustomShadowMungers(type); | |||
if (shadowMungers != null) { | |||
shadowMungerList.addAll(shadowMungers); | |||
} | |||
Collection/*ConcreteTypeMunger*/ typeMungers = customMungerFactory | |||
.createCustomTypeMungers(type); | |||
if (typeMungers != null) | |||
typeMungerList.addAll(typeMungers); | |||
} | |||
} | |||
} | |||
} | |||
public void setCustomMungerFactory(CustomMungerFactory factory) { | |||
customMungerFactory = factory; | |||
} | |||
/* | |||
* Rewrite all of the pointcuts in the world into their most efficient | |||
* form for subsequent matching. Also ensure that if pc1.equals(pc2) | |||
@@ -833,9 +863,7 @@ public class BcelWeaver implements IWeaver { | |||
*/ | |||
private void raiseUnboundFormalError(String name, Pointcut userPointcut) { | |||
world.showMessage(IMessage.ERROR, | |||
WeaverMessages.format(WeaverMessages.UNBOUND_FORMAL, | |||
name), | |||
userPointcut.getSourceContext().makeSourceLocation(userPointcut),null); | |||
WeaverMessages.format(WeaverMessages.UNBOUND_FORMAL,name),userPointcut.getSourceLocation(),null); | |||
} | |||
@@ -1037,6 +1065,17 @@ public class BcelWeaver implements IWeaver { | |||
} | |||
} | |||
// Go through the types and ensure any 'damaged' during compile time are repaired prior to weaving | |||
for (Iterator i = input.getClassFileIterator(); i.hasNext(); ) { | |||
UnwovenClassFile classFile = (UnwovenClassFile)i.next(); | |||
String className = classFile.getClassName(); | |||
ResolvedType theType = world.resolve(className); | |||
if (theType!=null) { | |||
BcelObjectType classType = BcelWorld.getBcelObjectType(theType); | |||
if (classType!=null) classType.ensureDelegateConsistent(); | |||
} | |||
} | |||
// special case for AtAspectJMungerOnly - see #113587 | |||
if (input.isApplyAtAspectJMungersOnly()) { | |||
ContextToken atAspectJMungersOnly = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.PROCESSING_ATASPECTJTYPE_MUNGERS_ONLY, ""); | |||
@@ -1345,6 +1384,10 @@ public class BcelWeaver implements IWeaver { | |||
//clazz is null if the classfile was unchanged by weaving... | |||
if (clazz != null) { | |||
UnwovenClassFile[] newClasses = getClassFilesFor(clazz); | |||
// Copy the char[] across as it means the WeaverAdapter.removeFromMap() can be fast! | |||
if (newClasses[0].getClassName().equals(classFile.getClassName())) { | |||
newClasses[0].setClassNameAsChars(classFile.getClassNameAsChars()); | |||
} | |||
for (int i = 0; i < newClasses.length; i++) { | |||
requestor.acceptResult(newClasses[i]); | |||
} | |||
@@ -1374,11 +1417,13 @@ public class BcelWeaver implements IWeaver { | |||
public UnwovenClassFile[] getClassFilesFor(LazyClassGen clazz) { | |||
List childClasses = clazz.getChildClasses(world); | |||
UnwovenClassFile[] ret = new UnwovenClassFile[1 + childClasses.size()]; | |||
ret[0] = new UnwovenClassFile(clazz.getFileName(),clazz.getJavaClassBytesIncludingReweavable(world)); | |||
// APR29 | |||
ret[0] = new UnwovenClassFile(clazz.getFileName(),clazz.getClassName(),clazz.getJavaClassBytesIncludingReweavable(world)); | |||
int index = 1; | |||
for (Iterator iter = childClasses.iterator(); iter.hasNext();) { | |||
UnwovenClassFile.ChildClass element = (UnwovenClassFile.ChildClass) iter.next(); | |||
UnwovenClassFile childClass = new UnwovenClassFile(clazz.getFileName() + "$" + element.name, element.bytes); | |||
// APR29 | |||
UnwovenClassFile childClass = new UnwovenClassFile(clazz.getFileName() + "$" + element.name,/*clazz.getClassName()+"$"+element.name,*/ element.bytes); | |||
ret[index++] = childClass; | |||
} | |||
return ret; | |||
@@ -1409,8 +1454,8 @@ public class BcelWeaver implements IWeaver { | |||
boolean typeChanged = applyDeclareParents(decp,onType); | |||
if (typeChanged) { | |||
aParentChangeOccurred = true; | |||
} else { // Perhaps it would have matched if a 'dec @type' had modified the type | |||
if (!decp.getChild().isStarAnnotation()) decpToRepeat.add(decp); | |||
} else { | |||
decpToRepeat.add(decp); | |||
} | |||
} | |||
@@ -1718,7 +1763,6 @@ public class BcelWeaver implements IWeaver { | |||
while (iter.hasNext()) { | |||
ShadowMunger munger = (ShadowMunger)iter.next(); | |||
FuzzyBoolean fb = munger.getPointcut().fastMatch(info); | |||
WeaverMetrics.recordFastMatchTypeResult(fb); // Could pass: munger.getPointcut().toString(),info | |||
if (fb.maybeTrue()) { | |||
result.add(munger); | |||
} |
@@ -45,13 +45,13 @@ import org.aspectj.apache.bcel.util.NonCachingClassLoaderRepository; | |||
import org.aspectj.apache.bcel.util.Repository; | |||
import org.aspectj.bridge.IMessageHandler; | |||
import org.aspectj.weaver.Advice; | |||
import org.aspectj.weaver.AdviceKind; | |||
import org.aspectj.weaver.AjAttribute; | |||
import org.aspectj.weaver.AnnotationOnTypeMunger; | |||
import org.aspectj.weaver.AnnotationX; | |||
import org.aspectj.weaver.BCException; | |||
import org.aspectj.weaver.ConcreteTypeMunger; | |||
import org.aspectj.weaver.ICrossReferenceHandler; | |||
import org.aspectj.weaver.MemberKind; | |||
import org.aspectj.weaver.Member; | |||
import org.aspectj.weaver.MemberImpl; | |||
import org.aspectj.weaver.NewParentTypeMunger; | |||
@@ -104,8 +104,6 @@ public class BcelWorld extends World implements Repository { | |||
} | |||
private static List getPathEntries(String s) { | |||
List ret = new ArrayList(); | |||
StringTokenizer tok = new StringTokenizer(s, File.pathSeparator); | |||
@@ -170,61 +168,6 @@ public class BcelWorld extends World implements Repository { | |||
classPath.addPath(name, this.getMessageHandler()); | |||
} | |||
/** | |||
* Parse a string into advice. | |||
* | |||
* <blockquote><pre> | |||
* Kind ( Id , ... ) : Pointcut -> MethodSignature | |||
* </pre></blockquote> | |||
*/ | |||
public Advice shadowMunger(String str, int extraFlag) { | |||
str = str.trim(); | |||
int start = 0; | |||
int i = str.indexOf('('); | |||
AdviceKind kind = | |||
AdviceKind.stringToKind(str.substring(start, i)); | |||
start = ++i; | |||
i = str.indexOf(')', i); | |||
String[] ids = parseIds(str.substring(start, i).trim()); | |||
//start = ++i; | |||
i = str.indexOf(':', i); | |||
start = ++i; | |||
i = str.indexOf("->", i); | |||
Pointcut pointcut = Pointcut.fromString(str.substring(start, i).trim()); | |||
Member m = MemberImpl.methodFromString(str.substring(i+2, str.length()).trim()); | |||
// now, we resolve | |||
UnresolvedType[] types = m.getParameterTypes(); | |||
FormalBinding[] bindings = new FormalBinding[ids.length]; | |||
for (int j = 0, len = ids.length; j < len; j++) { | |||
bindings[j] = new FormalBinding(types[j], ids[j], j, 0, 0, "fromString"); | |||
} | |||
Pointcut p = | |||
pointcut.resolve(new SimpleScope(this, bindings)); | |||
return new BcelAdvice(kind, p, m, extraFlag, 0, 0, null, null); | |||
} | |||
private String[] parseIds(String str) { | |||
if (str.length() == 0) return ZERO_STRINGS; | |||
List l = new ArrayList(); | |||
int start = 0; | |||
while (true) { | |||
int i = str.indexOf(',', start); | |||
if (i == -1) { | |||
l.add(str.substring(start).trim()); | |||
break; | |||
} | |||
l.add(str.substring(start, i).trim()); | |||
start = i+1; | |||
} | |||
return (String[]) l.toArray(new String[l.size()]); | |||
} | |||
// ---- various interactions with bcel | |||
public static Type makeBcelType(UnresolvedType type) { | |||
@@ -452,7 +395,7 @@ public class BcelWorld extends World implements Repository { | |||
} | |||
public Member makeJoinPointSignatureFromMethod(LazyMethodGen mg, MemberImpl.Kind kind) { | |||
public Member makeJoinPointSignatureFromMethod(LazyMethodGen mg, MemberKind kind) { | |||
Member ret = mg.getMemberView(); | |||
if (ret == null) { | |||
int mods = mg.getAccessFlags(); | |||
@@ -460,7 +403,8 @@ public class BcelWorld extends World implements Repository { | |||
mods |= Modifier.INTERFACE; | |||
} | |||
if (kind == null) { | |||
if (mg.getName().equals("<init>")) { | |||
//OPTIMIZE surely we can pass the kind in and not resort to string compares? | |||
if (mg.getName().equals("<init>")) { | |||
kind = Member.CONSTRUCTOR; | |||
} else if (mg.getName().equals("<clinit>")) { | |||
kind = Member.STATIC_INITIALIZATION; | |||
@@ -482,12 +426,10 @@ public class BcelWorld extends World implements Repository { | |||
} | |||
public Member makeJoinPointSignatureForMonitorEnter(LazyClassGen cg,InstructionHandle h) { | |||
Instruction i = h.getInstruction(); | |||
return MemberImpl.monitorEnter(); | |||
} | |||
public Member makeJoinPointSignatureForMonitorExit(LazyClassGen cg,InstructionHandle h) { | |||
Instruction i = h.getInstruction(); | |||
return MemberImpl.monitorExit(); | |||
} | |||
@@ -53,7 +53,7 @@ import org.aspectj.apache.bcel.generic.Type; | |||
import org.aspectj.bridge.IMessage; | |||
import org.aspectj.bridge.ISourceLocation; | |||
import org.aspectj.bridge.SourceLocation; | |||
import org.aspectj.util.CollectionUtil; | |||
import org.aspectj.util.LangUtil; | |||
import org.aspectj.weaver.AjAttribute; | |||
import org.aspectj.weaver.BCException; | |||
import org.aspectj.weaver.Member; | |||
@@ -481,17 +481,12 @@ public final class LazyClassGen { | |||
} | |||
// Add a weaver version attribute to the file being produced (if necessary...) | |||
boolean hasVersionAttribute = false; | |||
Attribute[] attrs = myGen.getAttributes(); | |||
for (int i = 0; i < attrs.length && !hasVersionAttribute; i++) { | |||
Attribute attribute = attrs[i]; | |||
if (attribute.getName().equals("org.aspectj.weaver.WeaverVersion")) hasVersionAttribute=true; | |||
} | |||
if (!hasVersionAttribute) | |||
myGen.addAttribute(BcelAttributes.bcelAttribute(new AjAttribute.WeaverVersionInfo(),getConstantPool())); | |||
if (!myGen.hasAttribute("org.aspectj.weaver.WeaverVersion")) { | |||
myGen.addAttribute(Utility.bcelAttribute(new AjAttribute.WeaverVersionInfo(),getConstantPool())); | |||
} | |||
if (myType != null && myType.getWeaverState() != null) { | |||
myGen.addAttribute(BcelAttributes.bcelAttribute( | |||
myGen.addAttribute(Utility.bcelAttribute( | |||
new AjAttribute.WeaverState(myType.getWeaverState()), | |||
getConstantPool())); | |||
} | |||
@@ -505,7 +500,13 @@ public final class LazyClassGen { | |||
addAjcInitializers(); | |||
calculateSourceDebugExtensionOffsets(); | |||
// 17Feb05 - ASC - Skip this for now - it crashes IBM 1.4.2 jvms (pr80430). Will be revisited when contents | |||
// of attribute are confirmed to be correct. | |||
boolean sourceDebugExtensionSupportSwitchedOn = false; | |||
if (sourceDebugExtensionSupportSwitchedOn) { | |||
calculateSourceDebugExtensionOffsets(); | |||
} | |||
int len = methodGens.size(); | |||
myGen.setMethods(Method.NoMethods); | |||
@@ -515,25 +516,26 @@ public final class LazyClassGen { | |||
if (isEmptyClinit(gen)) continue; | |||
myGen.addMethod(gen.getMethod()); | |||
} | |||
len = fields.size(); | |||
myGen.setFields(Field.NoFields); | |||
for (int i = 0; i < len; i++) { | |||
BcelField gen = (BcelField) fields.get(i); | |||
myGen.addField(gen.getField(this.constantPoolGen)); | |||
} | |||
if (inlinedFiles.size() != 0) { | |||
if (hasSourceDebugExtensionAttribute(myGen)) { | |||
world.showMessage( | |||
IMessage.WARNING, | |||
WeaverMessages.format(WeaverMessages.OVERWRITE_JSR45,getFileName()), | |||
null, | |||
null); | |||
if (sourceDebugExtensionSupportSwitchedOn) { | |||
if (inlinedFiles.size() != 0) { | |||
if (hasSourceDebugExtensionAttribute(myGen)) { | |||
world.showMessage( | |||
IMessage.WARNING, | |||
WeaverMessages.format(WeaverMessages.OVERWRITE_JSR45,getFileName()), | |||
null, | |||
null); | |||
} | |||
// myGen.addAttribute(getSourceDebugExtensionAttribute()); | |||
} | |||
// 17Feb05 - ASC - Skip this for now - it crashes IBM 1.4.2 jvms (pr80430). Will be revisited when contents | |||
// of attribute are confirmed to be correct. | |||
// myGen.addAttribute(getSourceDebugExtensionAttribute()); | |||
} | |||
} | |||
fixupGenericSignatureAttribute(); | |||
} | |||
@@ -560,11 +562,7 @@ public final class LazyClassGen { | |||
// 2. Find the old attribute | |||
Signature sigAttr = null; | |||
if (myType!=null) { // if null, this is a type built from scratch, it won't already have a sig attribute | |||
Attribute[] as = myGen.getAttributes(); | |||
for (int i = 0; i < as.length; i++) { | |||
Attribute attribute = as[i]; | |||
if (attribute.getName().equals("Signature")) sigAttr = (Signature)attribute; | |||
} | |||
sigAttr = (Signature) myGen.getAttribute("Signature"); | |||
} | |||
// 3. Do we need an attribute? | |||
@@ -632,7 +630,7 @@ public final class LazyClassGen { | |||
// create an empty myGen so that we can give back a return value that doesn't upset the | |||
// rest of the process. | |||
myGen = new ClassGen(myGen.getClassName(), myGen.getSuperclassName(), | |||
myGen.getFileName(), myGen.getAccessFlags(), myGen.getInterfaceNames()); | |||
myGen.getFileName(), myGen.getModifiers(), myGen.getInterfaceNames()); | |||
// raise an error against this compilation unit. | |||
getWorld().showMessage( | |||
IMessage.ERROR, | |||
@@ -643,15 +641,16 @@ public final class LazyClassGen { | |||
} | |||
private static boolean hasSourceDebugExtensionAttribute(ClassGen gen) { | |||
ConstantPool pool = gen.getConstantPool(); | |||
Attribute[] attrs = gen.getAttributes(); | |||
for (int i = 0; i < attrs.length; i++) { | |||
if ("SourceDebugExtension" | |||
.equals(((ConstantUtf8) pool.getConstant(attrs[i].getNameIndex())).getBytes())) { | |||
return true; | |||
} | |||
} | |||
return false; | |||
return gen.hasAttribute("SourceDebugExtension"); | |||
// ConstantPool pool = gen.getConstantPool(); | |||
// Attribute[] attrs = gen.getAttributes(); | |||
// for (int i = 0; i < attrs.length; i++) { | |||
// if ("SourceDebugExtension" | |||
// .equals(((ConstantUtf8) pool.getConstant(attrs[i].getNameIndex())).getBytes())) { | |||
// return true; | |||
// } | |||
// } | |||
// return false; | |||
} | |||
public JavaClass getJavaClass(BcelWorld world) { | |||
@@ -734,10 +733,10 @@ public final class LazyClassGen { | |||
public String toShortString() { | |||
String s = | |||
org.aspectj.apache.bcel.classfile.Utility.accessToString(myGen.getAccessFlags(), true); | |||
org.aspectj.apache.bcel.classfile.Utility.accessToString(myGen.getModifiers(), true); | |||
if (s != "") | |||
s += " "; | |||
s += org.aspectj.apache.bcel.classfile.Utility.classOrInterface(myGen.getAccessFlags()); | |||
s += org.aspectj.apache.bcel.classfile.Utility.classOrInterface(myGen.getModifiers()); | |||
s += " "; | |||
s += myGen.getClassName(); | |||
return s; | |||
@@ -861,7 +860,7 @@ public final class LazyClassGen { | |||
Type.VOID, | |||
"<clinit>", | |||
new Type[0], | |||
CollectionUtil.NO_STRINGS, | |||
LangUtil.NO_STRINGS, | |||
this); | |||
clinit.getBody().insert(InstructionConstants.RETURN); | |||
methodGens.add(clinit); | |||
@@ -878,7 +877,7 @@ public final class LazyClassGen { | |||
Type.VOID, | |||
NameMangler.AJC_PRE_CLINIT_NAME, | |||
new Type[0], | |||
CollectionUtil.NO_STRINGS, | |||
LangUtil.NO_STRINGS, | |||
this); | |||
ajcClinit.getBody().insert(InstructionConstants.RETURN); | |||
methodGens.add(ajcClinit); | |||
@@ -1258,7 +1257,8 @@ public final class LazyClassGen { | |||
private void makeSyntheticAndTransientIfNeeded(FieldGen field) { | |||
if (field.getName().startsWith(NameMangler.PREFIX) && | |||
!field.getName().startsWith("ajc$interField$")) { | |||
!field.getName().startsWith("ajc$interField$") && | |||
!field.getName().startsWith("ajc$instance$")) { | |||
// it's an aj added field | |||
// first do transient | |||
if (!field.isStatic()) { | |||
@@ -1284,9 +1284,9 @@ public final class LazyClassGen { | |||
} | |||
} | |||
private boolean hasSyntheticAttribute(Attribute[] attributes) { | |||
for (int i = 0; i < attributes.length; i++) { | |||
if (attributes[i].getName().equals("Synthetic")) { | |||
private boolean hasSyntheticAttribute(List attributes) { | |||
for (int i = 0; i < attributes.size(); i++) { | |||
if (((Attribute)attributes.get(i)).getName().equals("Synthetic")) { | |||
return true; | |||
} | |||
} | |||
@@ -1338,7 +1338,7 @@ public final class LazyClassGen { | |||
public void forcePublic() { | |||
myGen.setAccessFlags(Utility.makePublic(myGen.getAccessFlags())); | |||
myGen.setModifiers(Utility.makePublic(myGen.getModifiers())); | |||
} | |||
@@ -39,6 +39,7 @@ import org.aspectj.apache.bcel.generic.ClassGenException; | |||
import org.aspectj.apache.bcel.generic.CodeExceptionGen; | |||
import org.aspectj.apache.bcel.generic.Instruction; | |||
import org.aspectj.apache.bcel.generic.InstructionBranch; | |||
import org.aspectj.apache.bcel.generic.InstructionComparator; | |||
import org.aspectj.apache.bcel.generic.InstructionHandle; | |||
import org.aspectj.apache.bcel.generic.InstructionList; | |||
import org.aspectj.apache.bcel.generic.InstructionSelect; | |||
@@ -50,6 +51,7 @@ import org.aspectj.apache.bcel.generic.LocalVariableTag; | |||
import org.aspectj.apache.bcel.generic.MethodGen; | |||
import org.aspectj.apache.bcel.generic.ObjectType; | |||
import org.aspectj.apache.bcel.generic.Tag; | |||
import org.aspectj.apache.bcel.generic.TargetLostException; | |||
import org.aspectj.apache.bcel.generic.Type; | |||
import org.aspectj.bridge.IMessage; | |||
import org.aspectj.bridge.ISourceLocation; | |||
@@ -69,6 +71,7 @@ import org.aspectj.weaver.AjAttribute.WeaverVersionInfo; | |||
import org.aspectj.weaver.tools.Traceable; | |||
/** | |||
* A LazyMethodGen should be treated as a MethodGen. It's our way of abstracting over the | |||
* low-level Method objects. It converts through {@link MethodGen} to create | |||
@@ -86,22 +89,25 @@ import org.aspectj.weaver.tools.Traceable; | |||
public final class LazyMethodGen implements Traceable { | |||
private static final int ACC_SYNTHETIC = 0x1000; | |||
private int accessFlags; | |||
private Type returnType; | |||
private final String name; | |||
private int accessFlags; | |||
private Type returnType; | |||
private final String name; | |||
private Type[] argumentTypes; | |||
//private final String[] argumentNames; | |||
private String[] declaredExceptions; | |||
private InstructionList body; // leaving null for abstracts | |||
private Attribute[] attributes; | |||
private List attributes; | |||
private List newAnnotations; | |||
private final LazyClassGen enclosingClass; | |||
private BcelMethod memberView; | |||
private AjAttribute.EffectiveSignatureAttribute effectiveSignature; | |||
int highestLineNumber = 0; | |||
boolean wasNewPacked = false; | |||
/* | |||
* We use LineNumberTags and not Gens. | |||
* | |||
* This option specifies whether we let the BCEL classes create LineNumberGens and LocalVariableGens | |||
* or if we make it create LineNumberTags and LocalVariableTags. Up until 1.5.1 we always created | |||
* Gens - then on return from the MethodGen ctor we took them apart, reprocessed them all and | |||
@@ -114,12 +120,7 @@ public final class LazyMethodGen implements Traceable { | |||
* instructions it targets, it relies on the instructions targetting *it* - this reduces the amount | |||
* of targeter manipulation we have to do. | |||
* | |||
* Because this *could* go wrong - it passes all our tests, but you never know, the option: | |||
* -Xset:optimizeWithTags=false | |||
* will turn it *OFF* | |||
*/ | |||
public static boolean avoidUseOfBcelGenObjects = true; | |||
public static boolean checkedXsetOption = false; | |||
/** This is nonnull if this method is the result of an "inlining". We currently | |||
* copy methods into other classes for around advice. We add this field so | |||
@@ -167,7 +168,7 @@ public final class LazyMethodGen implements Traceable { | |||
} else { | |||
body = null; | |||
} | |||
this.attributes = new Attribute[0]; | |||
this.attributes = new ArrayList(); | |||
this.enclosingClass = enclosingClass; | |||
assertGoodBody(); | |||
@@ -207,7 +208,7 @@ public final class LazyMethodGen implements Traceable { | |||
} | |||
this.memberView = new BcelMethod(enclosingClass.getBcelObjectType(), m); | |||
this.accessFlags = m.getAccessFlags(); | |||
this.accessFlags = m.getModifiers(); | |||
this.name = m.getName(); | |||
// @AJ advice are not inlined by default since requires further analysis | |||
@@ -233,7 +234,7 @@ public final class LazyMethodGen implements Traceable { | |||
} | |||
//this.memberView = new BcelMethod(enclosingClass.getBcelObjectType(), m); | |||
this.memberView = m; | |||
this.accessFlags = savedMethod.getAccessFlags(); | |||
this.accessFlags = savedMethod.getModifiers(); | |||
this.name = m.getName(); | |||
// @AJ advice are not inlined by default since requires further analysis | |||
@@ -301,22 +302,15 @@ public final class LazyMethodGen implements Traceable { | |||
private void initialize() { | |||
if (returnType != null) return; | |||
// Check whether we need to configure the optimization | |||
if (!checkedXsetOption) { | |||
Properties p = enclosingClass.getWorld().getExtraConfiguration(); | |||
if (p!=null) { | |||
String s = p.getProperty("optimizeWithTags","true"); | |||
avoidUseOfBcelGenObjects = s.equalsIgnoreCase("true"); | |||
if (!avoidUseOfBcelGenObjects) | |||
enclosingClass.getWorld().getMessageHandler().handleMessage(MessageUtil.info("[optimizeWithTags=false] Disabling optimization to use Tags rather than Gens")); | |||
} | |||
checkedXsetOption=true; | |||
} | |||
//System.err.println("initializing: " + getName() + ", " + enclosingClass.getName() + ", " + returnType + ", " + savedMethod); | |||
MethodGen gen = new MethodGen(savedMethod, enclosingClass.getName(), enclosingClass.getConstantPool(),avoidUseOfBcelGenObjects); | |||
MethodGen gen = null; | |||
try { | |||
gen = new MethodGen(savedMethod, enclosingClass.getName(), enclosingClass.getConstantPool(),true); | |||
} catch (RuntimeException t) { | |||
System.err.println(getName()); | |||
throw t; | |||
} | |||
this.returnType = gen.getReturnType(); | |||
this.argumentTypes = gen.getArgumentTypes(); | |||
@@ -341,13 +335,9 @@ public final class LazyMethodGen implements Traceable { | |||
unpackHandlers(gen); | |||
if (avoidUseOfBcelGenObjects) { | |||
ensureAllLineNumberSetup(gen); | |||
highestLineNumber = gen.getHighestlinenumber(); | |||
} else { | |||
unpackLineNumbers(gen); | |||
unpackLocals(gen); | |||
} | |||
ensureAllLineNumberSetup(gen); | |||
highestLineNumber = gen.getHighestlinenumber(); | |||
} | |||
assertGoodBody(); | |||
@@ -411,29 +401,6 @@ public final class LazyMethodGen implements Traceable { | |||
} | |||
} | |||
private void unpackLineNumbers(MethodGen gen) { | |||
LineNumberTag lr = null; | |||
for (InstructionHandle ih = body.getStart(); ih != null; ih = ih.getNext()) { | |||
InstructionTargeter[] targeters = ih.getTargeters(); | |||
if (targeters != null) { | |||
for (int i = targeters.length - 1; i >= 0; i--) { | |||
InstructionTargeter targeter = targeters[i]; | |||
if (targeter instanceof LineNumberGen) { | |||
LineNumberGen lng = (LineNumberGen) targeter; | |||
lng.updateTarget(ih, null); | |||
int lineNumber = lng.getSourceLine(); | |||
if (highestLineNumber < lineNumber) highestLineNumber = lineNumber; | |||
lr = new LineNumberTag(lineNumber); | |||
} | |||
} | |||
} | |||
if (lr != null) { | |||
ih.addTargeter(lr); | |||
} | |||
} | |||
gen.removeLineNumbers(); | |||
} | |||
/** | |||
* On entry to this method we have a method whose instruction stream contains a few instructions | |||
* that have line numbers assigned to them (LineNumberTags). The aim is to ensure every instruction | |||
@@ -460,33 +427,6 @@ public final class LazyMethodGen implements Traceable { | |||
} | |||
} | |||
} | |||
private void unpackLocals(MethodGen gen) { | |||
Set locals = new HashSet(); | |||
for (InstructionHandle ih = body.getStart(); ih != null; ih = ih.getNext()) { | |||
InstructionTargeter[] targeters = ih.getTargeters(); | |||
List ends = new ArrayList(0); | |||
if (targeters != null) { | |||
for (int i = targeters.length - 1; i >= 0; i--) { | |||
InstructionTargeter targeter = targeters[i]; | |||
if (targeter instanceof LocalVariableGen) { | |||
LocalVariableGen lng = (LocalVariableGen) targeter; | |||
LocalVariableTag lr = new LocalVariableTag(lng.getType().getSignature()/*BcelWorld.fromBcel(lng.getType())*/, lng.getName(), lng.getIndex(), lng.getStart().getPosition()); | |||
if (lng.getStart() == ih) { | |||
locals.add(lr); | |||
} else { | |||
ends.add(lr); | |||
} | |||
} | |||
} | |||
} | |||
for (Iterator i = locals.iterator(); i.hasNext(); ) { | |||
ih.addTargeter((LocalVariableTag) i.next()); | |||
} | |||
locals.removeAll(ends); | |||
} | |||
gen.removeLocalVariables(); | |||
} | |||
// =============== | |||
@@ -505,7 +445,8 @@ public final class LazyMethodGen implements Traceable { | |||
try { | |||
MethodGen gen = pack(); | |||
return gen.getMethod(); | |||
savedMethod = gen.getMethod(); | |||
return savedMethod; | |||
} catch (ClassGenException e) { | |||
enclosingClass.getBcelObjectType().getResolvedTypeX().getWorld().showMessage( | |||
IMessage.ERROR, | |||
@@ -522,6 +463,9 @@ public final class LazyMethodGen implements Traceable { | |||
} | |||
public void markAsChanged() { | |||
if (wasNewPacked) { | |||
throw new RuntimeException("Already packed method is being re-modified: "+getClassName()+" "+toShortString()); | |||
} | |||
initialize(); | |||
savedMethod = null; | |||
} | |||
@@ -529,7 +473,8 @@ public final class LazyMethodGen implements Traceable { | |||
// ============================= | |||
public String toString() { | |||
WeaverVersionInfo weaverVersion = enclosingClass.getBcelObjectType().getWeaverVersionAttribute(); | |||
BcelObjectType bot = enclosingClass.getBcelObjectType(); | |||
WeaverVersionInfo weaverVersion = (bot==null?WeaverVersionInfo.CURRENT:bot.getWeaverVersionAttribute()); | |||
return toLongString(weaverVersion); | |||
} | |||
@@ -611,7 +556,7 @@ public final class LazyMethodGen implements Traceable { | |||
if (enclosingClass != null && enclosingClass.getType() != null) { | |||
context = enclosingClass.getType().getSourceContext(); | |||
} | |||
List as = BcelAttributes.readAjAttributes(getClassName(),attributes, context,null,weaverVersion); | |||
List as = BcelAttributes.readAjAttributes(getClassName(), (Attribute[])attributes.toArray(new Attribute[]{}), context,null,weaverVersion); | |||
if (! as.isEmpty()) { | |||
out.println(" " + as.get(0)); // XXX assuming exactly one attribute, munger... | |||
} | |||
@@ -909,6 +854,14 @@ public final class LazyMethodGen implements Traceable { | |||
return name; | |||
} | |||
public String getGenericReturnTypeSignature() { | |||
if (memberView == null) { | |||
return getReturnType().getSignature(); | |||
} else { | |||
return memberView.getGenericReturnType().getSignature(); | |||
} | |||
} | |||
public Type getReturnType() { | |||
initialize(); | |||
return returnType; | |||
@@ -928,7 +881,7 @@ public final class LazyMethodGen implements Traceable { | |||
return body != null; | |||
} | |||
public Attribute[] getAttributes() { | |||
public List/*Attribute*/ getAttributes() { | |||
return attributes; | |||
} | |||
@@ -966,8 +919,8 @@ public final class LazyMethodGen implements Traceable { | |||
gen.addException(declaredExceptions[i]); | |||
} | |||
for (int i = 0, len = attributes.length; i < len; i++) { | |||
gen.addAttribute(attributes[i]); | |||
for (int i = 0, len = attributes.size(); i < len; i++) { | |||
gen.addAttribute((Attribute)attributes.get(i)); | |||
} | |||
if (newAnnotations!=null) { | |||
@@ -996,7 +949,16 @@ public final class LazyMethodGen implements Traceable { | |||
} | |||
if (hasBody()) { | |||
packBody(gen); | |||
if (this.enclosingClass.getWorld().shouldGoForIt()) { | |||
if (isAdviceMethod() || getName().equals("<clinit>")) { | |||
packBody(gen); | |||
} else { | |||
newPackBody(gen); | |||
} | |||
} else { | |||
packBody(gen); | |||
} | |||
// FINISH OFF CASE/SWITCH ! | |||
gen.setMaxLocals(); | |||
gen.setMaxStack(); | |||
} else { | |||
@@ -1109,6 +1071,108 @@ public final class LazyMethodGen implements Traceable { | |||
} | |||
} | |||
/* | |||
* Andys version | |||
*/ | |||
public void newPackBody(MethodGen gen) { | |||
InstructionList theBody = getBody(); | |||
InstructionHandle iHandle = theBody.getStart(); | |||
int currLine = -1; | |||
int lineNumberOffset = (fromFilename == null) ? 0: getEnclosingClass().getSourceDebugExtensionOffset(fromFilename); | |||
Map localVariables = new HashMap(); | |||
LinkedList exceptionList = new LinkedList(); | |||
Set forDeletion = new HashSet(); | |||
Set branchInstructions = new HashSet(); | |||
// OPTIMIZE sort out in here: getRange()/insertHandler() and type of exceptionList | |||
while (iHandle != null) { | |||
Instruction inst = iHandle.getInstruction(); | |||
InstructionHandle nextInst = iHandle.getNext(); | |||
// OPTIMIZE remove this instructionhandle as it now points to nowhere? | |||
if (inst == Range.RANGEINSTRUCTION) { | |||
Range r = Range.getRange(iHandle); | |||
if (r instanceof ExceptionRange) { | |||
ExceptionRange er = (ExceptionRange) r; | |||
if (er.getStart() == iHandle) { | |||
if (!er.isEmpty()){ | |||
// order is important, insert handlers in order of start | |||
insertHandler(er, exceptionList); | |||
} | |||
} | |||
} | |||
forDeletion.add(iHandle); | |||
} else { | |||
if (inst instanceof InstructionBranch) { | |||
branchInstructions.add(iHandle); | |||
} | |||
InstructionTargeter[] targeters = iHandle.getTargeters(); | |||
if (targeters != null) { | |||
for (int k = targeters.length - 1; k >= 0; k--) { | |||
InstructionTargeter targeter = targeters[k]; | |||
if (targeter instanceof LineNumberTag) { | |||
int line = ((LineNumberTag)targeter).getLineNumber(); | |||
if (line != currLine) { | |||
gen.addLineNumber(iHandle, line + lineNumberOffset); | |||
currLine = line; | |||
} | |||
} else if (targeter instanceof LocalVariableTag) { | |||
LocalVariableTag lvt = (LocalVariableTag) targeter; | |||
LVPosition p = (LVPosition)localVariables.get(lvt); | |||
// If we don't know about it, create a new position and store | |||
// If we do know about it - update its end position | |||
if (p==null) { | |||
LVPosition newp = new LVPosition(); | |||
newp.start=newp.end=iHandle; | |||
localVariables.put(lvt,newp); | |||
} else { | |||
p.end = iHandle; | |||
} | |||
} | |||
} | |||
} | |||
} | |||
iHandle = iHandle.getNext(); | |||
} | |||
for (Iterator iterator = branchInstructions.iterator(); iterator.hasNext();) { | |||
BranchHandle iBranch = (BranchHandle) iterator.next(); | |||
handleBranchInstruction(iBranch,forDeletion); | |||
} | |||
// now add exception handlers | |||
for (Iterator iter = exceptionList.iterator(); iter.hasNext();) { | |||
ExceptionRange r = (ExceptionRange) iter.next(); | |||
if (r.isEmpty()) continue; | |||
gen.addExceptionHandler( | |||
jumpForward(r.getRealStart(),forDeletion), | |||
jumpForward(r.getRealEnd(),forDeletion), | |||
jumpForward(r.getHandler(),forDeletion), | |||
(r.getCatchType() == null) | |||
? null | |||
: (ObjectType) BcelWorld.makeBcelType(r.getCatchType())); | |||
} | |||
for (Iterator iterator = forDeletion.iterator(); iterator.hasNext();) { | |||
try { | |||
theBody.delete((InstructionHandle)iterator.next()); | |||
} catch (TargetLostException e) { | |||
// TODO Auto-generated catch block | |||
e.printStackTrace(); | |||
} | |||
} | |||
gen.setInstructionList(theBody); | |||
addLocalVariables(gen,localVariables); | |||
// JAVAC adds line number tables (with just one entry) to generated accessor methods - this | |||
// keeps some tools that rely on finding at least some form of linenumbertable happy. | |||
// Let's check if we have one - if we don't then let's add one. | |||
// TODO Could be made conditional on whether line debug info is being produced | |||
if (gen.getLineNumbers().length==0) { | |||
gen.addLineNumber(gen.getInstructionList().getStart(),1); | |||
} | |||
wasNewPacked = true; | |||
} | |||
private void addLocalVariables(MethodGen gen, Map localVariables) { | |||
// now add local variables | |||
gen.removeLocalVariables(); | |||
@@ -1166,28 +1230,59 @@ public final class LazyMethodGen implements Traceable { | |||
InstructionBranch newBranchInstruction = (InstructionBranch) newInstruction; | |||
InstructionHandle oldTarget = oldBranchInstruction.getTarget(); // old target | |||
// try { | |||
// New target is in hash map | |||
newBranchInstruction.setTarget(remap(oldTarget, map)); | |||
// } catch (NullPointerException e) { | |||
// print(); | |||
// System.out.println("Was trying to remap " + bi); | |||
// System.out.println("who's target was supposedly " + itarget); | |||
// throw e; | |||
// } | |||
if (oldBranchInstruction instanceof InstructionSelect) { | |||
// Either LOOKUPSWITCH or TABLESWITCH | |||
InstructionHandle[] oldTargets = ((InstructionSelect) oldBranchInstruction).getTargets(); | |||
InstructionHandle[] newTargets = ((InstructionSelect) newBranchInstruction).getTargets(); | |||
if (oldBranchInstruction instanceof InstructionSelect) { | |||
// Either LOOKUPSWITCH or TABLESWITCH | |||
InstructionHandle[] oldTargets = ((InstructionSelect) oldBranchInstruction).getTargets(); | |||
InstructionHandle[] newTargets = ((InstructionSelect) newBranchInstruction).getTargets(); | |||
for (int k = oldTargets.length - 1; k >= 0; k--) { | |||
// Update all targets | |||
for (int k = oldTargets.length - 1; k >= 0; k--) { | |||
// Update all targets | |||
newTargets[k] = remap(oldTargets[k], map); | |||
newTargets[k].addTargeter(newBranchInstruction); | |||
} | |||
} | |||
} | |||
private InstructionHandle jumpForward(InstructionHandle t,Set handlesForDeletion) { | |||
InstructionHandle target = t; | |||
if (handlesForDeletion.contains(target)) { | |||
do { | |||
target = target.getNext(); | |||
} while (handlesForDeletion.contains(target)); | |||
} | |||
return target; | |||
} | |||
private void handleBranchInstruction(BranchHandle branchHandle, Set handlesForDeletion) { | |||
InstructionBranch branchInstruction = (InstructionBranch) branchHandle.getInstruction(); | |||
InstructionHandle target = branchInstruction.getTarget(); // old target | |||
if (handlesForDeletion.contains(target)) { | |||
do { | |||
target = target.getNext(); | |||
} while (handlesForDeletion.contains(target)); | |||
branchInstruction.setTarget(target); | |||
} | |||
if (branchInstruction instanceof InstructionSelect) { | |||
// Either LOOKUPSWITCH or TABLESWITCH | |||
InstructionHandle[] targets = ((InstructionSelect)branchInstruction).getTargets(); | |||
for (int k = targets.length - 1; k >= 0; k--) { | |||
InstructionHandle oneTarget = targets[k]; | |||
if (handlesForDeletion.contains(oneTarget)) { | |||
do { | |||
oneTarget = oneTarget.getNext(); | |||
} while (handlesForDeletion.contains(oneTarget)); | |||
branchInstruction.setTarget(oneTarget); | |||
oneTarget.addTargeter(branchInstruction); | |||
} | |||
} | |||
} | |||
} | |||
private void handleRangeInstruction(InstructionHandle ih, LinkedList exnList) { | |||
// we're a range instruction | |||
@@ -1251,6 +1346,13 @@ public final class LazyMethodGen implements Traceable { | |||
// curr = next; | |||
// } | |||
// } | |||
private static InstructionHandle fNext(InstructionHandle ih) { | |||
while (true) { | |||
if (ih.getInstruction()==Range.RANGEINSTRUCTION) ih = ih.getNext(); | |||
else return ih; | |||
} | |||
} | |||
private static InstructionHandle remap(InstructionHandle ih, Map map) { | |||
while (true) { | |||
@@ -1513,6 +1615,7 @@ public final class LazyMethodGen implements Traceable { | |||
// ---- | |||
boolean isAdviceMethod() { | |||
if (memberView==null) return false; | |||
return memberView.getAssociatedShadowMunger() != null; | |||
} | |||
@@ -1576,10 +1679,11 @@ public final class LazyMethodGen implements Traceable { | |||
* @param attr | |||
*/ | |||
public void addAttribute(Attribute attr) { | |||
Attribute[] newAttributes = new Attribute[attributes.length + 1]; | |||
System.arraycopy(attributes, 0, newAttributes, 0, attributes.length); | |||
newAttributes[attributes.length] = attr; | |||
attributes = newAttributes; | |||
attributes.add(attr); | |||
// Attribute[] newAttributes = new Attribute[attributes.length + 1]; | |||
// System.arraycopy(attributes, 0, newAttributes, 0, attributes.length); | |||
// newAttributes[attributes.length] = attr; | |||
// attributes = newAttributes; | |||
} | |||
public String toTraceString() { |
@@ -27,6 +27,7 @@ import org.aspectj.util.FileUtil; | |||
public class UnwovenClassFile { | |||
protected String filename; | |||
protected char[] charfilename; | |||
protected byte[] bytes; | |||
// protected JavaClass javaClass = null; | |||
//protected byte[] writtenBytes = null; | |||
@@ -149,9 +150,15 @@ public class UnwovenClassFile { | |||
return true; | |||
} | |||
public char[] getClassNameAsChars() { | |||
if (charfilename==null) { | |||
charfilename = getClassName().replace('.', '/').toCharArray(); | |||
} | |||
return charfilename; | |||
} | |||
public String getClassName() { | |||
if (className == null) className = getJavaClass().getClassName(); | |||
if (className == null) className = getJavaClass().getClassName(); // OPTIMIZE quicker way to determine name??? surely? | |||
return className; | |||
} | |||
@@ -184,6 +191,7 @@ public class UnwovenClassFile { | |||
} | |||
// record | |||
// OPTIMIZE why is the 'short name' used here (the bit after the dollar) - seems we mess about a lot trimming it off only to put it back on! | |||
public static class ChildClass { | |||
public final String name; | |||
public final byte[] bytes; | |||
@@ -206,6 +214,10 @@ public class UnwovenClassFile { | |||
return "(ChildClass " + name + ")"; | |||
} | |||
} | |||
public void setClassNameAsChars(char[] classNameAsChars) { | |||
this.charfilename = classNameAsChars; | |||
} | |||
} | |||
@@ -29,9 +29,11 @@ public class UnwovenClassFileWithThirdPartyManagedBytecode | |||
byte[] getBytes(); | |||
} | |||
public UnwovenClassFileWithThirdPartyManagedBytecode(String filename, | |||
// OPTIMIZE make classname an input char[] | |||
public UnwovenClassFileWithThirdPartyManagedBytecode(String filename,String classname, | |||
IByteCodeProvider provider) { | |||
super(filename,null); | |||
// APR29 | |||
super(filename,classname,null); | |||
this.provider = provider; | |||
} | |||
@@ -24,9 +24,12 @@ import java.util.Hashtable; | |||
import java.util.List; | |||
import org.aspectj.apache.bcel.Constants; | |||
import org.aspectj.apache.bcel.classfile.Attribute; | |||
import org.aspectj.apache.bcel.classfile.ClassParser; | |||
import org.aspectj.apache.bcel.classfile.ConstantPool; | |||
import org.aspectj.apache.bcel.classfile.JavaClass; | |||
import org.aspectj.apache.bcel.classfile.Method; | |||
import org.aspectj.apache.bcel.classfile.Unknown; | |||
import org.aspectj.apache.bcel.classfile.annotation.ArrayElementValueGen; | |||
import org.aspectj.apache.bcel.classfile.annotation.ElementNameValuePairGen; | |||
import org.aspectj.apache.bcel.classfile.annotation.ElementValueGen; | |||
@@ -52,6 +55,7 @@ import org.aspectj.apache.bcel.generic.SwitchBuilder; | |||
import org.aspectj.apache.bcel.generic.TargetLostException; | |||
import org.aspectj.apache.bcel.generic.Type; | |||
import org.aspectj.bridge.ISourceLocation; | |||
import org.aspectj.weaver.AjAttribute; | |||
import org.aspectj.weaver.AnnotationX; | |||
import org.aspectj.weaver.BCException; | |||
import org.aspectj.weaver.Lint; | |||
@@ -205,12 +209,8 @@ public class Utility { | |||
kind = Constants.INVOKEVIRTUAL; | |||
} | |||
return fact.createInvoke( | |||
declaringClass.getClassName(), | |||
newMethod.getName(), | |||
Type.getReturnType(newMethod.getSignature()), | |||
Type.getArgumentTypes(newMethod.getSignature()), | |||
kind); | |||
String sig = newMethod.getSignature(); | |||
return fact.createInvoke(declaringClass.getClassName(),newMethod.getName(),sig,kind); | |||
} | |||
public static byte[] stringToUTF(String s) { | |||
@@ -541,37 +541,6 @@ public class Utility { | |||
} | |||
} | |||
public static String arrayToString(int[] a) { | |||
int len = a.length; | |||
if (len == 0) return "[]"; | |||
StringBuffer buf = new StringBuffer("["); | |||
buf.append(a[0]); | |||
for (int i = 1; i < len; i++) { | |||
buf.append(", "); | |||
buf.append(a[i]); | |||
} | |||
buf.append("]"); | |||
return buf.toString(); | |||
} | |||
/** | |||
* replace an instruction handle with another instruction, in this case, a branch instruction. | |||
* | |||
* @param ih the instruction handle to replace. | |||
* @param branchInstruction the branch instruction to replace ih with | |||
* @param enclosingMethod where to find ih's instruction list. | |||
*/ | |||
public static void replaceInstruction( | |||
InstructionHandle ih, | |||
InstructionBranch branchInstruction, | |||
LazyMethodGen enclosingMethod) | |||
{ | |||
InstructionList il = enclosingMethod.getBody(); | |||
InstructionHandle fresh = il.append(ih, branchInstruction); | |||
deleteInstruction(ih, fresh, enclosingMethod); | |||
} | |||
public static void replaceInstruction( | |||
InstructionHandle ih, | |||
InstructionList replacementInstructions, | |||
@@ -704,15 +673,14 @@ public class Utility { | |||
// assumes that there is no already extant source line tag. Otherwise we'll have to be better. | |||
public static void setSourceLine(InstructionHandle ih, int lineNumber) { | |||
// OPTIMIZE LineNumberTag instances for the same line could be shared throughout a method... | |||
ih.addTargeter(new LineNumberTag(lineNumber)); | |||
} | |||
public static int makePublic(int i) { | |||
return i & ~(Modifier.PROTECTED | Modifier.PRIVATE) | Modifier.PUBLIC; | |||
} | |||
public static int makePrivate(int i) { | |||
return i & ~(Modifier.PROTECTED | Modifier.PUBLIC) | Modifier.PRIVATE; | |||
} | |||
public static BcelVar[] pushAndReturnArrayOfVars( | |||
ResolvedType[] proceedParamTypes, | |||
InstructionList il, | |||
@@ -806,25 +774,33 @@ public class Utility { | |||
} | |||
// not yet used... | |||
public static boolean isSimple(Method method) { | |||
if (method.getCode()==null) return true; | |||
if (method.getCode().getCode().length>10) return false; | |||
InstructionList instrucs = new InstructionList(method.getCode().getCode()); // expensive! | |||
InstructionHandle InstrHandle = instrucs.getStart(); | |||
while (InstrHandle != null) { | |||
Instruction Instr = InstrHandle.getInstruction(); | |||
int opCode = Instr.opcode; | |||
// if current instruction is a branch instruction, see if it's a backward branch. | |||
// if it is return immediately (can't be trivial) | |||
if (Instr instanceof InstructionBranch) { | |||
// InstructionBranch BI = (InstructionBranch) Instr; | |||
if (Instr.getIndex() < 0) return false; | |||
} else if (Instr instanceof InvokeInstruction) { | |||
// if current instruction is an invocation, indicate that it can't be trivial | |||
return false; | |||
} | |||
InstrHandle = InstrHandle.getNext(); | |||
} | |||
return true; | |||
} | |||
// public static boolean isSimple(Method method) { | |||
// if (method.getCode()==null) return true; | |||
// if (method.getCode().getCode().length>10) return false; | |||
// InstructionList instrucs = new InstructionList(method.getCode().getCode()); // expensive! | |||
// InstructionHandle InstrHandle = instrucs.getStart(); | |||
// while (InstrHandle != null) { | |||
// Instruction Instr = InstrHandle.getInstruction(); | |||
// int opCode = Instr.opcode; | |||
// // if current instruction is a branch instruction, see if it's a backward branch. | |||
// // if it is return immediately (can't be trivial) | |||
// if (Instr instanceof InstructionBranch) { | |||
// // InstructionBranch BI = (InstructionBranch) Instr; | |||
// if (Instr.getIndex() < 0) return false; | |||
// } else if (Instr instanceof InvokeInstruction) { | |||
// // if current instruction is an invocation, indicate that it can't be trivial | |||
// return false; | |||
// } | |||
// InstrHandle = InstrHandle.getNext(); | |||
// } | |||
// return true; | |||
// } | |||
public static Attribute bcelAttribute(AjAttribute a, ConstantPool pool) { | |||
int nameIndex = pool.addUtf8(a.getNameString()); | |||
byte[] bytes = a.getBytes(); | |||
int length = bytes.length; | |||
return new Unknown(nameIndex, length, bytes, pool); | |||
} | |||
} |
@@ -14,6 +14,9 @@ package org.aspectj.weaver.loadtime; | |||
import java.io.IOException; | |||
import java.net.URL; | |||
import java.util.Enumeration; | |||
import java.util.List; | |||
import org.aspectj.weaver.tools.WeavingAdaptor; | |||
/** | |||
* This class adds support to AspectJ for an OSGi environment | |||
@@ -73,4 +76,14 @@ public interface IWeavingContext { | |||
*/ | |||
public boolean isLocallyDefined(String classname); | |||
/** | |||
* Allow custom parsing of aop.xml or alternative mechanism for providing | |||
* Definitions | |||
* | |||
* @param loader | |||
* @param adaptor | |||
* @return List containing 0 or more Definition instances | |||
*/ | |||
public List getDefinitions(final ClassLoader loader, WeavingAdaptor adaptor); | |||
} |
@@ -258,6 +258,8 @@ public class LTWWorld extends BcelWorld implements IReflectionWorld { | |||
visitor.visitObject(loader.getParent()); | |||
super.accept(visitor); | |||
} | |||
public boolean shouldGoForIt() { | |||
return true; // Zooooooooooom | |||
} | |||
} |
@@ -1,22 +0,0 @@ | |||
/* ******************************************************************* | |||
* Copyright (c) 2005 Contributors. | |||
* 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://eclipse.org/legal/epl-v10.html | |||
* | |||
* Contributors: | |||
* Adrian Colyer Initial implementation | |||
* ******************************************************************/ | |||
package org.aspectj.weaver.ltw; | |||
import org.aspectj.weaver.IWeaver; | |||
/** | |||
* @author adrian | |||
* | |||
*/ | |||
public class LTWeaver implements IWeaver { | |||
} |
@@ -18,7 +18,8 @@ import org.aspectj.weaver.AnnotatedElement; | |||
import org.aspectj.weaver.ISourceContext; | |||
import org.aspectj.weaver.VersionedDataInputStream; | |||
import org.aspectj.weaver.World; | |||
import org.aspectj.weaver.AjAttribute.WeaverVersionInfo; | |||
import org.aspectj.weaver.ResolvedType; | |||
/** | |||
* @author colyer | |||
* | |||
@@ -39,6 +40,10 @@ public class AndAnnotationTypePattern extends AnnotationTypePattern { | |||
public FuzzyBoolean matches(AnnotatedElement annotated) { | |||
return left.matches(annotated).and(right.matches(annotated)); | |||
} | |||
public FuzzyBoolean matches(AnnotatedElement annotated, ResolvedType[] parameterAnnotations ) { | |||
return left.matches(annotated,parameterAnnotations).and(right.matches(annotated,parameterAnnotations)); | |||
} | |||
public void resolve(World world) { | |||
left.resolve(world); | |||
@@ -60,6 +65,7 @@ public class AndAnnotationTypePattern extends AnnotationTypePattern { | |||
AnnotationTypePattern newRight = right.parameterizeWith(typeVariableMap,w); | |||
AndAnnotationTypePattern ret = new AndAnnotationTypePattern(newLeft,newRight); | |||
ret.copyLocationFrom(this); | |||
if (this.isForParameterAnnotationMatch()) ret.setForParameterAnnotationMatch(); | |||
return ret; | |||
} | |||
@@ -68,6 +74,9 @@ public class AndAnnotationTypePattern extends AnnotationTypePattern { | |||
AnnotationTypePattern.read(s,context), | |||
AnnotationTypePattern.read(s,context)); | |||
p.readLocation(context,s); | |||
if (s.getMajorVersion()>=WeaverVersionInfo.WEAVER_VERSION_MINOR_AJ160) { | |||
if (s.readBoolean()) p.setForParameterAnnotationMatch(); | |||
} | |||
return p; | |||
} | |||
@@ -76,18 +85,20 @@ public class AndAnnotationTypePattern extends AnnotationTypePattern { | |||
left.write(s); | |||
right.write(s); | |||
writeLocation(s); | |||
s.writeBoolean(isForParameterAnnotationMatch()); | |||
} | |||
public boolean equals(Object obj) { | |||
if (!(obj instanceof AndAnnotationTypePattern)) return false; | |||
AndAnnotationTypePattern other = (AndAnnotationTypePattern) obj; | |||
return (left.equals(other.left) && right.equals(other.right)); | |||
return (left.equals(other.left) && right.equals(other.right) && left.isForParameterAnnotationMatch()==right.isForParameterAnnotationMatch()); | |||
} | |||
public int hashCode() { | |||
int result = 17; | |||
result = result*37 + left.hashCode(); | |||
result = result*37 + right.hashCode(); | |||
result = result*37 + (isForParameterAnnotationMatch()?0:1); | |||
return result; | |||
} | |||
@@ -108,4 +119,9 @@ public class AndAnnotationTypePattern extends AnnotationTypePattern { | |||
right.traverse(visitor,ret); | |||
return ret; | |||
} | |||
public void setForParameterAnnotationMatch() { | |||
left.setForParameterAnnotationMatch(); | |||
right.setForParameterAnnotationMatch(); | |||
} | |||
} |
@@ -18,6 +18,7 @@ import org.aspectj.weaver.AnnotatedElement; | |||
import org.aspectj.weaver.BCException; | |||
import org.aspectj.weaver.ISourceContext; | |||
import org.aspectj.weaver.IntMap; | |||
import org.aspectj.weaver.ResolvedType; | |||
import org.aspectj.weaver.VersionedDataInputStream; | |||
import org.aspectj.weaver.World; | |||
@@ -25,6 +26,8 @@ public abstract class AnnotationTypePattern extends PatternNode { | |||
public static final AnnotationTypePattern ANY = new AnyAnnotationTypePattern(); | |||
public static final AnnotationTypePattern ELLIPSIS = new EllipsisAnnotationTypePattern(); | |||
public static final AnnotationTypePattern[] NONE = new AnnotationTypePattern[0]; | |||
private boolean isForParameterAnnotationMatch; | |||
/** | |||
* TODO: write, read, equals & hashcode both in annotation hierarachy and | |||
@@ -35,6 +38,7 @@ public abstract class AnnotationTypePattern extends PatternNode { | |||
} | |||
public abstract FuzzyBoolean matches(AnnotatedElement annotated); | |||
public abstract FuzzyBoolean matches(AnnotatedElement annotated,ResolvedType[] parameterAnnotations); | |||
public FuzzyBoolean fastMatches(AnnotatedElement annotated) { | |||
return FuzzyBoolean.MAYBE; | |||
@@ -84,44 +88,22 @@ public abstract class AnnotationTypePattern extends PatternNode { | |||
throw new BCException("unknown TypePattern kind: " + key); | |||
} | |||
} | |||
class AnyAnnotationTypePattern extends AnnotationTypePattern { | |||
public FuzzyBoolean fastMatches(AnnotatedElement annotated) { | |||
return FuzzyBoolean.YES; | |||
} | |||
public FuzzyBoolean matches(AnnotatedElement annotated) { | |||
return FuzzyBoolean.YES; | |||
} | |||
public void write(DataOutputStream s) throws IOException { | |||
s.writeByte(AnnotationTypePattern.ANY_KEY); | |||
} | |||
public void resolve(World world) { | |||
} | |||
public String toString() { return "@ANY"; } | |||
public void setForParameterAnnotationMatch() { isForParameterAnnotationMatch = true; } | |||
public boolean isForParameterAnnotationMatch() { return isForParameterAnnotationMatch; } | |||
public Object accept(PatternNodeVisitor visitor, Object data) { | |||
return visitor.visit(this, data); | |||
} | |||
public boolean isAny() { return true; } | |||
public AnnotationTypePattern parameterizeWith(Map arg0,World w) { | |||
return this; | |||
} | |||
} | |||
class EllipsisAnnotationTypePattern extends AnnotationTypePattern { | |||
public FuzzyBoolean matches(AnnotatedElement annotated) { | |||
return FuzzyBoolean.NO; | |||
} | |||
public FuzzyBoolean matches(AnnotatedElement annotated,ResolvedType[] parameterAnnotations) { | |||
return FuzzyBoolean.NO; | |||
} | |||
public void write(DataOutputStream s) throws IOException { | |||
s.writeByte(AnnotationTypePattern.ELLIPSIS_KEY); | |||
} |
@@ -0,0 +1,55 @@ | |||
/* ******************************************************************* | |||
* Copyright (c) 2008 Contributors | |||
* 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 | |||
* Andy Clement - extracted from AnnotationTypePattern | |||
* ******************************************************************/ | |||
package org.aspectj.weaver.patterns; | |||
import java.io.DataOutputStream; | |||
import java.io.IOException; | |||
import java.util.Map; | |||
import org.aspectj.util.FuzzyBoolean; | |||
import org.aspectj.weaver.AnnotatedElement; | |||
import org.aspectj.weaver.World; | |||
import org.aspectj.weaver.ResolvedType; | |||
public class AnyAnnotationTypePattern extends AnnotationTypePattern { | |||
public FuzzyBoolean fastMatches(AnnotatedElement annotated) { | |||
return FuzzyBoolean.YES; | |||
} | |||
public FuzzyBoolean matches(AnnotatedElement annotated) { | |||
return FuzzyBoolean.YES; | |||
} | |||
public FuzzyBoolean matches(AnnotatedElement annotated,ResolvedType[] parameterAnnotations) { | |||
return FuzzyBoolean.YES; | |||
} | |||
public void write(DataOutputStream s) throws IOException { | |||
s.writeByte(AnnotationTypePattern.ANY_KEY); | |||
} | |||
public void resolve(World world) { | |||
} | |||
public String toString() { return "@ANY"; } | |||
public Object accept(PatternNodeVisitor visitor, Object data) { | |||
return visitor.visit(this, data); | |||
} | |||
public boolean isAny() { return true; } | |||
public AnnotationTypePattern parameterizeWith(Map arg0,World w) { | |||
return this; | |||
} | |||
} |
@@ -23,7 +23,7 @@ import java.util.Map; | |||
import org.aspectj.bridge.IMessage; | |||
import org.aspectj.bridge.ISourceLocation; | |||
import org.aspectj.util.FuzzyBoolean; | |||
import org.aspectj.weaver.BetaException; | |||
import org.aspectj.weaver.BCException; | |||
import org.aspectj.weaver.ISourceContext; | |||
import org.aspectj.weaver.IntMap; | |||
import org.aspectj.weaver.ResolvedType; | |||
@@ -293,7 +293,7 @@ public class ArgsPointcut extends NameBindingPointcut { | |||
} | |||
return findResidueNoEllipsis(shadow, state, patternsWithoutEllipsis); | |||
} else { | |||
throw new BetaException("unimplemented"); | |||
throw new BCException("unimplemented"); | |||
} | |||
} | |||
@@ -106,6 +106,7 @@ public class BasicTokenSource implements ITokenSource { | |||
case '@': | |||
case '<': | |||
case '>': | |||
case '=': | |||
case '?': | |||
tokens.add(BasicToken.makeOperator(makeString(ch), i-1, i-1)); | |||
continue; |
@@ -33,7 +33,7 @@ public class BindingAnnotationTypePattern extends ExactAnnotationTypePattern imp | |||
* @param annotationType | |||
*/ | |||
public BindingAnnotationTypePattern(UnresolvedType annotationType, int index) { | |||
super(annotationType); | |||
super(annotationType,null); | |||
this.formalIndex = index; | |||
} | |||
@@ -105,7 +105,7 @@ public class BindingAnnotationTypePattern extends ExactAnnotationTypePattern imp | |||
public AnnotationTypePattern remapAdviceFormals(IntMap bindings) { | |||
if (!bindings.hasKey(formalIndex)) { | |||
return new ExactAnnotationTypePattern(annotationType); | |||
return new ExactAnnotationTypePattern(annotationType,null); | |||
} else { | |||
int newFormalIndex = bindings.get(formalIndex); | |||
return new BindingAnnotationTypePattern(annotationType, newFormalIndex); |
@@ -50,8 +50,6 @@ public class CflowPointcut extends Pointcut { | |||
boolean isBelow;// Is this cflowbelow? | |||
private int[] freeVars; | |||
private static Hashtable cflowFields = new Hashtable(); | |||
private static Hashtable cflowBelowFields = new Hashtable(); | |||
/** | |||
* Used to indicate that we're in the context of a cflow when concretizing if's | |||
@@ -217,7 +215,7 @@ public class CflowPointcut extends Pointcut { | |||
if (freeVars==null || freeVars.length == 0) { // No state, so don't use a stack, use a counter. | |||
ResolvedMember localCflowField = null; | |||
Object field = getCflowfield(concreteEntry,concreteAspect,"counter"); | |||
Object field = getCflowfield(xcut, concreteEntry, concreteAspect, "counter"); | |||
// Check if we have already got a counter for this cflow pointcut | |||
if (field != null) { | |||
@@ -236,7 +234,7 @@ public class CflowPointcut extends Pointcut { | |||
concreteAspect.crosscuttingMembers.addConcreteShadowMunger( | |||
Advice.makeCflowEntry(world,concreteEntry,isBelow,localCflowField,freeVars==null?0:freeVars.length,innerCflowEntries,inAspect)); | |||
putCflowfield(concreteEntry,concreteAspect,localCflowField,"counter"); // Remember it | |||
putCflowfield(xcut,concreteEntry,concreteAspect,localCflowField,"counter"); // Remember it | |||
} | |||
Pointcut ret = new ConcreteCflowPointcut(localCflowField, null,true); | |||
@@ -276,7 +274,7 @@ public class CflowPointcut extends Pointcut { | |||
slots.add(slot); | |||
} | |||
ResolvedMember localCflowField = null; | |||
Object field = getCflowfield(concreteEntry,concreteAspect,"stack"); | |||
Object field = getCflowfield(xcut,concreteEntry,concreteAspect,"stack"); | |||
if (field != null) { | |||
localCflowField = (ResolvedMember)field; | |||
} else { | |||
@@ -295,7 +293,7 @@ public class CflowPointcut extends Pointcut { | |||
concreteAspect.crosscuttingMembers.addTypeMunger( | |||
world.makeCflowStackFieldAdder(localCflowField)); | |||
putCflowfield(concreteEntry,concreteAspect,localCflowField,"stack"); | |||
putCflowfield(xcut,concreteEntry,concreteAspect,localCflowField,"stack"); | |||
} | |||
Pointcut ret = new ConcreteCflowPointcut(localCflowField, slots,false); | |||
ret.copyLocationFrom(this); | |||
@@ -304,10 +302,6 @@ public class CflowPointcut extends Pointcut { | |||
} | |||
public static void clearCaches() { | |||
cflowFields.clear(); | |||
cflowBelowFields.clear(); | |||
} | |||
private String getKey(Pointcut p,ResolvedType a,String stackOrCounter) { | |||
StringBuffer sb = new StringBuffer(); | |||
@@ -319,22 +313,22 @@ public class CflowPointcut extends Pointcut { | |||
return sb.toString(); | |||
} | |||
private Object getCflowfield(Pointcut pcutkey, ResolvedType concreteAspect,String stackOrCounter) { | |||
private Object getCflowfield(CrosscuttingMembers xcut, Pointcut pcutkey, ResolvedType concreteAspect,String stackOrCounter) { | |||
String key = getKey(pcutkey,concreteAspect,stackOrCounter); | |||
Object o =null; | |||
if (isBelow) o = cflowBelowFields.get(key); | |||
else o = cflowFields.get(key); | |||
if (isBelow) o = xcut.getCflowBelowFields().get(key); | |||
else o = xcut.getCflowFields().get(key); | |||
//System.err.println("Retrieving for key "+key+" returning "+o); | |||
return o; | |||
} | |||
private void putCflowfield(Pointcut pcutkey,ResolvedType concreteAspect,Object o,String stackOrCounter) { | |||
private void putCflowfield(CrosscuttingMembers xcut, Pointcut pcutkey,ResolvedType concreteAspect,Object o,String stackOrCounter) { | |||
String key = getKey(pcutkey,concreteAspect,stackOrCounter); | |||
//System.err.println("Storing cflow field for key"+key); | |||
if (isBelow) { | |||
cflowBelowFields.put(key,o); | |||
xcut.getCflowBelowFields().put(key,o); | |||
} else { | |||
cflowFields.put(key,o); | |||
xcut.getCflowFields().put(key,o); | |||
} | |||
} | |||
@@ -342,23 +336,4 @@ public class CflowPointcut extends Pointcut { | |||
return visitor.visit(this, data); | |||
} | |||
public static void clearCaches(ResolvedType aspectType) { | |||
//System.err.println("Wiping entries starting "+aspectType.getName()); | |||
String key = aspectType.getName()+"::"; | |||
wipeKeys(key,cflowFields); | |||
wipeKeys(key,cflowBelowFields); | |||
} | |||
private static void wipeKeys(String keyPrefix,Hashtable ht) { | |||
Enumeration keys = ht.keys(); | |||
List forRemoval = new ArrayList(); | |||
while (keys.hasMoreElements()) { | |||
String s = (String)keys.nextElement(); | |||
if (s.startsWith(keyPrefix)) forRemoval.add(s); | |||
} | |||
for (Iterator iter = forRemoval.iterator(); iter.hasNext();) { | |||
String element = (String) iter.next(); | |||
ht.remove(element); | |||
} | |||
} | |||
} |
@@ -11,21 +11,27 @@ package org.aspectj.weaver.patterns; | |||
import java.io.DataOutputStream; | |||
import java.io.IOException; | |||
import java.util.HashMap; | |||
import java.util.Iterator; | |||
import java.util.Map; | |||
import java.util.Set; | |||
import org.aspectj.bridge.IMessage; | |||
import org.aspectj.bridge.MessageUtil; | |||
import org.aspectj.util.FuzzyBoolean; | |||
import org.aspectj.weaver.AnnotatedElement; | |||
import org.aspectj.weaver.AnnotationX; | |||
import org.aspectj.weaver.BCException; | |||
import org.aspectj.weaver.ISourceContext; | |||
import org.aspectj.weaver.ReferenceType; | |||
import org.aspectj.weaver.ResolvedMember; | |||
import org.aspectj.weaver.ResolvedType; | |||
import org.aspectj.weaver.TypeVariableReference; | |||
import org.aspectj.weaver.UnresolvedType; | |||
import org.aspectj.weaver.VersionedDataInputStream; | |||
import org.aspectj.weaver.WeaverMessages; | |||
import org.aspectj.weaver.World; | |||
import org.aspectj.weaver.AjAttribute.WeaverVersionInfo; | |||
/** | |||
* Matches an annotation of a given type | |||
@@ -36,11 +42,21 @@ public class ExactAnnotationTypePattern extends AnnotationTypePattern { | |||
protected String formalName; | |||
protected boolean resolved = false; | |||
private boolean bindingPattern = false; | |||
private Map annotationValues; | |||
/** | |||
* @param annotationValues | |||
* | |||
*/ | |||
public ExactAnnotationTypePattern(UnresolvedType annotationType) { | |||
// OPTIMIZE is annotationtype really unresolved???? surely it is resolved by now... | |||
public ExactAnnotationTypePattern(UnresolvedType annotationType, Map annotationValues) { | |||
this.annotationType = annotationType; | |||
this.annotationValues = annotationValues; | |||
this.resolved = (annotationType instanceof ResolvedType); | |||
} | |||
// Used when deserializing, values will be added | |||
private ExactAnnotationTypePattern(UnresolvedType annotationType) { | |||
this.annotationType = annotationType; | |||
this.resolved = (annotationType instanceof ResolvedType); | |||
} | |||
@@ -60,9 +76,13 @@ public class ExactAnnotationTypePattern extends AnnotationTypePattern { | |||
public UnresolvedType getAnnotationType() { | |||
return annotationType; | |||
} | |||
public Map getAnnotationValues() { | |||
return annotationValues; | |||
} | |||
public FuzzyBoolean fastMatches(AnnotatedElement annotated) { | |||
if (annotated.hasAnnotation(annotationType)) { | |||
if (annotated.hasAnnotation(annotationType) && annotationValues == null) { | |||
return FuzzyBoolean.YES; | |||
} else { | |||
// could be inherited, but we don't know that until we are | |||
@@ -72,30 +92,116 @@ public class ExactAnnotationTypePattern extends AnnotationTypePattern { | |||
} | |||
public FuzzyBoolean matches(AnnotatedElement annotated) { | |||
boolean checkSupers = false; | |||
if (getResolvedAnnotationType().hasAnnotation(UnresolvedType.AT_INHERITED)) { | |||
if (annotated instanceof ResolvedType) { | |||
checkSupers = true; | |||
} | |||
} | |||
if (annotated.hasAnnotation(annotationType)) { | |||
if (annotationType instanceof ReferenceType) { | |||
ReferenceType rt = (ReferenceType)annotationType; | |||
if (rt.getRetentionPolicy()!=null && rt.getRetentionPolicy().equals("SOURCE")) { | |||
rt.getWorld().getMessageHandler().handleMessage( | |||
MessageUtil.warn(WeaverMessages.format(WeaverMessages.NO_MATCH_BECAUSE_SOURCE_RETENTION,annotationType,annotated),getSourceLocation())); | |||
return FuzzyBoolean.NO; | |||
return matches(annotated,null); | |||
} | |||
public FuzzyBoolean matches(AnnotatedElement annotated,ResolvedType[] parameterAnnotations) { | |||
if (!isForParameterAnnotationMatch()) { | |||
boolean checkSupers = false; | |||
if (getResolvedAnnotationType().hasAnnotation(UnresolvedType.AT_INHERITED)) { | |||
if (annotated instanceof ResolvedType) { | |||
checkSupers = true; | |||
} | |||
} | |||
return FuzzyBoolean.YES; | |||
} else if (checkSupers) { | |||
ResolvedType toMatchAgainst = ((ResolvedType) annotated).getSuperclass(); | |||
while (toMatchAgainst != null) { | |||
if (toMatchAgainst.hasAnnotation(annotationType)) return FuzzyBoolean.YES; | |||
toMatchAgainst = toMatchAgainst.getSuperclass(); | |||
if (annotated.hasAnnotation(annotationType)) { | |||
if (annotationType instanceof ReferenceType) { | |||
ReferenceType rt = (ReferenceType)annotationType; | |||
if (rt.getRetentionPolicy()!=null && rt.getRetentionPolicy().equals("SOURCE")) { | |||
rt.getWorld().getMessageHandler().handleMessage( | |||
MessageUtil.warn(WeaverMessages.format(WeaverMessages.NO_MATCH_BECAUSE_SOURCE_RETENTION,annotationType,annotated),getSourceLocation())); | |||
return FuzzyBoolean.NO; | |||
} | |||
} | |||
// Are we also matching annotation values? | |||
if (annotationValues!=null) { | |||
AnnotationX theAnnotation = annotated.getAnnotationOfType(annotationType); | |||
// Check each one | |||
Set keys = annotationValues.keySet(); | |||
for (Iterator keyIter = keys.iterator(); keyIter.hasNext();) { | |||
String k = (String) keyIter.next(); | |||
String v = (String)annotationValues.get(k); | |||
if (theAnnotation.hasNamedValue(k)) { | |||
// Simple case, value is 'name=value' and the annotation specified the same thing | |||
if (!theAnnotation.hasNameValuePair(k,v)) { | |||
return FuzzyBoolean.NO; | |||
} | |||
} else { | |||
// Complex case, look at the default value | |||
ResolvedMember[] ms = ((ResolvedType)annotationType).getDeclaredMethods(); | |||
boolean foundMatch = false; | |||
for (int i=0; i<ms.length && !foundMatch;i++) { | |||
if (ms[i].isAbstract() && ms[i].getParameterTypes().length==0 && ms[i].getName().equals(k)) { | |||
// we might be onto something | |||
String s= ms[i].getAnnotationDefaultValue(); | |||
if (s!=null && s.equals(v)) foundMatch=true;; | |||
} | |||
} | |||
if (!foundMatch) | |||
return FuzzyBoolean.NO; | |||
} | |||
} | |||
} | |||
return FuzzyBoolean.YES; | |||
} else if (checkSupers) { | |||
ResolvedType toMatchAgainst = ((ResolvedType) annotated).getSuperclass(); | |||
while (toMatchAgainst != null) { | |||
if (toMatchAgainst.hasAnnotation(annotationType)) { | |||
// Are we also matching annotation values? | |||
if (annotationValues!=null) { | |||
AnnotationX theAnnotation = toMatchAgainst.getAnnotationOfType(annotationType); | |||
// Check each one | |||
Set keys = annotationValues.keySet(); | |||
for (Iterator keyIter = keys.iterator(); keyIter.hasNext();) { | |||
String k = (String) keyIter.next(); | |||
String v = (String)annotationValues.get(k); | |||
if (theAnnotation.hasNamedValue(k)) { | |||
// Simple case, value is 'name=value' and the annotation specified the same thing | |||
if (!theAnnotation.hasNameValuePair(k,v)) { | |||
return FuzzyBoolean.NO; | |||
} | |||
} else { | |||
// Complex case, look at the default value | |||
ResolvedMember[] ms = ((ResolvedType)annotationType).getDeclaredMethods(); | |||
boolean foundMatch = false; | |||
for (int i=0; i<ms.length && !foundMatch;i++) { | |||
if (ms[i].isAbstract() && ms[i].getParameterTypes().length==0 && ms[i].getName().equals(k)) { | |||
// we might be onto something | |||
String s= ms[i].getAnnotationDefaultValue(); | |||
if (s!=null && s.equals(v)) foundMatch=true;; | |||
} | |||
} | |||
if (!foundMatch) | |||
return FuzzyBoolean.NO; | |||
} | |||
} | |||
} | |||
return FuzzyBoolean.YES; | |||
} | |||
toMatchAgainst = toMatchAgainst.getSuperclass(); | |||
} | |||
} | |||
} else { | |||
// check parameter annotations | |||
if (parameterAnnotations==null) return FuzzyBoolean.NO; | |||
for (int i = 0; i < parameterAnnotations.length; i++) { | |||
if (annotationType.equals(parameterAnnotations[i])) { | |||
// Are we also matching annotation values? | |||
if (annotationValues!=null) { | |||
parameterAnnotations[i].getWorld().getMessageHandler().handleMessage( | |||
MessageUtil.error("Compiler limitation: annotation value matching for parameter annotations not yet supported")); | |||
return FuzzyBoolean.NO; | |||
} | |||
return FuzzyBoolean.YES; | |||
} | |||
} | |||
} | |||
} | |||
return FuzzyBoolean.NO; | |||
} | |||
@@ -113,7 +219,9 @@ public class ExactAnnotationTypePattern extends AnnotationTypePattern { | |||
public void resolve(World world) { | |||
if (!resolved) annotationType = annotationType.resolve(world); | |||
if (!resolved) { | |||
annotationType = annotationType.resolve(world); | |||
} | |||
resolved = true; | |||
} | |||
@@ -144,6 +252,7 @@ public class ExactAnnotationTypePattern extends AnnotationTypePattern { | |||
binding.copyLocationFrom(this); | |||
bindings.register(binding, scope); | |||
binding.resolveBinding(scope.getWorld()); | |||
if (isForParameterAnnotationMatch()) binding.setForParameterAnnotationMatch(); | |||
return binding; | |||
} | |||
@@ -179,10 +288,11 @@ public class ExactAnnotationTypePattern extends AnnotationTypePattern { | |||
} else if (annotationType.isParameterizedType()) { | |||
newAnnotationType = annotationType.parameterize(typeVariableMap); | |||
} | |||
ExactAnnotationTypePattern ret = new ExactAnnotationTypePattern(newAnnotationType); | |||
ExactAnnotationTypePattern ret = new ExactAnnotationTypePattern(newAnnotationType,annotationValues); | |||
ret.formalName = formalName; | |||
ret.bindingPattern = bindingPattern; | |||
ret.copyLocationFrom(this); | |||
if (isForParameterAnnotationMatch()) ret.setForParameterAnnotationMatch(); | |||
return ret; | |||
} | |||
@@ -219,10 +329,22 @@ public class ExactAnnotationTypePattern extends AnnotationTypePattern { | |||
annotationType.write(s); | |||
} | |||
writeLocation(s); | |||
s.writeBoolean(isForParameterAnnotationMatch()); | |||
if (annotationValues==null) { | |||
s.writeInt(0); | |||
} else { | |||
s.writeInt(annotationValues.size()); | |||
Set key = annotationValues.keySet(); | |||
for (Iterator keys = key.iterator(); keys.hasNext();) { | |||
String k = (String) keys.next(); | |||
s.writeUTF(k); | |||
s.writeUTF((String)annotationValues.get(k)); | |||
} | |||
} | |||
} | |||
public static AnnotationTypePattern read(VersionedDataInputStream s,ISourceContext context) throws IOException { | |||
AnnotationTypePattern ret; | |||
ExactAnnotationTypePattern ret; | |||
byte version = s.readByte(); | |||
if (version > VERSION) { | |||
throw new BCException("ExactAnnotationTypePattern was written by a newer version of AspectJ"); | |||
@@ -234,6 +356,21 @@ public class ExactAnnotationTypePattern extends AnnotationTypePattern { | |||
ret = new ExactAnnotationTypePattern(UnresolvedType.read(s)); | |||
} | |||
ret.readLocation(context,s); | |||
if (s.getMajorVersion()>=WeaverVersionInfo.WEAVER_VERSION_MAJOR_AJ160) { | |||
if (s.readBoolean()) ret.setForParameterAnnotationMatch(); | |||
} | |||
if (s.getMajorVersion()>=WeaverVersionInfo.WEAVER_VERSION_MAJOR_AJ160M2) { | |||
int annotationValueCount = s.readInt(); | |||
if (annotationValueCount>0) { | |||
Map aValues = new HashMap(); | |||
for (int i=0;i<annotationValueCount;i++) { | |||
String key = s.readUTF(); | |||
String val = s.readUTF(); | |||
aValues.put(key,val); | |||
} | |||
ret.annotationValues = aValues; | |||
} | |||
} | |||
return ret; | |||
} | |||
@@ -243,14 +380,14 @@ public class ExactAnnotationTypePattern extends AnnotationTypePattern { | |||
public boolean equals(Object obj) { | |||
if (!(obj instanceof ExactAnnotationTypePattern)) return false; | |||
ExactAnnotationTypePattern other = (ExactAnnotationTypePattern) obj; | |||
return (other.annotationType.equals(annotationType)); | |||
return (other.annotationType.equals(annotationType)) && isForParameterAnnotationMatch()==other.isForParameterAnnotationMatch(); | |||
} | |||
/* (non-Javadoc) | |||
* @see java.lang.Object#hashCode() | |||
*/ | |||
public int hashCode() { | |||
return annotationType.hashCode(); | |||
return annotationType.hashCode()*37+(isForParameterAnnotationMatch()?0:1); | |||
} | |||
public String toString() { |
@@ -106,7 +106,12 @@ public class ExactTypePattern extends TypePattern { | |||
typeMatch = matchesTypeVariable((TypeVariableReferenceType)matchType); | |||
} | |||
annotationPattern.resolve(matchType.getWorld()); | |||
boolean annMatch = this.annotationPattern.matches(matchType).alwaysTrue(); | |||
boolean annMatch = false; | |||
if (matchType.temporaryAnnotationTypes!=null) { | |||
annMatch = annotationPattern.matches(matchType,matchType.temporaryAnnotationTypes).alwaysTrue(); | |||
} else { | |||
annMatch = annotationPattern.matches(matchType).alwaysTrue(); | |||
} | |||
return (typeMatch && annMatch); | |||
} | |||
@@ -125,7 +130,12 @@ public class ExactTypePattern extends TypePattern { | |||
typeMatch = matchesTypeVariable((TypeVariableReferenceType)matchType); | |||
} | |||
annotationPattern.resolve(matchType.getWorld()); | |||
boolean annMatch = this.annotationPattern.matches(annotatedType).alwaysTrue(); | |||
boolean annMatch = false; | |||
if (annotatedType.temporaryAnnotationTypes!=null) { | |||
annMatch = annotationPattern.matches(annotatedType,annotatedType.temporaryAnnotationTypes).alwaysTrue(); | |||
} else { | |||
annMatch = annotationPattern.matches(annotatedType).alwaysTrue(); | |||
} | |||
return (typeMatch && annMatch); | |||
} | |||
@@ -134,6 +144,7 @@ public class ExactTypePattern extends TypePattern { | |||
// true if (matchType instanceof this.type) | |||
public FuzzyBoolean matchesInstanceof(ResolvedType matchType) { | |||
// in our world, Object is assignable from anything | |||
annotationPattern.resolve(matchType.getWorld()); | |||
if (type.equals(ResolvedType.OBJECT)) | |||
return FuzzyBoolean.YES.and(annotationPattern.matches(matchType)); | |||
@@ -16,8 +16,10 @@ import java.util.Map; | |||
import org.aspectj.util.FuzzyBoolean; | |||
import org.aspectj.weaver.AnnotatedElement; | |||
import org.aspectj.weaver.ISourceContext; | |||
import org.aspectj.weaver.ResolvedType; | |||
import org.aspectj.weaver.VersionedDataInputStream; | |||
import org.aspectj.weaver.World; | |||
import org.aspectj.weaver.AjAttribute.WeaverVersionInfo; | |||
public class NotAnnotationTypePattern extends AnnotationTypePattern { | |||
@@ -35,6 +37,9 @@ public class NotAnnotationTypePattern extends AnnotationTypePattern { | |||
return negatedPattern.matches(annotated).not(); | |||
} | |||
public FuzzyBoolean matches(AnnotatedElement annotated,ResolvedType[] parameterAnnotations) { | |||
return negatedPattern.matches(annotated,parameterAnnotations).not(); | |||
} | |||
/* (non-Javadoc) | |||
* @see org.aspectj.weaver.patterns.AnnotationTypePattern#resolve(org.aspectj.weaver.World) | |||
*/ | |||
@@ -56,6 +61,7 @@ public class NotAnnotationTypePattern extends AnnotationTypePattern { | |||
AnnotationTypePattern newNegatedPattern = negatedPattern.parameterizeWith(typeVariableMap,w); | |||
NotAnnotationTypePattern ret = new NotAnnotationTypePattern(newNegatedPattern); | |||
ret.copyLocationFrom(this); | |||
if (this.isForParameterAnnotationMatch()) ret.setForParameterAnnotationMatch(); | |||
return ret; | |||
} | |||
@@ -66,22 +72,27 @@ public class NotAnnotationTypePattern extends AnnotationTypePattern { | |||
s.writeByte(AnnotationTypePattern.NOT); | |||
negatedPattern.write(s); | |||
writeLocation(s); | |||
s.writeBoolean(isForParameterAnnotationMatch()); | |||
} | |||
public static AnnotationTypePattern read(VersionedDataInputStream s, ISourceContext context) throws IOException { | |||
AnnotationTypePattern ret = new NotAnnotationTypePattern(AnnotationTypePattern.read(s,context)); | |||
ret.readLocation(context,s); | |||
if (s.getMajorVersion()>=WeaverVersionInfo.WEAVER_VERSION_MINOR_AJ160) { | |||
if (s.readBoolean()) ret.setForParameterAnnotationMatch(); | |||
} | |||
return ret; | |||
} | |||
public boolean equals(Object obj) { | |||
if (!(obj instanceof NotAnnotationTypePattern)) return false; | |||
NotAnnotationTypePattern other = (NotAnnotationTypePattern) obj; | |||
return other.negatedPattern.equals(negatedPattern); | |||
return other.negatedPattern.equals(negatedPattern) && other.isForParameterAnnotationMatch()==isForParameterAnnotationMatch(); | |||
} | |||
public int hashCode() { | |||
int result = 17 + 37*negatedPattern.hashCode(); | |||
result = 37*result +(isForParameterAnnotationMatch()?0:1); | |||
return result; | |||
} | |||
@@ -102,4 +113,8 @@ public class NotAnnotationTypePattern extends AnnotationTypePattern { | |||
negatedPattern.traverse(visitor,ret); | |||
return ret; | |||
} | |||
public void setForParameterAnnotationMatch() { | |||
negatedPattern.setForParameterAnnotationMatch(); | |||
} | |||
} |
@@ -16,8 +16,10 @@ import java.util.Map; | |||
import org.aspectj.util.FuzzyBoolean; | |||
import org.aspectj.weaver.AnnotatedElement; | |||
import org.aspectj.weaver.ISourceContext; | |||
import org.aspectj.weaver.ResolvedType; | |||
import org.aspectj.weaver.VersionedDataInputStream; | |||
import org.aspectj.weaver.World; | |||
import org.aspectj.weaver.AjAttribute.WeaverVersionInfo; | |||
public class OrAnnotationTypePattern extends AnnotationTypePattern { | |||
@@ -33,6 +35,10 @@ public class OrAnnotationTypePattern extends AnnotationTypePattern { | |||
public FuzzyBoolean matches(AnnotatedElement annotated) { | |||
return left.matches(annotated).or(right.matches(annotated)); | |||
} | |||
public FuzzyBoolean matches(AnnotatedElement annotated, ResolvedType[] parameterAnnotations ) { | |||
return left.matches(annotated,parameterAnnotations).or(right.matches(annotated,parameterAnnotations)); | |||
} | |||
public void resolve(World world) { | |||
left.resolve(world); | |||
@@ -54,6 +60,7 @@ public class OrAnnotationTypePattern extends AnnotationTypePattern { | |||
AnnotationTypePattern newRight = right.parameterizeWith(typeVariableMap,w); | |||
OrAnnotationTypePattern ret = new OrAnnotationTypePattern(newLeft,newRight); | |||
ret.copyLocationFrom(this); | |||
if (isForParameterAnnotationMatch()) ret.setForParameterAnnotationMatch(); | |||
return ret; | |||
} | |||
@@ -73,6 +80,9 @@ public class OrAnnotationTypePattern extends AnnotationTypePattern { | |||
AnnotationTypePattern.read(s,context), | |||
AnnotationTypePattern.read(s,context)); | |||
p.readLocation(context,s); | |||
if (s.getMajorVersion()>=WeaverVersionInfo.WEAVER_VERSION_MINOR_AJ160) { | |||
if (s.readBoolean()) p.setForParameterAnnotationMatch(); | |||
} | |||
return p; | |||
} | |||
@@ -81,18 +91,20 @@ public class OrAnnotationTypePattern extends AnnotationTypePattern { | |||
left.write(s); | |||
right.write(s); | |||
writeLocation(s); | |||
s.writeBoolean(isForParameterAnnotationMatch()); | |||
} | |||
public boolean equals(Object obj) { | |||
if (!(obj instanceof OrAnnotationTypePattern)) return false; | |||
OrAnnotationTypePattern other = (OrAnnotationTypePattern) obj; | |||
return (left.equals(other.left) && right.equals(other.right)); | |||
return (left.equals(other.left) && right.equals(other.right)) && isForParameterAnnotationMatch()==other.isForParameterAnnotationMatch(); | |||
} | |||
public int hashCode() { | |||
int result = 17; | |||
result = result*37 + left.hashCode(); | |||
result = result*37 + right.hashCode(); | |||
result = result*37 + (isForParameterAnnotationMatch()?0:1); | |||
return result; | |||
} | |||
@@ -103,4 +115,9 @@ public class OrAnnotationTypePattern extends AnnotationTypePattern { | |||
public AnnotationTypePattern getLeft() { return left; } | |||
public AnnotationTypePattern getRight() { return right; } | |||
public void setForParameterAnnotationMatch() { | |||
left.setForParameterAnnotationMatch(); | |||
right.setForParameterAnnotationMatch(); | |||
} | |||
} |
@@ -12,7 +12,6 @@ | |||
*******************************************************************************/ | |||
package org.aspectj.weaver.patterns; | |||
import org.aspectj.weaver.Member; | |||
/** | |||
* A Pointcut or TypePattern visitor | |||
@@ -93,515 +92,4 @@ public interface PatternNodeVisitor { | |||
// Catch-all | |||
Object visit(PatternNode node, Object data); | |||
/** | |||
* A sample toString like visitor that helps understanding the AST tree structure organization | |||
* | |||
* @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a> | |||
*/ | |||
static class DumpPointcutVisitor implements PatternNodeVisitor { | |||
private StringBuffer sb = new StringBuffer(); | |||
public String get() { | |||
return sb.toString(); | |||
} | |||
private void append(Object o) { | |||
sb.append(o.toString()); | |||
} | |||
private void append(char c) { | |||
sb.append(c); | |||
} | |||
/** | |||
* This method helps maintaining the API and raises warning when PatternNode subclasses do not | |||
* implement the visitor pattern | |||
* | |||
* @param node | |||
* @param data | |||
* @return | |||
*/ | |||
public Object visit(PatternNode node, Object data) { | |||
System.err.println("Should implement: " + node.getClass()); | |||
return null; | |||
} | |||
public Object visit(AnyTypePattern node, Object data) { | |||
append('*'); | |||
return null; | |||
} | |||
public Object visit(NoTypePattern node, Object data) { | |||
append(node.toString());//TODO no idea when this one is used | |||
return null; | |||
} | |||
public Object visit(EllipsisTypePattern node, Object data) { | |||
append(node.toString()); | |||
return null; | |||
} | |||
public Object visit(AnyWithAnnotationTypePattern node, Object data) { | |||
node.annotationPattern.accept(this, data); | |||
append(" *"); | |||
return null; | |||
} | |||
public Object visit(AnyAnnotationTypePattern node, Object data) { | |||
//@ANY : ignore | |||
append('*'); | |||
return null; | |||
} | |||
public Object visit(EllipsisAnnotationTypePattern node, Object data) { | |||
append(".."); | |||
return null; | |||
} | |||
public Object visit(AndAnnotationTypePattern node, Object data) { | |||
node.getLeft().accept(this, data); | |||
append(' '); | |||
node.getRight().accept(this, data); | |||
return null; | |||
} | |||
public Object visit(AndPointcut node, Object data) { | |||
append('('); | |||
node.getLeft().accept(this, data); | |||
append(" && "); | |||
node.getRight().accept(this, data); | |||
append(')'); | |||
return null; | |||
} | |||
public Object visit(AndTypePattern node, Object data) { | |||
append('('); | |||
node.getLeft().accept(this, data); | |||
append(" && "); | |||
node.getRight().accept(this, data); | |||
append(')'); | |||
return null; | |||
} | |||
public Object visit(AnnotationPatternList node, Object data) { | |||
AnnotationTypePattern[] annotations = node.getAnnotationPatterns(); | |||
for (int i = 0; i < annotations.length; i++) { | |||
if (i>0) append(", ");//Note: list is ",", and is " " separated for annotations | |||
annotations[i].accept(this, data); | |||
} | |||
return null; | |||
} | |||
public Object visit(AnnotationPointcut node, Object data) { | |||
append("@annotation("); | |||
node.getAnnotationTypePattern().accept(this, data); | |||
append(')'); | |||
return null; | |||
} | |||
public Object visit(ArgsAnnotationPointcut node, Object data) { | |||
append("@args("); | |||
node.getArguments().accept(this, data); | |||
append(')'); | |||
return null; | |||
} | |||
public Object visit(ArgsPointcut node, Object data) { | |||
append("args("); | |||
node.getArguments().accept(this, data); | |||
append(')'); | |||
return null; | |||
} | |||
public Object visit(BindingAnnotationTypePattern node, Object data) { | |||
append(node); | |||
return null; | |||
} | |||
public Object visit(BindingTypePattern node, Object data) { | |||
append(node); | |||
return null; | |||
} | |||
public Object visit(CflowPointcut node, Object data) { | |||
append(node.isCflowBelow()?"cflowbelow(":"cflow("); | |||
node.getEntry().accept(this, data); | |||
append(')'); | |||
return null; | |||
} | |||
public Object visit(ExactAnnotationTypePattern node, Object data) { | |||
//append('@'); // since @annotation(@someAnno) cannot be parsed anymore | |||
append(node.getAnnotationType().getName()); | |||
return null; | |||
} | |||
public Object visit(ExactTypePattern node, Object data) { | |||
if (node.getAnnotationPattern() != AnnotationTypePattern.ANY) { | |||
append('('); | |||
node.getAnnotationPattern().accept(this, data); | |||
append(' '); | |||
} | |||
String typeString = node.getType().toString(); | |||
if (node.isVarArgs()) typeString = typeString.substring(0, typeString.lastIndexOf('['));//TODO AV - ugly | |||
append(typeString); | |||
if (node.isIncludeSubtypes()) append('+'); | |||
if (node.isVarArgs()) append("..."); | |||
if (node.getAnnotationPattern() != AnnotationTypePattern.ANY) { | |||
append(')'); | |||
} | |||
return null; | |||
} | |||
public Object visit(KindedPointcut node, Object data) { | |||
append(node.getKind().getSimpleName()); | |||
append('('); | |||
node.getSignature().accept(this, data); | |||
append(')'); | |||
return null; | |||
} | |||
public Object visit(ModifiersPattern node, Object data) { | |||
append(node.toString());//note: node takes care of forbidden mods | |||
return null; | |||
} | |||
public Object visit(NamePattern node, Object data) { | |||
append(node.toString()); | |||
return null; | |||
} | |||
public Object visit(NotAnnotationTypePattern node, Object data) { | |||
append("!"); | |||
node.getNegatedPattern().accept(this, data); | |||
return null; | |||
} | |||
public Object visit(NotPointcut node, Object data) { | |||
append("!("); | |||
node.getNegatedPointcut().accept(this, data); | |||
append(')'); | |||
return null; | |||
} | |||
public Object visit(NotTypePattern node, Object data) { | |||
append("!("); | |||
node.getNegatedPattern().accept(this, data); | |||
append(')'); | |||
return null; | |||
} | |||
public Object visit(OrAnnotationTypePattern node, Object data) { | |||
append('('); | |||
node.getLeft().accept(this, data); | |||
append(" || "); | |||
node.getRight().accept(this, data); | |||
append(')'); | |||
return null; | |||
} | |||
public Object visit(OrPointcut node, Object data) { | |||
append('('); | |||
node.getLeft().accept(this, data); | |||
append(" || "); | |||
node.getRight().accept(this, data); | |||
append(')'); | |||
return null; | |||
} | |||
public Object visit(OrTypePattern node, Object data) { | |||
append('('); | |||
node.getLeft().accept(this, data); | |||
append(" || "); | |||
node.getRight().accept(this, data); | |||
append(')'); | |||
return null; | |||
} | |||
public Object visit(ReferencePointcut node, Object data) { | |||
append(node.toString()); | |||
return null; | |||
} | |||
public Object visit(SignaturePattern node, Object data) { | |||
if (node.getAnnotationPattern() != AnnotationTypePattern.ANY) { | |||
node.getAnnotationPattern().accept(this, data); | |||
append(' '); | |||
} | |||
if (node.getModifiers() != ModifiersPattern.ANY) { | |||
node.getModifiers().accept(this, data); | |||
append(' '); | |||
} | |||
if (node.getKind() == Member.STATIC_INITIALIZATION) { | |||
node.getDeclaringType().accept(this, data); | |||
} else if (node.getKind() == Member.HANDLER) { | |||
append("handler("); | |||
node.getParameterTypes().get(0).accept(this, data);//Note: we know we have 1 child | |||
append(')'); | |||
} else { | |||
if (!(node.getKind() == Member.CONSTRUCTOR)) { | |||
node.getReturnType().accept(this, data); | |||
append(' '); | |||
} | |||
if (node.getDeclaringType() != TypePattern.ANY) { | |||
node.getDeclaringType().accept(this, data); | |||
append('.'); | |||
} | |||
if (node.getKind() == Member.CONSTRUCTOR) { | |||
append("new"); | |||
} else { | |||
node.getName().accept(this, data); | |||
} | |||
if (node.getKind() == Member.METHOD || node.getKind() == Member.CONSTRUCTOR) { | |||
append('('); | |||
node.getParameterTypes().accept(this, data); | |||
append(')'); | |||
} | |||
if (node.getThrowsPattern() != null) { | |||
append(' '); | |||
node.getThrowsPattern().accept(this, data); | |||
} | |||
} | |||
return null; | |||
} | |||
public Object visit(ThisOrTargetAnnotationPointcut node, Object data) { | |||
append(node.isThis() ? "@this(" : "@target("); | |||
node.getAnnotationTypePattern().accept(this, data); | |||
append(')'); | |||
return null; | |||
} | |||
public Object visit(ThisOrTargetPointcut node, Object data) { | |||
append(node.isThis() ? "this(" : "target("); | |||
node.getType().accept(this, data); | |||
append(')'); | |||
return null; | |||
} | |||
// Note: a visitor instance is not thread safe so should not be shared | |||
private boolean inThrowsForbidden = false; | |||
public Object visit(ThrowsPattern node, Object data) { | |||
if (node == ThrowsPattern.ANY) return null; | |||
append("throws "); | |||
node.getRequired().accept(this, data); | |||
if (node.getForbidden().size() > 0) { | |||
// a hack since throws !(A, B) cannot be parsed | |||
try { | |||
inThrowsForbidden = true; | |||
node.getForbidden().accept(this, data); | |||
} finally { | |||
inThrowsForbidden = false; | |||
} | |||
} | |||
return null; | |||
} | |||
public Object visit(TypePatternList node, Object data) { | |||
if (node.getTypePatterns().length == 0) return null; | |||
TypePattern[] typePatterns = node.getTypePatterns(); | |||
for (int i = 0; i < typePatterns.length; i++) { | |||
TypePattern typePattern = typePatterns[i]; | |||
if (i > 0) append(", "); | |||
if (inThrowsForbidden) append('!'); | |||
typePattern.accept(this, data); | |||
} | |||
return null; | |||
} | |||
public Object visit(WildAnnotationTypePattern node, Object data) { | |||
append("@("); | |||
node.getTypePattern().accept(this, data); | |||
append(')'); | |||
return null; | |||
} | |||
public Object visit(WildTypePattern node, Object data) { | |||
if (node.getAnnotationPattern() != AnnotationTypePattern.ANY) { | |||
append('('); | |||
node.getAnnotationPattern().accept(this, data); | |||
append(' '); | |||
} | |||
NamePattern[] namePatterns = node.getNamePatterns(); | |||
for (int i=0; i < namePatterns.length; i++) { | |||
if (namePatterns[i] == null) { | |||
append('.');//FIXME mh, error prone, can't we have a nullNamePattern ? | |||
} else { | |||
if (i > 0) append('.'); | |||
namePatterns[i].accept(this, data); | |||
} | |||
} | |||
if (node.isIncludeSubtypes()) append('+'); | |||
if (node.isVarArgs()) append("..."); | |||
if (node.getAnnotationPattern() != AnnotationTypePattern.ANY) { | |||
append(')'); | |||
} | |||
return null; | |||
} | |||
public Object visit(WithinAnnotationPointcut node, Object data) { | |||
append("@within("); | |||
node.getAnnotationTypePattern().accept(this, data); | |||
append(')'); | |||
return null; | |||
} | |||
public Object visit(WithinCodeAnnotationPointcut node, Object data) { | |||
append("@withincode("); | |||
node.getAnnotationTypePattern().accept(this, data); | |||
append(')'); | |||
return null; | |||
} | |||
public Object visit(WithinPointcut node, Object data) { | |||
append("within("); | |||
node.getTypePattern().accept(this, data); | |||
append(')'); | |||
return null; | |||
} | |||
public Object visit(WithincodePointcut node, Object data) { | |||
append("withincode("); | |||
node.getSignature().accept(this, data); | |||
append(')'); | |||
return null; | |||
} | |||
public Object visit(Pointcut.MatchesNothingPointcut node, Object data) { | |||
append("");//TODO shouldn't that be a "false" ? | |||
return null; | |||
} | |||
//-------------- perX | |||
public Object visit(PerCflow node, Object data) { | |||
append(node); | |||
return null; | |||
} | |||
public Object visit(PerFromSuper node, Object data) { | |||
append(node); | |||
return null; | |||
} | |||
public Object visit(PerObject node, Object data) { | |||
append(node); | |||
return null; | |||
} | |||
public Object visit(PerSingleton node, Object data) { | |||
append(node); | |||
return null; | |||
} | |||
public Object visit(PerTypeWithin node, Object data) { | |||
append(node); | |||
return null; | |||
} | |||
// ------------- declare X | |||
public Object visit(DeclareAnnotation node, Object data) { | |||
append(node); | |||
return null; | |||
} | |||
public Object visit(DeclareErrorOrWarning node, Object data) { | |||
append(node); | |||
return null; | |||
} | |||
public Object visit(DeclareParents node, Object data) { | |||
append(node); | |||
return null; | |||
} | |||
public Object visit(DeclarePrecedence node, Object data) { | |||
append(node); | |||
return null; | |||
} | |||
public Object visit(DeclareSoft node, Object data) { | |||
append(node); | |||
return null; | |||
} | |||
// ----------- misc | |||
public Object visit(ConcreteCflowPointcut node, Object data) { | |||
append(node); | |||
return null; | |||
} | |||
public Object visit(HandlerPointcut node, Object data) { | |||
append(node); | |||
return null; | |||
} | |||
public Object visit(IfPointcut node, Object data) { | |||
append(node); | |||
return null; | |||
} | |||
public Object visit(TypeVariablePattern node, Object data) { | |||
append(node); | |||
return null; | |||
} | |||
public Object visit(TypeVariablePatternList node, Object data) { | |||
append(node); | |||
return null; | |||
} | |||
public Object visit(HasMemberTypePattern node, Object data) { | |||
append(node); | |||
return null; | |||
} | |||
public static void check(String s) { | |||
check(Pointcut.fromString(s), false); | |||
} | |||
public static void check(PatternNode pc, boolean isTypePattern) { | |||
DumpPointcutVisitor v1 = new DumpPointcutVisitor(); | |||
pc.accept(v1, null); | |||
DumpPointcutVisitor v2 = new DumpPointcutVisitor(); | |||
final PatternNode pc2; | |||
if (isTypePattern) { | |||
pc2 = new PatternParser(v1.get()).parseTypePattern(); | |||
} else { | |||
pc2 = Pointcut.fromString(v1.get()); | |||
} | |||
pc2.accept(v2, null); | |||
// at second parsing, the String form stay stable when parsed and parsed again | |||
if (! v1.get().equals(v2.get())) { | |||
throw new ParserException("Unstable back parsing for '"+pc+"', got '" + v1.get() + "' and '" + v2.get() + "'", null); | |||
} | |||
} | |||
public static void main(String args[]) throws Throwable { | |||
String[] s = new String[]{ | |||
//"@args(Foo, Goo, *, .., Moo)", | |||
//"execution(* *())", | |||
//"call(* *(int, Integer...))", | |||
//"staticinitialization(@(Foo) @(Boo) @(Goo) Moo)", | |||
"(if(true) && set(int BaseApp.i))" | |||
}; | |||
for (int i = 0; i < s.length; i++) { | |||
check(s[i]); | |||
} | |||
} | |||
} | |||
} |
@@ -17,11 +17,14 @@ package org.aspectj.weaver.patterns; | |||
import java.util.ArrayList; | |||
import java.util.Collections; | |||
import java.util.HashMap; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.Set; | |||
import org.aspectj.weaver.ISourceContext; | |||
import org.aspectj.weaver.MemberKind; | |||
import org.aspectj.weaver.Member; | |||
import org.aspectj.weaver.Shadow; | |||
import org.aspectj.weaver.UnresolvedType; | |||
@@ -42,6 +45,8 @@ public class PatternParser { | |||
/** extension handlers used in weaver tools API only */ | |||
private Set pointcutDesignatorHandlers = Collections.EMPTY_SET; | |||
private ReflectionWorld world; | |||
private AnnotationTypePattern[] parameterAnnotationTypePatterns; | |||
/** | |||
* Constructor for PatternParser. | |||
@@ -213,7 +218,7 @@ public class PatternParser { | |||
*/ | |||
eat(":"); | |||
allowHasTypePatterns = true; | |||
TypePattern p = parseTypePattern(false); | |||
TypePattern p = parseTypePattern(false,false); | |||
allowHasTypePatterns = false; | |||
IToken t = tokenSource.next(); | |||
if (!(t.getString().equals("extends") || t.getString().equals("implements"))) { | |||
@@ -336,7 +341,7 @@ public class PatternParser { | |||
AnnotationTypePattern.ANY)); | |||
} else if (kind.equals("handler")) { | |||
eat("("); | |||
TypePattern typePat = parseTypePattern(false); | |||
TypePattern typePat = parseTypePattern(false,false); | |||
eat(")"); | |||
p = new HandlerPointcut(typePat); | |||
} else if (kind.equals("lock") || kind.equals("unlock")) { | |||
@@ -348,7 +353,7 @@ public class PatternParser { | |||
p = new KindedPointcut(Shadow.Initialization, sig); | |||
} else if (kind.equals("staticinitialization")) { | |||
eat("("); | |||
TypePattern typePat = parseTypePattern(false); | |||
TypePattern typePat = parseTypePattern(false,false); | |||
eat(")"); | |||
p = new KindedPointcut(Shadow.StaticInitialization, | |||
new SignaturePattern(Member.STATIC_INITIALIZATION, ModifiersPattern.ANY, | |||
@@ -522,7 +527,7 @@ public class PatternParser { | |||
*/ | |||
private Pointcut parseArgsPointcut() { | |||
//parseIdentifier(); | |||
TypePatternList arguments = parseArgumentsPattern(); | |||
TypePatternList arguments = parseArgumentsPattern(false); | |||
return new ArgsPointcut(arguments); | |||
} | |||
@@ -553,7 +558,7 @@ public class PatternParser { | |||
throw new ParserException("(",tokenSource.peek(-1)); | |||
} | |||
TypePatternList arguments = parseArgumentsPattern(); | |||
TypePatternList arguments = parseArgumentsPattern(false); | |||
return new ReferencePointcut(onType, simpleName, arguments); | |||
} | |||
@@ -652,41 +657,62 @@ public class PatternParser { | |||
} | |||
public TypePattern parseTypePattern() { | |||
return parseTypePattern(false); | |||
return parseTypePattern(false,false); | |||
} | |||
public TypePattern parseTypePattern(boolean insideTypeParameters) { | |||
TypePattern p = parseAtomicTypePattern(insideTypeParameters); | |||
public TypePattern parseTypePattern(boolean insideTypeParameters,boolean parameterAnnotationsPossible) { | |||
TypePattern p = parseAtomicTypePattern(insideTypeParameters,parameterAnnotationsPossible); | |||
if (maybeEat("&&")) { | |||
p = new AndTypePattern(p, parseNotOrTypePattern(insideTypeParameters)); | |||
p = new AndTypePattern(p, parseNotOrTypePattern(insideTypeParameters,parameterAnnotationsPossible)); | |||
} | |||
if (maybeEat("||")) { | |||
p = new OrTypePattern(p, parseTypePattern(insideTypeParameters)); | |||
p = new OrTypePattern(p, parseTypePattern(insideTypeParameters,parameterAnnotationsPossible)); | |||
} | |||
return p; | |||
} | |||
private TypePattern parseNotOrTypePattern(boolean insideTypeParameters) { | |||
TypePattern p = parseAtomicTypePattern(insideTypeParameters); | |||
private TypePattern parseNotOrTypePattern(boolean insideTypeParameters,boolean parameterAnnotationsPossible) { | |||
TypePattern p = parseAtomicTypePattern(insideTypeParameters,parameterAnnotationsPossible); | |||
if (maybeEat("&&")) { | |||
p = new AndTypePattern(p, parseTypePattern(insideTypeParameters)); | |||
p = new AndTypePattern(p, parseTypePattern(insideTypeParameters,parameterAnnotationsPossible)); | |||
} | |||
return p; | |||
} | |||
private TypePattern parseAtomicTypePattern(boolean insideTypeParameters) { | |||
AnnotationTypePattern ap = maybeParseAnnotationPattern(); | |||
// Need to differentiate in here between two kinds of annotation pattern - depending on where the ( is | |||
private TypePattern parseAtomicTypePattern(boolean insideTypeParameters,boolean parameterAnnotationsPossible) { | |||
AnnotationTypePattern ap = maybeParseAnnotationPattern(); // might be parameter annotation pattern or type annotation pattern | |||
if (maybeEat("!")) { | |||
//int startPos = tokenSource.peek(-1).getStart(); | |||
//??? we lose source location for true start of !type | |||
TypePattern p = new NotTypePattern(parseAtomicTypePattern(insideTypeParameters)); | |||
p = setAnnotationPatternForTypePattern(p,ap); | |||
// An annotation, if processed, is outside of the Not - so here we have to build | |||
// an And pattern containing the annotation and the not as left and right children | |||
// *unless* the annotation pattern was just 'Any' then we can skip building the | |||
// And and just return the Not directly (pr228980) | |||
TypePattern p = null; | |||
TypePattern tp = parseAtomicTypePattern(insideTypeParameters,parameterAnnotationsPossible); | |||
if (!(ap instanceof AnyAnnotationTypePattern)) { | |||
p = new NotTypePattern(tp); | |||
p = new AndTypePattern(setAnnotationPatternForTypePattern(TypePattern.ANY,ap,false),p); | |||
} else { | |||
p = new NotTypePattern(tp); | |||
} | |||
return p; | |||
} | |||
if (maybeEat("(")) { | |||
TypePattern p = parseTypePattern(insideTypeParameters); | |||
p = setAnnotationPatternForTypePattern(p,ap); | |||
TypePattern p = parseTypePattern(insideTypeParameters,false); | |||
if ((p instanceof NotTypePattern) && !(ap instanceof AnyAnnotationTypePattern)) { | |||
// dont set the annotation on it, we don't want the annotation to be | |||
// considered as part of the not, it is outside the not (pr228980) | |||
TypePattern tp = setAnnotationPatternForTypePattern(TypePattern.ANY, ap, parameterAnnotationsPossible); | |||
p = new AndTypePattern(tp,p); | |||
} else { | |||
p = setAnnotationPatternForTypePattern(p,ap,parameterAnnotationsPossible); | |||
} | |||
eat(")"); | |||
boolean isVarArgs = maybeEat("..."); | |||
if (isVarArgs) p.setIsVarArgs(isVarArgs); | |||
@@ -697,13 +723,15 @@ public class PatternParser { | |||
int startPos = tokenSource.peek().getStart(); | |||
TypePattern p = parseSingleTypePattern(insideTypeParameters); | |||
int endPos = tokenSource.peek(-1).getEnd(); | |||
p = setAnnotationPatternForTypePattern(p,ap); | |||
p = setAnnotationPatternForTypePattern(p,ap,false); | |||
p.setLocation(sourceContext, startPos, endPos); | |||
return p; | |||
} | |||
private TypePattern setAnnotationPatternForTypePattern(TypePattern t, AnnotationTypePattern ap) { | |||
private TypePattern setAnnotationPatternForTypePattern(TypePattern t, AnnotationTypePattern ap,boolean parameterAnnotationsPattern) { | |||
TypePattern ret = t; | |||
if (parameterAnnotationsPattern) ap.setForParameterAnnotationMatch(); | |||
if (ap != AnnotationTypePattern.ANY) { | |||
if (t == TypePattern.ANY) { | |||
ret = new WildTypePattern(new NamePattern[] {NamePattern.ANY},false,0,false,null); | |||
@@ -730,8 +758,10 @@ public class PatternParser { | |||
return ret; | |||
} | |||
// PVAL cope with annotation values at other places in this code | |||
public AnnotationTypePattern maybeParseSingleAnnotationPattern() { | |||
AnnotationTypePattern ret = null; | |||
Map values = null; | |||
// LALR(2) - fix by making "!@" a single token | |||
int startIndex = tokenSource.getIndex(); | |||
if (maybeEat("!")) { | |||
@@ -743,7 +773,13 @@ public class PatternParser { | |||
return ret; | |||
} else { | |||
TypePattern p = parseSingleTypePattern(); | |||
ret = new NotAnnotationTypePattern(new WildAnnotationTypePattern(p)); | |||
if (maybeEatAdjacent("(")) { | |||
values = parseAnnotationValues(); | |||
eat(")"); | |||
ret = new NotAnnotationTypePattern(new WildAnnotationTypePattern(p,values)); | |||
} else { | |||
ret = new NotAnnotationTypePattern(new WildAnnotationTypePattern(p)); | |||
} | |||
return ret; | |||
} | |||
} else { | |||
@@ -759,7 +795,13 @@ public class PatternParser { | |||
return ret; | |||
} else { | |||
TypePattern p = parseSingleTypePattern(); | |||
ret = new WildAnnotationTypePattern(p); | |||
if (maybeEatAdjacent("(")) { | |||
values = parseAnnotationValues(); | |||
eat(")"); | |||
ret = new WildAnnotationTypePattern(p,values); | |||
} else { | |||
ret = new WildAnnotationTypePattern(p); | |||
} | |||
return ret; | |||
} | |||
} else { | |||
@@ -768,6 +810,35 @@ public class PatternParser { | |||
} | |||
} | |||
// Parse annotation values. In an expression in @A(a=b,c=d) this method will be | |||
// parsing the a=b,c=d.) | |||
public Map/*String,String*/ parseAnnotationValues() { | |||
Map values = new HashMap(); | |||
boolean seenDefaultValue = false; | |||
do { | |||
String possibleKeyString = parseAnnotationNameValuePattern(); | |||
if (possibleKeyString==null) { | |||
throw new ParserException("expecting simple literal ",tokenSource.peek(-1)); | |||
} | |||
// did they specify just a single entry 'v' or a keyvalue pair 'k=v' | |||
if (maybeEat("=")) { | |||
// it was a key! | |||
String valueString = parseAnnotationNameValuePattern(); | |||
if (valueString==null) { | |||
throw new ParserException("expecting simple literal ",tokenSource.peek(-1)); | |||
} | |||
values.put(possibleKeyString,valueString); | |||
} else { | |||
if (seenDefaultValue) { | |||
throw new ParserException("cannot specify two default values",tokenSource.peek(-1)); | |||
} | |||
seenDefaultValue = true; | |||
values.put("value",possibleKeyString); | |||
} | |||
} while (maybeEat(",")); // keep going whilst there are ',' | |||
return values; | |||
} | |||
public TypePattern parseSingleTypePattern() { | |||
return parseSingleTypePattern(false); | |||
} | |||
@@ -836,11 +907,11 @@ public class PatternParser { | |||
TypePattern[] additionalInterfaceBounds = new TypePattern[0]; | |||
TypePattern lowerBound = null; | |||
if (maybeEatIdentifier("extends")) { | |||
upperBound = parseTypePattern(false); | |||
upperBound = parseTypePattern(false,false); | |||
additionalInterfaceBounds = maybeParseAdditionalInterfaceBounds(); | |||
} | |||
if (maybeEatIdentifier("super")) { | |||
lowerBound = parseTypePattern(false); | |||
lowerBound = parseTypePattern(false,false); | |||
} | |||
int endPos = tokenSource.peek(-1).getEnd(); | |||
return new WildTypePattern(names,false,0,endPos,false,null,upperBound,additionalInterfaceBounds,lowerBound); | |||
@@ -903,7 +974,7 @@ public class PatternParser { | |||
annotationName.append(parseIdentifier()); | |||
} | |||
UnresolvedType type = UnresolvedType.forName(annotationName.toString()); | |||
p = new ExactAnnotationTypePattern(type); | |||
p = new ExactAnnotationTypePattern(type,null); | |||
return p; | |||
} | |||
@@ -1018,6 +1089,36 @@ public class PatternParser { | |||
return names; | |||
} | |||
// supported form 'a.b.c.d' or just 'a' | |||
public String parseAnnotationNameValuePattern() { | |||
StringBuffer buf = new StringBuffer(); | |||
IToken tok; | |||
int startPos = tokenSource.peek().getStart(); | |||
boolean dotOK = false; | |||
int depth = 0; | |||
while (true) { | |||
tok = tokenSource.peek(); | |||
// keep going until we hit ')' or '=' or ',' | |||
if (tok.getString()==")" && depth==0) break; | |||
if (tok.getString()=="=" && depth==0) break; | |||
if (tok.getString()=="," && depth==0) break; | |||
// keep track of nested brackets | |||
if (tok.getString()=="(") depth++; | |||
if (tok.getString()==")") depth--; | |||
if (tok.getString()=="{") depth++; | |||
if (tok.getString()=="}") depth--; | |||
if (tok.getString()=="." && !dotOK) { | |||
throw new ParserException("dot not expected",tok); | |||
} | |||
buf.append(tok.getString()); | |||
tokenSource.next(); | |||
dotOK=true; | |||
} | |||
if (buf.length()==0) return null; | |||
else return buf.toString(); | |||
} | |||
public NamePattern parseNamePattern() { | |||
@@ -1098,19 +1199,21 @@ public class PatternParser { | |||
} | |||
} | |||
public TypePatternList parseArgumentsPattern() { | |||
public TypePatternList parseArgumentsPattern(boolean parameterAnnotationsPossible) { | |||
List patterns = new ArrayList(); | |||
eat("("); | |||
// () | |||
if (maybeEat(")")) { | |||
return new TypePatternList(); | |||
} | |||
do { | |||
if (maybeEat(".")) { | |||
if (maybeEat(".")) { // .. | |||
eat("."); | |||
patterns.add(TypePattern.ELLIPSIS); | |||
} else { | |||
patterns.add(parseTypePattern()); | |||
} else { | |||
patterns.add(parseTypePattern(false,parameterAnnotationsPossible)); | |||
} | |||
} while (maybeEat(",")); | |||
eat(")"); | |||
@@ -1162,11 +1265,11 @@ public class PatternParser { | |||
int startPos = tokenSource.peek().getStart(); | |||
AnnotationTypePattern annotationPattern = maybeParseAnnotationPattern(); | |||
ModifiersPattern modifiers = parseModifiersPattern(); | |||
TypePattern returnType = parseTypePattern(false); | |||
TypePattern returnType = parseTypePattern(false,false); | |||
TypePattern declaringType; | |||
NamePattern name = null; | |||
Member.Kind kind; | |||
MemberKind kind; | |||
// here we can check for 'new' | |||
if (maybeEatNew(returnType)) { | |||
kind = Member.CONSTRUCTOR; | |||
@@ -1180,7 +1283,7 @@ public class PatternParser { | |||
} else { | |||
kind = Member.METHOD; | |||
IToken nameToken = tokenSource.peek(); | |||
declaringType = parseTypePattern(false); | |||
declaringType = parseTypePattern(false,false); | |||
if (maybeEat(".")) { | |||
nameToken = tokenSource.peek(); | |||
name = parseNamePattern(); | |||
@@ -1201,8 +1304,8 @@ public class PatternParser { | |||
} | |||
} | |||
TypePatternList parameterTypes = parseArgumentsPattern(); | |||
TypePatternList parameterTypes = parseArgumentsPattern(true); | |||
ThrowsPattern throwsPattern = parseOptionalThrowsPattern(); | |||
SignaturePattern ret = new SignaturePattern(kind, modifiers, returnType, declaringType, name, parameterTypes, throwsPattern, annotationPattern); | |||
int endPos = tokenSource.peek(-1).getEnd(); | |||
@@ -1304,7 +1407,7 @@ public class PatternParser { | |||
if (!maybeEat("<")) return null; | |||
List typePats = new ArrayList(); | |||
do { | |||
TypePattern tp = parseTypePattern(true); | |||
TypePattern tp = parseTypePattern(true,false); | |||
typePats.add(tp); | |||
} while(maybeEat(",")); | |||
eat(">"); | |||
@@ -1430,6 +1533,17 @@ public class PatternParser { | |||
} | |||
} | |||
public boolean maybeEatAdjacent(String token) { | |||
IToken next = tokenSource.peek(); | |||
if (next.getString() == token) { | |||
if (isAdjacent(tokenSource.peek(-1),next)) { | |||
tokenSource.next(); | |||
return true; | |||
} | |||
} | |||
return false; | |||
} | |||
public boolean maybeEat(String token) { | |||
IToken next = tokenSource.peek(); | |||
if (next.getString() == token) { |
@@ -168,8 +168,6 @@ public class PointcutRewriter { | |||
// A && (B || C) => (A && B) || (A && C) | |||
// (A || B) && C => (A && C) || (B && C) | |||
// is this next one optimal?? | |||
// (A || B) && (C || D) => (¬A && B && ¬C && D) || (B && C) || (A && ¬C && D) || (A && ¬B && C) | |||
private Pointcut pullUpDisjunctions(Pointcut pc) { | |||
if (isNot(pc)) { | |||
NotPointcut npc = (NotPointcut)pc; |
@@ -32,9 +32,11 @@ import org.aspectj.util.FuzzyBoolean; | |||
import org.aspectj.weaver.AjAttribute; | |||
import org.aspectj.weaver.AjcMemberMaker; | |||
import org.aspectj.weaver.AnnotationTargetKind; | |||
import org.aspectj.weaver.ConcreteTypeMunger; | |||
import org.aspectj.weaver.Constants; | |||
import org.aspectj.weaver.ISourceContext; | |||
import org.aspectj.weaver.JoinPointSignature; | |||
import org.aspectj.weaver.MemberKind; | |||
import org.aspectj.weaver.Member; | |||
import org.aspectj.weaver.NameMangler; | |||
import org.aspectj.weaver.NewFieldTypeMunger; | |||
@@ -43,11 +45,10 @@ import org.aspectj.weaver.ResolvedType; | |||
import org.aspectj.weaver.UnresolvedType; | |||
import org.aspectj.weaver.VersionedDataInputStream; | |||
import org.aspectj.weaver.World; | |||
import org.aspectj.weaver.bcel.BcelTypeMunger; | |||
public class SignaturePattern extends PatternNode { | |||
private Member.Kind kind; | |||
private MemberKind kind; | |||
private ModifiersPattern modifiers; | |||
private TypePattern returnType; | |||
private TypePattern declaringType; | |||
@@ -57,7 +58,7 @@ public class SignaturePattern extends PatternNode { | |||
private AnnotationTypePattern annotationPattern; | |||
private transient int hashcode = -1; | |||
public SignaturePattern(Member.Kind kind, ModifiersPattern modifiers, | |||
public SignaturePattern(MemberKind kind, ModifiersPattern modifiers, | |||
TypePattern returnType, TypePattern declaringType, | |||
NamePattern name, TypePatternList parameterTypes, | |||
ThrowsPattern throwsPattern, | |||
@@ -84,7 +85,7 @@ public class SignaturePattern extends PatternNode { | |||
} | |||
if (parameterTypes != null) { | |||
parameterTypes = parameterTypes.resolveBindings(scope, bindings, false, false); | |||
checkForIncorrectTargetKind(parameterTypes,scope,false); | |||
checkForIncorrectTargetKind(parameterTypes,scope,false,true); | |||
} | |||
if (throwsPattern != null) { | |||
throwsPattern = throwsPattern.resolveBindings(scope, bindings); | |||
@@ -100,11 +101,15 @@ public class SignaturePattern extends PatternNode { | |||
hashcode =-1; | |||
return this; | |||
} | |||
private void checkForIncorrectTargetKind(PatternNode patternNode, IScope scope, boolean targetsOtherThanTypeAllowed) { | |||
checkForIncorrectTargetKind(patternNode, scope, targetsOtherThanTypeAllowed, false); | |||
} | |||
// bug 115252 - adding an xlint warning if the annnotation target type is | |||
// wrong. This logic, or similar, may have to be applied elsewhere in the case | |||
// of pointcuts which don't go through SignaturePattern.resolveBindings(..) | |||
private void checkForIncorrectTargetKind(PatternNode patternNode, IScope scope, boolean targetsOtherThanTypeAllowed) { | |||
private void checkForIncorrectTargetKind(PatternNode patternNode, IScope scope, boolean targetsOtherThanTypeAllowed, boolean parameterTargettingAnnotationsAllowed) { | |||
// return if we're not in java5 mode, if the unmatchedTargetKind Xlint | |||
// warning has been turned off, or if the patternNode is * | |||
if (!scope.getWorld().isInJava5Mode() | |||
@@ -125,7 +130,7 @@ public class SignaturePattern extends PatternNode { | |||
reportUnmatchedTargetKindMessage(targetKinds,patternNode,scope,false); | |||
} | |||
} else { | |||
TypePatternVisitor visitor = new TypePatternVisitor(scope,targetsOtherThanTypeAllowed); | |||
TypePatternVisitor visitor = new TypePatternVisitor(scope,targetsOtherThanTypeAllowed,parameterTargettingAnnotationsAllowed); | |||
patternNode.traverse(visitor,null); | |||
if (visitor.containedIncorrectTargetKind()) { | |||
Set keys = visitor.getIncorrectTargetKinds().keySet(); | |||
@@ -171,14 +176,17 @@ public class SignaturePattern extends PatternNode { | |||
private IScope scope; | |||
private Map incorrectTargetKinds /* PatternNode -> AnnotationTargetKind[] */ = new HashMap(); | |||
private boolean targetsOtherThanTypeAllowed; | |||
private boolean parameterTargettingAnnotationsAllowed; | |||
/** | |||
* @param requiredTarget - the signature pattern Kind | |||
* @param scope | |||
* @param parameterTargettingAnnotationsAllowed | |||
*/ | |||
public TypePatternVisitor(IScope scope, boolean targetsOtherThanTypeAllowed) { | |||
public TypePatternVisitor(IScope scope, boolean targetsOtherThanTypeAllowed, boolean parameterTargettingAnnotationsAllowed) { | |||
this.scope = scope; | |||
this.targetsOtherThanTypeAllowed = targetsOtherThanTypeAllowed; | |||
this.parameterTargettingAnnotationsAllowed = parameterTargettingAnnotationsAllowed; | |||
} | |||
public Object visit(WildAnnotationTypePattern node, Object data) { | |||
@@ -196,7 +204,9 @@ public class SignaturePattern extends PatternNode { | |||
if (targetKinds == null) return data; | |||
List incorrectTargets = new ArrayList(); | |||
for (int i = 0; i < targetKinds.length; i++) { | |||
if (targetKinds[i].getName().equals(kind.getName())) { | |||
if (targetKinds[i].getName().equals(kind.getName()) || | |||
(targetKinds[i].getName().equals("PARAMETER") && node.isForParameterAnnotationMatch()) | |||
) { | |||
return data; | |||
} | |||
incorrectTargets.add(targetKinds[i]); | |||
@@ -207,13 +217,20 @@ public class SignaturePattern extends PatternNode { | |||
} else if (!targetsOtherThanTypeAllowed && !resolvedType.canAnnotationTargetType()) { | |||
AnnotationTargetKind[] targetKinds = resolvedType.getAnnotationTargetKinds(); | |||
if (targetKinds == null) return data; | |||
// exception here is if parameter annotations are allowed | |||
if (parameterTargettingAnnotationsAllowed) { | |||
for (int i = 0; i < targetKinds.length; i++) { | |||
AnnotationTargetKind annotationTargetKind = targetKinds[i]; | |||
if (annotationTargetKind.getName().equals("PARAMETER") && node.isForParameterAnnotationMatch()) return data; | |||
} | |||
} | |||
incorrectTargetKinds.put(node,targetKinds); | |||
} | |||
return data; | |||
} | |||
public Object visit(ExactTypePattern node, Object data) { | |||
ExactAnnotationTypePattern eatp = new ExactAnnotationTypePattern(node.getExactType().resolve(scope.getWorld())); | |||
ExactAnnotationTypePattern eatp = new ExactAnnotationTypePattern(node.getExactType().resolve(scope.getWorld()),null); | |||
eatp.accept(this,data); | |||
return data; | |||
} | |||
@@ -382,9 +399,11 @@ public class SignaturePattern extends PatternNode { | |||
} | |||
if (!parameterTypes.canMatchSignatureWithNParameters(aMethod.getParameterTypes().length)) return FuzzyBoolean.NO; | |||
ResolvedType[] resolvedParameters = world.resolve(aMethod.getParameterTypes()); | |||
if (!parameterTypes.matches(resolvedParameters, TypePattern.STATIC).alwaysTrue()) { | |||
ResolvedType[][] parameterAnnotationTypes = aMethod.getParameterAnnotationTypes(); | |||
if (parameterAnnotationTypes==null || parameterAnnotationTypes.length==0) parameterAnnotationTypes=null; | |||
if (!parameterTypes.matches(resolvedParameters, TypePattern.STATIC,parameterAnnotationTypes).alwaysTrue()) { | |||
// It could still be a match based on the generic sig parameter types of a parameterized type | |||
if (!parameterTypes.matches(world.resolve(aMethod.getGenericParameterTypes()),TypePattern.STATIC).alwaysTrue()) { | |||
if (!parameterTypes.matches(world.resolve(aMethod.getGenericParameterTypes()),TypePattern.STATIC,parameterAnnotationTypes).alwaysTrue()) { | |||
return FuzzyBoolean.MAYBE; | |||
// It could STILL be a match based on the erasure of the parameter types?? | |||
// to be determined via test cases... | |||
@@ -398,6 +417,8 @@ public class SignaturePattern extends PatternNode { | |||
return FuzzyBoolean.YES; | |||
} | |||
/** | |||
* match on declaring type, parameter types, throws types | |||
*/ | |||
@@ -406,7 +427,12 @@ public class SignaturePattern extends PatternNode { | |||
if (!parameterTypes.canMatchSignatureWithNParameters(aConstructor.getParameterTypes().length)) return FuzzyBoolean.NO; | |||
ResolvedType[] resolvedParameters = world.resolve(aConstructor.getParameterTypes()); | |||
if (!parameterTypes.matches(resolvedParameters, TypePattern.STATIC).alwaysTrue()) { | |||
ResolvedType[][] parameterAnnotationTypes = aConstructor.getParameterAnnotationTypes(); | |||
if (parameterAnnotationTypes==null || parameterAnnotationTypes.length==0) parameterAnnotationTypes=null; | |||
if (!parameterTypes.matches(resolvedParameters, TypePattern.STATIC,parameterAnnotationTypes).alwaysTrue()) { | |||
// It could still be a match based on the generic sig parameter types of a parameterized type | |||
if (!parameterTypes.matches(world.resolve(aConstructor.getGenericParameterTypes()),TypePattern.STATIC).alwaysTrue()) { | |||
return FuzzyBoolean.MAYBE; | |||
@@ -474,7 +500,7 @@ public class SignaturePattern extends PatternNode { | |||
ResolvedMember [] mems = member.getDeclaringType().resolve(world).getDeclaredFields(); // FIXME asc should include supers with getInterTypeMungersIncludingSupers? | |||
List mungers = member.getDeclaringType().resolve(world).getInterTypeMungers(); | |||
for (Iterator iter = mungers.iterator(); iter.hasNext();) { | |||
BcelTypeMunger typeMunger = (BcelTypeMunger) iter.next(); | |||
ConcreteTypeMunger typeMunger = (ConcreteTypeMunger) iter.next(); | |||
if (typeMunger.getMunger() instanceof NewFieldTypeMunger) { | |||
ResolvedMember fakerm = typeMunger.getSignature(); | |||
ResolvedMember ajcMethod = AjcMemberMaker.interFieldInitializer(fakerm,typeMunger.getAspectType()); | |||
@@ -571,7 +597,7 @@ public class SignaturePattern extends PatternNode { | |||
public NamePattern getName() { return name; } | |||
public TypePattern getDeclaringType() { return declaringType; } | |||
public Member.Kind getKind() { | |||
public MemberKind getKind() { | |||
return kind; | |||
} | |||
@@ -657,7 +683,7 @@ public class SignaturePattern extends PatternNode { | |||
} | |||
public static SignaturePattern read(VersionedDataInputStream s, ISourceContext context) throws IOException { | |||
Member.Kind kind = Member.Kind.read(s); | |||
MemberKind kind = MemberKind.read(s); | |||
ModifiersPattern modifiers = ModifiersPattern.read(s); | |||
TypePattern returnType = TypePattern.read(s, context); | |||
TypePattern declaringType = TypePattern.read(s, context); |
@@ -158,7 +158,11 @@ public abstract class TypePattern extends PatternNode { | |||
if (type.isTypeVariableReference()) { | |||
typesIterator = ((TypeVariableReference)type).getTypeVariable().getFirstBound().resolve(type.getWorld()).getDirectSupertypes(); | |||
} else { | |||
typesIterator = type.getDirectSupertypes(); | |||
// pr223605 | |||
if (type.isRawType()) { | |||
type = type.getGenericType(); | |||
} | |||
typesIterator = type.getDirectSupertypes(); | |||
} | |||
// FuzzyBoolean ret = FuzzyBoolean.NO; // ??? -eh | |||
@@ -467,9 +471,16 @@ class AnyWithAnnotationTypePattern extends TypePattern { | |||
protected boolean matchesExactly(ResolvedType type) { | |||
annotationPattern.resolve(type.getWorld()); | |||
return annotationPattern.matches(type).alwaysTrue(); | |||
boolean b = false; | |||
if (type.temporaryAnnotationTypes!=null) { | |||
b = annotationPattern.matches(type,type.temporaryAnnotationTypes).alwaysTrue(); | |||
} else { | |||
b = annotationPattern.matches(type).alwaysTrue(); | |||
} | |||
return b; | |||
} | |||
protected boolean matchesExactly(ResolvedType type, ResolvedType annotatedType) { | |||
annotationPattern.resolve(type.getWorld()); | |||
return annotationPattern.matches(annotatedType).alwaysTrue(); |
@@ -87,6 +87,9 @@ public class TypePatternList extends PatternNode { | |||
return (size() -ellipsisCount) <= numParams; | |||
} | |||
} | |||
public FuzzyBoolean matches(ResolvedType[] types, TypePattern.MatchKind kind) { | |||
return matches(types,kind,null); | |||
} | |||
//XXX shares much code with WildTypePattern and with NamePattern | |||
/** | |||
@@ -99,7 +102,7 @@ public class TypePatternList extends PatternNode { | |||
* | |||
* This method will never return FuzzyBoolean.NEVER | |||
*/ | |||
public FuzzyBoolean matches(ResolvedType[] types, TypePattern.MatchKind kind) { | |||
public FuzzyBoolean matches(ResolvedType[] types, TypePattern.MatchKind kind, ResolvedType[][] parameterAnnotations) { | |||
int nameLength = types.length; | |||
int patternLength = typePatterns.length; | |||
@@ -110,7 +113,16 @@ public class TypePatternList extends PatternNode { | |||
if (nameLength != patternLength) return FuzzyBoolean.NO; | |||
FuzzyBoolean finalReturn = FuzzyBoolean.YES; | |||
while (patternIndex < patternLength) { | |||
FuzzyBoolean ret = typePatterns[patternIndex++].matches(types[nameIndex++], kind); | |||
ResolvedType t = types[nameIndex]; | |||
FuzzyBoolean ret = null; | |||
try { | |||
if (parameterAnnotations!=null) t.temporaryAnnotationTypes = parameterAnnotations[nameIndex]; | |||
ret = typePatterns[patternIndex].matches(t,kind); | |||
} finally { | |||
t.temporaryAnnotationTypes=null; | |||
} | |||
patternIndex++; | |||
nameIndex++; | |||
if (ret == FuzzyBoolean.NO) return ret; | |||
if (ret == FuzzyBoolean.MAYBE) finalReturn = ret; | |||
} | |||
@@ -123,7 +135,15 @@ public class TypePatternList extends PatternNode { | |||
if (p == TypePattern.ELLIPSIS) { | |||
nameIndex = nameLength - (patternLength-patternIndex); | |||
} else { | |||
FuzzyBoolean ret = p.matches(types[nameIndex++], kind); | |||
ResolvedType t = types[nameIndex]; | |||
FuzzyBoolean ret = null; | |||
try { | |||
if (parameterAnnotations!=null) t.temporaryAnnotationTypes = parameterAnnotations[nameIndex]; | |||
ret = p.matches(t, kind); | |||
} finally { | |||
t.temporaryAnnotationTypes=null; | |||
} | |||
nameIndex++; | |||
if (ret == FuzzyBoolean.NO) return ret; | |||
if (ret == FuzzyBoolean.MAYBE) finalReturn = ret; | |||
} |
@@ -11,7 +11,10 @@ package org.aspectj.weaver.patterns; | |||
import java.io.DataOutputStream; | |||
import java.io.IOException; | |||
import java.util.HashMap; | |||
import java.util.Iterator; | |||
import java.util.Map; | |||
import java.util.Set; | |||
import org.aspectj.bridge.IMessage; | |||
import org.aspectj.bridge.MessageUtil; | |||
@@ -19,10 +22,12 @@ import org.aspectj.util.FuzzyBoolean; | |||
import org.aspectj.weaver.AnnotatedElement; | |||
import org.aspectj.weaver.BCException; | |||
import org.aspectj.weaver.ISourceContext; | |||
import org.aspectj.weaver.ResolvedMember; | |||
import org.aspectj.weaver.ResolvedType; | |||
import org.aspectj.weaver.VersionedDataInputStream; | |||
import org.aspectj.weaver.WeaverMessages; | |||
import org.aspectj.weaver.World; | |||
import org.aspectj.weaver.AjAttribute.WeaverVersionInfo; | |||
/** | |||
* @author colyer | |||
@@ -34,6 +39,7 @@ public class WildAnnotationTypePattern extends AnnotationTypePattern { | |||
private TypePattern typePattern; | |||
private boolean resolved = false; | |||
Map annotationValues; | |||
/** | |||
* | |||
@@ -43,26 +49,189 @@ public class WildAnnotationTypePattern extends AnnotationTypePattern { | |||
this.typePattern = typePattern; | |||
this.setLocation(typePattern.getSourceContext(), typePattern.start, typePattern.end); | |||
} | |||
public WildAnnotationTypePattern(TypePattern typePattern, Map annotationValues) { | |||
super(); | |||
this.typePattern = typePattern; | |||
this.annotationValues = annotationValues; | |||
// PVAL make the location be from start of type pattern to end of values | |||
this.setLocation(typePattern.getSourceContext(), typePattern.start, typePattern.end); | |||
} | |||
public TypePattern getTypePattern() { | |||
return typePattern; | |||
} | |||
/* (non-Javadoc) | |||
* @see org.aspectj.weaver.patterns.AnnotationTypePattern#matches(org.aspectj.weaver.AnnotatedElement) | |||
*/ | |||
public FuzzyBoolean matches(AnnotatedElement annotated) { | |||
return matches(annotated,null); | |||
} | |||
/** | |||
* Resolve any annotation values specified, checking they are all well formed (valid names, valid values) | |||
* @param annotationType the annotation type for which the values have been specified | |||
* @param scope the scope within which to resolve type references (eg. Color.GREEN) | |||
*/ | |||
protected void resolveAnnotationValues(ResolvedType annotationType, IScope scope) { | |||
if (annotationValues == null) return; | |||
// Check any values specified are OK: | |||
// - the value names are for valid annotation fields | |||
// - the specified values are of the correct type | |||
// - for enums, check the specified values can be resolved in the specified scope | |||
Set keys = annotationValues.keySet(); | |||
ResolvedMember[] ms = annotationType.getDeclaredMethods(); | |||
for (Iterator kIter = keys.iterator(); kIter.hasNext();) { | |||
String k = (String) kIter.next(); | |||
String v = (String) annotationValues.get(k); | |||
boolean validKey = false; | |||
for (int i = 0; i < ms.length; i++) { | |||
ResolvedMember resolvedMember = ms[i]; | |||
if (resolvedMember.getName().equals(k) && resolvedMember.isAbstract()) { | |||
validKey = true; | |||
ResolvedType t = resolvedMember.getReturnType().resolve(scope.getWorld()); | |||
if (t.isEnum()) { | |||
// value must be an enum reference X.Y | |||
int pos = v.lastIndexOf("."); | |||
if (pos == -1) { | |||
IMessage m = MessageUtil.error( | |||
WeaverMessages.format(WeaverMessages.INVALID_ANNOTATION_VALUE,v,"enum"), | |||
getSourceLocation()); | |||
scope.getWorld().getMessageHandler().handleMessage(m); | |||
} else { | |||
String typename = v.substring(0,pos); | |||
ResolvedType rt = scope.lookupType(typename, this).resolve(scope.getWorld()); | |||
v = rt.getSignature()+v.substring(pos+1); // from 'Color.RED' to 'Lp/Color;RED' | |||
annotationValues.put(k,v); | |||
} | |||
} else if (t.isPrimitiveType()) { | |||
if (t.getSignature()=="I") { | |||
try { | |||
int value = Integer.parseInt(v); | |||
annotationValues.put(k,Integer.toString(value)); | |||
} catch (NumberFormatException nfe) { | |||
IMessage m = MessageUtil.error( | |||
WeaverMessages.format(WeaverMessages.INVALID_ANNOTATION_VALUE,v,"int"), | |||
getSourceLocation()); | |||
scope.getWorld().getMessageHandler().handleMessage(m); | |||
} | |||
} else if (t.getSignature()=="F") { | |||
try { | |||
float value = Float.parseFloat(v); | |||
annotationValues.put(k,Float.toString(value)); | |||
} catch (NumberFormatException nfe) { | |||
IMessage m = MessageUtil.error( | |||
WeaverMessages.format(WeaverMessages.INVALID_ANNOTATION_VALUE,v,"float"), | |||
getSourceLocation()); | |||
scope.getWorld().getMessageHandler().handleMessage(m); | |||
} | |||
} else if (t.getSignature()=="Z") { | |||
if (v.equalsIgnoreCase("true") || v.equalsIgnoreCase("false")) { | |||
// is it ok ! | |||
} else { | |||
IMessage m = MessageUtil.error( | |||
WeaverMessages.format(WeaverMessages.INVALID_ANNOTATION_VALUE,v,"boolean"), | |||
getSourceLocation()); | |||
scope.getWorld().getMessageHandler().handleMessage(m); | |||
} | |||
} else if (t.getSignature()=="S") { | |||
try { | |||
short value = Short.parseShort(v); | |||
annotationValues.put(k,Short.toString(value)); | |||
} catch (NumberFormatException nfe) { | |||
IMessage m = MessageUtil.error( | |||
WeaverMessages.format(WeaverMessages.INVALID_ANNOTATION_VALUE,v,"short"), | |||
getSourceLocation()); | |||
scope.getWorld().getMessageHandler().handleMessage(m); | |||
} | |||
} else if (t.getSignature()=="J") { | |||
try { | |||
long value = Long.parseLong(v); | |||
annotationValues.put(k,Long.toString(value)); | |||
} catch (NumberFormatException nfe) { | |||
IMessage m = MessageUtil.error( | |||
WeaverMessages.format(WeaverMessages.INVALID_ANNOTATION_VALUE,v,"long"), | |||
getSourceLocation()); | |||
scope.getWorld().getMessageHandler().handleMessage(m); | |||
} | |||
} else if (t.getSignature()=="D") { | |||
try { | |||
double value = Double.parseDouble(v); | |||
annotationValues.put(k,Double.toString(value)); | |||
} catch (NumberFormatException nfe) { | |||
IMessage m = MessageUtil.error( | |||
WeaverMessages.format(WeaverMessages.INVALID_ANNOTATION_VALUE,v,"double"), | |||
getSourceLocation()); | |||
scope.getWorld().getMessageHandler().handleMessage(m); | |||
} | |||
} else if (t.getSignature()=="B") { | |||
try { | |||
byte value = Byte.parseByte(v); | |||
annotationValues.put(k,Byte.toString(value)); | |||
} catch (NumberFormatException nfe) { | |||
IMessage m = MessageUtil.error( | |||
WeaverMessages.format(WeaverMessages.INVALID_ANNOTATION_VALUE,v,"byte"), | |||
getSourceLocation()); | |||
scope.getWorld().getMessageHandler().handleMessage(m); | |||
} | |||
} else if (t.getSignature()=="C") { | |||
if (v.length()!=3) { // '?' | |||
IMessage m = MessageUtil.error( | |||
WeaverMessages.format(WeaverMessages.INVALID_ANNOTATION_VALUE,v,"char"), | |||
getSourceLocation()); | |||
scope.getWorld().getMessageHandler().handleMessage(m); | |||
} else { | |||
annotationValues.put(k,v.substring(1,2)); | |||
} | |||
} else { | |||
throw new RuntimeException("Not implemented for "+t); | |||
} | |||
} else if (t.equals(ResolvedType.JAVA_LANG_STRING)) { | |||
// nothing to do, it will be OK | |||
} else { | |||
throw new RuntimeException("Compiler limitation: annotation value support not implemented for type "+t); | |||
} | |||
} | |||
} | |||
if (!validKey) { | |||
IMessage m = MessageUtil.error( | |||
WeaverMessages.format(WeaverMessages.UNKNOWN_ANNOTATION_VALUE,annotationType,k), | |||
getSourceLocation()); | |||
scope.getWorld().getMessageHandler().handleMessage(m); | |||
} | |||
} | |||
} | |||
public FuzzyBoolean matches(AnnotatedElement annotated,ResolvedType[] parameterAnnotations) { | |||
if (!resolved) { | |||
throw new IllegalStateException("Can't match on an unresolved annotation type pattern"); | |||
} | |||
// matches if the type of any of the annotations on the AnnotatedElement is | |||
// matched by the typePattern. | |||
ResolvedType[] annTypes = annotated.getAnnotationTypes(); | |||
if (annTypes!=null && annTypes.length!=0) { | |||
for (int i = 0; i < annTypes.length; i++) { | |||
if (typePattern.matches(annTypes[i],TypePattern.STATIC).alwaysTrue()) { | |||
return FuzzyBoolean.YES; | |||
if (annotationValues!=null) { | |||
// PVAL improve this restriction, would allow '*(value=Color.RED)' | |||
throw new IllegalStateException("Cannot use annotationvalues with a wild annotation pattern"); | |||
} | |||
if (isForParameterAnnotationMatch()) { | |||
if (parameterAnnotations!=null && parameterAnnotations.length!=0) { | |||
for (int i = 0; i < parameterAnnotations.length; i++) { | |||
if (typePattern.matches(parameterAnnotations[i],TypePattern.STATIC).alwaysTrue()) { | |||
return FuzzyBoolean.YES; | |||
} | |||
} | |||
} | |||
} else { | |||
// matches if the type of any of the annotations on the AnnotatedElement is | |||
// matched by the typePattern. | |||
ResolvedType[] annTypes = annotated.getAnnotationTypes(); | |||
if (annTypes!=null && annTypes.length!=0) { | |||
for (int i = 0; i < annTypes.length; i++) { | |||
if (typePattern.matches(annTypes[i],TypePattern.STATIC).alwaysTrue()) { | |||
return FuzzyBoolean.YES; | |||
} | |||
} | |||
} | |||
} | |||
@@ -100,8 +269,11 @@ public class WildAnnotationTypePattern extends AnnotationTypePattern { | |||
scope.getWorld().getMessageHandler().handleMessage(m); | |||
resolved = false; | |||
} | |||
ExactAnnotationTypePattern eatp = new ExactAnnotationTypePattern(et.getExactType().resolve(scope.getWorld())); | |||
ResolvedType annotationType = et.getExactType().resolve(scope.getWorld()); | |||
resolveAnnotationValues(annotationType,scope); | |||
ExactAnnotationTypePattern eatp = new ExactAnnotationTypePattern(annotationType,annotationValues); | |||
eatp.copyLocationFrom(this); | |||
if (isForParameterAnnotationMatch()) eatp.setForParameterAnnotationMatch(); | |||
return eatp; | |||
} else { | |||
return this; | |||
@@ -124,10 +296,23 @@ public class WildAnnotationTypePattern extends AnnotationTypePattern { | |||
s.writeByte(VERSION); | |||
typePattern.write(s); | |||
writeLocation(s); | |||
s.writeBoolean(isForParameterAnnotationMatch()); | |||
// PVAL | |||
if (annotationValues==null) { | |||
s.writeInt(0); | |||
} else { | |||
s.writeInt(annotationValues.size()); | |||
Set key = annotationValues.keySet(); | |||
for (Iterator keys = key.iterator(); keys.hasNext();) { | |||
String k = (String) keys.next(); | |||
s.writeUTF(k); | |||
s.writeUTF((String)annotationValues.get(k)); | |||
} | |||
} | |||
} | |||
public static AnnotationTypePattern read(VersionedDataInputStream s,ISourceContext context) throws IOException { | |||
AnnotationTypePattern ret; | |||
WildAnnotationTypePattern ret; | |||
byte version = s.readByte(); | |||
if (version > VERSION) { | |||
throw new BCException("ExactAnnotationTypePattern was written by a newer version of AspectJ"); | |||
@@ -135,6 +320,21 @@ public class WildAnnotationTypePattern extends AnnotationTypePattern { | |||
TypePattern t = TypePattern.read(s,context); | |||
ret = new WildAnnotationTypePattern(t); | |||
ret.readLocation(context,s); | |||
if (s.getMajorVersion()>=WeaverVersionInfo.WEAVER_VERSION_MINOR_AJ160) { | |||
if (s.readBoolean()) ret.setForParameterAnnotationMatch(); | |||
} | |||
if (s.getMajorVersion()>=WeaverVersionInfo.WEAVER_VERSION_MAJOR_AJ160M2) { | |||
int annotationValueCount = s.readInt(); | |||
if (annotationValueCount>0) { | |||
Map aValues = new HashMap(); | |||
for (int i=0;i<annotationValueCount;i++) { | |||
String key = s.readUTF(); | |||
String val = s.readUTF(); | |||
aValues.put(key,val); | |||
} | |||
ret.annotationValues = aValues; | |||
} | |||
} | |||
return ret; | |||
} | |||
@@ -144,14 +344,14 @@ public class WildAnnotationTypePattern extends AnnotationTypePattern { | |||
public boolean equals(Object obj) { | |||
if (!(obj instanceof WildAnnotationTypePattern)) return false; | |||
WildAnnotationTypePattern other = (WildAnnotationTypePattern) obj; | |||
return other.typePattern.equals(typePattern); | |||
return other.typePattern.equals(typePattern) && this.isForParameterAnnotationMatch()==other.isForParameterAnnotationMatch(); | |||
} | |||
/* (non-Javadoc) | |||
* @see java.lang.Object#hashCode() | |||
*/ | |||
public int hashCode() { | |||
return 17 + 37*typePattern.hashCode(); | |||
return (17 + 37*typePattern.hashCode())*37+(isForParameterAnnotationMatch()?0:1); | |||
} | |||
/* (non-Javadoc) |
@@ -236,8 +236,8 @@ public class WildTypePattern extends TypePattern { | |||
return matchesExactlyByName(targetTypeName,type.isAnonymous(),type.isNested()) && | |||
matchesParameters(type,STATIC) && | |||
matchesBounds(type,STATIC) && | |||
annotationPattern.matches(annotatedType).alwaysTrue(); | |||
matchesBounds(type,STATIC) && | |||
annotationPattern.matches(annotatedType,type.temporaryAnnotationTypes).alwaysTrue(); | |||
} | |||
@@ -644,7 +644,7 @@ public class WildTypePattern extends TypePattern { | |||
if (dim == 0 && !isVarArgs && upperBound == null && lowerBound == null && (additionalInterfaceBounds == null || additionalInterfaceBounds.length==0)) { // pr72531 | |||
return TypePattern.ANY; //??? loses source location | |||
} | |||
} else { | |||
} else if (!isVarArgs){ | |||
annotationPattern = annotationPattern.resolveBindings(scope,bindings,allowBinding); | |||
AnyWithAnnotationTypePattern ret = new AnyWithAnnotationTypePattern(annotationPattern); | |||
ret.setLocation(sourceContext,start,end); |
@@ -1,40 +0,0 @@ | |||
Current situation with respect to raw types... | |||
* We can create an unresolved type (typeKind = SIMPLE) by | |||
UnresolvedType.forSignature or forName | |||
* We can create an unresolved type (typeKind = RAW) by calling | |||
UnresolvedType.forRawTypeName | |||
This method is called by... | |||
BcelWorld.addSourceObjectType when types in jar files or on the classpath are added to | |||
the weaver for processing. If the JavaClass is determined to be generic then a raw | |||
UnresolvedType is built and a ReferenceType constructed from that. A BcelObjectType is | |||
built using the Resolved raw type (and when it's generic signature is unpacked later that will | |||
be swapped out for the generic type). Then a generic type is created, the delegates of | |||
the generic and raw types are set to point to the BcelObjectType, and the generic type | |||
of the raw type is set to point to the generic type. The raw type is explicitly added into | |||
the typeMap. | |||
EclipseFactory.addSourceTypeBinding when adding a binding for a generic type during | |||
completeTypeBindings. This is put into the world by calling world.lookupOrCreateName. | |||
Then a generic type is created and the raw type's generic type is set to refer to it. | |||
EclipseFactory.fromBinding when processing a RawTypeBinding. A later call to resolve | |||
is responsible for adding this to the type map. | |||
* World.resolve processing works as follows: | |||
in resolveObjectType, if the typeKind of the UnresolvedType is neither parameterized | |||
nor generic, then a new ReferenceType is created using the rawTypeSignature of the | |||
unresolved type. Then the delegate is created, and if this turns out to be generic then a | |||
generic type is also built and set as the generic type of the reference type (but nothing | |||
sets the type of the reference type to raw???). | |||
in resolveTheGenericType the rawTypeSignature is looked up in the typeMap. If it | |||
is not found, then a new UnresolvedType is created forSignature, resolved (see above), | |||
and put in the type map. The generic type is then created and set as the generic type | |||
of the raw type. | |||
@@ -14,7 +14,9 @@ package org.aspectj.weaver.reflect; | |||
import java.lang.reflect.Member; | |||
import java.util.Set; | |||
import org.aspectj.weaver.AnnotationX; | |||
import org.aspectj.weaver.ResolvedType; | |||
import org.aspectj.weaver.UnresolvedType; | |||
import org.aspectj.weaver.World; | |||
/** | |||
@@ -30,8 +32,13 @@ public interface AnnotationFinder { | |||
Object getAnnotation(ResolvedType annotationType, Object onObject); | |||
Object getAnnotationFromMember(ResolvedType annotationType, Member aMember); | |||
public AnnotationX getAnnotationOfType(UnresolvedType ofType,Member onMember); | |||
public String getAnnotationDefaultValue(Member onMember); | |||
Object getAnnotationFromClass(ResolvedType annotationType, Class aClass); | |||
Set/*ResolvedType*/ getAnnotations(Member onMember); | |||
ResolvedType[][] getParameterAnnotationTypes(Member onMember); | |||
} |
@@ -215,11 +215,12 @@ public class ReflectionBasedReferenceTypeDelegate implements ReferenceTypeDelega | |||
public ResolvedMember[] getDeclaredFields() { | |||
if (fields == null) { | |||
Field[] reflectFields = this.myClass.getDeclaredFields(); | |||
this.fields = new ResolvedMember[reflectFields.length]; | |||
ResolvedMember[] rFields = new ResolvedMember[reflectFields.length]; | |||
for (int i = 0; i < reflectFields.length; i++) { | |||
this.fields[i] = | |||
rFields[i] = | |||
ReflectionBasedReferenceTypeDelegateFactory.createResolvedMember(reflectFields[i], world); | |||
} | |||
this.fields = rFields; | |||
} | |||
return fields; | |||
} | |||
@@ -230,11 +231,12 @@ public class ReflectionBasedReferenceTypeDelegate implements ReferenceTypeDelega | |||
public ResolvedType[] getDeclaredInterfaces() { | |||
if (interfaces == null) { | |||
Class[] reflectInterfaces = this.myClass.getInterfaces(); | |||
this.interfaces = new ResolvedType[reflectInterfaces.length]; | |||
ResolvedType[] rInterfaces = new ResolvedType[reflectInterfaces.length]; | |||
for (int i = 0; i < reflectInterfaces.length; i++) { | |||
this.interfaces[i] = ReflectionBasedReferenceTypeDelegateFactory | |||
rInterfaces[i] = ReflectionBasedReferenceTypeDelegateFactory | |||
.resolveTypeInWorld(reflectInterfaces[i],world); | |||
} | |||
this.interfaces = rInterfaces; | |||
} | |||
return interfaces; | |||
} | |||
@@ -246,15 +248,16 @@ public class ReflectionBasedReferenceTypeDelegate implements ReferenceTypeDelega | |||
if (methods == null) { | |||
Method[] reflectMethods = this.myClass.getDeclaredMethods(); | |||
Constructor[] reflectCons = this.myClass.getDeclaredConstructors(); | |||
this.methods = new ResolvedMember[reflectMethods.length + reflectCons.length]; | |||
ResolvedMember[] rMethods = new ResolvedMember[reflectMethods.length + reflectCons.length]; | |||
for (int i = 0; i < reflectMethods.length; i++) { | |||
this.methods[i] = | |||
rMethods[i] = | |||
ReflectionBasedReferenceTypeDelegateFactory.createResolvedMember(reflectMethods[i], world); | |||
} | |||
for (int i = 0; i < reflectCons.length; i++) { | |||
this.methods[i + reflectMethods.length] = | |||
rMethods[i + reflectMethods.length] = | |||
ReflectionBasedReferenceTypeDelegateFactory.createResolvedMember(reflectCons[i], world); | |||
} | |||
this.methods = rMethods; | |||
} | |||
return methods; | |||
} |
@@ -12,12 +12,16 @@ | |||
package org.aspectj.weaver.reflect; | |||
import java.lang.reflect.Member; | |||
import java.util.Iterator; | |||
import org.aspectj.weaver.AnnotationX; | |||
import org.aspectj.weaver.MemberKind; | |||
import org.aspectj.weaver.ResolvedMember; | |||
import org.aspectj.weaver.ResolvedMemberImpl; | |||
import org.aspectj.weaver.ResolvedType; | |||
import org.aspectj.weaver.UnresolvedType; | |||
/** | |||
* Subtype of ResolvedMemberImpl used in reflection world. | |||
* Knows how to get annotations from a java.lang.reflect.Member | |||
@@ -39,7 +43,7 @@ public class ReflectionBasedResolvedMemberImpl extends ResolvedMemberImpl { | |||
* @param name | |||
* @param parameterTypes | |||
*/ | |||
public ReflectionBasedResolvedMemberImpl(Kind kind, | |||
public ReflectionBasedResolvedMemberImpl(MemberKind kind, | |||
UnresolvedType declaringType, int modifiers, | |||
UnresolvedType returnType, String name, | |||
UnresolvedType[] parameterTypes, | |||
@@ -57,7 +61,7 @@ public class ReflectionBasedResolvedMemberImpl extends ResolvedMemberImpl { | |||
* @param parameterTypes | |||
* @param checkedExceptions | |||
*/ | |||
public ReflectionBasedResolvedMemberImpl(Kind kind, | |||
public ReflectionBasedResolvedMemberImpl(MemberKind kind, | |||
UnresolvedType declaringType, int modifiers, | |||
UnresolvedType returnType, String name, | |||
UnresolvedType[] parameterTypes, UnresolvedType[] checkedExceptions, | |||
@@ -77,7 +81,7 @@ public class ReflectionBasedResolvedMemberImpl extends ResolvedMemberImpl { | |||
* @param checkedExceptions | |||
* @param backingGenericMember | |||
*/ | |||
public ReflectionBasedResolvedMemberImpl(Kind kind, | |||
public ReflectionBasedResolvedMemberImpl(MemberKind kind, | |||
UnresolvedType declaringType, int modifiers, | |||
UnresolvedType returnType, String name, | |||
UnresolvedType[] parameterTypes, | |||
@@ -96,7 +100,7 @@ public class ReflectionBasedResolvedMemberImpl extends ResolvedMemberImpl { | |||
* @param name | |||
* @param signature | |||
*/ | |||
public ReflectionBasedResolvedMemberImpl(Kind kind, | |||
public ReflectionBasedResolvedMemberImpl(MemberKind kind, | |||
UnresolvedType declaringType, int modifiers, String name, | |||
String signature, Member reflectMember) { | |||
super(kind, declaringType, modifiers, name, signature); | |||
@@ -169,6 +173,30 @@ public class ReflectionBasedResolvedMemberImpl extends ResolvedMemberImpl { | |||
return super.getAnnotationTypes(); | |||
} | |||
public AnnotationX getAnnotationOfType(UnresolvedType ofType) { | |||
unpackAnnotations(); | |||
if (annotationFinder==null) return null; | |||
for (Iterator iterator = annotationTypes.iterator(); iterator.hasNext();) { | |||
ResolvedType type = (ResolvedType) iterator.next(); | |||
if (type.getSignature().equals(ofType.getSignature())) { | |||
return annotationFinder.getAnnotationOfType(ofType, reflectMember); | |||
} | |||
} | |||
return null; | |||
} | |||
public String getAnnotationDefaultValue() { | |||
if (annotationFinder==null) return null; | |||
return annotationFinder.getAnnotationDefaultValue(reflectMember); | |||
} | |||
public ResolvedType[][] getParameterAnnotationTypes() { | |||
if (parameterAnnotationTypes==null && annotationFinder!=null) { | |||
parameterAnnotationTypes = annotationFinder.getParameterAnnotationTypes(reflectMember); | |||
} | |||
return parameterAnnotationTypes; | |||
} | |||
private void unpackAnnotations() { | |||
if (annotationTypes == null && annotationFinder != null) { | |||
annotationTypes = annotationFinder.getAnnotations(reflectMember); |
@@ -11,7 +11,7 @@ | |||
package org.aspectj.weaver.tools; | |||
import org.apache.commons.logging.LogFactory; | |||
//OPTIMIZE move out of main weaver for now? | |||
public class CommonsTraceFactory extends TraceFactory { | |||
private LogFactory logFactory = LogFactory.getFactory(); |
@@ -12,7 +12,8 @@ | |||
package org.aspectj.weaver.tools; | |||
/** This class implements a boolean that includes a "maybe" | |||
/** | |||
* This class implements a boolean that includes a "maybe" | |||
*/ | |||
public class FuzzyBoolean { | |||
@@ -260,6 +260,7 @@ public class PointcutParser { | |||
*/ | |||
public void registerPointcutDesignatorHandler(PointcutDesignatorHandler designatorHandler) { | |||
this.pointcutDesignators.add(designatorHandler); | |||
if (world != null) world.registerPointcutHandler(designatorHandler); | |||
} | |||
/** |
@@ -26,6 +26,7 @@ import java.util.Iterator; | |||
import java.util.LinkedList; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.Properties; | |||
import java.util.Set; | |||
import java.util.StringTokenizer; | |||
@@ -46,12 +47,14 @@ import org.aspectj.util.LangUtil; | |||
import org.aspectj.weaver.IClassFileProvider; | |||
import org.aspectj.weaver.IWeaveRequestor; | |||
import org.aspectj.weaver.ResolvedType; | |||
import org.aspectj.weaver.World; | |||
import org.aspectj.weaver.bcel.BcelObjectType; | |||
import org.aspectj.weaver.bcel.BcelWeaver; | |||
import org.aspectj.weaver.bcel.BcelWorld; | |||
import org.aspectj.weaver.bcel.UnwovenClassFile; | |||
import org.aspectj.weaver.bcel.Utility; | |||
// OPTIMIZE add guards for all the debug/info/etc | |||
/** | |||
* This adaptor allows the AspectJ compiler to be embedded in an existing | |||
* system to facilitate load-time weaving. It provides an interface for a | |||
@@ -86,6 +89,12 @@ public class WeavingAdaptor implements IMessageContext { | |||
protected Map generatedClasses = new HashMap(); /* String -> UnwovenClassFile */ | |||
protected BcelObjectType delegateForCurrentClass; // lazily initialized, should be used to prevent parsing bytecode multiple times | |||
private int weavingSpecialTypes = 0; | |||
private static final int INITIALIZED = 0x1; | |||
private static final int WEAVE_JAVA_PACKAGE = 0x2; | |||
private static final int WEAVE_JAVAX_PACKAGE= 0x4; | |||
private static Trace trace = TraceFactory.getTraceFactory().getTrace(WeavingAdaptor.class); | |||
protected WeavingAdaptor () { | |||
@@ -128,7 +137,7 @@ public class WeavingAdaptor implements IMessageContext { | |||
URL[] urls = ((URLClassLoader)loader).getURLs(); | |||
list.addAll(0,FileUtil.makeClasspath(urls)); | |||
} | |||
else { | |||
else { | |||
warn("cannot determine classpath"); | |||
} | |||
} | |||
@@ -157,7 +166,6 @@ public class WeavingAdaptor implements IMessageContext { | |||
private void init(List classPath, List aspectPath) { | |||
abortOnError = true; | |||
createMessageHandler(); | |||
info("using classpath: " + classPath); | |||
info("using aspectpath: " + aspectPath); | |||
@@ -227,7 +235,7 @@ public class WeavingAdaptor implements IMessageContext { | |||
weaver.addLibraryJarFile(libFile); | |||
} | |||
catch (IOException ex) { | |||
warn("bad library: '" + libFile + "'"); | |||
warn("bad library: '" + libFile + "'"); | |||
} | |||
} | |||
@@ -235,10 +243,11 @@ public class WeavingAdaptor implements IMessageContext { | |||
* Weave a class using aspects previously supplied to the adaptor. | |||
* @param name the name of the class | |||
* @param bytes the class bytes | |||
* @param mustWeave if true then this class *must* get woven (used for concrete aspects generated from XML) | |||
* @return the woven bytes | |||
* @exception IOException weave failed | |||
*/ | |||
public byte[] weaveClass (String name, byte[] bytes) throws IOException { | |||
public byte[] weaveClass (String name, byte[] bytes,boolean mustWeave) throws IOException { | |||
if (trace.isTraceEnabled()) trace.enter("weaveClass",this,new Object[] {name, bytes}); | |||
if (!enabled) { | |||
@@ -259,6 +268,11 @@ public class WeavingAdaptor implements IMessageContext { | |||
debug("weaving '" + name + "'"); | |||
bytes = getWovenBytes(name, bytes); | |||
} else if (shouldWeaveAnnotationStyleAspect(name, bytes)) { | |||
if (mustWeave) { | |||
if (bcelWorld.getLint().mustWeaveXmlDefinedAspects.isEnabled()) { | |||
bcelWorld.getLint().mustWeaveXmlDefinedAspects.signal(name,null); | |||
} | |||
} | |||
// an @AspectJ aspect needs to be at least munged by the aspectOf munger | |||
debug("weaving '" + name + "'"); | |||
bytes = getAtAspectJAspectBytes(name, bytes); | |||
@@ -294,10 +308,25 @@ public class WeavingAdaptor implements IMessageContext { | |||
} | |||
private boolean shouldWeaveName (String name) { | |||
if ((weavingSpecialTypes&INITIALIZED)==0) { | |||
weavingSpecialTypes|=INITIALIZED; | |||
// initialize it | |||
Properties p = weaver.getWorld().getExtraConfiguration(); | |||
if (p!=null) { | |||
boolean b = p.getProperty(World.xsetWEAVE_JAVA_PACKAGES,"false").equalsIgnoreCase("true"); | |||
if (b) { | |||
weavingSpecialTypes|=WEAVE_JAVA_PACKAGE; | |||
} | |||
b = p.getProperty(World.xsetWEAVE_JAVAX_PACKAGES,"false").equalsIgnoreCase("true"); | |||
if (b) { | |||
weavingSpecialTypes|=WEAVE_JAVAX_PACKAGE; | |||
} | |||
} | |||
} | |||
boolean should = | |||
!((name.startsWith("org.aspectj.") | |||
|| name.startsWith("java.") | |||
|| name.startsWith("javax.")) | |||
!(name.startsWith("org.aspectj.") | |||
|| (name.startsWith("java.") && (weavingSpecialTypes&WEAVE_JAVA_PACKAGE)==0) | |||
|| (name.startsWith("javax.") && (weavingSpecialTypes&WEAVE_JAVAX_PACKAGE)==0) | |||
//|| name.startsWith("$Proxy")//JDK proxies//FIXME AV is that 1.3 proxy ? fe. ataspect.$Proxy0 is a java5 proxy... | |||
|| name.startsWith("sun.reflect."));//JDK reflect | |||
return should; | |||
@@ -319,25 +348,9 @@ public class WeavingAdaptor implements IMessageContext { | |||
} | |||
return (delegateForCurrentClass.isAnnotationStyleAspect()); | |||
} | |||
// private boolean asmCheckAnnotationStyleAspect(byte[] bytes) { | |||
// IsAtAspectAnnotationVisitor detector = new IsAtAspectAnnotationVisitor(); | |||
// | |||
// ClassReader cr = new ClassReader(bytes); | |||
// try { | |||
// cr.accept(detector, true);//, ClassReader.SKIP_DEBUG | ClassReader.SKIP_CODE | ClassReader.SKIP_FRAMES); | |||
// } catch (Exception spe) { | |||
// // if anything goes wrong, e.g., an NPE, then assume it's NOT an @AspectJ aspect... | |||
// System.err.println("Unexpected problem parsing bytes to discover @Aspect annotation"); | |||
// spe.printStackTrace(); | |||
// return false; | |||
// } | |||
// | |||
// return detector.isAspect(); | |||
// } | |||
protected void ensureDelegateInitialized(String name,byte[] bytes) { | |||
if (delegateForCurrentClass==null) | |||
if (delegateForCurrentClass==null) // OPTIMIZE better job here? | |||
delegateForCurrentClass = ((BcelWorld)weaver.getWorld()).addSourceObjectType(Utility.makeJavaClass(name, bytes)); | |||
} | |||
@@ -396,10 +409,10 @@ public class WeavingAdaptor implements IMessageContext { | |||
info("adding aspect library: '" + aspectLibrary + "'"); | |||
weaver.addLibraryJarFile(aspectLibrary); | |||
} catch (IOException ex) { | |||
error("exception adding aspect library: '" + ex + "'"); | |||
error("exception adding aspect library: '" + ex + "'"); | |||
} | |||
} else { | |||
error("bad aspect library: '" + aspectLibrary + "'"); | |||
error("bad aspect library: '" + aspectLibrary + "'"); | |||
} | |||
} | |||
@@ -470,7 +483,7 @@ public class WeavingAdaptor implements IMessageContext { | |||
os.close(); | |||
} | |||
catch (IOException ex) { | |||
warn("unable to dump class " + name + " in directory " + dirName,ex); | |||
warn("unable to dump class " + name + " in directory " + dirName,ex); | |||
} | |||
} | |||
@@ -649,7 +662,7 @@ public class WeavingAdaptor implements IMessageContext { | |||
private class WeavingClassFileProvider implements IClassFileProvider { | |||
private UnwovenClassFile unwovenClass; | |||
private List unwovenClasses = new ArrayList(); /* List<UnovenClassFile> */ | |||
private List unwovenClasses = new ArrayList(); /* List<UnwovenClassFile> */ | |||
private UnwovenClassFile wovenClass; | |||
private boolean isApplyAtAspectJMungersOnly = false; | |||
@@ -1,6 +0,0 @@ | |||
<html> | |||
<body> | |||
Provides a set of interfaces for third-parties wishing to integrate | |||
AspectJ weaving capabilities into their environments. | |||
</body> | |||
</html> |
@@ -157,6 +157,10 @@ referenceToNonAnnotationType=Type referred to is not an annotation type: {0} | |||
bindingNonRuntimeRetentionAnnotation=Annotation type {0} does not have runtime retention | |||
noMatchBecauseSourceRetention=Failing match because annotation ''{0}'' on type ''{1}'' has SOURCE retention. Matching allowed when RetentionPolicy is CLASS or RUNTIME | |||
# Annotation value | |||
invalidAnnotationValue=Invalid annotation value ''{0}'', expected {1} value | |||
unknownAnnotationValue=The annotation ''{0}'' does not define a value named ''{1}'' | |||
# Generics | |||
cantDecpMultipleParameterizations=Cannot declare parent {0} onto type {1} since it already has {2} in its hierarchy | |||
noParameterizedTypePatternInHandler=a parameterized type pattern may not be used in a handler pointcut expression |
@@ -29,10 +29,10 @@ public class MemberTestCase extends TestCase { | |||
} | |||
public void testMethodConstruction() { | |||
Member s = MemberImpl.methodFromString("void Foo.goo(int)"); | |||
Member s = TestUtils.methodFromString("void Foo.goo(int)"); | |||
Member t = MemberImpl.method(UnresolvedType.forName("Foo"), 0, "goo", "(I)V"); | |||
Member u = MemberImpl.methodFromString("void Foo1.goo(int)"); | |||
Member v = MemberImpl.methodFromString("int Foo.goo(int)"); | |||
Member u = TestUtils.methodFromString("void Foo1.goo(int)"); | |||
Member v = TestUtils.methodFromString("int Foo.goo(int)"); | |||
TestUtil.assertCommutativeEquals(s, s, true); | |||
TestUtil.assertCommutativeEquals(t, t, true); | |||
@@ -45,10 +45,10 @@ public class MemberTestCase extends TestCase { | |||
TestUtil.assertCommutativeEquals(t, v, false); | |||
TestUtil.assertCommutativeEquals(u, v, false); | |||
s = MemberImpl.fieldFromString("int Foo.goo"); | |||
s = TestUtils.fieldFromString("int Foo.goo"); | |||
t = MemberImpl.field("Foo", 0, "goo", "I"); | |||
u = MemberImpl.fieldFromString("int Foo.goo1"); | |||
v = MemberImpl.fieldFromString("long Foo.goo"); | |||
u = TestUtils.fieldFromString("int Foo.goo1"); | |||
v = TestUtils.fieldFromString("long Foo.goo"); | |||
TestUtil.assertCommutativeEquals(s, s, true); | |||
TestUtil.assertCommutativeEquals(t, t, true); | |||
@@ -64,7 +64,7 @@ public class MemberTestCase extends TestCase { | |||
public void testMethodContents() { | |||
Member m = MemberImpl.methodFromString("void Foo.goo(int)"); | |||
Member m = TestUtils.methodFromString("void Foo.goo(int)"); | |||
kindTest(m, Member.METHOD); | |||
declaringTypeTest(m, "Foo"); | |||
nameTest(m, "goo"); | |||
@@ -75,7 +75,7 @@ public class MemberTestCase extends TestCase { | |||
isConstructorTest(m, false); | |||
isStaticTest(m, false); | |||
m = MemberImpl.methodFromString("interface java.lang.Object java.util.Iterator.next()"); | |||
m = TestUtils.methodFromString("interface java.lang.Object java.util.Iterator.next()"); | |||
kindTest(m, Member.METHOD); | |||
declaringTypeTest(m, "java.util.Iterator"); | |||
nameTest(m, "next"); | |||
@@ -86,7 +86,7 @@ public class MemberTestCase extends TestCase { | |||
isConstructorTest(m, false); | |||
isStaticTest(m, false); | |||
m = MemberImpl.methodFromString("void Foo.<init>(int, java.lang.Object)"); | |||
m = TestUtils.methodFromString("void Foo.<init>(int, java.lang.Object)"); | |||
kindTest(m, Member.CONSTRUCTOR); | |||
declaringTypeTest(m, "Foo"); | |||
nameTest(m, "<init>"); | |||
@@ -97,7 +97,7 @@ public class MemberTestCase extends TestCase { | |||
isConstructorTest(m, true); | |||
isStaticTest(m, false); | |||
m = MemberImpl.methodFromString("private double Foo.sqrt(double)"); | |||
m = TestUtils.methodFromString("private double Foo.sqrt(double)"); | |||
kindTest(m, Member.METHOD); | |||
declaringTypeTest(m, "Foo"); | |||
nameTest(m, "sqrt"); | |||
@@ -108,7 +108,7 @@ public class MemberTestCase extends TestCase { | |||
isConstructorTest(m, false); | |||
isStaticTest(m, false); | |||
m = MemberImpl.methodFromString("static int java.lang.Math.max(int, int)"); | |||
m = TestUtils.methodFromString("static int java.lang.Math.max(int, int)"); | |||
kindTest(m, Member.METHOD); | |||
declaringTypeTest(m, "java.lang.Math"); | |||
nameTest(m, "max"); | |||
@@ -121,7 +121,7 @@ public class MemberTestCase extends TestCase { | |||
} | |||
public void testFieldContents() { | |||
Member m = MemberImpl.fieldFromString("int Foo.goo"); | |||
Member m = TestUtils.fieldFromString("int Foo.goo"); | |||
kindTest(m, Member.FIELD); | |||
declaringTypeTest(m, "Foo"); | |||
nameTest(m, "goo"); | |||
@@ -132,7 +132,7 @@ public class MemberTestCase extends TestCase { | |||
isConstructorTest(m, false); | |||
isStaticTest(m, false); | |||
m = MemberImpl.fieldFromString("static java.util.Iterator goo.Bar.i"); | |||
m = TestUtils.fieldFromString("static java.util.Iterator goo.Bar.i"); | |||
kindTest(m, Member.FIELD); | |||
declaringTypeTest(m, "goo.Bar"); | |||
nameTest(m, "i"); | |||
@@ -168,7 +168,7 @@ public class MemberTestCase extends TestCase { | |||
private void declaringTypeTest(Member m, String declaringName) { | |||
assertEquals(m + " declared in", UnresolvedType.forName(declaringName), m.getDeclaringType()); | |||
} | |||
private void kindTest(Member m, MemberImpl.Kind kind) { | |||
private void kindTest(Member m, MemberKind kind) { | |||
assertEquals(m + " kind", kind, m.getKind()); | |||
} | |||
@@ -0,0 +1,162 @@ | |||
/* ******************************************************************* | |||
* Copyright (c) 2008 Contributors | |||
* 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: | |||
* Andy Clement initial implementation | |||
* ******************************************************************/ | |||
package org.aspectj.weaver; | |||
import java.lang.reflect.Modifier; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import org.aspectj.weaver.bcel.BcelAdvice; | |||
import org.aspectj.weaver.patterns.FormalBinding; | |||
import org.aspectj.weaver.patterns.Pointcut; | |||
import org.aspectj.weaver.patterns.SimpleScope; | |||
public class TestUtils { | |||
private static final String[] ZERO_STRINGS = new String[0]; | |||
/** | |||
* Build a member from a string representation: | |||
* <blockquote><pre> | |||
* static? TypeName TypeName.Id | |||
* </pre></blockquote> | |||
*/ | |||
public static MemberImpl fieldFromString(String str) { | |||
str = str.trim(); | |||
final int len = str.length(); | |||
int i = 0; | |||
int mods = 0; | |||
if (str.startsWith("static", i)) { | |||
mods = Modifier.STATIC; | |||
i += 6; | |||
while (Character.isWhitespace(str.charAt(i))) i++; | |||
} | |||
int start = i; | |||
while (! Character.isWhitespace(str.charAt(i))) i++; | |||
UnresolvedType retTy = UnresolvedType.forName(str.substring(start, i)); | |||
start = i; | |||
i = str.lastIndexOf('.'); | |||
UnresolvedType declaringTy = UnresolvedType.forName(str.substring(start, i).trim()); | |||
start = ++i; | |||
String name = str.substring(start, len).trim(); | |||
return new MemberImpl( | |||
Member.FIELD, | |||
declaringTy, | |||
mods, | |||
retTy, | |||
name, | |||
UnresolvedType.NONE); | |||
} | |||
/** | |||
* Build a member from a string representation: | |||
* <blockquote><pre> | |||
* (static|interface|private)? TypeName TypeName . Id ( TypeName , ...) | |||
* </pre></blockquote> | |||
*/ | |||
public static Member methodFromString(String str) { | |||
str = str.trim(); | |||
// final int len = str.length(); | |||
int i = 0; | |||
int mods = 0; | |||
if (str.startsWith("static", i)) { | |||
mods = Modifier.STATIC; | |||
i += 6; | |||
} else if (str.startsWith("interface", i)) { | |||
mods = Modifier.INTERFACE; | |||
i += 9; | |||
} else if (str.startsWith("private", i)) { | |||
mods = Modifier.PRIVATE; | |||
i += 7; | |||
} | |||
while (Character.isWhitespace(str.charAt(i))) i++; | |||
int start = i; | |||
while (! Character.isWhitespace(str.charAt(i))) i++; | |||
UnresolvedType returnTy = UnresolvedType.forName(str.substring(start, i)); | |||
start = i; | |||
i = str.indexOf('(', i); | |||
i = str.lastIndexOf('.', i); | |||
UnresolvedType declaringTy = UnresolvedType.forName(str.substring(start, i).trim()); | |||
start = ++i; | |||
i = str.indexOf('(', i); | |||
String name = str.substring(start, i).trim(); | |||
start = ++i; | |||
i = str.indexOf(')', i); | |||
String[] paramTypeNames = parseIds(str.substring(start, i).trim()); | |||
return MemberImpl.method(declaringTy, mods, returnTy, name, UnresolvedType.forNames(paramTypeNames)); | |||
} | |||
private static String[] parseIds(String str) { | |||
if (str.length() == 0) return ZERO_STRINGS; | |||
List l = new ArrayList(); | |||
int start = 0; | |||
while (true) { | |||
int i = str.indexOf(',', start); | |||
if (i == -1) { | |||
l.add(str.substring(start).trim()); | |||
break; | |||
} | |||
l.add(str.substring(start, i).trim()); | |||
start = i+1; | |||
} | |||
return (String[]) l.toArray(new String[l.size()]); | |||
} | |||
/** | |||
* Moved from BcelWorld to here | |||
* | |||
* Parse a string into advice. | |||
* | |||
* <blockquote><pre> | |||
* Kind ( Id , ... ) : Pointcut -> MethodSignature | |||
* </pre></blockquote> | |||
*/ | |||
public static Advice shadowMunger(World w,String str, int extraFlag) { | |||
str = str.trim(); | |||
int start = 0; | |||
int i = str.indexOf('('); | |||
AdviceKind kind = | |||
AdviceKind.stringToKind(str.substring(start, i)); | |||
start = ++i; | |||
i = str.indexOf(')', i); | |||
String[] ids = parseIds(str.substring(start, i).trim()); | |||
//start = ++i; | |||
i = str.indexOf(':', i); | |||
start = ++i; | |||
i = str.indexOf("->", i); | |||
Pointcut pointcut = Pointcut.fromString(str.substring(start, i).trim()); | |||
Member m = TestUtils.methodFromString(str.substring(i+2, str.length()).trim()); | |||
// now, we resolve | |||
UnresolvedType[] types = m.getParameterTypes(); | |||
FormalBinding[] bindings = new FormalBinding[ids.length]; | |||
for (int j = 0, len = ids.length; j < len; j++) { | |||
bindings[j] = new FormalBinding(types[j], ids[j], j, 0, 0, "fromString"); | |||
} | |||
Pointcut p = | |||
pointcut.resolve(new SimpleScope(w, bindings)); | |||
return new BcelAdvice(kind, p, m, extraFlag, 0, 0, null, null); | |||
} | |||
} |
@@ -122,6 +122,29 @@ public class TypeXTestCase extends TestCase { | |||
} | |||
} | |||
public void testTypeFactoryForParameterizedTypes() { | |||
if (LangUtil.is15VMOrGreater()) { // no funny types pre 1.5 | |||
UnresolvedType enumOfSimpleType = | |||
TypeFactory.createTypeFromSignature("Pjava/lang/Enum<Ljava/lang/String;>;"); | |||
assertEquals(1, enumOfSimpleType.getTypeParameters().length); | |||
UnresolvedType enumOfNestedType = | |||
TypeFactory.createTypeFromSignature("Pjava/lang/Enum<Ljavax/jws/soap/SOAPBinding$ParameterStyle;>;"); | |||
assertEquals(1, enumOfNestedType.getTypeParameters().length); | |||
// is this signature right? | |||
UnresolvedType nestedTypeOfParameterized = | |||
TypeFactory.createTypeFromSignature("PMyInterface<Ljava/lang/String;>$MyOtherType;"); | |||
assertEquals(0, nestedTypeOfParameterized.getTypeParameters().length); | |||
// how about this one? is this valid? | |||
UnresolvedType doublyNestedTypeSignatures = | |||
TypeFactory.createTypeFromSignature("PMyInterface<Ljava/lang/String;Ljava/lang/String;>$MyOtherType<Ljava/lang/Object;>;"); | |||
assertEquals(1, doublyNestedTypeSignatures.getTypeParameters().length); | |||
} | |||
} | |||
private void checkTX(UnresolvedType tx,boolean shouldBeParameterized,int numberOfTypeParameters) { | |||
assertTrue("Expected parameterization flag to be "+shouldBeParameterized,tx.isParameterizedType()==shouldBeParameterized); | |||
if (numberOfTypeParameters==0) { |
@@ -33,7 +33,7 @@ public class AfterThrowingWeaveTestCase extends WeaveTestCase { | |||
BcelWorld world = new BcelWorld(); | |||
ShadowMunger myMunger = | |||
world.shadowMunger("afterThrowing(): get(* *.out) -> static void Aspect.ajc_afterThrowing_field_get(java.lang.Throwable)", | |||
TestUtils.shadowMunger(world,"afterThrowing(): get(* *.out) -> static void Aspect.ajc_afterThrowing_field_get(java.lang.Throwable)", | |||
Advice.ExtraArgument); | |||
ShadowMunger cm = myMunger.concretize(ResolvedType.MISSING, world, null); | |||
@@ -19,6 +19,7 @@ import java.util.Arrays; | |||
import org.aspectj.weaver.Advice; | |||
import org.aspectj.weaver.AdviceKind; | |||
import org.aspectj.weaver.MemberImpl; | |||
import org.aspectj.weaver.TestUtils; | |||
import org.aspectj.weaver.ResolvedType; | |||
import org.aspectj.weaver.UnresolvedType; | |||
@@ -46,7 +47,7 @@ public class TjpWeaveTestCase extends WeaveTestCase { | |||
BcelAdvice munger = new BcelAdvice( | |||
AdviceKind.stringToKind("before"), | |||
makePointcutAll(), | |||
MemberImpl.methodFromString("static void Aspect.ajc_before(org.aspectj.lang.JoinPoint$StaticPart)"), | |||
TestUtils.methodFromString("static void Aspect.ajc_before(org.aspectj.lang.JoinPoint$StaticPart)"), | |||
Advice.ThisJoinPointStaticPart, -1, -1, null, null); | |||
weaveTest("HelloWorld", "StaticTjpBeforeHelloWorld", munger); | |||
@@ -57,7 +58,7 @@ public class TjpWeaveTestCase extends WeaveTestCase { | |||
BcelAdvice munger = new BcelAdvice( | |||
AdviceKind.stringToKind("before"), | |||
makePointcutAll(), | |||
MemberImpl.methodFromString("static void Aspect.ajc_before(org.aspectj.lang.JoinPoint$StaticPart)"), | |||
TestUtils.methodFromString("static void Aspect.ajc_before(org.aspectj.lang.JoinPoint$StaticPart)"), | |||
Advice.ThisEnclosingJoinPointStaticPart, -1, -1, null, null); | |||
weaveTest("HelloWorld", "StaticEnclosingTjpBeforeHelloWorld", munger); | |||
@@ -68,7 +69,7 @@ public class TjpWeaveTestCase extends WeaveTestCase { | |||
BcelAdvice munger = new BcelAdvice( | |||
AdviceKind.stringToKind("before"), | |||
makePointcutAll(), | |||
MemberImpl.methodFromString("static void Aspect.ajc_before(org.aspectj.lang.JoinPoint)"), | |||
TestUtils.methodFromString("static void Aspect.ajc_before(org.aspectj.lang.JoinPoint)"), | |||
Advice.ThisJoinPoint, -1, -1, null, null); | |||
weaveTest("HelloWorld", "TjpBeforeHelloWorld", munger); | |||
@@ -78,7 +79,7 @@ public class TjpWeaveTestCase extends WeaveTestCase { | |||
BcelAdvice munger = new BcelAdvice( | |||
AdviceKind.stringToKind("around"), | |||
makePointcutAll(), | |||
MemberImpl.methodFromString("static java.lang.Object Aspect.ajc_around(org.aspectj.runtime.internal.AroundClosure, org.aspectj.lang.JoinPoint)"), | |||
TestUtils.methodFromString("static java.lang.Object Aspect.ajc_around(org.aspectj.runtime.internal.AroundClosure, org.aspectj.lang.JoinPoint)"), | |||
Advice.ThisJoinPoint | Advice.ExtraArgument, -1, -1, null, null); | |||
weaveTest("HelloWorld", "TjpAroundHelloWorld", munger); | |||
@@ -90,14 +91,14 @@ public class TjpWeaveTestCase extends WeaveTestCase { | |||
BcelAdvice munger1 = new BcelAdvice( | |||
AdviceKind.stringToKind("around"), | |||
makePointcutAll(), | |||
MemberImpl.methodFromString("static java.lang.Object Aspect.ajc_around(org.aspectj.runtime.internal.AroundClosure, org.aspectj.lang.JoinPoint)"), | |||
TestUtils.methodFromString("static java.lang.Object Aspect.ajc_around(org.aspectj.runtime.internal.AroundClosure, org.aspectj.lang.JoinPoint)"), | |||
Advice.ThisJoinPoint | Advice.ExtraArgument, -1, -1, null, | |||
rtx); | |||
BcelAdvice munger2 = new BcelAdvice( | |||
AdviceKind.stringToKind("around"), | |||
makePointcutAll(), | |||
MemberImpl.methodFromString("static java.lang.Object Aspect.ajc_around(org.aspectj.runtime.internal.AroundClosure, org.aspectj.lang.JoinPoint)"), | |||
TestUtils.methodFromString("static java.lang.Object Aspect.ajc_around(org.aspectj.runtime.internal.AroundClosure, org.aspectj.lang.JoinPoint)"), | |||
Advice.ThisJoinPoint | Advice.ExtraArgument, -1, -1, null, | |||
rtx); | |||
@@ -189,7 +189,7 @@ public abstract class WeaveTestCase extends TestCase { | |||
protected ShadowMunger makeConcreteAdvice(String mungerString, int extraArgFlag, PerClause perClause) { | |||
Advice myMunger = | |||
world.shadowMunger(mungerString, extraArgFlag); | |||
TestUtils.shadowMunger(world,mungerString, extraArgFlag); | |||
// PerSingleton s = new PerSingleton(); | |||
// s.concretize(world.resolve("Aspect")); |