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

org.aspectj.weaver.bcel.BcelTypeMunger 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
 *     Alexandre Vasseur    @AspectJ ITDs
 * ******************************************************************/

package org.aspectj.weaver.bcel;

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

import org.aspectj.apache.bcel.Constants;
import org.aspectj.apache.bcel.classfile.ClassFormatException;
import org.aspectj.apache.bcel.classfile.ConstantPool;
import org.aspectj.apache.bcel.classfile.Signature;
import org.aspectj.apache.bcel.classfile.annotation.AnnotationGen;
import org.aspectj.apache.bcel.generic.FieldGen;
import org.aspectj.apache.bcel.generic.InstructionBranch;
import org.aspectj.apache.bcel.generic.InstructionConstants;
import org.aspectj.apache.bcel.generic.InstructionFactory;
import org.aspectj.apache.bcel.generic.InstructionHandle;
import org.aspectj.apache.bcel.generic.InstructionList;
import org.aspectj.apache.bcel.generic.InvokeInstruction;
import org.aspectj.apache.bcel.generic.Type;
import org.aspectj.asm.AsmManager;
import org.aspectj.asm.IProgramElement;
import org.aspectj.bridge.IMessage;
import org.aspectj.bridge.ISourceLocation;
import org.aspectj.bridge.Message;
import org.aspectj.bridge.MessageUtil;
import org.aspectj.bridge.WeaveMessage;
import org.aspectj.bridge.context.CompilationAndWeavingContext;
import org.aspectj.bridge.context.ContextToken;
import org.aspectj.weaver.AjcMemberMaker;
import org.aspectj.weaver.AnnotationAJ;
import org.aspectj.weaver.AnnotationOnTypeMunger;
import org.aspectj.weaver.BCException;
import org.aspectj.weaver.ConcreteTypeMunger;
import org.aspectj.weaver.Member;
import org.aspectj.weaver.MemberUtils;
import org.aspectj.weaver.MethodDelegateTypeMunger;
import org.aspectj.weaver.NameMangler;
import org.aspectj.weaver.NewConstructorTypeMunger;
import org.aspectj.weaver.NewFieldTypeMunger;
import org.aspectj.weaver.NewMemberClassTypeMunger;
import org.aspectj.weaver.NewMethodTypeMunger;
import org.aspectj.weaver.NewParentTypeMunger;
import org.aspectj.weaver.PerObjectInterfaceTypeMunger;
import org.aspectj.weaver.PrivilegedAccessMunger;
import org.aspectj.weaver.ResolvedMember;
import org.aspectj.weaver.ResolvedMemberImpl;
import org.aspectj.weaver.ResolvedType;
import org.aspectj.weaver.ResolvedTypeMunger;
import org.aspectj.weaver.Shadow;
import org.aspectj.weaver.TypeVariableReference;
import org.aspectj.weaver.UnresolvedType;
import org.aspectj.weaver.WeaverMessages;
import org.aspectj.weaver.WeaverStateInfo;
import org.aspectj.weaver.World;
import org.aspectj.weaver.model.AsmRelationshipProvider;
import org.aspectj.weaver.patterns.DeclareAnnotation;
import org.aspectj.weaver.patterns.Pointcut;

public class BcelTypeMunger extends ConcreteTypeMunger {

	public BcelTypeMunger(ResolvedTypeMunger munger, ResolvedType aspectType) {
		super(munger, aspectType);
	}

	@Override
	public String toString() {
		return "(BcelTypeMunger " + getMunger() + ")";
	}

	@Override
	public boolean shouldOverwrite() {
		return false;
	}

	public boolean munge(BcelClassWeaver weaver) {
		ContextToken tok = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.MUNGING_WITH, this);
		boolean changed = false;
		boolean worthReporting = true;

		if (weaver.getWorld().isOverWeaving()) {
			WeaverStateInfo typeWeaverState = weaver.getLazyClassGen().getType().getWeaverState();
			if (typeWeaverState != null && typeWeaverState.isAspectAlreadyApplied(getAspectType())) {
				return false;
			}
		}

		if (munger.getKind() == ResolvedTypeMunger.Field) {
			changed = mungeNewField(weaver, (NewFieldTypeMunger) munger);
		} else if (munger.getKind() == ResolvedTypeMunger.Method) {
			changed = mungeNewMethod(weaver, (NewMethodTypeMunger) munger);
		} else if (munger.getKind() == ResolvedTypeMunger.InnerClass) {
			changed = mungeNewMemberType(weaver, (NewMemberClassTypeMunger) munger);
		} else if (munger.getKind() == ResolvedTypeMunger.MethodDelegate2) {
			changed = mungeMethodDelegate(weaver, (MethodDelegateTypeMunger) munger);
		} else if (munger.getKind() == ResolvedTypeMunger.FieldHost) {
			changed = mungeFieldHost(weaver, (MethodDelegateTypeMunger.FieldHostTypeMunger) munger);
		} else if (munger.getKind() == ResolvedTypeMunger.PerObjectInterface) {
			changed = mungePerObjectInterface(weaver, (PerObjectInterfaceTypeMunger) munger);
			worthReporting = false;
		} else if (munger.getKind() == ResolvedTypeMunger.PerTypeWithinInterface) {
			// PTWIMPL Transform the target type (add the aspect instance field)
			changed = mungePerTypeWithinTransformer(weaver);
			worthReporting = false;
		} else if (munger.getKind() == ResolvedTypeMunger.PrivilegedAccess) {
			changed = mungePrivilegedAccess(weaver, (PrivilegedAccessMunger) munger);
			worthReporting = false;
		} else if (munger.getKind() == ResolvedTypeMunger.Constructor) {
			changed = mungeNewConstructor(weaver, (NewConstructorTypeMunger) munger);
		} else if (munger.getKind() == ResolvedTypeMunger.Parent) {
			changed = mungeNewParent(weaver, (NewParentTypeMunger) munger);
		} else if (munger.getKind() == ResolvedTypeMunger.AnnotationOnType) {
			changed = mungeNewAnnotationOnType(weaver, (AnnotationOnTypeMunger) munger);
			worthReporting = false;
		} else {
			throw new RuntimeException("unimplemented");
		}

		if (changed && munger.changesPublicSignature()) {
			WeaverStateInfo info = weaver.getLazyClassGen().getOrCreateWeaverStateInfo(weaver.getReweavableMode());
			info.addConcreteMunger(this);
		}

		if (changed && worthReporting) {
			ResolvedType declaringAspect = null;
			AsmManager model = ((BcelWorld) getWorld()).getModelAsAsmManager();
			if (model != null) {
				if (munger instanceof NewParentTypeMunger) {
					NewParentTypeMunger nptMunger = (NewParentTypeMunger) munger;
					declaringAspect = nptMunger.getDeclaringType();
					if (declaringAspect.isParameterizedOrGenericType()) {
						declaringAspect = declaringAspect.getRawType();
					}
					ResolvedType thisAspect = getAspectType();
					AsmRelationshipProvider.addRelationship(model, weaver.getLazyClassGen().getType(), munger, thisAspect);

					// Add a relationship on the actual declaring aspect too
					if (!thisAspect.equals(declaringAspect)) {
						// Might be the case the declaring aspect is generic and thisAspect is parameterizing it. In that case
						// record the actual parameterizations

						ResolvedType target = weaver.getLazyClassGen().getType();
						ResolvedType newParent = nptMunger.getNewParent();
						IProgramElement thisAspectNode = model.getHierarchy().findElementForType(thisAspect.getPackageName(),
								thisAspect.getClassName());
						Map> declareParentsMap = thisAspectNode.getDeclareParentsMap();
						if (declareParentsMap == null) {
							declareParentsMap = new HashMap<>();
							thisAspectNode.setDeclareParentsMap(declareParentsMap);
						}
						String tname = target.getName();
						String pname = newParent.getName();
						List newparents = declareParentsMap.computeIfAbsent(tname, k -> new ArrayList<>());
						newparents.add(pname);
						AsmRelationshipProvider.addRelationship(model, weaver.getLazyClassGen().getType(), munger, declaringAspect);
					}
				} else {
					declaringAspect = getAspectType();
					AsmRelationshipProvider.addRelationship(model, weaver.getLazyClassGen().getType(), munger, declaringAspect);
				}
			}
		}

		// TAG: WeavingMessage
		if (changed && worthReporting && munger != null && !weaver.getWorld().getMessageHandler().isIgnoring(IMessage.WEAVEINFO)) {
			String tName = weaver.getLazyClassGen().getType().getSourceLocation().getSourceFile().getName();
			if (tName.contains("no debug info available")) {
				tName = "no debug info available";
			} else {
				tName = getShortname(weaver.getLazyClassGen().getType().getSourceLocation().getSourceFile().getPath());
			}
			String fName = getShortname(getAspectType().getSourceLocation().getSourceFile().getPath());
			if (munger.getKind().equals(ResolvedTypeMunger.Parent)) {
				// This message could come out of AjLookupEnvironment.addParent
				// if doing parents munging at compile time only...
				NewParentTypeMunger parentTM = (NewParentTypeMunger) munger;
				if (parentTM.isMixin()) {
					weaver.getWorld()
							.getMessageHandler()
							.handleMessage(
									WeaveMessage.constructWeavingMessage(WeaveMessage.WEAVEMESSAGE_MIXIN, new String[] {
											parentTM.getNewParent().getName(), fName, weaver.getLazyClassGen().getType().getName(),
											tName }, weaver.getLazyClassGen().getClassName(), getAspectType().getName()));
				} else {
					if (parentTM.getNewParent().isInterface()) {
						weaver.getWorld()
								.getMessageHandler()
								.handleMessage(
										WeaveMessage.constructWeavingMessage(WeaveMessage.WEAVEMESSAGE_DECLAREPARENTSIMPLEMENTS,
												new String[] { weaver.getLazyClassGen().getType().getName(), tName,
														parentTM.getNewParent().getName(), fName }, weaver.getLazyClassGen()
														.getClassName(), getAspectType().getName()));
					} else {
						weaver.getWorld()
								.getMessageHandler()
								.handleMessage(
										WeaveMessage.constructWeavingMessage(WeaveMessage.WEAVEMESSAGE_DECLAREPARENTSEXTENDS,
												new String[] { weaver.getLazyClassGen().getType().getName(), tName,
														parentTM.getNewParent().getName(), fName }));
						// TAG: WeavingMessage DECLARE PARENTS: EXTENDS
						// reportDeclareParentsMessage(WeaveMessage.
						// WEAVEMESSAGE_DECLAREPARENTSEXTENDS,sourceType,parent);

					}
				}
			} else if (munger.getKind().equals(ResolvedTypeMunger.FieldHost)) {
				// hidden
			} else {
				ResolvedMember declaredSig = munger.getSignature();
				String fromString = fName + ":'" + declaredSig + "'";
				// if (declaredSig==null) declaredSig= munger.getSignature();
				String kindString = munger.getKind().toString().toLowerCase();
				if (kindString.equals("innerclass")) {
					kindString = "member class";
					fromString = fName;
				}
				weaver.getWorld()
						.getMessageHandler()
						.handleMessage(
								WeaveMessage.constructWeavingMessage(WeaveMessage.WEAVEMESSAGE_ITD, new String[] {
										weaver.getLazyClassGen().getType().getName(), tName, kindString, getAspectType().getName(),
										fromString }, weaver.getLazyClassGen().getClassName(), getAspectType().getName()));
			}
		}

		CompilationAndWeavingContext.leavingPhase(tok);
		return changed;
	}

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

	private boolean mungeNewAnnotationOnType(BcelClassWeaver weaver, AnnotationOnTypeMunger munger) {
		// FIXME asc this has already been done up front, need to do it here too?
		try {
			BcelAnnotation anno = (BcelAnnotation) munger.getNewAnnotation();
			weaver.getLazyClassGen().addAnnotation(anno.getBcelAnnotation());
		} catch (ClassCastException cce) {
			throw new IllegalStateException("DiagnosticsFor318237: The typemunger "+munger+" contains an annotation of type "+
					munger.getNewAnnotation().getClass().getName()+" when it should be a BcelAnnotation",cce);
		}
		return true;
	}

	/**
	 * For a long time, AspectJ did not allow binary weaving of declare parents. This restriction is now lifted but could do with
	 * more testing!
	 */
	private boolean mungeNewParent(BcelClassWeaver weaver, NewParentTypeMunger typeTransformer) {
		LazyClassGen newParentTarget = weaver.getLazyClassGen();
		ResolvedType newParent = typeTransformer.getNewParent();

		boolean performChange = true;
		performChange = enforceDecpRule1_abstractMethodsImplemented(weaver, typeTransformer.getSourceLocation(), newParentTarget,
				newParent);
		performChange = enforceDecpRule2_cantExtendFinalClass(weaver, typeTransformer.getSourceLocation(), newParentTarget,
				newParent) && performChange;

		List methods = newParent.getMethodsWithoutIterator(false, true, false);
		for (ResolvedMember method : methods) {
			if (!method.getName().equals("")) {
				LazyMethodGen subMethod = findMatchingMethod(newParentTarget, method);
				// FIXME asc is this safe for all bridge methods?
				if (subMethod != null && !subMethod.isBridgeMethod()) {
					if (!(subMethod.isSynthetic() && method.isSynthetic())) {
						if (!(subMethod.isStatic() && subMethod.getName().startsWith("access$"))) {
							// ignore generated accessors
							performChange = enforceDecpRule3_visibilityChanges(weaver, newParent, method, subMethod)
									&& performChange;
							performChange = enforceDecpRule4_compatibleReturnTypes(weaver, method, subMethod) && performChange;
							performChange = enforceDecpRule5_cantChangeFromStaticToNonstatic(weaver,
									typeTransformer.getSourceLocation(), method, subMethod)
									&& performChange;
						}
					}
				}
			}
		}
		if (!performChange) {
			// A rule was violated and an error message already reported
			return false;
		}

		if (newParent.isClass()) {
			// Changing the supertype
			if (!attemptToModifySuperCalls(weaver, newParentTarget, newParent)) {
				return false;
			}
			newParentTarget.setSuperClass(newParent);
		} else {
			// Add a new interface
			newParentTarget.addInterface(newParent, getSourceLocation());
		}
		return true;
	}

	/**
	 * Rule 1: For the declare parents to be allowed, the target type must override and implement inherited abstract methods (if the
	 * type is not declared abstract)
	 */
	private boolean enforceDecpRule1_abstractMethodsImplemented(BcelClassWeaver weaver, ISourceLocation mungerLoc,
			LazyClassGen newParentTarget, ResolvedType newParent) {
		// Ignore abstract classes or interfaces
		if (newParentTarget.isAbstract() || newParentTarget.isInterface()) {
			return true;
		}
		boolean ruleCheckingSucceeded = true;
		List newParentMethods = newParent.getMethodsWithoutIterator(false, true, false);
		for (ResolvedMember newParentMethod : newParentMethods) {
			String newParentMethodName = newParentMethod.getName();
			// Ignore abstract ajc$interField prefixed methods
			if (newParentMethod.isAbstract() && !newParentMethodName.startsWith("ajc$interField")) {
				ResolvedMember discoveredImpl = null;
				List targetMethods = newParentTarget.getType().getMethodsWithoutIterator(false, true, false);
				for (ResolvedMember targetMethod : targetMethods) {
					if (!targetMethod.isAbstract() && targetMethod.getName().equals(newParentMethodName)) {
						String newParentMethodSig = newParentMethod.getParameterSignature(); // ([TT;)
						String targetMethodSignature = targetMethod.getParameterSignature(); // ([Ljava/lang/Object;)
						// could be a match
						if (targetMethodSignature.equals(newParentMethodSig)) {
							discoveredImpl = targetMethod;
						} else {
							// Does the erasure match? In which case a bridge method will be created later to
							// satisfy the abstract method
							if (targetMethod.hasBackingGenericMember()
									&& targetMethod.getBackingGenericMember().getParameterSignature().equals(newParentMethodSig)) {
								discoveredImpl = targetMethod;
							} else if (newParentMethod.hasBackingGenericMember()) {
 								if (newParentMethod.getBackingGenericMember().getParameterSignature().equals(targetMethodSignature)) { // newParentMethod.getBackingGenericMember().getParameterSignature gives: (Pjava/util/List;)  targetMethodSignature= (Ljava/util/List;)
									discoveredImpl = targetMethod;
								} else if (targetMethod instanceof BcelMethod) {
									// BcelMethod does not have backing generic member set (need to investigate why). For now, special case here:
									UnresolvedType[] targetMethodGenericParameterTypes = targetMethod.getGenericParameterTypes();
									if (targetMethodGenericParameterTypes !=null) {
										StringBuilder b = new StringBuilder("(");
										for (UnresolvedType p: targetMethodGenericParameterTypes) {
											b.append(p.getSignature());
										}
										b.append(')');
										if (b.toString().equals(newParentMethodSig)) {
											discoveredImpl = targetMethod;
										}
									}
								}
							}
						}
						if (discoveredImpl != null) {
							break;
						}
					}
				}
				if (discoveredImpl == null) {
					// didnt find a valid implementation, lets check the
					// ITDs on this type to see if they satisfy it
					boolean satisfiedByITD = false;
					for (ConcreteTypeMunger m : newParentTarget.getType().getInterTypeMungersIncludingSupers()) {
						if (m.getMunger() != null && m.getMunger().getKind() == ResolvedTypeMunger.Method) {
							ResolvedMember sig = m.getSignature();
							if (!Modifier.isAbstract(sig.getModifiers())) {
								// If the ITD shares a type variable with some target type, we need to tailor it
								// for that type
								if (m.isTargetTypeParameterized()) {
									ResolvedType genericOnType = getWorld().resolve(sig.getDeclaringType()).getGenericType();
									ResolvedType actualOccurrence = newParent.discoverActualOccurrenceOfTypeInHierarchy(genericOnType);
									if (actualOccurrence == null) {
									    // Handle the case where the ITD is onto the type targeted by the declare parents (PR478003)
										actualOccurrence = newParentTarget.getType().discoverActualOccurrenceOfTypeInHierarchy(genericOnType);
									}
									m = m.parameterizedFor(actualOccurrence);
									// possible sig change when type parameters filled in
									sig = m.getSignature();
								}
								if (ResolvedType.matches(
										AjcMemberMaker.interMethod(sig, m.getAspectType(),
												sig.getDeclaringType().resolve(weaver.getWorld()).isInterface()), newParentMethod)) {
									satisfiedByITD = true;
								}
							}
						} else if (m.getMunger() != null && m.getMunger().getKind() == ResolvedTypeMunger.MethodDelegate2) {
							// AV - that should be enough, no need to check more
							satisfiedByITD = true;
						}
					}
					if (!satisfiedByITD) {
						error(weaver,
								"The type " + newParentTarget.getName() + " must implement the inherited abstract method "
										+ newParentMethod.getDeclaringType() + "." + newParentMethodName
										+ newParentMethod.getParameterSignature(), newParentTarget.getType().getSourceLocation(),
								new ISourceLocation[] { newParentMethod.getSourceLocation(), mungerLoc });
						ruleCheckingSucceeded = false;
					}
				}
			}
		}
		return ruleCheckingSucceeded;
	}

	/**
	 * Rule 2. Can't extend final types
	 */
	private boolean enforceDecpRule2_cantExtendFinalClass(BcelClassWeaver weaver, ISourceLocation transformerLoc,
			LazyClassGen targetType, ResolvedType newParent) {
		if (newParent.isFinal()) {
			error(weaver, "Cannot make type " + targetType.getName() + " extend final class " + newParent.getName(), targetType
					.getType().getSourceLocation(), new ISourceLocation[] { transformerLoc });
			return false;
		}
		return true;
	}

	/**
	 * Rule 3. Can't narrow visibility of methods when overriding
	 */
	private boolean enforceDecpRule3_visibilityChanges(BcelClassWeaver weaver, ResolvedType newParent, ResolvedMember superMethod,
			LazyMethodGen subMethod) {
		boolean cont = true;
		if (Modifier.isPublic(superMethod.getModifiers())) {
			if (subMethod.isProtected() || subMethod.isDefault() || subMethod.isPrivate()) {
				weaver.getWorld()
						.getMessageHandler()
						.handleMessage(
								MessageUtil.error("Cannot reduce the visibility of the inherited method '" + superMethod
										+ "' from " + newParent.getName(), superMethod.getSourceLocation()));
				cont = false;
			}
		} else if (Modifier.isProtected(superMethod.getModifiers())) {
			if (subMethod.isDefault() || subMethod.isPrivate()) {
				weaver.getWorld()
						.getMessageHandler()
						.handleMessage(
								MessageUtil.error("Cannot reduce the visibility of the inherited method '" + superMethod
										+ "' from " + newParent.getName(), superMethod.getSourceLocation()));
				cont = false;
			}
		} else if (superMethod.isDefault()) {
			if (subMethod.isPrivate()) {
				weaver.getWorld()
						.getMessageHandler()
						.handleMessage(
								MessageUtil.error("Cannot reduce the visibility of the inherited method '" + superMethod
										+ "' from " + newParent.getName(), superMethod.getSourceLocation()));
				cont = false;
			}
		}
		return cont;
	}

	/**
	 * Rule 4. Can't have incompatible return types
	 */
	private boolean enforceDecpRule4_compatibleReturnTypes(BcelClassWeaver weaver, ResolvedMember superMethod,
			LazyMethodGen subMethod) {
		boolean cont = true;
		String superReturnTypeSig = superMethod.getGenericReturnType().getSignature(); // eg. Pjava/util/Collection
		String subReturnTypeSig = subMethod.getGenericReturnTypeSignature();
		superReturnTypeSig = superReturnTypeSig.replace('.', '/');
		subReturnTypeSig = subReturnTypeSig.replace('.', '/');
		if (!superReturnTypeSig.equals(subReturnTypeSig)) {
			// Check for covariance
			ResolvedType subType = weaver.getWorld().resolve(subMethod.getReturnType());
			ResolvedType superType = weaver.getWorld().resolve(superMethod.getReturnType());
			if (!superType.isAssignableFrom(subType)) {
				weaver.getWorld()
						.getMessageHandler()
						.handleMessage(
								MessageUtil.error("The return type is incompatible with " + superMethod.getDeclaringType() + "."
										+ superMethod.getName() + superMethod.getParameterSignature(),
										subMethod.getSourceLocation()));
				// this just might be a better error message...
				// "The return type '"+subReturnTypeSig+
				// "' is incompatible with the overridden method "
				// +superMethod.getDeclaringType()+"."+
				// superMethod.getName()+superMethod.getParameterSignature()+
				// " which returns '"+superReturnTypeSig+"'",
				cont = false;
			}
		}
		return cont;
	}

	/**
	 * Rule5. Method overrides can't change the staticality (word?) - you can't override and make an instance method static or
	 * override and make a static method an instance method.
	 */
	private boolean enforceDecpRule5_cantChangeFromStaticToNonstatic(BcelClassWeaver weaver, ISourceLocation mungerLoc,
			ResolvedMember superMethod, LazyMethodGen subMethod) {
		boolean superMethodStatic = Modifier.isStatic(superMethod.getModifiers());
		if (superMethodStatic && !subMethod.isStatic()) {
			error(weaver, "This instance method " + subMethod.getName() + subMethod.getParameterSignature()
					+ " cannot override the static method from " + superMethod.getDeclaringType().getName(),
					subMethod.getSourceLocation(), new ISourceLocation[] { mungerLoc });
			return false;
		} else if (!superMethodStatic && subMethod.isStatic()) {
			error(weaver, "The static method " + subMethod.getName() + subMethod.getParameterSignature()
					+ " cannot hide the instance method from " + superMethod.getDeclaringType().getName(),
					subMethod.getSourceLocation(), new ISourceLocation[] { mungerLoc });
			return false;
		}
		return true;
	}

	public void error(BcelClassWeaver weaver, String text, ISourceLocation primaryLoc, ISourceLocation[] extraLocs) {
		IMessage msg = new Message(text, primaryLoc, true, extraLocs);
		weaver.getWorld().getMessageHandler().handleMessage(msg);
	}

	/**
	 * Search the specified type for a particular method - do not use the return value in the comparison as it is not considered for
	 * overriding.
	 */
	private LazyMethodGen findMatchingMethod(LazyClassGen type, ResolvedMember searchMethod) {
		String searchName = searchMethod.getName();
		String searchSig = searchMethod.getParameterSignature();
		for (LazyMethodGen method : type.getMethodGens()) {
			if (method.getName().equals(searchName) && method.getParameterSignature().equals(searchSig)) {
				return method;
			}
		}
		return null;
	}

	/**
	 * The main part of implementing declare parents extends. Modify super ctor calls to target the new type.
	 */
	public boolean attemptToModifySuperCalls(BcelClassWeaver weaver, LazyClassGen newParentTarget, ResolvedType newParent) {
		ResolvedType currentParentType = newParentTarget.getSuperClass();
		if (currentParentType.getGenericType() != null) {
			currentParentType = currentParentType.getGenericType();
		}
		String currentParent = currentParentType.getName();
		if (newParent.getGenericType() != null) {
			newParent = newParent.getGenericType(); // target new super calls at
		}
		// the generic type if its raw or parameterized
		List mgs = newParentTarget.getMethodGens();

		// Look for ctors to modify
		for (LazyMethodGen aMethod : mgs) {
			if (LazyMethodGen.isConstructor(aMethod)) {
				InstructionList insList = aMethod.getBody();
				InstructionHandle handle = insList.getStart();
				while (handle != null) {
					if (handle.getInstruction().opcode == Constants.INVOKESPECIAL) {
						ConstantPool cpg = newParentTarget.getConstantPool();
						InvokeInstruction invokeSpecial = (InvokeInstruction) handle.getInstruction();
						if (invokeSpecial.getClassName(cpg).equals(currentParent)
								&& invokeSpecial.getMethodName(cpg).equals("")) {
							// System.err.println("Transforming super call '" + invokeSpecial.getSignature(cpg) + "'");

							// 1. Check there is a ctor in the new parent with
							// the same signature
							ResolvedMember newCtor = getConstructorWithSignature(newParent, invokeSpecial.getSignature(cpg));

							if (newCtor == null) {

								// 2. Check ITDCs to see if the necessary ctor is provided that way
								boolean satisfiedByITDC = false;
								for (Iterator ii = newParentTarget.getType()
										.getInterTypeMungersIncludingSupers().iterator(); ii.hasNext() && !satisfiedByITDC;) {
									ConcreteTypeMunger m = ii.next();
									if (m.getMunger() instanceof NewConstructorTypeMunger) {
										if (m.getSignature().getSignature().equals(invokeSpecial.getSignature(cpg))) {
											satisfiedByITDC = true;
										}
									}
								}

								if (!satisfiedByITDC) {
									String csig = createReadableCtorSig(newParent, cpg, invokeSpecial);
									weaver.getWorld()
											.getMessageHandler()
											.handleMessage(
													MessageUtil.error(
															"Unable to modify hierarchy for " + newParentTarget.getClassName()
																	+ " - the constructor " + csig + " is missing",
															this.getSourceLocation()));
									return false;
								}
							}

							int idx = cpg.addMethodref(newParent.getName(), invokeSpecial.getMethodName(cpg),
									invokeSpecial.getSignature(cpg));
							invokeSpecial.setIndex(idx);
						}
					}
					handle = handle.getNext();
				}
			}
		}
		return true;
	}

	/**
	 * Creates a nice signature for the ctor, something like "(int,Integer,String)"
	 */
	private String createReadableCtorSig(ResolvedType newParent, ConstantPool cpg, InvokeInstruction invokeSpecial) {
		StringBuilder sb = new StringBuilder();
		Type[] ctorArgs = invokeSpecial.getArgumentTypes(cpg);
		sb.append(newParent.getClassName());
		sb.append("(");
		for (int i = 0; i < ctorArgs.length; i++) {
			String argtype = ctorArgs[i].toString();
			if (argtype.lastIndexOf(".") != -1) {
				sb.append(argtype.substring(argtype.lastIndexOf(".") + 1));
			} else {
				sb.append(argtype);
			}
			if (i + 1 < ctorArgs.length) {
				sb.append(",");
			}
		}
		sb.append(")");
		return sb.toString();
	}

	private ResolvedMember getConstructorWithSignature(ResolvedType type, String searchSig) {
		for (ResolvedMember method : type.getDeclaredJavaMethods()) {
			if (MemberUtils.isConstructor(method)) {
				if (method.getSignature().equals(searchSig)) {
					return method;
				}
			}
		}
		return null;
	}

	private boolean mungePrivilegedAccess(BcelClassWeaver weaver, PrivilegedAccessMunger munger) {
		LazyClassGen gen = weaver.getLazyClassGen();
		ResolvedMember member = munger.getMember();

		ResolvedType onType = weaver.getWorld().resolve(member.getDeclaringType(), munger.getSourceLocation());
		if (onType.isRawType()) {
			onType = onType.getGenericType();
		}

		// System.out.println("munging: " + gen + " with " + member);
		if (onType.equals(gen.getType())) {
			if (member.getKind() == Member.FIELD) {
				// System.out.println("matched: " + gen);
				addFieldGetter(gen, member,
						AjcMemberMaker.privilegedAccessMethodForFieldGet(aspectType, member, munger.shortSyntax));
				addFieldSetter(gen, member,
						AjcMemberMaker.privilegedAccessMethodForFieldSet(aspectType, member, munger.shortSyntax));
				return true;
			} else if (member.getKind() == Member.METHOD) {
				addMethodDispatch(gen, member, AjcMemberMaker.privilegedAccessMethodForMethod(aspectType, member));
				return true;
			} else if (member.getKind() == Member.CONSTRUCTOR) {
				for (LazyMethodGen m : gen.getMethodGens()) {
					if (m.getMemberView() != null && m.getMemberView().getKind() == Member.CONSTRUCTOR) {
						// m.getMemberView().equals(member)) {
						m.forcePublic();
						// return true;
					}
				}
				return true;
				// throw new BCException("no match for " + member + " in " +
				// gen);
			} else if (member.getKind() == Member.STATIC_INITIALIZATION) {
				gen.forcePublic();
				return true;
			} else {
				throw new RuntimeException("unimplemented");
			}
		}
		return false;
	}

	private void addFieldGetter(LazyClassGen gen, ResolvedMember field, ResolvedMember accessMethod) {
		LazyMethodGen mg = makeMethodGen(gen, accessMethod);
		InstructionList il = new InstructionList();
		InstructionFactory fact = gen.getFactory();
		if (Modifier.isStatic(field.getModifiers())) {
			il.append(fact.createFieldAccess(gen.getClassName(), field.getName(), BcelWorld.makeBcelType(field.getType()),
					Constants.GETSTATIC));
		} else {
			il.append(InstructionConstants.ALOAD_0);
			il.append(fact.createFieldAccess(gen.getClassName(), field.getName(), BcelWorld.makeBcelType(field.getType()),
					Constants.GETFIELD));
		}
		il.append(InstructionFactory.createReturn(BcelWorld.makeBcelType(field.getType())));
		mg.getBody().insert(il);

		gen.addMethodGen(mg, getSignature().getSourceLocation());
	}

	private void addFieldSetter(LazyClassGen gen, ResolvedMember field, ResolvedMember accessMethod) {
		LazyMethodGen mg = makeMethodGen(gen, accessMethod);
		InstructionList il = new InstructionList();
		InstructionFactory fact = gen.getFactory();
		Type fieldType = BcelWorld.makeBcelType(field.getType());

		if (Modifier.isStatic(field.getModifiers())) {
			il.append(InstructionFactory.createLoad(fieldType, 0));
			il.append(fact.createFieldAccess(gen.getClassName(), field.getName(), fieldType, Constants.PUTSTATIC));
		} else {
			il.append(InstructionConstants.ALOAD_0);
			il.append(InstructionFactory.createLoad(fieldType, 1));
			il.append(fact.createFieldAccess(gen.getClassName(), field.getName(), fieldType, Constants.PUTFIELD));
		}
		il.append(InstructionFactory.createReturn(Type.VOID));
		mg.getBody().insert(il);

		gen.addMethodGen(mg, getSignature().getSourceLocation());
	}

	private void addMethodDispatch(LazyClassGen gen, ResolvedMember method, ResolvedMember accessMethod) {
		LazyMethodGen mg = makeMethodGen(gen, accessMethod);
		InstructionList il = new InstructionList();
		InstructionFactory fact = gen.getFactory();
		Type[] paramTypes = BcelWorld.makeBcelTypes(method.getParameterTypes());

		int pos = 0;

		if (!Modifier.isStatic(method.getModifiers())) {
			il.append(InstructionConstants.ALOAD_0);
			pos++;
		}
		for (Type paramType : paramTypes) {
			il.append(InstructionFactory.createLoad(paramType, pos));
			pos += paramType.getSize();
		}
		il.append(Utility.createInvoke(fact, (BcelWorld) aspectType.getWorld(), method));
		il.append(InstructionFactory.createReturn(BcelWorld.makeBcelType(method.getReturnType())));

		mg.getBody().insert(il);

		gen.addMethodGen(mg);
	}

	protected LazyMethodGen makeMethodGen(LazyClassGen gen, ResolvedMember member) {
		try {
			Type returnType = BcelWorld.makeBcelType(member.getReturnType());
			Type[] parameterTypes = BcelWorld.makeBcelTypes(member.getParameterTypes());
			LazyMethodGen ret = new LazyMethodGen(member.getModifiers(), returnType,
					member.getName(), parameterTypes, UnresolvedType.getNames(member
							.getExceptions()), gen);

			// 43972 : Static crosscutting makes interfaces unusable for javac
			// ret.makeSynthetic();
			return ret;
		} catch (ClassFormatException cfe) {
			throw new RuntimeException("Problem with makeMethodGen for method "+member.getName()+" in type "+gen.getName()+"  ret="+member.getReturnType(),cfe);
		}
	}

	protected FieldGen makeFieldGen(LazyClassGen gen, ResolvedMember member) {
		return new FieldGen(member.getModifiers(), BcelWorld.makeBcelType(member.getReturnType()), member.getName(),
				gen.getConstantPool());
	}

	private boolean mungePerObjectInterface(BcelClassWeaver weaver, PerObjectInterfaceTypeMunger munger) {
		// System.err.println("Munging perobject ["+munger+"] onto "+weaver.
		// getLazyClassGen().getClassName());
		LazyClassGen gen = weaver.getLazyClassGen();

		if (couldMatch(gen.getBcelObjectType(), munger.getTestPointcut())) {
			FieldGen fg = makeFieldGen(gen, AjcMemberMaker.perObjectField(gen.getType(), aspectType));

			gen.addField(fg, getSourceLocation());

			Type fieldType = BcelWorld.makeBcelType(aspectType);
			LazyMethodGen mg = new LazyMethodGen(Modifier.PUBLIC, fieldType, NameMangler.perObjectInterfaceGet(aspectType),
					Type.NO_ARGS, new String[0], gen);
			InstructionList il = new InstructionList();
			InstructionFactory fact = gen.getFactory();
			il.append(InstructionConstants.ALOAD_0);
			il.append(fact.createFieldAccess(gen.getClassName(), fg.getName(), fieldType, Constants.GETFIELD));
			il.append(InstructionFactory.createReturn(fieldType));
			mg.getBody().insert(il);

			gen.addMethodGen(mg);

			LazyMethodGen mg1 = new LazyMethodGen(Modifier.PUBLIC, Type.VOID, NameMangler.perObjectInterfaceSet(aspectType),

			new Type[] { fieldType, }, new String[0], gen);
			InstructionList il1 = new InstructionList();
			il1.append(InstructionConstants.ALOAD_0);
			il1.append(InstructionFactory.createLoad(fieldType, 1));
			il1.append(fact.createFieldAccess(gen.getClassName(), fg.getName(), fieldType, Constants.PUTFIELD));
			il1.append(InstructionFactory.createReturn(Type.VOID));
			mg1.getBody().insert(il1);

			gen.addMethodGen(mg1);

			gen.addInterface(munger.getInterfaceType().resolve(weaver.getWorld()), getSourceLocation());

			return true;
		} else {
			return false;
		}
	}

	// PTWIMPL Add field to hold aspect instance and an accessor
	private boolean mungePerTypeWithinTransformer(BcelClassWeaver weaver) {
		LazyClassGen gen = weaver.getLazyClassGen();

		// if (couldMatch(gen.getBcelObjectType(), munger.getTestPointcut())) {

		// Add (to the target type) the field that will hold the aspect instance
		// e.g ajc$com_blah_SecurityAspect$ptwAspectInstance
		FieldGen fg = makeFieldGen(gen, AjcMemberMaker.perTypeWithinField(gen.getType(), aspectType));
		gen.addField(fg, getSourceLocation());
		if (!gen.getType().canBeSeenBy(aspectType) && aspectType.isPrivilegedAspect()) {
			gen.forcePublic();
		}
		// Add an accessor for this new field, the
		// ajc$$localAspectOf() method
		// e.g.
		// "public com_blah_SecurityAspect ajc$com_blah_SecurityAspect$localAspectOf()"
		Type fieldType = BcelWorld.makeBcelType(aspectType);
		LazyMethodGen mg = new LazyMethodGen(Modifier.PUBLIC | Modifier.STATIC, fieldType,
				NameMangler.perTypeWithinLocalAspectOf(aspectType), Type.NO_ARGS, new String[0], gen);
		InstructionList il = new InstructionList();
		// PTWIMPL ?? Should check if it is null and throw
		// NoAspectBoundException
		InstructionFactory fact = gen.getFactory();
		il.append(fact.createFieldAccess(gen.getClassName(), fg.getName(), fieldType, Constants.GETSTATIC));
		il.append(InstructionFactory.createReturn(fieldType));
		mg.getBody().insert(il);
		gen.addMethodGen(mg);
		return true;
		// } else {
		// return false;
		// }
	}

	// ??? Why do we have this method? I thought by now we would know if it
	// matched or not
	private boolean couldMatch(BcelObjectType bcelObjectType, Pointcut pointcut) {
		return !bcelObjectType.isInterface();
	}

	private boolean mungeNewMemberType(BcelClassWeaver classWeaver, NewMemberClassTypeMunger munger) {
		World world = classWeaver.getWorld();
		ResolvedType onType = world.resolve(munger.getTargetType());
		if (onType.isRawType()) {
			onType = onType.getGenericType();
		}
		return onType.equals(classWeaver.getLazyClassGen().getType());
	}

	private boolean mungeNewMethod(BcelClassWeaver classWeaver, NewMethodTypeMunger munger) {
		World world = classWeaver.getWorld();

		// Resolving it will sort out the tvars
		ResolvedMember unMangledInterMethod = munger.getSignature().resolve(world);

		// do matching on the unMangled one, but actually add them to the mangled method
		ResolvedMember interMethodBody = munger.getDeclaredInterMethodBody(aspectType, world);
		ResolvedMember interMethodDispatcher = munger.getDeclaredInterMethodDispatcher(aspectType, world);
		ResolvedMember memberHoldingAnyAnnotations = interMethodDispatcher;
		LazyClassGen classGen = classWeaver.getLazyClassGen();

		ResolvedType onType = world.resolve(unMangledInterMethod.getDeclaringType(), munger.getSourceLocation());
		if (onType.isRawType()) {
			onType = onType.getGenericType();
		}

		// Simple checks, can't ITD on annotations or enums
		if (onType.isAnnotation()) {
			signalError(WeaverMessages.ITDM_ON_ANNOTATION_NOT_ALLOWED, classWeaver, onType);
			return false;
		}

		if (onType.isEnum()) {
			signalError(WeaverMessages.ITDM_ON_ENUM_NOT_ALLOWED, classWeaver, onType);
			return false;
		}

		boolean mungingInterface = classGen.isInterface();
		boolean onInterface = onType.isInterface();

		if (onInterface
				&& classGen.getLazyMethodGen(unMangledInterMethod.getName(), unMangledInterMethod.getSignature(), true) != null) {
			// this is ok, we could be providing the default implementation of a
			// method
			// that the target has already declared
			return false;
		}

		// If we are processing the intended ITD target type (might be an interface)
		if (onType.equals(classGen.getType())) {
			ResolvedMember mangledInterMethod = AjcMemberMaker.interMethod(unMangledInterMethod, aspectType, onInterface);

			LazyMethodGen newMethod = makeMethodGen(classGen, mangledInterMethod);
			if (mungingInterface) {
				// we want the modifiers of the ITD to be used for all *implementors* of the
				// interface, but the method itself we add to the interface must be public abstract
				newMethod.setAccessFlags(Modifier.PUBLIC | Modifier.ABSTRACT);
			}

			// pr98901
			// For copying the annotations across, we have to discover the real
			// member in the aspect which is holding them.
			if (classWeaver.getWorld().isInJava5Mode()) {
				AnnotationAJ annotationsOnRealMember[] = null;
				ResolvedType toLookOn = aspectType;
				if (aspectType.isRawType()) {
					toLookOn = aspectType.getGenericType();
				}
				ResolvedMember realMember = getRealMemberForITDFromAspect(toLookOn, memberHoldingAnyAnnotations, false);
				// 266602 - consider it missing to mean that the corresponding aspect had errors
				if (realMember == null) {
					// signalWarning("Unable to apply any annotations attached to " + munger.getSignature(), weaver);
					// throw new BCException("Couldn't find ITD init member '" + interMethodBody + "' on aspect " + aspectType);
				} else {
					annotationsOnRealMember = realMember.getAnnotations();
				}
				Set addedAnnotations = new HashSet<>();
				if (annotationsOnRealMember != null) {
					for (AnnotationAJ anno : annotationsOnRealMember) {
						AnnotationGen a = ((BcelAnnotation) anno).getBcelAnnotation();
						AnnotationGen ag = new AnnotationGen(a, classGen.getConstantPool(), true);
						newMethod.addAnnotation(new BcelAnnotation(ag, classWeaver.getWorld()));
						addedAnnotations.add(anno.getType());
					}
				}
				if (realMember != null) {
					copyOverParameterAnnotations(newMethod, realMember);
				}
				// the code below was originally added to cope with the case where an aspect declares an annotation on an ITD
				// declared within itself (an unusual situation). However, it also addresses the case where we may not find the
				// annotation on the real representation of the ITD. This can happen in a load-time weaving situation where
				// we couldn't add the annotation in time - and so here we recheck the declare annotations. Not quite ideal but
				// works. pr288635
				List allDecams = world.getDeclareAnnotationOnMethods();
				for (DeclareAnnotation declareAnnotationMC : allDecams) {
					if (declareAnnotationMC.matches(unMangledInterMethod, world)) {
						// && newMethod.getEnclosingClass().getType() == aspectType) {
						AnnotationAJ annotation = declareAnnotationMC.getAnnotation();
						if (!addedAnnotations.contains(annotation.getType())) {
							newMethod.addAnnotation(annotation);
						}
					}
				}
			}

			// If it doesn't target an interface and there is a body (i.e. it isnt abstract)
			if (!onInterface && !Modifier.isAbstract(mangledInterMethod.getModifiers())) {
				InstructionList body = newMethod.getBody();
				InstructionFactory fact = classGen.getFactory();
				int pos = 0;

				if (!Modifier.isStatic(unMangledInterMethod.getModifiers())) {
					body.append(InstructionFactory.createThis());
					pos++;
				}
				Type[] paramTypes = BcelWorld.makeBcelTypes(mangledInterMethod.getParameterTypes());
				for (Type paramType : paramTypes) {
					body.append(InstructionFactory.createLoad(paramType, pos));
					pos += paramType.getSize();
				}
				body.append(Utility.createInvoke(fact, classWeaver.getWorld(), interMethodBody));
				body.append(InstructionFactory.createReturn(BcelWorld.makeBcelType(mangledInterMethod.getReturnType())));

				if (classWeaver.getWorld().isInJava5Mode()) { // Don't need bridge
					// methods if not in
					// 1.5 mode.
					createAnyBridgeMethodsForCovariance(classWeaver, munger, unMangledInterMethod, onType, classGen, paramTypes);
				}

			} else {
				// ??? this is okay
				// if (!(mg.getBody() == null)) throw new
				// RuntimeException("bas");
			}

			if (world.isInJava5Mode()) {
				String basicSignature = mangledInterMethod.getSignature();
				String genericSignature = ((ResolvedMemberImpl) mangledInterMethod).getSignatureForAttribute();
				if (!basicSignature.equals(genericSignature)) {
					// Add a signature attribute to it
					newMethod.addAttribute(createSignatureAttribute(classGen.getConstantPool(), genericSignature));
				}
			}
			// XXX make sure to check that we set exceptions properly on this
			// guy.
			classWeaver.addLazyMethodGen(newMethod);
			classWeaver.getLazyClassGen().warnOnAddedMethod(newMethod.getMethod(), getSignature().getSourceLocation());

			addNeededSuperCallMethods(classWeaver, onType, munger.getSuperMethodsCalled());

			return true;

		} else if (onInterface && !Modifier.isAbstract(unMangledInterMethod.getModifiers())) {

			// This means the 'gen' should be the top most implementor
			// - if it is *not* then something went wrong after we worked
			// out that it was the top most implementor (see pr49657)
			if (!classGen.getType().isTopmostImplementor(onType)) {
				ResolvedType rtx = classGen.getType().getTopmostImplementor(onType);
				if (rtx == null) {
					// pr302460
					// null means there is something wrong with what we are looking at
					ResolvedType rt = classGen.getType();
					if (rt.isInterface()) {
						ISourceLocation sloc = munger.getSourceLocation();
						classWeaver
								.getWorld()
								.getMessageHandler()
								.handleMessage(
										MessageUtil.error(
												"ITD target "
														+ rt.getName()
														+ " is an interface but has been incorrectly determined to be the topmost implementor of "
														+ onType.getName() + ". ITD is " + this.getSignature(), sloc));
					}
					if (!onType.isAssignableFrom(rt)) {
						ISourceLocation sloc = munger.getSourceLocation();
						classWeaver
								.getWorld()
								.getMessageHandler()
								.handleMessage(
										MessageUtil.error(
												"ITD target " + rt.getName() + " doesn't appear to implement " + onType.getName()
														+ " why did we consider it the top most implementor? ITD is "
														+ this.getSignature(), sloc));
					}
				} else if (!rtx.isExposedToWeaver()) {
					ISourceLocation sLoc = munger.getSourceLocation();
					classWeaver
							.getWorld()
							.getMessageHandler()
							.handleMessage(
									MessageUtil.error(WeaverMessages.format(WeaverMessages.ITD_NON_EXPOSED_IMPLEMENTOR, rtx,
											getAspectType().getName()), (sLoc == null ? getAspectType().getSourceLocation() : sLoc)));
				} else {
					// XXX what does this state mean?
					// We have incorrectly identified what is the top most
					// implementor and its not because
					// a type wasn't exposed to the weaver
				}
				return false;
			} else {

				ResolvedMember mangledInterMethod = AjcMemberMaker.interMethod(unMangledInterMethod, aspectType, false);

				LazyMethodGen mg = makeMethodGen(classGen, mangledInterMethod);

				// From 98901#29 - need to copy annotations across
				if (classWeaver.getWorld().isInJava5Mode()) {
					AnnotationAJ annotationsOnRealMember[] = null;
					ResolvedType toLookOn = aspectType;
					if (aspectType.isRawType()) {
						toLookOn = aspectType.getGenericType();
					}
					ResolvedMember realMember = getRealMemberForITDFromAspect(toLookOn, memberHoldingAnyAnnotations, false);
					if (realMember == null) {
						throw new BCException("Couldn't find ITD holder member '" + memberHoldingAnyAnnotations + "' on aspect "
								+ aspectType);
					}
					annotationsOnRealMember = realMember.getAnnotations();

					if (annotationsOnRealMember != null) {
						for (AnnotationAJ annotationX : annotationsOnRealMember) {
							AnnotationGen a = ((BcelAnnotation) annotationX).getBcelAnnotation();
							AnnotationGen ag = new AnnotationGen(a, classWeaver.getLazyClassGen().getConstantPool(), true);
							mg.addAnnotation(new BcelAnnotation(ag, classWeaver.getWorld()));
						}
					}

					copyOverParameterAnnotations(mg, realMember);
				}

				if (mungingInterface) {
					// we want the modifiers of the ITD to be used for all
					// *implementors* of the
					// interface, but the method itself we add to the interface
					// must be public abstract
					mg.setAccessFlags(Modifier.PUBLIC | Modifier.ABSTRACT);
				}

				Type[] paramTypes = BcelWorld.makeBcelTypes(mangledInterMethod.getParameterTypes());
				Type returnType = BcelWorld.makeBcelType(mangledInterMethod.getReturnType());

				InstructionList body = mg.getBody();
				InstructionFactory fact = classGen.getFactory();
				int pos = 0;

				if (!Modifier.isStatic(mangledInterMethod.getModifiers())) {
					body.append(InstructionFactory.createThis());
					pos++;
				}
				for (Type paramType : paramTypes) {
					body.append(InstructionFactory.createLoad(paramType, pos));
					pos += paramType.getSize();
				}

				body.append(Utility.createInvoke(fact, classWeaver.getWorld(), interMethodBody));
				Type t = BcelWorld.makeBcelType(interMethodBody.getReturnType());
				if (!t.equals(returnType)) {
					body.append(fact.createCast(t, returnType));
				}
				body.append(InstructionFactory.createReturn(returnType));
				mg.definingType = onType;

				if (world.isInJava5Mode()) {
					String basicSignature = mangledInterMethod.getSignature();
					String genericSignature = ((ResolvedMemberImpl) mangledInterMethod).getSignatureForAttribute();
					if (!basicSignature.equals(genericSignature)) {
						// Add a signature attribute to it
						mg.addAttribute(createSignatureAttribute(classGen.getConstantPool(), genericSignature));
					}
				}

				classWeaver.addOrReplaceLazyMethodGen(mg);

				addNeededSuperCallMethods(classWeaver, onType, munger.getSuperMethodsCalled());

				// Work out if we need a bridge method for the new method added to the topmostimplementor.

				// Check if the munger being processed is a parameterized form of the original munger
				createBridgeIfNecessary(classWeaver, munger, unMangledInterMethod, classGen);

				return true;
			}
		} else {
			return false;
		}
	}

	private void createBridgeIfNecessary(BcelClassWeaver classWeaver, NewMethodTypeMunger munger,
			ResolvedMember unMangledInterMethod, LazyClassGen classGen) {
		if (munger.getDeclaredSignature() != null) {
			boolean needsbridging = false;
			ResolvedMember mungerSignature = munger.getSignature();
			ResolvedMember toBridgeTo = munger.getDeclaredSignature().parameterizedWith(null,
					mungerSignature.getDeclaringType().resolve(getWorld()), false, munger.getTypeVariableAliases());
			if (!toBridgeTo.getReturnType().getErasureSignature().equals(mungerSignature.getReturnType().getErasureSignature())) {
				needsbridging = true;
			}
			UnresolvedType[] originalParams = toBridgeTo.getParameterTypes();
			UnresolvedType[] newParams = mungerSignature.getParameterTypes();
			for (int ii = 0; ii < originalParams.length; ii++) {
				if (!originalParams[ii].getErasureSignature().equals(newParams[ii].getErasureSignature())) {
					needsbridging = true;
				}
			}
			if (needsbridging) {
				createBridge(classWeaver, unMangledInterMethod, classGen, toBridgeTo);
			}
		}
	}

	private void copyOverParameterAnnotations(LazyMethodGen receiverMethod, ResolvedMember donorMethod) {
		AnnotationAJ[][] pAnnos = donorMethod.getParameterAnnotations();
		if (pAnnos != null) {
			int offset = receiverMethod.isStatic() ? 0 : 1;
			int param = 0;
			for (int i = offset; i < pAnnos.length; i++) {
				AnnotationAJ[] annosOnParam = pAnnos[i];
				if (annosOnParam != null) {
					for (AnnotationAJ anno : annosOnParam) {
						receiverMethod.addParameterAnnotation(param, anno);
					}
				}
				param++;
			}
		}
	}

	private void createBridge(BcelClassWeaver weaver, ResolvedMember unMangledInterMethod, LazyClassGen classGen,
			ResolvedMember toBridgeTo) {
		Type[] paramTypes;
		Type returnType;
		InstructionList body;
		InstructionFactory fact;
		int pos;
		ResolvedMember bridgerMethod = AjcMemberMaker.bridgerToInterMethod(unMangledInterMethod, classGen.getType());
		ResolvedMember bridgingSetter = AjcMemberMaker.interMethodBridger(toBridgeTo, aspectType, false); // pr250493

		LazyMethodGen bridgeMethod = makeMethodGen(classGen, bridgingSetter);
		paramTypes = BcelWorld.makeBcelTypes(bridgingSetter.getParameterTypes());
		Type[] bridgingToParms = BcelWorld.makeBcelTypes(unMangledInterMethod.getParameterTypes());
		returnType = BcelWorld.makeBcelType(bridgingSetter.getReturnType());
		body = bridgeMethod.getBody();
		fact = classGen.getFactory();
		pos = 0;
		if (!Modifier.isStatic(bridgingSetter.getModifiers())) {
			body.append(InstructionFactory.createThis());
			pos++;
		}
		for (int i = 0, len = paramTypes.length; i < len; i++) {
			Type paramType = paramTypes[i];
			body.append(InstructionFactory.createLoad(paramType, pos));
			if (!bridgingSetter.getParameterTypes()[i].getErasureSignature().equals(
					unMangledInterMethod.getParameterTypes()[i].getErasureSignature())) {
				// System.err.println("Putting in cast from "+
				// paramType+" to "+bridgingToParms[i]);
				body.append(fact.createCast(paramType, bridgingToParms[i]));
			}
			pos += paramType.getSize();
		}

		body.append(Utility.createInvoke(fact, weaver.getWorld(), bridgerMethod));
		body.append(InstructionFactory.createReturn(returnType));
		classGen.addMethodGen(bridgeMethod);
		// mg.definingType = onType;
	}

	/**
	 * Helper method to create a signature attribute based on a string signature: e.g. "Ljava/lang/Object;LI;"
	 */
	private Signature createSignatureAttribute(ConstantPool cp, String signature) {
		int nameIndex = cp.addUtf8("Signature");
		int sigIndex = cp.addUtf8(signature);
		return new Signature(nameIndex, 2, sigIndex, cp);
	}

	/**
	 * Create any bridge method required because of covariant returns being used. This method is used in the case where an ITD is
	 * applied to some type and it may be in an override relationship with a method from the supertype - but due to covariance there
	 * is a mismatch in return values. Example of when required: Super defines: Object m(String s) Sub defines: String m(String s)
	 * then we need a bridge method in Sub called 'Object m(String s)' that forwards to 'String m(String s)'
	 */
	private void createAnyBridgeMethodsForCovariance(BcelClassWeaver weaver, NewMethodTypeMunger munger,
			ResolvedMember unMangledInterMethod, ResolvedType onType, LazyClassGen gen, Type[] paramTypes) {
		// PERFORMANCE BOTTLENECK? Might need investigating, method analysis
		// between types in a hierarchy just seems expensive...
		// COVARIANCE BRIDGING
		// Algorithm: Step1. Check in this type - has someone already created
		// the bridge method?
		// Step2. Look above us - do we 'override' a method and yet differ in
		// return type (i.e. covariance)
		// Step3. Create a forwarding bridge method
		// ResolvedType superclass = onType.getSuperclass();
		boolean quitRightNow = false;

		String localMethodName = unMangledInterMethod.getName();
		String erasedSig = unMangledInterMethod.getSignatureErased(); // will be something like (LSuperB;)LFoo;
		String localParameterSig = erasedSig.substring(0,erasedSig.lastIndexOf(')')+1);//unMangledInterMethod.getParameterSignature();
		// getParameterSignatureErased() does not include parens, which we do need.
		String localReturnTypeESig = unMangledInterMethod.getReturnType().getErasureSignature();

		// Step1
		boolean alreadyDone = false; // Compiler might have done it
		ResolvedMember[] localMethods = onType.getDeclaredMethods();
		for (ResolvedMember member : localMethods) {
			if (member.getName().equals(localMethodName)) {
				// Check the params
				if (member.getParameterSignature().equals(localParameterSig)) {
					alreadyDone = true;
				}
			}
		}

		// Step2
		if (!alreadyDone) {
			// Use the iterator form of 'getMethods()' so we do as little work as necessary
			ResolvedType supertype = onType.getSuperclass();
			if (supertype != null) {
				for (Iterator iter = supertype.getMethods(true, true); iter.hasNext() && !quitRightNow;) {
					ResolvedMember aMethod = iter.next();
					if (aMethod.getName().equals(localMethodName) && aMethod.getParameterSignature().equals(localParameterSig)) {
						// check the return types, if they are different we need a
						// bridging method.
						if (!aMethod.getReturnType().getErasureSignature().equals(localReturnTypeESig)
								&& !Modifier.isPrivate(aMethod.getModifiers())) {
							// Step3
							createBridgeMethod(weaver.getWorld(), munger, unMangledInterMethod, gen, paramTypes, aMethod);
							quitRightNow = true;
						}
					}
				}
			}
		}
	}

	/**
	 * Create a bridge method for a particular munger.
	 *
	 * @param world
	 * @param munger
	 * @param unMangledInterMethod the method to bridge 'to' that we have already created in the 'subtype'
	 * @param clazz the class in which to put the bridge method
	 * @param paramTypes Parameter types for the bridge method, passed in as an optimization since the caller is likely to have
	 *        already created them.
	 * @param theBridgeMethod
	 */
	private void createBridgeMethod(BcelWorld world, NewMethodTypeMunger munger, ResolvedMember unMangledInterMethod,
			LazyClassGen clazz, Type[] paramTypes, ResolvedMember theBridgeMethod) {
		InstructionList body;
		InstructionFactory fact;
		int pos = 0;

		// The bridge method in this type will have the same signature as the one in the supertype
		LazyMethodGen bridgeMethod = makeMethodGen(clazz, theBridgeMethod);
		bridgeMethod.setAccessFlags(bridgeMethod.getAccessFlags() | 0x00000040 /* BRIDGE = 0x00000040 */);
		// UnresolvedType[] newParams = munger.getSignature().getParameterTypes();
		Type returnType = BcelWorld.makeBcelType(theBridgeMethod.getReturnType());
		body = bridgeMethod.getBody();
		fact = clazz.getFactory();

		if (!Modifier.isStatic(unMangledInterMethod.getModifiers())) {
			body.append(InstructionFactory.createThis());
			pos++;
		}
		for (Type paramType : paramTypes) {
			body.append(InstructionFactory.createLoad(paramType, pos));
			// if (!bridgingSetter.getParameterTypes()[i].getErasureSignature().
			// equals
			// (unMangledInterMethod.getParameterTypes()[i].getErasureSignature
			// ())) {
			// System.err.println("Putting in cast from "+paramType+" to "+
			// bridgingToParms[i]);
			// body.append(fact.createCast(paramType,bridgingToParms[i]));
			// }
			pos += paramType.getSize();
		}

		body.append(Utility.createInvoke(fact, world, unMangledInterMethod));
		body.append(InstructionFactory.createReturn(returnType));
		clazz.addMethodGen(bridgeMethod);
	}

	// Unlike toString() on a member, this does not include the declaring type
	private String stringifyMember(ResolvedMember member) {
		StringBuilder buf = new StringBuilder();
		buf.append(member.getReturnType().getName());
		buf.append(' ');
		buf.append(member.getName());
		if (member.getKind() != Member.FIELD) {
			buf.append("(");
			UnresolvedType[] params = member.getParameterTypes();
			if (params.length != 0) {
				buf.append(params[0]);
				for (int i = 1, len = params.length; i < len; i++) {
					buf.append(", ");
					buf.append(params[i].getName());
				}
			}
			buf.append(")");
		}
		return buf.toString();
	}

	private boolean mungeMethodDelegate(BcelClassWeaver weaver, MethodDelegateTypeMunger munger) {
		World world = weaver.getWorld();

		LazyClassGen gen = weaver.getLazyClassGen();
		if (gen.getType().isAnnotation() || gen.getType().isEnum()) {
			// don't signal error as it could be a consequence of a wild type pattern
			return false;
		}

		ResolvedMember introduced = munger.getSignature();

		ResolvedType fromType = world.resolve(introduced.getDeclaringType(), munger.getSourceLocation());
		if (fromType.isRawType()) {
			fromType = fromType.getGenericType();
		}

		boolean shouldApply = munger.matches(weaver.getLazyClassGen().getType(), aspectType);

		if (shouldApply) {
			Type bcelReturnType = BcelWorld.makeBcelType(introduced.getReturnType());

			// If no implementation class was specified, the intention was that
			// the types matching the pattern
			// already implemented the interface, let's check that now!
			if (munger.getImplClassName() == null && !munger.specifiesDelegateFactoryMethod()) {
				boolean isOK = false;
				List existingMethods = gen.getMethodGens();
				for (LazyMethodGen m : existingMethods) {
					if (m.getName().equals(introduced.getName())
							&& m.getParameterSignature().equals(introduced.getParameterSignature())
							&& m.getReturnType().equals(bcelReturnType)) {
						isOK = true;
					}
				}
				if (!isOK) {
					// the class does not implement this method, they needed to
					// supply a default impl class
					IMessage msg = new Message("@DeclareParents: No defaultImpl was specified but the type '" + gen.getName()
							+ "' does not implement the method '" + stringifyMember(introduced) + "' defined on the interface '"
							+ introduced.getDeclaringType() + "'", weaver.getLazyClassGen().getType().getSourceLocation(), true,
							new ISourceLocation[] { munger.getSourceLocation() });
					weaver.getWorld().getMessageHandler().handleMessage(msg);
					return false;
				}

				return true;
			}

			LazyMethodGen mg = new LazyMethodGen(introduced.getModifiers() - Modifier.ABSTRACT, bcelReturnType,
					introduced.getName(), BcelWorld.makeBcelTypes(introduced.getParameterTypes()),
					BcelWorld.makeBcelTypesAsClassNames(introduced.getExceptions()), gen);

			// annotation copy from annotation on ITD interface
			if (weaver.getWorld().isInJava5Mode()) {
				AnnotationAJ annotationsOnRealMember[] = null;
				ResolvedType toLookOn = weaver.getWorld().lookupOrCreateName(introduced.getDeclaringType());
				if (fromType.isRawType()) {
					toLookOn = fromType.getGenericType();
				}
				// lookup the method
				ResolvedMember[] ms = toLookOn.getDeclaredJavaMethods();
				for (ResolvedMember m : ms) {
					if (introduced.getName().equals(m.getName()) && introduced.getSignature().equals(m.getSignature())) {
						annotationsOnRealMember = m.getAnnotations();
						break;
					}
				}
				if (annotationsOnRealMember != null) {
					for (AnnotationAJ anno : annotationsOnRealMember) {
						AnnotationGen a = ((BcelAnnotation) anno).getBcelAnnotation();
						AnnotationGen ag = new AnnotationGen(a, weaver.getLazyClassGen().getConstantPool(), true);
						mg.addAnnotation(new BcelAnnotation(ag, weaver.getWorld()));
					}
				}
			}

			InstructionList body = new InstructionList();
			InstructionFactory fact = gen.getFactory();

			// Create a delegate method body which basically looks as follows:
			//
			// public void methodOne() {
			//   if (this.ajc$instance$MyAspect$MyMixin == null) {
			//     synchronized(this) {
			//       if (this.ajc$instance$MyAspect$MyMixin == null) {
			//         this.ajc$instance$MyAspect$MyMixin = MyAspect.aspectOf().createImplementation(this);
			//       }
			//     }
			//   }
			//   this.ajc$instance$MyAspect$MyMixin.methodOne();
			// }

			// Before synchronising on 'this', perform a preliminary null check on the delegate field. Only if it is null,
			// it makes sense to synchronise, then check for null again and initialise the delegate, if null.
			body.append(InstructionConstants.ALOAD_0);
			body.append(Utility.createGet(fact, munger.getDelegate(weaver.getLazyClassGen().getType())));
			InstructionBranch outerIfNonNull = InstructionFactory.createBranchInstruction(Constants.IFNONNULL, null);
			body.append(outerIfNonNull);

			// Wrap delegate field initialisation in 'synchronized(this)' block - MONITORENTER (beginning of 'try')
			body.append(InstructionConstants.ALOAD_0);
			body.append(InstructionConstants.MONITORENTER);

			// The JVM spec requires us add an exception handler ensuring MONITOREXIT in case of an exception inside the
			// synchronized block, see https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-3.html#jvms-3.14.
			InstructionHandle tryStart = body.append(InstructionConstants.ALOAD_0);
			body.append(Utility.createGet(fact, munger.getDelegate(weaver.getLazyClassGen().getType())));
			InstructionBranch innerIfNonNull = InstructionFactory.createBranchInstruction(Constants.IFNONNULL, null);
			body.append(innerIfNonNull);

			// Create and store a new instance
			body.append(InstructionConstants.ALOAD_0); // 'this' is where we'll store the field value

			// TODO for non-static case, call aspectOf() then call the factory method on the retval
			// TODO decide whether the value can really be cached

			// locate the aspect and call the static method in it
			if (munger.specifiesDelegateFactoryMethod()) {
				ResolvedMember rm = munger.getDelegateFactoryMethod(weaver.getWorld());

				// Check the method parameter is compatible with the type of the instance to be passed
				if (rm.getArity() != 0) {
					ResolvedType parameterType = rm.getParameterTypes()[0].resolve(weaver.getWorld());
					if (!parameterType.isAssignableFrom(weaver.getLazyClassGen().getType())) {
						signalError("For mixin factory method '" + rm + "': Instance type '" + weaver.getLazyClassGen().getType()
								+ "' is not compatible with factory parameter type '" + parameterType + "'", weaver);
						return false;
					}
				}
				if (Modifier.isStatic(rm.getModifiers())) {
					if (rm.getArity() != 0) {
						body.append(InstructionConstants.ALOAD_0);
					}
					body.append(fact.createInvoke(rm.getDeclaringType().getName(), rm.getName(), rm.getSignature(),
							Constants.INVOKESTATIC));
					body.append(Utility.createSet(fact, munger.getDelegate(weaver.getLazyClassGen().getType())));
				} else {
					// Need to call aspectOf() to obtain the aspect instance then call the factory method upon that
					UnresolvedType theAspect = munger.getAspect();
					body.append(fact.createInvoke(theAspect.getName(), "aspectOf", "()" + theAspect.getSignature(),
							Constants.INVOKESTATIC));
					if (rm.getArity() != 0) {
						body.append(InstructionConstants.ALOAD_0);
					}
					body.append(fact.createInvoke(rm.getDeclaringType().getName(), rm.getName(), rm.getSignature(),
							Constants.INVOKEVIRTUAL));
					body.append(Utility.createSet(fact, munger.getDelegate(weaver.getLazyClassGen().getType())));
				}
			} else {
				body.append(fact.createNew(munger.getImplClassName()));
				body.append(InstructionConstants.DUP);
				body.append(fact.createInvoke(munger.getImplClassName(), "", Type.VOID, Type.NO_ARGS, Constants.INVOKESPECIAL));
				body.append(Utility.createSet(fact, munger.getDelegate(weaver.getLazyClassGen().getType())));
			}

			// Wrap delegate field initialisation in 'synchronized(this)' block - MONITOREXIT (end of 'try')
			InstructionHandle ifNonNullElse = body.append(InstructionConstants.ALOAD_0);
			innerIfNonNull.setTarget(ifNonNullElse);
			body.append(InstructionConstants.MONITOREXIT);

			// There was no error in the 'synchronized(this)' block -> jump to first instruction after exception handler
			InstructionBranch gotoAfterTryCatch = new InstructionBranch(Constants.GOTO, null);
			InstructionHandle tryEnd = body.append(gotoAfterTryCatch);

			// Exception handler (logical 'catch') for the 'synchronized(this)' block ensures that MONITOREXIT is also called
			// in case of an error
			InstructionHandle catchStart = body.append(InstructionConstants.ALOAD_0);
			body.append(InstructionConstants.MONITOREXIT);
			InstructionHandle catchEnd = body.append(InstructionConstants.ATHROW);

			// Add exception handler for 'synchronized(this)' block
			mg.addExceptionHandler(tryStart, tryEnd.getPrev(), catchStart, null, false);

			// CAVEAT: Add an extra, self-referential exception handler entry. I.e., the handler handles its own exceptions.
			// According to https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-3.html#jvms-3.14, this is required, and
			// Javac also creates code like this, which is why we are mimicking it.
			mg.addExceptionHandler(catchStart, catchEnd.getPrev(), catchStart, null, false);

			// if not null use the instance we've got
			InstructionHandle afterTryCatch = body.append(InstructionConstants.ALOAD_0);
			// Tell 'gotoAfterTryCatch' where to find the first statement after the exception handler
			gotoAfterTryCatch.setTarget(afterTryCatch);
			// The outer delegate field null check should also jump to the same place, if the delegate field is not null
			outerIfNonNull.setTarget(afterTryCatch);
			body.append(Utility.createGet(fact, munger.getDelegate(weaver.getLazyClassGen().getType())));

			// args
			int pos = 0;
			if (!Modifier.isStatic(introduced.getModifiers())) { // skip 'this' (?? can this really
				// happen)
				// body.append(InstructionFactory.createThis());
				pos++;
			}
			Type[] paramTypes = BcelWorld.makeBcelTypes(introduced.getParameterTypes());
			for (Type paramType : paramTypes) {
				body.append(InstructionFactory.createLoad(paramType, pos));
				pos += paramType.getSize();
			}
			body.append(Utility.createInvoke(fact, Constants.INVOKEINTERFACE, introduced));
			body.append(InstructionFactory.createReturn(bcelReturnType));

			mg.getBody().append(body);
			weaver.addLazyMethodGen(mg);
			weaver.getLazyClassGen().warnOnAddedMethod(mg.getMethod(), getSignature().getSourceLocation());
			return true;
		}
		return false;
	}

	private boolean mungeFieldHost(BcelClassWeaver weaver, MethodDelegateTypeMunger.FieldHostTypeMunger munger) {
		LazyClassGen gen = weaver.getLazyClassGen();
		if (gen.getType().isAnnotation() || gen.getType().isEnum()) {
			// don't signal error as it could be a consequence of a wild type
			// pattern
			return false;
		}
		// boolean shouldApply =
		munger.matches(weaver.getLazyClassGen().getType(), aspectType); // why
		// do
		// this?
		ResolvedMember host = AjcMemberMaker.itdAtDeclareParentsField(weaver.getLazyClassGen().getType(), munger.getSignature()
				.getType(), aspectType);
		FieldGen field = makeFieldGen(weaver.getLazyClassGen(), host);
		field.setModifiers(field.getModifiers() | BcelField.AccSynthetic);
		weaver.getLazyClassGen().addField(field, null);
		return true;
	}

	private ResolvedMember getRealMemberForITDFromAspect(ResolvedType aspectType, ResolvedMember lookingFor, boolean isCtorRelated) {
		World world = aspectType.getWorld();
		boolean debug = false;
		if (debug) {
			System.err.println("Searching for a member on type: " + aspectType);
			System.err.println("Member we are looking for: " + lookingFor);
		}

		ResolvedMember[] aspectMethods = aspectType.getDeclaredMethods();
		UnresolvedType[] lookingForParams = lookingFor.getParameterTypes();

		ResolvedMember realMember = null;
		for (int i = 0; realMember == null && i < aspectMethods.length; i++) {
			ResolvedMember member = aspectMethods[i];
			if (member.getName().equals(lookingFor.getName())) {
				UnresolvedType[] memberParams = member.getGenericParameterTypes();
				if (memberParams.length == lookingForParams.length) {
					if (debug)
						System.err.println("Reviewing potential candidates: " + member);
					boolean matchOK = true;

					// Check that all method/ctor params all match, although only the erasure
					for (int j = 0; j < memberParams.length && matchOK; j++) {
						ResolvedType pMember = memberParams[j].resolve(world);
						ResolvedType pLookingFor = lookingForParams[j].resolve(world);

						if (pMember.isTypeVariableReference())
							pMember = ((TypeVariableReference) pMember).getTypeVariable().getFirstBound().resolve(world);
						if (pMember.isParameterizedType() || pMember.isGenericType())
							pMember = pMember.getRawType().resolve(aspectType.getWorld());

						if (pLookingFor.isTypeVariableReference())
							pLookingFor = ((TypeVariableReference) pLookingFor).getTypeVariable().getFirstBound().resolve(world);
						if (pLookingFor.isParameterizedType() || pLookingFor.isGenericType())
							pLookingFor = pLookingFor.getRawType().resolve(world);

						if (debug)
							System.err.println("Comparing parameter " + j + "   member=" + pMember + "   lookingFor=" + pLookingFor);
						if (!pMember.equals(pLookingFor))
							matchOK = false;
					}

					if (matchOK)
						realMember = member;
				}
			}
		}
		if (debug && realMember == null)
			System.err.println("Didn't find a match");
		return realMember;
	}

	private void addNeededSuperCallMethods(BcelClassWeaver weaver, ResolvedType onType, Set neededSuperCalls) {
		LazyClassGen gen = weaver.getLazyClassGen();
		for (ResolvedMember superMethod: neededSuperCalls) {
			if (weaver.addDispatchTarget(superMethod)) {
				// System.err.println("super type: " + superMethod.getDeclaringType() + ", " + gen.getType());
				boolean isSuper = !superMethod.getDeclaringType().equals(gen.getType());
				String dispatchName;
				if (isSuper) {
					dispatchName = NameMangler.superDispatchMethod(onType, superMethod.getName());
				} else {
					dispatchName = NameMangler.protectedDispatchMethod(onType, superMethod.getName());
				}
				superMethod = superMethod.resolve(weaver.getWorld());
				LazyMethodGen dispatcher = makeDispatcher(gen, dispatchName, superMethod, weaver.getWorld(), isSuper);
				weaver.addLazyMethodGen(dispatcher);
			}
		}
	}

	private void signalError(String msgid, BcelClassWeaver weaver, UnresolvedType onType) {
		IMessage msg = MessageUtil.error(WeaverMessages.format(msgid, onType.getName()), getSourceLocation());
		weaver.getWorld().getMessageHandler().handleMessage(msg);
	}

	// private void signalWarning(String msgString, BcelClassWeaver weaver) {
	// IMessage msg = MessageUtil.warn(msgString, getSourceLocation());
	// weaver.getWorld().getMessageHandler().handleMessage(msg);
	// }

	private void signalError(String msgString, BcelClassWeaver weaver) {
		IMessage msg = MessageUtil.error(msgString, getSourceLocation());
		weaver.getWorld().getMessageHandler().handleMessage(msg);
	}

	private boolean mungeNewConstructor(BcelClassWeaver weaver, NewConstructorTypeMunger newConstructorTypeMunger) {

		final LazyClassGen currentClass = weaver.getLazyClassGen();
		final InstructionFactory fact = currentClass.getFactory();

		ResolvedMember newConstructorMember = newConstructorTypeMunger.getSyntheticConstructor();
		ResolvedType onType = newConstructorMember.getDeclaringType().resolve(weaver.getWorld());
		if (onType.isRawType()) {
			onType = onType.getGenericType();
		}

		if (onType.isAnnotation()) {
			signalError(WeaverMessages.ITDC_ON_ANNOTATION_NOT_ALLOWED, weaver, onType);
			return false;
		}

		if (onType.isEnum()) {
			signalError(WeaverMessages.ITDC_ON_ENUM_NOT_ALLOWED, weaver, onType);
			return false;
		}

		if (!onType.equals(currentClass.getType())) {
			return false;
		}

		ResolvedMember explicitConstructor = newConstructorTypeMunger.getExplicitConstructor();
		// int declaredParameterCount =
		// newConstructorTypeMunger.getDeclaredParameterCount();
		LazyMethodGen mg = makeMethodGen(currentClass, newConstructorMember);
		mg.setEffectiveSignature(newConstructorTypeMunger.getSignature(), Shadow.ConstructorExecution, true);

		// pr98901
		// For copying the annotations across, we have to discover the real
		// member in the aspect
		// which is holding them.
		if (weaver.getWorld().isInJava5Mode()) {

			ResolvedMember interMethodDispatcher = AjcMemberMaker.postIntroducedConstructor(aspectType, onType,
					newConstructorTypeMunger.getSignature().getParameterTypes());
			AnnotationAJ annotationsOnRealMember[] = null;
			ResolvedMember realMember = getRealMemberForITDFromAspect(aspectType, interMethodDispatcher, true);
			// 266602 - consider it missing to mean that the corresponding aspect had errors
			if (realMember == null) {
				// signalWarning("Unable to apply any annotations attached to " + munger.getSignature(), weaver);
				// throw new BCException("Couldn't find ITD init member '" + interMethodBody + "' on aspect " + aspectType);
			} else {
				annotationsOnRealMember = realMember.getAnnotations();
			}
			if (annotationsOnRealMember != null) {
				for (AnnotationAJ annotationX : annotationsOnRealMember) {
					AnnotationGen a = ((BcelAnnotation) annotationX).getBcelAnnotation();
					AnnotationGen ag = new AnnotationGen(a, weaver.getLazyClassGen().getConstantPool(), true);
					mg.addAnnotation(new BcelAnnotation(ag, weaver.getWorld()));
				}
			}
			// the below loop fixes the very special (and very stupid)
			// case where an aspect declares an annotation
			// on an ITD it declared on itself.
			List allDecams = weaver.getWorld().getDeclareAnnotationOnMethods();
			for (DeclareAnnotation decaMC : allDecams) {
				if (decaMC.matches(explicitConstructor, weaver.getWorld()) && mg.getEnclosingClass().getType() == aspectType) {
					mg.addAnnotation(decaMC.getAnnotation());
				}
			}
		}

		// Might have to remove the default constructor - b275032
		// TODO could have tagged the type munger when the fact we needed to do this was detected earlier
		if (mg.getArgumentTypes().length == 0) {
			LazyMethodGen toRemove = null;
			for (LazyMethodGen object : currentClass.getMethodGens()) {
				if (object.getName().equals("") && object.getArgumentTypes().length == 0) {
					toRemove = object;
				}
			}
			if (toRemove != null) {
				currentClass.removeMethodGen(toRemove);
			}
		}

		currentClass.addMethodGen(mg);
		// weaver.addLazyMethodGen(freshConstructor);

		InstructionList body = mg.getBody();

		// add to body: push arts for call to pre, from actual args starting at
		// 1 (skipping this), going to
		// declared argcount + 1
		UnresolvedType[] declaredParams = newConstructorTypeMunger.getSignature().getParameterTypes();
		Type[] paramTypes = mg.getArgumentTypes();
		int frameIndex = 1;
		for (int i = 0, len = declaredParams.length; i < len; i++) {
			body.append(InstructionFactory.createLoad(paramTypes[i], frameIndex));
			frameIndex += paramTypes[i].getSize();
		}
		// do call to pre
		Member preMethod = AjcMemberMaker.preIntroducedConstructor(aspectType, onType, declaredParams);
		body.append(Utility.createInvoke(fact, null, preMethod));

		// create a local, and store return pre stuff into it.
		int arraySlot = mg.allocateLocal(1);
		body.append(InstructionFactory.createStore(Type.OBJECT, arraySlot));

		// put this on the stack
		body.append(InstructionConstants.ALOAD_0);

		// unpack pre args onto stack
		UnresolvedType[] superParamTypes = explicitConstructor.getParameterTypes();

		for (int i = 0, len = superParamTypes.length; i < len; i++) {
			body.append(InstructionFactory.createLoad(Type.OBJECT, arraySlot));
			body.append(Utility.createConstant(fact, i));
			body.append(InstructionFactory.createArrayLoad(Type.OBJECT));
			body.append(Utility.createConversion(fact, Type.OBJECT, BcelWorld.makeBcelType(superParamTypes[i])));
		}

		// call super/this

		body.append(Utility.createInvoke(fact, null, explicitConstructor));

		// put this back on the stack

		body.append(InstructionConstants.ALOAD_0);

		// unpack params onto stack
		Member postMethod = AjcMemberMaker.postIntroducedConstructor(aspectType, onType, declaredParams);
		UnresolvedType[] postParamTypes = postMethod.getParameterTypes();

		for (int i = 1, len = postParamTypes.length; i < len; i++) {
			body.append(InstructionFactory.createLoad(Type.OBJECT, arraySlot));
			body.append(Utility.createConstant(fact, superParamTypes.length + i - 1));
			body.append(InstructionFactory.createArrayLoad(Type.OBJECT));
			body.append(Utility.createConversion(fact, Type.OBJECT, BcelWorld.makeBcelType(postParamTypes[i])));
		}

		// call post
		body.append(Utility.createInvoke(fact, null, postMethod));

		// don't forget to return!!
		body.append(InstructionConstants.RETURN);

		addNeededSuperCallMethods(weaver, onType, munger.getSuperMethodsCalled());

		return true;
	}

	private static LazyMethodGen makeDispatcher(LazyClassGen onGen, String dispatchName, ResolvedMember superMethod,
			BcelWorld world, boolean isSuper) {
		Type[] paramTypes = BcelWorld.makeBcelTypes(superMethod.getParameterTypes());
		Type returnType = BcelWorld.makeBcelType(superMethod.getReturnType());

		int modifiers = Modifier.PUBLIC;
		if (onGen.isInterface()) {
			modifiers |= Modifier.ABSTRACT;
		}

		LazyMethodGen mg = new LazyMethodGen(modifiers, returnType, dispatchName, paramTypes, UnresolvedType.getNames(superMethod
				.getExceptions()), onGen);
		InstructionList body = mg.getBody();

		if (onGen.isInterface()) {
			return mg;
		}

		// assert (!superMethod.isStatic())
		InstructionFactory fact = onGen.getFactory();
		int pos = 0;

		body.append(InstructionFactory.createThis());
		pos++;
		for (Type paramType : paramTypes) {
			body.append(InstructionFactory.createLoad(paramType, pos));
			pos += paramType.getSize();
		}
		if (isSuper) {
			body.append(Utility.createSuperInvoke(fact, world, superMethod));
		} else {
			body.append(Utility.createInvoke(fact, world, superMethod));
		}
		body.append(InstructionFactory.createReturn(returnType));

		return mg;
	}

	private boolean mungeNewField(BcelClassWeaver weaver, NewFieldTypeMunger munger) {
		/* ResolvedMember initMethod = */munger.getInitMethod(aspectType);
		LazyClassGen gen = weaver.getLazyClassGen();
		ResolvedMember field = munger.getSignature();

		ResolvedType onType = weaver.getWorld().resolve(field.getDeclaringType(), munger.getSourceLocation());
		if (onType.isRawType()) {
			onType = onType.getGenericType();
		}

		boolean onInterface = onType.isInterface();

		if (onType.isAnnotation()) {
			signalError(WeaverMessages.ITDF_ON_ANNOTATION_NOT_ALLOWED, weaver, onType);
			return false;
		}

		if (onType.isEnum()) {
			signalError(WeaverMessages.ITDF_ON_ENUM_NOT_ALLOWED, weaver, onType);
			return false;
		}

		ResolvedMember interMethodBody = munger.getInitMethod(aspectType);

		AnnotationAJ annotationsOnRealMember[] = null;
		// pr98901
		// For copying the annotations across, we have to discover the real
		// member in the aspect
		// which is holding them.
		if (weaver.getWorld().isInJava5Mode()) {
			// the below line just gets the method with the same name in
			// aspectType.getDeclaredMethods();
			ResolvedType toLookOn = aspectType;
			if (aspectType.isRawType()) {
				toLookOn = aspectType.getGenericType();
			}
			ResolvedMember realMember = getRealMemberForITDFromAspect(toLookOn, interMethodBody, false);
			if (realMember == null) {
				// signalWarning("Unable to apply any annotations attached to " + munger.getSignature(), weaver);
				// throw new BCException("Couldn't find ITD init member '" + interMethodBody + "' on aspect " + aspectType);
			} else {
				annotationsOnRealMember = realMember.getAnnotations();
			}
		}

		if (onType.equals(gen.getType())) {
			if (onInterface) {
				ResolvedMember itdfieldGetter = AjcMemberMaker.interFieldInterfaceGetter(field, onType, aspectType);
				LazyMethodGen mg = makeMethodGen(gen, itdfieldGetter);
				gen.addMethodGen(mg);

				LazyMethodGen mg1 = makeMethodGen(gen, AjcMemberMaker.interFieldInterfaceSetter(field, onType, aspectType));
				gen.addMethodGen(mg1);
			} else {
				weaver.addInitializer(this);
				ResolvedMember newField = AjcMemberMaker.interFieldClassField(field, aspectType,
						munger.version == NewFieldTypeMunger.VersionTwo);
				FieldGen fg = makeFieldGen(gen, newField);

				if (annotationsOnRealMember != null) {
					for (AnnotationAJ annotationX : annotationsOnRealMember) {
						AnnotationGen a = ((BcelAnnotation) annotationX).getBcelAnnotation();
						AnnotationGen ag = new AnnotationGen(a, weaver.getLazyClassGen().getConstantPool(), true);
						fg.addAnnotation(ag);
					}
				}

				if (weaver.getWorld().isInJava5Mode()) {
					String basicSignature = field.getSignature();
					String genericSignature = field.getReturnType().resolve(weaver.getWorld()).getSignatureForAttribute();
					// String genericSignature =
					// ((ResolvedMemberImpl)field).getSignatureForAttribute();
					if (!basicSignature.equals(genericSignature)) {
						// Add a signature attribute to it
						fg.addAttribute(createSignatureAttribute(gen.getConstantPool(), genericSignature));
					}
				}
				gen.addField(fg, getSourceLocation());

			}
			return true;
		} else if (onInterface && gen.getType().isTopmostImplementor(onType)) {
			// we know that we can't be static since we don't allow statics on interfaces
			if (Modifier.isStatic(field.getModifiers())) {
				throw new RuntimeException("unimplemented");
			}

			boolean alreadyExists = false;
			// only need to check for version 2 style mungers
			if (munger.version==NewFieldTypeMunger.VersionTwo) {
				for (BcelField fieldgen: gen.getFieldGens()) {
					if (fieldgen.getName().equals(field.getName())) {
						alreadyExists=true;
						break;
					}
				}
			}

			// FieldGen fg = makeFieldGen(gen, AjcMemberMaker.interFieldInterfaceField(field, onType, aspectType));
			ResolvedMember newField = AjcMemberMaker.interFieldInterfaceField(field, onType, aspectType, munger.version == NewFieldTypeMunger.VersionTwo);
			String fieldName = newField.getName();

			Type fieldType = BcelWorld.makeBcelType(field.getType());
			if (!alreadyExists) {
				weaver.addInitializer(this);
				FieldGen fg = makeFieldGen(gen,newField);
				if (annotationsOnRealMember != null) {
					for (AnnotationAJ annotationX : annotationsOnRealMember) {
						AnnotationGen a = ((BcelAnnotation) annotationX).getBcelAnnotation();
						AnnotationGen ag = new AnnotationGen(a, weaver.getLazyClassGen().getConstantPool(), true);
						fg.addAnnotation(ag);
					}
				}

				if (weaver.getWorld().isInJava5Mode()) {
					String basicSignature = field.getSignature();
					String genericSignature = field.getReturnType().resolve(weaver.getWorld()).getSignatureForAttribute();
					// String genericSignature =
					// ((ResolvedMemberImpl)field).getSignatureForAttribute();
					if (!basicSignature.equals(genericSignature)) {
						// Add a signature attribute to it
						fg.addAttribute(createSignatureAttribute(gen.getConstantPool(), genericSignature));
					}
				}
				gen.addField(fg, getSourceLocation());
			}
			// this uses a shadow munger to add init method to constructors
			// weaver.getShadowMungers().add(makeInitCallShadowMunger(initMethod)
			// );

			ResolvedMember itdfieldGetter = AjcMemberMaker.interFieldInterfaceGetter(field, gen.getType()/* onType */, aspectType);
			LazyMethodGen mg = makeMethodGen(gen, itdfieldGetter);
			InstructionList il = new InstructionList();
			InstructionFactory fact = gen.getFactory();
			if (Modifier.isStatic(field.getModifiers())) {
				il.append(fact.createFieldAccess(gen.getClassName(), fieldName, fieldType, Constants.GETSTATIC));
			} else {
				il.append(InstructionConstants.ALOAD_0);
				il.append(fact.createFieldAccess(gen.getClassName(), fieldName, fieldType, Constants.GETFIELD));
			}
			il.append(InstructionFactory.createReturn(fieldType));
			mg.getBody().insert(il);

			gen.addMethodGen(mg);

			// Check if we need bridge methods for the field getter and setter
			if (munger.getDeclaredSignature() != null) { // is this munger a
				// parameterized
				// form of some
				// original munger?
				ResolvedMember toBridgeTo = munger.getDeclaredSignature().parameterizedWith(null,
						munger.getSignature().getDeclaringType().resolve(getWorld()), false, munger.getTypeVariableAliases());
				boolean needsbridging = false;
				if (!toBridgeTo.getReturnType().getErasureSignature()
						.equals(munger.getSignature().getReturnType().getErasureSignature())) {
					needsbridging = true;
				}
				if (needsbridging) {
					ResolvedMember bridgingGetter = AjcMemberMaker.interFieldInterfaceGetter(toBridgeTo, gen.getType(), aspectType);
					createBridgeMethodForITDF(weaver, gen, itdfieldGetter, bridgingGetter);
				}
			}

			ResolvedMember itdfieldSetter = AjcMemberMaker.interFieldInterfaceSetter(field, gen.getType(), aspectType);
			LazyMethodGen mg1 = makeMethodGen(gen, itdfieldSetter);
			InstructionList il1 = new InstructionList();
			if (Modifier.isStatic(field.getModifiers())) {
				il1.append(InstructionFactory.createLoad(fieldType, 0));
				il1.append(fact.createFieldAccess(gen.getClassName(), fieldName, fieldType, Constants.PUTSTATIC));
			} else {
				il1.append(InstructionConstants.ALOAD_0);
				il1.append(InstructionFactory.createLoad(fieldType, 1));
				il1.append(fact.createFieldAccess(gen.getClassName(), fieldName, fieldType, Constants.PUTFIELD));
			}
			il1.append(InstructionFactory.createReturn(Type.VOID));
			mg1.getBody().insert(il1);

			gen.addMethodGen(mg1);

			if (munger.getDeclaredSignature() != null) {
				ResolvedMember toBridgeTo = munger.getDeclaredSignature().parameterizedWith(null,
						munger.getSignature().getDeclaringType().resolve(getWorld()), false, munger.getTypeVariableAliases());
				boolean needsbridging = false;
				if (!toBridgeTo.getReturnType().getErasureSignature()
						.equals(munger.getSignature().getReturnType().getErasureSignature())) {
					needsbridging = true;
				}
				if (needsbridging) {
					ResolvedMember bridgingSetter = AjcMemberMaker.interFieldInterfaceSetter(toBridgeTo, gen.getType(), aspectType);
					createBridgeMethodForITDF(weaver, gen, itdfieldSetter, bridgingSetter);
				}
			}

			return true;
		} else {
			return false;
		}
	}

	// FIXME asc combine with other createBridge.. method in this class, avoid
	// the duplication...
	private void createBridgeMethodForITDF(BcelClassWeaver weaver, LazyClassGen gen, ResolvedMember itdfieldSetter,
			ResolvedMember bridgingSetter) {
		InstructionFactory fact;
		LazyMethodGen bridgeMethod = makeMethodGen(gen, bridgingSetter);
		bridgeMethod.setAccessFlags(bridgeMethod.getAccessFlags() | 0x00000040); // BRIDGE = 0x00000040
		Type[] paramTypes = BcelWorld.makeBcelTypes(bridgingSetter.getParameterTypes());
		Type[] bridgingToParms = BcelWorld.makeBcelTypes(itdfieldSetter.getParameterTypes());
		Type returnType = BcelWorld.makeBcelType(bridgingSetter.getReturnType());
		InstructionList body = bridgeMethod.getBody();
		fact = gen.getFactory();
		int pos = 0;

		if (!Modifier.isStatic(bridgingSetter.getModifiers())) {
			body.append(InstructionFactory.createThis());
			pos++;
		}
		for (int i = 0, len = paramTypes.length; i < len; i++) {
			Type paramType = paramTypes[i];
			body.append(InstructionFactory.createLoad(paramType, pos));
			if (!bridgingSetter.getParameterTypes()[i].getErasureSignature().equals(
					itdfieldSetter.getParameterTypes()[i].getErasureSignature())) {
				body.append(fact.createCast(paramType, bridgingToParms[i]));
			}
			pos += paramType.getSize();
		}

		body.append(Utility.createInvoke(fact, weaver.getWorld(), itdfieldSetter));
		body.append(InstructionFactory.createReturn(returnType));
		gen.addMethodGen(bridgeMethod);
	}

	@Override
	public ConcreteTypeMunger parameterizedFor(ResolvedType target) {
		return new BcelTypeMunger(munger.parameterizedFor(target), aspectType);
	}

	@Override
	public ConcreteTypeMunger parameterizeWith(Map m, World w) {
		return new BcelTypeMunger(munger.parameterizeWith(m, w), aspectType);
	}

	/**
	 * Returns a list of type variable aliases used in this munger. For example, if the ITD is 'int I<A,B>.m(List<A> las,List<B>
	 * lbs) {}' then this returns a list containing the strings "A" and "B".
	 */
	public List getTypeVariableAliases() {
		return munger.getTypeVariableAliases();
	}

	@Override
	public boolean equals(Object other) {
		if (!(other instanceof BcelTypeMunger)) {
			return false;
		}
		BcelTypeMunger o = (BcelTypeMunger) other;
		return ((o.getMunger() == null) ? (getMunger() == null) : o.getMunger().equals(getMunger()))
				&& ((o.getAspectType() == null) ? (getAspectType() == null) : o.getAspectType().equals(getAspectType()));
		// && (AsmManager.getDefault().getHandleProvider().dependsOnLocation() ? ((o.getSourceLocation() == null) ?
		// (getSourceLocation() == null)
		// : o.getSourceLocation().equals(getSourceLocation()))
		// : true); // pr134471 - remove when handles are improved
		// to be independent of location

	}

	private volatile int hashCode = 0;

	@Override
	public int hashCode() {
		if (hashCode == 0) {
			int result = 17;
			result = 37 * result + ((getMunger() == null) ? 0 : getMunger().hashCode());
			result = 37 * result + ((getAspectType() == null) ? 0 : getAspectType().hashCode());
			hashCode = result;
		}
		return hashCode;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy