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

Explore the source code of the class Utility.java

/* *******************************************************************
 * 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 v1.0 
 * which accompanies this distribution and is available at 
 * http://www.eclipse.org/legal/epl-v10.html 
 *  
 * Contributors: 
 *     PARC     initial implementation 
 * ******************************************************************/

package org.aspectj.weaver.bcel;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;

import org.aspectj.apache.bcel.Constants;
import org.aspectj.apache.bcel.classfile.Attribute;
import org.aspectj.apache.bcel.classfile.ClassParser;
import org.aspectj.apache.bcel.classfile.ConstantPool;
import org.aspectj.apache.bcel.classfile.JavaClass;
import org.aspectj.apache.bcel.classfile.Unknown;
import org.aspectj.apache.bcel.classfile.annotation.ArrayElementValue;
import org.aspectj.apache.bcel.classfile.annotation.ElementValue;
import org.aspectj.apache.bcel.classfile.annotation.NameValuePair;
import org.aspectj.apache.bcel.classfile.annotation.SimpleElementValue;
import org.aspectj.apache.bcel.generic.ArrayType;
import org.aspectj.apache.bcel.generic.BasicType;
import org.aspectj.apache.bcel.generic.Instruction;
import org.aspectj.apache.bcel.generic.InstructionByte;
import org.aspectj.apache.bcel.generic.InstructionCP;
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.InstructionSelect;
import org.aspectj.apache.bcel.generic.InstructionShort;
import org.aspectj.apache.bcel.generic.InstructionTargeter;
import org.aspectj.apache.bcel.generic.LineNumberTag;
import org.aspectj.apache.bcel.generic.ObjectType;
import org.aspectj.apache.bcel.generic.ReferenceType;
import org.aspectj.apache.bcel.generic.SwitchBuilder;
import org.aspectj.apache.bcel.generic.TargetLostException;
import org.aspectj.apache.bcel.generic.Type;
import org.aspectj.bridge.ISourceLocation;
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.ConstantPoolReader;
import org.aspectj.weaver.ISourceContext;
import org.aspectj.weaver.Lint;
import org.aspectj.weaver.Member;
import org.aspectj.weaver.ResolvedType;
import org.aspectj.weaver.UnresolvedType;
import org.aspectj.weaver.Utils;
import org.aspectj.weaver.World;

public class Utility {

	public static List readAjAttributes(String classname, Attribute[] as, ISourceContext context, World w,
			AjAttribute.WeaverVersionInfo version, ConstantPoolReader dataDecompressor) {
		List attributes = new ArrayList();

		// first pass, look for version
		List forSecondPass = new ArrayList();
		for (int i = as.length - 1; i >= 0; i--) {
			Attribute a = as[i];
			if (a instanceof Unknown) {
				Unknown u = (Unknown) a;
				String name = u.getName();
				if (name.charAt(0) == 'o') { // 'o'rg.aspectj
					if (name.startsWith(AjAttribute.AttributePrefix)) {
						if (name.endsWith(WeaverVersionInfo.AttributeName)) {
							version = (AjAttribute.WeaverVersionInfo) AjAttribute.read(version, name, u.getBytes(), context, w,
									dataDecompressor);
							if (version.getMajorVersion() > WeaverVersionInfo.getCurrentWeaverMajorVersion()) {
								throw new BCException(
										"Unable to continue, this version of AspectJ supports classes built with weaver version "
												+ WeaverVersionInfo.toCurrentVersionString() + " but the class " + classname
												+ " is version " + version.toString() + ".  Please update your AspectJ.");
							}
						}
						forSecondPass.add(u);
					}
				}
			}
		}

		// FIXASC why going backwards? is it important
		for (int i = forSecondPass.size() - 1; i >= 0; i--) {
			Unknown a = forSecondPass.get(i);
			String name = a.getName();
			AjAttribute attr = AjAttribute.read(version, name, a.getBytes(), context, w, dataDecompressor);
			if (attr != null) {
				attributes.add(attr);
			}
		}
		return attributes;
	}

	/*
	 * Ensure we report a nice source location - particular in the case where the source info is missing (binary weave).
	 */
	public static String beautifyLocation(ISourceLocation isl) {
		StringBuffer nice = new StringBuffer();
		if (isl == null || isl.getSourceFile() == null || isl.getSourceFile().getName().indexOf("no debug info available") != -1) {
			nice.append("no debug info available");
		} else {
			// can't use File.getName() as this fails when a Linux box
			// encounters a path created on Windows and vice-versa
			int takeFrom = isl.getSourceFile().getPath().lastIndexOf('/');
			if (takeFrom == -1) {
				takeFrom = isl.getSourceFile().getPath().lastIndexOf('\\');
			}
			nice.append(isl.getSourceFile().getPath().substring(takeFrom + 1));
			if (isl.getLine() != 0) {
				nice.append(":").append(isl.getLine());
			}
		}
		return nice.toString();
	}

	public static Instruction createSuperInvoke(InstructionFactory fact, BcelWorld world, Member signature) {
		short kind;
		if (Modifier.isInterface(signature.getModifiers())) {
			throw new RuntimeException("bad");
		} else if (Modifier.isPrivate(signature.getModifiers()) || signature.getName().equals("")) {
			throw new RuntimeException("unimplemented, possibly bad");
		} else if (Modifier.isStatic(signature.getModifiers())) {
			throw new RuntimeException("bad");
		} else {
			kind = Constants.INVOKESPECIAL;
		}

		return fact.createInvoke(signature.getDeclaringType().getName(), signature.getName(),
				BcelWorld.makeBcelType(signature.getReturnType()), BcelWorld.makeBcelTypes(signature.getParameterTypes()), kind);
	}

	public static Instruction createInvoke(InstructionFactory fact, BcelWorld world, Member signature) {
		short kind;
		int signatureModifiers = signature.getModifiers();
		if (Modifier.isInterface(signatureModifiers)) {
			kind = Constants.INVOKEINTERFACE;
		} else if (Modifier.isStatic(signatureModifiers)) {
			kind = Constants.INVOKESTATIC;
		} else if (Modifier.isPrivate(signatureModifiers) || signature.getName().equals("")) {
			kind = Constants.INVOKESPECIAL;
		} else {
			kind = Constants.INVOKEVIRTUAL;
		}

		UnresolvedType targetType = signature.getDeclaringType();
		if (targetType.isParameterizedType()) {
			targetType = targetType.resolve(world).getGenericType();
		}
		return fact.createInvoke(targetType.getName(), signature.getName(), BcelWorld.makeBcelType(signature.getReturnType()),
				BcelWorld.makeBcelTypes(signature.getParameterTypes()), kind);
	}

	public static Instruction createGet(InstructionFactory fact, Member signature) {
		short kind;
		if (Modifier.isStatic(signature.getModifiers())) {
			kind = Constants.GETSTATIC;
		} else {
			kind = Constants.GETFIELD;
		}

		return fact.createFieldAccess(signature.getDeclaringType().getName(), signature.getName(),
				BcelWorld.makeBcelType(signature.getReturnType()), kind);
	}

	public static Instruction createSet(InstructionFactory fact, Member signature) {
		short kind;
		if (Modifier.isStatic(signature.getModifiers())) {
			kind = Constants.PUTSTATIC;
		} else {
			kind = Constants.PUTFIELD;
		}

		return fact.createFieldAccess(signature.getDeclaringType().getName(), signature.getName(),
				BcelWorld.makeBcelType(signature.getReturnType()), kind);
	}

	public static Instruction createInstanceof(InstructionFactory fact, ReferenceType t) {
		int cpoolEntry = (t instanceof ArrayType) ? fact.getConstantPool().addArrayClass((ArrayType) t) : fact.getConstantPool()
				.addClass((ObjectType) t);
		return new InstructionCP(Constants.INSTANCEOF, cpoolEntry);
	}

	public static Instruction createInvoke(InstructionFactory fact, LazyMethodGen m) {
		short kind;
		if (m.getEnclosingClass().isInterface()) {
			if (m.isStatic()) {
				// For static methods on interfaces
				kind = Constants.INVOKESTATIC;				
			} else {
				kind = Constants.INVOKEINTERFACE;
			}
		} else if (m.isStatic()) {
			kind = Constants.INVOKESTATIC;
		} else if (m.isPrivate() || m.getName().equals("")) {
			kind = Constants.INVOKESPECIAL;
		} else {
			kind = Constants.INVOKEVIRTUAL;
		}

		return fact.createInvoke(m.getClassName(), m.getName(), m.getReturnType(), m.getArgumentTypes(), kind);
	}

	/**
	 * Create an invoke instruction
	 * 
	 * @param fact
	 * @param kind INVOKEINTERFACE, INVOKEVIRTUAL..
	 * @param member
	 * @return
	 */
	public static Instruction createInvoke(InstructionFactory fact, short kind, Member member) {
		return fact.createInvoke(member.getDeclaringType().getName(), member.getName(),
				BcelWorld.makeBcelType(member.getReturnType()), BcelWorld.makeBcelTypes(member.getParameterTypes()), kind);
	}

	private static String[] argNames = new String[] { "arg0", "arg1", "arg2", "arg3", "arg4" };

	// ??? these should perhaps be cached. Remember to profile this to see if
	// it's a problem.
	public static String[] makeArgNames(int n) {
		String[] ret = new String[n];
		for (int i = 0; i < n; i++) {
			if (i < 5) {
				ret[i] = argNames[i];
			} else {
				ret[i] = "arg" + i;
			}
		}
		return ret;
	}

	// Lookup table, for converting between pairs of types, it gives
	// us the method name in the Conversions class
	private static Hashtable validBoxing = new Hashtable();

	static {
		validBoxing.put("Ljava/lang/Byte;B", "byteObject");
		validBoxing.put("Ljava/lang/Character;C", "charObject");
		validBoxing.put("Ljava/lang/Double;D", "doubleObject");
		validBoxing.put("Ljava/lang/Float;F", "floatObject");
		validBoxing.put("Ljava/lang/Integer;I", "intObject");
		validBoxing.put("Ljava/lang/Long;J", "longObject");
		validBoxing.put("Ljava/lang/Short;S", "shortObject");
		validBoxing.put("Ljava/lang/Boolean;Z", "booleanObject");
		validBoxing.put("BLjava/lang/Byte;", "byteValue");
		validBoxing.put("CLjava/lang/Character;", "charValue");
		validBoxing.put("DLjava/lang/Double;", "doubleValue");
		validBoxing.put("FLjava/lang/Float;", "floatValue");
		validBoxing.put("ILjava/lang/Integer;", "intValue");
		validBoxing.put("JLjava/lang/Long;", "longValue");
		validBoxing.put("SLjava/lang/Short;", "shortValue");
		validBoxing.put("ZLjava/lang/Boolean;", "booleanValue");
	}

	public static void appendConversion(InstructionList il, InstructionFactory fact, ResolvedType fromType, ResolvedType toType) {
		if (!toType.isConvertableFrom(fromType) && !fromType.isConvertableFrom(toType)) {
			throw new BCException("can't convert from " + fromType + " to " + toType);
		}
		// XXX I'm sure this test can be simpler but my brain hurts and this works
		World w = toType.getWorld();
		if (w == null) { // dbg349636
			throw new IllegalStateException("Debug349636: Unexpectedly found world null for type " + toType.getName());
		}

		if (!w.isInJava5Mode()) {
			if (toType.needsNoConversionFrom(fromType)) {
				return;
			}
		} else {
			if (toType.needsNoConversionFrom(fromType) && !(toType.isPrimitiveType() ^ fromType.isPrimitiveType())) {
				return;
			}
		}
		if (toType.equals(UnresolvedType.VOID)) {
			// assert fromType.equals(UnresolvedType.OBJECT)
			il.append(InstructionFactory.createPop(fromType.getSize()));
		} else if (fromType.equals(UnresolvedType.VOID)) {
			// assert toType.equals(UnresolvedType.OBJECT)
			il.append(InstructionFactory.createNull(Type.OBJECT));
			return;
		} else if (fromType.equals(UnresolvedType.OBJECT)) {
			Type to = BcelWorld.makeBcelType(toType);
			if (toType.isPrimitiveType()) {
				String name = toType.toString() + "Value";
				il.append(fact.createInvoke("org.aspectj.runtime.internal.Conversions", name, to, new Type[] { Type.OBJECT },
						Constants.INVOKESTATIC));
			} else {
				il.append(fact.createCheckCast((ReferenceType) to));
			}
		} else if (toType.equals(UnresolvedType.OBJECT)) {
			// assert fromType.isPrimitive()
			Type from = BcelWorld.makeBcelType(fromType);
			String name = fromType.toString() + "Object";
			il.append(fact.createInvoke("org.aspectj.runtime.internal.Conversions", name, Type.OBJECT, new Type[] { from },
					Constants.INVOKESTATIC));
		} else if (toType.getWorld().isInJava5Mode() && validBoxing.get(toType.getSignature() + fromType.getSignature()) != null) {
			// XXX could optimize by using any java boxing code that may be just
			// before the call...
			Type from = BcelWorld.makeBcelType(fromType);
			Type to = BcelWorld.makeBcelType(toType);
			String name = validBoxing.get(toType.getSignature() + fromType.getSignature());
			if (toType.isPrimitiveType()) {
				il.append(fact.createInvoke("org.aspectj.runtime.internal.Conversions", name, to, new Type[] { Type.OBJECT },
						Constants.INVOKESTATIC));
			} else {
				il.append(fact.createInvoke("org.aspectj.runtime.internal.Conversions", name, Type.OBJECT, new Type[] { from },
						Constants.INVOKESTATIC));
				il.append(fact.createCheckCast((ReferenceType) to));
			}
		} else if (fromType.isPrimitiveType()) {
			// assert toType.isPrimitive()
			Type from = BcelWorld.makeBcelType(fromType);
			Type to = BcelWorld.makeBcelType(toType);
			try {
				Instruction i = fact.createCast(from, to);
				if (i != null) {
					il.append(i);
				} else {
					il.append(fact.createCast(from, Type.INT));
					il.append(fact.createCast(Type.INT, to));
				}
			} catch (RuntimeException e) {
				il.append(fact.createCast(from, Type.INT));
				il.append(fact.createCast(Type.INT, to));
			}
		} else {
			Type to = BcelWorld.makeBcelType(toType);
			// assert ! fromType.isPrimitive() && ! toType.isPrimitive()
			il.append(fact.createCheckCast((ReferenceType) to));
		}
	}

	public static InstructionList createConversion(InstructionFactory factory, Type fromType, Type toType) {
		return createConversion(factory, fromType, toType, false);
	}

	public static InstructionList createConversion(InstructionFactory fact, Type fromType, Type toType, boolean allowAutoboxing) {
		// System.out.println("cast to: " + toType);

		InstructionList il = new InstructionList();

		// PR71273
		if ((fromType.equals(Type.BYTE) || fromType.equals(Type.CHAR) || fromType.equals(Type.SHORT)) && (toType.equals(Type.INT))) {
			return il;
		}

		if (fromType.equals(toType)) {
			return il;
		}
		if (toType.equals(Type.VOID)) {
			il.append(InstructionFactory.createPop(fromType.getSize()));
			return il;
		}

		if (fromType.equals(Type.VOID)) {
			if (toType instanceof BasicType) {
				throw new BCException("attempting to cast from void to basic type");
			}
			il.append(InstructionFactory.createNull(Type.OBJECT));
			return il;
		}

		if (fromType.equals(Type.OBJECT)) {
			if (toType instanceof BasicType) {
				String name = toType.toString() + "Value";
				il.append(fact.createInvoke("org.aspectj.runtime.internal.Conversions", name, toType, new Type[] { Type.OBJECT },
						Constants.INVOKESTATIC));
				return il;
			}
		}

		if (toType.equals(Type.OBJECT)) {
			if (fromType instanceof BasicType) {
				String name = fromType.toString() + "Object";
				il.append(fact.createInvoke("org.aspectj.runtime.internal.Conversions", name, Type.OBJECT, new Type[] { fromType },
						Constants.INVOKESTATIC));
				return il;
			} else if (fromType instanceof ReferenceType) {
				return il;
			} else {
				throw new RuntimeException();
			}
		}

		if (fromType instanceof ReferenceType && ((ReferenceType) fromType).isAssignmentCompatibleWith(toType)) {
			return il;
		}

		if (allowAutoboxing) {
			if (toType instanceof BasicType && fromType instanceof ReferenceType) {
				// unboxing
				String name = toType.toString() + "Value";
				il.append(fact.createInvoke("org.aspectj.runtime.internal.Conversions", name, toType, new Type[] { Type.OBJECT },
						Constants.INVOKESTATIC));
				return il;
			}

			if (fromType instanceof BasicType && toType instanceof ReferenceType) {
				// boxing
				String name = fromType.toString() + "Object";
				il.append(fact.createInvoke("org.aspectj.runtime.internal.Conversions", name, Type.OBJECT, new Type[] { fromType },
						Constants.INVOKESTATIC));
				il.append(fact.createCast(Type.OBJECT, toType));
				return il;
			}
		}

		il.append(fact.createCast(fromType, toType));
		return il;
	}

	public static Instruction createConstant(InstructionFactory fact, int value) {
		Instruction inst;
		switch (value) {
		case -1:
			inst = InstructionConstants.ICONST_M1;
			break;
		case 0:
			inst = InstructionConstants.ICONST_0;
			break;
		case 1:
			inst = InstructionConstants.ICONST_1;
			break;
		case 2:
			inst = InstructionConstants.ICONST_2;
			break;
		case 3:
			inst = InstructionConstants.ICONST_3;
			break;
		case 4:
			inst = InstructionConstants.ICONST_4;
			break;
		case 5:
			inst = InstructionConstants.ICONST_5;
			break;
		default:
			if (value <= Byte.MAX_VALUE && value >= Byte.MIN_VALUE) {
				inst = new InstructionByte(Constants.BIPUSH, (byte) value);
			} else if (value <= Short.MAX_VALUE && value >= Short.MIN_VALUE) {
				inst = new InstructionShort(Constants.SIPUSH, (short) value);
			} else {
				int ii = fact.getClassGen().getConstantPool().addInteger(value);
				inst = new InstructionCP(value <= Constants.MAX_BYTE ? Constants.LDC : Constants.LDC_W, ii);
			}
			break;
		}
		return inst;
	}

	/** For testing purposes: bit clunky but does work */
	public static int testingParseCounter = 0;

	public static JavaClass makeJavaClass(String filename, byte[] bytes) {
		try {
			testingParseCounter++;
			ClassParser parser = new ClassParser(new ByteArrayInputStream(bytes), filename);
			return parser.parse();
		} catch (IOException e) {
			throw new BCException("malformed class file");
		}
	}

	/**
	 * replace an instruction handle with another instruction, in this case, a branch instruction.
	 * 
	 * @param ih the instruction handle to replace.
	 * @param branchInstruction the branch instruction to replace ih with
	 * @param enclosingMethod where to find ih's instruction list.
	 */
	public static void replaceInstruction(InstructionHandle ih, InstructionList replacementInstructions,
			LazyMethodGen enclosingMethod) {
		InstructionList il = enclosingMethod.getBody();
		InstructionHandle fresh = il.append(ih, replacementInstructions);
		deleteInstruction(ih, fresh, enclosingMethod);
	}

	/**
	 * delete an instruction handle and retarget all targeters of the deleted instruction to the next instruction. Obviously, this
	 * should not be used to delete a control transfer instruction unless you know what you're doing.
	 * 
	 * @param ih the instruction handle to delete.
	 * @param enclosingMethod where to find ih's instruction list.
	 */
	public static void deleteInstruction(InstructionHandle ih, LazyMethodGen enclosingMethod) {
		deleteInstruction(ih, ih.getNext(), enclosingMethod);
	}

	/**
	 * delete an instruction handle and retarget all targeters of the deleted instruction to the provided target.
	 * 
	 * @param ih the instruction handle to delete
	 * @param retargetTo the instruction handle to retarget targeters of ih to.
	 * @param enclosingMethod where to find ih's instruction list.
	 */
	public static void deleteInstruction(InstructionHandle ih, InstructionHandle retargetTo, LazyMethodGen enclosingMethod) {
		InstructionList il = enclosingMethod.getBody();
		for (InstructionTargeter targeter : ih.getTargetersCopy()) {
			targeter.updateTarget(ih, retargetTo);
		}
		ih.removeAllTargeters();
		try {
			il.delete(ih);
		} catch (TargetLostException e) {
			throw new BCException("this really can't happen");
		}
	}

	/**
	 * Fix for Bugzilla #39479, #40109 patch contributed by Andy Clement
	 * 
	 * Need to manually copy Select instructions - if we rely on the the 'fresh' object created by copy(), the InstructionHandle
	 * array 'targets' inside the Select object will not have been deep copied, so modifying targets in fresh will modify the
	 * original Select - not what we want ! (It is a bug in BCEL to do with cloning Select objects).
	 * 
	 * 
	 * declare error:
	 *     call(* Instruction.copy()) && within(org.aspectj.weaver)
	 *       && !withincode(* Utility.copyInstruction(Instruction)):
	 *     "use Utility.copyInstruction to work-around bug in Select.copy()";
	 * 
*/ public static Instruction copyInstruction(Instruction i) { if (i instanceof InstructionSelect) { InstructionSelect freshSelect = (InstructionSelect) i; // Create a new targets array that looks just like the existing one InstructionHandle[] targets = new InstructionHandle[freshSelect.getTargets().length]; for (int ii = 0; ii < targets.length; ii++) { targets[ii] = freshSelect.getTargets()[ii]; } // Create a new select statement with the new targets array return new SwitchBuilder(freshSelect.getMatchs(), targets, freshSelect.getTarget()).getInstruction(); } else { return i.copy(); // Use clone for shallow copy... } } /** returns -1 if no source line attribute */ // this naive version overruns the JVM stack size, if only Java understood // tail recursion... // public static int getSourceLine(InstructionHandle ih) { // if (ih == null) return -1; // // InstructionTargeter[] ts = ih.getTargeters(); // if (ts != null) { // for (int j = ts.length - 1; j >= 0; j--) { // InstructionTargeter t = ts[j]; // if (t instanceof LineNumberTag) { // return ((LineNumberTag)t).getLineNumber(); // } // } // } // return getSourceLine(ih.getNext()); // } public static int getSourceLine(InstructionHandle ih) {// ,boolean // goforwards) { int lookahead = 0; // arbitrary rule that we will never lookahead more than 100 // instructions for a line # while (lookahead++ < 100) { if (ih == null) { return -1; } Iterator tIter = ih.getTargeters().iterator(); while (tIter.hasNext()) { InstructionTargeter t = tIter.next(); if (t instanceof LineNumberTag) { return ((LineNumberTag) t).getLineNumber(); } } // if (goforwards) ih=ih.getNext(); else ih = ih.getPrev(); } // System.err.println("no line information available for: " + ih); return -1; } // public static int getSourceLine(InstructionHandle ih) { // return getSourceLine(ih,false); // } // assumes that there is no already extant source line tag. Otherwise we'll // have to be better. public static void setSourceLine(InstructionHandle ih, int lineNumber) { // OPTIMIZE LineNumberTag instances for the same line could be shared // throughout a method... ih.addTargeter(new LineNumberTag(lineNumber)); } public static int makePublic(int i) { return i & ~(Modifier.PROTECTED | Modifier.PRIVATE) | Modifier.PUBLIC; } public static BcelVar[] pushAndReturnArrayOfVars(ResolvedType[] proceedParamTypes, InstructionList il, InstructionFactory fact, LazyMethodGen enclosingMethod) { int len = proceedParamTypes.length; BcelVar[] ret = new BcelVar[len]; for (int i = len - 1; i >= 0; i--) { ResolvedType typeX = proceedParamTypes[i]; Type type = BcelWorld.makeBcelType(typeX); int local = enclosingMethod.allocateLocal(type); il.append(InstructionFactory.createStore(type, local)); ret[i] = new BcelVar(typeX, local); } return ret; } public static boolean isConstantPushInstruction(Instruction i) { long ii = Constants.instFlags[i.opcode]; return ((ii & Constants.PUSH_INST) != 0 && (ii & Constants.CONSTANT_INST) != 0); } /** * Checks for suppression specified on the member or on the declaring type of that member */ public static boolean isSuppressing(Member member, String lintkey) { boolean isSuppressing = Utils.isSuppressing(member.getAnnotations(), lintkey); if (isSuppressing) { return true; } UnresolvedType type = member.getDeclaringType(); if (type instanceof ResolvedType) { return Utils.isSuppressing(((ResolvedType) type).getAnnotations(), lintkey); } return false; } public static List getSuppressedWarnings(AnnotationAJ[] anns, Lint lint) { if (anns == null) { return Collections.emptyList(); } // Go through the annotation types List suppressedWarnings = new ArrayList(); boolean found = false; for (int i = 0; !found && i < anns.length; i++) { // Check for the SuppressAjWarnings annotation if (UnresolvedType.SUPPRESS_AJ_WARNINGS.getSignature().equals( ((BcelAnnotation) anns[i]).getBcelAnnotation().getTypeSignature())) { found = true; // Two possibilities: // 1. there are no values specified (i.e. @SuppressAjWarnings) // 2. there are values specified (i.e. @SuppressAjWarnings("A") // or @SuppressAjWarnings({"A","B"}) List vals = ((BcelAnnotation) anns[i]).getBcelAnnotation().getValues(); if (vals == null || vals.isEmpty()) { // (1) suppressedWarnings.addAll(lint.allKinds()); } else { // (2) // We know the value is an array value ArrayElementValue array = (ArrayElementValue) (vals.get(0)).getValue(); ElementValue[] values = array.getElementValuesArray(); for (int j = 0; j < values.length; j++) { // We know values in the array are strings SimpleElementValue value = (SimpleElementValue) values[j]; Lint.Kind lintKind = lint.getLintKind(value.getValueString()); if (lintKind != null) { suppressedWarnings.add(lintKind); } } } } } return suppressedWarnings; } // not yet used... // public static boolean isSimple(Method method) { // if (method.getCode()==null) return true; // if (method.getCode().getCode().length>10) return false; // InstructionList instrucs = new // InstructionList(method.getCode().getCode()); // expensive! // InstructionHandle InstrHandle = instrucs.getStart(); // while (InstrHandle != null) { // Instruction Instr = InstrHandle.getInstruction(); // int opCode = Instr.opcode; // // if current instruction is a branch instruction, see if it's a backward // branch. // // if it is return immediately (can't be trivial) // if (Instr instanceof InstructionBranch) { // // InstructionBranch BI = (InstructionBranch) Instr; // if (Instr.getIndex() < 0) return false; // } else if (Instr instanceof InvokeInstruction) { // // if current instruction is an invocation, indicate that it can't be // trivial // return false; // } // InstrHandle = InstrHandle.getNext(); // } // return true; // } public static Attribute bcelAttribute(AjAttribute a, ConstantPool pool) { int nameIndex = pool.addUtf8(a.getNameString()); byte[] bytes = a.getBytes(new BcelConstantPoolWriter(pool)); int length = bytes.length; return new Unknown(nameIndex, length, bytes, pool); } }