[Fb-contrib-commit] SF.net SVN: fb-contrib: [923] trunk/fb-contrib
Brought to you by:
dbrosius
From: <dbr...@us...> - 2007-10-06 22:29:44
|
Revision: 923 http://fb-contrib.svn.sourceforge.net/fb-contrib/?rev=923&view=rev Author: dbrosius Date: 2007-10-06 15:29:47 -0700 (Sat, 06 Oct 2007) Log Message: ----------- initial checkin - EXS detector - not even close to working Modified Paths: -------------- trunk/fb-contrib/etc/findbugs.xml trunk/fb-contrib/etc/messages.xml Added Paths: ----------- trunk/fb-contrib/samples/EXS_Sample.java trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/ExceptionSoftening.java Modified: trunk/fb-contrib/etc/findbugs.xml =================================================================== --- trunk/fb-contrib/etc/findbugs.xml 2007-10-01 03:27:47 UTC (rev 922) +++ trunk/fb-contrib/etc/findbugs.xml 2007-10-06 22:29:47 UTC (rev 923) @@ -295,6 +295,10 @@ speed="fast" reports="MOM_MISLEADING_OVERLOAD_MODEL" /> + <Detector class="com.mebigfatguy.fbcontrib.detect.ExceptionSoftening" + speed="moderate" + reports="EXS_EXCEPTION_SOFTENING_NO_CONSTRAINTS,EXS_EXCEPTION_SOFTENING_HAS_CHECKED,EXS_EXCEPTION_SOFTENING_NO_CHECKED" /> + <!-- BugPattern --> <BugPattern abbrev="ISB" type="ISB_INEFFICIENT_STRING_BUFFERING" category="PERFORMANCE" /> @@ -387,4 +391,7 @@ <BugPattern abbrev="MRC" type="MRC_METHOD_RETURNS_CONSTANT" category="STYLE" experimental="true" /> <BugPattern abbrev="NCS" type="NCS_NEEDLESS_CUSTOM_SERIALIZATION" category="CORRECTNESS" experimental="true" /> <BugPattern abbrev="MOM" type="MOM_MISLEADING_OVERLOAD_MODEL" category="STYLE" experimental="true" /> + <BugPattern abbrev="EXS" type="EXS_EXCEPTION_SOFTENING_NO_CONSTRAINTS" category="STYLE" experimental="true" /> + <BugPattern abbrev="EXS" type="EXS_EXCEPTION_SOFTENING_HAS_CHECKED" category="STYLE" experimental="true" /> + <BugPattern abbrev="EXS" type="EXS_EXCEPTION_SOFTENING_NO_CHECKED" category="STYLE" experimental="true" /> </FindbugsPlugin> \ No newline at end of file Modified: trunk/fb-contrib/etc/messages.xml =================================================================== --- trunk/fb-contrib/etc/messages.xml 2007-10-01 03:27:47 UTC (rev 922) +++ trunk/fb-contrib/etc/messages.xml 2007-10-06 22:29:47 UTC (rev 923) @@ -801,6 +801,21 @@ </Details> </Detector> + <Detector class="com.mebigfatguy.fbcontrib.detect.ExceptionSoftening"> + <Details> + <![CDATA[ + <p>looks for methods that catch checked exceptions, and throw unchecked + exceptions in their place. There are several levels of concern. Least + concerning 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. Most egregious are method not constrained by any interface + or superclass contract.</p> + <p>It is a moderately fast detector</p> + ]]> + </Details> + </Detector> + <!-- BugPattern --> <BugPattern type="ISB_INEFFICIENT_STRING_BUFFERING"> @@ -1991,6 +2006,44 @@ </Details> </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> + <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> + ]]> + </Details> + </BugPattern> + + <BugPattern type="EXS_EXCEPTION_SOFTENING_HAS_CHECKED"> + <ShortDescription>constrained method converts checked exception to unchecked instead of another allowable checked exception</ShortDescription> + <LongDescription>constrained method {1} converts checked exception to unchecked instead of another allowable checked exception</LongDescription> + <Details> + <![CDATA[ + <p>This method's exception signature is constrained by an interface of super class to not throw a + checked exception that was caught. Therefore this exception was converted to an unchecked exception and + thrown. It would probably be better to throw the closest checked exception allowed, and to annotate + the new exception with the original exception using the initial cause field.</p> + ]]> + </Details> + </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> + <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. + ]]> + </Details> + </BugPattern> + <!-- BugCode --> <BugCode abbrev="ISB">Inefficient String Buffering</BugCode> @@ -2059,4 +2112,5 @@ <BugCode abbrev="MRC">Method Returns Constant</BugCode> <BugCode abbrev="NCS">Needless Custom Serialization</BugCode> <BugCode abbrev="MOM">Misleading Overload Model</BugCode> + <BugCode abbrev="EXS">Exception Softening</BugCode> </MessageCollection> \ No newline at end of file Added: trunk/fb-contrib/samples/EXS_Sample.java =================================================================== --- trunk/fb-contrib/samples/EXS_Sample.java (rev 0) +++ trunk/fb-contrib/samples/EXS_Sample.java 2007-10-06 22:29:47 UTC (rev 923) @@ -0,0 +1,55 @@ +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.sql.SQLException; + + +public class EXS_Sample extends Super +{ + @Override + public void constrainedNone() + { + try + { + InputStream is = new FileInputStream("c:\\test.txt"); + } + catch (IOException ioe) + { + throw new RuntimeException("Ooops"); + } + } + + @Override + public void constrainedNon() throws SQLException + { + try + { + InputStream is = new FileInputStream("c:\\test.txt"); + } + catch (IOException ioe) + { + throw new RuntimeException("Ooops"); + } + } + + public void notConstrained() + { + try + { + InputStream is = new FileInputStream("c:\\test.txt"); + } + catch (IOException ioe) + { + throw new RuntimeException("Ooops"); + } + } +} + +class Super +{ + public void constrainedNone() + {} + + public void constrainedNon() throws SQLException + {} +} \ No newline at end of file Property changes on: trunk/fb-contrib/samples/EXS_Sample.java ___________________________________________________________________ Name: svn:mime-type + text/plain Name: svn:eol-style + native Added: trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/ExceptionSoftening.java =================================================================== --- trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/ExceptionSoftening.java (rev 0) +++ trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/ExceptionSoftening.java 2007-10-06 22:29:47 UTC (rev 923) @@ -0,0 +1,182 @@ +/* + * fb-contrib - Auxilliary detectors for Java programs + * Copyright (C) 2005-2007 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.ArrayList; +import java.util.BitSet; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Set; + +import org.apache.bcel.Constants; +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.Method; + +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 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 BugReporter bugReporter; + private OpcodeStack stack; + private LinkedHashMap<Integer, CodeException> catchHandlerPCs; + private Set<CatchInfo> catchInfos; + + + /** constructs a EXS detector given the reporter to report bugs on. + + * @param bugReporter the sync of bug reports + */ + public ExceptionSoftening(BugReporter bugReporter) { + this.bugReporter = bugReporter; + } + + /** overrides the visitor to reset the stack + * + * @param classContext the context object of the currently parsed class + */ + @Override + public void visitClassContext(ClassContext classContext) { + try { + stack = new OpcodeStack(); + super.visitClassContext(classContext); + } finally { + stack = null; + } + } + + /** overrides the visitor to look for methods that catch exceptions + * + * @param obj the context object of the currently parsed code block + */ + @Override + public void visitCode(Code obj) { + try { + Method method = getMethod(); + if (prescreen(method)) { + stack.resetForMethodEntry(this); + catchHandlerPCs = collectExceptions(obj.getExceptionTable()); + catchInfos = new HashSet<CatchInfo>(); + super.visitCode(obj); + } + } finally { + catchInfos = null; + catchHandlerPCs = null; + } + } + + /** overrides the visitor to find catch blocks that throw runtime exceptions + * + * @param seen the opcode of the currently parsed instruction + */ + @Override + public void sawOpcode(int seen) { + try { + stack.mergeJumps(this); + int nextPC = getNextPC(); + CodeException ex = catchHandlerPCs.get(Integer.valueOf(nextPC)); + if (ex != null) { + int endPC; + if ((seen == GOTO) || (seen == GOTO_W)) + endPC = this.getBranchTarget(); + else + endPC = Integer.MAX_VALUE; + ConstantPool pool = getConstantPool(); + ConstantClass ccls = (ConstantClass)pool.getConstant(ex.getCatchType()); + String catchSig = ccls.getBytes(pool); + CatchInfo ci = new CatchInfo(ex.getHandlerPC(), endPC, catchSig); + catchInfos.add(ci); + } + } finally { + stack.sawOpcode(this, seen); + } + } + + /** + * collects all the valid exception objects (ones where start and finish are before the target) + * and with a catch type + * + * @param exceptions the exceptions from the class file + * @return the filtered exceptions keyed by catch handler 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.getHandlerPC()), ex); + } + + return handlers; + } + + /** returns whether a method explicitly throws an exception + * + * @param method the currently parsed method + * @return 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 int catchStart; + private int catchFinish; + private String catchSignature; + + public CatchInfo(int start, int finish, String signature) { + catchStart = start; + catchFinish = finish; + catchSignature = signature; + } + + public int getStart() { + return catchStart; + } + + public int getFinish() { + return catchFinish; + } + + public String getSignature() { + return catchSignature; + } + } +} Property changes on: trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/ExceptionSoftening.java ___________________________________________________________________ Name: svn:mime-type + text/plain Name: svn:eol-style + native This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |