Package org.aspectj.weaver

Source Code of org.aspectj.weaver.World

/* *******************************************************************
* Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
*               2005 Contributors
* 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
*     Adrian Colyer, Andy Clement, overhaul for generics
* ******************************************************************/

package org.aspectj.weaver;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;

import org.aspectj.asm.IHierarchy;
import org.aspectj.bridge.IMessageHandler;
import org.aspectj.bridge.ISourceLocation;
import org.aspectj.bridge.Message;
import org.aspectj.bridge.MessageUtil;
import org.aspectj.bridge.IMessage.Kind;
import org.aspectj.bridge.context.PinpointingMessageHandler;
import org.aspectj.weaver.UnresolvedType.TypeKind;
import org.aspectj.weaver.patterns.DeclarePrecedence;
import org.aspectj.weaver.patterns.PerClause;
import org.aspectj.weaver.patterns.Pointcut;

/**
* A World is a collection of known types and crosscutting members.
*/
public abstract class World implements Dump.INode {
  /** handler for any messages produced during resolution etc. */
  private IMessageHandler messageHandler = IMessageHandler.SYSTEM_ERR;
 
  /** handler for cross-reference information produced during the weaving process */
  private ICrossReferenceHandler xrefHandler = null;

  /** Currently 'active' scope in which to lookup (resolve) typevariable references */
  private TypeVariableDeclaringElement typeVariableLookupScope;
 
  /** The heart of the world, a map from type signatures to resolved types */
    protected TypeMap typeMap = new TypeMap(); // Signature to ResolvedType
   

    /** Calculator for working out aspect precedence */
    private AspectPrecedenceCalculator precedenceCalculator;
   
    /** All of the type and shadow mungers known to us */
    private CrosscuttingMembersSet crosscuttingMembersSet =
      new CrosscuttingMembersSet(this);
   
    /** Model holds ASM relationships */
    private IHierarchy model = null;
   
    /** for processing Xlint messages */
    private Lint lint = new Lint(this);
   
    /** XnoInline option setting passed down to weaver */
    private boolean XnoInline;
   
    /** XlazyTjp option setting passed down to weaver */
    private boolean XlazyTjp;

    /** XhasMember option setting passed down to weaver */
    private boolean XhasMember = false;
   
    /** Xpinpoint controls whether we put out developer info showing the source of messages */
    private boolean Xpinpoint = false;
   
    /** When behaving in a Java 5 way autoboxing is considered */
    private boolean behaveInJava5Way = false;
   
    /** The level of the aspectjrt.jar the code we generate needs to run on */
    private String targetAspectjRuntimeLevel = Constants.RUNTIME_LEVEL_DEFAULT;
   
    /**
     * A list of RuntimeExceptions containing full stack information for every
     * type we couldn't find.
     */
    private List dumpState_cantFindTypeExceptions = null;
 
    /**
     * Play God.
     * On the first day, God created the primitive types and put them in the type
     * map.
     */
    protected World() {
        super();
        Dump.registerNode(this.getClass(),this);
        typeMap.put("B", ResolvedType.BYTE);
        typeMap.put("S", ResolvedType.SHORT);
        typeMap.put("I", ResolvedType.INT);
        typeMap.put("J", ResolvedType.LONG);
        typeMap.put("F", ResolvedType.FLOAT);
        typeMap.put("D", ResolvedType.DOUBLE);
        typeMap.put("C", ResolvedType.CHAR);
        typeMap.put("Z", ResolvedType.BOOLEAN);
        typeMap.put("V", ResolvedType.VOID);
        precedenceCalculator = new AspectPrecedenceCalculator(this);
    }
   
    /**
     * Dump processing when a fatal error occurs
     */
    public void accept (Dump.IVisitor visitor) {
    visitor.visitString("Shadow mungers:");
    visitor.visitList(crosscuttingMembersSet.getShadowMungers());
    visitor.visitString("Type mungers:");
    visitor.visitList(crosscuttingMembersSet.getTypeMungers());
        visitor.visitString("Late Type mungers:");
        visitor.visitList(crosscuttingMembersSet.getLateTypeMungers());
        if (dumpState_cantFindTypeExceptions!=null) {
          visitor.visitString("Cant find type problems:");
          visitor.visitList(dumpState_cantFindTypeExceptions);
          dumpState_cantFindTypeExceptions = null;
        }
    }
   
   
    // =============================================================================
    // T Y P E   R E S O L U T I O N
    // =============================================================================

    /**
     * Resolve a type that we require to be present in the world
     */
    public ResolvedType resolve(UnresolvedType ty) {
      return resolve(ty, false);
    }

    /**
     * Attempt to resolve a type - the source location gives you some context in which
     * resolution is taking place.  In the case of an error where we can't find the
     * type - we can then at least report why (source location) we were trying to resolve it.
     */
    public ResolvedType resolve(UnresolvedType ty,ISourceLocation isl) {
        ResolvedType ret = resolve(ty,true);
        if (ResolvedType.isMissing(ty)) {
            //IMessage msg = null;
            getLint().cantFindType.signal(WeaverMessages.format(WeaverMessages.CANT_FIND_TYPE,ty.getName()),isl);
            //if (isl!=null) {
              //msg = MessageUtil.error(WeaverMessages.format(WeaverMessages.CANT_FIND_TYPE,ty.getName()),isl);
            //} else {
              //msg = MessageUtil.error(WeaverMessages.format(WeaverMessages.CANT_FIND_TYPE,ty.getName()));
            //}
            //messageHandler.handleMessage(msg);
        }
        return ret;
    }
   
    /**
     * Convenience method for resolving an array of unresolved types
     * in one hit. Useful for e.g. resolving type parameters in signatures.
     */
    public ResolvedType[] resolve(UnresolvedType[] types) {
      if (types == null) return new ResolvedType[0];
     
        ResolvedType[] ret = new ResolvedType[types.length];
        for (int i=0; i<types.length; i++) {
            ret[i] = resolve(types[i]);
        }
        return ret;
    }

    /**
     * Resolve a type. This the hub of type resolution. The resolved type is added
     * to the type map by signature.
     */
    public ResolvedType resolve(UnresolvedType ty, boolean allowMissing) {
     
      // special resolution processing for already resolved types.
      if (ty instanceof ResolvedType) {
        ResolvedType rty = (ResolvedType) ty;
        rty = resolve(rty);
        return rty;
      }

      // dispatch back to the type variable reference to resolve its constituent parts
      // don't do this for other unresolved types otherwise you'll end up in a loop
      if (ty.isTypeVariableReference()) {
        return ty.resolve(this);
      }
     
      // if we've already got a resolved type for the signature, just return it
      // after updating the world
        String signature = ty.getSignature();
        ResolvedType ret = typeMap.get(signature);
        if (ret != null) {
          ret.world = this// Set the world for the RTX
          return ret;
        } else if ( signature.equals("?") || signature.equals("*")) {
        // might be a problem here, not sure '?' should make it to here as a signature, the
        // proper signature for wildcard '?' is '*'
          // fault in generic wildcard, can't be done earlier because of init issues
          ResolvedType something = new BoundedReferenceType("?",this);
          typeMap.put("?",something);
          return something;
        }
       
        // no existing resolved type, create one
        if (ty.isArray()) {
          ResolvedType componentType = resolve(ty.getComponentType(),allowMissing);
          //String brackets = signature.substring(0,signature.lastIndexOf("[")+1);
            ret = new ResolvedType.Array(signature, "["+componentType.getErasureSignature(),
                                     this,
                                     componentType);
        } else {
            ret = resolveToReferenceType(ty);
            if (!allowMissing && ret.isMissing()) {
                ret = handleRequiredMissingTypeDuringResolution(ty);
            }
        }       
 
    // Pulling in the type may have already put the right entry in the map
    if (typeMap.get(signature)==null && !ret.isMissing()) {
          typeMap.put(signature, ret);
    }
        return ret;
    }

    /**
     * We tried to resolve a type and couldn't find it...
     */
  private ResolvedType handleRequiredMissingTypeDuringResolution(UnresolvedType ty) {
    // defer the message until someone asks a question of the type that we can't answer
    // just from the signature.
//    MessageUtil.error(messageHandler,
//        WeaverMessages.format(WeaverMessages.CANT_FIND_TYPE,ty.getName()));
    if (dumpState_cantFindTypeExceptions==null) {
      dumpState_cantFindTypeExceptions = new ArrayList();  
    }
    dumpState_cantFindTypeExceptions.add(new RuntimeException("Can't find type "+ty.getName()));
    return new MissingResolvedTypeWithKnownSignature(ty.getSignature(),this);
  }
   
    /**
     * Some TypeFactory operations create resolved types directly, but these won't be
     * in the typeMap - this resolution process puts them there. Resolved types are
     * also told their world which is needed for the special autoboxing resolved types.
     */
    public ResolvedType resolve(ResolvedType ty) {
      if (ty.isTypeVariableReference()) return ty; // until type variables have proper sigs...
      ResolvedType resolved = typeMap.get(ty.getSignature());
      if (resolved == null) {
        typeMap.put(ty.getSignature(), ty);
        resolved = ty;
      }
      resolved.world = this;
      return resolved;
    }
   
    /**
     * Convenience method for finding a type by name and resolving it in one step.
     */
    public ResolvedType resolve(String name) {
      return resolve(UnresolvedType.forName(name));
    }
   
    public ResolvedType resolve(String name,boolean allowMissing) {
      return resolve(UnresolvedType.forName(name),allowMissing);
    }
   
  private ResolvedType currentlyResolvingBaseType;

  /**
   * Resolve to a ReferenceType - simple, raw, parameterized, or generic.
     * Raw, parameterized, and generic versions of a type share a delegate.
     */
    private final ResolvedType resolveToReferenceType(UnresolvedType ty) {
    if (ty.isParameterizedType()) {
      // ======= parameterized types ================
      ReferenceType genericType = (ReferenceType)resolveGenericTypeFor(ty,false);
      currentlyResolvingBaseType = genericType;
      ReferenceType parameterizedType =
        TypeFactory.createParameterizedType(genericType, ty.typeParameters, this);
      currentlyResolvingBaseType = null;
      return parameterizedType;
     
    } else if (ty.isGenericType()) {
      // ======= generic types ======================
      ReferenceType genericType = (ReferenceType)resolveGenericTypeFor(ty,false);
      return genericType;
     
    } else if (ty.isGenericWildcard()) {
      // ======= generic wildcard types =============
      return resolveGenericWildcardFor(ty);
      } else {
      // ======= simple and raw types ===============
      String erasedSignature = ty.getErasureSignature();
        ReferenceType simpleOrRawType = new ReferenceType(erasedSignature, this);
        ReferenceTypeDelegate delegate = resolveDelegate(simpleOrRawType);
        // 117854
//        if (delegate == null) return ResolvedType.MISSING;
        if (delegate == null) return new MissingResolvedTypeWithKnownSignature(ty.getSignature(),erasedSignature,this);//ResolvedType.MISSING;
       
        if (delegate.isGeneric() && behaveInJava5Way) {
          // ======== raw type ===========
          simpleOrRawType.typeKind = TypeKind.RAW;
            ReferenceType genericType = makeGenericTypeFrom(delegate,simpleOrRawType);
          // name =  ReferenceType.fromTypeX(UnresolvedType.forRawTypeNames(ty.getName()),this);
          simpleOrRawType.setDelegate(delegate);
          genericType.setDelegate(delegate);
          simpleOrRawType.setGenericType(genericType);
          return simpleOrRawType;
         
        } else {
          // ======== simple type =========
          simpleOrRawType.setDelegate(delegate);
          return simpleOrRawType;
        }
    }
    }

    /**
     * Attempt to resolve a type that should be a generic type. 
     */
    public ResolvedType resolveGenericTypeFor(UnresolvedType anUnresolvedType, boolean allowMissing) {
        // Look up the raw type by signature
      String rawSignature = anUnresolvedType.getRawType().getSignature();
      ResolvedType rawType = (ResolvedType) typeMap.get(rawSignature);
      if (rawType==null) {
        rawType = resolve(UnresolvedType.forSignature(rawSignature),false);
          typeMap.put(rawSignature,rawType);
      }
     
      // Does the raw type know its generic form? (It will if we created the
      // raw type from a source type, it won't if its been created just through
      // being referenced, e.g. java.util.List
      ResolvedType genericType = rawType.getGenericType();
     
      // There is a special case to consider here (testGenericsBang_pr95993 highlights it)
      // You may have an unresolvedType for a parameterized type but it
      // is backed by a simple type rather than a generic type.  This occurs for
      // inner types of generic types that inherit their enclosing types
      // type variables.
      if (rawType.isSimpleType() && (anUnresolvedType.typeParameters==null || anUnresolvedType.typeParameters.length==0)) {
        rawType.world = this;
        return rawType;
      }
     
      if (genericType != null) {
        genericType.world = this;
        return genericType;
      } else {
        // Fault in the generic that underpins the raw type ;)
        ReferenceTypeDelegate delegate = resolveDelegate((ReferenceType)rawType);
        ReferenceType genericRefType = makeGenericTypeFrom(delegate,((ReferenceType)rawType));
        ((ReferenceType)rawType).setGenericType(genericRefType);
        genericRefType.setDelegate(delegate);
        ((ReferenceType)rawType).setDelegate(delegate);
        return genericRefType;
      }
    }
   
    private ReferenceType makeGenericTypeFrom(ReferenceTypeDelegate delegate, ReferenceType rawType) {
      String genericSig = delegate.getDeclaredGenericSignature();
      if (genericSig != null) {
        return new ReferenceType(
            UnresolvedType.forGenericTypeSignature(rawType.getSignature(),delegate.getDeclaredGenericSignature()),this);
      } else {
        return new ReferenceType(
            UnresolvedType.forGenericTypeVariables(rawType.getSignature(), delegate.getTypeVariables()),this);
      }
    }

    /**
     * Go from an unresolved generic wildcard (represented by UnresolvedType) to a resolved version (BoundedReferenceType).
     */
    private ReferenceType resolveGenericWildcardFor(UnresolvedType aType) {
      BoundedReferenceType ret = null;
      // FIXME asc doesnt take account of additional interface bounds (e.g. ? super R & Serializable - can you do that?)
      if (aType.isExtends()) {
        ReferenceType upperBound = (ReferenceType)resolve(aType.getUpperBound());
        ret = new BoundedReferenceType(upperBound,true,this);
         } else if (aType.isSuper()) {
        ReferenceType lowerBound = (ReferenceType) resolve(aType.getLowerBound());
        ret = new BoundedReferenceType(lowerBound,false,this);
      } else {
        // must be ? on its own!
      }
      return ret;
    }
   
    /**
     * Find the ReferenceTypeDelegate behind this reference type so that it can
     * fulfill its contract.
     */
    protected abstract ReferenceTypeDelegate resolveDelegate(ReferenceType ty);
   
    /**
     * Special resolution for "core" types like OBJECT. These are resolved just like
     * any other type, but if they are not found it is more serious and we issue an
     * error message immediately.
     */
    public ResolvedType getCoreType(UnresolvedType tx) {
      ResolvedType coreTy = resolve(tx,true);
      if (coreTy.isMissing()) {
         MessageUtil.error(messageHandler,
              WeaverMessages.format(WeaverMessages.CANT_FIND_CORE_TYPE,tx.getName()));
      }
      return coreTy;
    }

    /**
     * Lookup a type by signature, if not found then build one and put it in the
     * map.
     */
  public ReferenceType lookupOrCreateName(UnresolvedType ty) {
    String signature = ty.getSignature();
        ReferenceType ret = lookupBySignature(signature);
        if (ret == null) {
          ret = ReferenceType.fromTypeX(ty, this);
          typeMap.put(signature, ret);
        }
    return ret;
  }

  /**
   * Lookup a reference type in the world by its signature. Returns
   * null if not found.
   */
  public ReferenceType lookupBySignature(String signature) {
    return (ReferenceType) typeMap.get(signature);
  }
 

    // =============================================================================
    // T Y P E   R E S O L U T I O N  -- E N D
    // =============================================================================

    /**
     * Member resolution is achieved by resolving the declaring type and then
     * looking up the member in the resolved declaring type.
     */
    public ResolvedMember resolve(Member member) {
        ResolvedType declaring = member.getDeclaringType().resolve(this);
        if (declaring.isRawType()) declaring = declaring.getGenericType();
        ResolvedMember ret;
        if (member.getKind() == Member.FIELD) {
            ret = declaring.lookupField(member);
        } else {
            ret = declaring.lookupMethod(member);
        }
       
        if (ret != null) return ret;
       
        return declaring.lookupSyntheticMember(member);  
    }
   
    // Methods for creating various cross-cutting members...
    // ===========================================================
   
    /**
     * Create an advice shadow munger from the given advice attribute
     */
    public abstract Advice createAdviceMunger(
      AjAttribute.AdviceAttribute attribute,
      Pointcut pointcut,
        Member signature);
       
    /**
     * Create an advice shadow munger for the given advice kind
     */
    public final Advice createAdviceMunger(
       AdviceKind kind,
        Pointcut p,
        Member signature,
        int extraParameterFlags,
        IHasSourceLocation loc)
    {
      AjAttribute.AdviceAttribute attribute =
        new AjAttribute.AdviceAttribute(kind, p, extraParameterFlags, loc.getStart(), loc.getEnd(), loc.getSourceContext());
    return createAdviceMunger(attribute, p, signature);
    }
       
  public abstract ConcreteTypeMunger makeCflowStackFieldAdder(ResolvedMember cflowField);
 
  public abstract ConcreteTypeMunger makeCflowCounterFieldAdder(ResolvedMember cflowField);

    /**
     * Register a munger for perclause @AJ aspect so that we add aspectOf(..) to them as needed
     * @see org.aspectj.weaver.bcel.BcelWorld#makePerClauseAspect(ResolvedType, org.aspectj.weaver.patterns.PerClause.Kind)
     */
    public abstract ConcreteTypeMunger makePerClauseAspect(ResolvedType aspect, PerClause.Kind kind);

    public abstract ConcreteTypeMunger concreteTypeMunger(ResolvedTypeMunger munger, ResolvedType aspectType);

  /**
   * Same signature as org.aspectj.util.PartialOrder.PartialComparable.compareTo
   */
  public int compareByPrecedence(ResolvedType aspect1, ResolvedType aspect2) {
    return precedenceCalculator.compareByPrecedence(aspect1, aspect2);
  }
  public Integer getPrecedenceIfAny(ResolvedType aspect1, ResolvedType aspect2) {
    return precedenceCalculator.getPrecedenceIfAny(aspect1, aspect2);
  }
   
  /**
   * compares by precedence with the additional rule that a super-aspect is
   * sorted before its sub-aspects
   */
  public int compareByPrecedenceAndHierarchy(ResolvedType aspect1, ResolvedType aspect2) {
    return precedenceCalculator.compareByPrecedenceAndHierarchy(aspect1, aspect2);
  }

    // simple property getter and setters
    // ===========================================================
   
  /**
   * Nobody should hold onto a copy of this message handler, or setMessageHandler won't
   * work right.
   */
  public IMessageHandler getMessageHandler() {
    return messageHandler;
  }

