Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * fb-contrib - Auxiliary detectors for Java programs
   * Copyright (C) 2005-2013 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.Repository;
 import  org.apache.bcel.classfile.Code;
 import  org.apache.bcel.classfile.Field;
 import  org.apache.bcel.classfile.JavaClass;
 import  org.apache.bcel.generic.Type;
 
 
 import  edu.umd.cs.findbugs.BugInstance;
 import  edu.umd.cs.findbugs.BugReporter;
 import  edu.umd.cs.findbugs.BytecodeScanningDetector;
 import  edu.umd.cs.findbugs.FieldAnnotation;
 import  edu.umd.cs.findbugs.OpcodeStack;
 import  edu.umd.cs.findbugs.OpcodeStack.CustomUserValue;
 import  edu.umd.cs.findbugs.SourceLineAnnotation;
 import  edu.umd.cs.findbugs.ba.ClassContext;
 import  edu.umd.cs.findbugs.ba.XField;

looks for private collection members, either static or instance, that are only initialized in the clinit or init, but are synchronized. This is not necessary as the constructor or static initializer are guaranteed to be thread safe.
 
 @CustomUserValue
 public class NeedlessMemberCollectionSynchronization extends BytecodeScanningDetector {
 	private static JavaClass collectionClass;
 	static {
 		try {
 			 = Repository.lookupClass("java/util/Collection");
 		} catch (ClassNotFoundException cnfe) {
 			 = null;
 		}
 	}
 	private static JavaClass mapClass;
 	static {
 		try {
 			 = Repository.lookupClass("java/util/Map");
 		} catch (ClassNotFoundException cnfe) {
 			 = null;
 		}
 	}
 	private static Set<StringsyncCollections = new HashSet<String>();
 	static {
 		.add("java/util/Vector");
 		.add("java/util/Hashtable");
 	}
 	private static Set<StringmodifyingMethods = new HashSet<String>();
 	static {
 		.add("addAll");
 		.add("addFirst");
 		.add("addElement");
 		.add("addLast");
 		.add("clear");
 		.add("insertElementAt");
 		.add("remove");
 		.add("removeAll");
 		.add("removeAllElements");
 		.add("removeElement");
 		.add("removeElementAt");
 		.add("removeFirst");
 		.add("removeLast");
 		.add("removeRange");
 		.add("retainAll");
 		.add("setElementAt");
 		.add("setSize");
 	}
 	private static final int IN_METHOD = 0;
 	private static final int IN_CLINIT = 1;
 	private static final int IN_INIT = 2;
 	
 	private BugReporter bugReporter;
	private Map<IntegerStringaliases;
	private OpcodeStack stack;
	private int state;
	private String className;

constructs a NMCS detector given the reporter to report bugs on

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

implements the visitor to clear the collectionFields and stack and to report collections that remain unmodified out of clinit or init

Parameters:
classContext the context object of the currently parsed class
	public void visitClassContext(ClassContext classContext) {
		try {
			if (( != null) && ( != null)) {
				 = new OpcodeStack();
				JavaClass cls = classContext.getJavaClass();
				 = cls.getClassName();
				super.visitClassContext(classContext);
				for (FieldInfo fi : .values()) {
					if (fi.isSynchronized()) {
						.reportBug(new BugInstance(this"NMCS_NEEDLESS_MEMBER_COLLECTION_SYNCHRONIZATION", NORMAL_PRIORITY)
									.addClass(this)
									.addField(fi.getFieldAnnotation()));
					}
				}
			}
finally {
			 = null;
			 = null;
		}
	}

implements the visitor to find collection fields

Parameters:
obj the context object of the currently parse field
	public void visitField(Field obj) {
		if (obj.isPrivate()) {
			String signature = obj.getSignature();
			if (signature.charAt(0) == 'L') {
				try {
					JavaClass cls = Repository.lookupClass(signature.substring(1, signature.length() - 1));
					if (cls.implementationOf() || cls.implementationOf()) {
						FieldAnnotation fa = FieldAnnotation.fromVisitedField(this);
						.put(fa.getFieldName(), new FieldInfo(fa));
					}
catch (ClassNotFoundException cnfe) {
					.reportMissingClass(cnfe);
				}
			}
		}
	}

implements the visitor to set the state based on the type of method being parsed

Parameters:
obj the context object of the currently parsed code block
	public void visitCode(Code obj) {
		if (.size() > 0) {
			String methodName = getMethodName();
			if ("<clinit>".equals(methodName))
			else if ("<init>".equals(methodName))
			else
			.resetForMethodEntry(this);
			super.visitCode(obj);
		}
	}

implements the visitor to call the approriate visitor based on state

Parameters:
seen the opcode of the currently parsed instruction
	public void sawOpcode(int seen) {
		switch () {
			case :
			break;
			case :
			break;
			case :
			break;
		}
	}

handle <clinit> blocks by looking for putstatic calls referencing synchronized collections

Parameters:
seen the opcode of the currently parsed instruction
	private void sawCLInitOpcode(int seen) {
		boolean isSyncCollection = false;
		try {
	        .precomputation(this);
	        
			isSyncCollection = isSyncCollectionCreation(seen);
			if (seen == PUTSTATIC)
finally {
			.sawOpcode(thisseen);
			if (isSyncCollection) {
				if (.getStackDepth() > 0) {
					OpcodeStack.Item item = .getStackItem(0);
					item.setUserValue(.);
				}
			}
		}
	}

handle <init> blocks by looking for putfield calls referencing synchronized collections

Parameters:
seen the opcode of the currently parsed instruction
	private void sawInitOpcode(int seen) {
		boolean isSyncCollection = false;
		try {
			.mergeJumps(this);
			isSyncCollection = isSyncCollectionCreation(seen);
			if (seen == PUTFIELD)
finally {
			.sawOpcode(thisseen);
			if (isSyncCollection) {
				if (.getStackDepth() > 0) {
					OpcodeStack.Item item = .getStackItem(0);
					item.setUserValue(.);
				}
			}
		}
	}

handles regular methods by looking for methods on collections that are modifying and removes those collections from the ones under review

Parameters:
seen the opcode of the currently parsed instruction
	private void sawMethodOpcode(int seen) {
		boolean isSyncCollection = false;
		try {
			.mergeJumps(this);
			isSyncCollection = isSyncCollectionCreation(seen);
			switch (seen) {
				case INVOKEVIRTUAL:
				case INVOKEINTERFACE:
					String methodName = getNameConstantOperand();
					if (.contains(methodName)) {
						String signature = getSigConstantOperand();
						int parmCount = Type.getArgumentTypes(signature).length;
						if (.getStackDepth() > parmCount) {
							OpcodeStack.Item item = .getStackItem(parmCount);
							XField field = item.getXField();
							if (field != null) {
								.remove(field.getName());
else {
								int reg = item.getRegisterNumber();
								if (reg >= 0) {
									Integer register = Integer.valueOf(reg);
									String fName = .get(register);
									if (fName != null) {
										.remove(register);
									}
								}
							}
						}
					}
                    removeCollectionParameters();
				break;
                
                case INVOKESTATIC:
                    removeCollectionParameters();
                break;
				case ARETURN:
					if (.getStackDepth() > 0) {
						OpcodeStack.Item item = .getStackItem(0);
						XField field = item.getXField();
						if (field != null) {
							.remove(field.getName());
						}
					}
				break;
				case PUTFIELD:
				case PUTSTATIC:
				break;
				case GOTO:
				case GOTO_W:
					if (.getStackDepth() > 0) {
						OpcodeStack.Item item = .getStackItem(0);
						XField field = item.getXField();
						if (field != null) {
							.remove(field.getName());
						}
					}
				break;
			}
finally {
			TernaryPatcher.pre(seen);
			.sawOpcode(thisseen);
			TernaryPatcher.post(seen);
			if (isSyncCollection) {
				if (.getStackDepth() > 0) {
					OpcodeStack.Item item = .getStackItem(0);
					item.setUserValue(.);
				}
			}
		}
	}

returns whether this instruction is creating a synchronized collection

Parameters:
seen the opcode of the currently parsed instruction
Returns:
whether a synchronized collection has just been created
	private boolean isSyncCollectionCreation(int seen) {
		if (seen == INVOKESPECIAL) {
			if ("<init>".equals(getNameConstantOperand())) {
			}
else if (seen == INVOKESTATIC) {
			if ("java/util/Collections".equals(getClassConstantOperand())) {
				String methodName = getNameConstantOperand();
				return ("synchronizedMap".equals(methodName) || "synchronizedSet".equals(methodName));
			}
		}
		return false;
	}

sets the source line annotation of a store to a collection if that collection is synchronized.
	private void processCollectionStore() {
		if (fieldClassName.equals()) {
			if (.getStackDepth() > 0) {
				OpcodeStack.Item item = .getStackItem(0);
				if (item.getUserValue() != null) {
					if (fieldName != null) {
						FieldInfo fi = .get(fieldName);
						if (fi != null) {
							fi.getFieldAnnotation().setSourceLines(SourceLineAnnotation.fromVisitedInstruction(this));
						}
					}
				}
			}
		}
	}
    
    
removes collection fields that are passed to other methods as arguments
    private void removeCollectionParameters() {
        int parmCount = Type.getArgumentTypes(getSigConstantOperand()).length;
        if (.getStackDepth() >= parmCount) {
            for (int i = 0; i < parmCounti++) {
                OpcodeStack.Item item = .getStackItem(i);
                XField field = item.getXField();
                if (field != null) {
                    .remove(field.getName());
                }
            }
        }
    }

holds information about a field, namely the annotation and whether the collection is synchronized.
	static class FieldInfo {
		private FieldAnnotation fieldAnnotation;
		private boolean isSynchronized;
		public FieldInfo(FieldAnnotation fa) {
			 = false;
		}
		public void setSynchronized() {
		}
		public FieldAnnotation getFieldAnnotation() {
		}
		public boolean isSynchronized() {
		}
	}
New to GrepCode? Check out our FAQ X