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.classfile.Code;
 import  org.apache.bcel.classfile.CodeException;
 import  org.apache.bcel.classfile.LineNumber;
 import  org.apache.bcel.classfile.LineNumberTable;
 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.OpcodeStack;
 import  edu.umd.cs.findbugs.OpcodeStack.CustomUserValue;
 import  edu.umd.cs.findbugs.ba.ClassContext;
 import  edu.umd.cs.findbugs.ba.XField;

looks for calls of the same method on the same object when that object hasn't changed. This often is redundant, and the second call can be removed, or combined.
 
 @CustomUserValue
 public class PossiblyRedundantMethodCalls extends BytecodeScanningDetector
 {
     public static final String PRMC_RISKY_FIELD_USER_KEY = "fbcontrib.PRMC.riskynames";
     public static final String PRMC_RISKY_CLASS_USER_KEY = "fbcontrib.PRMC.riskyclasses";
     public static final String PRMC_HIGH_BYTECOUNT = "fbcontrib.PRMC.highbytecount";
     public static final String PRMC_HIGH_METHODCALLS = "fbcontrib.PRMC.highmethodcalls";
     public static final String PRMC_NORMAL_BYTECOUNT = "fbcontrib.PRMC.normalbytecount";
     public static final String PRMC_NORMAL_METHODCALLS = "fbcontrib.PRMC.normalmethodcalls";
 
 	private static Set<StringriskyMethodNameContents = new HashSet<String>();
 	private static int highByteCountLimit = 200;
 	private static int highMethodCallLimit = 10;
 	private static int normalByteCountLimit = 50;
 	private static int normalMethodCallLimit = 4;
 
 	static {
         .add("currentTimeMillis");
         .add("nanoTime");
         .add("newInstance");
         .add("noneOf");
         .add("allOf");
         .add("beep");
 
 		String userNameProp = System.getProperty();
 		if (userNameProp != null) {
 			String[] userNames = userNameProp.split("\\s*,\\s*");
 			for (String name : userNames) {
 			}
 		}
 		if (prop != null) {
 		}
		if (prop != null) {
		}
		if (prop != null) {
		}
		if (prop != null) {
		}
	}
    private static Set<StringriskyClassNames = new HashSet<String>();
    static {
        .add("java/nio/ByteBuffer");
        .add("java/io/DataInputStream");
        .add("java/io/ObjectInputStream");
        String userNameProp = System.getProperty();
        if (userNameProp != null) {
            String[] userNames = userNameProp.split("\\s*,\\s*");
            for (String name : userNames) {
			}
        }
    }
	private final BugReporter bugReporter;
	private OpcodeStack stack = null;
	private Map<IntegerMethodCalllocalMethodCalls = null;
	private Map<StringMethodCallfieldMethodCalls = null;
	private Map<StringMethodCallstaticMethodCalls = null;
	private BitSet branchTargets = null;

constructs a PRMC detector given the reporter to report bugs on

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

implements the visitor to create and clear the stack, method call maps, and branch targets

Parameters:
classContext the context object of the currently visited class
	public void visitClassContext(ClassContext classContext) {
		try {
			 = new OpcodeStack();
			super.visitClassContext(classContext);
finally {
			 = null;
			 = null;
		}
	}

implements the visitor to reset the stack, and method call maps for new method

Parameters:
obj the context object of the currently parsed code block
	public void visitCode(Code obj) {
		.resetForMethodEntry(this);
		CodeException[] codeExceptions = obj.getExceptionTable();
		for (CodeException codeEx : codeExceptions) {
			.set(codeEx.getHandlerPC());
		}
		super.visitCode(obj);
	}

implements the visitor to look for repetitive calls to the same method on the same object using the same constant parameters. These methods must return a value.

Parameters:
seen the opcode of the currently parsed instruction
	public void sawOpcode(int seen) {
	    String userValue = null;
		try {
	        .precomputation(this);
	        
            int pc = getPC();
			if (.get(pc)) {
			}
			if (((seen >= IFEQ) && (seen <= GOTO)) || ((seen >= IFNULL) && (seen <= GOTO_W))) {
else if ((seen == TABLESWITCH) || (seen == LOOKUPSWITCH)) {
				int[] offsets = getSwitchOffsets();
				for (int offset : offsets) {
					.set(offset + pc);
				}
else if ((seen == ASTORE) || ((seen >= ASTORE_0) && (seen <= ASTORE_3))) {
				.remove(Integer.valueOf(RegisterUtils.getAStoreReg(thisseen)));
else if (seen == PUTFIELD) {
			    String fieldSource = "";
			    if (.getStackDepth() > 0) {
			        OpcodeStack.Item item = .getStackItem(0);
			        fieldSource = (Stringitem.getUserValue();
			        if (fieldSource == null)
			            fieldSource = "";
			    }
else if (seen == GETFIELD) {
			    if (.getStackDepth() > 0) {
			        OpcodeStack.Item item = .getStackItem(0);
			        userValue = (Stringitem.getUserValue();
			        if (userValue == null) {
			            int reg = item.getRegisterNumber();
			            if (reg >= 0) {
			                userValue = String.valueOf(reg);
			            } else {
			                XField xf = item.getXField();
			                if (xf != null) {
			                    userValue = xf.getName();
			                }
			            }
			        }
			    }
else if ((seen == INVOKEVIRTUAL) || (seen == INVOKEINTERFACE) || (seen == INVOKESTATIC)) {
				String signature = getSigConstantOperand();
				int parmCount = Type.getArgumentTypes(signature).length;
				int neededStackSize = parmCount - ((seen == INVOKESTATIC) ? 1 : 0);
				if (.getStackDepth() > neededStackSize) {
					Object[] parmConstants = new Object[parmCount];
					for (int i = 0; i < parmCounti++) {
						OpcodeStack.Item parm = .getStackItem(i);
						parmConstants[i] = parm.getConstant();
						if (parmConstants[i] == null) {
							return;
						}
					}
	                String className = getClassConstantOperand();
					int reg = -1;
					XField field = null;
					if (seen == INVOKESTATIC) {
						mc = .get(className);
else {
						OpcodeStack.Item obj = .getStackItem(parmCount);
						reg = obj.getRegisterNumber();
						field = obj.getXField();
						if (reg >= 0) {
							mc = .get(Integer.valueOf(reg));
else if (field != null) {
						    String fieldSource = (Stringobj.getUserValue();
						    if (fieldSource == null)
						        fieldSource = "";
							mc = .get(fieldSource + ":" + field.getName());
else {
							return;
						}
					}
	                String methodName = getNameConstantOperand();
					if (mc != null) {
						if (!signature.endsWith("V") && methodName.equals(mc.getName()) && signature.equals(mc.getSignature()) && !isRiskyName(classNamemethodName)) {
							Object[] parms = mc.getParms();
							if (Arrays.equals(parmsparmConstants)) {
			                    int ln = getLineNumber(pc);
			                    
			                    if ((ln != mc.getLineNumber()) || (Math.abs(pc - mc.getPC()) < 10)) {
    								Statistics statistics = Statistics.getStatistics();
    								Statistics.MethodInfo mi = statistics.getMethodStatistics(getClassConstantOperand(), methodNamesignature);
    
    								.reportBug(new BugInstance(this"PRMC_POSSIBLY_REDUNDANT_METHOD_CALLS",
    																	  ((mi.numBytes >= ) || (mi.numMethodCalls >= )) ?
    																			  HIGH_PRIORITY :
    																		      ((mi.numBytes >= ) || (mi.numMethodCalls >= )) ?
    																		    		  NORMAL_PRIORITY :
    																		    			  ((mi.numBytes == 0) || (mi.numMethodCalls == 0)) ?
    																		    					  LOW_PRIORITY :
    																		    				      EXP_PRIORITY)
    											.addClass(this)
    											.addMethod(this)
    											.addSourceLine(this)
    											.addString(methodName + signature));
			                    }
							}
						}
						if (seen == INVOKESTATIC) {
else {
							if (reg >= 0) {
else if (field != null) {
				                String fieldSource = "";
				                if (.getStackDepth() > 0) {
				                    OpcodeStack.Item item = .getStackItem(0);
				                    fieldSource = (Stringitem.getUserValue();
				                    if (fieldSource == null)
				                        fieldSource = "";
				                }
								.remove(fieldSource + ":" + field.getName());
							}
						}
else {
					    int ln = getLineNumber(pc);
						if (seen == INVOKESTATIC) {
							.put(classNamenew MethodCall(methodNamesignatureparmConstantspcln));
else {
							if (reg >= 0) {
								.put(Integer.valueOf(reg), new MethodCall(methodNamesignatureparmConstantspcln));
else if (field != null) {
							    OpcodeStack.Item obj = .getStackItem(parmCount);
							    String fieldSource = (Stringobj.getUserValue();
	                            if (fieldSource == null)
	                                fieldSource = "";
								.put(fieldSource + ":" + field.getName(), new MethodCall(methodNamesignatureparmConstantspcln));
							}
						}
					}
				}
			}
finally {
			.sawOpcode(thisseen);
			if (userValue != null) {
			    if (.getStackDepth() > 0) {
			        OpcodeStack.Item item = .getStackItem(0);
			        item.setUserValue(userValue);
			    }
			}
		}
	}

returns true if the class or method name contains a pattern that is considered likely to be this modifying

Parameters:
className the class name to check
methodName the method name to check
Returns:
whether the method sounds like it modifies this
	private boolean isRiskyName(String classNameString methodName) {
        if (.contains(className)) {
			return true;
		}
		for (String riskyName : ) {
			if (methodName.indexOf(riskyName) >= 0) {
				return true;
			}
		}
		return false;
	}

returns the source line number for the pc, or just the pc if the line number table doesn't exist

Parameters:
pc current pc
Returns:
the line number
	private int getLineNumber(int pc) {
	    LineNumberTable lnt = getMethod().getLineNumberTable();
	    if (lnt == null)
	        return pc;
	    
	    LineNumber[] lns = lnt.getLineNumberTable();
	    if (lns == null)
	        return pc;
	    
	    if (pc > lns[lns.length-1].getStartPC())
	        return lns[lns.length-1].getLineNumber();
	    
	    int lo = 0;
	    int hi = lns.length - 2;
	    int mid = 0;
	    while (lo <= hi) {
	        mid = (lo + hi) / 2;
	        if (pc < lns[mid].getStartPC()) {
	            hi = mid - 1;
	        } else if (pc >= lns[mid+1].getStartPC()) {
	            lo = mid + 1;
	        } else {
	            break;
	        }
	    }
	    
	    return lns[mid].getLineNumber();
	}

contains information about a method call
	static class MethodCall
	{
		private final String methodName;
		private final String methodSignature;
		private final Object[] methodParms;
		private final int methodPC;
		private final int methodLineNumber;
		public MethodCall(String nameString signatureObject[] parmsint pcint lineNumber) {
			 = name;
			 = signature;
			 = parms;
			 = pc;
			 = lineNumber;
		}
		public String getName() {
			return ;
		}
		public String getSignature() {
		}
		public Object[] getParms() {
			return ;
		}
		public int getPC() {
		    return ;
		}
		public int getLineNumber() {
		    return ;
		}
	}
New to GrepCode? Check out our FAQ X