Package org.aspectj.weaver

Source Code of org.aspectj.weaver.Shadow$Kind

/* *******************************************************************
* 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 Common Public License v1.0
* which accompanies this distribution and is available at
* http://www.eclipse.org/legal/cpl-v10.html
* Contributors:
*     PARC     initial implementation
* ******************************************************************/


package org.aspectj.weaver;

import java.io.DataInputStream;
import java.io.IOException;
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.asm.IRelationship;
import org.aspectj.bridge.IMessage;
import org.aspectj.bridge.ISourceLocation;
import org.aspectj.bridge.Message;
import org.aspectj.bridge.MessageUtil;
import org.aspectj.bridge.WeaveMessage;
import org.aspectj.lang.JoinPoint;
import org.aspectj.util.PartialOrder;
import org.aspectj.util.TypeSafeEnum;
import org.aspectj.weaver.ast.Var;
import org.aspectj.weaver.bcel.BcelAdvice;

/*
* 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.
 
  private final Kind kind;
    private final Member signature;
    private Member matchingSignature;
    private ResolvedMember resolvedSignature;
  protected final Shadow enclosingShadow;
    protected List mungers = new ArrayList(1);

    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 !getSignature().isStatic();
      } 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 !getSignature().isStatic();
      }
    }

    /**
     * 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 UnresolvedType[] getGenericArgTypes() {
      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();
   
  // 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 ResolvedType.VOID;
    return getResolvedSignature().getGenericReturnType();
  }

   
    /**
     * 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(JoinPoint.METHOD_CALL, 1true);
    public static final Kind ConstructorCall      = new Kind(JoinPoint.CONSTRUCTOR_CALL, 2true);
    public static final Kind MethodExecution      = new Kind(JoinPoint.METHOD_EXECUTION, 3false);
    public static final Kind ConstructorExecution = new Kind(JoinPoint.CONSTRUCTOR_EXECUTION, 4false);
    public static final Kind FieldGet             = new Kind(JoinPoint.FIELD_GET, 5true);
    public static final Kind FieldSet             = new Kind(JoinPoint.FIELD_SET, 6true);
    public static final Kind StaticInitialization = new Kind(JoinPoint.STATICINITIALIZATION, 7false);
    public static final Kind PreInitialization    = new Kind(JoinPoint.PREINTIALIZATION, 8false);
    public static final Kind AdviceExecution      = new Kind(JoinPoint.ADVICE_EXECUTION, 9false);
    public static final Kind Initialization       = new Kind(JoinPoint.INITIALIZATION, 10false);
    public static final Kind ExceptionHandler     = new Kind(JoinPoint.EXCEPTION_HANDLER, 11true);
   
    public static final int MAX_SHADOW_KIND = 11;
    public static final Kind[] SHADOW_KINDS = new Kind[] {
      MethodCall, ConstructorCall, MethodExecution, ConstructorExecution,
      FieldGet, FieldSet, StaticInitialization, PreInitialization,
      AdviceExecution, Initialization, ExceptionHandler,
    };

    public static final Set ALL_SHADOW_KINDS;  
    static {
      HashSet aSet = new HashSet();
      for (int i = 0; i < SHADOW_KINDS.length; i++) {
      aSet.add(SHADOW_KINDS[i]);
    }
      ALL_SHADOW_KINDS = Collections.unmodifiableSet(aSet);
    }

    /** A type-safe enum representing the kind of shadows
     */
  public static final class Kind extends TypeSafeEnum {
//    private boolean argsOnStack;  //XXX unused

    public Kind(String name, int key, boolean argsOnStack) {
      super(name, key);
//      this.argsOnStack = argsOnStack;
    }

    public String toLegalJavaIdentifier() {
      return getName().replace('-', '_');
    }

    public boolean argsOnStack() {
      return !isTargetSameAsThis();
    }

    // !!! this is false for handlers!
    public boolean allowsExtraction() {
      return true;
    }
   
    // XXX revisit along with removal of priorities
    public boolean hasHighPriorityExceptions() {
      return !isTargetSameAsThis();
    }
   
    /**
     * These shadow kinds have return values that can be bound in
     * after returning(Dooberry doo) advice.
     * @return
     */
    public boolean hasReturnValue() {
      return
        this == MethodCall ||
        this == ConstructorCall ||
        this == MethodExecution ||
        this == FieldGet ||
        this == AdviceExecution;
    }
   
   
    /**
     * These are all the shadows that contains other shadows within them and
     * are often directly associated with methods.
     */
    public boolean isEnclosingKind() {
      return this == MethodExecution || this == ConstructorExecution ||
          this == AdviceExecution || this == StaticInitialization
          || this == Initialization;
    }
   
    public boolean isTargetSameAsThis() {
      return this == MethodExecution
        || this == ConstructorExecution
        || this == StaticInitialization
        || this == PreInitialization
        || this == AdviceExecution
        || this == Initialization;
    }
   
    public boolean neverHasTarget() {
      return this == ConstructorCall
        || this == ExceptionHandler
        || this == PreInitialization
        || this == StaticInitialization;
    }
   
    public boolean neverHasThis() {
      return this == PreInitialization
        || this == StaticInitialization;
    }
   
   
    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;
      }
      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 i = munger.getThrownExceptions().iterator(); i.hasNext(); ) {
                if (!checkCanThrow(munger,  (ResolvedType)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)) 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 (Iterator i = mungers.iterator(); i.hasNext(); ) {
        ShadowMunger m = (ShadowMunger)i.next();
        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 clashingAspects = new HashSet();
      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 BcelAdvice && b instanceof BcelAdvice) {
            BcelAdvice adviceA = (BcelAdvice)a;
            BcelAdvice adviceB = (BcelAdvice)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 iter = clashingAspects.iterator(); iter.hasNext();) {
        String element = (String) 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");   
  }
 
  /*
   * Ensure we report a nice source location - particular in the case
   * where the source info is missing (binary weave).
   */
  private String beautifyLocation(ISourceLocation isl) {
    StringBuffer nice = new StringBuffer();
    if (isl==null || isl.getSourceFile()==null || isl.getSourceFile().getName().indexOf("no debug info available")!=-1) {
      nice.append("no debug info available");
      } else {
        // can't use File.getName() as this fails when a Linux box encounters a path created on Windows and vice-versa
        int takeFrom = isl.getSourceFile().getPath().lastIndexOf('/');
        if (takeFrom == -1) {
          takeFrom = isl.getSourceFile().getPath().lastIndexOf('\\');
        }         
        nice.append(isl.getSourceFile().getPath().substring(takeFrom +1));
        if (isl.getLine()!=0) nice.append(":").append(isl.getLine());
    }
    return nice.toString();
  }
 
  /*
   * Report a message about the advice weave that has occurred.  Some messing about
   * to make it pretty !  This code is just asking for an NPE to occur ...
   */
  private void reportWeavingMessage(ShadowMunger munger) {
    Advice advice = (Advice)munger;
    AdviceKind aKind = advice.getKind();
    // Only report on interesting advice kinds ...
    if (aKind == null || advice.getConcreteAspect()==null) {
      // We suspect someone is programmatically driving the weaver
      // (e.g. IdWeaveTestCase in the weaver testcases)
      return;
    }
    if (!( aKind.equals(AdviceKind.Before) ||
           aKind.equals(AdviceKind.After) ||
           aKind.equals(AdviceKind.AfterReturning) ||
           aKind.equals(AdviceKind.AfterThrowing) ||
           aKind.equals(AdviceKind.Around) ||
           aKind.equals(AdviceKind.Softener))) return;
   
    String description = advice.getKind().toString();
    String advisedType = this.getEnclosingType().getName();
    String advisingType= advice.getConcreteAspect().getName();
    Message msg = null;
    if (advice.getKind().equals(AdviceKind.Softener)) {
      msg = WeaveMessage.constructWeavingMessage(
        WeaveMessage.WEAVEMESSAGE_SOFTENS,
          new String[]{advisedType,beautifyLocation(getSourceLocation()),
                 advisingType,beautifyLocation(munger.getSourceLocation())},
        advisedType,
        advisingType);
    } else {
      boolean runtimeTest = ((BcelAdvice)advice).hasDynamicTests();
      String joinPointDescription = this.toString();
        msg = WeaveMessage.constructWeavingMessage(WeaveMessage.WEAVEMESSAGE_ADVISES,
            new String[]{ joinPointDescription, advisedType, beautifyLocation(getSourceLocation()),
                    description,
                    advisingType,beautifyLocation(munger.getSourceLocation()),
                    (runtimeTest?" [with runtime test]":"")},
          advisedType,
          advisingType);
                 // Boolean.toString(runtimeTest)});
    }
    getIWorld().getMessageHandler().handleMessage(msg);
  }


  public IRelationship.Kind determineRelKind(ShadowMunger munger) {
    AdviceKind ak = ((Advice)munger).getKind();
    if (ak.getKey()==AdviceKind.Before.getKey())
        return IRelationship.Kind.ADVICE_BEFORE;
    else if (ak.getKey()==AdviceKind.After.getKey())
        return IRelationship.Kind.ADVICE_AFTER;
    else if (ak.getKey()==AdviceKind.AfterThrowing.getKey())
        return IRelationship.Kind.ADVICE_AFTERTHROWING;
    else if (ak.getKey()==AdviceKind.AfterReturning.getKey())
        return IRelationship.Kind.ADVICE_AFTERRETURNING;
    else if (ak.getKey()==AdviceKind.Around.getKey())
        return IRelationship.Kind.ADVICE_AROUND;
    else if (ak.getKey()==AdviceKind.CflowEntry.getKey() ||
                ak.getKey()==AdviceKind.CflowBelowEntry.getKey() ||
                ak.getKey()==AdviceKind.InterInitializer.getKey() ||
                ak.getKey()==AdviceKind.PerCflowEntry.getKey() ||
                ak.getKey()==AdviceKind.PerCflowBelowEntry.getKey() ||
                ak.getKey()==AdviceKind.PerThisEntry.getKey() ||
                ak.getKey()==AdviceKind.PerTargetEntry.getKey() ||
                ak.getKey()==AdviceKind.Softener.getKey() ||
                ak.getKey()==AdviceKind.PerTypeWithinEntry.getKey()) {
            //System.err.println("Dont want a message about this: "+ak);
            return null;
    }
    throw new RuntimeException("Shadow.determineRelKind: What the hell is it? "+ak);
  }

   /** Actually implement the (non-empty) mungers associated with this shadow */
  private void implementMungers() {
    World world = getIWorld();
    for (Iterator iter = mungers.iterator(); iter.hasNext();) {
      ShadowMunger munger = (ShadowMunger) iter.next();
      munger.implementOn(this);
     
      if (world.getCrossReferenceHandler() != null) {
        world.getCrossReferenceHandler().addCrossReference(
          munger.getSourceLocation(), // What is being applied
          this.getSourceLocation(),   // Where is it being applied
          determineRelKind(munger),   // What kind of advice?
          ((BcelAdvice)munger).hasDynamicTests() // Is a runtime test being stuffed in the code?
          );
      }
     
      // TAG: WeavingMessage
      if (!getIWorld().getMessageHandler().isIgnoring(IMessage.WEAVEINFO)) {
        reportWeavingMessage(munger);
      }     
     
      if (world.getModel() != null) {
        //System.err.println("munger: " + munger + " on " + this);
        AsmRelationshipProvider.getDefault().adviceMunger(world.getModel(), this, munger);
      }
    }
  }

  public String makeReflectiveFactoryString() {
    return null; //XXX
  }
 
  public abstract ISourceLocation getSourceLocation();

  // ---- utility
   
    public String toString() {
        return getKind() + "(" + getSignature() + ")"; // + getSourceLines();
    }
   
    public String toResolvedString(World world) {
      return getKind() + "(" + world.resolve(getSignature()).toGenericString() + ")";
    }
}
TOP

Related Classes of org.aspectj.weaver.Shadow$Kind

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.