Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * fb-contrib - Auxiliary detectors for Java programs
   * Copyright (C) 2005-2014 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.ConstantClass;
 import  org.apache.bcel.classfile.ConstantPool;
 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;
 
 
looks for methods that catch checked exceptions, and throw unchecked exceptions in their place. There are several levels of concern. Least important are methods constrained by interface or super class contracts not to throw checked exceptions but appear owned by the same author. Next are methods constrained by interface or super class contracts and throw other types of checked exceptions. Lastly are method not constrained by any interface or superclass contract.
 
 public class ExceptionSoftening extends BytecodeScanningDetector 
 {
 	private static JavaClass runtimeClass;
 	static {
 		try {
 			 = Repository.lookupClass("java/lang/RuntimeException");
 		} catch (ClassNotFoundException cnfe) {
 			 = null;
 		}
 	}
 	private final BugReporter bugReporter;
 	private OpcodeStack stack;
 	private Map<Integer, CodeException> catchHandlerPCs;
 	private List<CatchInfocatchInfos;
 	private LocalVariableTable lvt;
 	private Map<StringSet<String>> constrainingInfo;


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

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

overrides the visitor to reset the stack

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

overrides the visitor to look for methods that catch exceptions

Parameters:
obj the context object of the currently parsed code block
	public void visitCode(Code obj) {
		try {
			Method method = getMethod();
			if (prescreen(method)) {
				 = collectExceptions(obj.getExceptionTable());
				 = method.getLocalVariableTable();
				super.visitCode(obj);
			}
finally {
			 = null;
			 = null;
		}
	}

overrides the visitor to find catch blocks that throw runtime exceptions

Parameters:
seen the opcode of the currently parsed instruction
	public void sawOpcode(int seen) {
		try {
	        .precomputation(this);
	        
			int pc = getPC();
			CodeException ex = .get(Integer.valueOf(pc));
			if (ex != null) {
				int endPC;
				if ((seen == GOTO) || (seen == GOTO_W))
					endPC = this.getBranchTarget();
				else
					endPC = .;
				ConstantPool pool = getConstantPool();
				ConstantClass ccls = (ConstantClass)pool.getConstant(ex.getCatchType());
				String catchSig = ccls.getBytes(pool);
				CatchInfo ci = new CatchInfo(ex.getHandlerPC(), endPCcatchSig);
			}
			if (seen == ATHROW) {
				try {
					if (.getStackDepth() > 0) {
						JavaClass exClass = itm.getJavaClass();
						if ((exClass != null) && exClass.instanceOf()) {
							if (.size() > 0) {
								Set<StringpossibleCatchSignatures = findPossibleCatchSignatures(pc);								
								if (!possibleCatchSignatures.contains(exClass.getClassName())) {
									boolean anyRuntimes = false;
									for (String possibleCatches : possibleCatchSignatures) {
										exClass = Repository.lookupClass(possibleCatches);
										if (exClass.instanceOf()) {
											anyRuntimes = true;
											break;
										}
									}
									if (!anyRuntimes) {
										if ( == null)
										String bug = null;
										int priority = NORMAL_PRIORITY;
										if ( == null) {
											bug = "EXS_EXCEPTION_SOFTENING_NO_CONSTRAINTS";
											priority = HIGH_PRIORITY;
										}
											bug = "EXS_EXCEPTION_SOFTENING_HAS_CHECKED";
											priority = NORMAL_PRIORITY;
										}
										else {
											String pack2 = getClassContext().getJavaClass().getClassName();
											int dotPos = pack1.lastIndexOf('.');
											if (dotPos >= 0)
												pack1 = pack1.substring(0, dotPos);
											else
												pack1 = "";
											dotPos = pack2.lastIndexOf('.');
											if (dotPos >= 0)
												pack2 = pack2.substring(0, dotPos);
											else
												pack2 = "";
											if (SignatureUtils.similarPackages(pack1pack2, 2)) {
												bug = "EXS_EXCEPTION_SOFTENING_NO_CHECKED";
												priority = NORMAL_PRIORITY;
											}
										}
										if (bug != null) {
											.reportBug(new BugInstance(thisbugpriority)
														.addClass(this)
														.addMethod(this)
														.addSourceLine(this));
										}
									}
								}
							}
						}
					}
catch (ClassNotFoundException cnfe) {
				}
			}
finally {
			.sawOpcode(thisseen);
		}
	}

collects all the valid exception objects (ones where start and finish are before the target) and with a catch type

Parameters:
exceptions the exceptions from the class file
Returns:
the filtered exceptions keyed by catch end pc
	private LinkedHashMap<Integer, CodeException> collectExceptions(CodeException[] exceptions) {
		List<CodeException> filteredEx = new ArrayList<CodeException>();
		for (CodeException ce : exceptions) {
			if ((ce.getCatchType() != 0) && (ce.getStartPC() < ce.getEndPC()) && (ce.getEndPC() <= ce.getHandlerPC())) {
				filteredEx.add(ce);
			}
		}
		LinkedHashMap<Integer, CodeException> handlers = new LinkedHashMap<Integer, CodeException>();
		for (CodeException ex : filteredEx) {
			handlers.put(Integer.valueOf(ex.getEndPC()), ex);
		}
		return handlers;
	}

remove catchinfo blocks from the map where the handler end is before the current pc

Parameters:
infos the exception handlers installed
pc the current pc
	private void removeFinishedCatchBlocks(List<CatchInfoinfosint pc) {
		Iterator<CatchInfoit = infos.iterator();
		while (it.hasNext()) {
			if (it.next().getFinish() < pc)
				it.remove();
		}
	}

reduces the end pc based on the optional LocalVariableTable's exception register scope

Parameters:
infos the list of active catch blocks
pc the current pc
	private void updateEndPCsOnCatchRegScope(List<CatchInfoinfosint pcint seen)
	{
		if ( != null) {
			for (CatchInfo ci : infos) {
				if (ci.getStart() == pc) {
					if ((seen == ASTORE) || ((seen >= ASTORE_0) && (seen <= ASTORE_3))) {
						int exReg = RegisterUtils.getAStoreReg(thisseen);
						LocalVariable lv = .getLocalVariable(exRegpc + 1);
						if (lv != null) {
							ci.setFinish(lv.getStartPC() + lv.getLength());
						}
						break;
					}
				}
			}
		}
	}

returns an array of catch types that the current pc is in

Parameters:
infos the list of catch infos for this method
pc the current pc
Returns:
an set of catch exception types that the pc is currently in
	public Set<StringfindPossibleCatchSignatures(List<CatchInfoinfosint pc) {
		Set<StringcatchTypes = new HashSet<String>(6);
		ListIterator<CatchInfoit = infos.listIterator(infos.size());
		while (it.hasPrevious()) {
			CatchInfo ci = it.previous();
			if ((pc >= ci.getStart()) && (pc < ci.getFinish())) {
				catchTypes.add(ci.getSignature());
else {
				break;
			}
		}
		return catchTypes;
	}

finds the super class or interface that constrains the types of exceptions that can be thrown from the given method

Parameters:
m the method to check
Returns:
a map containing the class name to a set of exceptions that constrain this method
	public Map<StringSet<String>> getConstrainingInfo(JavaClass cls, Method mthrows ClassNotFoundException {
		String methodName = m.getName();
		String methodSig = m.getSignature();
		{
			//First look for the method in interfaces of the class
			JavaClass[] infClasses = cls.getInterfaces();
			for (JavaClass infCls : infClasses) {
				Method infMethod = findMethod(infClsmethodNamemethodSig);
				if (infMethod != null) {
					return buildConstrainingInfo(infClsinfMethod);
else {
					Map<StringSet<String>> constrainingExs = getConstrainingInfo(infClsm);
					if (constrainingExs != null) {
						return constrainingExs;
					}
				}
			}
		}
		{
			//Next look at the superclass
			JavaClass superCls = cls.getSuperClass();
			if (superCls != null) {
				Method superMethod = findMethod(superClsmethodNamemethodSig);
				if (superMethod != null) {
					return buildConstrainingInfo(superClssuperMethod);
				}
				//Otherwise recursively call this on the super class
				return getConstrainingInfo(superClsm);
			}
			return null;
		}
	}

finds a method that matches the name and signature in the given class

Parameters:
cls the class to look in
methodName the name to look for
methodSig the signature to look for
Returns:
the method or null
	private Method findMethod(JavaClass clsString methodNameString methodSig) {
		Method[] methods = cls.getMethods();
		for (Method method : methods) {
			if (method.getName().equals(methodName) && method.getSignature().equals(methodSig)) {
				return method;
			}
		}
		return null;
	}

returns exception names describing what exceptions are allowed to be thrown

Parameters:
cls the cls to find the exceptions in
m the method to add exceptions from
Returns:
a map with one entry of a class name to a set of exceptions that constrain what can be thrown.
	private Map<StringSet<String>> buildConstrainingInfo(JavaClass cls, Method mthrows ClassNotFoundException {
		Map<StringSet<String>> constraintInfo = new HashMap<StringSet<String>>();
		Set<Stringexs = new HashSet<String>();
		ExceptionTable et = m.getExceptionTable();
		if (et != null) {
			int[] indexTable = et.getExceptionIndexTable();
			ConstantPool pool = cls.getConstantPool();
			for (int index : indexTable) {
				if (index != 0) {
					ConstantClass ccls = (ConstantClass)pool.getConstant(index);
					String exName = ccls.getBytes(pool);
					JavaClass exClass = Repository.lookupClass(exName);
					if (!exClass.instanceOf())
						exs.add(ccls.getBytes(pool));
				}
			}
		}
		constraintInfo.put(cls.getClassName(), exs);
		return constraintInfo;
	}

returns whether a method explicitly throws an exception

Parameters:
method the currently parsed method
Returns:
if the method throws an exception
	private boolean prescreen(Method method) {
		BitSet bytecodeSet = getClassContext().getBytecodeSet(method);
		return (bytecodeSet != null) && (bytecodeSet.get(Constants.ATHROW));
	}
	private static class CatchInfo {
		private final int catchStart;
		private int catchFinish;
		private final String catchSignature;
		public CatchInfo(int startint finishString signature) {
			 = start;
			 = finish;
			 = signature;
		}
		public int getStart() {
			return ;
		}
		public void setFinish(int finish) {
			 = finish;
		}
		public int getFinish() {
			return ;
		}
		public String getSignature() {
		}
	}
New to GrepCode? Check out our FAQ X