  public void setMessageHandler(IMessageHandler messageHandler) {
    if (this.isInPinpointMode()) {
      this.messageHandler = new PinpointingMessageHandler(messageHandler);
    } else {
      this.messageHandler = messageHandler;     
    }
  }

  /**
   * convenenience method for creating and issuing messages via the message handler -
   * if you supply two locations you will get two messages.
   */
  public void showMessage(
      Kind kind,
      String message,
      ISourceLocation loc1,
      ISourceLocation loc2)
    {
      if (loc1 != null) {
        messageHandler.handleMessage(new Message(message, kind, null, loc1));
        if (loc2 != null) {
          messageHandler.handleMessage(new Message(message, kind, null, loc2));
        }
      } else {
        messageHandler.handleMessage(new Message(message, kind, null, loc2));
      }
    }


  public void setCrossReferenceHandler(ICrossReferenceHandler xrefHandler) {
    this.xrefHandler = xrefHandler;
  }

    /**
     * Get the cross-reference handler for the world, may be null.
     */
    public ICrossReferenceHandler getCrossReferenceHandler() {
      return this.xrefHandler;
    }
   
    public void setTypeVariableLookupScope(TypeVariableDeclaringElement scope) {
      this.typeVariableLookupScope = scope;
    }

    public TypeVariableDeclaringElement getTypeVariableLookupScope() {
      return typeVariableLookupScope;
    }


  public List getDeclareParents() {
    return crosscuttingMembersSet.getDeclareParents();
  }
 
  public List getDeclareAnnotationOnTypes() {
    return crosscuttingMembersSet.getDeclareAnnotationOnTypes();
  }
 
  public List getDeclareAnnotationOnFields() {
    return crosscuttingMembersSet.getDeclareAnnotationOnFields();
  }
 
  public List getDeclareAnnotationOnMethods() {
    return crosscuttingMembersSet.getDeclareAnnotationOnMethods();
  }

  public List getDeclareSoft() {
    return crosscuttingMembersSet.getDeclareSofts();
  }

  public CrosscuttingMembersSet getCrosscuttingMembersSet() {
    return crosscuttingMembersSet;
  }

  public IHierarchy getModel() {
    return model;
  }

  public void setModel(IHierarchy model) {
    this.model = model;
  }

  public Lint getLint() {
    return lint;
  }

  public void setLint(Lint lint) {
    this.lint = lint;
  }

  public boolean isXnoInline() {
    return XnoInline;
  }

  public void setXnoInline(boolean xnoInline) {
    XnoInline = xnoInline;
  }
 
  public boolean isXlazyTjp() {
    return XlazyTjp;
  }

  public void setXlazyTjp(boolean b) {
    XlazyTjp = b;
  }
 
  public boolean isHasMemberSupportEnabled() {
    return XhasMember;
  }
 
  public void setXHasMemberSupportEnabled(boolean b) {
    XhasMember = b;
  }

  public boolean isInPinpointMode() {
    return Xpinpoint;
  }
 
  public void setPinpointMode(boolean b) {
    this.Xpinpoint = b;
  }
 
  public void setBehaveInJava5Way(boolean b) {
      behaveInJava5Way = b;
    }
 
  public boolean isInJava5Mode() {
    return behaveInJava5Way;
  }
 
  public void setTargetAspectjRuntimeLevel(String s) {
    targetAspectjRuntimeLevel = s;
  }
 
  public String getTargetAspectjRuntimeLevel() {
    return targetAspectjRuntimeLevel;
  }
 
  public boolean isTargettingAspectJRuntime12() {
    boolean b = false; // pr116679
    if (!isInJava5Mode()) b=true;
    else b = getTargetAspectjRuntimeLevel().equals(org.aspectj.weaver.Constants.RUNTIME_LEVEL_12);
    //System.err.println("Asked if targetting runtime 1.2 , returning: "+b);
    return b;
  }
 
  /*
   *  Map of types in the world, with soft links to expendable ones.
   *  An expendable type is a reference type that is not exposed to the weaver (ie
   *  just pulled in for type resolution purposes).
   */
  protected static class TypeMap {
    /** Map of types that never get thrown away */
    private Map tMap = new HashMap();
    /** Map of types that may be ejected from the cache if we need space */
    private Map expendableMap = new WeakHashMap();
   
    private static final boolean debug = false;
    /**
     * Add a new type into the map, the key is the type signature.
     * Some types do *not* go in the map, these are ones involving
     * *member* type variables.  The reason is that when all you have is the
     * signature which gives you a type variable name, you cannot
     * guarantee you are using the type variable in the same way
     * as someone previously working with a similarly
     * named type variable.  So, these do not go into the map:
     * - TypeVariableReferenceType.
     * - ParameterizedType where a member type variable is involved.
     * - BoundedReferenceType when one of the bounds is a type variable.
     *
     * definition: "member type variables" - a tvar declared on a generic
     * method/ctor as opposed to those you see declared on a generic type.
     */
    public ResolvedType put(String key, ResolvedType type) {
      if (key.indexOf("String")!=-1) {
        int stop=1;
      }
      if (type.isParameterizedType() && type.isParameterizedWithAMemberTypeVariable()) {
        if (debug)
          System.err.println("Not putting a parameterized type that utilises member declared type variables into the typemap: key="+key+" type="+type);
        return type;
      }
      if (type.isTypeVariableReference()) {
        if (debug)
          System.err.println("Not putting a type variable reference type into the typemap: key="+key+" type="+type);
        return type;
      }
      // this test should be improved - only avoid putting them in if one of the
      // bounds is a member type variable
      if (type instanceof BoundedReferenceType) {
        if (debug)
          System.err.println("Not putting a bounded reference type into the typemap: key="+key+" type="+type);
        return type;
      }
      if (type instanceof MissingResolvedTypeWithKnownSignature) {
        if (debug)
          System.err.println("Not putting a missing type into the typemap: key="+key+" type="+type);
        return type;
      }
           
      if (isExpendable(type))  {
        return (ResolvedType) expendableMap.put(key,type);
      } else {
        return (ResolvedType) tMap.put(key,type);
      }
    }
   
    /** Lookup a type by its signature */
    public ResolvedType get(String key) {
      ResolvedType ret = (ResolvedType) tMap.get(key);
      if (ret == null) ret = (ResolvedType) expendableMap.get(key);
      return ret;
    }
   
    /** Remove a type from the map */
    public ResolvedType remove(String key) {
      ResolvedType ret = (ResolvedType) tMap.remove(key);
      if (ret == null) ret = (ResolvedType) expendableMap.remove(key);
      return ret;
    }
   
    /** Reference types we don't intend to weave may be ejected from
     * the cache if we need the space.
     */
    private boolean isExpendable(ResolvedType type) {
      return (
            (type != null) &&
            (!type.isExposedToWeaver()) &&
            (!type.isPrimitiveType())
          );
    }
   
      public String toString() {
        StringBuffer sb = new StringBuffer();
        sb.append("types:\n");
        sb.append(dumpthem(tMap));
        sb.append("expendables:\n");
        sb.append(dumpthem(expendableMap));
        return sb.toString();
      }
     
      private String dumpthem(Map m) {
        StringBuffer sb = new StringBuffer();
        Set keys = m.keySet();
        for (Iterator iter = keys.iterator(); iter.hasNext();) {
        String k = (String) iter.next();
        sb.append(k+"="+m.get(k)).append("\n");
      }
        return sb.toString();
      }
  } 

  /**
   * This class is used to compute and store precedence relationships between
   * aspects.
   */
  private static class AspectPrecedenceCalculator {
   
    private World world;
    private Map cachedResults;
   
    public AspectPrecedenceCalculator(World forSomeWorld) {
      this.world = forSomeWorld;
      this.cachedResults = new HashMap();
    }
   
