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.List;
 import java.util.Map;
 import java.util.Set;
 
 import  org.apache.bcel.Constants;
 import  org.apache.bcel.Repository;
 import  org.apache.bcel.classfile.Code;
 import  org.apache.bcel.classfile.CodeException;
 import  org.apache.bcel.classfile.ExceptionTable;
 import  org.apache.bcel.classfile.JavaClass;
 import  org.apache.bcel.classfile.LocalVariable;
 import  org.apache.bcel.classfile.LocalVariableTable;
 import  org.apache.bcel.classfile.Method;
 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.ba.ClassContext;

looks for parameters that are defined by classes, but only use methods defined by an implemented interface or super class. Relying on concrete classes in public signatures causes cohesion, and makes low impact changes more difficult.
 
 public class OverlyConcreteParameter extends BytecodeScanningDetector
 {
 	private final BugReporter bugReporter;
 	private JavaClass[] constrainingClasses;
 	private Map<IntegerMap<JavaClass, List<MethodInfo>>> parameterDefiners;
 	private JavaClass objectClass;
 	private OpcodeStack stack;
 	private int parmCount;
 	private boolean methodSignatureIsConstrained;
 	private boolean methodIsStatic;

constructs a OCP detector given the reporter to report bugs on

Parameters:
bugReporter the sync of bug reports
 
 	public OverlyConcreteParameter(final BugReporter bugReporter) {
 		this. = bugReporter;
 		try {
 			 = Repository.lookupClass("java/lang/Object");
 		} catch (ClassNotFoundException cnfe) {
 			bugReporter.reportMissingClass(cnfe);
 			 = null;
 		}
 	}
 
 	public void visitClassContext(ClassContext classContext) {
 		try {
 			JavaClass[] infs = classContext.getJavaClass().getAllInterfaces();
 			JavaClass[] sups = classContext.getJavaClass().getSuperClasses();
 			 = new JavaClass[infs.length + sups.length];
 			System.arraycopy(infs, 0, , 0, infs.length);
 			System.arraycopy(sups, 0, infs.length, sups.length);
 			 = new HashMap<IntegerMap<JavaClass, List<MethodInfo>>>();
 			 = new OpcodeStack();
 			super.visitClassContext(classContext);
 		} catch (ClassNotFoundException cnfe) {
 			.reportMissingClass(cnfe);
 		} finally {
 			 = null;
 			 = null;
 			 = null;
 		}
 	}
	public void visitMethod(Method obj) {
		String methodName = obj.getName();
		if (!"<init>".equals(methodName)
		&&  !"<clinit>".equals(methodName)) {
			String methodSig = obj.getSignature();
			 = methodIsSpecial(methodNamemethodSig);
				String parms = methodSig.split("\\(|\\)")[1];
				if (parms.indexOf(';') >= 0) {
					outer:for (JavaClass cls : ) {
						Method[] methods = cls.getMethods();
						for (Method m : methods) {
							if (methodName.equals(m.getName())) {
								if (methodSig.equals(m.getSignature())) {
									break outer;
								}
							}
						}
					}
				}
			}
		}
	}
	public void visitCode(final Code obj) {
		try {
				return;
			}
			if (obj.getCode() == null) {
				return;
			}
			Method m = getMethod();
			if (m.getName().startsWith("access$")) {
				return;
			}
			 = m.isStatic();
			 = m.getArgumentTypes().length;
			if ( == 0) {
				return;
			}
			.resetForMethodEntry(this);
				super.visitCode(obj);
			}
catch (ClassNotFoundException cnfe) {
			.reportMissingClass(cnfe);
		}
	}
	public void sawOpcode(final int seen) {
		if (.isEmpty()) {
			return;
		}
		try {
			.mergeJumps(this);
			if ((seen == INVOKEVIRTUAL) || (seen == INVOKESTATIC) || (seen == INVOKESPECIAL) || (seen == INVOKEINTERFACE)) {
				String methodSig = getSigConstantOperand();
				Type[] parmTypes = Type.getArgumentTypes(methodSig);
				int stackDepth = .getStackDepth();
				if (stackDepth >= parmTypes.length) {
					for (int i = 0; i < parmTypes.length; i++) {
						OpcodeStack.Item itm = .getStackItem(i);
						int reg = itm.getRegisterNumber();
						removeUselessDefiners(parmTypes[parmTypes.length - i - 1].getSignature(), reg);
					}
				}
				if ((seen != INVOKESPECIAL) && (seen != INVOKESTATIC)) {
					if (stackDepth > parmTypes.length) {
						OpcodeStack.Item itm = .getStackItem(parmTypes.length);
						int reg = itm.getRegisterNumber();
						int parm = reg;
							parm--;
						}
						if ((parm >= 0) && (parm < )) {
						}
else {
					}
				}
else if ((seen == ASTORE) || ((seen >= ASTORE_0) && (seen <= ASTORE_3)) || (seen == PUTFIELD) || (seen == GETFIELD) || (seen == PUTSTATIC) || (seen == GETSTATIC)) {
				//Don't check parameters that are aliased
				if (.getStackDepth() > 0) {
					OpcodeStack.Item itm = .getStackItem(0);
					int reg = itm.getRegisterNumber();
					int parm = reg;
						parm--;
					}
					if ((parm >= 0) && (parm < )) {
						.remove(Integer.valueOf(reg));
					}
else {
				}
				if ((seen == GETFIELD) || (seen == PUTFIELD)) {
					if (.getStackDepth() > 1) {
						OpcodeStack.Item itm = .getStackItem(1);
						int reg = itm.getRegisterNumber();
						int parm = reg;
							parm--;
						}
						if ((parm >= 0) && (parm < )) {
							.remove(Integer.valueOf(reg));
						}
else {
					}
				}
else if ((seen == ALOAD) || ((seen >= ALOAD_0) && (seen <= ALOAD_3))) {
				int reg = RegisterUtils.getALoadReg(thisseen);
				int parm = reg;
					parm--;
				}
				if ((parm >= 0) && (parm < )) {
					.add(Integer.valueOf(reg));
				}
else if (seen == AASTORE) {
				//Don't check parameters that are stored in
				if (.getStackDepth() >= 3) {
					OpcodeStack.Item itm = .getStackItem(0);
					int reg = itm.getRegisterNumber();
					int parm = reg;
						parm--;
					}
					if ((parm >= 0) && (parm < )) {
						.remove(Integer.valueOf(reg));
					}
else {
				}
else if (seen == ARETURN) {
				if (.getStackDepth() >= 1) {
					OpcodeStack.Item item = .getStackItem(0);
					int reg = item.getRegisterNumber();
					int parm = reg;
						parm--;
					}
					if ((parm >= 0) && (parm < )) {
						.remove(Integer.valueOf(reg));
					}
else {
				}
			}
finally {
			.sawOpcode(thisseen);
		}
	}
	private boolean methodIsSpecial(String methodNameString methodSig) {
		if ("readObject".equals(methodName) && "(Ljava/io/ObjectInputStream;)V".equals(methodSig)) {
			return true;
		}
		return false;
	}
	private void reportBugs() {
		Iterator<Map.Entry<IntegerMap<JavaClass, List<MethodInfo>>>> it = .entrySet().iterator();
		while (it.hasNext()) {
			Map.Entry<IntegerMap<JavaClass, List<MethodInfo>>> entry = it.next();
			Integer reg = entry.getKey();
			if (!.contains(reg)) {
				it.remove();
				continue;
			}
			Map<JavaClass, List<MethodInfo>> definers = entry.getValue();
			definers.remove();
			if (definers.size() > 0) {
				String name = "";
				LocalVariableTable lvt = getMethod().getLocalVariableTable();
				if (lvt != null) {
					LocalVariable lv = lvt.getLocalVariable(reg.intValue(), 0);
					if (lv != null) {
						name = lv.getName();
					}
				}
				int parm = reg.intValue();
					parm--;
				}
				parm++; //users expect 1 based parameters
				String infName = definers.keySet().iterator().next().getClassName();
				.reportBug( new BugInstance(this"OCP_OVERLY_CONCRETE_PARAMETER", NORMAL_PRIORITY)
					.addClass(this)
					.addMethod(this)
					.addSourceLine(this, 0)
					.addString("Parameter [" + parm + "] " + name + " implements " + infName));
			}
		}
	}

builds a map of method information for each method of each interface that each parameter implements of this method

Returns:
a map by parameter id of all the method signatures that interfaces of that parameter implements
Throws:
ClassNotFoundException if the class can't be loaded
	private boolean buildParameterDefiners()
		Type[] parms = getMethod().getArgumentTypes();
		if (parms.length == 0) {
			return false;
		}
		boolean hasPossiblyOverlyConcreteParm = false;
		for (int i = 0; i < parms.length; i++) {
			String parm = parms[i].getSignature();
			if (parm.startsWith("L")) {
				String clsName = parm.substring(1, parm.length() - 1).replace('/''.');
				if (clsName.startsWith("java.lang.")) {
					continue;
				}
				JavaClass cls = Repository.lookupClass(clsName);
				if (cls.isClass() && (!cls.isAbstract())) {
					Map<JavaClass, List<MethodInfo>> definers = getClassDefiners(cls);
					if (definers.size() > 0) {
						.put( Integer.valueOf(i + ( ? 0 : 1)), definers );
						hasPossiblyOverlyConcreteParm = true;
					}
				}
			}
		}
		return hasPossiblyOverlyConcreteParm;
	}

returns a map of method information for each public method for each interface this class implements

Parameters:
cls the class whose interfaces to record
Returns:
a map of (method name)(method sig) by interface
Throws:
ClassNotFoundException if unable to load the class
	private Map<JavaClass, List<MethodInfo>> getClassDefiners(final JavaClass cls)
		Map<JavaClass, List<MethodInfo>> definers = new HashMap<JavaClass, List<MethodInfo>>();
		for (JavaClass ci : cls.getAllInterfaces()) {
			if ("java.lang.Comparable".equals(ci.getClassName())) {
				continue;
			}
			List<MethodInfomethodInfos = getPublicMethodInfos(ci);
			if (methodInfos.size() > 0) {
				definers.put(cimethodInfos);
			}
		}
		return definers;
	}

returns a lost of method information of all public or protected methods in this class

Parameters:
cls the class to look for methods
Returns:
a map of (method name)(method signature)
	private List<MethodInfogetPublicMethodInfos(final JavaClass cls) {
		List<MethodInfomethodInfos = new ArrayList<MethodInfo>();
		Method[] methods = cls.getMethods();
		for (Method m : methods) {
			if ((m.getAccessFlags() & (Constants.ACC_PUBLIC|Constants.ACC_PROTECTED)) != 0) {
				ExceptionTable et = m.getExceptionTable();
				methodInfos.add(new MethodInfo(m.getName(), m.getSignature(), et == null ? null : et.getExceptionNames()));
			}
		}
		return methodInfos;
	}
	private void removeUselessDefiners(final int reg) {
		Map<JavaClass, List<MethodInfo>> definers = .get(Integer.valueOf(reg));
		if ((definers != null) && (definers.size() > 0)) {
			String methodSig = getSigConstantOperand();
			String methodName = getNameConstantOperand();
			MethodInfo methodInfo = new MethodInfo(methodNamemethodSignull);
			Iterator<List<MethodInfo>> it = definers.values().iterator();
			while (it.hasNext()) {
				boolean methodDefined = false;
				List<MethodInfomethodSigs = it.next();
                for (MethodInfo mi : methodSigs) {
					if (methodInfo.equals(mi)) {
						methodDefined = true;
						String[] exceptions = mi.getMethodExceptions();
						if (exceptions != null) {
							for (String ex : exceptions) {
								if (!isExceptionHandled(ex)) {
									methodDefined = false;
									break;
								}
							}
						}
						break;
					}
				}
				if (!methodDefined) {
					it.remove();
				}
			}
			if (definers.isEmpty()) {
				.remove(Integer.valueOf(reg));
			}
		}
	}

returns whether this exception is handled either in a try/catch or throws clause at this pc

Parameters:
ex the name of the exception
Returns:
whether the exception is handled
	private boolean isExceptionHandled(String ex) {
		try {
			JavaClass thrownEx = Repository.lookupClass(ex);
			//First look at the throws clause
			ExceptionTable et = getMethod().getExceptionTable();
			if (et != null) {
				String[] throwClauseExNames = et.getExceptionNames();
				for (String throwClauseExName : throwClauseExNames) {
					JavaClass throwClauseEx = Repository.lookupClass(throwClauseExName);
					if (thrownEx.instanceOf(throwClauseEx)) {
						return true;
					}
				}
			}
			// Next look at the try catch blocks
			CodeException[] catchExs = getCode().getExceptionTable();
			if (catchExs != null) {
				int pc = getPC();
				for (CodeException catchEx : catchExs) {
					if ((pc >= catchEx.getStartPC()) && (pc <= catchEx.getEndPC())) {
						int type = catchEx.getCatchType();
						if (type != 0) {
							String catchExName = getConstantPool().getConstantString(type, Constants.CONSTANT_Class);
							JavaClass catchException = Repository.lookupClass(catchExName);
							if (thrownEx.instanceOf(catchException)) {
								return true;
							}
						}
					}
				}
			}
catch (ClassNotFoundException cnfe) {
			.reportMissingClass(cnfe);
		}
		return false;
	}
	private void removeUselessDefiners(String parmSigfinal int reg) {
		if (parmSig.startsWith("L")) {
			parmSig = parmSig.substring( 1, parmSig.length() - 1).replace('/''.');
			if ("java.lang.Object".equals(parmSig)) {
				.remove(Integer.valueOf(reg));
				return;
			}
			Map<JavaClass, List<MethodInfo>> definers = .get(Integer.valueOf(reg));
			if ((definers != null) && (definers.size() > 0)) {
				Iterator<JavaClass> it = definers.keySet().iterator();
				while (it.hasNext()) {
					JavaClass definer = it.next();
					if (!definer.getClassName().equals(parmSig)) {
						it.remove();
					}
				}
				if (definers.isEmpty()) {
					.remove(Integer.valueOf(reg));
				}
			}
		}
	}
	public static class MethodInfo
	{
		private final String methodName;
		private final String methodSig;
		private final String[] methodExceptions;
		public MethodInfo(String nameString sigString[] excs) {
			 = name;
			 = sig;
		}
		public String getMethodName() {
			return ;
		}
			return ;
		}
		}
		public int hashCode() {
		}
		public boolean equals(Object o) {
			if (!(o instanceof MethodInfo)) {
				return false;
			}
			MethodInfo that = (MethodInfo)o;
			if (!.equals(that.methodName)) {
				return false;
			}
			if (!.equals(that.methodSig)) {
				return false;
			}
			return true;
		}
		public String toString() {
			return  + ;
		}
	}
New to GrepCode? Check out our FAQ X