[Fb-contrib-commit] SF.net SVN: fb-contrib:[1787] trunk/fb-contrib
Brought to you by:
dbrosius
|
From: <dbr...@us...> - 2015-12-29 21:37:12
|
Revision: 1787
http://sourceforge.net/p/fb-contrib/code/1787
Author: dbrosius
Date: 2015-12-29 21:37:08 +0000 (Tue, 29 Dec 2015)
Log Message:
-----------
sync from github
Modified Paths:
--------------
trunk/fb-contrib/.classpath
trunk/fb-contrib/build.xml
trunk/fb-contrib/etc/bugrank.txt
trunk/fb-contrib/etc/findbugs.xml
trunk/fb-contrib/etc/messages.xml
trunk/fb-contrib/htdocs/index.shtml
trunk/fb-contrib/htdocs/repository.html
trunk/fb-contrib/samples/ACEM_Sample.java
trunk/fb-contrib/samples/MDM_Sample.java
trunk/fb-contrib/samples/OCP_Sample.java
trunk/fb-contrib/samples/PRMC_Sample.java
trunk/fb-contrib/samples/SPP_Sample.java
trunk/fb-contrib/samples/UMTP_Sample.java
trunk/fb-contrib/samples/UTAO_Sample.java
trunk/fb-contrib/samples/samples.fbp
trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/AbstractClassEmptyMethods.java
trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/BloatedAssignmentScope.java
trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/DeletingWhileIterating.java
trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/DubiousListCollection.java
trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/FieldCouldBeLocal.java
trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/HttpClientProblems.java
trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/ImmatureClass.java
trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/InefficientStringBuffering.java
trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/JAXRSIssues.java
trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/LoggerOddities.java
trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/ModifyingUnmodifiableCollection.java
trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/MoreDumbMethods.java
trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/NeedlessMemberCollectionSynchronization.java
trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/NonOwnedSynchronization.java
trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/NonRecycleableTaglibs.java
trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/OverlyPermissiveMethod.java
trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/PossibleMemoryBloat.java
trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/PossiblyRedundantMethodCalls.java
trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/SQLInLoop.java
trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/SillynessPotPourri.java
trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/UnboundMethodTemplateParameter.java
trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/UnitTestAssertionOddities.java
trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/UseSplit.java
trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/UseVarArgs.java
trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/WriteOnlyCollection.java
trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/utils/BugType.java
trunk/fb-contrib/yank.xls
Added Paths:
-----------
trunk/fb-contrib/samples/JPAI_Sample.java
trunk/fb-contrib/samples/SEO_Sample.java
trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/JPAIssues.java
trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/SuboptimalExpressionOrder.java
trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/utils/QMethod.java
Modified: trunk/fb-contrib/.classpath
===================================================================
--- trunk/fb-contrib/.classpath 2015-12-12 17:33:56 UTC (rev 1786)
+++ trunk/fb-contrib/.classpath 2015-12-29 21:37:08 UTC (rev 1787)
@@ -27,5 +27,7 @@
<classpathentry kind="lib" path="lib/junit-4.12.jar"/>
<classpathentry kind="lib" path="lib/testng-6.9.6.jar"/>
<classpathentry kind="lib" path="lib/jsr311-api-1.1.1.jar" sourcepath="lib/sources/jsr311-api-1.1.1-sources.jar"/>
+ <classpathentry kind="lib" path="lib/spring-tx-4.2.3.RELEASE.jar"/>
+ <classpathentry kind="lib" path="lib/javax.persistence-2.1.1.jar"/>
<classpathentry kind="output" path="target/classes/main"/>
</classpath>
Modified: trunk/fb-contrib/build.xml
===================================================================
--- trunk/fb-contrib/build.xml 2015-12-12 17:33:56 UTC (rev 1786)
+++ trunk/fb-contrib/build.xml 2015-12-29 21:37:08 UTC (rev 1787)
@@ -101,6 +101,8 @@
<pathelement location="${lib.dir}/httpclient-${httpclient.version}.jar" />
<pathelement location="${lib.dir}/commons-codec-${commons-codec.version}.jar" />
<pathelement location="${lib.dir}/jsr311-api-${jsr311-api.version}.jar" />
+ <pathelement location="${lib.dir}/spring-tx-${spring-tx.version}.jar" />
+ <pathelement location="${lib.dir}/javax.persistence-${javax.persistence.version}.jar" />
</path>
</target>
Modified: trunk/fb-contrib/etc/bugrank.txt
===================================================================
--- trunk/fb-contrib/etc/bugrank.txt 2015-12-12 17:33:56 UTC (rev 1786)
+++ trunk/fb-contrib/etc/bugrank.txt 2015-12-29 21:37:08 UTC (rev 1787)
@@ -71,6 +71,13 @@
+0 BugPattern ISB_TOSTRING_APPENDING
+0 BugPattern ITC_INHERITANCE_TYPE_CHECKING
+2 BugPattern ITU_INAPPROPRIATE_TOSTRING_USE
++1 BugPattern JPAI_HC_EQUALS_ON_MANAGED_ENTITY
++1 BugPattern JPAI_IGNORED_MERGE_RESULT
++1 BugPattern JPAI_INEFFICIENT_EAGER_FETCH
++0 BugPattern JPAI_NON_PROXIED_TRANSACTION_CALL
++0 BugPattern JPAI_NON_SPECIFIED_TRANSACTION_EXCEPTION_HANDLING
++0 BugPattern JPAI_TRANSACTION_ON_NON_PUBLIC_METHOD
++0 BugPattern JPAI_UNNECESSARY_TRANSACTION_EXCEPTION_HANDLING
+0 BugPattern JVR_JDBC_VENDOR_RELIANCE
+0 BugPattern JXI_GET_ENDPOINT_CONSUMES_CONTENT
+0 BugPattern JXI_INVALID_CONTEXT_PARAMETER_TYPE
@@ -157,6 +164,7 @@
+0 BugPattern SCR_SLOPPY_CLASS_REFLECTION
+0 BugPattern SCSS_SUSPICIOUS_CLUSTERED_SESSION_SUPPORT
+0 BugPattern SEC_SIDE_EFFECT_CONSTRUCTOR
++0 BugPattern SEO_SUBOPTIMAL_EXPRESSION_ORDER
+0 BugPattern SGSU_SUSPICIOUS_GETTER_SETTER_USE
+0 BugPattern SG_SLUGGISH_GUI
+0 BugPattern SIL_SQL_IN_LOOP
@@ -179,6 +187,7 @@
+0 BugPattern SPP_NON_USEFUL_TOSTRING
+0 BugPattern SPP_NO_CHAR_SB_CTOR
+0 BugPattern SPP_NULL_BEFORE_INSTANCEOF
++0 BugPattern SPP_NULL_CHECK_ON_OPTIONAL
+0 BugPattern SPP_SERIALVER_SHOULD_BE_PRIVATE
+0 BugPattern SPP_STATIC_FORMAT_STRING
+0 BugPattern SPP_STRINGBUFFER_WITH_EMPTY_STRING
Modified: trunk/fb-contrib/etc/findbugs.xml
===================================================================
--- trunk/fb-contrib/etc/findbugs.xml 2015-12-12 17:33:56 UTC (rev 1786)
+++ trunk/fb-contrib/etc/findbugs.xml 2015-12-29 21:37:08 UTC (rev 1787)
@@ -147,7 +147,7 @@
<Detector class="com.mebigfatguy.fbcontrib.detect.SuspiciousComparatorReturnValues" speed="fast" reports="SCRV_SUSPICIOUS_COMPARATOR_RETURN_VALUES" />
<Detector class="com.mebigfatguy.fbcontrib.detect.SillynessPotPourri" speed="fast"
- reports="SPP_NEGATIVE_BITSET_ITEM,SPP_INTERN_ON_CONSTANT,SPP_NO_CHAR_SB_CTOR,SPP_USE_MATH_CONSTANT,SPP_STUTTERED_ASSIGNMENT,SPP_USE_ISNAN,SPP_USE_BIGDECIMAL_STRING_CTOR,SPP_STRINGBUFFER_WITH_EMPTY_STRING,SPP_EQUALS_ON_ENUM,SPP_INVALID_BOOLEAN_NULL_CHECK,SPP_USE_CHARAT,SPP_USELESS_TERNARY,SPP_SUSPECT_STRING_TEST,SPP_USE_STRINGBUILDER_LENGTH,SPP_INVALID_CALENDAR_COMPARE,SPP_USE_CONTAINSKEY,SPP_USE_ISEMPTY,SPP_USE_GETPROPERTY,SPP_USELESS_CASING,SPP_SERIALVER_SHOULD_BE_PRIVATE,SPP_NON_ARRAY_PARM,SPP_EMPTY_CASING,SPP_TEMPORARY_TRIM,SPP_STRINGBUILDER_IS_MUTABLE,SPP_USE_GET0,SPP_DOUBLE_APPENDED_LITERALS,SPP_NULL_BEFORE_INSTANCEOF,SPP_NON_USEFUL_TOSTRING,SPP_TOSTRING_ON_STRING,SPP_EQUALS_ON_STRING_BUILDER,SPP_CONVERSION_OF_STRING_LITERAL,SPP_STATIC_FORMAT_STRING" />
+ reports="SPP_NEGATIVE_BITSET_ITEM,SPP_INTERN_ON_CONSTANT,SPP_NO_CHAR_SB_CTOR,SPP_USE_MATH_CONSTANT,SPP_STUTTERED_ASSIGNMENT,SPP_USE_ISNAN,SPP_USE_BIGDECIMAL_STRING_CTOR,SPP_STRINGBUFFER_WITH_EMPTY_STRING,SPP_EQUALS_ON_ENUM,SPP_INVALID_BOOLEAN_NULL_CHECK,SPP_USE_CHARAT,SPP_USELESS_TERNARY,SPP_SUSPECT_STRING_TEST,SPP_USE_STRINGBUILDER_LENGTH,SPP_INVALID_CALENDAR_COMPARE,SPP_USE_CONTAINSKEY,SPP_USE_ISEMPTY,SPP_USE_GETPROPERTY,SPP_USELESS_CASING,SPP_SERIALVER_SHOULD_BE_PRIVATE,SPP_NON_ARRAY_PARM,SPP_EMPTY_CASING,SPP_TEMPORARY_TRIM,SPP_STRINGBUILDER_IS_MUTABLE,SPP_USE_GET0,SPP_DOUBLE_APPENDED_LITERALS,SPP_NULL_BEFORE_INSTANCEOF,SPP_NON_USEFUL_TOSTRING,SPP_TOSTRING_ON_STRING,SPP_EQUALS_ON_STRING_BUILDER,SPP_CONVERSION_OF_STRING_LITERAL,SPP_STATIC_FORMAT_STRING,SPP_NULL_CHECK_ON_OPTIONAL" />
<Detector class="com.mebigfatguy.fbcontrib.detect.SpoiledChildInterfaceImplementor" speed="fast" reports="SCII_SPOILED_CHILD_INTERFACE_IMPLEMENTOR" />
@@ -292,6 +292,11 @@
<Detector class="com.mebigfatguy.fbcontrib.detect.JAXRSIssues" speed="fast" reports="JXI_GET_ENDPOINT_CONSUMES_CONTENT,JXI_INVALID_CONTEXT_PARAMETER_TYPE,JXI_PARM_PARAM_NOT_FOUND_IN_PATH,JXI_UNDEFINED_PARAMETER_SOURCE_IN_ENDPOINT" />
<!-- COMMENT OUT FOR POINT RELEASE -->
+
+ <Detector class="com.mebigfatguy.fbcontrib.detect.JPAIssues" speed="fast" reports="JPAI_TRANSACTION_ON_NON_PUBLIC_METHOD,JPAI_HC_EQUALS_ON_MANAGED_ENTITY,JPAI_NON_PROXIED_TRANSACTION_CALL,JPAI_INEFFICIENT_EAGER_FETCH,JPAI_IGNORED_MERGE_RESULT,JPAI_NON_SPECIFIED_TRANSACTION_EXCEPTION_HANDLING,JPAI_UNNECESSARY_TRANSACTION_EXCEPTION_HANDLING"/>
+
+ <Detector class="com.mebigfatguy.fbcontrib.detect.SuboptimalExpressionOrder" speed="fast" reports="SEO_SUBOPTIMAL_EXPRESSION_ORDER"/>
+
<!-- COMMENT OUT FOR POINT RELEASE -->
<!-- BugPattern -->
@@ -403,6 +408,7 @@
<BugPattern abbrev="SPP" type="SPP_EQUALS_ON_STRING_BUILDER" category="CORRECTNESS" />
<BugPattern abbrev="SPP" type="SPP_CONVERSION_OF_STRING_LITERAL" category="CORRECTNESS" />
<BugPattern abbrev="SPP" type="SPP_STATIC_FORMAT_STRING" category="CORRECTNESS" />
+ <BugPattern abbrev="SPP" type="SPP_NULL_CHECK_ON_OPTIONAL" category="CORRECTNESS" />
<BugPattern abbrev="BAS" type="BAS_BLOATED_ASSIGNMENT_SCOPE" category="PERFORMANCE" />
<BugPattern abbrev="SCII" type="SCII_SPOILED_CHILD_INTERFACE_IMPLEMENTOR" category="STYLE" />
<BugPattern abbrev="DWI" type="DWI_DELETING_WHILE_ITERATING" category="CORRECTNESS" />
@@ -541,5 +547,13 @@
<BugPattern abbrev="JXI" type="JXI_INVALID_CONTEXT_PARAMETER_TYPE" category="CORRECTNESS" />
<BugPattern abbrev="JXI" type="JXI_PARM_PARAM_NOT_FOUND_IN_PATH" category="CORRECTNESS" />
<BugPattern abbrev="JXI" type="JXI_UNDEFINED_PARAMETER_SOURCE_IN_ENDPOINT" category="CORRECTNESS" />
+ <BugPattern abbrev="JPAI" type="JPAI_TRANSACTION_ON_NON_PUBLIC_METHOD" category="CORRECTNESS" experimental="true"/>
+ <BugPattern abbrev="JPAI" type="JPAI_HC_EQUALS_ON_MANAGED_ENTITY" category="CORRECTNESS" experimental="true"/>
+ <BugPattern abbrev="JPAI" type="JPAI_NON_PROXIED_TRANSACTION_CALL" category="CORRECTNESS" experimental="true"/>
+ <BugPattern abbrev="JPAI" type="JPAI_INEFFICIENT_EAGER_FETCH" category="CORRECTNESS" experimental="true"/>
+ <BugPattern abbrev="JPAI" type="JPAI_IGNORED_MERGE_RESULT" category="CORRECTNESS" experimental="true"/>
+ <BugPattern abbrev="JPAI" type="JPAI_NON_SPECIFIED_TRANSACTION_EXCEPTION_HANDLING" category="CORRECTNESS" experimental="true"/>
+ <BugPattern abbrev="JPAI" type="JPAI_UNNECESSARY_TRANSACTION_EXCEPTION_HANDLING" category="CORRECTNESS" experimental="true"/>
+ <BugPattern abbrev="SEO" type="SEO_SUBOPTIMAL_EXPRESSION_ORDER" category="PERFORMANCE" experimental="true"/>
</FindbugsPlugin>
Modified: trunk/fb-contrib/etc/messages.xml
===================================================================
--- trunk/fb-contrib/etc/messages.xml 2015-12-12 17:33:56 UTC (rev 1786)
+++ trunk/fb-contrib/etc/messages.xml 2015-12-29 21:37:08 UTC (rev 1787)
@@ -1547,9 +1547,32 @@
<Details>
<![CDATA[
<p>Looks for problems with the use of the JAX-RS specification.</p>
+ <p>It is a fast detector</p>
]]>
</Details>
</Detector>
+
+ <Detector class="com.mebigfatguy.fbcontrib.detect.JPAIssues">
+ <Details>
+ <![CDATA[
+ <p>Looks for problems with the use of the JPA specification, including spring's
+ support of JPA</p>
+ <p>It is a fast detector</p>
+ ]]>
+ </Details>
+ </Detector>
+
+ <Detector class="com.mebigfatguy.fbcontrib.detect.SuboptimalExpressionOrder">
+ <Details>
+ <![CDATA[
+ <p>Looks for conditional expressions that are a combination of simple local variable (in)equalities
+ and tests on the results of method calls where the method calls are done first. By placing the simple
+ conditions first you may elminate costly calls in certain cases. This assumes that the method calls
+ do not have side effects that should happen always.</p>
+ <p>It is a fast detector</p>
+ ]]>
+ </Details>
+ </Detector>
<Detector class="com.mebigfatguy.fbcontrib.debug.OCSDebugger">
<Details></Details>
@@ -3245,6 +3268,20 @@
]]>
</Details>
</BugPattern>
+
+ <BugPattern type="SPP_NULL_CHECK_ON_OPTIONAL">
+ <ShortDescription>Method checks an Optional reference for null or non nullness</ShortDescription>
+ <LongDescription>Method {1} checks an Optional reference for null or non nullness</LongDescription>
+ <Details>
+ <![CDATA[
+ This method uses an Optional variable, and checks the reference value for whether it is null or not null.
+ Since the point of the Optional class is to avoid 'the null reference problem', having code that needs to
+ check the reference itself is self defeating, and therefore makes the use of the Optional variable useless.
+ You should never use a variable of type Optional that has a value of null, and so there should be no need to
+ check for it.
+ ]]>
+ </Details>
+ </BugPattern>
<BugPattern type="BAS_BLOATED_ASSIGNMENT_SCOPE">
<ShortDescription>Method assigns a variable in a larger scope than is needed</ShortDescription>
@@ -5103,6 +5140,112 @@
]]>
</Details>
</BugPattern>
+
+ <BugPattern type="JPAI_TRANSACTION_ON_NON_PUBLIC_METHOD">
+ <ShortDescription>Method has a Spring @Transactional annotation on it, but is non-public</ShortDescription>
+ <LongDescription>Method {1} has a Spring @Transactional annotation on it, but is non-public</LongDescription>
+ <Details>
+ <![CDATA[
+ <p>This method specifies a Spring @Transactional annotation but the method is defined as being non public.
+ Spring only creates transactional boundaries on methods that are public, and so this annotation not doing
+ anything for this method. Make the method public, or place the annotation on a more appropriate method.
+ ]]>
+ </Details>
+ </BugPattern>
+
+ <BugPattern type="JPAI_HC_EQUALS_ON_MANAGED_ENTITY">
+ <ShortDescription>JPA Entity with Generated @Id defined with hashCode/equals</ShortDescription>
+ <LongDescription>JPA Entity {0} with Generated @Id defined with hashCode/equals</LongDescription>
+ <Details>
+ <![CDATA[
+ <p>This class is defined to be a JPA Entity, and has an @Id field that is generated by the JPA provider.
+ Since you do not control when that Id is created directly, it is risky to implement hashCode/equals for this
+ class, and especially for use with Collections, as the data behind the algorithms will not be immutable, and
+ thus cause problems when those fields change, and the object is in the collection. It is usually safer
+ to not define hashCode and equals for entity objects, but treat them as objects for IdentityHashSet/Maps instead.
+ ]]>
+ </Details>
+ </BugPattern>
+
+ <BugPattern type="JPAI_NON_PROXIED_TRANSACTION_CALL">
+ <ShortDescription>Method annotated with @Transactional is called from a non Spring proxy</ShortDescription>
+ <LongDescription>Method {1} annotated with @Transactional is called from a non Spring proxy</LongDescription>
+ <Details>
+ <![CDATA[
+ <p>This method call is to a method that has a @Transactional annotation on it. However since this call is from the
+ same class, it is not going through any Spring proxy, and thus the transactional quality of this method is completely
+ lost. @Transactional method must always be called through a Spring bean that is autowired.</p>
+ ]]>
+ </Details>
+ </BugPattern>
+
+ <BugPattern type="JPAI_INEFFICIENT_EAGER_FETCH">
+ <ShortDescription>OneToMany join specifies 1+n EAGER join</ShortDescription>
+ <LongDescription>OneToMany join specifies 1+n EAGER join</LongDescription>
+ <Details>
+ <![CDATA[
+ <p>This JPA entity specifies a @OneToMany join with a fetch type of EAGER. By Default EAGER joins perform
+ select operations on each element returned from the original query in sequence, thus producing 1 + n queries.
+ If you are going to use EAGER joins, it is wise to specify a Join type by using @Fetch annotations in
+ Hibernate or @JoinFetch/@BatchFetch annotations (or hints) in EclipseLink, for example. Even so, These
+ annotations may only apply in limited cases, such as in the use of find.</p>
+ ]]>
+ </Details>
+ </BugPattern>
+
+ <BugPattern type="JPAI_IGNORED_MERGE_RESULT">
+ <ShortDescription>Method ignores the return value of EntityManager.merge</ShortDescription>
+ <LongDescription>Method {1} ignores the return value of EntityManager.merge</LongDescription>
+ <Details>
+ <![CDATA[
+ <p>This method calls EntityManager.merge, and throws away the resultant value. This result is the
+ managed entity version of the potentially unmanaged object that was passed to merge. You should use
+ the returned managed entity for any further use.</p>
+ ]]>
+ </Details>
+ </BugPattern>
+
+ <BugPattern type="JPAI_NON_SPECIFIED_TRANSACTION_EXCEPTION_HANDLING">
+ <ShortDescription>Method does not specify how to handle transaction when exception is thrown</ShortDescription>
+ <LongDescription>Method {1} does not specify how to handle transaction when exception is thrown</LongDescription>
+ <Details>
+ <![CDATA[
+ <p>This method declares that it throws one or more non-runtime exceptions. It also is annotated with a
+ @Transactional annotation but fails to describe whether to rollback the transaction or not based on this
+ thrown exception. use 'rollbackFor' or 'noRollbackFor' attributes of the Transactional annotation to
+ document this.</p>
+ ]]>
+ </Details>
+ </BugPattern>
+
+ <BugPattern type="JPAI_UNNECESSARY_TRANSACTION_EXCEPTION_HANDLING">
+ <ShortDescription>Method declares handling a transactional exception that won't be thrown</ShortDescription>
+ <LongDescription>Method {1} declares handling a transactional exception that won't be thrown</LongDescription>
+ <Details>
+ <![CDATA[
+ <p>This method declares that it either rolls back or does not rollback a transaction based on an
+ expected transaction being thrown. However this exception can not be thrown from this method, and so the
+ annotation is useless.</p>
+ ]]>
+ </Details>
+ </BugPattern>
+
+ <BugPattern type="SEO_SUBOPTIMAL_EXPRESSION_ORDER">
+ <ShortDescription>Method orders expressions in a conditional in a sub optimal way</ShortDescription>
+ <LongDescription>Method {1} orders expressions in a conditional in a sub optimal way</LongDescription>
+ <Details>
+ <![CDATA[
+ <p>This method builds a conditional for an if or while statement where the expressions contain both simple
+ local variable comparisons, as well as comparisons on method calls. The expression orders these so that the method calls
+ come before the simple local variable call comparisons. This causes method calls to be executed in conditions when they
+ do not need to be, and thus potentially causes a lot of code to be executed for nothing. By ordering the expressions so that
+ the simple conditions contains local variable conditions are first, you eliminate this waste. This assumes that the method
+ calls do not have side effects. If the method do have side effects, it is probably a better idea to pull these calls out of
+ the condition and execute them first, assigning a value to a local variable. In this way you give a hint that the call may have
+ side effects.</p>
+ ]]>
+ </Details>
+ </BugPattern>
<!-- BugCode -->
@@ -5234,4 +5377,6 @@
<BugCode abbrev="CRF">Conflating Resources And Files</BugCode>
<BugCode abbrev="IMC">Immature Class</BugCode>
<BugCode abbrev="JXI">JAX-RS Issues</BugCode>
+ <BugCode abbrev="JPAI">JPA Issues</BugCode>
+ <BugCode abbrev="SEO">Suboptimal Expression Order</BugCode>
</MessageCollection>
Modified: trunk/fb-contrib/htdocs/index.shtml
===================================================================
--- trunk/fb-contrib/htdocs/index.shtml 2015-12-12 17:33:56 UTC (rev 1786)
+++ trunk/fb-contrib/htdocs/index.shtml 2015-12-29 21:37:08 UTC (rev 1787)
@@ -68,7 +68,7 @@
</li>
</ul>
</p>
- <p style="font-weight: bold;">The latest version of fb-contrib is 6.4.0 available for download
+ <p style="font-weight: bold;">The latest version of fb-contrib is 6.4.1 available for download
<a href="http://search.maven.org/#search%7Cga%7C1%7Ca%3A%22fb-contrib%22">here</a>.</p>
<p style="font-weight: bold;">This version requires FindBugs 3.0.1 or better</p>
<p style="font-weight: bold;">Please note that active development for this project is now done on
@@ -86,6 +86,17 @@
same kind of exception, and throw the same exception always. These blocks can
be coalesced into one.
</li>
+ <li><b>[JPAI] JPA Issues</b><br/>
+ Looks for various issues around the use of the Java Persistence API (JPA), including
+ with use with spring-tx.
+ </li>
+ <li><b>[SEO] Suboptimal Expression Order</b><br/>
+ Looks for conditional expressions where both simple local variable (in)equalities are used
+ along with method calls, where the method calls are done first. By placing the simple local
+ checks first, you eliminate potentially costly calls in some cases. This assumes that the methods
+ called won't have side-effects that are desired. At present it only looks for simple sequences
+ of 'and' based conditions.
+ </li>
</ul>
</div>
<hr/>
Modified: trunk/fb-contrib/htdocs/repository.html
===================================================================
--- trunk/fb-contrib/htdocs/repository.html 2015-12-12 17:33:56 UTC (rev 1786)
+++ trunk/fb-contrib/htdocs/repository.html 2015-12-29 21:37:08 UTC (rev 1787)
@@ -22,7 +22,7 @@
<table style="margin-left: 40px; background-color: #A0A0FF; padding: 20px; border-width: 1px; border-style: outset; border-color: #000000;">
<tr><td><b>GroupId:</b></td><td>com.mebigfatguy.fb-contrib</td></tr>
<tr><td><b>ArtifactId:</b></td><td>fb-contrib</td></tr>
- <tr><td><b>Version:</b></td><td>6.4.0</td></tr>
+ <tr><td><b>Version:</b></td><td>6.4.1</td></tr>
</table>
</div>
Modified: trunk/fb-contrib/samples/ACEM_Sample.java
===================================================================
--- trunk/fb-contrib/samples/ACEM_Sample.java 2015-12-12 17:33:56 UTC (rev 1786)
+++ trunk/fb-contrib/samples/ACEM_Sample.java 2015-12-29 21:37:08 UTC (rev 1787)
@@ -1,9 +1,19 @@
-public abstract class ACEM_Sample {
+public abstract class ACEM_Sample implements Foo {
public void test() {
}
public int test1() {
throw new UnsupportedOperationException("Not implemented");
}
+
+ @Override
+ public void doFPFoo() {
+ }
+
+
+}
+
+interface Foo {
+ void doFPFoo();
}
\ No newline at end of file
Added: trunk/fb-contrib/samples/JPAI_Sample.java
===================================================================
--- trunk/fb-contrib/samples/JPAI_Sample.java (rev 0)
+++ trunk/fb-contrib/samples/JPAI_Sample.java 2015-12-29 21:37:08 UTC (rev 1787)
@@ -0,0 +1,145 @@
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.EntityManager;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToMany;
+import javax.persistence.SequenceGenerator;
+import javax.persistence.Table;
+
+import org.springframework.transaction.annotation.Transactional;
+
+public class JPAI_Sample {
+
+ EntityManager em;
+
+ @Transactional
+ private void writeData() {
+ }
+
+ @Transactional
+ public void writeGoodData() {
+ }
+
+ private void badWrite() {
+ writeGoodData();
+ }
+
+ public void ignoreMergeResult(MyEntity e, SubEntity s) {
+
+ em.merge(e);
+ em.merge(s);
+
+ List<SubEntity> ss = new ArrayList<SubEntity>();
+ ss.add(s);
+ e.setSubEntities(ss);
+
+ em.flush();
+ }
+
+ @Transactional
+ public void noRollbacks(MyEntity e) throws IOException {
+
+ }
+
+ @Transactional(rollbackFor = { SQLException.class, CloneNotSupportedException.class }, noRollbackFor = IOException.class)
+ public void noDeclaredRollbackExceptions() {
+ }
+
+ @Transactional(rollbackFor = SQLException.class, noRollbackFor = IOException.class)
+ public void fpDefinedRollBack(MyEntity e) throws SQLException, FileNotFoundException {
+ }
+
+ @Transactional(readOnly = true)
+ public void fpReadOnlyExceptions(MyEntity e) throws IOException {
+ }
+
+ @Entity
+ @Table(name = "MY_ENTITY")
+ public static class MyEntity {
+
+ private Integer id;
+ private List<SubEntity> subEntities;
+
+ @Id
+ @SequenceGenerator(name = "MY_ENTITY_SEQ", sequenceName = "MY_ENTITY_SEQ", allocationSize = 100)
+ @GeneratedValue(generator = "MY_ENTITY_SEQ")
+ @Column(name = "ID", nullable = false, unique = true)
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "myEntity", targetEntity = MyEntity.class)
+ public List<SubEntity> getSubEntities() {
+ return subEntities;
+ }
+
+ public void setSubEntities(List<SubEntity> subEntities) {
+ this.subEntities = subEntities;
+ }
+
+ @Override
+ public int hashCode() {
+ return id.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof MyEntity)) {
+ return false;
+ }
+
+ MyEntity that = (MyEntity) o;
+ if (id == null) {
+ return that.id == null;
+ }
+
+ return id.equals(that.id);
+ }
+ }
+
+ @Entity
+ @Table(name = "SUB_ENTITY")
+ public static class SubEntity {
+
+ public Integer subId;
+ public MyEntity myEntity;
+
+ @Id
+ @SequenceGenerator(name = "SUB_ENTITY_SEQ", sequenceName = "SUB_ENTITY_SEQ", allocationSize = 100)
+ @GeneratedValue(generator = "SUB_ENTITY_SEQ")
+ @Column(name = "SUB_ID", nullable = false, unique = true)
+ public Integer getSubId() {
+ return subId;
+ }
+
+ public void setSubId(Integer subId) {
+ this.subId = subId;
+ }
+
+ @JoinColumn(name = "ID", referencedColumnName = "ID", nullable = false)
+ @ManyToOne(fetch = FetchType.EAGER, targetEntity = MyEntity.class)
+ public MyEntity getMyEntity() {
+ return myEntity;
+ }
+
+ public void setMyEntity(MyEntity myEntity) {
+ this.myEntity = myEntity;
+ }
+
+ }
+}
Property changes on: trunk/fb-contrib/samples/JPAI_Sample.java
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Modified: trunk/fb-contrib/samples/MDM_Sample.java
===================================================================
--- trunk/fb-contrib/samples/MDM_Sample.java 2015-12-12 17:33:56 UTC (rev 1786)
+++ trunk/fb-contrib/samples/MDM_Sample.java 2015-12-29 21:37:08 UTC (rev 1787)
@@ -12,6 +12,9 @@
import javax.net.ssl.SSLServerSocketFactory;
public class MDM_Sample implements Runnable {
+ private ReentrantLock myLock;
+
+
public MDM_Sample() throws Exception {
boolean b;
@@ -103,4 +106,8 @@
private static void touch(Object o) {
}
+
+ private void fpAssertReentrantLock() {
+ assert myLock.isHeldByCurrentThread();
+ }
}
Modified: trunk/fb-contrib/samples/OCP_Sample.java
===================================================================
--- trunk/fb-contrib/samples/OCP_Sample.java 2015-12-12 17:33:56 UTC (rev 1786)
+++ trunk/fb-contrib/samples/OCP_Sample.java 2015-12-29 21:37:08 UTC (rev 1787)
@@ -165,6 +165,7 @@
}
class fpOverride {
+ @SuppressWarnings("deprecation")
public static final Comparator<Date> COMPARATOR = new Comparator<Date>() {
@Override // no tag, override
Modified: trunk/fb-contrib/samples/PRMC_Sample.java
===================================================================
--- trunk/fb-contrib/samples/PRMC_Sample.java 2015-12-12 17:33:56 UTC (rev 1786)
+++ trunk/fb-contrib/samples/PRMC_Sample.java 2015-12-29 21:37:08 UTC (rev 1787)
@@ -15,6 +15,8 @@
private static PRMC_Sample SAMPLE1;
private static PRMC_Sample SAMPLE2;
String data;
+ String[] array1;
+ String[] array2;
public boolean test1(Calendar c) {
Date d = c.getTime();
@@ -149,4 +151,13 @@
return sb.toString();
}
}
-}
+
+ class SFIssue71 {
+ protected String[] inc = new String[0];
+ protected String[] dec = new String[0];
+
+ public void fplog() {
+ System.out.println(Arrays.toString(inc));
+ System.out.println(Arrays.toString(dec));
+ }
+ }}
Added: trunk/fb-contrib/samples/SEO_Sample.java
===================================================================
--- trunk/fb-contrib/samples/SEO_Sample.java (rev 0)
+++ trunk/fb-contrib/samples/SEO_Sample.java 2015-12-29 21:37:08 UTC (rev 1787)
@@ -0,0 +1,31 @@
+import java.util.Random;
+
+public class SEO_Sample {
+
+ public void seo() {
+ int a = calcA();
+ int b = calcB();
+
+ System.out.println(a + b);
+
+ if (hasC() && (a == 0) && (b > 3)) {
+ System.out.println(a - b);
+ }
+ }
+
+
+ private int calcA() {
+ Random r = new Random();
+ return r.nextInt(10);
+ }
+
+ private int calcB() {
+ Random r = new Random();
+ return r.nextInt(10);
+ }
+
+ private boolean hasC() {
+ Random r = new Random();
+ return r.nextBoolean();
+ }
+}
Property changes on: trunk/fb-contrib/samples/SEO_Sample.java
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Modified: trunk/fb-contrib/samples/SPP_Sample.java
===================================================================
--- trunk/fb-contrib/samples/SPP_Sample.java 2015-12-12 17:33:56 UTC (rev 1786)
+++ trunk/fb-contrib/samples/SPP_Sample.java 2015-12-29 21:37:08 UTC (rev 1787)
@@ -17,6 +17,8 @@
import java.util.Set;
import java.util.StringTokenizer;
+import com.google.common.base.Optional;
+
@SuppressWarnings("all")
public class SPP_Sample implements Serializable {
public static final long serialVersionUID = -2766574418713802220L;
@@ -367,6 +369,14 @@
System.out.println(x.trim());
return x;
}
+
+ public String testOptional(Optional<String> o) {
+ if (o == null) {
+ return "";
+ }
+
+ return o.get();
+ }
public boolean fpNullAndInstanceOf(Object o) {
if (o != null) {
Modified: trunk/fb-contrib/samples/UMTP_Sample.java
===================================================================
--- trunk/fb-contrib/samples/UMTP_Sample.java 2015-12-12 17:33:56 UTC (rev 1786)
+++ trunk/fb-contrib/samples/UMTP_Sample.java 2015-12-29 21:37:08 UTC (rev 1787)
@@ -33,6 +33,9 @@
public <X, Y> void fpEmbedded(Map<X, Map<String, Y>> x) {
}
+
+ public <C, K extends C, V extends C> void fpParentRestriction(Iterable<K> source, Map<K, V> target) {
+ }
public Object getFoo() {
return null;
Modified: trunk/fb-contrib/samples/UTAO_Sample.java
===================================================================
--- trunk/fb-contrib/samples/UTAO_Sample.java 2015-12-12 17:33:56 UTC (rev 1786)
+++ trunk/fb-contrib/samples/UTAO_Sample.java 2015-12-29 21:37:08 UTC (rev 1787)
@@ -3,6 +3,7 @@
import junit.framework.TestCase;
+@SuppressWarnings("deprecation")
public class UTAO_Sample extends TestCase {
public void testExactDoubles(double d1, double d2) {
@@ -93,6 +94,7 @@
}
@Test
+ @SuppressWarnings("deprecation")
public void usingOldClasses(int x) {
junit.framework.Assert.assertEquals(0, x);
}
Modified: trunk/fb-contrib/samples/samples.fbp
===================================================================
--- trunk/fb-contrib/samples/samples.fbp 2015-12-12 17:33:56 UTC (rev 1786)
+++ trunk/fb-contrib/samples/samples.fbp 2015-12-29 21:37:08 UTC (rev 1787)
@@ -1,19 +1,20 @@
<Project projectName="sample">
- <Jar>./../target/classes/samples</Jar>
- <AuxClasspathEntry>./../lib/backport-util-concurrent-3.1.jar</AuxClasspathEntry>
- <AuxClasspathEntry>./../lib/commons-collections-3.2.1.jar</AuxClasspathEntry>
- <AuxClasspathEntry>./../lib/javax.servlet-api-3.1.0.jar</AuxClasspathEntry>
- <AuxClasspathEntry>./../lib/javax.servlet.jsp-api-2.3.1.jar</AuxClasspathEntry>
- <AuxClasspathEntry>./../lib/log4j-1.2.17.jar</AuxClasspathEntry>
- <AuxClasspathEntry>./../lib/commons-lang3-3.3.jar</AuxClasspathEntry>
- <AuxClasspathEntry>./../lib/slf4j-api-1.7.7.jar</AuxClasspathEntry>
- <AuxClasspathEntry>./../lib/guava-17.0.jar</AuxClasspathEntry>
- <AuxClasspathEntry>./../lib/httpclient-4.3.4.jar</AuxClasspathEntry>
- <AuxClasspathEntry>./../lib/httpclient-cache-4.3.4.jar</AuxClasspathEntry>
- <AuxClasspathEntry>./../lib/httpcore-4.3.2.jar</AuxClasspathEntry>
- <AuxClasspathEntry>./../lib/commons-codec-1.6.jar</AuxClasspathEntry>
- <AuxClasspathEntry>./../lib/junit-4.12.jar</AuxClasspathEntry>
- <AuxClasspathEntry>./../lib/testng-6.9.6.jar</AuxClasspathEntry>
+ <Jar>../target/classes/samples</Jar>
+ <AuxClasspathEntry>../lib/backport-util-concurrent-3.1.jar</AuxClasspathEntry>
+ <AuxClasspathEntry>../lib/commons-collections-3.2.1.jar</AuxClasspathEntry>
+ <AuxClasspathEntry>../lib/javax.servlet-api-3.1.0.jar</AuxClasspathEntry>
+ <AuxClasspathEntry>../lib/javax.servlet.jsp-api-2.3.1.jar</AuxClasspathEntry>
+ <AuxClasspathEntry>../lib/log4j-1.2.17.jar</AuxClasspathEntry>
+ <AuxClasspathEntry>../lib/commons-lang3-3.3.jar</AuxClasspathEntry>
+ <AuxClasspathEntry>../lib/slf4j-api-1.7.7.jar</AuxClasspathEntry>
+ <AuxClasspathEntry>../lib/guava-17.0.jar</AuxClasspathEntry>
+ <AuxClasspathEntry>../lib/httpclient-4.3.4.jar</AuxClasspathEntry>
+ <AuxClasspathEntry>../lib/httpclient-cache-4.3.4.jar</AuxClasspathEntry>
+ <AuxClasspathEntry>../lib/httpcore-4.3.2.jar</AuxClasspathEntry>
+ <AuxClasspathEntry>../lib/commons-codec-1.6.jar</AuxClasspathEntry>
+ <AuxClasspathEntry>../lib/junit-4.12.jar</AuxClasspathEntry>
+ <AuxClasspathEntry>../lib/testng-6.9.6.jar</AuxClasspathEntry>
<AuxClasspathEntry>../lib/jsr311-api-1.1.1.jar</AuxClasspathEntry>
+ <AuxClasspathEntry>../lib/javax.persistence-2.1.1.jar</AuxClasspathEntry>
<SrcDir>./.</SrcDir>
</Project>
Modified: trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/AbstractClassEmptyMethods.java
===================================================================
--- trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/AbstractClassEmptyMethods.java 2015-12-12 17:33:56 UTC (rev 1786)
+++ trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/AbstractClassEmptyMethods.java 2015-12-29 21:37:08 UTC (rev 1787)
@@ -18,6 +18,9 @@
*/
package com.mebigfatguy.fbcontrib.detect;
+import java.util.HashSet;
+import java.util.Set;
+
import org.apache.bcel.Repository;
import org.apache.bcel.classfile.Code;
import org.apache.bcel.classfile.ConstantString;
@@ -25,6 +28,7 @@
import org.apache.bcel.classfile.Method;
import com.mebigfatguy.fbcontrib.utils.BugType;
+import com.mebigfatguy.fbcontrib.utils.QMethod;
import com.mebigfatguy.fbcontrib.utils.Values;
import edu.umd.cs.findbugs.BugInstance;
@@ -53,6 +57,7 @@
}
private final BugReporter bugReporter;
+ private Set<QMethod> interfaceMethods;
private String methodName;
private State state;
@@ -74,9 +79,17 @@
*/
@Override
public void visitClassContext(ClassContext classContext) {
- JavaClass cls = classContext.getJavaClass();
- if (cls.isAbstract())
- super.visitClassContext(classContext);
+ try {
+ JavaClass cls = classContext.getJavaClass();
+ if (cls.isAbstract()) {
+ interfaceMethods = collectInterfaceMethods(cls);
+ super.visitClassContext(classContext);
+ }
+ } catch (ClassNotFoundException cnfe) {
+ bugReporter.reportMissingClass(cnfe);
+ } finally {
+ interfaceMethods = null;
+ }
}
/**
@@ -101,8 +114,10 @@
public void visitCode(Code obj) {
if (Values.CONSTRUCTOR.equals(methodName) || Values.STATIC_INITIALIZER.equals(methodName))
return;
-
- super.visitCode(obj);
+
+ if (!interfaceMethods.contains(new QMethod(methodName, getMethod().getSignature()))) {
+ super.visitCode(obj);
+ }
}
/**
@@ -169,4 +184,15 @@
state = State.SAW_DONE;
}
}
+
+ private Set<QMethod> collectInterfaceMethods(JavaClass cls) throws ClassNotFoundException {
+ Set<QMethod> methods = new HashSet<QMethod>();
+ for (JavaClass inf : cls.getAllInterfaces()) {
+ for (Method m : inf.getMethods()) {
+ methods.add(new QMethod(m.getName(), m.getSignature()));
+ }
+ }
+
+ return methods;
+ }
}
Modified: trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/BloatedAssignmentScope.java
===================================================================
--- trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/BloatedAssignmentScope.java 2015-12-12 17:33:56 UTC (rev 1786)
+++ trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/BloatedAssignmentScope.java 2015-12-29 21:37:08 UTC (rev 1787)
@@ -871,7 +871,7 @@
stores.remove(Integer.valueOf(r));
}
- if ((stores.size() > 0) && (children != null)) {
+ if ((children != null) && (stores.size() > 0)) {
for (Map.Entry<Integer, Integer> entry : stores.entrySet()) {
int childUseCount = 0;
boolean inIgnoreSB = false;
Modified: trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/DeletingWhileIterating.java
===================================================================
--- trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/DeletingWhileIterating.java 2015-12-12 17:33:56 UTC (rev 1786)
+++ trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/DeletingWhileIterating.java 2015-12-29 21:37:08 UTC (rev 1787)
@@ -39,9 +39,11 @@
import com.mebigfatguy.fbcontrib.utils.BugType;
import com.mebigfatguy.fbcontrib.utils.CodeByteUtils;
import com.mebigfatguy.fbcontrib.utils.OpcodeUtils;
+import com.mebigfatguy.fbcontrib.utils.QMethod;
import com.mebigfatguy.fbcontrib.utils.RegisterUtils;
import com.mebigfatguy.fbcontrib.utils.TernaryPatcher;
import com.mebigfatguy.fbcontrib.utils.ToString;
+import com.mebigfatguy.fbcontrib.utils.UnmodifiableSet;
import com.mebigfatguy.fbcontrib.utils.Values;
import edu.umd.cs.findbugs.BugInstance;
@@ -66,8 +68,7 @@
private static JavaClass collectionClass;
private static JavaClass iteratorClass;
private static Set<JavaClass> exceptionClasses;
- private static final Set<String> collectionMethods;
-
+
static {
try {
collectionClass = Repository.lookupClass("java/util/Collection");
@@ -84,26 +85,31 @@
} catch (ClassNotFoundException cnfe) {
// don't have a bugReporter yet, so do nothing
}
-
- collectionMethods = new HashSet<String>(3);
- collectionMethods.add("entrySet()Ljava/lang/Set;");
- collectionMethods.add("keySet()Ljava/lang/Set;");
- collectionMethods.add("values()Ljava/lang/Collection;");
}
- private static final Map<String, Integer> modifyingMethods;
+ private static final Set<QMethod> collectionMethods = UnmodifiableSet.create(
+ new QMethod("entrySet", "()Ljava/lang/Set;"),
+ new QMethod("keySet", "()Ljava/lang/Set;"),
+ new QMethod("values", "()Ljava/lang/Collection;")
+ );
+
+ private static final Map<QMethod, Integer> modifyingMethods;
static {
- Map<String, Integer> mm = new HashMap<String, Integer>();
- mm.put("add(Ljava/lang/Object;)Z", Values.ONE);
- mm.put("addAll(Ljava/util/Collection;)Z", Values.ONE);
- mm.put("addAll(ILjava/util/Collection;)Z", Values.TWO);
- mm.put("clear()V", Values.ZERO);
- mm.put("remove(I)Ljava/lang/Object;", Values.ONE);
- mm.put("removeAll(Ljava/util/Collection;)Z", Values.ONE);
- mm.put("retainAll(Ljava/util/Collection;)Z", Values.ONE);
- modifyingMethods = Collections.<String, Integer>unmodifiableMap(mm);
+ Map<QMethod, Integer> mm = new HashMap<QMethod, Integer>();
+ mm.put(new QMethod("add", "(Ljava/lang/Object;)Z"), Values.ONE);
+ mm.put(new QMethod("addAll", "(Ljava/util/Collection;)Z"), Values.ONE);
+ mm.put(new QMethod("addAll", "(ILjava/util/Collection;)Z"), Values.TWO);
+ mm.put(new QMethod("clear", "()V"), Values.ZERO);
+ mm.put(new QMethod("remove", "(I)Ljava/lang/Object;"), Values.ONE);
+ mm.put(new QMethod("removeAll", "(Ljava/util/Collection;)Z"), Values.ONE);
+ mm.put(new QMethod("retainAll", "(Ljava/util/Collection;)Z"), Values.ONE);
+ modifyingMethods = Collections.<QMethod, Integer>unmodifiableMap(mm);
}
+
+ private static final QMethod ITERATOR = new QMethod("iterator", "()Ljava/util/Iterator;");
+ private static final QMethod REMOVE = new QMethod("remove", "(Ljava/lang/Object;)Z");
+ private static final QMethod HASNEXT = new QMethod("hasNext", "()Z");
private final BugReporter bugReporter;
private OpcodeStack stack;
@@ -186,7 +192,7 @@
String className = getClassConstantOperand();
String methodName = getNameConstantOperand();
String signature = getSigConstantOperand();
- String methodInfo = methodName + signature;
+ QMethod methodInfo = new QMethod(methodName, signature);
if (isCollection(className)) {
if (collectionMethods.contains(methodInfo)) {
@@ -195,12 +201,12 @@
groupId = findCollectionGroup(itm, true);
}
- } else if ("iterator()Ljava/util/Iterator;".equals(methodInfo)) {
+ } else if (ITERATOR.equals(methodInfo)) {
if (stack.getStackDepth() > 0) {
OpcodeStack.Item itm = stack.getStackItem(0);
groupId = findCollectionGroup(itm, true);
}
- } else if ("remove(Ljava/lang/Object;)Z".equals(methodInfo)) {
+ } else if (REMOVE.equals(methodInfo)) {
if (stack.getStackDepth() > 1) {
OpcodeStack.Item itm = stack.getStackItem(1);
int id = findCollectionGroup(itm, true);
@@ -252,7 +258,7 @@
}
}
}
- } else if ("java/util/Iterator".equals(className) && "hasNext()Z".equals(methodInfo)) {
+ } else if ("java/util/Iterator".equals(className) && HASNEXT.equals(methodInfo)) {
if (stack.getStackDepth() > 0) {
OpcodeStack.Item itm = stack.getStackItem(0);
Integer id = (Integer) itm.getUserValue();
Modified: trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/DubiousListCollection.java
===================================================================
--- trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/DubiousListCollection.java 2015-12-12 17:33:56 UTC (rev 1786)
+++ trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/DubiousListCollection.java 2015-12-29 21:37:08 UTC (rev 1787)
@@ -1,26 +1,24 @@
/*
* fb-contrib - Auxiliary detectors for Java programs
* Copyright (C) 2005-2015 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.Collections;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.Map;
import java.util.Set;
@@ -31,7 +29,9 @@
import org.apache.bcel.generic.Type;
import com.mebigfatguy.fbcontrib.utils.BugType;
+import com.mebigfatguy.fbcontrib.utils.QMethod;
import com.mebigfatguy.fbcontrib.utils.ToString;
+import com.mebigfatguy.fbcontrib.utils.UnmodifiableSet;
import edu.umd.cs.findbugs.BugInstance;
import edu.umd.cs.findbugs.BugReporter;
@@ -43,47 +43,44 @@
import edu.umd.cs.findbugs.ba.XField;
/**
- * looks for fields that are implementations of java.util.List, but that are
- * used in a set-like fashion. Since lookup type operations are performed using
- * a linear search for Lists, the performance for large Lists will be poor.
- * Consideration should be made as to whether these fields should be sets. In
- * the case that order is important, consider using LinkedHashSet.
+ * looks for fields that are implementations of java.util.List, but that are used in a set-like fashion. Since lookup type operations are performed using a
+ * linear search for Lists, the performance for large Lists will be poor. Consideration should be made as to whether these fields should be sets. In the case
+ * that order is important, consider using LinkedHashSet.
*/
public class DubiousListCollection extends BytecodeScanningDetector {
- private static final Set<String> setMethods;
- private static final Set<String> listMethods;
- static {
- Set<String> sm = new HashSet<String>();
- sm.add("contains(Ljava/lang/Object;)Z");
- sm.add("containsAll(Ljava/util/Collection;)Z");
- sm.add("remove(Ljava/lang/Object;)Ljava/lang/Object;");
- sm.add("removeAll(Ljava/util/Collection;)Z");
- sm.add("retainAll(Ljava/util/Collection;)Z");
- setMethods = Collections.<String>unmodifiableSet(sm);
+ private static final Set<QMethod> setMethods = UnmodifiableSet.create(
+ //@formatter:off
+ new QMethod("contains", "(Ljava/lang/Object;)Z"),
+ new QMethod("containsAll", "(Ljava/util/Collection;)Z"),
+ new QMethod("remove", "(Ljava/lang/Object;)Ljava/lang/Object;"),
+ new QMethod("removeAll", "(Ljava/util/Collection;)Z"),
+ new QMethod("retainAll", "(Ljava/util/Collection;)Z")
+ //@formatter:on
+ );
- Set<String> lm = new HashSet<String>();
- lm.add("add(ILjava/lang/Object;)V");
- lm.add("addAll(ILjava/util/Collection;)Z");
- lm.add("lastIndexOf(Ljava/lang/Object;)I");
- lm.add("remove(I)Ljava/lang/Object;");
- lm.add("set(ILjava/lang/Object;)Ljava/lang/Object;");
- lm.add("subList(II)Ljava/util/List;");
- lm.add("listIterator()Ljava/util/ListIterator;");
- lm.add("listIterator(I)Ljava/util/ListIterator;");
- listMethods = Collections.<String>unmodifiableSet(lm);
+ private static final Set<QMethod> listMethods = UnmodifiableSet.create(
+ //@formatter:off
+ new QMethod("add", "(ILjava/lang/Object;)V"),
+ new QMethod("addAll", "(ILjava/util/Collection;)Z"),
+ new QMethod("lastIndexOf", "(Ljava/lang/Object;)I"),
+ new QMethod("remove", "(I)Ljava/lang/Object;"),
+ new QMethod("set", "(ILjava/lang/Object;)Ljava/lang/Object;"),
+ new QMethod("subList", "(II)Ljava/util/List;"),
+ new QMethod("listIterator", "()Ljava/util/ListIterator;"),
+ new QMethod("listIterator", "(I)Ljava/util/ListIterator;")
+ // Theoretically get(i) and indexOf(Object) are list Methods but are so
+ // abused, as to be meaningless
+ //@formatter:on
+ );
- // Theoretically get(i) and indexOf(Object) are list Methods but are so
- // abused, as to be meaningless
- }
-
private final BugReporter bugReporter;
private final OpcodeStack stack = new OpcodeStack();
private final Map<String, FieldInfo> fieldsReported = new HashMap<String, FieldInfo>(10);
/**
* constructs a DLC detector given the reporter to report bugs on
- *
+ *
* @param bugReporter
* the sync of bug reports
*/
@@ -93,7 +90,7 @@
/**
* overrides the visitor to accept classes that define List based fields
- *
+ *
* @param classContext
* the context object for the currently parsed class
*/
@@ -119,7 +116,7 @@
/**
* overrides the visitor to reset the opcode stack object
- *
+ *
* @param obj
* the code object for the currently parse method
*/
@@ -130,9 +127,8 @@
}
/**
- * overrides the visitor to record all method calls on List fields. If a
- * method is not a set based method, remove it from further consideration
- *
+ * overrides the visitor to record all method calls on List fields. If a method is not a set based method, remove it from further consideration
+ *
* @param seen
* the current opcode parsed.
*/
@@ -152,11 +148,12 @@
FieldInfo fi = fieldsReported.get(fieldName);
if (fi != null) {
String methodName = getNameConstantOperand();
- String methodInfo = methodName + signature;
- if (listMethods.contains(methodInfo))
+ QMethod methodInfo = new QMethod(methodName, signature);
+ if (listMethods.contains(methodInfo)) {
fieldsReported.remove(fieldName);
- else if (setMethods.contains(methodInfo))
+ } else if (setMethods.contains(methodInfo)) {
fi.addUse(getPC());
+ }
}
}
}
@@ -185,14 +182,13 @@
}
/**
- * return the field object that the current method was called on, by finding
- * the reference down in the stack based on the number of parameters
- *
+ * return the field object that the current method was called on, by finding the reference down in the stack based on the number of parameters
+ *
* @param stk
* the opcode stack where fields are stored
* @param signature
* the signature of the called method
- *
+ *
* @return the field annotation for the field whose method was executed
*/
private static XField getFieldFromStack(final OpcodeStack stk, final String signature) {
@@ -205,8 +201,7 @@
}
/**
- * implements the detector, by reporting all remaining fields that only have
- * set based access
+ * implements the detector, by reporting all remaining fields that only have set based access
*/
private void reportBugs() {
int major = getClassContext().getJavaClass().getMajor();
@@ -228,18 +223,19 @@
/**
* builds a field annotation by finding the field in the classes' field list
- *
+ *
* @param fieldName
* the field for which to built the field annotation
- *
+ *
* @return the field annotation of the specified field
*/
private FieldAnnotation getFieldAnnotation(final String fieldName) {
JavaClass cls = getClassContext().getJavaClass();
Field[] fields = cls.getFields();
for (Field f : fields) {
- if (f.getName().equals(fieldName))
+ if (f.getName().equals(fieldName)) {
return new FieldAnnotation(cls.getClassName(), fieldName, f.getSignature(), (f.getAccessFlags() & Constants.ACC_STATIC) != 0);
+ }
}
return null; // shouldn't happen
}
@@ -254,12 +250,14 @@
/**
* increments the number of times this field has a set method called on it
*
- * @param pc the current instruction offset
+ * @param pc
+ * the current instruction offset
*/
public void addUse(final int pc) {
setCnt++;
- if (slAnnotation == null)
+ if (slAnnotation == null) {
slAnnotation = SourceLineAnnotation.fromVisitedInstruction(DubiousListCollection.this.getClassContext(), DubiousListCollection.this, pc);
+ }
}
public SourceLineAnnotation getSourceLineAnnotation() {
Modified: trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/FieldCouldBeLocal.java
===================================================================
--- trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/FieldCouldBeLocal.java 2015-12-12 17:33:56 UTC (rev 1786)
+++ trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/FieldCouldBeLocal.java 2015-12-29 21:37:08 UTC (rev 1787)
@@ -42,6 +42,8 @@
import org.apache.bcel.generic.INVOKEVIRTUAL;
import org.apache.bcel.generic.Instruction;
import org.apache.bcel.generic.InstructionHandle;
+import org.apache.bcel.generic.ObjectType;
+import org.apache.bcel.generic.ReferenceType;
import com.mebigfatguy.fbcontrib.utils.BugType;
import com.mebigfatguy.fbcontrib.utils.ToString;
@@ -275,13 +277,15 @@
} else if (ins instanceof INVOKESPECIAL) {
INVOKESPECIAL is = (INVOKESPECIAL) ins;
- if (Values.CONSTRUCTOR.equals(is.getMethodName(cpg)) && (is.getClassName(cpg).startsWith(clsContext.getJavaClass().getClassName() + "$"))) {
+ ReferenceType rt = is.getReferenceType(cpg);
+ if (Values.CONSTRUCTOR.equals(is.getMethodName(cpg)) && ((rt instanceof ObjectType) && ((ObjectType) rt).getClassName().startsWith(clsContext.getJavaClass().getClassName() + "$"))) {
localizableFields.clear();
}
} else if (ins instanceof INVOKEVIRTUAL) {
INVOKEVIRTUAL is = (INVOKEVIRTUAL) ins;
- if (is.getClassName(cpg).equals(clsName)) {
+ ReferenceType rt = is.getReferenceType(cpg);
+ if ((rt instanceof ObjectType) && ((ObjectType) rt).getClassName().equals(clsName)) {
String methodDesc = is.getName(cpg) + is.getSignature(cpg);
Set<String> fields = methodFieldModifiers.get(methodDesc);
if (fields != null) {
Modified: trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/HttpClientProblems.java
===================================================================
--- trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/HttpClientProblems.java 2015-12-12 17:33:56 UTC (rev 1786)
+++ trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/HttpClientProblems.java 2015-12-29 21:37:08 UTC (rev 1787)
@@ -19,10 +19,10 @@
*/
package com.mebigfatguy.fbcontrib.detect;
-import java.util.HashSet;
import java.util.Set;
import com.mebigfatguy.fbcontrib.utils.BugType;
+import com.mebigfatguy.fbcontrib.utils.UnmodifiableSet;
import edu.umd.cs.findbugs.BugInstance;
import edu.umd.cs.findbugs.BugReporter;
@@ -34,40 +34,33 @@
*/
public class HttpClientProblems extends MissingMethodsDetector {
- private static Set<String> httpRequestClasses = new HashSet<String>();
+ private static Set<String> httpRequestClasses = UnmodifiableSet.create(
+ "org.apache.http.client.methods.HttpGet",
+ "org.apache.http.client.methods.HttpPut",
+ "org.apache.http.client.methods.HttpDelete",
+ "org.apache.http.client.methods.HttpPost",
+ "org.apache.http.client.methods.HttpPatch"
+ );
- static {
- httpRequestClasses.add("org.apache.http.client.methods.HttpGet");
- httpRequestClasses.add("org.apache.http.client.methods.HttpPut");
- httpRequestClasses.add("org.apache.http.client.methods.HttpDelete");
- httpRequestClasses.add("org.apache.http.client.methods.HttpPost");
- httpRequestClasses.add("org.apache.http.client.methods.HttpPatch");
- }
-
- private static Set<String> resetMethods = new HashSet<String>();
-
- static {
- resetMethods.add("reset");
- resetMethods.add("releaseConnection");
- }
-
+ private static Set<String> resetMethods = UnmodifiableSet.create(
+ "reset",
+ "releaseConnection"
+ );
+
// Any methods that should not be treated as a "will call a reset method"
- private static Set<String> whiteListMethods = new HashSet<String>();
+ private static Set<String> whiteListMethods = UnmodifiableSet.create(
+ "execute",
+ "fatal",
+ "error",
+ "info",
+ "debug",
+ "trace",
+ "println",
+ "print",
+ "format",
+ "append" // for when Java uses StringBuilders to append Strings
+ );
- static {
- whiteListMethods.add("execute");
- whiteListMethods.add("fatal");
- whiteListMethods.add("error");
- whiteListMethods.add("info");
- whiteListMethods.add("debug");
- whiteListMethods.add("trace");
- whiteListMethods.add("println");
- whiteListMethods.add("print");
- whiteListMethods.add("format");
- whiteListMethods.add("append"); // for when Java uses StringBuilders to
- // append Strings
- }
-
public HttpClientProblems(BugReporter bugReporter) {
super(bugReporter);
}
Modified: trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/ImmatureClass.java
===================================================================
--- trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/ImmatureClass.java 2015-12-12 17:33:56 UTC (rev 1786)
+++ trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/ImmatureClass.java 2015-12-29 21:37:08 UTC (rev 1787)
@@ -153,7 +153,7 @@
/**
* looks to see the field has a runtime visible ...
[truncated message content] |