/* *******************************************************************
 * 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.weaver;

import java.lang.reflect.Modifier;

/**
 * The AjcMemberMaker is responsible for creating the representations of methods/fields/etc that are placed in both aspects and
 * affected target types. It uses the NameMangler class to create the actual names that will be used.
 */
public class AjcMemberMaker {

	private static final int PUBLIC_STATIC_FINAL = Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL;

	private static final int PRIVATE_STATIC = Modifier.PRIVATE | Modifier.STATIC;

	private static final int PUBLIC_STATIC = Modifier.PUBLIC | Modifier.STATIC;

	private static final int BRIDGE = 0x0040;

	private static final int VISIBILITY = Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED;

	public static final UnresolvedType CFLOW_STACK_TYPE = UnresolvedType.forName(NameMangler.CFLOW_STACK_TYPE);

	public static final UnresolvedType AROUND_CLOSURE_TYPE = UnresolvedType
			.forSignature("Lorg/aspectj/runtime/internal/AroundClosure;");

	public static final UnresolvedType CONVERSIONS_TYPE = UnresolvedType.forSignature("Lorg/aspectj/runtime/internal/Conversions;");

	public static final UnresolvedType NO_ASPECT_BOUND_EXCEPTION = UnresolvedType
			.forSignature("Lorg/aspectj/lang/NoAspectBoundException;");

	public static ResolvedMember ajcPreClinitMethod(UnresolvedType declaringType) {
		return new ResolvedMemberImpl(Member.METHOD, declaringType, PRIVATE_STATIC, NameMangler.AJC_PRE_CLINIT_NAME, "()V");
	}

	public static ResolvedMember ajcPostClinitMethod(UnresolvedType declaringType) {
		return new ResolvedMemberImpl(Member.METHOD, declaringType, PRIVATE_STATIC, NameMangler.AJC_POST_CLINIT_NAME, "()V");
	}

	public static Member noAspectBoundExceptionInit() {
		return new ResolvedMemberImpl(Member.METHOD, NO_ASPECT_BOUND_EXCEPTION, Modifier.PUBLIC, "<init>", "()V");
	}

	public static Member noAspectBoundExceptionInit2() {
		return new ResolvedMemberImpl(Member.METHOD, NO_ASPECT_BOUND_EXCEPTION, Modifier.PUBLIC, "<init>",
				"(Ljava/lang/String;Ljava/lang/Throwable;)V");
	}

	public static Member noAspectBoundExceptionInitWithCause() {
		return new ResolvedMemberImpl(Member.METHOD, NO_ASPECT_BOUND_EXCEPTION, Modifier.PUBLIC, "<init>",
				"(Ljava/lang/String;Ljava/lang/Throwable;)V");
	}

	public static ResolvedMember perCflowPush(UnresolvedType declaringType) {
		return new ResolvedMemberImpl(Member.METHOD, declaringType, PUBLIC_STATIC, NameMangler.PERCFLOW_PUSH_METHOD, "()V");
	}

	public static ResolvedMember perCflowField(UnresolvedType declaringType) {
		return new ResolvedMemberImpl(Member.FIELD, declaringType, PUBLIC_STATIC, NameMangler.PERCFLOW_FIELD_NAME,
				CFLOW_STACK_TYPE.getSignature());
	}

	public static ResolvedMember perSingletonField(UnresolvedType declaringType) {
		return new ResolvedMemberImpl(Member.FIELD, declaringType, PUBLIC_STATIC, NameMangler.PERSINGLETON_FIELD_NAME,
				declaringType.getSignature());
	}

	public static ResolvedMember initFailureCauseField(UnresolvedType declaringType) {
		return new ResolvedMemberImpl(Member.FIELD, declaringType, PRIVATE_STATIC, NameMangler.INITFAILURECAUSE_FIELD_NAME,
				UnresolvedType.THROWABLE.getSignature());
	}

	public static ResolvedMember perObjectField(UnresolvedType declaringType, ResolvedType aspectType) {
		int modifiers = Modifier.PRIVATE;
		if (!UnresolvedType.SERIALIZABLE.resolve(aspectType.getWorld()).isAssignableFrom(aspectType)) {
			modifiers |= Modifier.TRANSIENT;
		}
		return new ResolvedMemberImpl(Member.FIELD, declaringType, modifiers, aspectType,
				NameMangler.perObjectInterfaceField(aspectType), UnresolvedType.NONE);
	}

	// PTWIMPL ResolvedMember for aspect instance field, declared in matched type
	public static ResolvedMember perTypeWithinField(UnresolvedType declaringType, ResolvedType aspectType) {
		int modifiers = Modifier.PRIVATE | Modifier.STATIC;
		if (!isSerializableAspect(aspectType)) {
			modifiers |= Modifier.TRANSIENT;
		}
		return new ResolvedMemberImpl(Member.FIELD, declaringType, modifiers, aspectType,
				NameMangler.perTypeWithinFieldForTarget(aspectType), UnresolvedType.NONE);
	}

	// PTWIMPL ResolvedMember for type instance field, declared in aspect
	// (holds typename for which aspect instance exists)
	public static ResolvedMember perTypeWithinWithinTypeField(UnresolvedType declaringType, ResolvedType aspectType) {
		int modifiers = Modifier.PRIVATE;
		if (!isSerializableAspect(aspectType)) {
			modifiers |= Modifier.TRANSIENT;
		}
		return new ResolvedMemberImpl(Member.FIELD, declaringType, modifiers, UnresolvedType.JL_STRING,
				NameMangler.PERTYPEWITHIN_WITHINTYPEFIELD, UnresolvedType.NONE);
	}

	private static boolean isSerializableAspect(ResolvedType aspectType) {
		return UnresolvedType.SERIALIZABLE.resolve(aspectType.getWorld()).isAssignableFrom(aspectType);
	}

	public static ResolvedMember perObjectBind(UnresolvedType declaringType) {
		return new ResolvedMemberImpl(Member.METHOD, declaringType, PUBLIC_STATIC | Modifier.SYNCHRONIZED, NameMangler.PEROBJECT_BIND_METHOD,
				"(Ljava/lang/Object;)V");
	}

	// PTWIMPL ResolvedMember for getInstance() method, declared in aspect
	public static ResolvedMember perTypeWithinGetInstance(UnresolvedType declaringType) {
		// private static a.X ajc$getInstance(java.lang.Class)
		ResolvedMemberImpl rm = new ResolvedMemberImpl(Member.METHOD, declaringType, PRIVATE_STATIC, declaringType, // return value
				NameMangler.PERTYPEWITHIN_GETINSTANCE_METHOD, new UnresolvedType[] { UnresolvedType.JL_CLASS });
		return rm;
	}

	// PTWIMPL ResolvedMember for getWithinTypeName() method
	public static ResolvedMember perTypeWithinGetWithinTypeNameMethod(UnresolvedType declaringType, boolean inJava5Mode) {
		// public String getWithinTypeName()
		ResolvedMemberImpl rm = new ResolvedMemberImpl(Member.METHOD, declaringType, Modifier.PUBLIC, UnresolvedType.JL_STRING, // return
																																// value
				NameMangler.PERTYPEWITHIN_GETWITHINTYPENAME_METHOD, UnresolvedType.NONE);
		return rm;
	}

	public static ResolvedMember perTypeWithinCreateAspectInstance(UnresolvedType declaringType) {
		// public static a.X ajc$createAspectInstance(java.lang.String)
		ResolvedMemberImpl rm = new ResolvedMemberImpl(Member.METHOD, declaringType, PUBLIC_STATIC, declaringType, // return value
				NameMangler.PERTYPEWITHIN_CREATEASPECTINSTANCE_METHOD,
				new UnresolvedType[] { UnresolvedType.forSignature("Ljava/lang/String;") }, UnresolvedType.NONE);
		return rm;
	}

	public static UnresolvedType perObjectInterfaceType(UnresolvedType aspectType) {
		return UnresolvedType.forName(aspectType.getName() + "$ajcMightHaveAspect");
	}

	public static ResolvedMember perObjectInterfaceGet(UnresolvedType aspectType) {
		return new ResolvedMemberImpl(Member.METHOD, perObjectInterfaceType(aspectType), Modifier.PUBLIC | Modifier.ABSTRACT,
				NameMangler.perObjectInterfaceGet(aspectType), "()" + aspectType.getSignature());
	}

	public static ResolvedMember perObjectInterfaceSet(UnresolvedType aspectType) {
		return new ResolvedMemberImpl(Member.METHOD, perObjectInterfaceType(aspectType), Modifier.PUBLIC | Modifier.ABSTRACT,
				NameMangler.perObjectInterfaceSet(aspectType), "(" + aspectType.getSignature() + ")V");
	}

	// PTWIMPL ResolvedMember for localAspectOf() method, declared in matched type
	public static ResolvedMember perTypeWithinLocalAspectOf(UnresolvedType shadowType, UnresolvedType aspectType) {
		return new ResolvedMemberImpl(Member.METHOD, shadowType,// perTypeWithinInterfaceType(aspectType),
				Modifier.PUBLIC | Modifier.STATIC, NameMangler.perTypeWithinLocalAspectOf(aspectType), "()"
						+ aspectType.getSignature());
	}

	public static ResolvedMember perSingletonAspectOfMethod(UnresolvedType declaringType) {
		return new ResolvedMemberImpl(Member.METHOD, declaringType, PUBLIC_STATIC, "aspectOf", "()" + declaringType.getSignature());
	}

	public static ResolvedMember perSingletonHasAspectMethod(UnresolvedType declaringType) {
		return new ResolvedMemberImpl(Member.METHOD, declaringType, PUBLIC_STATIC, "hasAspect", "()Z");
	}

	public static ResolvedMember perCflowAspectOfMethod(UnresolvedType declaringType) {
		return perSingletonAspectOfMethod(declaringType);
	}

	public static ResolvedMember perCflowHasAspectMethod(UnresolvedType declaringType) {
		return perSingletonHasAspectMethod(declaringType);
	}

	public static ResolvedMember perObjectAspectOfMethod(UnresolvedType declaringType) {
		return new ResolvedMemberImpl(Member.METHOD, declaringType, PUBLIC_STATIC, "aspectOf", "(Ljava/lang/Object;)"
				+ declaringType.getSignature());
	}

	public static ResolvedMember perObjectHasAspectMethod(UnresolvedType declaringType) {
		return new ResolvedMemberImpl(Member.METHOD, declaringType, PUBLIC_STATIC, "hasAspect", "(Ljava/lang/Object;)Z");
	}

	// PTWIMPL ResolvedMember for aspectOf(), declared in aspect
	public static ResolvedMember perTypeWithinAspectOfMethod(UnresolvedType declaringType, boolean inJava5Mode) {
		UnresolvedType parameterType = null;
		if (inJava5Mode) {
			parameterType = UnresolvedType.forRawTypeName("java.lang.Class");
		} else {
			parameterType = UnresolvedType.forSignature("Ljava/lang/Class;");
		}
		return new ResolvedMemberImpl(Member.METHOD, declaringType, PUBLIC_STATIC, declaringType, "aspectOf",
				new UnresolvedType[] { parameterType });
		// return new ResolvedMemberImpl(Member.METHOD,
		// declaringType, PUBLIC_STATIC, "aspectOf",
		// "(Ljava/lang/Class;)" + declaringType.getSignature());
	}

	/*
	 * public static ResolvedMember perTypeWithinGetWithinTypeMethod(UnresolvedType declaringType, boolean inJava5Mode) {
	 * UnresolvedType returnType = null; if (inJava5Mode) { returnType = UnresolvedType.forRawTypeName("java.lang.Class"); } else {
	 * returnType = UnresolvedType.forSignature("Ljava/lang/Class;"); } return new
	 * ResolvedMemberImpl(Member.METHOD,declaringType,Modifier.PUBLIC,ResolvedType.JAVA_LANG_STRING,"getWithinType",new
	 * UnresolvedType[]{}); }
	 */

	// PTWIMPL ResolvedMember for hasAspect(), declared in aspect
	public static ResolvedMember perTypeWithinHasAspectMethod(UnresolvedType declaringType, boolean inJava5Mode) {
		UnresolvedType parameterType = null;
		if (inJava5Mode) {
			parameterType = UnresolvedType.forRawTypeName("java.lang.Class");
		} else {
			parameterType = UnresolvedType.forSignature("Ljava/lang/Class;");
		}
		return new ResolvedMemberImpl(Member.METHOD, declaringType, PUBLIC_STATIC, UnresolvedType.BOOLEAN, "hasAspect",
				new UnresolvedType[] { parameterType });
		// return new ResolvedMemberImpl(Member.METHOD,
		// declaringType, PUBLIC_STATIC, "hasAspect",
		// "(Ljava/lang/Class;)Z");
	}

	// -- privileged accessors

	public static ResolvedMember privilegedAccessMethodForMethod(UnresolvedType aspectType, ResolvedMember method) {
		return new ResolvedMemberImpl(Member.METHOD, method.getDeclaringType(), Modifier.PUBLIC
				| (Modifier.isStatic(method.getModifiers()) ? Modifier.STATIC : 0), method.getReturnType(),
				NameMangler.privilegedAccessMethodForMethod(method.getName(), method.getDeclaringType(), aspectType),
				method.getParameterTypes(), method.getExceptions());
	}

	/**
	 * Return a resolvedmember representing the synthetic getter for the field. The old style (&lt;1.6.9) is a heavyweight static
	 * method with a long name. The new style (1.6.9 and later) is short, and reusable across aspects.
	 *
	 * @param aspectType the aspect attempting the access
	 * @param field the field to be accessed
	 * @param shortSyntax is the old (long) or new (short) style format being used
	 * @return a resolvedmember representing the synthetic getter
	 */
	public static ResolvedMember privilegedAccessMethodForFieldGet(UnresolvedType aspectType, Member field, boolean shortSyntax) {
		UnresolvedType fieldDeclaringType = field.getDeclaringType();
		if (shortSyntax) {
			UnresolvedType[] args = null;
			if (Modifier.isStatic(field.getModifiers())) {
				args = ResolvedType.NONE;
			} else {
				args = new UnresolvedType[] { fieldDeclaringType };
			}
			StringBuilder name = new StringBuilder("ajc$get$");
			name.append(field.getName());
			return new ResolvedMemberImpl(Member.METHOD, fieldDeclaringType, PUBLIC_STATIC, field.getReturnType(), name.toString(),
					args);
		} else {
			String getterName = NameMangler.privilegedAccessMethodForFieldGet(field.getName(), fieldDeclaringType, aspectType);
			String sig;
			if (Modifier.isStatic(field.getModifiers())) {
				sig = "()" + field.getReturnType().getSignature();
			} else {
				sig = "(" + fieldDeclaringType.getSignature() + ")" + field.getReturnType().getSignature();
			}
			return new ResolvedMemberImpl(Member.METHOD, fieldDeclaringType, PUBLIC_STATIC, getterName, sig);
		}
	}

	/**
	 * Return a resolvedmember representing the synthetic setter for the field. The old style (&lt;1.6.9) is a heavyweight static
	 * method with a long name. The new style (1.6.9 and later) is short, not always static, and reusable across aspects.
	 *
	 * @param aspectType the aspect attempting the access
	 * @param field the field to be accessed
	 * @param shortSyntax is the old or new style format being used
	 * @return a resolvedmember representing the synthetic setter
	 */
	public static ResolvedMember privilegedAccessMethodForFieldSet(UnresolvedType aspectType, Member field, boolean shortSyntax) {
		UnresolvedType fieldDeclaringType = field.getDeclaringType();
		if (shortSyntax) {
			UnresolvedType[] args = null;
			if (Modifier.isStatic(field.getModifiers())) {
				args = new UnresolvedType[] { field.getType() };
			} else {
				args = new UnresolvedType[] { fieldDeclaringType, field.getType() };
			}
			StringBuilder name = new StringBuilder("ajc$set$");
			name.append(field.getName());
			return new ResolvedMemberImpl(Member.METHOD, fieldDeclaringType, PUBLIC_STATIC, UnresolvedType.VOID, name.toString(),
					args);
		} else {
			String setterName = NameMangler.privilegedAccessMethodForFieldSet(field.getName(), fieldDeclaringType, aspectType);
			String sig;
			if (Modifier.isStatic(field.getModifiers())) {
				sig = "(" + field.getReturnType().getSignature() + ")V";
			} else {
				sig = "(" + fieldDeclaringType.getSignature() + field.getReturnType().getSignature() + ")V";
			}
			return new ResolvedMemberImpl(Member.METHOD, fieldDeclaringType, PUBLIC_STATIC, setterName, sig);
		}
	}

	// --- inline accessors
	// ??? can eclipse handle a transform this weird without putting synthetics into the mix
	public static ResolvedMember superAccessMethod(UnresolvedType baseType, ResolvedMember method) {
		UnresolvedType[] paramTypes = method.getParameterTypes();
		// if (!method.isStatic()) {
		// paramTypes = UnresolvedType.insert(method.getDeclaringType(), paramTypes);
		// }
		return new ResolvedMemberImpl(Member.METHOD, baseType, Modifier.PUBLIC, method.getReturnType(),
				NameMangler.superDispatchMethod(baseType, method.getName()), paramTypes, method.getExceptions());
	}

	public static ResolvedMember inlineAccessMethodForMethod(UnresolvedType aspectType, ResolvedMember method) {
		UnresolvedType[] paramTypes = method.getParameterTypes();
		if (!Modifier.isStatic(method.getModifiers())) {
			paramTypes = UnresolvedType.insert(method.getDeclaringType(), paramTypes);
		}
		return new ResolvedMemberImpl(Member.METHOD, aspectType,
				PUBLIC_STATIC, // ??? what about privileged and super access
				// ???Modifier.PUBLIC | (method.isStatic() ? Modifier.STATIC : 0),
				method.getReturnType(),

				NameMangler.inlineAccessMethodForMethod(method.getName(), method.getDeclaringType(), aspectType), paramTypes,
				method.getExceptions());
	}

	public static ResolvedMember inlineAccessMethodForFieldGet(UnresolvedType aspectType, Member field) {
		String sig;
		if (Modifier.isStatic(field.getModifiers())) {
			sig = "()" + field.getReturnType().getSignature();
		} else {
			sig = "(" + field.getDeclaringType().getSignature() + ")" + field.getReturnType().getSignature();
		}

		return new ResolvedMemberImpl(Member.METHOD, aspectType, PUBLIC_STATIC, // Modifier.PUBLIC | (field.isStatic() ?
				// Modifier.STATIC : 0),
				NameMangler.inlineAccessMethodForFieldGet(field.getName(), field.getDeclaringType(), aspectType), sig);
	}

	public static ResolvedMember inlineAccessMethodForFieldSet(UnresolvedType aspectType, Member field) {
		String sig;
		if (Modifier.isStatic(field.getModifiers())) {
			sig = "(" + field.getReturnType().getSignature() + ")V";
		} else {
			sig = "(" + field.getDeclaringType().getSignature() + field.getReturnType().getSignature() + ")V";
		}

		return new ResolvedMemberImpl(Member.METHOD, aspectType, PUBLIC_STATIC, // Modifier.PUBLIC | (field.isStatic() ?
				// Modifier.STATIC : 0),
				NameMangler.inlineAccessMethodForFieldSet(field.getName(), field.getDeclaringType(), aspectType), sig);
	}

	// --- runtimeLibrary api stuff

	public static Member cflowStackPeekInstance() {
		return new MemberImpl(Member.METHOD, CFLOW_STACK_TYPE, 0, "peekInstance", "()Ljava/lang/Object;");
	}

	public static Member cflowStackPushInstance() {
		return new MemberImpl(Member.METHOD, CFLOW_STACK_TYPE, 0, "pushInstance", "(Ljava/lang/Object;)V");
	}

	public static Member cflowStackIsValid() {
		return new MemberImpl(Member.METHOD, CFLOW_STACK_TYPE, 0, "isValid", "()Z");
	}

	public static Member cflowStackInit() {
		return new MemberImpl(Member.CONSTRUCTOR, CFLOW_STACK_TYPE, 0, "<init>", "()V");
	}

	public static Member aroundClosurePreInitializationField() {
		return new MemberImpl(Member.FIELD, AROUND_CLOSURE_TYPE, 0, "preInitializationState", "[Ljava/lang/Object;");
	}

	public static Member aroundClosurePreInitializationGetter() {
		return new MemberImpl(Member.METHOD, AROUND_CLOSURE_TYPE, 0, "getPreInitializationState", "()[Ljava/lang/Object;");
	}

	public static ResolvedMember preIntroducedConstructor(UnresolvedType aspectType, UnresolvedType targetType,
			UnresolvedType[] paramTypes) {
		return new ResolvedMemberImpl(Member.METHOD, aspectType, PUBLIC_STATIC_FINAL, UnresolvedType.OBJECTARRAY,
				NameMangler.preIntroducedConstructor(aspectType, targetType), paramTypes);
	}

	public static ResolvedMember postIntroducedConstructor(UnresolvedType aspectType, UnresolvedType targetType,
			UnresolvedType[] paramTypes) {
		return new ResolvedMemberImpl(Member.METHOD, aspectType, PUBLIC_STATIC_FINAL, UnresolvedType.VOID,
				NameMangler.postIntroducedConstructor(aspectType, targetType), UnresolvedType.insert(targetType, paramTypes));
	}

	public static ResolvedMember itdAtDeclareParentsField(ResolvedType targetType, UnresolvedType itdType, UnresolvedType aspectType) {
		return new ResolvedMemberImpl(Member.FIELD, targetType, Modifier.PRIVATE, itdType, NameMangler.itdAtDeclareParentsField(
				aspectType, itdType), ResolvedType.NONE);
	}

	public static ResolvedMember interConstructor(ResolvedType targetType, ResolvedMember constructor, UnresolvedType aspectType) {
		//
		// ResolvedType targetType,
		// UnresolvedType[] argTypes,
		// int modifiers)
		// {
		ResolvedMember ret = new ResolvedMemberImpl(Member.CONSTRUCTOR, targetType, Modifier.PUBLIC, UnresolvedType.VOID, "<init>",
				constructor.getParameterTypes(), constructor.getExceptions());
		// System.out.println("ret: " + ret + " mods: " + Modifier.toString(modifiers));
		if (Modifier.isPublic(constructor.getModifiers())) {
			return ret;
		}
		while (true) {
			ret = addCookieTo(ret, aspectType);
			if (targetType.lookupMemberNoSupers(ret) == null) {
				return ret;
			}
		}
	}

	public static ResolvedMember interFieldInitializer(ResolvedMember field, UnresolvedType aspectType) {
		return new ResolvedMemberImpl(Member.METHOD, aspectType, PUBLIC_STATIC, NameMangler.interFieldInitializer(aspectType,
				field.getDeclaringType(), field.getName()), Modifier.isStatic(field.getModifiers()) ? "()V" : "("
				+ field.getDeclaringType().getSignature() + ")V");
	}

	private static int makePublicNonFinal(int modifiers) {
		return (modifiers & ~VISIBILITY & ~Modifier.FINAL) | Modifier.PUBLIC;
	}

	private static int makeNonFinal(int modifiers) {
		return (modifiers & ~Modifier.FINAL);
	}

	/**
	 * This static method goes on the aspect that declares the inter-type field
	 */
	public static ResolvedMember interFieldSetDispatcher(ResolvedMember field, UnresolvedType aspectType) {
		ResolvedMember rm = new ResolvedMemberImpl(Member.METHOD, aspectType, PUBLIC_STATIC, UnresolvedType.VOID,
				NameMangler.interFieldSetDispatcher(aspectType, field.getDeclaringType(), field.getName()), Modifier.isStatic(field
						.getModifiers()) ? new UnresolvedType[] { field.getReturnType() } : new UnresolvedType[] {
						field.getDeclaringType(), field.getReturnType() });
		rm.setTypeVariables(field.getTypeVariables());
		return rm;
	}

	/**
	 * This static method goes on the aspect that declares the inter-type field
	 */
	public static ResolvedMember interFieldGetDispatcher(ResolvedMember field, UnresolvedType aspectType) {
		ResolvedMember rm = new ResolvedMemberImpl(Member.METHOD, aspectType, PUBLIC_STATIC, field.getReturnType(),
				NameMangler.interFieldGetDispatcher(aspectType, field.getDeclaringType(), field.getName()), Modifier.isStatic(field
						.getModifiers()) ? UnresolvedType.NONE : new UnresolvedType[] { field.getDeclaringType() },
				UnresolvedType.NONE);
		rm.setTypeVariables(field.getTypeVariables());
		return rm;
	}

	// private static int makeFieldModifiers(int declaredModifiers) {
	// int ret = Modifier.PUBLIC;
	// if (Modifier.isTransient(declaredModifiers)) ret |= Modifier.TRANSIENT;
	// if (Modifier.isVolatile(declaredModifiers)) ret |= Modifier.VOLATILE;
	// return ret;
	// }

	/**
	 * This field goes on the class the field is declared onto. Field names for ITDs onto interfaces are handled below.
	 */
	public static ResolvedMember interFieldClassField(ResolvedMember field, UnresolvedType aspectType, boolean newStyle) {
		int modifiers = (newStyle ? makeNonFinal(field.getModifiers()) : makePublicNonFinal(field.getModifiers()));
		String name = null;
		if (newStyle) {
			name = field.getName();
		} else {
			name = NameMangler.interFieldClassField(field.getModifiers(), aspectType, field.getDeclaringType(), field.getName());
		}
		return new ResolvedMemberImpl(Member.FIELD, field.getDeclaringType(), modifiers, field.getReturnType(), name,
				UnresolvedType.NONE, UnresolvedType.NONE);
	}

	/**
	 * This field goes on top-most implementers of the interface the field is declared onto
	 */
	public static ResolvedMember interFieldInterfaceField(ResolvedMember field, UnresolvedType onClass, UnresolvedType aspectType, boolean newStyle) {
		String name = null;
		if (newStyle) {
			name = field.getName();
		} else {
			name = NameMangler.interFieldInterfaceField(aspectType, field.getDeclaringType(), field.getName());
		}
		return new ResolvedMemberImpl(Member.FIELD, onClass, makePublicNonFinal(field.getModifiers()), field.getReturnType(),
				name, UnresolvedType.NONE, UnresolvedType.NONE);
	}

	/**
	 * This instance method goes on the interface the field is declared onto as well as its top-most implementors
	 */
	public static ResolvedMember interFieldInterfaceSetter(ResolvedMember field, ResolvedType onType, UnresolvedType aspectType) {
		int modifiers = Modifier.PUBLIC;
		if (onType.isInterface()) {
			modifiers |= Modifier.ABSTRACT;
		}
		ResolvedMember rm = new ResolvedMemberImpl(Member.METHOD, onType, modifiers, UnresolvedType.VOID,
				NameMangler.interFieldInterfaceSetter(aspectType, field.getDeclaringType(), field.getName()),
				new UnresolvedType[] { field.getReturnType() }, UnresolvedType.NONE);
		rm.setTypeVariables(field.getTypeVariables());
		return rm;
	}

	/**
	 * This instance method goes on the interface the field is declared onto as well as its top-most implementors
	 */
	public static ResolvedMember interFieldInterfaceGetter(ResolvedMember field, ResolvedType onType, UnresolvedType aspectType) {
		int modifiers = Modifier.PUBLIC;
		if (onType.isInterface()) {
			modifiers |= Modifier.ABSTRACT;
		}
		ResolvedMember rm = new ResolvedMemberImpl(Member.METHOD, onType, modifiers, field.getReturnType(),
				NameMangler.interFieldInterfaceGetter(aspectType, field.getDeclaringType(), field.getName()), UnresolvedType.NONE,
				UnresolvedType.NONE);
		rm.setTypeVariables(field.getTypeVariables());
		return rm;
	}

	/**
	 * This method goes on the target type of the inter-type method. (and possibly the topmost-implementors, if the target type is
	 * an interface). The implementation will call the interMethodDispatch method on the aspect.
	 */
	public static ResolvedMember interMethod(ResolvedMember meth, UnresolvedType aspectType, boolean onInterface) {
		if (Modifier.isPublic(meth.getModifiers()) && !onInterface) {
			return meth;
		}

		int modifiers = makePublicNonFinal(meth.getModifiers());
		if (onInterface) {
			modifiers |= Modifier.ABSTRACT;
		}

		ResolvedMemberImpl rmi = new ResolvedMemberImpl(Member.METHOD, meth.getDeclaringType(), modifiers, meth.getReturnType(),
				NameMangler.interMethod(meth.getModifiers(), aspectType, meth.getDeclaringType(), meth.getName()),
				meth.getParameterTypes(), meth.getExceptions());
		rmi.setParameterNames(meth.getParameterNames());
		rmi.setTypeVariables(meth.getTypeVariables());
		return rmi;
	}

	/**
	 * This method goes on the target type of the inter-type method. (and possibly the topmost-implementors, if the target type is
	 * an interface). The implementation will call the interMethodDispatch method on the aspect.
	 */
	public static ResolvedMember interMethodBridger(ResolvedMember meth, UnresolvedType aspectType, boolean onInterface) {
		// if (Modifier.isPublic(meth.getModifiers()) && !onInterface)
		// return meth;

		int modifiers = makePublicNonFinal(meth.getModifiers()) | BRIDGE;
		if (onInterface) {
			modifiers |= Modifier.ABSTRACT;
		}

		ResolvedMemberImpl rmi = new ResolvedMemberImpl(Member.METHOD, meth.getDeclaringType(), modifiers, meth.getReturnType(),
				NameMangler.interMethod(meth.getModifiers(), aspectType, meth.getDeclaringType(), meth.getName()),
				meth.getParameterTypes(), meth.getExceptions());
		rmi.setTypeVariables(meth.getTypeVariables());
		return rmi;
	}

	/**
	 * Sometimes the intertyped method requires a bridge method alongside it. For example if the method 'N SomeI&lt;N&gt;.m()' is put onto
	 * an interface 'interface I&lt;N extends Number&gt;' and then a concrete implementation is 'class C implements I&lt;Float&gt;' then the ITD
	 * on the interface will be 'Number m()', whereas the ITD on the 'topmostimplementor' will be 'Float m()'. A bridge method needs
	 * to be created in the topmostimplementor 'Number m()' that delegates to 'Float m()'
	 */
	public static ResolvedMember bridgerToInterMethod(ResolvedMember meth, UnresolvedType aspectType) {

		int modifiers = makePublicNonFinal(meth.getModifiers());

		ResolvedMemberImpl rmi = new ResolvedMemberImpl(Member.METHOD, aspectType, modifiers, meth.getReturnType(),
				NameMangler.interMethod(meth.getModifiers(), aspectType, meth.getDeclaringType(), meth.getName()),
				meth.getParameterTypes(), meth.getExceptions());
		rmi.setTypeVariables(meth.getTypeVariables());
		return rmi;
	}

	/**
	 * This static method goes on the declaring aspect of the inter-type method. The implementation calls the interMethodBody()
	 * method on the aspect.
	 */
	public static ResolvedMember interMethodDispatcher(ResolvedMember meth, UnresolvedType aspectType) {
		UnresolvedType[] paramTypes = meth.getParameterTypes();
		if (!Modifier.isStatic(meth.getModifiers())) {
			paramTypes = UnresolvedType.insert(meth.getDeclaringType(), paramTypes);
		}

		ResolvedMemberImpl rmi = new ResolvedMemberImpl(Member.METHOD, aspectType, PUBLIC_STATIC, meth.getReturnType(),
				NameMangler.interMethodDispatcher(aspectType, meth.getDeclaringType(), meth.getName()), paramTypes,
				meth.getExceptions());
		rmi.setParameterNames(meth.getParameterNames());
		rmi.setTypeVariables(meth.getTypeVariables());

		return rmi;
	}

	/**
	 * This method goes on the declaring aspect of the inter-type method. It contains the real body of the ITD method.
	 */
	public static ResolvedMember interMethodBody(ResolvedMember meth, UnresolvedType aspectType) {
		UnresolvedType[] paramTypes = meth.getParameterTypes();
		if (!Modifier.isStatic(meth.getModifiers())) {
			paramTypes = UnresolvedType.insert(meth.getDeclaringType(), paramTypes);
		}

		int modifiers = PUBLIC_STATIC;
		if (Modifier.isStrict(meth.getModifiers())) {
			modifiers |= Modifier.STRICT;
		}

		ResolvedMemberImpl rmi = new ResolvedMemberImpl(Member.METHOD, aspectType, modifiers, meth.getReturnType(),
				NameMangler.interMethodBody(aspectType, meth.getDeclaringType(), meth.getName()), paramTypes, meth.getExceptions());
		rmi.setParameterNames(meth.getParameterNames());
		rmi.setTypeVariables(meth.getTypeVariables());
		return rmi;
	}

	private static ResolvedMember addCookieTo(ResolvedMember ret, UnresolvedType aspectType) {
		UnresolvedType[] params = ret.getParameterTypes();

		UnresolvedType[] freshParams = UnresolvedType.add(params, aspectType);
		return new ResolvedMemberImpl(ret.getKind(), ret.getDeclaringType(), ret.getModifiers(), ret.getReturnType(),
				ret.getName(), freshParams, ret.getExceptions());
	}

	public static ResolvedMember toObjectConversionMethod(UnresolvedType fromType) {
		if (fromType.isPrimitiveType()) {
			String name = fromType.toString() + "Object";
			return new ResolvedMemberImpl(Member.METHOD, CONVERSIONS_TYPE, PUBLIC_STATIC, UnresolvedType.OBJECT, name,
					new UnresolvedType[] { fromType }, UnresolvedType.NONE);
		} else {
			return null;
		}
	}

	public static Member interfaceConstructor(ResolvedType resolvedTypeX) {
		// AMC next two lines should not be needed when sig for generic type is changed
		ResolvedType declaringType = resolvedTypeX;
		if (declaringType.isRawType()) {
			declaringType = declaringType.getGenericType();
		}
		return new ResolvedMemberImpl(Member.CONSTRUCTOR, declaringType, Modifier.PUBLIC, "<init>", "()V");
	}

	// -- common types we use. Note: Java 5 dependand types are refered to as String
	public final static UnresolvedType ASPECT_ANNOTATION = UnresolvedType.forSignature("Lorg/aspectj/lang/annotation/Aspect;");

	public final static UnresolvedType BEFORE_ANNOTATION = UnresolvedType.forSignature("Lorg/aspectj/lang/annotation/Before;");

	public final static UnresolvedType AROUND_ANNOTATION = UnresolvedType.forSignature("Lorg/aspectj/lang/annotation/Around;");

	public final static UnresolvedType AFTERRETURNING_ANNOTATION = UnresolvedType
			.forSignature("Lorg/aspectj/lang/annotation/AfterReturning;");

	public final static UnresolvedType AFTERTHROWING_ANNOTATION = UnresolvedType
			.forSignature("Lorg/aspectj/lang/annotation/AfterThrowing;");

	public final static UnresolvedType AFTER_ANNOTATION = UnresolvedType.forSignature("Lorg/aspectj/lang/annotation/After;");

	public final static UnresolvedType POINTCUT_ANNOTATION = UnresolvedType.forSignature("Lorg/aspectj/lang/annotation/Pointcut;");

	public final static UnresolvedType DECLAREERROR_ANNOTATION = UnresolvedType
			.forSignature("Lorg/aspectj/lang/annotation/DeclareError;");

	public final static UnresolvedType DECLAREWARNING_ANNOTATION = UnresolvedType
			.forSignature("Lorg/aspectj/lang/annotation/DeclareWarning;");

	public final static UnresolvedType DECLAREPRECEDENCE_ANNOTATION = UnresolvedType
			.forSignature("Lorg/aspectj/lang/annotation/DeclarePrecedence;");

	// public final static UnresolvedType DECLAREIMPLEMENTS_ANNOTATION =
	// UnresolvedType.forSignature("Lorg/aspectj/lang/annotation/DeclareImplements;");

	public final static UnresolvedType DECLAREPARENTS_ANNOTATION = UnresolvedType
			.forSignature("Lorg/aspectj/lang/annotation/DeclareParents;");

	public final static UnresolvedType DECLAREMIXIN_ANNOTATION = UnresolvedType
			.forSignature("Lorg/aspectj/lang/annotation/DeclareMixin;");

	public final static UnresolvedType TYPEX_JOINPOINT = UnresolvedType.forSignature("Lorg/aspectj/lang/JoinPoint;");

	public final static UnresolvedType TYPEX_PROCEEDINGJOINPOINT = UnresolvedType
			.forSignature("Lorg/aspectj/lang/ProceedingJoinPoint;");

	public final static UnresolvedType TYPEX_STATICJOINPOINT = UnresolvedType
			.forSignature("Lorg/aspectj/lang/JoinPoint$StaticPart;");

	public final static UnresolvedType TYPEX_ENCLOSINGSTATICJOINPOINT = UnresolvedType
			.forSignature("Lorg/aspectj/lang/JoinPoint$EnclosingStaticPart;");

}