    /**
     * Ask every declare precedence in the world to order the two aspects.
     * If more than one declare precedence gives an ordering, and the orderings
     * conflict, then that's an error.
     */
    public int compareByPrecedence(ResolvedType firstAspect, ResolvedType secondAspect) {
      PrecedenceCacheKey key = new PrecedenceCacheKey(firstAspect,secondAspect);
      if (cachedResults.containsKey(key)) {
        return ((Integer) cachedResults.get(key)).intValue();
      } else {
        int order = 0;
        DeclarePrecedence orderer = null; // Records the declare precedence statement that gives the first ordering
        for (Iterator i = world.getCrosscuttingMembersSet().getDeclareDominates().iterator(); i.hasNext(); ) {
          DeclarePrecedence d = (DeclarePrecedence)i.next();
          int thisOrder = d.compare(firstAspect, secondAspect);
          if (thisOrder != 0) {
            if (orderer==null) orderer = d;
            if (order != 0 && order != thisOrder) {
              ISourceLocation[] isls = new ISourceLocation[2];
              isls[0]=orderer.getSourceLocation();
              isls[1]=d.getSourceLocation();
              Message m =
                new Message("conflicting declare precedence orderings for aspects: "+
                            firstAspect.getName()+" and "+secondAspect.getName(),null,true,isls);
              world.getMessageHandler().handleMessage(m);
            } else {
              order = thisOrder;
            }
          }
        }   
        cachedResults.put(key, new Integer(order));
        return order;
      }
    }
   
    public Integer getPrecedenceIfAny(ResolvedType aspect1,ResolvedType aspect2) {
      return (Integer)cachedResults.get(new PrecedenceCacheKey(aspect1,aspect2));
    }
   
    public int compareByPrecedenceAndHierarchy(ResolvedType firstAspect, ResolvedType secondAspect) {
      if (firstAspect.equals(secondAspect)) return 0;
     
      int ret = compareByPrecedence(firstAspect, secondAspect);
      if (ret != 0) return ret;
     
      if (firstAspect.isAssignableFrom(secondAspect)) return -1;
      else if (secondAspect.isAssignableFrom(firstAspect)) return +1;

      return 0;
    }
   
   
    private static class PrecedenceCacheKey {
      public ResolvedType aspect1;
      public ResolvedType aspect2;
     
      public PrecedenceCacheKey(ResolvedType a1, ResolvedType a2) {
        this.aspect1 = a1;
        this.aspect2 = a2;
      }
     
      public boolean equals(Object obj) {
        if (!(obj instanceof PrecedenceCacheKey)) return false;
        PrecedenceCacheKey other = (PrecedenceCacheKey) obj;
        return (aspect1 == other.aspect1 && aspect2 == other.aspect2);
      }
     
      public int hashCode() {
        return aspect1.hashCode() + aspect2.hashCode();
      }
    }
  }

  public void validateType(UnresolvedType type) { }

    // --- with java5 we can get into a recursive mess if we aren't careful when resolving types (*cough* java.lang.Enum) ---
 
    // --- this first map is for java15 delegates which may try and recursively access the same type variables.
  // --- I would rather stash this against a reference type - but we don't guarantee referencetypes are unique for
  //     so we can't :(
  private Map workInProgress1 = new HashMap();
  public TypeVariable[] getTypeVariablesCurrentlyBeingProcessed(Class baseClass) {
    return (TypeVariable[])workInProgress1.get(baseClass);
  }
  public void recordTypeVariablesCurrentlyBeingProcessed(Class baseClass, TypeVariable[] typeVariables) {
    workInProgress1.put(baseClass,typeVariables);
  }
  public void forgetTypeVariablesCurrentlyBeingProcessed(Class baseClass) {
    workInProgress1.remove(baseClass);
  }

    // ---
 
}
TOP

Related Classes of org.aspectj.weaver.World

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.