Skip to content

Commit d21d4ab

Browse files
authored
Fix bugs in handling of valueOf calls for map keys (#1085)
Fixes the second crash from #1082. Our handling of `valueOf` calls in map key arguments was a bit hacky and syntactic. Fix to properly check for calls to `Integer.valueOf` or `Long.valueOf`.
1 parent 1fc39b3 commit d21d4ab

File tree

2 files changed

+68
-5
lines changed

2 files changed

+68
-5
lines changed

nullaway/src/main/java/com/uber/nullaway/dataflow/AccessPath.java

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
import com.google.common.collect.ImmutableList;
2929
import com.google.common.collect.ImmutableSet;
3030
import com.google.errorprone.VisitorState;
31+
import com.google.errorprone.suppliers.Supplier;
32+
import com.google.errorprone.suppliers.Suppliers;
3133
import com.google.errorprone.util.ASTHelpers;
3234
import com.sun.source.tree.LiteralTree;
3335
import com.sun.source.tree.MethodInvocationTree;
@@ -75,6 +77,12 @@
7577
*/
7678
public final class AccessPath implements MapKey {
7779

80+
private static final Supplier<Type> INTEGER_TYPE_SUPPLIER =
81+
Suppliers.typeFromString("java.lang.Integer");
82+
83+
private static final Supplier<Type> LONG_TYPE_SUPPLIER =
84+
Suppliers.typeFromString("java.lang.Long");
85+
7886
/**
7987
* A prefix added for elements appearing in method invocation APs which represent fields that can
8088
* be proven to be class-initialization time constants (i.e. static final fields of a type known
@@ -278,14 +286,15 @@ private static Node stripCasts(Node node) {
278286
return new NumericMapKey(((LongLiteralNode) argument).getValue());
279287
case METHOD_INVOCATION:
280288
MethodAccessNode target = ((MethodInvocationNode) argument).getTarget();
281-
Node receiver = stripCasts(target.getReceiver());
282289
List<Node> arguments = ((MethodInvocationNode) argument).getArguments();
283290
// Check for int/long boxing.
284291
if (target.getMethod().getSimpleName().toString().equals("valueOf")
285-
&& arguments.size() == 1
286-
&& castToNonNull(receiver.getTree()).getKind().equals(Tree.Kind.IDENTIFIER)
287-
&& (receiver.toString().equals("Integer") || receiver.toString().equals("Long"))) {
288-
return argumentToMapKeySpecifier(arguments.get(0), state, apContext);
292+
&& arguments.size() == 1) {
293+
Type ownerType = ((Symbol.MethodSymbol) target.getMethod()).owner.type;
294+
if (ASTHelpers.isSameType(ownerType, INTEGER_TYPE_SUPPLIER.get(state), state)
295+
|| ASTHelpers.isSameType(ownerType, LONG_TYPE_SUPPLIER.get(state), state)) {
296+
return argumentToMapKeySpecifier(arguments.get(0), state, apContext);
297+
}
289298
}
290299
// Fine to fallthrough:
291300
default:

nullaway/src/test/java/com/uber/nullaway/AccessPathsTests.java

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,4 +434,58 @@ public void testAccessUsingExplicitThis() {
434434
"}")
435435
.doTest();
436436
}
437+
438+
@Test
439+
public void mapKeysFromValueOf() {
440+
defaultCompilationHelper
441+
.addSourceLines(
442+
"Foo.java",
443+
"package com.uber;",
444+
"import java.util.HashMap;",
445+
"import java.util.Map;",
446+
"public class Foo {",
447+
" private final Map<Integer, Object> map = new HashMap<>();",
448+
" private final Map<Long, Object> longMap = new HashMap<>();",
449+
" static Integer valueOf(int i) { return 0; }",
450+
" static Integer valueOf(int i, int j) { return i+j; }",
451+
" public void putThenGetIntegerValueOf() {",
452+
" map.put(Integer.valueOf(10), new Object());",
453+
" map.get(Integer.valueOf(10)).toString();",
454+
" }",
455+
" public void putThenGetLongValueOf() {",
456+
" longMap.put(Long.valueOf(10), new Object());",
457+
" longMap.get(Long.valueOf(10)).toString();",
458+
" }",
459+
" public void putThenGetFooValueOf() {",
460+
" map.put(valueOf(10), new Object());",
461+
" // Unknown valueOf method so we report a warning",
462+
" // BUG: Diagnostic contains: dereferenced expression map.get(valueOf(10)) is @Nullable",
463+
" map.get(valueOf(10)).toString();",
464+
" map.put(valueOf(10,20), new Object());",
465+
" // Unknown valueOf method so we report a warning",
466+
" // BUG: Diagnostic contains: dereferenced expression map.get(valueOf(10,20)) is @Nullable",
467+
" map.get(valueOf(10,20)).toString();",
468+
" }",
469+
"}")
470+
.doTest();
471+
}
472+
473+
@Test
474+
public void mapKeyFromIntegerValueOfStaticImport() {
475+
defaultCompilationHelper
476+
.addSourceLines(
477+
"Foo.java",
478+
"package com.uber;",
479+
"import java.util.HashMap;",
480+
"import java.util.Map;",
481+
"import static java.lang.Integer.valueOf;",
482+
"public class Foo {",
483+
" private final Map<Integer, Object> map = new HashMap<>();",
484+
" public void putThenGet() {",
485+
" map.put(valueOf(10), new Object());",
486+
" map.get(valueOf(10)).toString();",
487+
" }",
488+
"}")
489+
.doTest();
490+
}
437491
}

0 commit comments

Comments
 (0)