mirror of
https://github.com/github/codeql.git
synced 2026-04-29 18:55:14 +02:00
Merge pull request #2205 from rneatherway/java/hamcrest-nullness
Java: Respect Hamcrest assertThat(X, notNullValue())
This commit is contained in:
@@ -143,11 +143,21 @@ private ControlFlowNode varDereference(SsaVariable v, VarAccess va) {
|
||||
* subsequent use, either by dereferencing it or by an assertion.
|
||||
*/
|
||||
private ControlFlowNode ensureNotNull(SsaVariable v) {
|
||||
result = varDereference(v, _) or
|
||||
result.(AssertStmt).getExpr() = nullGuard(v, true, false) or
|
||||
exists(AssertTrueMethod m | result = m.getACheck(nullGuard(v, true, false))) or
|
||||
exists(AssertFalseMethod m | result = m.getACheck(nullGuard(v, false, false))) or
|
||||
result = varDereference(v, _)
|
||||
or
|
||||
result.(AssertStmt).getExpr() = nullGuard(v, true, false)
|
||||
or
|
||||
exists(AssertTrueMethod m | result = m.getACheck(nullGuard(v, true, false)))
|
||||
or
|
||||
exists(AssertFalseMethod m | result = m.getACheck(nullGuard(v, false, false)))
|
||||
or
|
||||
exists(AssertNotNullMethod m | result = m.getACheck(v.getAUse()))
|
||||
or
|
||||
exists(AssertThatMethod m, MethodAccess ma |
|
||||
result = m.getACheck(v.getAUse()) and ma.getControlFlowNode() = result
|
||||
|
|
||||
ma.getAnArgument().(MethodAccess).getMethod().getName() = "notNullValue"
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -11,7 +11,8 @@ newtype AssertKind =
|
||||
AssertKindTrue() or
|
||||
AssertKindFalse() or
|
||||
AssertKindNotNull() or
|
||||
AssertKindFail()
|
||||
AssertKindFail() or
|
||||
AssertKindThat()
|
||||
|
||||
private predicate assertionMethod(Method m, AssertKind kind) {
|
||||
exists(RefType junit |
|
||||
@@ -27,6 +28,13 @@ private predicate assertionMethod(Method m, AssertKind kind) {
|
||||
m.hasName("fail") and kind = AssertKindFail()
|
||||
)
|
||||
or
|
||||
exists(RefType hamcrest |
|
||||
m.getDeclaringType() = hamcrest and
|
||||
hamcrest.hasQualifiedName("org.hamcrest", "MatcherAssert")
|
||||
|
|
||||
m.hasName("assertThat") and kind = AssertKindThat()
|
||||
)
|
||||
or
|
||||
exists(RefType objects |
|
||||
m.getDeclaringType() = objects and
|
||||
objects.hasQualifiedName("java.util", "Objects")
|
||||
@@ -82,6 +90,14 @@ class AssertFailMethod extends AssertionMethod {
|
||||
AssertFailMethod() { assertionMethod(this, AssertKindFail()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A method that asserts that its first argument has a property
|
||||
* given by its second argument.
|
||||
*/
|
||||
class AssertThatMethod extends AssertionMethod {
|
||||
AssertThatMethod() { assertionMethod(this, AssertKindThat()) }
|
||||
}
|
||||
|
||||
/** A trivially failing assertion. That is, `assert false` or its equivalents. */
|
||||
predicate assertFail(BasicBlock bb, ControlFlowNode n) {
|
||||
bb = n.getBasicBlock() and
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.hamcrest.core.IsNull.*;
|
||||
import static org.hamcrest.MatcherAssert.*;
|
||||
|
||||
public class A {
|
||||
public void notTest() {
|
||||
@@ -296,6 +298,12 @@ public class A {
|
||||
for (it = iter.iterator(); !!it.hasNext(); ) {}
|
||||
}
|
||||
|
||||
public void assertThatTest() {
|
||||
Object assertThat_ok1 = maybe() ? null : new Object();
|
||||
assertThat(assertThat_ok1, notNullValue());
|
||||
assertThat_ok1.toString();
|
||||
}
|
||||
|
||||
private boolean m;
|
||||
A(boolean m) {
|
||||
this.m = m;
|
||||
|
||||
@@ -120,7 +120,7 @@ public class B {
|
||||
}
|
||||
|
||||
private Object mkMaybe() {
|
||||
if (maybe) throw new Exception();
|
||||
if (maybe) throw new RuntimeException();
|
||||
return new Object();
|
||||
}
|
||||
|
||||
@@ -267,7 +267,7 @@ public class B {
|
||||
}
|
||||
if(msg != null) {
|
||||
msg += "foobar";
|
||||
throw new Exception(msg);
|
||||
throw new RuntimeException(msg);
|
||||
}
|
||||
obj.hashCode(); // OK
|
||||
}
|
||||
@@ -286,7 +286,7 @@ public class B {
|
||||
|
||||
int[] b = maybe ? null : new int[iters];
|
||||
if (iters > 0 && (b == null || b.length < iters)) {
|
||||
throw new Exception();
|
||||
throw new RuntimeException();
|
||||
}
|
||||
for (int i = 0; i < iters; ++i) {
|
||||
b[i] = 0; // NPE - false positive
|
||||
|
||||
@@ -87,7 +87,7 @@ public class C {
|
||||
vals[0] = 0; // OK
|
||||
break;
|
||||
default:
|
||||
throw new Exception();
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
| A.java:13:7:13:9 | not | Variable $@ is always null here. | A.java:11:5:11:22 | Object not | not |
|
||||
| A.java:95:18:95:36 | synchronized_always | Variable $@ is always null here. | A.java:94:5:94:38 | Object synchronized_always | synchronized_always |
|
||||
| A.java:159:26:159:34 | do_always | Variable $@ is always null here. | A.java:157:5:157:28 | String do_always | do_always |
|
||||
| A.java:165:26:165:34 | do_maybe1 | Variable $@ is always null here. | A.java:163:5:163:28 | String do_maybe1 | do_maybe1 |
|
||||
| A.java:185:26:185:37 | while_always | Variable $@ is always null here. | A.java:183:5:183:31 | String while_always | while_always |
|
||||
| A.java:205:26:205:34 | if_always | Variable $@ is always null here. | A.java:203:5:203:28 | String if_always | if_always |
|
||||
| A.java:221:24:221:29 | for_ok | Variable $@ is always null here. | A.java:217:5:217:19 | String for_ok | for_ok |
|
||||
| A.java:224:26:224:35 | for_always | Variable $@ is always null here. | A.java:223:10:223:33 | String for_always | for_always |
|
||||
| A.java:234:5:234:14 | array_null | Variable $@ is always null here. | A.java:233:5:233:28 | int[] array_null | array_null |
|
||||
| A.java:246:24:246:34 | arrayaccess | Variable $@ is always null here. | A.java:242:5:242:29 | int[] arrayaccess | arrayaccess |
|
||||
| A.java:247:24:247:34 | fieldaccess | Variable $@ is always null here. | A.java:243:5:243:32 | String[] fieldaccess | fieldaccess |
|
||||
| A.java:248:24:248:35 | methodaccess | Variable $@ is always null here. | A.java:244:5:244:31 | Object methodaccess | methodaccess |
|
||||
| A.java:262:21:262:30 | for_always | Variable $@ is always null here. | A.java:261:5:261:35 | List<String> for_always | for_always |
|
||||
| A.java:264:24:264:33 | for_always | Variable $@ is always null here. | A.java:261:5:261:35 | List<String> for_always | for_always |
|
||||
| A.java:15:7:15:9 | not | Variable $@ is always null here. | A.java:13:5:13:22 | Object not | not |
|
||||
| A.java:97:18:97:36 | synchronized_always | Variable $@ is always null here. | A.java:96:5:96:38 | Object synchronized_always | synchronized_always |
|
||||
| A.java:161:26:161:34 | do_always | Variable $@ is always null here. | A.java:159:5:159:28 | String do_always | do_always |
|
||||
| A.java:167:26:167:34 | do_maybe1 | Variable $@ is always null here. | A.java:165:5:165:28 | String do_maybe1 | do_maybe1 |
|
||||
| A.java:187:26:187:37 | while_always | Variable $@ is always null here. | A.java:185:5:185:31 | String while_always | while_always |
|
||||
| A.java:207:26:207:34 | if_always | Variable $@ is always null here. | A.java:205:5:205:28 | String if_always | if_always |
|
||||
| A.java:223:24:223:29 | for_ok | Variable $@ is always null here. | A.java:219:5:219:19 | String for_ok | for_ok |
|
||||
| A.java:226:26:226:35 | for_always | Variable $@ is always null here. | A.java:225:10:225:33 | String for_always | for_always |
|
||||
| A.java:236:5:236:14 | array_null | Variable $@ is always null here. | A.java:235:5:235:28 | int[] array_null | array_null |
|
||||
| A.java:248:24:248:34 | arrayaccess | Variable $@ is always null here. | A.java:244:5:244:29 | int[] arrayaccess | arrayaccess |
|
||||
| A.java:249:24:249:34 | fieldaccess | Variable $@ is always null here. | A.java:245:5:245:32 | String[] fieldaccess | fieldaccess |
|
||||
| A.java:250:24:250:35 | methodaccess | Variable $@ is always null here. | A.java:246:5:246:31 | Object methodaccess | methodaccess |
|
||||
| A.java:264:21:264:30 | for_always | Variable $@ is always null here. | A.java:263:5:263:35 | List<String> for_always | for_always |
|
||||
| A.java:266:24:266:33 | for_always | Variable $@ is always null here. | A.java:263:5:263:35 | List<String> for_always | for_always |
|
||||
| B.java:304:7:304:9 | ioe | Variable $@ is always null here. | B.java:297:5:297:25 | Exception ioe | ioe |
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
| A.java:46:5:46:21 | assertNotNull_ok3 | Variable $@ may be null here because of $@ assignment. | A.java:44:5:44:61 | Object assertNotNull_ok3 | assertNotNull_ok3 | A.java:44:12:44:60 | assertNotNull_ok3 | this |
|
||||
| A.java:170:26:170:33 | do_maybe | Variable $@ may be null here because of $@ assignment. | A.java:168:5:168:25 | String do_maybe | do_maybe | A.java:171:7:171:21 | ...=... | this |
|
||||
| A.java:191:26:191:36 | while_maybe | Variable $@ may be null here because of $@ assignment. | A.java:189:5:189:28 | String while_maybe | while_maybe | A.java:192:7:192:24 | ...=... | this |
|
||||
| A.java:213:24:213:31 | if_maybe | Variable $@ may be null here because of $@ assignment. | A.java:209:5:209:25 | String if_maybe | if_maybe | A.java:211:7:211:21 | ...=... | this |
|
||||
| A.java:228:26:228:34 | for_maybe | Variable $@ may be null here because of $@ assignment. | A.java:227:10:227:30 | String for_maybe | for_maybe | A.java:227:35:227:50 | ...=... | this |
|
||||
| A.java:271:24:271:32 | for_maybe | Variable $@ may be null here because of $@ assignment. | A.java:266:5:266:63 | List<String> for_maybe | for_maybe | A.java:269:7:269:22 | ...=... | this |
|
||||
| A.java:48:5:48:21 | assertNotNull_ok3 | Variable $@ may be null here because of $@ assignment. | A.java:46:5:46:61 | Object assertNotNull_ok3 | assertNotNull_ok3 | A.java:46:12:46:60 | assertNotNull_ok3 | this |
|
||||
| A.java:172:26:172:33 | do_maybe | Variable $@ may be null here because of $@ assignment. | A.java:170:5:170:25 | String do_maybe | do_maybe | A.java:173:7:173:21 | ...=... | this |
|
||||
| A.java:193:26:193:36 | while_maybe | Variable $@ may be null here because of $@ assignment. | A.java:191:5:191:28 | String while_maybe | while_maybe | A.java:194:7:194:24 | ...=... | this |
|
||||
| A.java:215:24:215:31 | if_maybe | Variable $@ may be null here because of $@ assignment. | A.java:211:5:211:25 | String if_maybe | if_maybe | A.java:213:7:213:21 | ...=... | this |
|
||||
| A.java:230:26:230:34 | for_maybe | Variable $@ may be null here because of $@ assignment. | A.java:229:10:229:30 | String for_maybe | for_maybe | A.java:229:35:229:50 | ...=... | this |
|
||||
| A.java:273:24:273:32 | for_maybe | Variable $@ may be null here because of $@ assignment. | A.java:268:5:268:63 | List<String> for_maybe | for_maybe | A.java:271:7:271:22 | ...=... | this |
|
||||
| B.java:16:5:16:9 | param | Variable $@ may be null here because of $@ null argument. | B.java:15:23:15:34 | param | param | B.java:11:13:11:16 | null | this |
|
||||
| B.java:23:5:23:9 | param | Variable $@ may be null here as suggested by $@ null guard. | B.java:19:23:19:34 | param | param | B.java:20:9:20:21 | ... != ... | this |
|
||||
| B.java:57:7:57:8 | o7 | Variable $@ may be null here because of $@ assignment. | B.java:52:5:52:34 | Object o7 | o7 | B.java:52:12:52:33 | o7 | this |
|
||||
|
||||
@@ -1 +1 @@
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../stubs/junit-4.11:${testdir}/../../stubs/junit-jupiter-api-5.2.0
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../stubs/junit-4.11:${testdir}/../../stubs/hamcrest-2.2:${testdir}/../../stubs/junit-jupiter-api-5.2.0
|
||||
|
||||
27
java/ql/test/stubs/hamcrest-2.2/LICENSE.txt
Normal file
27
java/ql/test/stubs/hamcrest-2.2/LICENSE.txt
Normal file
@@ -0,0 +1,27 @@
|
||||
BSD License
|
||||
|
||||
Copyright (c) 2000-2015 www.hamcrest.org
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list of
|
||||
conditions and the following disclaimer. Redistributions in binary form must reproduce
|
||||
the above copyright notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
|
||||
Neither the name of Hamcrest nor the names of its contributors may be used to endorse
|
||||
or promote products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
|
||||
WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGE.
|
||||
@@ -0,0 +1,14 @@
|
||||
package org.hamcrest;
|
||||
|
||||
|
||||
public class MatcherAssert {
|
||||
public static <T> void assertThat(T actual, Object matcher) {
|
||||
assertThat("", actual, matcher);
|
||||
}
|
||||
|
||||
public static <T> void assertThat(String reason, T actual, Object matcher) {
|
||||
}
|
||||
|
||||
public static void assertThat(String reason, boolean assertion) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package org.hamcrest.core;
|
||||
|
||||
public class IsNull {
|
||||
|
||||
public static Object notNullValue() {
|
||||
return new String();
|
||||
}
|
||||
|
||||
public static <T> Object notNullValue(Class<T> type) {
|
||||
return new String();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user