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

org.aspectj.weaver.bcel.BcelMethod Maven / Gradle / Ivy

Go to download

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

There is a newer version: 1.9.22.1
Show newest version
/* *******************************************************************
 * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
 * All rights reserved.
 * This program and the accompanying materials are made available
 * under the terms of the Eclipse Public License v 2.0
 * which accompanies this distribution and is available at
 * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.txt
 *
 * Contributors:
 *     PARC     initial implementation
 * ******************************************************************/

package org.aspectj.weaver.bcel;

import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;

import org.aspectj.apache.bcel.classfile.AnnotationDefault;
import org.aspectj.apache.bcel.classfile.Attribute;
import org.aspectj.apache.bcel.classfile.ExceptionTable;
import org.aspectj.apache.bcel.classfile.JavaClass;
import org.aspectj.apache.bcel.classfile.LineNumber;
import org.aspectj.apache.bcel.classfile.LineNumberTable;
import org.aspectj.apache.bcel.classfile.LocalVariable;
import org.aspectj.apache.bcel.classfile.LocalVariableTable;
import org.aspectj.apache.bcel.classfile.Method;
import org.aspectj.apache.bcel.classfile.annotation.AnnotationGen;
import org.aspectj.apache.bcel.classfile.annotation.NameValuePair;
import org.aspectj.bridge.ISourceLocation;
import org.aspectj.bridge.SourceLocation;
import org.aspectj.util.GenericSignature;
import org.aspectj.util.GenericSignature.TypeVariableSignature;
import org.aspectj.util.GenericSignatureParser;
import org.aspectj.weaver.AjAttribute;
import org.aspectj.weaver.AjAttribute.WeaverVersionInfo;
import org.aspectj.weaver.AnnotationAJ;
import org.aspectj.weaver.BCException;
import org.aspectj.weaver.ISourceContext;
import org.aspectj.weaver.MemberKind;
import org.aspectj.weaver.ResolvedMemberImpl;
import org.aspectj.weaver.ResolvedPointcutDefinition;
import org.aspectj.weaver.ResolvedType;
import org.aspectj.weaver.ShadowMunger;
import org.aspectj.weaver.TypeVariable;
import org.aspectj.weaver.UnresolvedType;
import org.aspectj.weaver.World;
import org.aspectj.weaver.bcel.BcelGenericSignatureToTypeXConverter.GenericSignatureFormatException;

//public final
class BcelMethod extends ResolvedMemberImpl {

  private final static String ASPECTJ_ANNOTATION_PACKAGE = "org.aspectj.lang.annotation";
  private final static char PACKAGE_INITIAL_CHAR = ASPECTJ_ANNOTATION_PACKAGE.charAt(0);

	private Method method;

	// these fields are not set for many BcelMethods...
	private ShadowMunger associatedShadowMunger;
	private ResolvedPointcutDefinition preResolvedPointcut; // used when ajc has pre-resolved the pointcut of some @Advice
	private AjAttribute.EffectiveSignatureAttribute effectiveSignature;

	private AjAttribute.MethodDeclarationLineNumberAttribute declarationLineNumber;
	private final BcelObjectType bcelObjectType;

	private int bitflags;
	private static final int KNOW_IF_SYNTHETIC = 0x0001;
	private static final int PARAMETER_NAMES_INITIALIZED = 0x0002;
	private static final int CAN_BE_PARAMETERIZED = 0x0004;
	private static final int UNPACKED_GENERIC_SIGNATURE = 0x0008;
	private static final int IS_AJ_SYNTHETIC = 0x0040;
	private static final int IS_SYNTHETIC = 0x0080;
	private static final int IS_SYNTHETIC_INVERSE = 0x7f7f; // all bits but
	// IS_SYNTHETIC (and
	// topmost bit)
	private static final int HAS_ANNOTATIONS = 0x0400;
	private static final int HAVE_DETERMINED_ANNOTATIONS = 0x0800;

	// genericized version of return and parameter types
	private UnresolvedType genericReturnType = null;
	private UnresolvedType[] genericParameterTypes = null;

	BcelMethod(BcelObjectType declaringType, Method method) {
		super(method.getName().equals("") ? CONSTRUCTOR : (method.getName().equals("") ? STATIC_INITIALIZATION
				: METHOD), declaringType.getResolvedTypeX(), method.getModifiers(), method.getName(), method.getSignature());
		this.method = method;
		sourceContext = declaringType.getResolvedTypeX().getSourceContext();
		bcelObjectType = declaringType;
		unpackJavaAttributes();
		unpackAjAttributes(bcelObjectType.getWorld());
	}

	/**
	 * This constructor expects to be passed the attributes, rather than deserializing them.
	 */
	BcelMethod(BcelObjectType declaringType, Method method, List attributes) {
		super(method.getName().equals("") ? CONSTRUCTOR : (method.getName().equals("") ? STATIC_INITIALIZATION
				: METHOD), declaringType.getResolvedTypeX(), method.getModifiers(), method.getName(), method.getSignature());
		this.method = method;
		sourceContext = declaringType.getResolvedTypeX().getSourceContext();
		bcelObjectType = declaringType;
		unpackJavaAttributes();
		processAttributes(bcelObjectType.getWorld(), attributes);
	}

	// ----

	private void unpackJavaAttributes() {
		ExceptionTable exnTable = method.getExceptionTable();
		checkedExceptions = (exnTable == null) ? UnresolvedType.NONE : UnresolvedType.forNames(exnTable.getExceptionNames());
	}

	@Override
	public String[] getParameterNames() {
		determineParameterNames();
		return super.getParameterNames();
	}

	public int getLineNumberOfFirstInstruction() {
		LineNumberTable lnt = method.getLineNumberTable();
		if (lnt == null) {
			return -1;
		}
		LineNumber[] lns = lnt.getLineNumberTable();
		if (lns == null || lns.length == 0) {
			return -1;
		}
		return lns[0].getLineNumber();
	}

	public void determineParameterNames() {
		if ((bitflags & PARAMETER_NAMES_INITIALIZED) != 0) {
			return;
		}
		bitflags |= PARAMETER_NAMES_INITIALIZED;
		LocalVariableTable varTable = method.getLocalVariableTable();
		int len = getArity();
		if (varTable == null) {
			// do we have an annotation with the argNames value specified...
			AnnotationAJ[] annos = getAnnotations();
			if (annos != null && annos.length != 0) {
				AnnotationAJ[] axs = getAnnotations();
				for (AnnotationAJ annotationX : axs) {
					String typename = annotationX.getTypeName();
					if (typename.charAt(0) == PACKAGE_INITIAL_CHAR) {
						if (typename.equals("org.aspectj.lang.annotation.Pointcut")
								|| typename.equals("org.aspectj.lang.annotation.Before")
								|| typename.equals("org.aspectj.lang.annotation.Around")
								|| typename.startsWith("org.aspectj.lang.annotation.After")) {
							AnnotationGen a = ((BcelAnnotation) annotationX).getBcelAnnotation();
							if (a != null) {
								List values = a.getValues();
								for (NameValuePair nvPair : values) {
									if (nvPair.getNameString().equals("argNames")) {
										String argNames = nvPair.getValue().stringifyValue();
										StringTokenizer argNameTokenizer = new StringTokenizer(argNames, " ,");
										List argsList = new ArrayList<>();
										while (argNameTokenizer.hasMoreTokens()) {
											argsList.add(argNameTokenizer.nextToken());
										}
										int requiredCount = getParameterTypes().length;
										while (argsList.size() < requiredCount) {
											argsList.add("arg" + argsList.size());
										}
										setParameterNames(argsList.toArray(new String[]{}));
										return;
									}
								}
							}
						}
					}
				}
			}
			setParameterNames(Utility.makeArgNames(len));
		} else {
			UnresolvedType[] paramTypes = getParameterTypes();
			String[] paramNames = new String[len];
			int index = Modifier.isStatic(modifiers) ? 0 : 1;
			for (int i = 0; i < len; i++) {
				LocalVariable lv = varTable.getLocalVariable(index);
				if (lv == null) {
					paramNames[i] = "arg" + i;
				} else {
					paramNames[i] = lv.getName();
				}
				index += paramTypes[i].getSize();
			}
			setParameterNames(paramNames);
		}
	}

	private void unpackAjAttributes(World world) {
		associatedShadowMunger = null;
		ResolvedType resolvedDeclaringType = getDeclaringType().resolve(world);
		WeaverVersionInfo wvinfo = bcelObjectType.getWeaverVersionAttribute();
		List as = Utility.readAjAttributes(resolvedDeclaringType.getClassName(), method.getAttributes(),
				resolvedDeclaringType.getSourceContext(), world, wvinfo, new BcelConstantPoolReader(method.getConstantPool()));
		processAttributes(world, as);
		as = AtAjAttributes.readAj5MethodAttributes(method, this, resolvedDeclaringType, preResolvedPointcut,
				resolvedDeclaringType.getSourceContext(), world.getMessageHandler());
		processAttributes(world, as);
	}

	private void processAttributes(World world, List as) {
		for (AjAttribute attr : as) {
			if (attr instanceof AjAttribute.MethodDeclarationLineNumberAttribute) {
				declarationLineNumber = (AjAttribute.MethodDeclarationLineNumberAttribute) attr;
			} else if (attr instanceof AjAttribute.AdviceAttribute) {
				associatedShadowMunger = ((AjAttribute.AdviceAttribute) attr).reify(this, world, (ResolvedType) getDeclaringType());
			} else if (attr instanceof AjAttribute.AjSynthetic) {
				bitflags |= IS_AJ_SYNTHETIC;
			} else if (attr instanceof AjAttribute.EffectiveSignatureAttribute) {
				effectiveSignature = (AjAttribute.EffectiveSignatureAttribute) attr;
			} else if (attr instanceof AjAttribute.PointcutDeclarationAttribute) {
				// this is an @AspectJ annotated advice method, with pointcut pre-resolved by ajc
				preResolvedPointcut = ((AjAttribute.PointcutDeclarationAttribute) attr).reify();
			} else {
				throw new BCException("weird method attribute " + attr);
			}
		}
	}

	//
	// // for testing - if we have this attribute, return it - will return null
	// if
	// // it doesnt know anything
	// public AjAttribute[] getAttributes(String name) {
	// List results = new ArrayList();
	// List l = Utility.readAjAttributes(getDeclaringType().getClassName(),
	// method.getAttributes(),
	// getSourceContext(bcelObjectType.getWorld()), bcelObjectType.getWorld(),
	// bcelObjectType.getWeaverVersionAttribute());
	// for (Iterator iter = l.iterator(); iter.hasNext();) {
	// AjAttribute element = (AjAttribute) iter.next();
	// if (element.getNameString().equals(name))
	// results.add(element);
	// }
	// if (results.size() > 0) {
	// return (AjAttribute[]) results.toArray(new AjAttribute[] {});
	// }
	// return null;
	// }

	@Override
	public String getAnnotationDefaultValue() {
		Attribute[] attrs = method.getAttributes();
		for (Attribute attribute : attrs) {
			if (attribute.getName().equals("AnnotationDefault")) {
				AnnotationDefault def = (AnnotationDefault) attribute;
				return def.getElementValue().stringifyValue();
			}
		}
		return null;
	}

	// for testing - use with the method above
	public String[] getAttributeNames(boolean onlyIncludeAjOnes) {
		Attribute[] as = method.getAttributes();
		List names = new ArrayList<>();
		// String[] strs = new String[as.length];
		for (Attribute a : as) {
			if (!onlyIncludeAjOnes || a.getName().startsWith(AjAttribute.AttributePrefix)) {
				names.add(a.getName());
			}
		}
		return names.toArray(new String[] {});
	}

	@Override
	public boolean isAjSynthetic() {
		return (bitflags & IS_AJ_SYNTHETIC) != 0;
	}

	@Override
	public ShadowMunger getAssociatedShadowMunger() {
		return associatedShadowMunger;
	}

	@Override
	public AjAttribute.EffectiveSignatureAttribute getEffectiveSignature() {
		return effectiveSignature;
	}

	public boolean hasDeclarationLineNumberInfo() {
		return declarationLineNumber != null;
	}

	public int getDeclarationLineNumber() {
		if (declarationLineNumber != null) {
			return declarationLineNumber.getLineNumber();
		} else {
			return -1;
		}
	}

	public int getDeclarationOffset() {
		if (declarationLineNumber != null) {
			return declarationLineNumber.getOffset();
		} else {
			return -1;
		}
	}

	@Override
	public ISourceLocation getSourceLocation() {
		ISourceLocation ret = super.getSourceLocation();
		if ((ret == null || ret.getLine() == 0) && hasDeclarationLineNumberInfo()) {
			// lets see if we can do better
			ISourceContext isc = getSourceContext();
			if (isc != null) {
				ret = isc.makeSourceLocation(getDeclarationLineNumber(), getDeclarationOffset());
			} else {
				ret = new SourceLocation(null, getDeclarationLineNumber());
			}
		}
		return ret;
	}

	@Override
	public MemberKind getKind() {
		if (associatedShadowMunger != null) {
			return ADVICE;
		} else {
			return super.getKind();
		}
	}

	@Override
	public boolean hasAnnotation(UnresolvedType ofType) {
		ensureAnnotationsRetrieved();
		for (ResolvedType aType : annotationTypes) {
			if (aType.equals(ofType)) {
				return true;
			}
		}
		return false;
	}

	@Override
	public AnnotationAJ[] getAnnotations() {
		ensureAnnotationsRetrieved();
		if ((bitflags & HAS_ANNOTATIONS) != 0) {
			return annotations;
		} else {
			return AnnotationAJ.EMPTY_ARRAY;
		}
	}

	@Override
	public ResolvedType[] getAnnotationTypes() {
		ensureAnnotationsRetrieved();
		return annotationTypes;
	}

	@Override
	public AnnotationAJ getAnnotationOfType(UnresolvedType ofType) {
		ensureAnnotationsRetrieved();
		if ((bitflags & HAS_ANNOTATIONS) == 0) {
			return null;
		}
		for (AnnotationAJ annotation : annotations) {
			if (annotation.getTypeName().equals(ofType.getName())) {
				return annotation;
			}
		}
		return null;
	}

	@Override
	public void addAnnotation(AnnotationAJ annotation) {
		ensureAnnotationsRetrieved();
		if ((bitflags & HAS_ANNOTATIONS) == 0) {
			annotations = new AnnotationAJ[1];
			annotations[0] = annotation;
			annotationTypes = new ResolvedType[1];
			annotationTypes[0] = annotation.getType();
		} else {
			// Add it to the set of annotations
			int len = annotations.length;
			AnnotationAJ[] ret = new AnnotationAJ[len + 1];
			System.arraycopy(annotations, 0, ret, 0, len);
			ret[len] = annotation;
			annotations = ret;
			ResolvedType[] newAnnotationTypes = new ResolvedType[len + 1];
			System.arraycopy(annotationTypes, 0, newAnnotationTypes, 0, len);
			newAnnotationTypes[len] = annotation.getType();
			annotationTypes = newAnnotationTypes;
		}
		bitflags |= HAS_ANNOTATIONS;
	}

	public void removeAnnotation(ResolvedType annotationType) {
		ensureAnnotationsRetrieved();
		if ((bitflags & HAS_ANNOTATIONS) == 0) {
			// nothing to do, why did we get called?
		} else {
			int len = annotations.length;
			if (len == 1) {
				bitflags &= ~HAS_ANNOTATIONS;
				annotations = null;
				annotationTypes = null;
				return;
			}
			AnnotationAJ[] ret = new AnnotationAJ[len - 1];
			int p = 0;
			for (AnnotationAJ annotation : annotations) {
				if (!annotation.getType().equals(annotationType)) {
					ret[p++] = annotation;
				}
			}
			annotations = ret;

			ResolvedType[] newAnnotationTypes = new ResolvedType[len - 1];
			p = 0;
			for (AnnotationAJ annotation : annotations) {
				if (!annotation.getType().equals(annotationType)) {
					newAnnotationTypes[p++] = annotationType;
				}
			}
			annotationTypes = newAnnotationTypes;
		}
		bitflags |= HAS_ANNOTATIONS;
	}

	public void addParameterAnnotation(int param, AnnotationAJ anno) {
		ensureParameterAnnotationsRetrieved();
		if (parameterAnnotations == NO_PARAMETER_ANNOTATIONXS) {
			// First time we've added any, so lets set up the array
			parameterAnnotations = new AnnotationAJ[getArity()][];
			for (int i = 0; i < getArity(); i++) {
				parameterAnnotations[i] = AnnotationAJ.EMPTY_ARRAY;
			}
		}
		int existingCount = parameterAnnotations[param].length;
		if (existingCount == 0) {
			AnnotationAJ[] annoArray = new AnnotationAJ[1];
			annoArray[0] = anno;
			parameterAnnotations[param] = annoArray;
		} else {
			AnnotationAJ[] newAnnoArray = new AnnotationAJ[existingCount + 1];
			System.arraycopy(parameterAnnotations[param], 0, newAnnoArray, 0, existingCount);
			newAnnoArray[existingCount] = anno;
			parameterAnnotations[param] = newAnnoArray;
		}
	}

	private void ensureAnnotationsRetrieved() {
		if (method == null) {
			return; // must be ok, we have evicted it
		}
		if ((bitflags & HAVE_DETERMINED_ANNOTATIONS) != 0) {
			return;
		}
		bitflags |= HAVE_DETERMINED_ANNOTATIONS;
		AnnotationGen annos[] = method.getAnnotations();
		if (annos.length == 0) {
			annotationTypes = ResolvedType.NONE;
			annotations = AnnotationAJ.EMPTY_ARRAY;
		} else {
			int annoCount = annos.length;
			annotationTypes = new ResolvedType[annoCount];
			annotations = new AnnotationAJ[annoCount];
			for (int i = 0; i < annoCount; i++) {
				AnnotationGen annotation = annos[i];
				annotations[i] = new BcelAnnotation(annotation, bcelObjectType.getWorld());
				annotationTypes[i] = annotations[i].getType();
			}
			bitflags |= HAS_ANNOTATIONS;
		}
	}

	private void ensureParameterAnnotationsRetrieved() {
		if (method == null) {
			return; // must be ok, we have evicted it
		}
		AnnotationGen[][] pAnns = method.getParameterAnnotations();
		if (parameterAnnotationTypes == null || pAnns.length != parameterAnnotationTypes.length) {
			if (pAnns == Method.NO_PARAMETER_ANNOTATIONS) {
				parameterAnnotationTypes = BcelMethod.NO_PARAMETER_ANNOTATION_TYPES;
				parameterAnnotations = BcelMethod.NO_PARAMETER_ANNOTATIONXS;
			} else {
				AnnotationGen annos[][] = method.getParameterAnnotations();
				parameterAnnotations = new AnnotationAJ[annos.length][];
				parameterAnnotationTypes = new ResolvedType[annos.length][];
				for (int i = 0; i < annos.length; i++) {
					AnnotationGen[] annosOnThisParam = annos[i];
					if (annos[i].length == 0) {
						parameterAnnotations[i] = AnnotationAJ.EMPTY_ARRAY;
						parameterAnnotationTypes[i] = ResolvedType.NONE;
					} else {
						parameterAnnotations[i] = new AnnotationAJ[annosOnThisParam.length];
						parameterAnnotationTypes[i] = new ResolvedType[annosOnThisParam.length];
						for (int j = 0; j < annosOnThisParam.length; j++) {
							parameterAnnotations[i][j] = new BcelAnnotation(annosOnThisParam[j], bcelObjectType.getWorld());
							parameterAnnotationTypes[i][j] = bcelObjectType.getWorld().resolve(
									UnresolvedType.forSignature(annosOnThisParam[j].getTypeSignature()));
						}
					}
				}
			}
		}
	}

