Package org.aspectj.ajdt.internal.compiler.lookup

Source Code of org.aspectj.ajdt.internal.compiler.lookup.AjLookupEnvironment

/* *******************************************************************
* 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.ajdt.internal.compiler.lookup;

import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.aspectj.ajdt.internal.compiler.CommonPrinter;
import org.aspectj.ajdt.internal.compiler.ast.AspectDeclaration;
import org.aspectj.ajdt.internal.compiler.ast.PointcutDeclaration;
import org.aspectj.asm.AsmManager;
import org.aspectj.bridge.IMessage;
import org.aspectj.bridge.WeaveMessage;
import org.aspectj.bridge.context.CompilationAndWeavingContext;
import org.aspectj.bridge.context.ContextToken;
import org.aspectj.org.eclipse.jdt.core.compiler.CharOperation;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Annotation;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.NormalAnnotation;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.SingleTypeReference;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeReference;
import org.aspectj.org.eclipse.jdt.internal.compiler.env.AccessRestriction;
import org.aspectj.org.eclipse.jdt.internal.compiler.env.IBinaryType;
import org.aspectj.org.eclipse.jdt.internal.compiler.env.INameEnvironment;
import org.aspectj.org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.aspectj.org.eclipse.jdt.internal.compiler.impl.ITypeRequestor;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.BinaryTypeBinding;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ClassScope;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.LocalTypeBinding;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.PackageBinding;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TagBits;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
import org.aspectj.org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
import org.aspectj.weaver.AnnotationAJ;
import org.aspectj.weaver.ConcreteTypeMunger;
import org.aspectj.weaver.ReferenceType;
import org.aspectj.weaver.ReferenceTypeDelegate;
import org.aspectj.weaver.ResolvedMember;
import org.aspectj.weaver.ResolvedType;
import org.aspectj.weaver.ResolvedTypeMunger;
import org.aspectj.weaver.UnresolvedType;
import org.aspectj.weaver.WeaverMessages;
import org.aspectj.weaver.WeaverStateInfo;
import org.aspectj.weaver.World;
import org.aspectj.weaver.bcel.BcelAnnotation;
import org.aspectj.weaver.bcel.BcelObjectType;
import org.aspectj.weaver.bcel.FakeAnnotation;
import org.aspectj.weaver.bcel.LazyClassGen;
import org.aspectj.weaver.patterns.DeclareAnnotation;
import org.aspectj.weaver.patterns.DeclareParents;

/**
* Overrides the default eclipse LookupEnvironment for two purposes.
*
* 1. To provide some additional phases to <code>completeTypeBindings</code> that weave declare parents and inter-type declarations
* at the correct time.
*
* 2. To intercept the loading of new binary types to ensure the they will have declare parents and inter-type declarations woven
* when appropriate.
*
* @author Jim Hugunin
*/
public class AjLookupEnvironment extends LookupEnvironment implements AnonymousClassCreationListener {
  public EclipseFactory factory = null;

  // private boolean builtInterTypesAndPerClauses = false;
  private final List<SourceTypeBinding> pendingTypesToWeave = new ArrayList<SourceTypeBinding>();

  // Q: What are dangerousInterfaces?
  // A: An interface is considered dangerous if an ITD has been made upon it
  // and that ITD
  // requires the top most implementors of the interface to be woven *and yet*
  // the aspect
  // responsible for the ITD is not in the 'world'.
  // Q: Err, how can that happen?
  // A: When a type is on the inpath, it is 'processed' when completing type
  // bindings. At this
  // point we look at any type mungers it was affected by previously (stored
  // in the weaver
  // state info attribute). Effectively we are working with a type munger and
  // yet may not have its
  // originating aspect in the world. This is a problem if, for example, the
  // aspect supplied
  // a 'body' for a method targetting an interface - since the top most
  // implementors should
  // be woven by the munger from the aspect. When this happens we store the
  // interface name here
  // in the map - if we later process a type that is the topMostImplementor of
  // a dangerous
  // interface then we put out an error message.

  /**
   * interfaces targetted by ITDs that have to be implemented by accessing the topMostImplementor of the interface, yet the aspect
   * where the ITD originated is not in the world
   */
  private final Map dangerousInterfaces = new HashMap();

  public AjLookupEnvironment(ITypeRequestor typeRequestor, CompilerOptions options, ProblemReporter problemReporter,
      INameEnvironment nameEnvironment) {
    super(typeRequestor, options, problemReporter, nameEnvironment);
  }

  // ??? duplicates some of super's code
  public void completeTypeBindings() {
    AsmManager.setCompletingTypeBindings(true);
    ContextToken completeTypeBindingsToken = CompilationAndWeavingContext.enteringPhase(
        CompilationAndWeavingContext.COMPLETING_TYPE_BINDINGS, "");
    // builtInterTypesAndPerClauses = false;
    // pendingTypesToWeave = new ArrayList();
    stepCompleted = BUILD_TYPE_HIERARCHY;

    for (int i = lastCompletedUnitIndex + 1; i <= lastUnitIndex; i++) {
      ContextToken tok = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.CHECK_AND_SET_IMPORTS,
          units[i].compilationResult.fileName);
      units[i].scope.checkAndSetImports();
      CompilationAndWeavingContext.leavingPhase(tok);
    }
    stepCompleted = CHECK_AND_SET_IMPORTS;

    for (int i = lastCompletedUnitIndex + 1; i <= lastUnitIndex; i++) {
      ContextToken tok = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.CONNECTING_TYPE_HIERARCHY,
          units[i].compilationResult.fileName);
      units[i].scope.connectTypeHierarchy();
      CompilationAndWeavingContext.leavingPhase(tok);
    }
    stepCompleted = CONNECT_TYPE_HIERARCHY;

    for (int i = lastCompletedUnitIndex + 1; i <= lastUnitIndex; i++) {
      ContextToken tok = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.BUILDING_FIELDS_AND_METHODS,
          units[i].compilationResult.fileName);
      // units[i].scope.checkParameterizedTypes(); do this check a little
      // later, after ITDs applied to stbs
      units[i].scope.buildFieldsAndMethods();
      CompilationAndWeavingContext.leavingPhase(tok);
    }

    // would like to gather up all TypeDeclarations at this point and put
    // them in the factory
    for (int i = lastCompletedUnitIndex + 1; i <= lastUnitIndex; i++) {
      SourceTypeBinding[] b = units[i].scope.topLevelTypes;
      for (int j = 0; j < b.length; j++) {
        factory.addSourceTypeBinding(b[j], units[i]);
      }
    }

    // We won't find out about anonymous types until later though, so
    // register to be
    // told about them when they turn up.
    AnonymousClassPublisher.aspectOf().setAnonymousClassCreationListener(this);

    // need to build inter-type declarations for all AspectDeclarations at
    // this point
    // this MUST be done in order from super-types to subtypes
    List<SourceTypeBinding> typesToProcess = new ArrayList<SourceTypeBinding>();
    List<SourceTypeBinding> aspectsToProcess = new ArrayList<SourceTypeBinding>();
    for (int i = lastCompletedUnitIndex + 1; i <= lastUnitIndex; i++) {
      CompilationUnitScope cus = units[i].scope;
      SourceTypeBinding[] stbs = cus.topLevelTypes;
      for (int j = 0; j < stbs.length; j++) {
        SourceTypeBinding stb = stbs[j];
        typesToProcess.add(stb);
        TypeDeclaration typeDeclaration = stb.scope.referenceContext;
        if (typeDeclaration instanceof AspectDeclaration) {
          aspectsToProcess.add(stb);
        }
      }
    }
    factory.getWorld().getCrosscuttingMembersSet().reset();

    // Need to do these before the other ITDs
    for (SourceTypeBinding aspectToProcess : aspectsToProcess) {
      processInterTypeMemberTypes(aspectToProcess.scope);
    }

    while (typesToProcess.size() > 0) {
      // removes types from the list as they are processed...
      collectAllITDsAndDeclares(typesToProcess.get(0), typesToProcess);
    }

    factory.finishTypeMungers();

    // now do weaving
    List<ConcreteTypeMunger> typeMungers = factory.getTypeMungers();

    List<DeclareParents> declareParents = factory.getDeclareParents();
    List<DeclareAnnotation> declareAnnotationOnTypes = factory.getDeclareAnnotationOnTypes();

    doPendingWeaves();

    // We now have some list of types to process, and we are about to apply
    // the type mungers.
    // There can be situations where the order of types passed to the
    // compiler causes the
    // output from the compiler to vary - THIS IS BAD. For example, if we
    // have class A
    // and class B extends A. Also, an aspect that 'declare parents: A+
    // implements Serializable'
    // then depending on whether we see A first, we may or may not make B
    // serializable.

    // The fix is to process them in the right order, ensuring that for a
    // type we process its
    // supertypes and superinterfaces first. This algorithm may have
    // problems with:
    // - partial hierarchies (e.g. suppose types A,B,C are in a hierarchy
    // and A and C are to be woven but not B)
    // - weaving that brings new types in for processing (see
    // pendingTypesToWeave.add() calls) after we thought
    // we had the full list.
    //
    // but these aren't common cases (he bravely said...)
    boolean typeProcessingOrderIsImportant = declareParents.size() > 0 || declareAnnotationOnTypes.size() > 0; // DECAT

    if (typeProcessingOrderIsImportant) {
      typesToProcess = new ArrayList<SourceTypeBinding>();
      for (int i = lastCompletedUnitIndex + 1; i <= lastUnitIndex; i++) {
        CompilationUnitScope cus = units[i].scope;
        SourceTypeBinding[] stbs = cus.topLevelTypes;
        for (int j = 0; j < stbs.length; j++) {
          SourceTypeBinding stb = stbs[j];
          typesToProcess.add(stb);
        }
      }

      List<SourceTypeBinding> stb2 = new ArrayList<SourceTypeBinding>();
      stb2.addAll(typesToProcess);

      while (typesToProcess.size() > 0) {
        // A side effect of weaveIntertypes() is that the processed type is removed from the collection
        weaveIntertypes(typesToProcess, typesToProcess.get(0), typeMungers, declareParents, declareAnnotationOnTypes, 1);
      }

      while (stb2.size() > 0) {
        // A side effect of weaveIntertypes() is that the processed type is removed from the collection
        weaveIntertypes(stb2, stb2.get(0), typeMungers, declareParents, declareAnnotationOnTypes, 2);
      }

    } else {
      // Order isn't important
      for (int i = lastCompletedUnitIndex + 1; i <= lastUnitIndex; i++) {
        weaveInterTypeDeclarations(units[i].scope, typeMungers, declareParents, declareAnnotationOnTypes);
      }
    }

    for (int i = lastCompletedUnitIndex + 1; i <= lastUnitIndex; i++) {
      units[i].scope.checkParameterizedTypes();
    }

    for (int i = lastCompletedUnitIndex + 1; i <= lastUnitIndex; i++) {
      SourceTypeBinding[] b = units[i].scope.topLevelTypes;
      for (int j = 0; j < b.length; j++) {
        ContextToken tok = CompilationAndWeavingContext.enteringPhase(
            CompilationAndWeavingContext.RESOLVING_POINTCUT_DECLARATIONS, b[j].sourceName);
        resolvePointcutDeclarations(b[j].scope);
        CompilationAndWeavingContext.leavingPhase(tok);
      }
    }

    for (int i = lastCompletedUnitIndex + 1; i <= lastUnitIndex; i++) {
      SourceTypeBinding[] b = units[i].scope.topLevelTypes;
      for (int j = 0; j < b.length; j++) {
        ContextToken tok = CompilationAndWeavingContext.enteringPhase(
            CompilationAndWeavingContext.ADDING_DECLARE_WARNINGS_AND_ERRORS, b[j].sourceName);
        addAdviceLikeDeclares(b[j].scope);
        CompilationAndWeavingContext.leavingPhase(tok);
      }
    }

    for (int i = lastCompletedUnitIndex + 1; i <= lastUnitIndex; i++) {
      units[i] = null; // release unnecessary reference to the parsed unit
    }

    stepCompleted = BUILD_FIELDS_AND_METHODS;
    lastCompletedUnitIndex = lastUnitIndex;
    AsmManager.setCompletingTypeBindings(false);
    factory.getWorld().getCrosscuttingMembersSet().verify();
    CompilationAndWeavingContext.leavingPhase(completeTypeBindingsToken);
  }

  // /**
  // * For any given sourcetypebinding, this method checks that if it is a
  // parameterized aspect that
  // * the type parameters specified for any supertypes meet the bounds for
  // the generic type
  // * variables.
  // */
  // private void verifyAnyTypeParametersMeetBounds(SourceTypeBinding
  // sourceType) {
  // ResolvedType onType = factory.fromEclipse(sourceType);
  // if (onType.isAspect()) {
  // ResolvedType superType = factory.fromEclipse(sourceType.superclass);
  // // Don't need to check if it was used in its RAW form or isnt generic
  // if (superType.isGenericType() || superType.isParameterizedType()) {
  // TypeVariable[] typeVariables = superType.getTypeVariables();
  // UnresolvedType[] typeParams = superType.getTypeParameters();
  // if (typeVariables!=null && typeParams!=null) {
  // for (int i = 0; i < typeVariables.length; i++) {
  // boolean ok =
  // typeVariables[i].canBeBoundTo(typeParams[i].resolve(factory.getWorld()));
  // if (!ok) { // the supplied parameter violates the bounds
  // // Type {0} does not meet the specification for type parameter {1} ({2})
  // in generic type {3}
  // String msg =
  // WeaverMessages.format(
  // WeaverMessages.VIOLATES_TYPE_VARIABLE_BOUNDS,
  // typeParams[i],
  // new Integer(i+1),
  // typeVariables[i].getDisplayName(),
  // superType.getGenericType().getName());
  // factory.getWorld().getMessageHandler().handleMessage(MessageUtil.error(msg
  // ,onType.getSourceLocation()));
  // }
  // }
  // }
  // }
  // }
  // }

  public void doSupertypesFirst(ReferenceBinding rb, Collection yetToProcess) {
    if (rb instanceof SourceTypeBinding) {
      if (yetToProcess.contains(rb)) {
        collectAllITDsAndDeclares((SourceTypeBinding) rb, yetToProcess);
      }
    } else if (rb instanceof ParameterizedTypeBinding) {
      // If its a PTB we need to pull the SourceTypeBinding out of it.
      ParameterizedTypeBinding ptb = (ParameterizedTypeBinding) rb;
      if (ptb.type instanceof SourceTypeBinding && yetToProcess.contains(ptb.type)) {
        collectAllITDsAndDeclares((SourceTypeBinding) ptb.type, yetToProcess);
      }
    }
  }

  /**
   * Find all the ITDs and Declares, but it is important we do this from the supertypes down to the subtypes.
   *
   * @param sourceType
   * @param yetToProcess
   */
  private void collectAllITDsAndDeclares(SourceTypeBinding sourceType, Collection yetToProcess) {
    // Look at the supertype first
    ContextToken tok = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.COLLECTING_ITDS_AND_DECLARES,
        sourceType.sourceName);

    yetToProcess.remove(sourceType);
    // look out our direct supertype
    doSupertypesFirst(sourceType.superclass(), yetToProcess);

    // now check our membertypes (pr119570)
    ReferenceBinding[] memberTypes = sourceType.memberTypes;
    for (int i = 0, length = memberTypes.length; i < length; i++) {
      SourceTypeBinding rb = (SourceTypeBinding) memberTypes[i];
      if (!rb.superclass().equals(sourceType)) {
        doSupertypesFirst(rb.superclass(), yetToProcess);
      }
    }

    buildInterTypeAndPerClause(sourceType.scope);
    addCrosscuttingStructures(sourceType.scope);
    CompilationAndWeavingContext.leavingPhase(tok);
  }

  /**
   * Weave the parents and intertype decls into a given type. This method looks at the supertype and superinterfaces for the
   * specified type and recurses to weave those first if they are in the full list of types we are going to process during this
   * compile... it stops recursing the first time it hits a type we aren't going to process during this compile. This could cause
   * problems if you supply 'pieces' of a hierarchy, i.e. the bottom and the top, but not the middle - but what the hell are you
   * doing if you do that?
   *
   * @param mode 0=do everything, 1=do declare parents, 2=do ITDs
   */
  private void weaveIntertypes(List<SourceTypeBinding> typesToProcess, SourceTypeBinding typeToWeave,
      List<ConcreteTypeMunger> typeMungers, List<DeclareParents> declareParents,
      List<DeclareAnnotation> declareAnnotationOnTypes, int mode) {
    // Look at the supertype first
    ReferenceBinding superType = typeToWeave.superclass();
    if (typesToProcess.contains(superType) && superType instanceof SourceTypeBinding) {
      // System.err.println("Recursing to supertype "+new
      // String(superType.getFileName()));
      weaveIntertypes(typesToProcess, (SourceTypeBinding) superType, typeMungers, declareParents, declareAnnotationOnTypes,
          mode);
    }
    // Then look at the superinterface list
    ReferenceBinding[] interfaceTypes = typeToWeave.superInterfaces();
    for (int i = 0; i < interfaceTypes.length; i++) {
      ReferenceBinding binding = interfaceTypes[i];
      if (typesToProcess.contains(binding) && binding instanceof SourceTypeBinding) {
        // System.err.println("Recursing to superinterface "+new
        // String(binding.getFileName()));
        weaveIntertypes(typesToProcess, (SourceTypeBinding) binding, typeMungers, declareParents, declareAnnotationOnTypes,
            mode);
      }
    }
    weaveInterTypeDeclarations(typeToWeave, typeMungers, declareParents, declareAnnotationOnTypes, false, mode);
    typesToProcess.remove(typeToWeave);
  }

  private void doPendingWeaves() {
    for (Iterator i = pendingTypesToWeave.iterator(); i.hasNext();) {
      SourceTypeBinding t = (SourceTypeBinding) i.next();
      ContextToken tok = CompilationAndWeavingContext.enteringPhase(
          CompilationAndWeavingContext.WEAVING_INTERTYPE_DECLARATIONS, t.sourceName);
      weaveInterTypeDeclarations(t);
      CompilationAndWeavingContext.leavingPhase(tok);
    }
    pendingTypesToWeave.clear();
  }

  private void addAdviceLikeDeclares(ClassScope s) {
    TypeDeclaration dec = s.referenceContext;

    if (dec instanceof AspectDeclaration) {
      ResolvedType typeX = factory.fromEclipse(dec.binding);
      factory.getWorld().getCrosscuttingMembersSet().addAdviceLikeDeclares(typeX);
    }

    SourceTypeBinding sourceType = s.referenceContext.binding;
    ReferenceBinding[] memberTypes = sourceType.memberTypes;
    for (int i = 0, length = memberTypes.length; i < length; i++) {
      addAdviceLikeDeclares(((SourceTypeBinding) memberTypes[i]).scope);
    }
  }

  private void addCrosscuttingStructures(ClassScope s) {
    TypeDeclaration dec = s.referenceContext;

    if (dec instanceof AspectDeclaration) {
      ResolvedType typeX = factory.fromEclipse(dec.binding);
      factory.getWorld().getCrosscuttingMembersSet().addOrReplaceAspect(typeX, false);

      if (typeX.getSuperclass().isAspect() && !typeX.getSuperclass().isExposedToWeaver()) {
        factory.getWorld().getCrosscuttingMembersSet().addOrReplaceAspect(typeX.getSuperclass(), false);
      }
    }

    SourceTypeBinding sourceType = s.referenceContext.binding;
    ReferenceBinding[] memberTypes = sourceType.memberTypes;
    for (int i = 0, length = memberTypes.length; i < length; i++) {
      addCrosscuttingStructures(((SourceTypeBinding) memberTypes[i]).scope);
    }
  }

  private void resolvePointcutDeclarations(ClassScope s) {
    TypeDeclaration dec = s.referenceContext;
    SourceTypeBinding sourceType = s.referenceContext.binding;
    boolean hasPointcuts = false;
    AbstractMethodDeclaration[] methods = dec.methods;
    boolean initializedMethods = false;
    if (methods != null) {
      for (int i = 0; i < methods.length; i++) {
        if (methods[i] instanceof PointcutDeclaration) {
          hasPointcuts = true;
          if (!initializedMethods) {
            sourceType.methods(); // force initialization
            initializedMethods = true;
          }
          ((PointcutDeclaration) methods[i]).resolvePointcut(s);
        }
      }
    }

    if (hasPointcuts || dec instanceof AspectDeclaration || couldBeAnnotationStyleAspectDeclaration(dec)) {
      ReferenceType name = (ReferenceType) factory.fromEclipse(sourceType);
      EclipseSourceType eclipseSourceType = (EclipseSourceType) name.getDelegate();
      eclipseSourceType.checkPointcutDeclarations();
    }

    ReferenceBinding[] memberTypes = sourceType.memberTypes;
    for (int i = 0, length = memberTypes.length; i < length; i++) {
      resolvePointcutDeclarations(((SourceTypeBinding) memberTypes[i]).scope);
    }
  }

  /**
   * Return true if the declaration has @Aspect annotation. Called 'couldBe' rather than 'is' because someone else may have
   * defined an annotation called Aspect - we can't verify the full name (including package name) because it may not have been
   * resolved just yet and rather going through expensive resolution when we dont have to, this gives us a cheap check that tells
   * us whether to bother.
   */
  private boolean couldBeAnnotationStyleAspectDeclaration(TypeDeclaration dec) {
    Annotation[] annotations = dec.annotations;
    boolean couldBeAtAspect = false;
    if (annotations != null) {
      for (int i = 0; i < annotations.length && !couldBeAtAspect; i++) {
        if (annotations[i].toString().equals("@Aspect")) {
          couldBeAtAspect = true;
        }
      }
    }
    return couldBeAtAspect;
  }

  /**
   * Applies any intertype member type declarations up front.
   */
  private void processInterTypeMemberTypes(ClassScope classScope) {
    TypeDeclaration dec = classScope.referenceContext;
    if (dec instanceof AspectDeclaration) {
      ((AspectDeclaration) dec).processIntertypeMemberTypes(classScope);
    }
    // if we are going to support nested aspects making itd member types, copy the logic from the end of
    // buildInterTypeAndPerClause() which walks members
  }

  private void buildInterTypeAndPerClause(ClassScope s) {
    TypeDeclaration dec = s.referenceContext;
    if (dec instanceof AspectDeclaration) {
      ((AspectDeclaration) dec).buildInterTypeAndPerClause(s);
    }

    SourceTypeBinding sourceType = s.referenceContext.binding;
    // test classes don't extend aspects
    if (sourceType.superclass != null) {
      ResolvedType parent = factory.fromEclipse(sourceType.superclass);
      if (parent.isAspect() && !isAspect(dec)) {
        factory.showMessage(IMessage.ERROR, "class \'" + new String(sourceType.sourceName) + "\' can not extend aspect \'"
            + parent.getName() + "\'", factory.fromEclipse(sourceType).getSourceLocation(), null);
      }
    }

    ReferenceBinding[] memberTypes = sourceType.memberTypes;
    if (memberTypes == null) {
      System.err.println("Unexpectedly found null for memberTypes of " + sourceType.debugName());
    }
    if (memberTypes != null) {
      for (int i = 0, length = memberTypes.length; i < length; i++) {
        buildInterTypeAndPerClause(((SourceTypeBinding) memberTypes[i]).scope);
      }
    }
  }

  private boolean isAspect(TypeDeclaration decl) {
    if ((decl instanceof AspectDeclaration)) {
      return true;
    } else if (decl.annotations == null) {
      return false;
    } else {
      for (int i = 0; i < decl.annotations.length; i++) {
        Annotation ann = decl.annotations[i];
        if (ann.type instanceof SingleTypeReference) {
          if (CharOperation.equals("Aspect".toCharArray(), ((SingleTypeReference) ann.type).token)) {
            return true;
          }
        } else if (ann.type instanceof QualifiedTypeReference) {
          QualifiedTypeReference qtr = (QualifiedTypeReference) ann.type;
          if (qtr.tokens.length != 5) {
            return false;
          }
          if (!CharOperation.equals("org".toCharArray(), qtr.tokens[0])) {
            return false;
          }
          if (!CharOperation.equals("aspectj".toCharArray(), qtr.tokens[1])) {
            return false;
          }
          if (!CharOperation.equals("lang".toCharArray(), qtr.tokens[2])) {
            return false;
          }
          if (!CharOperation.equals("annotation".toCharArray(), qtr.tokens[3])) {
            return false;
          }
          if (!CharOperation.equals("Aspect".toCharArray(), qtr.tokens[4])) {
            return false;
          }
          return true;
        }
      }
    }
    return false;
  }

  private void weaveInterTypeDeclarations(CompilationUnitScope unit, List<ConcreteTypeMunger> typeMungers,
      List<DeclareParents> declareParents, List<DeclareAnnotation> declareAnnotationOnTypes) {
    for (int i = 0, length = unit.topLevelTypes.length; i < length; i++) {
      weaveInterTypeDeclarations(unit.topLevelTypes[i], typeMungers, declareParents, declareAnnotationOnTypes, false, 0);
    }
  }

  private void weaveInterTypeDeclarations(SourceTypeBinding sourceType) {
    if (!factory.areTypeMungersFinished()) {
      if (!pendingTypesToWeave.contains(sourceType)) {
        pendingTypesToWeave.add(sourceType);

        // inner type ITD support - may need this for some incremental cases...
        // List<ConcreteTypeMunger> ctms = factory.getWorld().getCrosscuttingMembersSet().getTypeMungersOfKind(
        // ResolvedTypeMunger.InnerClass);
        // // List<ConcreteTypeMunger> innerTypeMungers = new ArrayList<ConcreteTypeMunger>();
        // // for (ConcreteTypeMunger ctm : ctms) {
        // // if (ctm.getMunger() != null && ctm.getMunger().getKind() == ResolvedTypeMunger.InnerClass) {
        // // innerTypeMungers.add(ctm);
        // // }
        // // }
        // // that includes the innertype one...
        // // doPendingWeaves at this level is about applying inner class
        // BinaryTypeBinding t = (BinaryTypeBinding) sourceType;
        // for (ConcreteTypeMunger ctm : innerTypeMungers) {
        // NewMemberClassTypeMunger nmctm = (NewMemberClassTypeMunger) ctm.getMunger();
        // ReferenceBinding[] rbs = t.memberTypes;
        // UnresolvedType ut = factory.fromBinding(t);
        // if (ut.equals(nmctm.getTargetType())) {
        // // got a match here
        // SourceTypeBinding aspectTypeBinding = (SourceTypeBinding) factory.makeTypeBinding(ctm.getAspectType());
        //
        // char[] mungerMemberTypeName = ("$" + nmctm.getMemberTypeName()).toCharArray();
        // ReferenceBinding innerTypeBinding = null;
        // for (ReferenceBinding innerType : aspectTypeBinding.memberTypes) {
        // char[] compounded = CharOperation.concatWith(innerType.compoundName, '.');
        // if (org.aspectj.org.eclipse.jdt.core.compiler.CharOperation.endsWith(compounded, mungerMemberTypeName)) {
        // innerTypeBinding = innerType;
        // break;
        // }
        // }
        // // may be unresolved if the aspect type binding was a BinaryTypeBinding
        // if (innerTypeBinding instanceof UnresolvedReferenceBinding) {
        // innerTypeBinding = BinaryTypeBinding
        // .resolveType(innerTypeBinding, factory.getLookupEnvironment(), true);
        // }
        // t.memberTypes(); // cause initialization
        // t.memberTypes = new ReferenceBinding[] { innerTypeBinding };
        //
        // int stop = 1;
        // // The inner type from the aspect should be put into the membertypebindings for this
        //
        // }
        // }

      }
    } else {
      weaveInterTypeDeclarations(sourceType, factory.getTypeMungers(), factory.getDeclareParents(),
          factory.getDeclareAnnotationOnTypes(), true, 0);
    }
  }

  /**
   * @param mode 0=do everything, 1=do declare parents, 2=do ITDs
   */
  private void weaveInterTypeDeclarations(SourceTypeBinding sourceType, List<ConcreteTypeMunger> typeMungers,
      List<DeclareParents> declareParents, List<DeclareAnnotation> declareAnnotationOnTypes, boolean skipInners, int mode) {

    ContextToken tok = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.WEAVING_INTERTYPE_DECLARATIONS,
        sourceType.sourceName);

    ResolvedType onType = factory.fromEclipse(sourceType);

    // AMC we shouldn't need this when generic sigs are fixed??
    if (onType.isRawType()) {
      onType = onType.getGenericType();
    }

    WeaverStateInfo info = onType.getWeaverState();

    if (mode < 2) {
      // this test isnt quite right - there will be a case where we fail to
      // flag a problem
      // with a 'dangerous interface' because the type is reweavable when we
      // should have
      // because the type wasn't going to be rewoven... if that happens, we
      // should perhaps
      // move this test and dangerous interface processing to the end of this
      // method and
      // make it conditional on whether any of the typeMungers passed into
      // here actually
      // matched this type.
      if (info != null && !info.isOldStyle() && !info.isReweavable()) {
        processTypeMungersFromExistingWeaverState(sourceType, onType);
        CompilationAndWeavingContext.leavingPhase(tok);
        return;
      }

      // Check if the type we are looking at is the topMostImplementor of a
      // dangerous interface -
      // report a problem if it is.
      for (Iterator i = dangerousInterfaces.entrySet().iterator(); i.hasNext();) {
        Map.Entry entry = (Map.Entry) i.next();
        ResolvedType interfaceType = (ResolvedType) entry.getKey();
        if (onType.isTopmostImplementor(interfaceType)) {
          factory.showMessage(IMessage.ERROR, onType + ": " + entry.getValue(), onType.getSourceLocation(), null);
        }
      }

      boolean needOldStyleWarning = (info != null && info.isOldStyle());

      onType.clearInterTypeMungers();
      onType.ensureConsistent();

      // FIXME asc perf Could optimize here, after processing the expected set
      // of types we may bring
      // binary types that are not exposed to the weaver, there is no need to
      // attempt declare parents
      // or declare annotation really - unless we want to report the
      // not-exposed to weaver
      // messages...

      List<DeclareParents> decpToRepeat = new ArrayList<DeclareParents>();
      List<DeclareAnnotation> decaToRepeat = new ArrayList<DeclareAnnotation>();
      boolean anyNewParents = false;
      boolean anyNewAnnotations = false;

      // first pass
      // try and apply all decps - if they match, then great. If they don't
      // then
      // check if they are starred-annotation patterns. If they are not
      // starred
      // annotation patterns then they might match later...remember that...
      for (DeclareParents decp : declareParents) {
        if (!decp.isMixin()) {
          boolean didSomething = doDeclareParents(decp, sourceType);
          if (didSomething) {
            if (factory.pushinCollector != null) {
              factory.pushinCollector.tagAsMunged(sourceType, decp.getParents().get(0));
            }
            anyNewParents = true;
          } else {
            if (!decp.getChild().isStarAnnotation()) {
              decpToRepeat.add(decp);
            }
          }
        }
      }

      for (DeclareAnnotation deca : declareAnnotationOnTypes) {
        boolean didSomething = doDeclareAnnotations(deca, sourceType, true);
        if (didSomething) {
          anyNewAnnotations = true;
        } else {
          if (!deca.getTypePattern().isStar()) {
            decaToRepeat.add(deca);
          }
        }
      }

      List forRemoval = new ArrayList();
      // now lets loop over and over until we have done all we can
      while ((anyNewAnnotations || anyNewParents) && (!decpToRepeat.isEmpty() || !decaToRepeat.isEmpty())) {
        anyNewParents = anyNewAnnotations = false;
        forRemoval.clear();
        for (DeclareParents decp : decpToRepeat) {
          boolean didSomething = doDeclareParents(decp, sourceType);
          if (didSomething) {
            if (factory.pushinCollector != null) {
              factory.pushinCollector.tagAsMunged(sourceType, decp.getParents().get(0));
            }
            anyNewParents = true;
            forRemoval.add(decp);
          }
        }
        decpToRepeat.removeAll(forRemoval);

        forRemoval.clear();
        for (DeclareAnnotation deca : decaToRepeat) {
          boolean didSomething = doDeclareAnnotations(deca, sourceType, false);
          if (didSomething) {
            if (factory.pushinCollector != null) {
              factory.pushinCollector.tagAsMunged(sourceType, deca.getAnnotationString());
            }
            anyNewAnnotations = true;
            forRemoval.add(deca);
          }
        }
        decaToRepeat.removeAll(forRemoval);
      }
    }
    if (mode == 0 || mode == 2) {
      for (Iterator<ConcreteTypeMunger> i = typeMungers.iterator(); i.hasNext();) {
        EclipseTypeMunger munger = (EclipseTypeMunger) i.next();
        if (munger.matches(onType)) {
          // if (needOldStyleWarning) {
          // factory.showMessage(IMessage.WARNING, "The class for " + onType
          // + " should be recompiled with ajc-1.1.1 for best results", onType.getSourceLocation(), null);
          // needOldStyleWarning = false;
          // }
          onType.addInterTypeMunger(munger, true);
          if (munger.getMunger() != null && munger.getMunger().getKind() == ResolvedTypeMunger.InnerClass) {
            // Must do these right now, because if we do an ITD member afterwards it may attempt to reference the
            // type being applied (the call above 'addInterTypeMunger' will fail for these ITDs if it needed
            // it to be in place)
            if (munger.munge(sourceType, onType)) {
              if (factory.pushinCollector != null) {
                factory.pushinCollector.tagAsMunged(sourceType, munger.getSourceMethod());
              }
            }
          }
        }
      }

      onType.checkInterTypeMungers();
      for (Iterator i = onType.getInterTypeMungers().iterator(); i.hasNext();) {
        EclipseTypeMunger munger = (EclipseTypeMunger) i.next();
        if (munger.getMunger() == null || munger.getMunger().getKind() != ResolvedTypeMunger.InnerClass) {
          if (munger.munge(sourceType, onType)) {
            if (factory.pushinCollector != null) {
              factory.pushinCollector.tagAsMunged(sourceType, munger.getSourceMethod());
            }
          }
        }
      }
    }

    // Call if you would like to do source weaving of declare
    // @method/@constructor
    // at source time... no need to do this as it can't impact anything, but
    // left here for
    // future generations to enjoy. Method source is commented out at the
    // end of this module
    // doDeclareAnnotationOnMethods();

    // Call if you would like to do source weaving of declare @field
    // at source time... no need to do this as it can't impact anything, but
    // left here for
    // future generations to enjoy. Method source is commented out at the
    // end of this module
    // doDeclareAnnotationOnFields();

    if (skipInners) {
      CompilationAndWeavingContext.leavingPhase(tok);
      return;
    }

    ReferenceBinding[] memberTypes = sourceType.memberTypes;
    for (int i = 0, length = memberTypes.length; i < length; i++) {
      if (memberTypes[i] instanceof SourceTypeBinding) {
        weaveInterTypeDeclarations((SourceTypeBinding) memberTypes[i], typeMungers, declareParents,
            declareAnnotationOnTypes, false, mode);
      }
    }
    CompilationAndWeavingContext.leavingPhase(tok);
  }

  /**
   * Called when we discover we are weaving intertype declarations on some type that has an existing 'WeaverStateInfo' object -
   * this is typically some previously woven type that has been passed on the inpath.
   *
   * sourceType and onType are the 'same type' - the former is the 'Eclipse' version and the latter is the 'Weaver' version.
   */
  private void processTypeMungersFromExistingWeaverState(SourceTypeBinding sourceType, ResolvedType onType) {
    Collection previouslyAppliedMungers = onType.getWeaverState().getTypeMungers(onType);

    for (Iterator i = previouslyAppliedMungers.iterator(); i.hasNext();) {
      ConcreteTypeMunger m = (ConcreteTypeMunger) i.next();
      EclipseTypeMunger munger = factory.makeEclipseTypeMunger(m);
      if (munger.munge(sourceType, onType)) {
        if (onType.isInterface() && munger.getMunger().needsAccessToTopmostImplementor()) {
          if (!onType.getWorld().getCrosscuttingMembersSet().containsAspect(munger.getAspectType())) {
            dangerousInterfaces
                .put(onType, "implementors of " + onType + " must be woven by " + munger.getAspectType());
          }
        }
      }

    }
  }

  private boolean doDeclareParents(DeclareParents declareParents, SourceTypeBinding sourceType) {
    ContextToken tok = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.PROCESSING_DECLARE_PARENTS,
        sourceType.sourceName);
    ResolvedType resolvedSourceType = factory.fromEclipse(sourceType);
    List newParents = declareParents.findMatchingNewParents(resolvedSourceType, false);
    if (!newParents.isEmpty()) {
      for (Iterator i = newParents.iterator(); i.hasNext();) {
        ResolvedType parent = (ResolvedType) i.next();
        if (dangerousInterfaces.containsKey(parent)) {
          ResolvedType onType = factory.fromEclipse(sourceType);
          factory.showMessage(IMessage.ERROR, onType + ": " + dangerousInterfaces.get(parent),
              onType.getSourceLocation(), null);
        }
        if (Modifier.isFinal(parent.getModifiers())) {
          factory.showMessage(IMessage.ERROR, "cannot extend final class " + parent.getClassName(),
              declareParents.getSourceLocation(), null);
        } else {
          // do not actually do it if the type isn't exposed - this
          // will correctly reported as a problem elsewhere
          if (!resolvedSourceType.isExposedToWeaver()) {
            return false;
          }
          // AsmRelationshipProvider.getDefault().
          // addDeclareParentsRelationship
          // (declareParents.getSourceLocation(),
          // factory.fromEclipse(sourceType), newParents);
          addParent(sourceType, parent);
        }
      }
      CompilationAndWeavingContext.leavingPhase(tok);
      return true;
    }
    CompilationAndWeavingContext.leavingPhase(tok);
    return false;
  }

  private String stringifyTargets(long bits) {
    if ((bits & TagBits.AnnotationTargetMASK) == 0) {
      return "";
    }
    Set s = new HashSet();
    if ((bits & TagBits.AnnotationForAnnotationType) != 0) {
      s.add("ANNOTATION_TYPE");
    }
    if ((bits & TagBits.AnnotationForConstructor) != 0) {
      s.add("CONSTRUCTOR");
    }
    if ((bits & TagBits.AnnotationForField) != 0) {
      s.add("FIELD");
    }
    if ((bits & TagBits.AnnotationForLocalVariable) != 0) {
      s.add("LOCAL_VARIABLE");
    }
    if ((bits & TagBits.AnnotationForMethod) != 0) {
      s.add("METHOD");
    }
    if ((bits & TagBits.AnnotationForPackage) != 0) {
      s.add("PACKAGE");
    }
    if ((bits & TagBits.AnnotationForParameter) != 0) {
      s.add("PARAMETER");
    }
    if ((bits & TagBits.AnnotationForType) != 0) {
      s.add("TYPE");
    }
    StringBuffer sb = new StringBuffer();
    sb.append("{");
    for (Iterator iter = s.iterator(); iter.hasNext();) {
      String element = (String) iter.next();
      sb.append(element);
      if (iter.hasNext()) {
        sb.append(",");
      }
    }
    sb.append("}");
    return sb.toString();
  }

  private boolean doDeclareAnnotations(DeclareAnnotation decA, SourceTypeBinding sourceType, boolean reportProblems) {
    ResolvedType rtx = factory.fromEclipse(sourceType);
    if (!decA.matches(rtx)) {
      return false;
    }
    if (!rtx.isExposedToWeaver()) {
      return false;
    }

    ContextToken tok = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.PROCESSING_DECLARE_ANNOTATIONS,
        sourceType.sourceName);

    // Get the annotation specified in the declare
    UnresolvedType aspectType = decA.getAspect();
    if (aspectType instanceof ReferenceType) {
      ReferenceType rt = (ReferenceType) aspectType;
      if (rt.isParameterizedType() || rt.isRawType()) {
        aspectType = rt.getGenericType();
      }
    }
    TypeBinding tb = factory.makeTypeBinding(aspectType);

    // Hideousness follows:

    // There are multiple situations to consider here and they relate to the
    // combinations of
    // where the annotation is coming from and where the annotation is going
    // to be put:
    //
    // 1. Straight full build, all from source - the annotation is from a
    // dec@type and
    // is being put on some type. Both types are real SourceTypeBindings.
    // WORKS
    // 2. Incremental build, changing the affected type - the annotation is
    // from a
    // dec@type in a BinaryTypeBinding (so has to be accessed via bcel) and
    // the
    // affected type is a real SourceTypeBinding. Mostly works (pr128665)
    // 3. ?

    SourceTypeBinding stb = (SourceTypeBinding) tb;
    Annotation[] toAdd = null;
    long abits = 0;

    AbstractMethodDeclaration methodDecl = null;
    // Might have to retrieve the annotation through BCEL and construct an
    // eclipse one for it.
    if (stb instanceof BinaryTypeBinding) {
      toAdd = retrieveAnnotationFromBinaryTypeBinding(decA, stb);
      if (toAdd != null && toAdd.length > 0 && toAdd[0].resolvedType != null) {
        abits = toAdd[0].resolvedType.getAnnotationTagBits();
      }
    } else if (stb != null) {
      // much nicer, its a real SourceTypeBinding so we can stay in
      // eclipse land
      // if (decA.getAnnotationMethod() != null) {
      char[] declareSelector = decA.getAnnotationMethod().toCharArray();

      ReferenceBinding rb = stb;
      String declaringAspectName = decA.getDeclaringType().getRawName();
      while (rb != null && !new String(CharOperation.concatWith(rb.compoundName, '.')).equals(declaringAspectName)) {
        rb = rb.superclass();
      }
      MethodBinding[] mbs = rb.getMethods(declareSelector);

      ReferenceBinding declaringBinding = mbs[0].declaringClass;
      if (declaringBinding instanceof ParameterizedTypeBinding) {
        // Unwrap - this means we don't allow the type of the annotation to be parameterized, may need to revisit that
        declaringBinding = ((ParameterizedTypeBinding) declaringBinding).type;
      }
      if (declaringBinding instanceof BinaryTypeBinding) {
        toAdd = retrieveAnnotationFromBinaryTypeBinding(decA, declaringBinding);
        if (toAdd != null && toAdd.length > 0 && toAdd[0].resolvedType != null) {
          abits = toAdd[0].resolvedType.getAnnotationTagBits();
        }
      } else {
        abits = mbs[0].getAnnotationTagBits(); // ensure resolved
        TypeDeclaration typeDecl = ((SourceTypeBinding) declaringBinding).scope.referenceContext;
        methodDecl = typeDecl.declarationOf(mbs[0]);
        toAdd = methodDecl.annotations; // this is what to add
        toAdd[0] = createAnnotationCopy(toAdd[0]);
        if (toAdd[0].resolvedType != null) {
          abits = toAdd[0].resolvedType.getAnnotationTagBits();
          // }
        }
      }
    }

    // This happens if there is another error in the code - that should be reported separately
    if (toAdd == null || toAdd[0] == null || toAdd[0].type == null) {
      CompilationAndWeavingContext.leavingPhase(tok);
      return false;
    }
    if (sourceType instanceof BinaryTypeBinding) {
      // In this case we can't access the source type binding to add a new
      // annotation, so let's put something
      // on the weaver type temporarily
      ResolvedType theTargetType = factory.fromEclipse(sourceType);
      TypeBinding theAnnotationType = toAdd[0].resolvedType;
      // The annotation type may be null if it could not be resolved (eg. the relevant import has not been added yet)
      // In this case an error will be put out about the annotation but not if we crash here
      if (theAnnotationType == null) {
        return false;
      }
      String sig = new String(theAnnotationType.signature());
      UnresolvedType bcelAnnotationType = UnresolvedType.forSignature(sig);
      String name = bcelAnnotationType.getName();
      if (theTargetType.hasAnnotation(bcelAnnotationType)) {
        CompilationAndWeavingContext.leavingPhase(tok);
        return false;
      }

      // FIXME asc tidy up this code that duplicates whats below!
      // Simple checks on the bits
      boolean giveupnow = false;
      if (((abits & TagBits.AnnotationTargetMASK) != 0)) {
        if (isAnnotationTargettingSomethingOtherThanAnnotationOrNormal(abits)) {
          // error will have been already reported
          giveupnow = true;
        } else if ((sourceType.isAnnotationType() && (abits & TagBits.AnnotationForAnnotationType) == 0)
            || (!sourceType.isAnnotationType() && (abits & TagBits.AnnotationForType) == 0)) {

          if (reportProblems) {
            if (decA.isExactPattern()) {
              factory.showMessage(IMessage.ERROR, WeaverMessages.format(
                  WeaverMessages.INCORRECT_TARGET_FOR_DECLARE_ANNOTATION, rtx.getName(), toAdd[0].type,
                  stringifyTargets(abits)), decA.getSourceLocation(), null);
            }
            // dont put out the lint - the weaving process will do
            // that
            // else {
            // if (factory.getWorld().getLint().
            // invalidTargetForAnnotation.isEnabled()) {
            // factory.getWorld().getLint().invalidTargetForAnnotation
            // .signal(new
            // String[]{rtx.getName(),toAdd[0].type.toString(),
            // stringifyTargets
            // (abits)},decA.getSourceLocation(),null);
            // }
            // }
          }
          giveupnow = true;
        }
      }
      if (giveupnow) {
        CompilationAndWeavingContext.leavingPhase(tok);
        return false;
      }

      theTargetType.addAnnotation(new BcelAnnotation(new FakeAnnotation(name, sig,
          (abits & TagBits.AnnotationRuntimeRetention) != 0), factory.getWorld()));
      CompilationAndWeavingContext.leavingPhase(tok);
      return true;
    }

    Annotation currentAnnotations[] = sourceType.scope.referenceContext.annotations;
    if (currentAnnotations != null) {
      for (int i = 0; i < currentAnnotations.length; i++) {
        Annotation annotation = currentAnnotations[i];
        String a = CharOperation.toString(annotation.type.getTypeName());
        String b = CharOperation.toString(toAdd[0].type.getTypeName());
        // FIXME asc we have a lint for attempting to add an annotation
        // twice to a method,
        // we could put it out here *if* we can resolve the problem of
        // errors coming out
        // multiple times if we have cause to loop through here
        if (a.equals(b)) {
          CompilationAndWeavingContext.leavingPhase(tok);
          return false;
        }
      }
    }

    if (((abits & TagBits.AnnotationTargetMASK) != 0)) {
      if ((abits & (TagBits.AnnotationForAnnotationType | TagBits.AnnotationForType)) == 0) {
        // this means it specifies something other than annotation or
        // normal type - error will have been already reported,
        // just resolution process above
        CompilationAndWeavingContext.leavingPhase(tok);
        return false;
      }
      if ((sourceType.isAnnotationType() && (abits & TagBits.AnnotationForAnnotationType) == 0)
          || (!sourceType.isAnnotationType() && (abits & TagBits.AnnotationForType) == 0)) {

        if (reportProblems) {
          if (decA.isExactPattern()) {
            factory.showMessage(IMessage.ERROR, WeaverMessages.format(
                WeaverMessages.INCORRECT_TARGET_FOR_DECLARE_ANNOTATION, rtx.getName(), toAdd[0].type,
                stringifyTargets(abits)), decA.getSourceLocation(), null);
          }
          // dont put out the lint - the weaving process will do that
          // else {
          // if
          // (factory.getWorld().getLint().invalidTargetForAnnotation
          // .isEnabled()) {
          // factory.getWorld().getLint().invalidTargetForAnnotation.
          // signal(new
          // String[]{rtx.getName(),toAdd[0].type.toString(),
          // stringifyTargets(abits)},decA.getSourceLocation(),null);
          // }
          // }
        }
        CompilationAndWeavingContext.leavingPhase(tok);
        return false;
      }
    }

    // Build a new array of annotations

    // remember the current set (rememberAnnotations only does something the
    // first time it is called for a type)
    sourceType.scope.referenceContext.rememberAnnotations();

    // AsmRelationshipProvider.getDefault().addDeclareAnnotationRelationship(
    // decA.getSourceLocation(), rtx.getSourceLocation());
    Annotation abefore[] = sourceType.scope.referenceContext.annotations;
    Annotation[] newset = new Annotation[toAdd.length + (abefore == null ? 0 : abefore.length)];
    System.arraycopy(toAdd, 0, newset, 0, toAdd.length);
    if (abefore != null) {
      System.arraycopy(abefore, 0, newset, toAdd.length, abefore.length);
    }
    sourceType.scope.referenceContext.annotations = newset;
    CompilationAndWeavingContext.leavingPhase(tok);
    if (factory.pushinCollector != null) {
      factory.pushinCollector.tagAsMunged(sourceType, new CommonPrinter((methodDecl == null ? null : methodDecl.scope))
          .printAnnotation(toAdd[0]).toString());
    }
    return true;
  }

  private Annotation[] retrieveAnnotationFromBinaryTypeBinding(DeclareAnnotation decA, ReferenceBinding declaringBinding) {
    ReferenceType rt = (ReferenceType) factory.fromEclipse(declaringBinding);
    ResolvedMember[] methods = rt.getDeclaredMethods();
    ResolvedMember decaMethod = null;
    String nameToLookFor = decA.getAnnotationMethod();
    for (int i = 0; i < methods.length; i++) {
      if (methods[i].getName().equals(nameToLookFor)) {
        decaMethod = methods[i];
        break;
      }
    }
    if (decaMethod != null) { // could assert this ...
      AnnotationAJ[] axs = decaMethod.getAnnotations();
      if (axs != null) { // another error has occurred, dont crash here because of it
        Annotation[] toAdd = new Annotation[1];
        toAdd[0] = createAnnotationFromBcelAnnotation(axs[0], decaMethod.getSourceLocation().getOffset(), factory);
        // BUG BUG BUG - We dont test these abits are correct, in fact
        // we'll be very lucky if they are.
        // What does that mean? It means on an incremental compile you
        // might get away with an
        // annotation that isn't allowed on a type being put on a type.
        // if (toAdd[0].resolvedType != null) {
        // abits = toAdd[0].resolvedType.getAnnotationTagBits();
        // }
        return toAdd;
      }
    }
    return null;
  }

  /**
   * Transform an annotation from its AJ form to an eclipse form. We *DONT* care about the values of the annotation. that is
   * because it is only being stuck on a type during type completion to allow for other constructs (decps, decas) that might be
   * looking for it - when the class actually gets to disk it wont have this new annotation on it and during weave time we will do
   * the right thing copying across values too.
   */
  private static Annotation createAnnotationFromBcelAnnotation(AnnotationAJ annX, int pos, EclipseFactory factory) {
    String name = annX.getTypeName();
    TypeBinding tb = factory.makeTypeBinding(annX.getType());
    // String theName = annX.getSignature().getBaseName();
    char[][] typeName = CharOperation.splitOn('.', name.replace('$', '.').toCharArray()); // pr149293 - not bulletproof...
    long[] positions = new long[typeName.length];
    for (int i = 0; i < positions.length; i++) {
      positions[i] = pos;
    }
    TypeReference annType = new QualifiedTypeReference(typeName, positions);
    NormalAnnotation ann = new NormalAnnotation(annType, pos);
    ann.resolvedType = tb; // yuck - is this OK in all cases?
    // We don't need membervalues...
    // Expression pcExpr = new
    // StringLiteral(pointcutExpression.toCharArray(),pos,pos);
    // MemberValuePair[] mvps = new MemberValuePair[2];
    // mvps[0] = new MemberValuePair("value".toCharArray(),pos,pos,pcExpr);
    // Expression argNamesExpr = new
    // StringLiteral(argNames.toCharArray(),pos,pos);
    // mvps[1] = new
    // MemberValuePair("argNames".toCharArray(),pos,pos,argNamesExpr);
    // ann.memberValuePairs = mvps;
    return ann;
  }

  /**
   * Create a copy of an annotation, not deep but deep enough so we don't copy across fields that will get us into trouble like
   * 'recipient'
   */
  private static Annotation createAnnotationCopy(Annotation ann) {
    NormalAnnotation ann2 = new NormalAnnotation(ann.type, ann.sourceStart);
    ann2.memberValuePairs = ann.memberValuePairs();
    ann2.resolvedType = ann.resolvedType;
    ann2.bits = ann.bits;
    return ann2;
    // String name = annX.getTypeName();
    // TypeBinding tb = factory.makeTypeBinding(annX.getSignature());
    // String theName = annX.getSignature().getBaseName();
    // char[][] typeName =
    // CharOperation.splitOn('.',name.replace('$','.').toCharArray());
    // //pr149293 - not bulletproof...
    // long[] positions = new long[typeName.length];
    // for (int i = 0; i < positions.length; i++) positions[i]=pos;
    // TypeReference annType = new
    // QualifiedTypeReference(typeName,positions);
    // NormalAnnotation ann = new NormalAnnotation(annType,pos);
    // ann.resolvedType=tb; // yuck - is this OK in all cases?
    // // We don't need membervalues...
    // // Expression pcExpr = new
    // StringLiteral(pointcutExpression.toCharArray(),pos,pos);
    // // MemberValuePair[] mvps = new MemberValuePair[2];
    // // mvps[0] = new
    // MemberValuePair("value".toCharArray(),pos,pos,pcExpr);
    // // Expression argNamesExpr = new
    // StringLiteral(argNames.toCharArray(),pos,pos);
    // // mvps[1] = new
    // MemberValuePair("argNames".toCharArray(),pos,pos,argNamesExpr);
    // // ann.memberValuePairs = mvps;
    // return ann;
  }

  private boolean isAnnotationTargettingSomethingOtherThanAnnotationOrNormal(long abits) {
    return (abits & (TagBits.AnnotationForAnnotationType | TagBits.AnnotationForType)) == 0;
  }

  private void reportDeclareParentsMessage(WeaveMessage.WeaveMessageKind wmk, SourceTypeBinding sourceType, ResolvedType parent) {
    if (!factory.getWorld().getMessageHandler().isIgnoring(IMessage.WEAVEINFO)) {
      String filename = new String(sourceType.getFileName());

      int takefrom = filename.lastIndexOf('/');
      if (takefrom == -1) {
        takefrom = filename.lastIndexOf('\\');
      }
      filename = filename.substring(takefrom + 1);

      factory.getWorld()
          .getMessageHandler()
          .handleMessage(
              WeaveMessage.constructWeavingMessage(wmk,
                  new String[] { CharOperation.toString(sourceType.compoundName), filename,
                      parent.getClassName(),
                      getShortname(parent.getSourceLocation().getSourceFile().getPath()) }));
    }
  }

  private String getShortname(String path) {
    int takefrom = path.lastIndexOf('/');
    if (takefrom == -1) {
      takefrom = path.lastIndexOf('\\');
    }
    return path.substring(takefrom + 1);
  }

  private void addParent(SourceTypeBinding sourceType, ResolvedType parent) {
    ReferenceBinding parentBinding = (ReferenceBinding) factory.makeTypeBinding(parent);
    if (parentBinding == null) {
      return; // The parent is missing, it will be reported elsewhere.
    }
    sourceType.rememberTypeHierarchy();
    if (parentBinding.isClass()) {
      sourceType.superclass = parentBinding;

      // this used to be true, but I think I've fixed it now, decp is done
      // at weave time!
      // TAG: WeavingMessage DECLARE PARENTS: EXTENDS
      // Compiler restriction: Can't do EXTENDS at weave time
      // So, only see this message if doing a source compilation
      // reportDeclareParentsMessage(WeaveMessage.
      // WEAVEMESSAGE_DECLAREPARENTSEXTENDS,sourceType,parent);

    } else {
      ReferenceBinding[] oldI = sourceType.superInterfaces;
      ReferenceBinding[] newI;
      if (oldI == null) {
        newI = new ReferenceBinding[1];
        newI[0] = parentBinding;
      } else {
        int n = oldI.length;
        newI = new ReferenceBinding[n + 1];
        System.arraycopy(oldI, 0, newI, 0, n);
        newI[n] = parentBinding;
      }
      sourceType.superInterfaces = newI;
      // warnOnAddedInterface(factory.fromEclipse(sourceType),parent); //
      // now reported at weave time...

      // this used to be true, but I think I've fixed it now, decp is done
      // at weave time!
      // TAG: WeavingMessage DECLARE PARENTS: IMPLEMENTS
      // This message will come out of BcelTypeMunger.munge if doing a
      // binary weave
      // reportDeclareParentsMessage(WeaveMessage.
      // WEAVEMESSAGE_DECLAREPARENTSIMPLEMENTS,sourceType,parent);

    }

    // also add it to the bcel delegate if there is one
    if (sourceType instanceof BinaryTypeBinding) {
      ResolvedType onType = factory.fromEclipse(sourceType);
      ReferenceType rt = (ReferenceType) onType;
      ReferenceTypeDelegate rtd = rt.getDelegate();
      if (rtd instanceof BcelObjectType) {
        rt.addParent(parent);
        // ((BcelObjectType) rtd).addParent(parent);
      }
    }

  }

  public void warnOnAddedInterface(ResolvedType type, ResolvedType parent) {
    World world = factory.getWorld();
    ResolvedType serializable = world.getCoreType(UnresolvedType.SERIALIZABLE);
    if (serializable.isAssignableFrom(type) && !serializable.isAssignableFrom(parent)
        && !LazyClassGen.hasSerialVersionUIDField(type)) {
      world.getLint().needsSerialVersionUIDField.signal(new String[] { type.getName().toString(),
          "added interface " + parent.getName().toString() }, null, null);
    }
  }

  private final List pendingTypesToFinish = new ArrayList();
  boolean inBinaryTypeCreationAndWeaving = false;
  boolean processingTheQueue = false;

  public BinaryTypeBinding createBinaryTypeFrom(IBinaryType binaryType, PackageBinding packageBinding,
      boolean needFieldsAndMethods, AccessRestriction accessRestriction) {

    if (inBinaryTypeCreationAndWeaving) {
      BinaryTypeBinding ret = super.createBinaryTypeFrom(binaryType, packageBinding, needFieldsAndMethods, accessRestriction);
      pendingTypesToFinish.add(ret);
      return ret;
    }

    inBinaryTypeCreationAndWeaving = true;
    try {
      BinaryTypeBinding ret = super.createBinaryTypeFrom(binaryType, packageBinding, needFieldsAndMethods, accessRestriction);
      factory.getWorld().validateType(factory.fromBinding(ret));
      // if you need the bytes to pass to validate, here they
      // are:((ClassFileReader)binaryType).getReferenceBytes()
      weaveInterTypeDeclarations(ret);
      return ret;
    } finally {
      inBinaryTypeCreationAndWeaving = false;

      // Start processing the list...
      if (pendingTypesToFinish.size() > 0) {
        processingTheQueue = true;
        while (!pendingTypesToFinish.isEmpty()) {
          BinaryTypeBinding nextVictim = (BinaryTypeBinding) pendingTypesToFinish.remove(0);
          // During this call we may recurse into this method and add
          // more entries to the pendingTypesToFinish list.
          weaveInterTypeDeclarations(nextVictim);
        }
        processingTheQueue = false;
      }
    }
  }

  /**
   * Callback driven when the compiler detects an anonymous type during block resolution. We need to add it to the weaver so that
   * we don't trip up later.
   *
   * @param aBinding
   */
  public void anonymousTypeBindingCreated(LocalTypeBinding aBinding) {
    factory.addSourceTypeBinding(aBinding, null);
  }
}

// commented out, supplied as info on how to manipulate annotations in an
// eclipse world
//
// public void doDeclareAnnotationOnMethods() {
// Do the declare annotation on fields/methods/ctors
// Collection daoms = factory.getDeclareAnnotationOnMethods();
// if (daoms!=null && daoms.size()>0 && !(sourceType instanceof
// BinaryTypeBinding)) {
// System.err.println("Going through the methods on "+sourceType.debugName()+
// " looking for DECA matches");
// // We better take a look through them...
// for (Iterator iter = daoms.iterator(); iter.hasNext();) {
// DeclareAnnotation element = (DeclareAnnotation) iter.next();
// System.err.println("Looking for anything that might match "+element+" on "+
// sourceType.debugName()+"  "+getType(sourceType.
// compoundName).debugName()+"  "+(sourceType instanceof BinaryTypeBinding));
//
// ReferenceBinding rbb = getType(sourceType.compoundName);
// // fix me if we ever uncomment this code... should iterate the other way
// round, over the methods then over the decas
// sourceType.methods();
// MethodBinding sourceMbs[] = sourceType.methods;
// for (int i = 0; i < sourceMbs.length; i++) {
// MethodBinding sourceMb = sourceMbs[i];
// MethodBinding mbbbb =
// ((SourceTypeBinding)rbb).getExactMethod(sourceMb.selector
// ,sourceMb.parameters);
// boolean isCtor = sourceMb.selector[0]=='<';
//
// if ((element.isDeclareAtConstuctor() ^ !isCtor)) {
// System.err.println("Checking "+sourceMb+" ... declaringclass="+sourceMb.
// declaringClass.debugName()+" rbb="+rbb.debugName()+"  "+
// sourceMb.declaringClass.equals(rbb));
//
// ResolvedMember rm = null;
// rm = EclipseFactory.makeResolvedMember(mbbbb);
// if (element.matches(rm,factory.getWorld())) {
// System.err.println("MATCH");
//
// // Determine the set of annotations that are currently on the method
// ReferenceBinding rb = getType(sourceType.compoundName);
// // TypeBinding tb = factory.makeTypeBinding(decA.getAspect());
// MethodBinding mb =
// ((SourceTypeBinding)rb).getExactMethod(sourceMb.selector,sourceMb
// .parameters);
// //long abits = mbs[0].getAnnotationTagBits(); // ensure resolved
// TypeDeclaration typeDecl =
// ((SourceTypeBinding)sourceMb.declaringClass).scope.referenceContext;
// AbstractMethodDeclaration methodDecl = typeDecl.declarationOf(sourceMb);
// Annotation[] currentlyHas = methodDecl.annotations; // this is what to add
// //abits = toAdd[0].resolvedType.getAnnotationTagBits();
//
// // Determine the annotations to add to that method
// TypeBinding tb = factory.makeTypeBinding(element.getAspect());
// MethodBinding[] aspectMbs =
// ((SourceTypeBinding)tb).getMethods(element.getAnnotationMethod
// ().toCharArray());
// long abits = aspectMbs[0].getAnnotationTagBits(); // ensure resolved
// TypeDeclaration typeDecl2 =
// ((SourceTypeBinding)aspectMbs[0].declaringClass).scope.referenceContext;
// AbstractMethodDeclaration methodDecl2 =
// typeDecl2.declarationOf(aspectMbs[0]);
// Annotation[] toAdd = methodDecl2.annotations; // this is what to add
// // abits = toAdd[0].resolvedType.getAnnotationTagBits();
// System.err.println("Has: "+currentlyHas+"    toAdd: "+toAdd);
//
// // fix me? should check if it already has the annotation
// //Annotation abefore[] = sourceType.scope.referenceContext.annotations;
// Annotation[] newset = new
// Annotation[(currentlyHas==null?0:currentlyHas.length)+1];
// System.arraycopy(toAdd,0,newset,0,toAdd.length);
// if (currentlyHas!=null) {
// System.arraycopy(currentlyHas,0,newset,1,currentlyHas.length);
// }
// methodDecl.annotations = newset;
// System.err.println("New set on "+CharOperation.charToString(sourceMb.selector)
// +" is "+newset);
// } else
// System.err.println("NO MATCH");
// }
// }
// }
// }
// }

