123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687 |
- /* *******************************************************************
- * 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 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;
-
- /*
- * The superclass of anything representing a the shadow of a join point. A shadow represents
- * some bit of code, and encompasses both entry and exit from that code. All shadows have a kind
- * and a signature.
- */
-
- 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. // OPTIMIZE is this a bug? static?
-
- private final Kind kind;
- private final Member signature;
- private Member matchingSignature;
- private ResolvedMember resolvedSignature;
- protected final Shadow enclosingShadow;
- protected List<ShadowMunger> mungers = Collections.emptyList();
-
- public int shadowId = nextShadowID++; // every time we build a shadow, it gets a new id
-
- // ----
- 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;
- }
-
- /**
- * could this(*) pcd ever match
- */
- 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();
- }
- }
-
- /**
- * the type of the this object here
- *
- * @throws IllegalStateException if there is no this here
- */
- public final UnresolvedType getThisType() {
- if (!hasThis()) {
- throw new IllegalStateException("no this");
- }
- if (getKind().isEnclosingKind()) {
- return getSignature().getDeclaringType();
- } else {
- return enclosingShadow.getThisType();
- }
- }
-
- /**
- * a var referencing this
- *
- * @throws IllegalStateException if there is no target here
- */
- public abstract Var getThisVar();
-
- /**
- * could target(*) pcd ever match
- */
- public final boolean hasTarget() {
- if (getKind().neverHasTarget()) {
- return false;
- } else if (getKind().isTargetSameAsThis()) {
- return hasThis();
- } else {
- return !Modifier.isStatic(getSignature().getModifiers());
- }
- }
-
- /**
- * the type of the target object here
- *
- * @throws IllegalStateException if there is no target here
- */
- public final UnresolvedType getTargetType() {
- if (!hasTarget()) {
- throw new IllegalStateException("no target");
- }
- return getSignature().getDeclaringType();
- }
-
- /**
- * a var referencing the target
- *
- * @throws IllegalStateException if there is no target here
- */
- 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);
- }
-
- // will return the right length array of ints depending on how many dimensions the array has
- 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;
- }
-
- // /**
- // * 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();
-
- public abstract Var getArgVar(int i);
-
- public abstract Var getThisJoinPointVar();
-
- public abstract Var getThisJoinPointStaticPartVar();
-
- public abstract Var getThisEnclosingJoinPointStaticPartVar();
-
- public abstract Var getThisAspectInstanceVar(ResolvedType aspectType);
-
- // annotation variables
- 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();
-
- /**
- * returns the kind of shadow this is, representing what happens under this shadow
- */
- public Kind getKind() {
- return kind;
- }
-
- /**
- * returns the signature of the thing under this shadow
- */
- public Member getSignature() {
- return signature;
- }
-
- /**
- * returns the signature of the thing under this shadow, with any synthetic arguments removed
- */
- public Member getMatchingSignature() {
- return matchingSignature != null ? matchingSignature : signature;
- }
-
- public void setMatchingSignature(Member member) {
- this.matchingSignature = member;
- }
-
- /**
- * returns the resolved signature of the thing under this shadow
- *
- */
- 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";
-
- /**
- * These names are the ones that will be returned by thisJoinPoint.getKind() Those need to be documented somewhere
- */
- 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);
-
- // Bits here are 1<<(Kind.getKey()) - and unfortunately keys didn't start at zero so bits here start at 2
- 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;
- }
-
- /**
- * Return count of how many bits set in the supplied parameter.
- */
- 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;
- }
-
- /**
- * A type-safe enum representing the kind of shadows
- */
- public static final class Kind extends TypeSafeEnum {
- // private boolean argsOnStack; //XXX unused
-
- public int bit;
-
- public Kind(String name, int key, boolean argsOnStack) {
- super(name, key);
- bit = 1 << key;
- // this.argsOnStack = argsOnStack;
- }
-
- public String toLegalJavaIdentifier() {
- return getName().replace('-', '_');
- }
-
- public boolean argsOnStack() {
- return !isTargetSameAsThis();
- }
-
- // false for handlers
- public boolean allowsExtraction() {
- return true;
- }
-
- public boolean isSet(int i) {
- return (i & bit) != 0;
- }
-
- // XXX revisit along with removal of priorities
- public boolean hasHighPriorityExceptions() {
- return !isTargetSameAsThis();
- }
-
- private final static int hasReturnValueFlag = MethodCallBit | ConstructorCallBit | MethodExecutionBit | FieldGetBit
- | AdviceExecutionBit;
-
- /**
- * These shadow kinds have return values that can be bound in after returning(Dooberry doo) advice.
- *
- * @return
- */
- public boolean hasReturnValue() {
- return (bit & hasReturnValueFlag) != 0;
- }
-
- private final static int isEnclosingKindFlag = MethodExecutionBit | ConstructorExecutionBit | AdviceExecutionBit
- | StaticInitializationBit | InitializationBit;
-
- /**
- * These are all the shadows that contains other shadows within them and are often directly associated with methods.
- */
- 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);
- }
- }
-
- /**
- * Only does the check if the munger requires it (@AJ aspects don't)
- *
- * @param munger
- * @return
- */
- 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) {
- // XXX much too lenient rules here, need to walk up exception handlers
- return true;
- }
-
- if (!isDeclaredException(resolvedTypeX, getSignature())) {
- getIWorld().showMessage(IMessage.ERROR, WeaverMessages.format(WeaverMessages.CANT_THROW_CHECKED, resolvedTypeX, this), // from
- // advice
- // in
- // \
- // '"
- // +
- // munger
- // .
- // +
- // "\'"
- // ,
- 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);
-
- // Bunch of code to work out whether to report xlints for advice that isn't ordered at this Joinpoint
- possiblyReportUnorderedAdvice(sorted);
-
- if (sorted == null) {
- // this means that we have circular dependencies
- for (ShadowMunger m : mungers) {
- getIWorld().getMessageHandler().handleMessage(
- MessageUtil.error(WeaverMessages.format(WeaverMessages.CIRCULAR_DEPENDENCY, this), m.getSourceLocation()));
- }
- }
- mungers = sorted;
- }
-
- // not quite optimal... but the xlint is ignore by default
- private void possiblyReportUnorderedAdvice(List sorted) {
- if (sorted != null && getIWorld().getLint().unorderedAdviceAtShadow.isEnabled() && mungers.size() > 1) {
-
- // Stores a set of strings of the form 'aspect1:aspect2' which indicates there is no
- // precedence specified between the two aspects at this shadow.
- Set<String> clashingAspects = new HashSet<String>();
- int max = mungers.size();
-
- // Compare every pair of advice mungers
- 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);
-
- // Make sure they are the right type
- 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();
-
- // make sure they are the nice ones (<6) and not any synthetic advice ones we
- // create to support other features of the language.
- if (adviceKindA.getKey() < (byte) 6 && adviceKindB.getKey() < (byte) 6
- && adviceKindA.getPrecedence() == adviceKindB.getPrecedence()) {
-
- // Ask the world if it knows about precedence between these
- 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);
- }
- }
- }
-
- /**
- * Prepare the shadow for implementation. After this is done, the shadow should be in such a position that each munger simply
- * needs to be implemented.
- */
- protected void prepareForMungers() {
- throw new RuntimeException("Generic shadows cannot be prepared");
- }
-
- /** Actually implement the (non-empty) mungers associated with this shadow */
- private void implementMungers() {
- World world = getIWorld();
- for (ShadowMunger munger : mungers) {
- if (munger.implementOn(this)) {
- world.reportMatch(munger, this);
- }
- }
- }
-
- public abstract ISourceLocation getSourceLocation();
-
- // ---- utility
-
- public String toString() {
- return getKind() + "(" + getSignature() + ")"; // + getSourceLines();
- }
-
- 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();
- // was: return getKind() + "(" + world.resolve(getSignature()).toGenericString() + ")";
- }
-
- /**
- * Convert a bit array for the shadow kinds into a set of them... should only be used for testing - mainline code should do bit
- * manipulation!
- */
- 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;
- }
-
- }
|