diff --git a/nullaway/src/main/java/com/uber/nullaway/handlers/AssertionHandler.java b/nullaway/src/main/java/com/uber/nullaway/handlers/AssertionHandler.java index 90ccda05fd..72c7629fda 100644 --- a/nullaway/src/main/java/com/uber/nullaway/handlers/AssertionHandler.java +++ b/nullaway/src/main/java/com/uber/nullaway/handlers/AssertionHandler.java @@ -88,6 +88,16 @@ public NullnessHint onDataflowVisitMethodInvocation( return NullnessHint.UNKNOWN; } + /** + * Returns the AccessPath for the argument of an assertThat() call, if present as a valid nested + * receiver expression of a method invocation + * + * @param node the method invocation node + * @param state the visitor state + * @param apContext the access path context + * @return the AccessPath for the argument of the assertThat() call, if present, otherwise {@code + * null} + */ private @Nullable AccessPath getAccessPathForNotNullExpr( MethodInvocationNode node, VisitorState state, AccessPath.AccessPathContext apContext) { Node receiver = node.getTarget().getReceiver(); @@ -97,7 +107,8 @@ public NullnessHint onDataflowVisitMethodInvocation( if (methodNameUtil.isMethodAssertThat(receiver_symbol)) { Node arg = receiver_method.getArgument(0); return AccessPath.getAccessPathForNode(arg, state, apContext); - } else if (methodNameUtil.isMethodDescribedAs(receiver_symbol)) { + } else if (methodNameUtil.isMethodAssertJDescribedAs(receiver_symbol)) { + // For calls to as() or describedAs(), we recursively search for the assertThat() call return getAccessPathForNotNullExpr(receiver_method, state, apContext); } } diff --git a/nullaway/src/main/java/com/uber/nullaway/handlers/MethodNameUtil.java b/nullaway/src/main/java/com/uber/nullaway/handlers/MethodNameUtil.java index b85b77c0d6..203f545259 100644 --- a/nullaway/src/main/java/com/uber/nullaway/handlers/MethodNameUtil.java +++ b/nullaway/src/main/java/com/uber/nullaway/handlers/MethodNameUtil.java @@ -220,7 +220,10 @@ boolean isMethodAssertThat(Symbol.MethodSymbol methodSymbol) { || matchesMethod(methodSymbol, assertThat, assertThatOwnerAssertJ); } - public boolean isMethodDescribedAs(Symbol.MethodSymbol methodSymbol) { + public boolean isMethodAssertJDescribedAs(Symbol.MethodSymbol methodSymbol) { + // describedAs() and as() are equivalent. Also, we do not check the owner, as there are many + // possible implementations. This method should only be used in a caller content where it is + // clear that the operation is related to use of AssertJ. return methodSymbol.name.equals(as) || methodSymbol.name.equals(describedAs); }