[Fb-contrib-commit] SF.net SVN: fb-contrib:[1839] trunk/fb-contrib
Brought to you by:
dbrosius
From: <dbr...@us...> - 2018-06-01 00:35:53
|
Revision: 1839 http://sourceforge.net/p/fb-contrib/code/1839 Author: dbrosius Date: 2018-06-01 00:34:34 +0000 (Fri, 01 Jun 2018) Log Message: ----------- sync from github Modified Paths: -------------- trunk/fb-contrib/.classpath trunk/fb-contrib/build.xml trunk/fb-contrib/htdocs/index.shtml trunk/fb-contrib/htdocs/repository.html trunk/fb-contrib/pom.xml trunk/fb-contrib/src/main/java/com/mebigfatguy/fbcontrib/detect/AbstractClassEmptyMethods.java trunk/fb-contrib/src/main/java/com/mebigfatguy/fbcontrib/detect/AnnotationIssues.java trunk/fb-contrib/src/main/java/com/mebigfatguy/fbcontrib/detect/ClassEnvy.java trunk/fb-contrib/src/main/java/com/mebigfatguy/fbcontrib/detect/FunctionalInterfaceIssues.java trunk/fb-contrib/src/main/java/com/mebigfatguy/fbcontrib/detect/JPAIssues.java trunk/fb-contrib/src/main/java/com/mebigfatguy/fbcontrib/detect/LostExceptionStackTrace.java trunk/fb-contrib/src/main/java/com/mebigfatguy/fbcontrib/detect/OptionalIssues.java trunk/fb-contrib/src/main/java/com/mebigfatguy/fbcontrib/detect/PresizeCollections.java trunk/fb-contrib/src/main/java/com/mebigfatguy/fbcontrib/detect/ReflectionIssues.java trunk/fb-contrib/src/main/java/com/mebigfatguy/fbcontrib/detect/SpoiledChildInterfaceImplementor.java trunk/fb-contrib/src/main/java/com/mebigfatguy/fbcontrib/detect/SuspiciousNullGuard.java trunk/fb-contrib/src/main/java/com/mebigfatguy/fbcontrib/utils/SignatureBuilder.java trunk/fb-contrib/src/samples/java/ex/ACEM_Sample.java trunk/fb-contrib/src/samples/java/ex/AI_Sample.java trunk/fb-contrib/src/samples/java/ex/LEST_Sample.java Modified: trunk/fb-contrib/.classpath =================================================================== --- trunk/fb-contrib/.classpath 2018-05-20 22:03:10 UTC (rev 1838) +++ trunk/fb-contrib/.classpath 2018-06-01 00:34:34 UTC (rev 1839) @@ -25,7 +25,7 @@ </classpathentry> <classpathentry kind="lib" path="lib/threetenbp-1.3.2.jar"/> <classpathentry kind="lib" path="lib/commons-codec-1.10.jar"/> - <classpathentry kind="lib" path="lib/commons-collections-3.2.2.jar"/> + <classpathentry kind="lib" path="lib/commons-collections-3.2.2.jar" sourcepath="/home/dave/.m2/repository/commons-collections/commons-collections/3.2.2/commons-collections-3.2.2-sources.jar"/> <classpathentry kind="lib" path="lib/commons-lang3-3.4.jar"/> <classpathentry kind="lib" path="lib/findbugs-ant-3.0.0.jar"/> <classpathentry kind="lib" path="lib/guava-19.0.jar" sourcepath="lib/sources/guava-19.0-sources.jar"/> Modified: trunk/fb-contrib/build.xml =================================================================== --- trunk/fb-contrib/build.xml 2018-05-20 22:03:10 UTC (rev 1838) +++ trunk/fb-contrib/build.xml 2018-06-01 00:34:34 UTC (rev 1839) @@ -31,7 +31,7 @@ <property name="javac.debug" value="on" /> <property name="test_reports.dir" value="${target.dir}/reports/test"/> - <property name="fb-contrib.version" value="7.4.1" /> + <property name="fb-contrib.version" value="7.4.2" /> <property name="sonatype.dir" value="${user.home}/.fb-contrib-${fb-contrib.version}-sonatype" /> @@ -51,7 +51,7 @@ <target name="yank" xmlns:yank="antlib:com.mebigfatguy.yank" unless="no.yank"> <mkdir dir="${lib.dir}" /> - <yank:yank yankFile="${basedir}/yank.xls" destination="${lib.dir}" proxyServer="${proxy.server}" source="true" separateClassifierTypes="true" checkSHADigests="true"> + <yank:yank yankFile="${basedir}/yank.csv" destination="${lib.dir}" proxyServer="${proxy.server}" source="true" separateClassifierTypes="true" checkSHADigests="true"> <server url="http://repo1.maven.org/maven2" /> <generateVersions propertyFileName="${basedir}/version.properties" /> </yank:yank> @@ -126,8 +126,10 @@ <pathelement location="${lib.dir}/javax.servlet-api-${javax.servlet-api.version}.jar" /> <pathelement location="${lib.dir}/log4j-${log4j.version}.jar" /> <pathelement location="${lib.dir}/log4j-api-${log4j-api.version}.jar" /> - <pathelement location="${lib.dir}/commons-lang3-${commons-lang3.version}.jar" /> - <pathelement location="${lib.dir}/commons-io-${commons-io.version}.jar" /> + <pathelement location="${lib.dir}/commons-collections-${commons-collections.version}.jar" /> + <pathelement location="${lib.dir}/commons-lang3-${commons-lang3.version}.jar" /> + <pathelement location="${lib.dir}/commons-io-${commons-io.version}.jar" /> + <pathelement location="${lib.dir}/dom4j-${dom4j.version}.jar" /> <pathelement location="${lib.dir}/backport-util-concurrent-${backport-util-concurrent.version}.jar" /> <pathelement location="${lib.dir}/threetenbp-${threetenbp.version}.jar" /> <pathelement location="${lib.dir}/slf4j-api-${slf4j-api.version}.jar" /> @@ -139,7 +141,8 @@ <pathelement location="${lib.dir}/spring-beans-${spring-beans.version}.jar" /> <pathelement location="${lib.dir}/spring-context-${spring-context.version}.jar" /> <pathelement location="${lib.dir}/spring-tx-${spring-tx.version}.jar" /> - <pathelement location="${lib.dir}/javax.persistence-${javax.persistence.version}.jar" /> + <pathelement location="${lib.dir}/javax.persistence-${javax.persistence.version}.jar" /> + <pathelement location="${lib.dir}/jaxen-${jaxen.version}.jar" /> <pathelement location="${lib.dir}/mockito-core-${mockito-core.version}.jar" /> <pathelement location="${lib.dir}/hamcrest-core-${hamcrest-core.version}.jar" /> <pathelement location="${lib.dir}/jena-shaded-guava-${jena-shaded-guava.version}.jar" /> @@ -248,7 +251,7 @@ <include name="**/*.license" /> <include name="**/*.txt" /> <include name="**/*.md" /> - <include name="**/*.xls" /> + <include name="**/*.csv" /> <include name="**/*.example" /> <include name="**/*.fbp" /> </fileset> Modified: trunk/fb-contrib/htdocs/index.shtml =================================================================== --- trunk/fb-contrib/htdocs/index.shtml 2018-05-20 22:03:10 UTC (rev 1838) +++ trunk/fb-contrib/htdocs/index.shtml 2018-06-01 00:34:34 UTC (rev 1839) @@ -68,7 +68,7 @@ </li> </ul> </p> - <p style="font-weight: bold;">The latest version of fb-contrib is 7.4.1 available for download + <p style="font-weight: bold;">The latest version of fb-contrib is 7.4.2 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 Modified: trunk/fb-contrib/htdocs/repository.html =================================================================== --- trunk/fb-contrib/htdocs/repository.html 2018-05-20 22:03:10 UTC (rev 1838) +++ trunk/fb-contrib/htdocs/repository.html 2018-06-01 00:34:34 UTC (rev 1839) @@ -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>7.4.1 or 7.4.1.sb</td></tr> + <tr><td><b>Version:</b></td><td>7.4.2 or 7.4.2.sb</td></tr> </table> </div> Modified: trunk/fb-contrib/pom.xml =================================================================== --- trunk/fb-contrib/pom.xml 2018-05-20 22:03:10 UTC (rev 1838) +++ trunk/fb-contrib/pom.xml 2018-06-01 00:34:34 UTC (rev 1839) @@ -6,7 +6,7 @@ <modelVersion>4.0.0</modelVersion> <groupId>com.mebigfatguy.fb-contrib</groupId> <artifactId>fb-contrib</artifactId> - <version>7.4.1</version> + <version>7.4.2</version> <!-- TODO: Delete this and replace with enforcer plugin. This is for maven plugins only! Latest maven will through warnings. --> <prerequisites> Modified: trunk/fb-contrib/src/main/java/com/mebigfatguy/fbcontrib/detect/AbstractClassEmptyMethods.java =================================================================== --- trunk/fb-contrib/src/main/java/com/mebigfatguy/fbcontrib/detect/AbstractClassEmptyMethods.java 2018-05-20 22:03:10 UTC (rev 1838) +++ trunk/fb-contrib/src/main/java/com/mebigfatguy/fbcontrib/detect/AbstractClassEmptyMethods.java 2018-06-01 00:34:34 UTC (rev 1839) @@ -112,7 +112,12 @@ return; } - if (!interfaceMethods.contains(new QMethod(methodName, getMethod().getSignature()))) { + Method m = getMethod(); + if (m.isSynthetic()) { + return; + } + + if (!interfaceMethods.contains(new QMethod(methodName, m.getSignature()))) { super.visitCode(obj); } } Modified: trunk/fb-contrib/src/main/java/com/mebigfatguy/fbcontrib/detect/AnnotationIssues.java =================================================================== --- trunk/fb-contrib/src/main/java/com/mebigfatguy/fbcontrib/detect/AnnotationIssues.java 2018-05-20 22:03:10 UTC (rev 1838) +++ trunk/fb-contrib/src/main/java/com/mebigfatguy/fbcontrib/detect/AnnotationIssues.java 2018-06-01 00:34:34 UTC (rev 1839) @@ -18,9 +18,13 @@ */ package com.mebigfatguy.fbcontrib.detect; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; +import java.util.List; import java.util.Map; import java.util.Set; @@ -33,9 +37,12 @@ import com.mebigfatguy.fbcontrib.collect.MethodInfo; import com.mebigfatguy.fbcontrib.collect.Statistics; import com.mebigfatguy.fbcontrib.utils.BugType; +import com.mebigfatguy.fbcontrib.utils.CodeByteUtils; import com.mebigfatguy.fbcontrib.utils.FQMethod; +import com.mebigfatguy.fbcontrib.utils.OpcodeUtils; import com.mebigfatguy.fbcontrib.utils.SignatureBuilder; import com.mebigfatguy.fbcontrib.utils.StopOpcodeParsingException; +import com.mebigfatguy.fbcontrib.utils.ToString; import com.mebigfatguy.fbcontrib.utils.UnmodifiableSet; import com.mebigfatguy.fbcontrib.utils.Values; @@ -56,6 +63,13 @@ private static final String USER_NULLABLE_ANNOTATIONS = "fb-contrib.ai.annotations"; + private static final Set<String> IS_EMPTY_SIGNATURES = UnmodifiableSet.create( + // @formatter:off + new SignatureBuilder().withParamTypes(Collection.class).withReturnType(boolean.class).build(), + new SignatureBuilder().withParamTypes(Map.class).withReturnType(boolean.class).build() + // @formatter:on + ); + private static final Set<String> NULLABLE_ANNOTATIONS = new HashSet<>(); static { @@ -82,8 +96,18 @@ // @formatter:on ); - public enum NULLABLE { - TRUE + public static class AIUserValue { + + int reg; + + public AIUserValue(int reg) { + this.reg = reg; + } + + @Override + public String toString() { + return ToString.build(this); + } }; private BugReporter bugReporter; @@ -90,6 +114,7 @@ private Map<Integer, Integer> assumedNullTill; private Map<Integer, Integer> assumedNonNullTill; private Set<Integer> noAssumptionsPossible; + private List<Integer> branchTargets; private OpcodeStack stack; private boolean methodIsNullable; @@ -117,6 +142,7 @@ assumedNullTill = new HashMap<>(); assumedNonNullTill = new HashMap<>(); noAssumptionsPossible = new HashSet<>(); + branchTargets = new ArrayList<>(); super.visitClassContext(classContext); } } @@ -125,6 +151,7 @@ assumedNullTill = null; assumedNonNullTill = null; noAssumptionsPossible = null; + branchTargets = null; } } @@ -171,6 +198,7 @@ assumedNullTill.clear(); assumedNonNullTill.clear(); noAssumptionsPossible.clear(); + branchTargets.clear(); try { super.visitCode(obj); @@ -190,11 +218,23 @@ @Override public void sawOpcode(int seen) { - boolean resultIsNullable = false; + AIUserValue userValue = null; + if (OpcodeUtils.isBranch(seen) && (getBranchOffset() > 0)) { + branchTargets.add(getBranchTarget()); + Collections.sort(branchTargets); + } + + clearBranchTargets(getPC()); + convertNullToNonNull(getPC()); clearAssumptions(assumedNullTill, getPC()); clearAssumptions(assumedNonNullTill, getPC()); + if (OpcodeUtils.isBranch(seen) && (getBranchOffset() > 0)) { + branchTargets.add(getBranchTarget()); + Collections.sort(branchTargets); + } + try { switch (seen) { case ARETURN: { @@ -201,8 +241,8 @@ if (!methodIsNullable && (stack.getStackDepth() > 0)) { OpcodeStack.Item itm = stack.getStackItem(0); Integer reg = Integer.valueOf(itm.getRegisterNumber()); - methodIsNullable = !noAssumptionsPossible.contains(reg) && ((assumedNullTill.containsKey(reg) && !assumedNonNullTill.containsKey(reg)) - || isStackElementNullable(getClassName(), getMethod(), itm)); + methodIsNullable = !assumedNonNullTill.containsKey(reg) && (!noAssumptionsPossible.contains(reg) + && ((assumedNullTill.containsKey(reg)) || isStackElementNullable(getClassName(), getMethod(), itm))); if (methodIsNullable) { throw new StopOpcodeParsingException(); } @@ -234,10 +274,39 @@ } break; + case IFEQ: + if ((getBranchOffset() > 0) && (stack.getStackDepth() > 0)) { + OpcodeStack.Item itm = stack.getStackItem(0); + AIUserValue uv = (AIUserValue) itm.getUserValue(); + if ((uv != null) && (uv.reg >= 0)) { + assumedNullTill.put(uv.reg, getBranchTarget()); + } + } + break; + case INVOKESTATIC: + if (stack.getStackDepth() > 0) { + String signature = getSigConstantOperand(); + if (IS_EMPTY_SIGNATURES.contains(signature)) { + String methodName = getNameConstantOperand(); + if (methodName.equals("isEmpty")) { + OpcodeStack.Item item = stack.getStackItem(0); + int reg = item.getRegisterNumber(); + if (reg >= 0) { + userValue = new AIUserValue(reg); + break; + } + } + } + } + + // $FALL-THROUGH$ case INVOKEINTERFACE: case INVOKEVIRTUAL: { - resultIsNullable = (isMethodNullable(getClassConstantOperand(), getNameConstantOperand(), getSigConstantOperand())); + boolean resultIsNullable = (isMethodNullable(getClassConstantOperand(), getNameConstantOperand(), getSigConstantOperand())); + if (resultIsNullable) { + userValue = new AIUserValue(-1); + } break; } @@ -250,9 +319,9 @@ } } finally { stack.sawOpcode(this, seen); - if ((resultIsNullable) && (stack.getStackDepth() > 0)) { + if ((userValue != null) && (stack.getStackDepth() > 0)) { OpcodeStack.Item itm = stack.getStackItem(0); - itm.setUserValue(NULLABLE.TRUE); + itm.setUserValue(userValue); } } } @@ -269,7 +338,7 @@ } public static boolean isStackElementNullable(String className, Method method, OpcodeStack.Item itm) { - if (itm.isNull() || (itm.getUserValue() instanceof NULLABLE)) { + if (itm.isNull() || (itm.getUserValue() != null)) { MethodInfo mi = Statistics.getStatistics().getMethodStatistics(className, method.getName(), method.getSignature()); if (mi != null) { mi.setCanReturnNull(true); @@ -321,6 +390,47 @@ } } + public void convertNullToNonNull(int pc) { + for (Map.Entry<Integer, Integer> entry : assumedNullTill.entrySet()) { + if (entry.getValue().intValue() == pc) { + int lastOp = getPrevOpcode(1); + if ((lastOp == ARETURN) || (lastOp == ATHROW)) { + int nonNullTill = getNextBranchTarget(); + assumedNonNullTill.put(entry.getKey(), nonNullTill); + } else if (OpcodeUtils.isBranch(lastOp)) { + int branchOffset = CodeByteUtils.getshort(getCode().getCode(), getPC() - 2); + if (branchOffset > 0) { + assumedNonNullTill.put(entry.getKey(), getPC() + branchOffset); + } + } + } + } + } + + /** + * remove branch targets that have been passed + * + * @param pc + * the current pc + */ + public void clearBranchTargets(int pc) { + Iterator<Integer> it = branchTargets.iterator(); + while (it.hasNext()) { + int target = it.next().intValue(); + if (target <= pc) { + it.remove(); + } + } + } + + public int getNextBranchTarget() { + if (branchTargets.isEmpty()) { + return Integer.MAX_VALUE; + } + + return branchTargets.get(0); + } + public void removeAssumptions(Map<Integer, Integer> assumptionsTill) { noAssumptionsPossible.addAll(assumptionsTill.keySet()); } Modified: trunk/fb-contrib/src/main/java/com/mebigfatguy/fbcontrib/detect/ClassEnvy.java =================================================================== --- trunk/fb-contrib/src/main/java/com/mebigfatguy/fbcontrib/detect/ClassEnvy.java 2018-05-20 22:03:10 UTC (rev 1838) +++ trunk/fb-contrib/src/main/java/com/mebigfatguy/fbcontrib/detect/ClassEnvy.java 2018-06-01 00:34:34 UTC (rev 1839) @@ -347,7 +347,7 @@ private void addLineNumber(BitSet lineNumbers) { LineNumberTable lnt = getCode().getLineNumberTable(); if (lnt == null) { - lineNumbers.set(-lineNumbers.size()); + lineNumbers.set(0); } else { int line = lnt.getSourceLine(getPC()); if (line < 0) { Modified: trunk/fb-contrib/src/main/java/com/mebigfatguy/fbcontrib/detect/FunctionalInterfaceIssues.java =================================================================== --- trunk/fb-contrib/src/main/java/com/mebigfatguy/fbcontrib/detect/FunctionalInterfaceIssues.java 2018-05-20 22:03:10 UTC (rev 1838) +++ trunk/fb-contrib/src/main/java/com/mebigfatguy/fbcontrib/detect/FunctionalInterfaceIssues.java 2018-06-01 00:34:34 UTC (rev 1839) @@ -44,6 +44,7 @@ import com.mebigfatguy.fbcontrib.utils.FQMethod; import com.mebigfatguy.fbcontrib.utils.OpcodeUtils; import com.mebigfatguy.fbcontrib.utils.QMethod; +import com.mebigfatguy.fbcontrib.utils.SignatureBuilder; import com.mebigfatguy.fbcontrib.utils.SignatureUtils; import com.mebigfatguy.fbcontrib.utils.StopOpcodeParsingException; import com.mebigfatguy.fbcontrib.utils.ToString; @@ -65,14 +66,14 @@ private static final int REF_invokeStatic = 6; - private static final QMethod CONTAINS = new QMethod("contains", "(Ljava/lang/Object;)Z"); - private static final QMethod SIZE = new QMethod("size", "()I"); + private static final QMethod CONTAINS = new QMethod("contains", SignatureBuilder.SIG_OBJECT_TO_BOOLEAN); + private static final QMethod SIZE = new QMethod("size", SignatureBuilder.SIG_VOID_TO_INT); private static final FQMethod COLLECT = new FQMethod("java/util/stream/Stream", "collect", "(Ljava/util/stream/Collector;)Ljava/lang/Object;"); private static final FQMethod FILTER = new FQMethod("java/util/stream/Stream", "filter", "(Ljava/util/function/Predicate;)Ljava/util/stream/Stream;"); private static final FQMethod FINDFIRST = new FQMethod("java/util/stream/Stream", "findFirst", "()Ljava/util/Optional;"); - private static final FQMethod ISPRESENT = new FQMethod("java/util/Optional", "isPresent", "()Z"); - private static final FQMethod GET = new FQMethod("java/util/List", "get", "(I)Ljava/lang/Object;"); + private static final FQMethod ISPRESENT = new FQMethod("java/util/Optional", "isPresent", SignatureBuilder.SIG_VOID_TO_BOOLEAN); + private static final FQMethod GET = new FQMethod("java/util/List", "get", SignatureBuilder.SIG_INT_TO_OBJECT); enum ParseState { NORMAL, LAMBDA; @@ -367,7 +368,7 @@ @Nullable private String getAnonymousName(ConstantMethodHandle cmh) { - if (cmh.getReferenceKind() != REF_invokeStatic) { + if ((cmh == null) || (cmh.getReferenceKind() != REF_invokeStatic)) { return null; } Modified: trunk/fb-contrib/src/main/java/com/mebigfatguy/fbcontrib/detect/JPAIssues.java =================================================================== --- trunk/fb-contrib/src/main/java/com/mebigfatguy/fbcontrib/detect/JPAIssues.java 2018-05-20 22:03:10 UTC (rev 1838) +++ trunk/fb-contrib/src/main/java/com/mebigfatguy/fbcontrib/detect/JPAIssues.java 2018-06-01 00:34:34 UTC (rev 1839) @@ -268,10 +268,10 @@ /** * parses the current class for spring-tx and jpa annotations, as well as hashCode and equals methods. * - * @param cls + * @param clz * the currently parsed class */ - private void catalogClass(JavaClass cls) { + private void catalogClass(JavaClass clz) { transactionalMethods = new HashMap<>(); isEntity = false; hasId = false; @@ -279,7 +279,7 @@ hasEagerOneToMany = false; hasHCEquals = false; - for (AnnotationEntry entry : cls.getAnnotationEntries()) { + for (AnnotationEntry entry : clz.getAnnotationEntries()) { if ("Ljavax/persistence/Entity;".equals(entry.getAnnotationType())) { isEntity = true; break; @@ -286,7 +286,7 @@ } } - for (Method m : cls.getMethods()) { + for (Method m : clz.getMethods()) { catalogFieldOrMethod(m); if (("equals".equals(m.getName()) && SignatureBuilder.SIG_OBJECT_TO_BOOLEAN.equals(m.getSignature())) @@ -295,7 +295,7 @@ } } - for (Field f : cls.getFields()) { + for (Field f : clz.getFields()) { catalogFieldOrMethod(f); } } Modified: trunk/fb-contrib/src/main/java/com/mebigfatguy/fbcontrib/detect/LostExceptionStackTrace.java =================================================================== --- trunk/fb-contrib/src/main/java/com/mebigfatguy/fbcontrib/detect/LostExceptionStackTrace.java 2018-05-20 22:03:10 UTC (rev 1838) +++ trunk/fb-contrib/src/main/java/com/mebigfatguy/fbcontrib/detect/LostExceptionStackTrace.java 2018-06-01 00:34:34 UTC (rev 1839) @@ -241,8 +241,9 @@ markAsValid = true; // Fixes javac generated code } } - } else if (("getTargetException".equals(methodName) || "getCause".equals(methodName)) - && "java/lang/reflect/InvocationTargetException".equals(getClassConstantOperand())) { + } else if ((("getTargetException".equals(methodName) || "getCause".equals(methodName)) + && "java/lang/reflect/InvocationTargetException".equals(getClassConstantOperand())) + || "java/io/UncheckedIOException".equals(getClassConstantOperand())) { markAsValid = true; } else if (isPossibleExBuilder(catchInfo.getRegister())) { markAsValid = true; Modified: trunk/fb-contrib/src/main/java/com/mebigfatguy/fbcontrib/detect/OptionalIssues.java =================================================================== --- trunk/fb-contrib/src/main/java/com/mebigfatguy/fbcontrib/detect/OptionalIssues.java 2018-05-20 22:03:10 UTC (rev 1838) +++ trunk/fb-contrib/src/main/java/com/mebigfatguy/fbcontrib/detect/OptionalIssues.java 2018-06-01 00:34:34 UTC (rev 1839) @@ -55,7 +55,7 @@ private static Set<String> BOXED_OPTIONAL_TYPES = UnmodifiableSet.create("Ljava/lang/Integer;", "Ljava/lang/Long;", "Ljava/lang/Double;"); - private static final FQMethod OPTIONAL_OR_ELSE_METHOD = new FQMethod("java/util/Optional", "orElse", "(Ljava/lang/Object;)Ljava/lang/Object;"); + private static final FQMethod OPTIONAL_OR_ELSE_METHOD = new FQMethod("java/util/Optional", "orElse", SignatureBuilder.SIG_OBJECT_TO_OBJECT); private static final FQMethod OPTIONAL_OR_ELSE_GET_METHOD = new FQMethod("java/util/Optional", "orElseGet", "(Ljava/util/function/Supplier;)Ljava/lang/Object;"); private static final FQMethod OPTIONAL_GET_METHOD = new FQMethod("java/util/Optional", "get", SignatureBuilder.SIG_VOID_TO_OBJECT); @@ -64,8 +64,8 @@ // @formatter:off OPTIONAL_OR_ELSE_METHOD, new FQMethod("java/util/OptionalDouble", "orElse", "(D)D"), - new FQMethod("java/util/OptionalInt", "orElse", "(I)I"), - new FQMethod("java/util/OptionalLong", "orElse", "(J)J") + new FQMethod("java/util/OptionalInt", "orElse", SignatureBuilder.SIG_INT_TO_INT), + new FQMethod("java/util/OptionalLong", "orElse", SignatureBuilder.SIG_LONG_TO_LONG) // @formatter:on ); Modified: trunk/fb-contrib/src/main/java/com/mebigfatguy/fbcontrib/detect/PresizeCollections.java =================================================================== --- trunk/fb-contrib/src/main/java/com/mebigfatguy/fbcontrib/detect/PresizeCollections.java 2018-05-20 22:03:10 UTC (rev 1838) +++ trunk/fb-contrib/src/main/java/com/mebigfatguy/fbcontrib/detect/PresizeCollections.java 2018-06-01 00:34:34 UTC (rev 1839) @@ -460,7 +460,7 @@ return true; } - if ((seen != IFNE) || (stack.getStackDepth() == 0)) { + if (((seen != IFNE) && (seen != IFEQ)) || (stack.getStackDepth() == 0)) { return false; } Modified: trunk/fb-contrib/src/main/java/com/mebigfatguy/fbcontrib/detect/ReflectionIssues.java =================================================================== --- trunk/fb-contrib/src/main/java/com/mebigfatguy/fbcontrib/detect/ReflectionIssues.java 2018-05-20 22:03:10 UTC (rev 1838) +++ trunk/fb-contrib/src/main/java/com/mebigfatguy/fbcontrib/detect/ReflectionIssues.java 2018-06-01 00:34:34 UTC (rev 1839) @@ -18,6 +18,8 @@ */ package com.mebigfatguy.fbcontrib.detect; +import java.lang.reflect.AccessibleObject; + import org.apache.bcel.Repository; import org.apache.bcel.classfile.JavaClass; @@ -24,6 +26,7 @@ import com.mebigfatguy.fbcontrib.utils.BugType; import com.mebigfatguy.fbcontrib.utils.FQMethod; import com.mebigfatguy.fbcontrib.utils.QMethod; +import com.mebigfatguy.fbcontrib.utils.SignatureBuilder; import edu.umd.cs.findbugs.BugInstance; import edu.umd.cs.findbugs.BugReporter; @@ -32,9 +35,9 @@ public class ReflectionIssues extends BytecodeScanningDetector { - private static final QMethod SETACCESSIBLE = new QMethod("setAccessible", "(Z)V"); + private static final QMethod SETACCESSIBLE = new QMethod("setAccessible", SignatureBuilder.SIG_BOOLEAN_TO_VOID); private static final FQMethod SETACCESSIBLE_ARRAY = new FQMethod("java/lang/reflect/AccessibleObject", "setAccessible", - "([Ljava/lang/reflect/AccessibleObject;Z)V"); + new SignatureBuilder().withParamTypes(AccessibleObject.class).build()); private static final JavaClass ACCESSIBLE_OBJECT_CLASS; static { Modified: trunk/fb-contrib/src/main/java/com/mebigfatguy/fbcontrib/detect/SpoiledChildInterfaceImplementor.java =================================================================== --- trunk/fb-contrib/src/main/java/com/mebigfatguy/fbcontrib/detect/SpoiledChildInterfaceImplementor.java 2018-05-20 22:03:10 UTC (rev 1838) +++ trunk/fb-contrib/src/main/java/com/mebigfatguy/fbcontrib/detect/SpoiledChildInterfaceImplementor.java 2018-06-01 00:34:34 UTC (rev 1839) @@ -28,6 +28,7 @@ import com.mebigfatguy.fbcontrib.utils.BugType; import com.mebigfatguy.fbcontrib.utils.QMethod; +import com.mebigfatguy.fbcontrib.utils.SignatureBuilder; import com.mebigfatguy.fbcontrib.utils.ToString; import com.mebigfatguy.fbcontrib.utils.UnmodifiableSet; import com.mebigfatguy.fbcontrib.utils.Values; @@ -46,15 +47,15 @@ private static final Set<QMethod> OBJECT_METHODS = UnmodifiableSet.create( // @formatter:off - new QMethod("equals", "(Ljava/lang/Object;)Z"), - new QMethod(Values.HASHCODE, "()I"), - new QMethod(Values.TOSTRING, "()Ljava/lang/String;"), - new QMethod("clone", "()Ljava/lang/Object;"), - new QMethod("notify", "()V"), - new QMethod("notifyAll", "()V"), - new QMethod("wait", "(J)V"), + new QMethod("equals", SignatureBuilder.SIG_OBJECT_TO_BOOLEAN), + new QMethod(Values.HASHCODE, SignatureBuilder.SIG_VOID_TO_INT), + new QMethod(Values.TOSTRING, SignatureBuilder.SIG_VOID_TO_STRING), + new QMethod("clone", SignatureBuilder.SIG_VOID_TO_OBJECT), + new QMethod("notify", SignatureBuilder.SIG_VOID_TO_VOID), + new QMethod("notifyAll", SignatureBuilder.SIG_VOID_TO_VOID), + new QMethod("wait", SignatureBuilder.SIG_LONG_TO_VOID), new QMethod("wait", "(JI)V"), - new QMethod("wait", "()V") + new QMethod("wait", SignatureBuilder.SIG_VOID_TO_VOID) // @formatter:on ); private final BugReporter bugReporter; Modified: trunk/fb-contrib/src/main/java/com/mebigfatguy/fbcontrib/detect/SuspiciousNullGuard.java =================================================================== --- trunk/fb-contrib/src/main/java/com/mebigfatguy/fbcontrib/detect/SuspiciousNullGuard.java 2018-05-20 22:03:10 UTC (rev 1838) +++ trunk/fb-contrib/src/main/java/com/mebigfatguy/fbcontrib/detect/SuspiciousNullGuard.java 2018-06-01 00:34:34 UTC (rev 1839) @@ -25,6 +25,8 @@ import javax.annotation.Nullable; import org.apache.bcel.classfile.Code; +import org.apache.bcel.classfile.LocalVariable; +import org.apache.bcel.classfile.LocalVariableTable; import com.mebigfatguy.fbcontrib.utils.BugType; import com.mebigfatguy.fbcontrib.utils.RegisterUtils; @@ -101,8 +103,9 @@ try { stack.precomputation(this); - Integer pc = Integer.valueOf(getPC()); - nullGuards.remove(pc); + int pc = getPC(); + nullGuards.remove(Integer.valueOf(pc)); + clearEndOfLifeRegisters(); switch (seen) { case IFNULL: { @@ -111,12 +114,21 @@ int reg = itm.getRegisterNumber(); Integer target = Integer.valueOf(getBranchTarget()); if (reg >= 0) { - nullGuards.put(target, new NullGuard(reg, pc.intValue(), itm.getSignature())); + int eol = Integer.MAX_VALUE; + LocalVariableTable lvt = getMethod().getLocalVariableTable(); + if (lvt != null) { + LocalVariable lv = lvt.getLocalVariable(reg, pc); + if (lv != null) { + eol = pc + lv.getLength(); + } + } + + nullGuards.put(target, new NullGuard(reg, pc, eol, itm.getSignature())); } else { XField xf = itm.getXField(); Integer sourceFieldReg = (Integer) itm.getUserValue(); if ((xf != null) && (sourceFieldReg != null)) { - nullGuards.put(target, new NullGuard(xf, sourceFieldReg.intValue(), pc.intValue(), itm.getSignature())); + nullGuards.put(target, new NullGuard(xf, sourceFieldReg.intValue(), pc, itm.getSignature())); } } } @@ -258,17 +270,30 @@ } } + private void clearEndOfLifeRegisters() { + int pc = getPC(); + Iterator<NullGuard> it = nullGuards.values().iterator(); + while (it.hasNext()) { + NullGuard potentialEOL = it.next(); + if (potentialEOL.isEOL(pc)) { + it.remove(); + } + } + } + static class NullGuard { int register; XField field; int fieldSourceReg; int location; + int scopeEnd; String signature; - NullGuard(int reg, int start, String guardSignature) { + NullGuard(int reg, int start, int end, String guardSignature) { register = reg; field = null; location = start; + scopeEnd = end; signature = guardSignature; } @@ -277,6 +302,7 @@ field = xf; fieldSourceReg = fieldSource; location = start; + scopeEnd = Integer.MAX_VALUE; signature = guardSignature; } @@ -296,6 +322,10 @@ return location; } + boolean isEOL(int pc) { + return pc >= scopeEnd; + } + String getSignature() { return signature; } Modified: trunk/fb-contrib/src/main/java/com/mebigfatguy/fbcontrib/utils/SignatureBuilder.java =================================================================== --- trunk/fb-contrib/src/main/java/com/mebigfatguy/fbcontrib/utils/SignatureBuilder.java 2018-05-20 22:03:10 UTC (rev 1838) +++ trunk/fb-contrib/src/main/java/com/mebigfatguy/fbcontrib/utils/SignatureBuilder.java 2018-06-01 00:34:34 UTC (rev 1839) @@ -41,6 +41,8 @@ public static final String SIG_INT_TO_INT = new SignatureBuilder().withParamTypes(Values.SIG_PRIMITIVE_INT).withReturnType(Values.SIG_PRIMITIVE_INT) .toString(); + public static final String SIG_BOOLEAN_TO_VOID = new SignatureBuilder().withParamTypes(Values.SIG_PRIMITIVE_BOOLEAN).toString(); + public static final String SIG_LONG_TO_VOID = new SignatureBuilder().withParamTypes(Values.SIG_PRIMITIVE_LONG).toString(); public static final String SIG_LONG_TO_LONG = new SignatureBuilder().withParamTypes(Values.SIG_PRIMITIVE_LONG).withReturnType(Values.SIG_PRIMITIVE_LONG) .toString(); Modified: trunk/fb-contrib/src/samples/java/ex/ACEM_Sample.java =================================================================== --- trunk/fb-contrib/src/samples/java/ex/ACEM_Sample.java 2018-05-20 22:03:10 UTC (rev 1838) +++ trunk/fb-contrib/src/samples/java/ex/ACEM_Sample.java 2018-06-01 00:34:34 UTC (rev 1839) @@ -1,6 +1,10 @@ package ex; public abstract class ACEM_Sample implements Foo { + + public static final Runnable fpNOP283 = () -> { + }; + public void test() { } @@ -7,12 +11,11 @@ public int test1() { throw new UnsupportedOperationException("Not implemented"); } - + @Override public void doFPFoo() { } - - + } interface Foo { Modified: trunk/fb-contrib/src/samples/java/ex/AI_Sample.java =================================================================== --- trunk/fb-contrib/src/samples/java/ex/AI_Sample.java 2018-05-20 22:03:10 UTC (rev 1838) +++ trunk/fb-contrib/src/samples/java/ex/AI_Sample.java 2018-06-01 00:34:34 UTC (rev 1839) @@ -4,9 +4,13 @@ import java.lang.reflect.Constructor; import java.security.AccessController; import java.security.PrivilegedAction; +import java.util.Collections; +import java.util.List; import javax.annotation.Nullable; +import org.apache.commons.collections.CollectionUtils; + public class AI_Sample { @Nullable @@ -65,7 +69,47 @@ return AI_Sample.class.newInstance(); } + public Object fpConditionalWithThrow291() { + Object t = create(); + if (t != null) { + return t; + } else { + throw new RuntimeException(); + } + } + + public Object fpConditionalWithElseNotNull() { + Object t = create(); + if (t == null) { + return new Object(); + } else { + return t; + } + } + + public Object fpIsEmpty(String s) { + List<String> ss = maybeGetList(s); + + if (CollectionUtils.isEmpty(ss)) { + return Collections.emptyList(); + } + + return ss; + } + interface Stringer { String get(); } + + @Nullable + private static Object create() { + return Math.random() >= 0.5 ? new Object() : null; + } + + private List<String> maybeGetList(String s) { + if (s == null) { + return null; + } + return Collections.singletonList(s); + } } Modified: trunk/fb-contrib/src/samples/java/ex/LEST_Sample.java =================================================================== --- trunk/fb-contrib/src/samples/java/ex/LEST_Sample.java 2018-05-20 22:03:10 UTC (rev 1838) +++ trunk/fb-contrib/src/samples/java/ex/LEST_Sample.java 2018-06-01 00:34:34 UTC (rev 1839) @@ -3,6 +3,7 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; +import java.io.UncheckedIOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.text.DateFormat; @@ -9,6 +10,8 @@ import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; +import java.util.List; +import java.util.stream.Collectors; import com.google.common.base.Throwables; @@ -162,6 +165,20 @@ } } + public void testFPUncheckedIOException290(List<String> s) throws IOException { + try { + List<FileInputStream> fis = s.stream().map(ss -> { + try { + return new FileInputStream(ss); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + }).collect(Collectors.toList()); + } catch (UncheckedIOException e) { + throw e.getCause(); + } + } + static Class<?> testFP226(final String clazz) { if (clazz != null) { try { This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |