[Fb-contrib-commit] SF.net SVN: fb-contrib: [627] trunk/fb-contrib
Brought to you by:
dbrosius
From: <dbr...@us...> - 2006-09-04 04:08:24
|
Revision: 627 http://svn.sourceforge.net/fb-contrib/?rev=627&view=rev Author: dbrosius Date: 2006-09-03 21:08:09 -0700 (Sun, 03 Sep 2006) Log Message: ----------- initial checkin, new URV detector Modified Paths: -------------- trunk/fb-contrib/etc/findbugs.xml trunk/fb-contrib/etc/messages.xml Added Paths: ----------- trunk/fb-contrib/samples/URV_Sample.java trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/UnrelatedReturnValues.java Modified: trunk/fb-contrib/etc/findbugs.xml =================================================================== --- trunk/fb-contrib/etc/findbugs.xml 2006-09-04 03:08:46 UTC (rev 626) +++ trunk/fb-contrib/etc/findbugs.xml 2006-09-04 04:08:09 UTC (rev 627) @@ -242,6 +242,10 @@ speed="fast" reports="TR_TAIL_RECURSION" /> + <Detector class="com.mebigfatguy.fbcontrib.detect.UnrelatedReturnValues" + speed="fast" + reports="URV_UNRELATED_RETURN_VALUES,URV_CHANGE_RETURN_TYPE" /> + <!-- BugPattern --> <BugPattern abbrev="ISB" type="ISB_INEFFICIENT_STRING_BUFFERING" category="PERFORMANCE" /> @@ -302,4 +306,7 @@ <BugPattern abbrev="LEST" type="LEST_LOST_EXCEPTION_STACK_TRACE" category="CORRECTNESS" experimental="true" /> <BugPattern abbrev="UCPM" type="UCPM_USE_CHARACTER_PARAMETERIZED_METHOD" category="PERFORMANCE" experimental="true" /> <BugPattern abbrev="TR" type="TR_TAIL_RECURSION" category="PERFORMANCE" experimental="true" /> + <BugPattern abbrev="URV" type="URV_UNRELATED_RETURN_VALUES" category="STYLE" experimental="true" /> + <BugPattern abbrev="URV" type="URV_CHANGE_RETURN_TYPE" category="STYLE" experimental="true" /> + </FindbugsPlugin> \ No newline at end of file Modified: trunk/fb-contrib/etc/messages.xml =================================================================== --- trunk/fb-contrib/etc/messages.xml 2006-09-04 03:08:46 UTC (rev 626) +++ trunk/fb-contrib/etc/messages.xml 2006-09-04 04:08:09 UTC (rev 627) @@ -652,7 +652,18 @@ ]]> </Details> </Detector> - + + <Detector class="com.mebigfatguy.fbcontrib.detect.UnrelatedReturnValues"> + <Details> + <![CDATA[ + <p>looks for methods that are defined to return Object, and return different types of + objects based on different code paths. If this method is not based on a interface or + superclass, it is suggested to change the return type to a type that would accomodate + all kinds of return types.</p> + <p>It is a fast detector.</p> + ]]> + </Details> + </Detector> <!-- BugPattern --> @@ -1405,11 +1416,35 @@ <![CDATA[ <p>This method recursively calls itself as the last statement of the method (Tail Recursion). This method can be easily refactored into a simple loop, which - will make it more performant, and reduce the stack size requirements. + will make it more performant, and reduce the stack size requirements.</p> ]]> </Details> </BugPattern> + <BugPattern type="URV_UNRELATED_RETURN_VALUES"> + <ShortDescription>Derived method returns different types of unrelated Objects</ShortDescription> + <LongDescription>Derived method {1} returns different types of unrelated Objects</LongDescription> + <Details> + <![CDATA[ + <p>This method, which is derived from a superclass, or interface, returns two or + more unrelated types of objects. This will be very confusing to the code that must + call it.</p> + ]]> + </Details> + </BugPattern> + + <BugPattern type="URV_CHANGE_RETURN_TYPE"> + <ShortDescription>Method returns different types of unrelated Objects</ShortDescription> + <LongDescription>Method {1} returns different types of unrelated Objects</LongDescription> + <Details> + <![CDATA[ + <p>This method is defined to return a java.lang.Object. However, the return types + returned from this method can be defined by a more specific class or interface. Since this + method is not derived from a superclass or interface, it would be more clear to + change the return type of this method.</p> + ]]> + </Details> + </BugPattern> <!-- BugCode --> <BugCode abbrev="ISB">Inefficient String Buffering</BugCode> @@ -1465,4 +1500,5 @@ <BugCode abbrev="LEST">Lost Exception Stack Trace</BugCode> <BugCode abbrev="UCPM">Use Character Parameterized Method</BugCode> <BugCode abbrev="TR">Tail Recursion</BugCode> + <BugCode abbrev="URV">Unrelated Return Values</BugCode> </MessageCollection> \ No newline at end of file Added: trunk/fb-contrib/samples/URV_Sample.java =================================================================== --- trunk/fb-contrib/samples/URV_Sample.java (rev 0) +++ trunk/fb-contrib/samples/URV_Sample.java 2006-09-04 04:08:09 UTC (rev 627) @@ -0,0 +1,37 @@ +import java.util.HashSet; +import java.util.TreeSet; + +public class URV_Sample extends URV_Super +{ + public Object getASet(boolean b) + { + if (b) + return new HashSet(); + else + return new TreeSet(); + } + + public Object getInfo(boolean b) + { + if (b) + return new String[4]; + else + return ""; + } + + public Object getInheritedInfo(boolean b) + { + if (b) + return new Integer(1); + else + return new Float(1.0); + } +} + +class URV_Super +{ + public Object getInheritedInfo(boolean b) + { + return null; + } +} Added: trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/UnrelatedReturnValues.java =================================================================== --- trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/UnrelatedReturnValues.java (rev 0) +++ trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/UnrelatedReturnValues.java 2006-09-04 04:08:09 UTC (rev 627) @@ -0,0 +1,171 @@ +/* + * fb-contrib - Auxilliary detectors for Java programs + * Copyright (C) 2005-2006 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.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.apache.bcel.classfile.Code; +import org.apache.bcel.classfile.JavaClass; +import org.apache.bcel.classfile.Method; + +import com.mebigfatguy.fbcontrib.utils.Integer14; +import com.mebigfatguy.fbcontrib.utils.SignatureUtils; + +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 methods that return Object, and who's code body returns two or more + * different types of objects that are unrelated (other than by Object). + */ +public class UnrelatedReturnValues extends BytecodeScanningDetector +{ + private BugReporter bugReporter; + private OpcodeStack stack; + private JavaClass currentClass; + private Map<JavaClass, Integer> returnTypes; + private boolean isInherited; + + /** + * constructs a URV detector given the reporter to report bugs on + * @param bugReporter the sync of bug reports + */ + public UnrelatedReturnValues(BugReporter bugReporter) { + this.bugReporter = bugReporter; + } + + public void visitClassContext(ClassContext classContext) { + try { + currentClass = classContext.getJavaClass(); + stack = new OpcodeStack(); + returnTypes = new HashMap<JavaClass, Integer>(); + super.visitClassContext(classContext); + } + finally { + currentClass = null; + stack = null; + returnTypes = null; + } + } + /** + * implements the visitor to see if the method returns Object, and if the method + * is defined in a superclass, or interface. + * + * @param obj the context object of the currently parsed code block + */ + @Override + public void visitCode(Code obj) { + try { + Method m = getMethod(); + String methodName = m.getName(); + String signature = m.getSignature(); + if (signature.endsWith(")Ljava/lang/Object;")) { + isInherited = SignatureUtils.isInheritedMethod(currentClass, methodName, signature); + stack.resetForMethodEntry(this); + returnTypes.clear(); + super.visitCode(obj); + if (returnTypes.size() > 1) { + JavaClass cls = findCommonType(returnTypes.keySet()); + BugInstance bug = null; + if ((cls == null) || isInherited) { + bug = new BugInstance(this, "URV_UNRELATED_RETURN_VALUES", NORMAL_PRIORITY) + .addClass(this) + .addMethod(this); + } else if (!isInherited) { + bug = new BugInstance(this, "URV_CHANGE_RETURN_TYPE", NORMAL_PRIORITY) + .addClass(this) + .addMethod(this); + bug.addString(cls.getClassName()); + } + if (bug != null) { + for (Integer pc : returnTypes.values()) { + bug.addSourceLine(this, pc.intValue()); + } + bugReporter.reportBug(bug); + } + } + } + } catch (ClassNotFoundException cnfe) { + bugReporter.reportMissingClass(cnfe); + } + } + + /** + * implements the visitor to find return values where the types of objects returned from the + * method are related only by object. + */ + public void sawOpcode(int seen) { + try { + stack.mergeJumps(this); + if (seen == ARETURN) { + if (stack.getStackDepth() > 0) { + OpcodeStack.Item itm = stack.getStackItem(0); + returnTypes.put(itm.getJavaClass(), Integer14.valueOf(getPC())); + } + } + } catch (ClassNotFoundException cnfe) { + bugReporter.reportMissingClass(cnfe); + } finally { + stack.sawOpcode(this, seen); + } + } + + /** + * looks for a common superclass or interface for all the passed in types + * + * @param types the set of classes to look for a common super class or interface + * @return the type that is the common interface or superclass (not Object, tho). + */ + public JavaClass findCommonType(Set<JavaClass> classes) throws ClassNotFoundException { + Set<JavaClass> possibleCommonTypes = new HashSet<JavaClass>(); + classes.remove("java/lang/Object"); + boolean populate = true; + for (JavaClass cls : classes) { + JavaClass[] infs = cls.getAllInterfaces(); + JavaClass[] supers = cls.getSuperClasses(); + if (populate) { + possibleCommonTypes.addAll(Arrays.asList(infs)); + possibleCommonTypes.addAll(Arrays.asList(supers)); + possibleCommonTypes.remove("java/lang/Object"); + populate = false; + } else { + Set<JavaClass> retain = new HashSet<JavaClass>(); + retain.addAll(Arrays.asList(infs)); + retain.addAll(Arrays.asList(supers)); + possibleCommonTypes.retainAll(retain); + } + } + + if (possibleCommonTypes.size() == 0) + return null; + + for (JavaClass cls : possibleCommonTypes) { + if (cls.isInterface()) + return cls; + } + return possibleCommonTypes.iterator().next(); + } +} This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |