[Fb-contrib-commit] SF.net SVN: fb-contrib: [926] trunk/fb-contrib
Brought to you by:
dbrosius
From: <dbr...@us...> - 2007-10-08 01:34:29
|
Revision: 926 http://fb-contrib.svn.sourceforge.net/fb-contrib/?rev=926&view=rev Author: dbrosius Date: 2007-10-07 18:34:32 -0700 (Sun, 07 Oct 2007) Log Message: ----------- differentiate the three types of EXS bugs. Break out similarPackages to SignatureUtils Modified Paths: -------------- trunk/fb-contrib/etc/messages.xml trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/ClassEnvy.java trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/ExceptionSoftening.java trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/utils/SignatureUtils.java Modified: trunk/fb-contrib/etc/messages.xml =================================================================== --- trunk/fb-contrib/etc/messages.xml 2007-10-07 23:41:34 UTC (rev 925) +++ trunk/fb-contrib/etc/messages.xml 2007-10-08 01:34:32 UTC (rev 926) @@ -2007,14 +2007,13 @@ </BugPattern> <BugPattern type="EXS_EXCEPTION_SOFTENING_NO_CONSTRAINTS"> - <ShortDescription>constrained method converts checked exception to unchecked</ShortDescription> - <LongDescription>constrained method {1} converts checked exception to unchecked</LongDescription> + <ShortDescription>unconstrained method converts checked exception to unchecked</ShortDescription> + <LongDescription>unconstrained method {1} converts checked exception to unchecked</LongDescription> <Details> <![CDATA[ - <p>This method's exception signature is constrained by an interface or super class to not throw - any checked exceptions. Therefore a caught checked exception was converted to an unchecked exception - and thrown. However it appears that the class in question is owned by the same author as the constraining - interface or superclass. Consider changes the signature of this method to include the checked exception.</p> + <p>This method is not constrained by an interface or superclass, but converts a caught checked exception + to unchecked exception and thrown. It would be more appropriate just throw the checked exception, adding + the exception to the throws clause of the method. ]]> </Details> </BugPattern> @@ -2033,13 +2032,14 @@ </BugPattern> <BugPattern type="EXS_EXCEPTION_SOFTENING_NO_CHECKED"> - <ShortDescription>unconstrained method converts checked exception to unchecked</ShortDescription> - <LongDescription>unconstrained method {1} converts checked exception to unchecked</LongDescription> + <ShortDescription>constrained method converts checked exception to unchecked</ShortDescription> + <LongDescription>constrained method {1} converts checked exception to unchecked</LongDescription> <Details> <![CDATA[ - <p>This method is not constrained by an interface or superclass, but converts a caught checked exception - to unchecked exception and thrown. It would be more appropriate just throw the checked exception, adding - the exception to the throws clause of the method. + <p>This method's exception signature is constrained by an interface or super class to not throw + any checked exceptions. Therefore a caught checked exception was converted to an unchecked exception + and thrown. However it appears that the class in question is owned by the same author as the constraining + interface or superclass. Consider changes the signature of this method to include the checked exception.</p> ]]> </Details> </BugPattern> Modified: trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/ClassEnvy.java =================================================================== --- trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/ClassEnvy.java 2007-10-07 23:41:34 UTC (rev 925) +++ trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/ClassEnvy.java 2007-10-08 01:34:32 UTC (rev 926) @@ -33,6 +33,7 @@ import org.apache.bcel.generic.Type; import com.mebigfatguy.fbcontrib.utils.Integer14; +import com.mebigfatguy.fbcontrib.utils.SignatureUtils; import edu.umd.cs.findbugs.BugInstance; import edu.umd.cs.findbugs.BugReporter; @@ -262,7 +263,7 @@ thisClsAccessCount++; else { String calledPackage = getPackageName(calledClass); - if (similarPackages(calledPackage, packageName, 2) && !generalPurpose(calledClass)) { + if (SignatureUtils.similarPackages(calledPackage, packageName, 2) && !generalPurpose(calledClass)) { Set<Integer> lineNumbers = clsAccessCount.get(calledClass); if (lineNumbers == null) { lineNumbers = new HashSet<Integer>(); @@ -353,33 +354,4 @@ return ""; return className.substring(0, dotPos); } - - /** - * returns whether or not the two packages have the same first 'depth' parts, if they exist - * - * @param packName1 the first package to check - * @param packName2 the second package to check - * @param depth the number of package parts to check - * - * @return if they are similar - */ - private boolean similarPackages(final String packName1, final String packName2, int depth) { - if (depth == 0) - return true; - - int dot1 = packName1.indexOf('.'); - int dot2 = packName2.indexOf('.'); - if (dot1 < 0) - return (dot2 < 0); - else if (dot2 < 0) - return false; - - String s1 = packName1.substring(0, dot1); - String s2 = packName2.substring(0, dot2); - - if (!s1.equals(s2)) - return false; - - return similarPackages(packName1.substring(dot1+1), packName2.substring(dot2+1), depth-1); - } } Modified: trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/ExceptionSoftening.java =================================================================== --- trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/ExceptionSoftening.java 2007-10-07 23:41:34 UTC (rev 925) +++ trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/ExceptionSoftening.java 2007-10-08 01:34:32 UTC (rev 926) @@ -20,6 +20,7 @@ import java.util.ArrayList; import java.util.BitSet; +import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; @@ -34,9 +35,12 @@ 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.Method; +import com.mebigfatguy.fbcontrib.utils.SignatureUtils; + import edu.umd.cs.findbugs.BugInstance; import edu.umd.cs.findbugs.BugReporter; import edu.umd.cs.findbugs.BytecodeScanningDetector; @@ -65,6 +69,7 @@ private OpcodeStack stack; private Map<Integer, CodeException> catchHandlerPCs; private List<CatchInfo> catchInfos; + private Map<String, Set<String>> constrainingInfo; /** constructs a EXS detector given the reporter to report bugs on. @@ -103,11 +108,13 @@ stack.resetForMethodEntry(this); catchHandlerPCs = collectExceptions(obj.getExceptionTable()); catchInfos = new ArrayList<CatchInfo>(); + constrainingInfo = null; super.visitCode(obj); } } finally { catchInfos = null; catchHandlerPCs = null; + constrainingInfo = null; } } @@ -155,10 +162,38 @@ } if (!anyRuntimes) { - bugReporter.reportBug(new BugInstance(this, "EXS_EXCEPTION_SOFTENING_NO_CONSTRAINTS", NORMAL_PRIORITY) - .addClass(this) - .addMethod(this) - .addSourceLine(this)); + + if (constrainingInfo == null) + constrainingInfo = getConstrainingInfo(getClassContext().getJavaClass(), getMethod()); + + String bug = null; + if (constrainingInfo == null) + bug = "EXS_EXCEPTION_SOFTENING_NO_CONSTRAINTS"; + else if (!constrainingInfo.values().iterator().next().isEmpty()) + bug = "EXS_EXCEPTION_SOFTENING_HAS_CHECKED"; + else { + String pack1 = constrainingInfo.keySet().iterator().next(); + 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(pack1, pack2, 2)) + bug = "EXS_EXCEPTION_SOFTENING_NO_CHECKED"; + } + + if (bug != null) { + bugReporter.reportBug(new BugInstance(this, bug, NORMAL_PRIORITY) + .addClass(this) + .addMethod(this) + .addSourceLine(this)); + } } } } @@ -235,6 +270,91 @@ return catchTypes; } + /** finds the super class or interface that constrains the types of exceptions that can be thrown from the given method + * + * @param m the method to check + * @return a map containing the class name to a set of exceptions that constrain this method + */ + public Map<String, Set<String>> getConstrainingInfo(JavaClass cls, Method m) throws 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(infCls, methodName, methodSig); + if (infMethod != null) { + return buildConstrainingInfo(infCls, infMethod); + } else { + Map<String, Set<String>> constrainingExs = getConstrainingInfo(infCls, m); + if (constrainingExs != null) { + return constrainingExs; + } + } + } + } + + { + //Next look at the superclass + JavaClass superCls = cls.getSuperClass(); + if (superCls != null) { + Method superMethod = findMethod(superCls, methodName, methodSig); + if (superMethod != null) { + return buildConstrainingInfo(superCls, superMethod); + } + + //Otherwise recursively call this on the super class + return getConstrainingInfo(superCls, m); + } + + return null; + } + } + + /** finds a method that matches the name and signature in the given class + * @param cls the class to look in + * @param methodName the name to look for + * @param methodSig the signature to look for + * + * @return the method or null + */ + private Method findMethod(JavaClass cls, String methodName, String 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 + * + * @param cls the cls to find the exceptions in + * @param m the method to add exceptions from + * @return a map with one entry of a class name to a set of exceptions that constrain what can be thrown. + */ + private Map<String, Set<String>> buildConstrainingInfo(JavaClass cls, Method m) { + Map<String, Set<String>> constraintInfo = new HashMap<String, Set<String>>(); + Set<String> exs = new HashSet<String>(); + ExceptionTable et = m.getExceptionTable(); + if (et != null) { + int[] indexTable = et.getExceptionIndexTable(); + ConstantPool pool = cls.getConstantPool(); + for (int i = 0; i < indexTable.length; i++) { + int index = indexTable[i]; + if (index != 0) { + ConstantClass ccls = (ConstantClass)pool.getConstant(index); + exs.add(ccls.getBytes(pool)); + } + } + } + constraintInfo.put(cls.getClassName(), exs); + return constraintInfo; + } + /** returns whether a method explicitly throws an exception * * @param method the currently parsed method Modified: trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/utils/SignatureUtils.java =================================================================== --- trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/utils/SignatureUtils.java 2007-10-07 23:41:34 UTC (rev 925) +++ trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/utils/SignatureUtils.java 2007-10-08 01:34:32 UTC (rev 926) @@ -38,6 +38,36 @@ return findInheritedMethod(supers, methodName, signature) != null; } + /** + * returns whether or not the two packages have the same first 'depth' parts, if they exist + * + * @param packName1 the first package to check + * @param packName2 the second package to check + * @param depth the number of package parts to check + * + * @return if they are similar + */ + public static boolean similarPackages(final String packName1, final String packName2, int depth) { + if (depth == 0) + return true; + + int dot1 = packName1.indexOf('.'); + int dot2 = packName2.indexOf('.'); + if (dot1 < 0) + return (dot2 < 0); + else if (dot2 < 0) + return false; + + String s1 = packName1.substring(0, dot1); + String s2 = packName2.substring(0, dot2); + + if (!s1.equals(s2)) + return false; + + return similarPackages(packName1.substring(dot1+1), packName2.substring(dot2+1), depth-1); + } + + private static JavaClass findInheritedMethod(JavaClass[] classes, String methodName, String signature) { for (JavaClass cls : classes) { if (cls != null) { This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |