From 33152f15f93dae9b219f902bdf18fb9ff0faeefc Mon Sep 17 00:00:00 2001 From: shubham ugare Date: Tue, 11 Dec 2018 23:22:00 +0530 Subject: [PATCH] Model parseXXX methods of boxed primitives as having @NonNull parameter (#270) E.g., the parameter of Long.parseLong(String) should not be null or a NumberFormatException gets thrown. We should model all the parseXXX methods of all the java.lang boxed primitive types. Following methods are added 1. parseInt 2. parseFloat 3. parseShort 4. parseLong 5. parseDouble 6. parseByte 7. parseBoolean Fixes #269 Added unit tests. --- .../handlers/LibraryModelsHandler.java | 11 +++++++ .../testdata/NullAwayNativeModels.java | 32 +++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/nullaway/src/main/java/com/uber/nullaway/handlers/LibraryModelsHandler.java b/nullaway/src/main/java/com/uber/nullaway/handlers/LibraryModelsHandler.java index 40d8ef7ece..0b9def85c9 100644 --- a/nullaway/src/main/java/com/uber/nullaway/handlers/LibraryModelsHandler.java +++ b/nullaway/src/main/java/com/uber/nullaway/handlers/LibraryModelsHandler.java @@ -304,6 +304,17 @@ private static class DefaultLibraryModels implements LibraryModels { .put(methodRef("java.util.ArrayDeque", "offer(E)"), 0) .put(methodRef("java.util.ArrayDeque", "push(E)"), 0) .put(methodRef("java.util.ArrayDeque", "toArray(T[])"), 0) + .put(methodRef("java.lang.Integer", "parseInt(java.lang.String)"), 0) + .put(methodRef("java.lang.Long", "parseLong(java.lang.String)"), 0) + .put(methodRef("java.lang.Boolean", "parseBoolean(java.lang.String)"), 0) + .put(methodRef("java.lang.Float", "parseFloat(java.lang.String)"), 0) + .put(methodRef("java.lang.Double", "parseDouble(java.lang.String)"), 0) + .put(methodRef("java.lang.Short", "parseShort(java.lang.String)"), 0) + .put(methodRef("java.lang.Byte", "parseByte(java.lang.String)"), 0) + .put(methodRef("java.lang.Long", "parseLong(java.lang.String,int)"), 0) + .put(methodRef("java.lang.Integer", "parseInt(java.lang.String,int)"), 0) + .put(methodRef("java.lang.Byte", "parseByte(java.lang.String,int)"), 0) + .put(methodRef("java.lang.Short", "parseShort(java.lang.String,int)"), 0) .build(); private static final ImmutableSetMultimap NULL_IMPLIES_TRUE_PARAMETERS = diff --git a/nullaway/src/test/resources/com/uber/nullaway/testdata/NullAwayNativeModels.java b/nullaway/src/test/resources/com/uber/nullaway/testdata/NullAwayNativeModels.java index 14aa8781a6..634135d966 100644 --- a/nullaway/src/test/resources/com/uber/nullaway/testdata/NullAwayNativeModels.java +++ b/nullaway/src/test/resources/com/uber/nullaway/testdata/NullAwayNativeModels.java @@ -311,6 +311,38 @@ static void androidStuff() { } } + static void parseStringToPrimitiveTypesStuff() { + String s = null; + // BUG: Diagnostic contains: passing @Nullable parameter 's' where @NonNull is required + int a = Integer.parseInt(s); + // BUG: Diagnostic contains: passing @Nullable parameter 's' where @NonNull is required + double b = Double.parseDouble(s); + // BUG: Diagnostic contains: passing @Nullable parameter 's' where @NonNull is required + long c = Long.parseLong(s); + // BUG: Diagnostic contains: passing @Nullable parameter 's' where @NonNull is required + float d = Float.parseFloat(s); + // BUG: Diagnostic contains: passing @Nullable parameter 's' where @NonNull is required + short e = Short.parseShort(s); + // BUG: Diagnostic contains: passing @Nullable parameter 's' where @NonNull is required + byte f = Byte.parseByte(s); + // BUG: Diagnostic contains: passing @Nullable parameter 's' where @NonNull is required + boolean g = Boolean.parseBoolean(s); + // BUG: Diagnostic contains: passing @Nullable parameter 's' where @NonNull is required + byte h = Byte.parseByte(s, 1); + // BUG: Diagnostic contains: passing @Nullable parameter 's' where @NonNull is required + long i = Long.parseLong(s, 1); + // BUG: Diagnostic contains: passing @Nullable parameter 's' where @NonNull is required + int j = Integer.parseInt(s, 1); + // BUG: Diagnostic contains: passing @Nullable parameter 's' where @NonNull is required + short k = Short.parseShort(s, 1); + + s = "100"; + // no warning expected + int l = Integer.parseInt(s); + long m = Long.parseLong(s); + short n = Short.parseShort(s, 1); + } + static void apacheCommonsStuff() { String s = null; if (!org.apache.commons.lang.StringUtils.isEmpty(s)) {