[Fb-contrib-commit] SF.net SVN: fb-contrib: [982] trunk/fb-contrib
Brought to you by:
dbrosius
From: <dbr...@us...> - 2008-01-10 05:30:18
|
Revision: 982 http://fb-contrib.svn.sourceforge.net/fb-contrib/?rev=982&view=rev Author: dbrosius Date: 2008-01-09 21:30:23 -0800 (Wed, 09 Jan 2008) Log Message: ----------- Initial checkin JAO detector Modified Paths: -------------- trunk/fb-contrib/build.xml trunk/fb-contrib/etc/findbugs.xml trunk/fb-contrib/etc/messages.xml trunk/fb-contrib/samples/samples.fb Added Paths: ----------- trunk/fb-contrib/samples/JAO_Sample.java trunk/fb-contrib/samples/lib/junit.jar trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/JUnitAssertionOddities.java Modified: trunk/fb-contrib/build.xml =================================================================== --- trunk/fb-contrib/build.xml 2007-11-24 15:59:04 UTC (rev 981) +++ trunk/fb-contrib/build.xml 2008-01-10 05:30:23 UTC (rev 982) @@ -45,6 +45,7 @@ </path> <path id="fb-contrib.samples.classpath"> <pathelement location="${sampleslib.dir}/jsp-api.jar"/> + <pathelement location="${sampleslib.dir}/junit.jar"/> </path> <mkdir dir="${classes.dir}/com"/> <mkdir dir="${classes.dir}/com/mebigfatguy"/> Modified: trunk/fb-contrib/etc/findbugs.xml =================================================================== --- trunk/fb-contrib/etc/findbugs.xml 2007-11-24 15:59:04 UTC (rev 981) +++ trunk/fb-contrib/etc/findbugs.xml 2008-01-10 05:30:23 UTC (rev 982) @@ -304,6 +304,10 @@ speed="fast" reports="CFS_CONFUSING_FUNCTION_SEMANTICS" /> + <Detector class="com.mebigfatguy.fbcontrib.detect.JUnitAssertionOddities" + speed="fast" + reports="JAO_JUNIT_ASSERTION_ODDITIES_ACTUAL_CONSTANT,JAO_JUNIT_ASSERTION_ODDITIES_INEXACT_DOUBLE,JAO_JUNIT_ASSERTION_ODDITIES_BOOLEAN_ASSERT" /> + <!-- BugPattern --> <BugPattern abbrev="ISB" type="ISB_INEFFICIENT_STRING_BUFFERING" category="PERFORMANCE" /> @@ -404,4 +408,7 @@ <BugPattern abbrev="EXS" type="EXS_EXCEPTION_SOFTENING_HAS_CHECKED" category="STYLE" /> <BugPattern abbrev="EXS" type="EXS_EXCEPTION_SOFTENING_NO_CHECKED" category="STYLE" /> <BugPattern abbrev="CFS" type="CFS_CONFUSING_FUNCTION_SEMANTICS" category="STYLE" experimental="true" /> + <BugPattern abbrev="JAO" type="JAO_JUNIT_ASSERTION_ODDITIES_ACTUAL_CONSTANT" category="STYLE" experimental="true" /> + <BugPattern abbrev="JAO" type="JAO_JUNIT_ASSERTION_ODDITIES_INEXACT_DOUBLE" category="STYLE" experimental="true" /> + <BugPattern abbrev="JAO" type="JAO_JUNIT_ASSERTION_ODDITIES_BOOLEAN_ASSERT" 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-11-24 15:59:04 UTC (rev 981) +++ trunk/fb-contrib/etc/messages.xml 2008-01-10 05:30:23 UTC (rev 982) @@ -831,6 +831,23 @@ </Details> </Detector> + <Detector class="com.mebigfatguy.fbcontrib.detect.JUnitAssertionOddities"> + <Details> + <![CDATA[ + <p>looks for junit test case methods that use assertions with odd parameters. + Including in this is: + <ul> + <li>Passing a constant as the second (actual) parameter</li> + <li>not using the three parameter version of asserts for doubles</li> + <li>Passing true or false as the first parameter instead of using assertTrue, or assertFalse</li> + </ul> + </p> + <p>It is a fast detector</p> + ]]> + </Details> + </Detector> + + <!-- BugPattern --> <BugPattern type="ISB_INEFFICIENT_STRING_BUFFERING"> @@ -2135,6 +2152,40 @@ </Details> </BugPattern> + <BugPattern type="JAO_JUNIT_ASSERTION_ODDITIES_ACTUAL_CONSTANT"> + <ShortDescription>method passes constant to second (actual) assertion parameter</ShortDescription> + <LongDescription>method {1} passes constant to second (actual) assertion parameter</LongDescription> + <Details> + <![CDATA[ + <p>This method calls assert passing a constant value as the second of the two values. The assert + method assumes that the expected value is the first parameter, and so it appears that the order + of values has been swapped here.</p> + ]]> + </Details> + </BugPattern> + + <BugPattern type="JAO_JUNIT_ASSERTION_ODDITIES_INEXACT_DOUBLE"> + <ShortDescription>method asserts that two doubles are exactly equal</ShortDescription> + <LongDescription>method {1} asserts that two doubles are exactly equal</LongDescription> + <Details> + <![CDATA[ + <p>This method calls assert with two doubles or Doubles. Due to the inprecision of doubles, you + should be using the assert method that takes a range parameter that gives a range of error.</p> + ]]> + </Details> + </BugPattern> + + <BugPattern type="JAO_JUNIT_ASSERTION_ODDITIES_BOOLEAN_ASSERT"> + <ShortDescription>method asserts that a value is true or false</ShortDescription> + <LongDescription>method {1} asserts that a value is true or false</LongDescription> + <Details> + <![CDATA[ + <p>This method asserts that a value is equal to true or false. It is simpler to just + use assertTrue, or assertFalse, instead.</p> + ]]> + </Details> + </BugPattern> + <!-- BugCode --> <BugCode abbrev="ISB">Inefficient String Buffering</BugCode> @@ -2205,4 +2256,5 @@ <BugCode abbrev="MOM">Misleading Overload Model</BugCode> <BugCode abbrev="EXS">Exception Softening</BugCode> <BugCode abbrev="CFS">Confusing Function Semantics</BugCode> + <BugCode abbrev="JAO">JUnit Assertion Oddities</BugCode> </MessageCollection> \ No newline at end of file Added: trunk/fb-contrib/samples/JAO_Sample.java =================================================================== --- trunk/fb-contrib/samples/JAO_Sample.java (rev 0) +++ trunk/fb-contrib/samples/JAO_Sample.java 2008-01-10 05:30:23 UTC (rev 982) @@ -0,0 +1,27 @@ +import junit.framework.Assert; +import junit.framework.TestCase; + + +public class JAO_Sample extends TestCase +{ + + public void testExactDoubles(double d1, double d2) + { + Assert.assertEquals(d1, d2); + } + + public void testTrue(boolean b) + { + Assert.assertEquals(true, b); + } + + public void testFalse(boolean b) + { + Assert.assertEquals("Wow this is bad", false, b); + } + + public void testWrongOrder(int i) + { + Assert.assertEquals(i, 10); + } +} Property changes on: trunk/fb-contrib/samples/JAO_Sample.java ___________________________________________________________________ Name: svn:mime-type + text/plain Name: svn:eol-style + native Added: trunk/fb-contrib/samples/lib/junit.jar =================================================================== (Binary files differ) Property changes on: trunk/fb-contrib/samples/lib/junit.jar ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Modified: trunk/fb-contrib/samples/samples.fb =================================================================== --- trunk/fb-contrib/samples/samples.fb 2007-11-24 15:59:04 UTC (rev 981) +++ trunk/fb-contrib/samples/samples.fb 2008-01-10 05:30:23 UTC (rev 982) @@ -4,5 +4,6 @@ . [Aux classpath entries] .\lib\jsp-api.jar +.\lib\junit.jar [Options] relative_paths=true Added: trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/JUnitAssertionOddities.java =================================================================== --- trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/JUnitAssertionOddities.java (rev 0) +++ trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/JUnitAssertionOddities.java 2008-01-10 05:30:23 UTC (rev 982) @@ -0,0 +1,181 @@ +/* + * fb-contrib - Auxiliary 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 org.apache.bcel.Repository; +import org.apache.bcel.classfile.Attribute; +import org.apache.bcel.classfile.Code; +import org.apache.bcel.classfile.Constant; +import org.apache.bcel.classfile.ConstantPool; +import org.apache.bcel.classfile.ConstantUtf8; +import org.apache.bcel.classfile.JavaClass; +import org.apache.bcel.classfile.Method; +import org.apache.bcel.classfile.Unknown; +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 odd uses of the Assert class of the JUnit framework */ +public class JUnitAssertionOddities extends BytecodeScanningDetector +{ + private static final String RUNTIME_VISIBLE_ANNOTATIONS = "RuntimeVisibleAnnotations"; + private static final String TEST_ANNOTATION_SIGNATURE = "Lorg/junit/Test;"; + private static final String OLD_ASSERT_CLASS = "junit/framework/Assert"; + private static final String NEW_ASSERT_CLASS = "org/junit/Assert"; + private static JavaClass testCaseClass; + private static JavaClass testAnnotationClass; + static { + try { + testCaseClass = Repository.lookupClass("junit.framework.TestCase"); + } catch (ClassNotFoundException cnfe) { + testCaseClass = null; + } + try { + testAnnotationClass = Repository.lookupClass("org.junit.Test"); + } catch (ClassNotFoundException cnfe) { + testAnnotationClass = null; + } + } + private BugReporter bugReporter; + private OpcodeStack stack; + private boolean isTestCaseDerived; + private boolean isAnnotationCapable; + + /** + * constructs a JOA detector given the reporter to report bugs on + * @param bugReporter the sync of bug reports + */ + public JUnitAssertionOddities(BugReporter bugReporter) { + this.bugReporter = bugReporter; + } + + /** + * override the visitor to see if this class could be a test class + * + * @param classContext the context object of the currently parsed class + */ + @Override + public void visitClassContext(ClassContext classContext) { + try { + JavaClass cls = classContext.getJavaClass(); + isTestCaseDerived = ((testCaseClass != null) && cls.instanceOf(testCaseClass)); + isAnnotationCapable = (cls.getMajor() >= 5) && (testAnnotationClass != null); + if (isTestCaseDerived || isAnnotationCapable) { + stack = new OpcodeStack(); + super.visitClassContext(classContext); + } + } catch (ClassNotFoundException cnfe) { + bugReporter.reportMissingClass(cnfe); + } finally { + stack = null; + } + } + + @Override + public void visitCode(Code obj) { + Method m = getMethod(); + boolean isTestMethod = isTestCaseDerived && m.getName().startsWith("test"); + + if (!isTestMethod && isAnnotationCapable) { + Attribute[] atts = m.getAttributes(); + for (Attribute att : atts) { + ConstantPool cp = att.getConstantPool(); + Constant c = cp.getConstant(att.getNameIndex()); + if (c instanceof ConstantUtf8) { + String name = ((ConstantUtf8) c).getBytes(); + if (RUNTIME_VISIBLE_ANNOTATIONS.equals(name)) { + if (att instanceof Unknown) { + Unknown unAtt = (Unknown)att; + byte[] bytes = unAtt.getBytes(); + int constantPoolIndex = bytes[3]; + c = cp.getConstant(constantPoolIndex); + if (c instanceof ConstantUtf8) { + name = ((ConstantUtf8) c).getBytes(); + if (TEST_ANNOTATION_SIGNATURE.equals(name)) { + isTestMethod = true; + break; + } + } + } + } + } + } + } + + if (isTestMethod) { + stack.resetForMethodEntry(this); + super.visitCode(obj); + } + } + + @Override + public void sawOpcode(int seen) { + try { + stack.mergeJumps(this); + + if (seen == INVOKESTATIC) { + String clsName = getClassConstantOperand(); + if (OLD_ASSERT_CLASS.equals(clsName) || NEW_ASSERT_CLASS.equals(clsName)) { + String methodName = getNameConstantOperand(); + if ("assertEquals".equals(methodName)) { + String signature = getSigConstantOperand(); + Type[] argTypes = Type.getArgumentTypes(signature); + if (argTypes[0].equals(Type.STRING) && argTypes[1].equals(Type.STRING)) + return; + + if (stack.getStackDepth() >= 2) { + OpcodeStack.Item item1 = stack.getStackItem(1); + Object cons1 = item1.getConstant(); + if ((cons1 != null) && (argTypes[argTypes.length-1].equals(Type.BOOLEAN)) && (argTypes[argTypes.length-2].equals(Type.BOOLEAN))) { + bugReporter.reportBug(new BugInstance(this, "JAO_JUNIT_ASSERTION_ODDITIES_BOOLEAN_ASSERT", NORMAL_PRIORITY) + .addClass(this) + .addMethod(this) + .addSourceLine(this)); + return; + } + OpcodeStack.Item item0 = stack.getStackItem(0); + if (item0.getConstant() != null) { + bugReporter.reportBug(new BugInstance(this, "JAO_JUNIT_ASSERTION_ODDITIES_ACTUAL_CONSTANT", NORMAL_PRIORITY) + .addClass(this) + .addMethod(this) + .addSourceLine(this)); + return; + } + if (argTypes[0].equals(Type.OBJECT) && argTypes[1].equals(Type.OBJECT)) { + if ("Ljava/lang/Double;".equals(item0.getSignature()) && "Ljava/lang/Double;".equals(item1.getSignature())) { + bugReporter.reportBug(new BugInstance(this, "JAO_JUNIT_ASSERTION_ODDITIES_INEXACT_DOUBLE", NORMAL_PRIORITY) + .addClass(this) + .addMethod(this) + .addSourceLine(this)); + return; + } + } + } + } + } + } + } finally { + stack.sawOpcode(this, seen); + } + } +} Property changes on: trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/JUnitAssertionOddities.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. |