Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle CoreMatchers and core.IsNull in Hamcrest. #311

Merged
merged 1 commit into from May 1, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -49,6 +49,8 @@ public class AssertionHandler extends BaseNoOpHandler {
private static final String JUNIT_ASSERT_CLASS = "org.junit.Assert";

private static final String MATCHERS_CLASS = "org.hamcrest.Matchers";
private static final String CORE_MATCHERS_CLASS = "org.hamcrest.CoreMatchers";
private static final String CORE_IS_NULL_CLASS = "org.hamcrest.core.IsNull";
private static final String IS_MATCHER = "is";
private static final String NOT_MATCHER = "not";
private static final String NOT_NULL_VALUE_MATCHER = "notNullValue";
Expand All @@ -68,6 +70,8 @@ public class AssertionHandler extends BaseNoOpHandler {

// Names for hamcrest matchers.
private Name matchersClass;
private Name coreMatchersClass;
private Name coreIsNullClass;
private Name isMatcher;
private Name notMatcher;
private Name notNullValueMatcher;
Expand Down Expand Up @@ -144,7 +148,8 @@ private boolean isMatcherIsNotNull(Node node) {
// Matches with
// * is(not(nullValue()))
// * is(notNullValue())
if (matchesMatcherMethod(node, isMatcher)) {
if (matchesMatcherMethod(node, isMatcher, matchersClass)
|| matchesMatcherMethod(node, isMatcher, coreMatchersClass)) {
// All overloads of `is` method have exactly one argument.
return isMatcherNotNull(((MethodInvocationNode) node).getArgument(0));
}
Expand All @@ -155,23 +160,28 @@ private boolean isMatcherNotNull(Node node) {
// Matches with
// * not(nullValue())
// * notNullValue()
if (matchesMatcherMethod(node, notMatcher)) {
if (matchesMatcherMethod(node, notMatcher, matchersClass)
|| matchesMatcherMethod(node, notMatcher, coreMatchersClass)) {
// All overloads of `not` method have exactly one argument.
return isMatcherNull(((MethodInvocationNode) node).getArgument(0));
}
return matchesMatcherMethod(node, notNullValueMatcher);
return matchesMatcherMethod(node, notNullValueMatcher, matchersClass)
|| matchesMatcherMethod(node, notNullValueMatcher, coreMatchersClass)
|| matchesMatcherMethod(node, notNullValueMatcher, coreIsNullClass);
}

private boolean isMatcherNull(Node node) {
// Matches with nullValue()
return matchesMatcherMethod(node, nullValueMatcher);
return matchesMatcherMethod(node, nullValueMatcher, matchersClass)
|| matchesMatcherMethod(node, nullValueMatcher, coreMatchersClass)
|| matchesMatcherMethod(node, nullValueMatcher, coreIsNullClass);
}

private boolean matchesMatcherMethod(Node node, Name matcherName) {
private boolean matchesMatcherMethod(Node node, Name matcherName, Name matcherClass) {
if (node instanceof MethodInvocationNode) {
MethodInvocationNode methodInvocationNode = (MethodInvocationNode) node;
Symbol.MethodSymbol callee = ASTHelpers.getSymbol(methodInvocationNode.getTree());
return matchesMethod(callee, matcherName, matchersClass);
return matchesMethod(callee, matcherName, matcherClass);
}
return false;
}
Expand All @@ -196,6 +206,8 @@ private void initializeMethodNames(Name.Table table) {
junitAssertClass = table.fromString(JUNIT_ASSERT_CLASS);

matchersClass = table.fromString(MATCHERS_CLASS);
coreMatchersClass = table.fromString(CORE_MATCHERS_CLASS);
coreIsNullClass = table.fromString(CORE_IS_NULL_CLASS);
isMatcher = table.fromString(IS_MATCHER);
notMatcher = table.fromString(NOT_MATCHER);
notNullValueMatcher = table.fromString(NOT_NULL_VALUE_MATCHER);
Expand Down
59 changes: 58 additions & 1 deletion nullaway/src/test/java/com/uber/nullaway/NullAwayTest.java
Expand Up @@ -1043,7 +1043,7 @@ public void doNotSupportTruthAssertThatWhenDisabled() {
}

@Test
public void supportHamcrestAssertThatIsNotNull_Object() {
public void supportHamcrestAssertThatMatchersIsNotNull() {
compilationHelper
.setArgs(
Arrays.asList(
Expand Down Expand Up @@ -1097,6 +1097,63 @@ public void doNotSupportHamcrestAssertThatWhenDisabled() {
.doTest();
}

@Test
public void supportHamcrestAssertThatCoreMatchersIsNotNull() {
compilationHelper
.setArgs(
Arrays.asList(
"-d",
temporaryFolder.getRoot().getAbsolutePath(),
"-XepOpt:NullAway:AnnotatedPackages=com.uber",
"-XepOpt:NullAway:HandleTestAssertionLibraries=true"))
.addSourceLines(
"Test.java",
"package com.uber;",
"import java.lang.Object;",
"import java.util.Objects;",
"import javax.annotation.Nullable;",
"import static org.hamcrest.MatcherAssert.assertThat;",
"import static org.hamcrest.CoreMatchers.*;",
"class Test {",
" private void foo(@Nullable Object a, @Nullable Object b) {",
" assertThat(a, is(notNullValue()));",
" a.toString();",
" assertThat(b, is(not(nullValue())));",
" b.toString();",
" }",
"}")
.doTest();
}

@Test
public void supportHamcrestAssertThatCoreIsNotNull() {
compilationHelper
.setArgs(
Arrays.asList(
"-d",
temporaryFolder.getRoot().getAbsolutePath(),
"-XepOpt:NullAway:AnnotatedPackages=com.uber",
"-XepOpt:NullAway:HandleTestAssertionLibraries=true"))
.addSourceLines(
"Test.java",
"package com.uber;",
"import java.lang.Object;",
"import java.util.Objects;",
"import javax.annotation.Nullable;",
"import static org.hamcrest.MatcherAssert.assertThat;",
"import static org.hamcrest.CoreMatchers.*;",
"import org.hamcrest.core.IsNull;",
"class Test {",
" private void foo(@Nullable Object a, @Nullable Object b) {",
" assertThat(a, is(IsNull.notNullValue()));",
" a.toString();",
" assertThat(b, is(not(IsNull.nullValue())));",
" b.toString();",
" }",
"}")
.doTest();
}

@Test
public void supportJunitAssertThatIsNotNull_Object() {
compilationHelper
Expand Down