	@Override
	public AnnotationAJ[][] getParameterAnnotations() {
		ensureParameterAnnotationsRetrieved();
		return parameterAnnotations;
	}

	@Override
	public ResolvedType[][] getParameterAnnotationTypes() {
		ensureParameterAnnotationsRetrieved();
		return parameterAnnotationTypes;
	}

	/**
	 * A method can be parameterized if it has one or more generic parameters. A generic parameter (type variable parameter) is
	 * identified by the prefix "T"
	 */
	@Override
	public boolean canBeParameterized() {
		unpackGenericSignature();
		return (bitflags & CAN_BE_PARAMETERIZED) != 0;
	}

	@Override
	public UnresolvedType[] getGenericParameterTypes() {
		unpackGenericSignature();
		return genericParameterTypes;
	}

	/**
	 * Return the parameterized/generic return type or the normal return type if the method is not generic.
	 */
	@Override
	public UnresolvedType getGenericReturnType() {
		unpackGenericSignature();
		return genericReturnType;
	}

	/** For testing only */
	public Method getMethod() {
		return method;
	}

	private void unpackGenericSignature() {
		if ((bitflags & UNPACKED_GENERIC_SIGNATURE) != 0) {
			return;
		}
		bitflags |= UNPACKED_GENERIC_SIGNATURE;
		if (!bcelObjectType.getWorld().isInJava5Mode()) {
			genericReturnType = getReturnType();
			genericParameterTypes = getParameterTypes();
			return;
		}
		String gSig = method.getGenericSignature();
		if (gSig != null) {
			GenericSignature.MethodTypeSignature mSig = new GenericSignatureParser().parseAsMethodSignature(gSig);// method
			// .
			// getGenericSignature
			// ());
			if (mSig.formalTypeParameters.length > 0) {
				// generic method declaration
				bitflags |= CAN_BE_PARAMETERIZED;
			}

			typeVariables = new TypeVariable[mSig.formalTypeParameters.length];
			for (int i = 0; i < typeVariables.length; i++) {
				GenericSignature.FormalTypeParameter methodFtp = mSig.formalTypeParameters[i];
				try {
					typeVariables[i] = BcelGenericSignatureToTypeXConverter.formalTypeParameter2TypeVariable(methodFtp,
							mSig.formalTypeParameters, bcelObjectType.getWorld());
				} catch (GenericSignatureFormatException e) {
					// this is a development bug, so fail fast with good info
					throw new IllegalStateException("While getting the type variables for method " + this.toString()
							+ " with generic signature " + mSig + " the following error condition was detected: " + e.getMessage());
				}
			}

			GenericSignature.FormalTypeParameter[] parentFormals = bcelObjectType.getAllFormals();
			GenericSignature.FormalTypeParameter[] formals = new GenericSignature.FormalTypeParameter[parentFormals.length
					+ mSig.formalTypeParameters.length];
			// put method formal in front of type formals for overriding in
			// lookup
			System.arraycopy(mSig.formalTypeParameters, 0, formals, 0, mSig.formalTypeParameters.length);
			System.arraycopy(parentFormals, 0, formals, mSig.formalTypeParameters.length, parentFormals.length);
			GenericSignature.TypeSignature returnTypeSignature = mSig.returnType;
			try {
				genericReturnType = BcelGenericSignatureToTypeXConverter.typeSignature2TypeX(returnTypeSignature, formals,
						bcelObjectType.getWorld());
			} catch (GenericSignatureFormatException e) {
				// development bug, fail fast with good info
				throw new IllegalStateException("While determing the generic return type of " + this.toString()
						+ " with generic signature " + gSig + " the following error was detected: " + e.getMessage());
			}
			GenericSignature.TypeSignature[] paramTypeSigs = mSig.parameters;
			if (paramTypeSigs.length == 0) {
				genericParameterTypes = UnresolvedType.NONE;
			} else {
				genericParameterTypes = new UnresolvedType[paramTypeSigs.length];
			}
			for (int i = 0; i < paramTypeSigs.length; i++) {
				try {
					genericParameterTypes[i] = BcelGenericSignatureToTypeXConverter.typeSignature2TypeX(paramTypeSigs[i], formals,
							bcelObjectType.getWorld());
				} catch (GenericSignatureFormatException e) {
					// development bug, fail fast with good info
					throw new IllegalStateException("While determining the generic parameter types of " + this.toString()
							+ " with generic signature " + gSig + " the following error was detected: " + e.getMessage());
				}
				if (paramTypeSigs[i] instanceof TypeVariableSignature) {
					bitflags |= CAN_BE_PARAMETERIZED;
				}
			}
		} else {
			genericReturnType = getReturnType();
			genericParameterTypes = getParameterTypes();
		}
	}

	@Override
	public void evictWeavingState() {
		if (method != null) {
			unpackGenericSignature();
			unpackJavaAttributes();
			ensureAnnotationsRetrieved();
			ensureParameterAnnotationsRetrieved();
			determineParameterNames();
			// this.sourceContext = SourceContextImpl.UNKNOWN_SOURCE_CONTEXT;
			method = null;
		}
	}

	@Override
	public boolean isSynthetic() {
		if ((bitflags & KNOW_IF_SYNTHETIC) == 0) {
			workOutIfSynthetic();
		}
		return (bitflags & IS_SYNTHETIC) != 0;// isSynthetic;
	}

	// Pre Java5 synthetic is an attribute 'Synthetic', post Java5 it is a
	// modifier (4096 or 0x1000)
	private void workOutIfSynthetic() {
		if ((bitflags & KNOW_IF_SYNTHETIC) != 0) {
			return;
		}
		bitflags |= KNOW_IF_SYNTHETIC;
		JavaClass jc = bcelObjectType.getJavaClass();
		bitflags &= IS_SYNTHETIC_INVERSE; // unset the bit
		if (jc == null) {
			return; // what the hell has gone wrong?
		}
		if (jc.getMajor() < 49/* Java5 */) {
			// synthetic is an attribute
			String[] synthetics = getAttributeNames(false);
			if (synthetics != null) {
				for (String synthetic : synthetics) {
					if (synthetic.equals("Synthetic")) {
						bitflags |= IS_SYNTHETIC;
						break;
					}
				}
			}
		} else {
			// synthetic is a modifier (4096)
			if ((modifiers & 4096) != 0) {
				bitflags |= IS_SYNTHETIC;
			}
		}
	}

	/**
	 * Returns whether or not the given object is equivalent to the current one. Returns true if
	 * getMethod().getCode().getCodeString() are equal. Allows for different line number tables.
	 */
	// bug 154054: is similar to equals(Object) however
	// doesn't require implementing equals in Method and Code
	// which proved expensive. Currently used within
	// CrosscuttingMembers.replaceWith() to decide if we need
	// to do a full build
	@Override
	public boolean isEquivalentTo(Object other) {
		if (!(other instanceof BcelMethod)) {
			return false;
		}
		BcelMethod o = (BcelMethod) other;
		return getMethod().getCode().getCodeString().equals(o.getMethod().getCode().getCodeString());
	}

	/**
	 * Return true if the method represents the default constructor. Hard to determine this from bytecode, but the existence of the
	 * MethodDeclarationLineNumber attribute should tell us.
	 *
	 * @return true if this BcelMethod represents the default constructor
	 */
	@Override
	public boolean isDefaultConstructor() {
		boolean mightBe = !hasDeclarationLineNumberInfo() && name.equals("") && parameterTypes.length == 0;
		if (mightBe) {
			// TODO would be nice to do a check to see if the file was compiled with javac or ajc?
			// maybe by checking the constant pool for aspectj strings?
			return true;
		} else {
			return false;
		}
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy