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.Constants;
 import  org.apache.bcel.classfile.Code;
 import  org.apache.bcel.classfile.Field;
 import  org.apache.bcel.classfile.JavaClass;
 import  org.apache.bcel.classfile.Method;
 import  org.apache.bcel.generic.ConstantPoolGen;
 import  org.apache.bcel.generic.FieldInstruction;
 import  org.apache.bcel.generic.GETFIELD;
 import  org.apache.bcel.generic.Instruction;
 import  org.apache.bcel.generic.InstructionHandle;
 
 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.SourceLineAnnotation;
 import  edu.umd.cs.findbugs.ba.BasicBlock;
 import  edu.umd.cs.findbugs.ba.CFG;
 import  edu.umd.cs.findbugs.ba.CFGBuilderException;
 import  edu.umd.cs.findbugs.ba.ClassContext;
 import  edu.umd.cs.findbugs.ba.Edge;
 import  edu.umd.cs.findbugs.ba.BasicBlock.InstructionIterator;

finds fields that are used in a locals only fashion, specifically private fields that are accessed first in each method with a store vs. a load.
 
 public class FieldCouldBeLocal extends BytecodeScanningDetector
 {
 	private final BugReporter bugReporter;
 	private ClassContext clsContext;
 	private CFG cfg;
 	private ConstantPoolGen cpg;
 	private BitSet visitedBlocks;

    
constructs a FCBL detector given the reporter to report bugs on.

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

overrides the visitor to collect localizable fields, and then report those that survive all method checks.

Parameters:
classContext the context object that holds the JavaClass parsed
 
 	public void visitClassContext(ClassContext classContext) {
 		try {
 	         = new HashMap<StringFieldInfo>();
 	         = new BitSet();
 			 = classContext;
 			JavaClass cls = classContext.getJavaClass();
 			Field[] fields = cls.getFields();
 			for (Field f : fields) {
 				if ((!f.isStatic() && f.getName().indexOf('$') < 0) && f.isPrivate()) {
 					FieldAnnotation fa = new FieldAnnotation(cls.getClassName(), f.getName(), f.getSignature(), false);
 					.put(f.getName(), new FieldInfo(fa));
 				}
 			}
 
 			if (.size() > 0) {
 				super.visitClassContext(classContext);
 				for (FieldInfo fi : .values()) {
 					FieldAnnotation fa = fi.getFieldAnnotation();
 					SourceLineAnnotation sla = fi.getSrcLineAnnotation();
					BugInstance bug = new BugInstance(this"FCBL_FIELD_COULD_BE_LOCAL", NORMAL_PRIORITY)
													.addClass(this)
													.addField(fa);
					if (sla != null)
						bug.addSourceLine(sla);
					.reportBug(bug);
				}
			}
finally {
	         = null;
	         = null;
	         = null;
		}
	}

overrides the visitor to navigate basic blocks looking for all first usages of fields, removing those that are read from first.

Parameters:
obj the context object of the currently parsed method
	public void visitMethod(Method obj) {
			return;
		try {
			 = .getCFG(obj);
			 = .getMethodGen().getConstantPool();
			BasicBlock bb = .getEntry();
			Set<StringuncheckedFields = new HashSet<String>(.keySet());
			checkBlock(bbuncheckedFields);
		}
		catch (CFGBuilderException cbe) {
		}
        finally {
             = null;
             = null;
        }
	}

looks for methods that contain a GETFIELD or PUTFIELD opcodes

Parameters:
method the context object of the current method
Returns:
if the class uses synchronization
	public boolean prescreen(Method method) {
		BitSet bytecodeSet = getClassContext().getBytecodeSet(method);
		return (bytecodeSet != null) && (bytecodeSet.get(Constants.PUTFIELD) || bytecodeSet.get(Constants.GETFIELD));
	}

implements the visitor to pass through constructors and static initializers to the byte code scanning code. These methods are not reported, but are used to build SourceLineAnnotations for fields, if accessed.

Parameters:
obj the context object of the currently parsed code attribute
	public void visitCode(Code obj) {
		Method m = getMethod();
		if (prescreen(m)) {
			String methodName = m.getName();
			if ("<clinit".equals(methodName) || "<init>".equals(methodName))
				super.visitCode(obj);
		}
	}

implements the visitor to add SourceLineAnnotations for fields in constructors and static initializers.

Parameters:
seen the opcode of the currently visited instruction
	public void sawOpcode(int seen) {
		if ((seen == GETFIELD) || (seen == PUTFIELD)) {
			FieldInfo fi = .get(fieldName);
			if (fi != null) {
				SourceLineAnnotation sla = SourceLineAnnotation.fromVisitedInstruction(this);
			}
		}
	}

looks in this basic block for the first access to the fields in uncheckedFields. Once found the item is removed from uncheckedFields, and removed from localizableFields if the access is a GETFIELD. If any unchecked fields remain, this method is recursively called on all outgoing edges of this basic block.

Parameters:
bb this basic block
uncheckedFields the list of fields to look for
	private void checkBlock(BasicBlock bbSet<StringuncheckedFields) {
		LinkedList<BlockStatetoBeProcessed = new LinkedList<BlockState>();
		toBeProcessed.add(new BlockState(bbuncheckedFields));
		.set(bb.getLabel());
		while (!toBeProcessed.isEmpty()) {
				return;
			BlockState bState = toBeProcessed.removeFirst();
			bb = bState.getBasicBlock();
			InstructionIterator ii = bb.instructionIterator();
			while ((bState.getUncheckedFieldSize() > 0) && ii.hasNext()) {
				InstructionHandle ih = ii.next();
				Instruction ins = ih.getInstruction();
				if (ins instanceof FieldInstruction) {
					FieldInstruction fi = (FieldInstruction) ins;
					String fieldName = fi.getFieldName();
					boolean justRemoved = bState.removeUncheckedField(fieldName);
					if (ins instanceof GETFIELD) {
						if (justRemoved) {
								return;
						}
else {
						FieldInfo finfo = .get(fieldName);
						if (finfo != null)
							finfo.setSrcLineAnnotation(SourceLineAnnotation.fromVisitedInstruction(thisih.getPosition()));
					}
				}
			}
			if (bState.getUncheckedFieldSize() > 0) {
				Iterator<Edge> oei = .outgoingEdgeIterator(bb);
				while (oei.hasNext()) {
					Edge e = oei.next();
					BasicBlock cb = e.getTarget();
					int label = cb.getLabel();
					if (!.get(label)) {
						toBeProcessed.addLast(new BlockState(cbbState));
					}
				}
			}
		}
	}

holds information about a field and it's first usage
	private static class FieldInfo {
		private final FieldAnnotation fieldAnnotation;
		private SourceLineAnnotation srcLineAnnotation;

creates a FieldInfo from an annotation, and assumes no source line information

Parameters:
fa the field annotation for this field
		public FieldInfo(final FieldAnnotation fa) {
		}

set the source line annotation of first use for this field

Parameters:
sla the source line annotation
		public void setSrcLineAnnotation(final SourceLineAnnotation sla) {
			if ( == null)
		}

get the field annotation for this field

Returns:
the field annotation
		public FieldAnnotation getFieldAnnotation() {
		}

get the source line annotation for the first use of this field

Returns:
the source line annotation
		public SourceLineAnnotation getSrcLineAnnotation() {
		}
	}

holds the parse state of the current basic block, and what fields are left to be checked the fields that are left to be checked are a reference from the parent block and a new collection is created on first write to the set to reduce memory concerns.
	private static class BlockState {
		private final BasicBlock basicBlock;
		private boolean fieldsAreSharedWithParent;

creates a BlockState consisting of the next basic block to parse, and what fields are to be checked

Parameters:
bb the basic block to parse
fields the fields to look for first use
		public BlockState(final BasicBlock bbfinal Set<Stringfields) {
			 = bb;
			 = fields;
		}

creates a BlockState consisting of the next basic block to parse, and what fields are to be checked

Parameters:
bb the basic block to parse
the basic block to copy from
		public BlockState(final BasicBlock bbBlockState parentBlockState) {
			 = bb;
			 = parentBlockState.uncheckedFields;
		}

get the basic block to parse

Returns:
the basic block
		public BasicBlock getBasicBlock() {
			return ;
		}

returns the number of unchecked fields

Returns:
the number of unchecked fields
		public int getUncheckedFieldSize() {
			return ( == null) ? 0 : .size();
		}

return the field from the set of unchecked fields if this occurs make a copy of the set on write to reduce memory usage

Returns:
whether the object was removed.
		public boolean removeUncheckedField(String field) {
			if (( != null) && .contains(field)) {
				if (.size() == 1) {
					return true;
				}
					return true;
else {
					return true;
				}
			}
			return false;
		}
		public String toString() {
			return .toString() + "|" + ;
		}
	}
New to GrepCode? Check out our FAQ X