/* *******************************************************************
* Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
* All rights reserved.
* This program and the accompanying materials are made available
* under the terms of the Common Public License v1.0
* which accompanies this distribution and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* PARC initial implementation
* ******************************************************************/
package org.aspectj.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.ast.AspectDeclaration;
import org.aspectj.ajdt.internal.compiler.ast.PointcutDeclaration;
import org.aspectj.bridge.IMessage;
import org.aspectj.bridge.MessageUtil;
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.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.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.AnnotationX;
import org.aspectj.weaver.AsmRelationshipProvider;
import org.aspectj.weaver.ConcreteTypeMunger;
import org.aspectj.weaver.FakeAnnotation;
import org.aspectj.weaver.ReferenceType;
import org.aspectj.weaver.ResolvedType;
import org.aspectj.weaver.TypeVariable;
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.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 List pendingTypesToWeave = new ArrayList();
// 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 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() {
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.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 typesToProcess = new ArrayList();
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);
}
}
while (typesToProcess.size()>0) {
// removes types from the list as they are processed...
collectAllITDsAndDeclares((SourceTypeBinding)typesToProcess.get(0),typesToProcess);
}
factory.finishTypeMungers();
// now do weaving
Collection typeMungers = factory.getTypeMungers();
Collection declareParents = factory.getDeclareParents();
Collection 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();
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);
}
}
while (typesToProcess.size()>0) {
// A side effect of weaveIntertypes() is that the processed type is removed from the collection
weaveIntertypes(typesToProcess,(SourceTypeBinding)typesToProcess.get(0),typeMungers,declareParents,declareAnnotationOnTypes);
}
} else {
// Order isn't important
for (int i = lastCompletedUnitIndex + 1; i <= lastUnitIndex; i++) {
//System.err.println("Working on "+new String(units[i].getFileName()));
weaveInterTypeDeclarations(units[i].scope, typeMungers, declareParents,declareAnnotationOnTypes);
}
}
for (int i = lastCompletedUnitIndex +1; i<=lastUnitIndex; i++) {
SourceTypeBinding[] b = units[i].scope.topLevelTypes;
for (int j = 0; j < b.length; j++) {
verifyAnyTypeParametersMeetBounds(b[j]);
}
}
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;
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);
// 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);
yetToProcess.remove(sourceType);
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?
*/
private void weaveIntertypes(List typesToProcess,SourceTypeBinding typeToWeave,Collection typeMungers,
Collection declareParents,Collection declareAnnotationOnTypes) {
// 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);
}
// 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);
}
}
weaveInterTypeDeclarations(typeToWeave,typeMungers,declareParents,declareAnnotationOnTypes,false);
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);
if (typeX.getSuperclass().isAspect() && !typeX.getSuperclass().isExposedToWeaver()) {
factory.getWorld().getCrosscuttingMembersSet().addOrReplaceAspect(typeX.getSuperclass());
}
}
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) {
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);
}
}
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;
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, Collection typeMungers,
Collection declareParents, Collection declareAnnotationOnTypes) {
for (int i = 0, length = unit.topLevelTypes.length; i < length; i++) {
weaveInterTypeDeclarations(unit.topLevelTypes[i], typeMungers, declareParents, declareAnnotationOnTypes,false);
}
}
private void weaveInterTypeDeclarations(SourceTypeBinding sourceType) {
if (!factory.areTypeMungersFinished()) {
if (!pendingTypesToWeave.contains(sourceType)) pendingTypesToWeave.add(sourceType);
} else {
weaveInterTypeDeclarations(sourceType, factory.getTypeMungers(), factory.getDeclareParents(), factory.getDeclareAnnotationOnTypes(),true);
}
}
private void weaveInterTypeDeclarations(SourceTypeBinding sourceType, Collection typeMungers,
Collection declareParents, Collection declareAnnotationOnTypes, boolean skipInners) {
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();
// 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();
// 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 decpToRepeat = new ArrayList();
List decaToRepeat = new ArrayList();
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 (Iterator i = declareParents.iterator(); i.hasNext();) {
DeclareParents decp = (DeclareParents)i.next();
boolean didSomething = doDeclareParents(decp, sourceType);
if (didSomething) {
anyNewParents = true;
} else {
if (!decp.getChild().isStarAnnotation()) decpToRepeat.add(decp);
}
}
for (Iterator i = declareAnnotationOnTypes.iterator(); i.hasNext();) {
DeclareAnnotation deca = (DeclareAnnotation)i.next();
boolean didSomething = doDeclareAnnotations(deca, sourceType,true);
if (didSomething) {
anyNewAnnotations = true;
} else {
if (!deca.getTypePattern().isStar()) decaToRepeat.add(deca);
}
}
// now lets loop over and over until we have done all we can
while ((anyNewAnnotations || anyNewParents) &&
(!decpToRepeat.isEmpty() || !decaToRepeat.isEmpty())) {
anyNewParents = anyNewAnnotations = false;
List forRemoval = new ArrayList();
for (Iterator i = decpToRepeat.iterator(); i.hasNext();) {
DeclareParents decp = (DeclareParents)i.next();
boolean didSomething = doDeclareParents(decp, sourceType);
if (didSomething) {
anyNewParents = true;
forRemoval.add(decp);
}
}
decpToRepeat.removeAll(forRemoval);
forRemoval = new ArrayList();
for (Iterator i = declareAnnotationOnTypes.iterator(); i.hasNext();) {
DeclareAnnotation deca = (DeclareAnnotation)i.next();
boolean didSomething = doDeclareAnnotations(deca, sourceType,false);
if (didSomething) {
anyNewAnnotations = true;
forRemoval.add(deca);
}
}
decaToRepeat.removeAll(forRemoval);
}
for (Iterator 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);
}
}
onType.checkInterTypeMungers();
for (Iterator i = onType.getInterTypeMungers().iterator(); i.hasNext();) {
EclipseTypeMunger munger = (EclipseTypeMunger) i.next();
//System.out.println("applying: " + munger + " to " + new String(sourceType.sourceName));
munger.munge(sourceType,onType);
}
// 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);
}
}
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);
List newParents = declareParents.findMatchingNewParents(factory.fromEclipse(sourceType),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 {
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);
// TODO asc determine if there really is a problem here (see comment below)
// ClassCastException here means we probably have either a parameterized type or a raw type, we need the
// commented out code to get it to work ... currently uncommented because I've not seen a case where its
// required yet ...
SourceTypeBinding stb = (SourceTypeBinding)tb;
MethodBinding[] mbs = stb.getMethods(decA.getAnnotationMethod().toCharArray());
long abits = mbs[0].getAnnotationTagBits(); // ensure resolved
TypeDeclaration typeDecl = ((SourceTypeBinding)mbs[0].declaringClass).scope.referenceContext;
AbstractMethodDeclaration methodDecl = typeDecl.declarationOf(mbs[0]);
Annotation[] toAdd = methodDecl.annotations; // this is what to add
abits = toAdd[0].resolvedType.getAnnotationTagBits();
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;
String name = new String(theAnnotationType.qualifiedPackageName())+"."+new String(theAnnotationType.sourceName());
String sig = new String(theAnnotationType.signature());
if (theTargetType.hasAnnotation(UnresolvedType.forSignature(sig))) {
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 AnnotationX(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);
return true;
}
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);
}
}
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 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");
// }
//
// }
// }