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

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

There is a newer version: 1.9.3.RC1
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 - 2025 Weber Informatics LLC | Privacy Policy