Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * fb-contrib - Auxiliary detectors for Java programs
   * Copyright (C) 2005-2012 Dave Brosius
   * 
   * This library is free software; you can redistribute it and/or
   * modify it under the terms of the GNU Lesser General Public
   * License as published by the Free Software Foundation; either
   * version 2.1 of the License, or (at your option) any later version.
   * 
  * This library is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * Lesser General Public License for more details.
  * 
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 package com.mebigfatguy.fbcontrib.detect;
 
 import java.util.Map;
 import java.util.Set;
 
 import  org.apache.bcel.Constants;
 import  org.apache.bcel.classfile.JavaClass;
 import  org.apache.bcel.classfile.Method;
 
 
 import  edu.umd.cs.findbugs.BugInstance;
 import  edu.umd.cs.findbugs.BugReporter;
 import  edu.umd.cs.findbugs.BytecodeScanningDetector;
 import  edu.umd.cs.findbugs.OpcodeStack;
 import  edu.umd.cs.findbugs.ba.ClassContext;
 import  edu.umd.cs.findbugs.ba.XField;

looks for uses of sets or maps where the key is an enum. In these cases, it is more efficient to use EnumSet or EnumMap. It is a jdk1.5 only detector.
 
 public class UseEnumCollections extends BytecodeScanningDetector 
 {	
 	private static final Set<StringnonEnumCollections = new HashSet<String>();
 	static {
 		.add("Ljava/util/HashSet;");
 		.add("Ljava/util/HashMap;");
 		.add("Ljava/util/TreeMap;");
 		.add("Ljava/util/ConcurrentHashMap");
 		.add("Ljava/util/IdentityHashMap;");
 		.add("Ljava/util/WeakHashMap;");
 	}
 	private final BugReporter bugReporter;
 	private OpcodeStack stack;
 	private Set<StringcheckedFields;
 	private Map<IntegerBooleanenumRegs;
 	private Map<StringBooleanenumFields;
 	private boolean methodReported;
constructs a UEC detector given the reporter to report bugs on

Parameters:
bugReporter the sync of bug reports
 
 	public UseEnumCollections(BugReporter bugReporter) {
 		this. = bugReporter;
 	}

implements the visitor to check that the class is greater or equal than 1.5, and set and clear the stack

Parameters:
classContext the context object for the currently parsed class
 
 	public void visitClassContext(ClassContext classContext) {
 		try {
 			JavaClass cls = classContext.getJavaClass();
 			if (cls.getMajor() >= Constants.MAJOR_1_5) {
 				 = new OpcodeStack();
 				 = new HashMap<IntegerBoolean>();
 				super.visitClassContext(classContext);
 			}
 		} finally {
 			 = null;
 			 = null;
 			 = null;
 			 = null;
 		}
 	}

implements the visitor to reset the state

Parameters:
obj the context object for the currently parsed method
 
 	public void visitMethod(Method obj) {
		.resetForMethodEntry(this);
		 = false;
		super.visitMethod(obj);
	}
	public void sawOpcode(int seen) {
		Boolean sawEnumCollectionCreation = null//true - enum, false - nonenum
		try {
			.mergeJumps(this);
				return;
			if (seen == INVOKESTATIC) {
				String signature = getSigConstantOperand();
				if ("java/util/EnumSet".equals(clsName) && signature.endsWith(")Ljava/util/EnumSet;"))
					sawEnumCollectionCreation = .;
else if (seen == INVOKESPECIAL) {
				String methodName = getNameConstantOperand();
				if ("java/util/EnumMap".equals(clsName) && "<init>".equals(methodName))
					sawEnumCollectionCreation = .;
				else if (clsName.startsWith("java/util/")) {
					if (clsName.endsWith("Map") || clsName.endsWith("Set"))
						sawEnumCollectionCreation = .;
				}
else if ((seen == ASTORE) || ((seen >= ASTORE_0) && (seen <= ASTORE_3))) {
				if (.getStackDepth() > 0) {
					OpcodeStack.Item itm = .getStackItem(0);
					Integer reg = Integer.valueOf(RegisterUtils.getAStoreReg(thisseen));
					if (itm.getUserValue() != null)
						.put(reg, (Boolean)itm.getUserValue());
					else
				}
else if ((seen == ALOAD) || ((seen >= ALOAD_0) && (seen <= ALOAD_3))) {
				Integer reg = Integer.valueOf(RegisterUtils.getALoadReg(thisseen));
				sawEnumCollectionCreation = .get(reg);
else if (seen == PUTFIELD) {
				if (.getStackDepth() > 0) {
					OpcodeStack.Item itm = .getStackItem(0);
					if (itm.getUserValue() != null)
						.put(fieldName, (Boolean)itm.getUserValue());
					else
						.remove(fieldName);
				}
else if (seen == GETFIELD) {
				sawEnumCollectionCreation = .get(fieldName);
else if (seen == INVOKEINTERFACE) {
				boolean bug = false;
				String methodName = getNameConstantOperand();
				String signature = getSigConstantOperand();
				if (("java/util/Map".equals(clsName))
				&&  ("put".equals(methodName))
				&&  ("(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;".equals(signature))) {
					bug = isEnum(1) && !isEnumCollection(2) && !alreadyReported(2);
else if (("java/util/Set".equals(clsName))
						&& ("add".equals(methodName))
						&& ("(Ljava/lang/Object;)Z".equals(signature))) {
					bug = isEnum(0) && !isEnumCollection(1) && !alreadyReported(1);
				}
				if (bug) {
					.reportBug(new BugInstance(this"UEC_USE_ENUM_COLLECTIONS", NORMAL_PRIORITY)
									.addClass(this)
									.addMethod(this)
									.addSourceLine(this));
				}
			}
catch (ClassNotFoundException cnfe) {
			.reportMissingClass(cnfe);
finally {
			TernaryPatcher.pre(seen);
			.sawOpcode(thisseen);
			TernaryPatcher.post(seen);
			if (sawEnumCollectionCreation != null) {
				if (.getStackDepth() > 0) {
					OpcodeStack.Item itm = .getStackItem(0);
					itm.setUserValue(sawEnumCollectionCreation);
				}
			}
		}
	}

returns whether the item at the stackPos location on the stack is an enum, and doesn't implement any interfaces

Parameters:
stackPos the position on the opstack to check
Returns:
whether the class is an enum
Throws:
ClassNotFoundException if the class can not be loaded
	private boolean isEnum(int stackPosthrows ClassNotFoundException {
		if (.getStackDepth() > stackPos) {
			OpcodeStack.Item item = .getStackItem(stackPos);
			if (item.getSignature().charAt(0) != 'L')
				return false;
			JavaClass cls =  item.getJavaClass();
			if ((cls == null) || !cls.isEnum())
				return false;
			//If the cls implements any interface, it's possible the collection
			//is based on that interface, so ignore
			if (cls.getInterfaces().length == 0)
				return true;
		}
		return false;
	}

returns whether the item at the stackpos location is an instance of an EnumSet or EnumMap

Parameters:
stackPos the position on the opstack to check
Returns:
whether the class is an EnumSet or EnumMap
	private boolean isEnumCollection(int stackPos) {
		if (.getStackDepth() <= stackPos)
			return false;
		OpcodeStack.Item item = .getStackItem(stackPos);
		Boolean userValue = (Boolean)item.getUserValue();
		if (userValue != null)
			return userValue.booleanValue();
		String realClass = item.getSignature();
		if ("Ljava/util/EnumSet;".equals(realClass) || "Ljava/util/EnumMap;".equals(realClass))
			return true;
			return false;
		//Can't tell here so return true
		return true;
	}

returns whether the collection has already been reported on

Parameters:
stackPos the position on the opstack to check
Returns:
whether the collection has already been reported.
	private boolean alreadyReported(int stackPos) {
		if (.getStackDepth() > stackPos) {
			OpcodeStack.Item item = .getStackItem(stackPos);
			XField field = item.getXField();
			if (field == null)
				return false;
			else {
				String fieldName = field.getName();
				boolean checked = .contains(fieldName);
				.add(fieldName);
				return checked;
			}
		}
		return false;
	}
New to GrepCode? Check out our FAQ X