package org.aspectj.weaver;
import java.io.DataInputStream;
import java.io.IOException;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.aspectj.bridge.IMessage;
import org.aspectj.bridge.ISourceLocation;
import org.aspectj.bridge.MessageUtil;
import org.aspectj.util.PartialOrder;
import org.aspectj.util.TypeSafeEnum;
import org.aspectj.weaver.ast.Var;
public abstract class Shadow {
private static int nextShadowID = 100;
private final Kind kind;
private final Member signature;
private Member matchingSignature;
private ResolvedMember resolvedSignature;
protected final Shadow enclosingShadow;
protected List<ShadowMunger> mungers = Collections.emptyList();
protected boolean needAroundClosureStacking = false;
public int shadowId = nextShadowID++;
protected Shadow(Kind kind, Member signature, Shadow enclosingShadow) {
this.kind = kind;
this.signature = signature;
this.enclosingShadow = enclosingShadow;
}
public abstract World getIWorld();
public List<ShadowMunger> getMungers() {
return mungers;
}
public final boolean hasThis() {
if (getKind().neverHasThis()) {
return false;
} else if (getKind().isEnclosingKind()) {
return !Modifier.isStatic(getSignature().getModifiers());
} else if (enclosingShadow == null) {
return false;
} else {
return enclosingShadow.hasThis();
}
}
public final UnresolvedType getThisType() {
if (!hasThis()) {
throw new IllegalStateException("no this");
}
if (getKind().isEnclosingKind()) {
return getSignature().getDeclaringType();
} else {
return enclosingShadow.getThisType();
}
}
public abstract Var getThisVar();
public final boolean hasTarget() {
if (getKind().neverHasTarget()) {
return false;
} else if (getKind().isTargetSameAsThis()) {
return hasThis();
} else {
return !Modifier.isStatic(getSignature().getModifiers());
}
}
public final UnresolvedType getTargetType() {
if (!hasTarget()) {
throw new IllegalStateException("no target");
}
return getSignature().getDeclaringType();
}
public abstract Var getTargetVar();
public UnresolvedType[] getArgTypes() {
if (getKind() == FieldSet) {
return new UnresolvedType[] { getSignature().getReturnType() };
}
return getSignature().getParameterTypes();
}
public boolean isShadowForArrayConstructionJoinpoint() {
return (getKind() == ConstructorCall && signature.getDeclaringType().isArray());
}
public boolean isShadowForMonitor() {
return (getKind() == SynchronizationLock || getKind() == SynchronizationUnlock);
}
public ResolvedType[] getArgumentTypesForArrayConstructionShadow() {
String s = signature.getDeclaringType().getSignature();
int pos = s.indexOf("[");
int dims = 1;
while (pos < s.length()) {
pos++;
if (pos < s.length()) {
dims += (s.charAt(pos) == '[' ? 1 : 0);
}
}
ResolvedType intType = UnresolvedType.INT.resolve(this.getIWorld());
if (dims == 1) {
return new ResolvedType[] { intType };
}
ResolvedType[] someInts = new ResolvedType[dims];
for (int i = 0; i < dims; i++) {
someInts[i] = intType;
}
return someInts;
}
public UnresolvedType[] getGenericArgTypes() {
if (isShadowForArrayConstructionJoinpoint()) {
return getArgumentTypesForArrayConstructionShadow();
}
if (isShadowForMonitor()) {
return UnresolvedType.ARRAY_WITH_JUST_OBJECT;
}
if (getKind() == FieldSet) {
return new UnresolvedType[] { getResolvedSignature().getGenericReturnType() };
}
return getResolvedSignature().getGenericParameterTypes();
}
public UnresolvedType getArgType(int arg) {
if (getKind() == FieldSet) {
return getSignature().getReturnType();
}
return getSignature().getParameterTypes()[arg];
}
public int getArgCount() {
if (getKind() == FieldSet) {
return 1;
}
return getSignature().getParameterTypes().length;
}
public abstract UnresolvedType getEnclosingType();
public abstract Var getArgVar(int i);
public abstract Var getThisJoinPointVar();
public abstract Var getThisJoinPointStaticPartVar();
public abstract Var getThisEnclosingJoinPointStaticPartVar();
public abstract Var getThisAspectInstanceVar(ResolvedType aspectType);
public abstract Var getKindedAnnotationVar(UnresolvedType forAnnotationType);
public abstract Var getWithinAnnotationVar(UnresolvedType forAnnotationType);
public abstract Var getWithinCodeAnnotationVar(UnresolvedType forAnnotationType);
public abstract Var getThisAnnotationVar(UnresolvedType forAnnotationType);
public abstract Var getTargetAnnotationVar(UnresolvedType forAnnotationType);
public abstract Var getArgAnnotationVar(int i, UnresolvedType forAnnotationType);
public abstract Member getEnclosingCodeSignature();
public Kind getKind() {
return kind;
}
public Member getSignature() {
return signature;
}
public Member getMatchingSignature() {
return matchingSignature != null ? matchingSignature : signature;
}
public void setMatchingSignature(Member member) {
this.matchingSignature = member;
}
public ResolvedMember getResolvedSignature() {
if (resolvedSignature == null) {
resolvedSignature = signature.resolve(getIWorld());
}
return resolvedSignature;
}
public UnresolvedType getReturnType() {
if (kind == ConstructorCall) {
return getSignature().getDeclaringType();
} else if (kind == FieldSet) {
return UnresolvedType.VOID;
} else if (kind == SynchronizationLock || kind == SynchronizationUnlock) {
return UnresolvedType.VOID;
}
return getResolvedSignature().getGenericReturnType();
}
public static String METHOD_EXECUTION = "method-execution";
public static String METHOD_CALL = "method-call";
public static String CONSTRUCTOR_EXECUTION = "constructor-execution";
public static String CONSTRUCTOR_CALL = "constructor-call";
public static String FIELD_GET = "field-get";
public static String FIELD_SET = "field-set";
public static String STATICINITIALIZATION = "staticinitialization";
public static String PREINITIALIZATION = "preinitialization";
public static String INITIALIZATION = "initialization";
public static String EXCEPTION_HANDLER = "exception-handler";
public static String SYNCHRONIZATION_LOCK = "lock";
public static String SYNCHRONIZATION_UNLOCK = "unlock";
public static String ADVICE_EXECUTION = "adviceexecution";
public static final Kind MethodCall = new Kind(METHOD_CALL, 1, true);
public static final Kind ConstructorCall = new Kind(CONSTRUCTOR_CALL, 2, true);
public static final Kind MethodExecution = new Kind(METHOD_EXECUTION, 3, false);
public static final Kind ConstructorExecution = new Kind(CONSTRUCTOR_EXECUTION, 4, false);
public static final Kind FieldGet = new Kind(FIELD_GET, 5, true);
public static final Kind FieldSet = new Kind(FIELD_SET, 6, true);
public static final Kind StaticInitialization = new Kind(STATICINITIALIZATION, 7, false);
public static final Kind PreInitialization = new Kind(PREINITIALIZATION, 8, false);
public static final Kind AdviceExecution = new Kind(ADVICE_EXECUTION, 9, false);
public static final Kind Initialization = new Kind(INITIALIZATION, 10, false);
public static final Kind ExceptionHandler = new Kind(EXCEPTION_HANDLER, 11, true);
public static final Kind SynchronizationLock = new Kind(SYNCHRONIZATION_LOCK, 12, true);
public static final Kind SynchronizationUnlock = new Kind(SYNCHRONIZATION_UNLOCK, 13, true);
public static final int MethodCallBit = 0x002;
public static final int ConstructorCallBit = 0x004;
public static final int MethodExecutionBit = 0x008;
public static final int ConstructorExecutionBit = 0x010;
public static final int FieldGetBit = 0x020;
public static final int FieldSetBit = 0x040;
public static final int StaticInitializationBit = 0x080;
public static final int PreInitializationBit = 0x100;
public static final int AdviceExecutionBit = 0x200;
public static final int InitializationBit = 0x400;
public static final int ExceptionHandlerBit = 0x800;
public static final int SynchronizationLockBit = 0x1000;
public static final int SynchronizationUnlockBit = 0x2000;
public static final int MAX_SHADOW_KIND = 13;
public static final Kind[] SHADOW_KINDS = new Kind[] { MethodCall, ConstructorCall, MethodExecution, ConstructorExecution,
FieldGet, FieldSet, StaticInitialization, PreInitialization, AdviceExecution, Initialization, ExceptionHandler,
SynchronizationLock, SynchronizationUnlock };
public static final int ALL_SHADOW_KINDS_BITS;
public static final int NO_SHADOW_KINDS_BITS;
static {
ALL_SHADOW_KINDS_BITS = 0x3ffe;
NO_SHADOW_KINDS_BITS = 0x0000;
}
public static int howMany(int i) {
int count = 0;
for (int j = 0; j < SHADOW_KINDS.length; j++) {
if ((i & SHADOW_KINDS[j].bit) != 0) {
count++;
}
}
return count;
}
public static final class Kind extends TypeSafeEnum {
public int bit;
public Kind(String name, int key, boolean argsOnStack) {
super(name, key);
bit = 1 << key;
}
public String toLegalJavaIdentifier() {
return getName().replace('-', '_');
}
public boolean argsOnStack() {
return !isTargetSameAsThis();
}
public boolean allowsExtraction() {
return true;
}
public boolean isSet(int i) {
return (i & bit) != 0;
}
public boolean hasHighPriorityExceptions() {
return !isTargetSameAsThis();
}
private final static int hasReturnValueFlag = MethodCallBit | ConstructorCallBit | MethodExecutionBit | FieldGetBit
| AdviceExecutionBit;
public boolean hasReturnValue() {
return (bit & hasReturnValueFlag) != 0;
}
private final static int isEnclosingKindFlag = MethodExecutionBit | ConstructorExecutionBit | AdviceExecutionBit
| StaticInitializationBit | InitializationBit;
public boolean isEnclosingKind() {
return (bit & isEnclosingKindFlag) != 0;
}
private final static int isTargetSameAsThisFlag = MethodExecutionBit | ConstructorExecutionBit | StaticInitializationBit
| PreInitializationBit | AdviceExecutionBit | InitializationBit;
public boolean isTargetSameAsThis() {
return (bit & isTargetSameAsThisFlag) != 0;
}
private final static int neverHasTargetFlag = ConstructorCallBit | ExceptionHandlerBit | PreInitializationBit
| StaticInitializationBit | SynchronizationLockBit | SynchronizationUnlockBit;
public boolean neverHasTarget() {
return (bit & neverHasTargetFlag) != 0;
}
private final static int neverHasThisFlag = PreInitializationBit | StaticInitializationBit;
public boolean neverHasThis() {
return (bit & neverHasThisFlag) != 0;
}
public String getSimpleName() {
int dash = getName().lastIndexOf('-');
if (dash == -1) {
return getName();
} else {
return getName().substring(dash + 1);
}
}
public static Kind read(DataInputStream s) throws IOException {
int key = s.readByte();
switch (key) {
case 1:
return MethodCall;
case 2:
return ConstructorCall;
case 3:
return MethodExecution;
case 4:
return ConstructorExecution;
case 5:
return FieldGet;
case 6:
return FieldSet;
case 7:
return StaticInitialization;
case 8:
return PreInitialization;
case 9:
return AdviceExecution;
case 10:
return Initialization;
case 11:
return ExceptionHandler;
case 12:
return SynchronizationLock;
case 13:
return SynchronizationUnlock;
}
throw new BCException("unknown kind: " + key);
}
}
protected boolean checkMunger(ShadowMunger munger) {
if (munger.mustCheckExceptions()) {
for (Iterator<ResolvedType> i = munger.getThrownExceptions().iterator(); i.hasNext();) {
if (!checkCanThrow(munger, i.next())) {
return false;
}
}
}
return true;
}
protected boolean checkCanThrow(ShadowMunger munger, ResolvedType resolvedTypeX) {
if (getKind() == ExceptionHandler) {
return true;
}
if (!isDeclaredException(resolvedTypeX, getSignature())) {
getIWorld().showMessage(IMessage.ERROR, WeaverMessages.format(WeaverMessages.CANT_THROW_CHECKED, resolvedTypeX, this),
getSourceLocation(), munger.getSourceLocation());
}
return true;
}
private boolean isDeclaredException(ResolvedType resolvedTypeX, Member member) {
ResolvedType[] excs = getIWorld().resolve(member.getExceptions(getIWorld()));
for (int i = 0, len = excs.length; i < len; i++) {
if (excs[i].isAssignableFrom(resolvedTypeX)) {
return true;
}
}
return false;
}
public void addMunger(ShadowMunger munger) {
if (checkMunger(munger)) {
if (mungers == Collections.EMPTY_LIST) {
mungers = new ArrayList<ShadowMunger>();
}
this.mungers.add(munger);
}
}
public final void implement() {
sortMungers();
if (mungers == null) {
return;
}
prepareForMungers();
implementMungers();
}
private void sortMungers() {
List sorted = PartialOrder.sort(mungers);
possiblyReportUnorderedAdvice(sorted);
if (sorted == null) {
for (ShadowMunger m : mungers) {
getIWorld().getMessageHandler().handleMessage(
MessageUtil.error(WeaverMessages.format(WeaverMessages.CIRCULAR_DEPENDENCY, this), m.getSourceLocation()));
}
}
mungers = sorted;
}
private void possiblyReportUnorderedAdvice(List sorted) {
if (sorted != null && getIWorld().getLint().unorderedAdviceAtShadow.isEnabled() && mungers.size() > 1) {
Set<String> clashingAspects = new HashSet<String>();
int max = mungers.size();
for (int i = max - 1; i >= 0; i--) {
for (int j = 0; j < i; j++) {
Object a = mungers.get(i);
Object b = mungers.get(j);
if (a instanceof Advice && b instanceof Advice) {
Advice adviceA = (Advice) a;
Advice adviceB = (Advice) b;
if (!adviceA.concreteAspect.equals(adviceB.concreteAspect)) {
AdviceKind adviceKindA = adviceA.getKind();
AdviceKind adviceKindB = adviceB.getKind();
if (adviceKindA.getKey() < (byte) 6 && adviceKindB.getKey() < (byte) 6
&& adviceKindA.getPrecedence() == adviceKindB.getPrecedence()) {
Integer order = getIWorld().getPrecedenceIfAny(adviceA.concreteAspect, adviceB.concreteAspect);
if (order != null && order.equals(new Integer(0))) {
String key = adviceA.getDeclaringAspect() + ":" + adviceB.getDeclaringAspect();
String possibleExistingKey = adviceB.getDeclaringAspect() + ":" + adviceA.getDeclaringAspect();
if (!clashingAspects.contains(possibleExistingKey)) {
clashingAspects.add(key);
}
}
}
}
}
}
}
for (Iterator<String> iter = clashingAspects.iterator(); iter.hasNext();) {
String element = iter.next();
String aspect1 = element.substring(0, element.indexOf(":"));
String aspect2 = element.substring(element.indexOf(":") + 1);
getIWorld().getLint().unorderedAdviceAtShadow.signal(new String[] { this.toString(), aspect1, aspect2 },
this.getSourceLocation(), null);
}
}
}
protected void prepareForMungers() {
throw new RuntimeException("Generic shadows cannot be prepared");
}
private void implementMungers() {
World world = getIWorld();
needAroundClosureStacking = false;
int annotationStyleWithAroundAndProceedCount = 0;
for (ShadowMunger munger: mungers) {
if (munger.getDeclaringType()!= null &&
munger.getDeclaringType().isAnnotationStyleAspect() &&
munger.isAroundAdvice() &&
munger.bindsProceedingJoinPoint()) {
annotationStyleWithAroundAndProceedCount++;
if (annotationStyleWithAroundAndProceedCount>1) {
needAroundClosureStacking = true;
break;
}
}
}
for (ShadowMunger munger : mungers) {
if (munger.implementOn(this)) {
world.reportMatch(munger, this);
}
}
}
public abstract ISourceLocation getSourceLocation();
public String toString() {
return getKind() + "(" + getSignature() + ")";
}
public String toResolvedString(World world) {
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();
}
public static Set<Kind> toSet(int i) {
Set<Kind> results = new HashSet<Kind>();
for (int j = 0; j < Shadow.SHADOW_KINDS.length; j++) {
Kind k = Shadow.SHADOW_KINDS[j];
if (k.isSet(i)) {
results.add(k);
}
}
return results;
}
}