// commented out, supplied as info on how to manipulate annotations in an
// eclipse world
//
// public void doDeclareAnnotationOnFields() {
// Collection daofs = factory.getDeclareAnnotationOnFields();
// if (daofs!=null && daofs.size()>0 && !(sourceType instanceof
// BinaryTypeBinding)) {
// System.err.println("Going through the fields on "+sourceType.debugName()+
// " looking for DECA matches");
// // We better take a look through them...
// for (Iterator iter = daofs.iterator(); iter.hasNext();) {
// DeclareAnnotation element = (DeclareAnnotation) iter.next();
// System.err.println("Processing deca "+element+" on "+sourceType.debugName()+
// "  "+getType(sourceType.compoundName).debugName()+"  "
// +(sourceType instanceof BinaryTypeBinding));
//
// ReferenceBinding rbb = getType(sourceType.compoundName);
// // fix me? should iterate the other way round, over the methods then over the
// decas
// sourceType.fields(); // resolve the bloody things
// FieldBinding sourceFbs[] = sourceType.fields;
// for (int i = 0; i < sourceFbs.length; i++) {
// FieldBinding sourceFb = sourceFbs[i];
// //FieldBinding fbbbb =
// ((SourceTypeBinding)rbb).getgetExactMethod(sourceMb.selector
// ,sourceMb.parameters);
//
// System.err.println("Checking "+sourceFb+" ... declaringclass="+sourceFb.
// declaringClass.debugName()+" rbb="+rbb.debugName());
//
// ResolvedMember rm = null;
// rm = EclipseFactory.makeResolvedMember(sourceFb);
// if (element.matches(rm,factory.getWorld())) {
// System.err.println("MATCH");
//
// // Determine the set of annotations that are currently on the field
// ReferenceBinding rb = getType(sourceType.compoundName);
// // TypeBinding tb = factory.makeTypeBinding(decA.getAspect());
// FieldBinding fb = ((SourceTypeBinding)rb).getField(sourceFb.name,true);
// //long abits = mbs[0].getAnnotationTagBits(); // ensure resolved
// TypeDeclaration typeDecl =
// ((SourceTypeBinding)sourceFb.declaringClass).scope.referenceContext;
// FieldDeclaration fd = typeDecl.declarationOf(sourceFb);
// //AbstractMethodDeclaration methodDecl = typeDecl.declarationOf(sourceMb);
// Annotation[] currentlyHas = fd.annotations; // this is what to add
// //abits = toAdd[0].resolvedType.getAnnotationTagBits();
//
// // Determine the annotations to add to that method
// TypeBinding tb = factory.makeTypeBinding(element.getAspect());
// MethodBinding[] aspectMbs =
// ((SourceTypeBinding)tb).getMethods(element.getAnnotationMethod
// ().toCharArray());
// long abits = aspectMbs[0].getAnnotationTagBits(); // ensure resolved
// TypeDeclaration typeDecl2 =
// ((SourceTypeBinding)aspectMbs[0].declaringClass).scope.referenceContext;
// AbstractMethodDeclaration methodDecl2 =
// typeDecl2.declarationOf(aspectMbs[0]);
// Annotation[] toAdd = methodDecl2.annotations; // this is what to add
// // abits = toAdd[0].resolvedType.getAnnotationTagBits();
// System.err.println("Has: "+currentlyHas+"    toAdd: "+toAdd);
//
// // fix me? check if it already has the annotation
//
//
// //Annotation abefore[] = sourceType.scope.referenceContext.annotations;
// Annotation[] newset = new
// Annotation[(currentlyHas==null?0:currentlyHas.length)+1];
// System.arraycopy(toAdd,0,newset,0,toAdd.length);
// if (currentlyHas!=null) {
// System.arraycopy(currentlyHas,0,newset,1,currentlyHas.length);
// }
// fd.annotations = newset;
// System.err.println("New set on "+CharOperation.charToString(sourceFb.name)+
// " is "+newset);
// } else
// System.err.println("NO MATCH");
// }
//
// }
// }
TOP

Related Classes of org.aspectj.ajdt.internal.compiler.lookup.AjLookupEnvironment

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.