All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.aspectj.ajdt.internal.compiler.lookup.AjLookupEnvironment Maven / Gradle / Ivy

Go to download

AspectJ tools most notably contains the AspectJ compiler (AJC). AJC applies aspects to Java classes during compilation, fully replacing Javac for plain Java classes and also compiling native AspectJ or annotation-based @AspectJ syntax. Furthermore, AJC can weave aspects into existing class files in a post-compile binary weaving step. This library is a superset of AspectJ weaver and hence also of AspectJ runtime.

There is a newer version: 1.9.22.1
Show newest version
/* *******************************************************************
 * 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 v 2.0
 * which accompanies this distribution and is available at
 * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.txt
 *
 * Contributors:
 *     PARC     initial implementation
 * ******************************************************************/

package org.aspectj.ajdt.internal.compiler.lookup;

import java.lang.reflect.Modifier;
import java.util.*;

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.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.CompilationUnitDeclaration;
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.MissingTypeBinding;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ModuleBinding;
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.RawTypeBinding;
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.SourceTypeCollisionException;
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.Declare;
import org.aspectj.weaver.patterns.DeclareAnnotation;
import org.aspectj.weaver.patterns.DeclareParents;

import static org.aspectj.bridge.context.CompilationAndWeavingContext.*;

/**
 * Overrides the default Eclipse {@link LookupEnvironment} for two purposes:
 * 
    *
  1. * To provide some additional phases to {@code completeTypeBindings}, that weave declare parents and inter-type * declarations at the correct time. *
  2. *
  3. * To intercept loading of new binary types, to ensure they will have declare parents and inter-type declarations * woven when appropriate. *
  4. *
* * @author Jim Hugunin */ public class AjLookupEnvironment extends LookupEnvironment implements AnonymousClassCreationListener { public EclipseFactory factory = null; // private boolean builtInterTypesAndPerClauses = false; private final 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 e.g., // 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); } public AjLookupEnvironment(LookupEnvironment env, ModuleBinding moduleBinding) { super(env, moduleBinding); } // ??? duplicates some of super's code @Override public void completeTypeBindings() { AsmManager.setCompletingTypeBindings(true); ContextToken completeTypeBindingsToken = enteringPhase(COMPLETING_TYPE_BINDINGS, ""); // builtInterTypesAndPerClauses = false; // pendingTypesToWeave = new ArrayList(); stepCompleted = CompleteTypeBindingsSteps.CONNECT_TYPE_HIERARCHY; for (int i = lastCompletedUnitIndex + 1; i <= lastUnitIndex; i++) { ContextToken tok = enteringPhase(CHECK_AND_SET_IMPORTS, units[i].compilationResult.fileName); units[i].scope.checkAndSetImports(); leavingPhase(tok); } stepCompleted = CompleteTypeBindingsSteps.CHECK_AND_SET_IMPORTS; for (int i = lastCompletedUnitIndex + 1; i <= lastUnitIndex; i++) { ContextToken tok = enteringPhase(CONNECTING_TYPE_HIERARCHY1, units[i].compilationResult.fileName); units[i].scope.connectTypeHierarchy(); leavingPhase(tok); } stepCompleted = CompleteTypeBindingsSteps.CONNECT_TYPE_HIERARCHY; for (int i = lastCompletedUnitIndex + 1; i <= lastUnitIndex; i++) { ContextToken tok = enteringPhase(CONNECTING_TYPE_HIERARCHY2, units[i].compilationResult.fileName); units[i].scope.integrateAnnotationsInHierarchy(); leavingPhase(tok); } stepCompleted = CompleteTypeBindingsSteps.INTEGRATE_ANNOTATIONS_IN_HIERARCHY; for (int i = lastCompletedUnitIndex + 1; i <= lastUnitIndex; i++) { ContextToken tok = enteringPhase(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(); 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 (SourceTypeBinding sourceTypeBinding : b) { factory.addSourceTypeBinding(sourceTypeBinding, units[i]); if (sourceTypeBinding.superclass instanceof MissingTypeBinding) { // e37: Undoing the work in ClassScope.connectSuperClass() as it will lead to cascade errors // TODO allow MissingTypeBinding through here and cope with it in all situations later? sourceTypeBinding.superclass = units[i].scope.getJavaLangObject(); } } } // 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<>(); List aspectsToProcess = new ArrayList<>(); for (int i = lastCompletedUnitIndex + 1; i <= lastUnitIndex; i++) { CompilationUnitScope cus = units[i].scope; SourceTypeBinding[] stbs = cus.topLevelTypes; for (SourceTypeBinding stb : stbs) { 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.isEmpty()) { // removes types from the list as they are processed... collectAllITDsAndDeclares(typesToProcess.get(0), typesToProcess); } factory.finishTypeMungers(); // now do weaving final List typeMungers = factory.getTypeMungers(); final List declareParents = factory.getDeclareParents(); final List 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.isEmpty() || !declareAnnotationOnTypes.isEmpty(); // DECAT if (typeProcessingOrderIsImportant) { typesToProcess = new ArrayList<>(); for (int i = lastCompletedUnitIndex + 1; i <= lastUnitIndex; i++) { CompilationUnitScope cus = units[i].scope; SourceTypeBinding[] stbs = cus.topLevelTypes; Collections.addAll(typesToProcess, stbs); } List typesToProcessCopy = new ArrayList<>(typesToProcess); while (!typesToProcess.isEmpty()) { // A side effect of weaveIntertypes() is that the processed type is removed from the collection weaveIntertypes( typesToProcess, typesToProcess.get(0), typeMungers, declareParents, declareAnnotationOnTypes, 1 // do declare parents ); } typesToProcess = typesToProcessCopy; while (!typesToProcess.isEmpty()) { // A side effect of weaveIntertypes() is that the processed type is removed from the collection weaveIntertypes( typesToProcess, typesToProcess.get(0), typeMungers, declareParents, declareAnnotationOnTypes, 2 // do ITDs ); } } 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 (SourceTypeBinding sourceTypeBinding : b) { ContextToken tok = enteringPhase(RESOLVING_POINTCUT_DECLARATIONS, sourceTypeBinding.sourceName); resolvePointcutDeclarations(sourceTypeBinding.scope); leavingPhase(tok); } } for (int i = lastCompletedUnitIndex + 1; i <= lastUnitIndex; i++) { SourceTypeBinding[] b = units[i].scope.topLevelTypes; for (SourceTypeBinding sourceTypeBinding : b) { ContextToken tok = enteringPhase(ADDING_DECLARE_WARNINGS_AND_ERRORS, sourceTypeBinding.sourceName); addAdviceLikeDeclares(sourceTypeBinding.scope); leavingPhase(tok); } } for (int i = lastCompletedUnitIndex + 1; i <= lastUnitIndex; i++) { units[i] = null; // release unnecessary reference to the parsed unit } stepCompleted = CompleteTypeBindingsSteps.BUILD_FIELDS_AND_METHODS; lastCompletedUnitIndex = lastUnitIndex; AsmManager.setCompletingTypeBindings(false); factory.getWorld().getCrosscuttingMembersSet().verify(); leavingPhase(completeTypeBindingsToken); if (isProcessingAnnotations) { throw new SourceTypeCollisionException(); // TODO(yushkovskiy): temporary solution; forcing to recompile units to insert mungers into types } } /** * For any given sourcetypebinding, this method checks that if it is a parameterized aspect, 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 isn't 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 it is 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 = enteringPhase(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 (ReferenceBinding memberType : memberTypes) { SourceTypeBinding rb = (SourceTypeBinding) memberType; if (!rb.superclass().equals(sourceType)) { doSupertypesFirst(rb.superclass(), yetToProcess); } } buildInterTypeAndPerClause(sourceType.scope); addCrosscuttingStructures(sourceType.scope); 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 typesToProcess, SourceTypeBinding typeToWeave, List typeMungers, List declareParents, List 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 (ReferenceBinding binding : interfaceTypes) { 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 ); } else if ( binding instanceof ParameterizedTypeBinding && (((ParameterizedTypeBinding) binding).type instanceof SourceTypeBinding) && typesToProcess.contains(((ParameterizedTypeBinding) binding).type) ) { weaveIntertypes( typesToProcess, (SourceTypeBinding) ((ParameterizedTypeBinding) binding).type, typeMungers, declareParents, declareAnnotationOnTypes, mode ); } } weaveInterTypeDeclarations( typeToWeave, typeMungers, declareParents, declareAnnotationOnTypes, false, mode ); typesToProcess.remove(typeToWeave); } private void doPendingWeaves() { for (SourceTypeBinding t : pendingTypesToWeave) { ContextToken tok = enteringPhase(WEAVING_INTERTYPE_DECLARATIONS, t.sourceName); weaveInterTypeDeclarations(t); 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 (ReferenceBinding memberType : memberTypes) { addAdviceLikeDeclares(((SourceTypeBinding) memberType).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 (ReferenceBinding memberType : memberTypes) { addCrosscuttingStructures(((SourceTypeBinding) memberType).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 (AbstractMethodDeclaration method : methods) { if (method instanceof PointcutDeclaration) { hasPointcuts = true; if (!initializedMethods) { sourceType.methods(); // force initialization initializedMethods = true; } ((PointcutDeclaration) method).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 (ReferenceBinding memberType : memberTypes) { resolvePointcutDeclarations(((SourceTypeBinding) memberType).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 (ReferenceBinding memberType : memberTypes) { buildInterTypeAndPerClause(((SourceTypeBinding) memberType).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; } return CharOperation.equals("Aspect".toCharArray(), qtr.tokens[4]); } } } return false; } private void weaveInterTypeDeclarations(CompilationUnitScope unit, List typeMungers, List declareParents, List 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 ctms = factory.getWorld() .getCrosscuttingMembersSet() .getTypeMungersOfKind(ResolvedTypeMunger.InnerClass); List innerTypeMungers = new ArrayList(); 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 typeMungers, List declareParents, List declareAnnotationOnTypes, boolean skipInners, int mode) { ContextToken tok = enteringPhase(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 isn't 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); 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 (Map.Entry entry : dangerousInterfaces.entrySet()) { ResolvedType interfaceType = 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 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 (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 let's 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 (ConcreteTypeMunger typeMunger : typeMungers) { EclipseTypeMunger munger = (EclipseTypeMunger) typeMunger; 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 (ConcreteTypeMunger concreteTypeMunger : onType.getInterTypeMungers()) { EclipseTypeMunger munger = (EclipseTypeMunger) concreteTypeMunger; 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) { leavingPhase(tok); return; } ReferenceBinding[] memberTypes = sourceType.memberTypes; for (ReferenceBinding memberType : memberTypes) { if (memberType instanceof SourceTypeBinding) { weaveInterTypeDeclarations((SourceTypeBinding) memberType, typeMungers, declareParents, declareAnnotationOnTypes, false, mode); } } 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) { List previouslyAppliedMungers = onType.getWeaverState().getTypeMungers(onType); for (ConcreteTypeMunger m : previouslyAppliedMungers) { 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 = enteringPhase(PROCESSING_DECLARE_PARENTS, sourceType.sourceName); ResolvedType resolvedSourceType = factory.fromEclipse(sourceType); List newParents = declareParents.findMatchingNewParents(resolvedSourceType, false); if (!newParents.isEmpty()) { for (ResolvedType parent : newParents) { 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); } } leavingPhase(tok); return true; } 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"); } StringBuilder sb = new StringBuilder(); sb.append("{"); for (Iterator iter = s.iterator(); iter.hasNext(); ) { String element = 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 = enteringPhase(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, it's 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) { 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)) { 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); } // Don't 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) { leavingPhase(tok); return false; } theTargetType.addAnnotation(new BcelAnnotation(new FakeAnnotation(name, sig, (abits & TagBits.AnnotationRuntimeRetention) != 0), factory.getWorld())); leavingPhase(tok); return true; } Annotation[] currentAnnotations = sourceType.scope.referenceContext.annotations; if (currentAnnotations != null) { for (Annotation annotation : currentAnnotations) { 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)) { 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. 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); } // Don't 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 ); } } */ } 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()); final Annotation[] abefore = sourceType.scope.referenceContext.annotations; final 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; if ((sourceType.tagBits & TagBits.AnnotationResolved) != 0) { sourceType.tagBits = sourceType.tagBits - TagBits.AnnotationResolved; } 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 (ResolvedMember method : methods) { if (method.getName().equals(nameToLookFor)) { decaMethod = method; 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 don't 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. } // Due to e37 switching to MethodVerifier15 for everything, it is important added types are correctly raw or not. // For example, if Comparable is used in generic form compareTo(T) will be used to check methods against in the // verifier rather than compareTo(Object) if (!factory.getWorld().isInJava5Mode()) { parentBinding = (ReferenceBinding) convertToRawType(parentBinding, false /*do not force conversion of enclosing types*/); } else if (sourceType.isGenericType()) { RawTypeBinding rawTargetType = (RawTypeBinding) convertToRawType(sourceType, false); if (rawTargetType != null) { // assert: don't need to 'rememberTypeHierarchy' because the class file is constructed based on the generic type if (parentBinding.isClass()) { rawTargetType.superclass = parentBinding; } else { ReferenceBinding[] oldI = rawTargetType.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; } rawTargetType.superInterfaces = newI; } } // TODO what about parameterized types? } 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) { if (rt.isRawType()) { rt = rt.getGenericType(); } 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(), "added interface " + parent.getName()}, null, null); } } private final List pendingTypesToFinish = new ArrayList<>(); boolean inBinaryTypeCreationAndWeaving = false; boolean processingTheQueue = false; @Override 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.isEmpty()) { processingTheQueue = true; while (!pendingTypesToFinish.isEmpty()) { BinaryTypeBinding nextVictim = 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 */ @Override public void anonymousTypeBindingCreated(LocalTypeBinding aBinding) { factory.addSourceTypeBinding(aBinding, null); } @Override public void buildTypeBindings(CompilationUnitDeclaration unit, AccessRestriction accessRestriction) { if (this.isProcessingAnnotations && hasAspectDeclarations(unit)) { throw new SourceTypeCollisionException(); } super.buildTypeBindings(unit, accessRestriction); } private static boolean hasAspectDeclarations(CompilationUnitDeclaration unit) { if (unit.types == null) return false; for (int j = 0; j < unit.types.length; j++) { if (unit.types[j] instanceof AspectDeclaration) { return true; } } return false; } @Override public void reset() { this.factory.cleanup(); super.reset(); } @Override public LookupEnvironment wrapInModuleEnvironment(ModuleBinding moduleBinding) { AjLookupEnvironment newAjLookupEnvironment = new AjLookupEnvironment(this, moduleBinding); newAjLookupEnvironment.factory = this.factory; return newAjLookupEnvironment; } // 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"); } } } } */ }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy