diff --git a/infer/tests/codetoanalyze/java/nullsafe-default/ButterKnife.java b/infer/tests/codetoanalyze/java/nullsafe-default/ButterKnife.java new file mode 100644 index 000000000..c57036fa3 --- /dev/null +++ b/infer/tests/codetoanalyze/java/nullsafe-default/ButterKnife.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +package codetoanalyze.java.nullsafe_default; + +import javax.annotation.Nullable; + +@interface InjectView {} + +/** Support assignments of null to @InjectView fields, generated by butterknife. */ +public class ButterKnife { + @InjectView String injected; + String normal = ""; // assign to suppress not initialized warning + @Nullable String nullable = ""; // assign to suppress not initialized warning + + void f(String nonNullable) {} + + // When dereferencing, injected should behave as not nullable + + void dereferencingInjectedIsOK() { + int n = injected.length(); + } + + void dereferencingNormalIsOK() { + int n = normal.length(); + } + + void dereferencingNullableIsBAD() { + int n = nullable.length(); + } + + // When returning a value, injected should be treated as non nullable + + String convertingToNotNullableForInjectedIsOK() { + return injected; + } + + String convertingToNotNullableForNormalIsOK() { + return normal; + } + + String convertingToNotNullableForNullableIsBAD() { + return nullable; + } + + // When passing to a non nullable param, injected should be treated as non nullable + + void passingToNullableForInjectedIsOK() { + f(injected); + } + + void passingToNullableForNormalIsOK() { + f(normal); + } + + void passingToNullableForNullableIsBAD() { + f(nullable); + } + + // Assigning null to Injected should be allowed (as if it was nullable) + // (Those assignments are generated by Butterknife framework.) + + void assignNullToInjectedIsOK() { + injected = null; + } + + void assignNullToNullableIsOK() { + nullable = null; + } + + void assignNullToNormalIsBAD() { + normal = null; + } + + class TestNotInitialized { + @InjectView String notInitializedInjectedIsOK; + @Nullable String notInitializedNullableIsOK; + String notInitializedNormalIsBAD; + } +} diff --git a/infer/tests/codetoanalyze/java/nullsafe-default/CapturedParam.java b/infer/tests/codetoanalyze/java/nullsafe-default/CapturedParam.java new file mode 100644 index 000000000..756d96026 --- /dev/null +++ b/infer/tests/codetoanalyze/java/nullsafe-default/CapturedParam.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +package codetoanalyze.java.nullsafe_default; + +import javax.annotation.Nullable; + +/** Nullability checks for captured params */ +public class CapturedParam { + + void dereferencingNullableIsBAD(@Nullable Object parameter) { + parameter.toString(); + } + + void dereferencingCapturedNullableShouldBeBAD_FIXME(@Nullable Object parameter) { + Object object = + new Object() { + void foo() { + // Should be disallowed, but it is not the case + // TODO(T53473076) fix the FN. + parameter.toString(); + } + }; + } +} diff --git a/infer/tests/codetoanalyze/java/nullsafe-default/FieldNotNullable.java b/infer/tests/codetoanalyze/java/nullsafe-default/FieldNotNullable.java index 635ca2712..649b17a00 100644 --- a/infer/tests/codetoanalyze/java/nullsafe-default/FieldNotNullable.java +++ b/infer/tests/codetoanalyze/java/nullsafe-default/FieldNotNullable.java @@ -24,9 +24,6 @@ abstract class A { } } -// for butterknife -@interface InjectView {} - class FragmentExample extends Fragment { View view; @@ -156,212 +153,3 @@ class TestInitializer { TestInitializer x = b.build(); } } - -class NestedFieldAccess { - - class C { - @Nullable String s; - } - - class CC { - @Nullable C c; - } - - class CCC { - @Nullable CC cc; - } - - public class Test { - @Nullable String s; - C myc; - - Test() { - myc = new C(); - } - - void test() { - if (s != null) { - int n = s.length(); - } - } - - void test1() { - if (myc.s != null) { - int n = myc.s.length(); - } - } - - void test2(C c) { - if (c.s != null) { - int n = c.s.length(); - } - } - - void test2_local() { - C c = new C(); - if (c.s != null) { - int n = c.s.length(); - } - } - - void test3(CC cc) { - if (cc.c != null && cc.c.s != null) { - int n = cc.c.s.length(); - } - } - - void test4(CCC ccc) { - if (ccc.cc != null && ccc.cc.c != null && ccc.cc.c.s != null) { - int n = ccc.cc.c.s.length(); - } - } - - void test5(@Nullable CCC ccc) { - if (ccc == null || ccc.cc == null || ccc.cc.c == null || ccc.cc.c.s == null) { - } else { - int n = ccc.cc.c.s.length(); - } - } - } - - class TestFunctionsIdempotent { - @Nullable String s; - String dontAssignNull; - - TestFunctionsIdempotent() { - dontAssignNull = ""; - } - - @Nullable - String getS(int n) { - return s; - } - - TestFunctionsIdempotent getSelf() { - return this; - } - - void FlatOK1(TestFunctionsIdempotent x) { - if (getS(3) != null) { - dontAssignNull = getS(3); - } - } - - void FlatOK2(TestFunctionsIdempotent x) { - if (x.getS(3) != null) { - dontAssignNull = x.getS(3); - } - } - - void FlatBAD1(TestFunctionsIdempotent x) { - if (x.getS(3) != null) { - dontAssignNull = getS(3); - } - } - - void FlatBAD2(TestFunctionsIdempotent x) { - if (x.getS(3) != null) { - dontAssignNull = x.getS(4); - } - } - - void NestedOK1() { - if (getSelf().getS(3) != null) { - dontAssignNull = getSelf().getS(3); - } - } - - void NestedOK2() { - if (getSelf().getSelf().getS(3) != null) { - dontAssignNull = getSelf().getSelf().getS(3); - } - } - - void NestedBAD1() { - if (getSelf().getS(3) != null) { - dontAssignNull = getSelf().getS(4); - } - } - - void NestedBAD2() { - if (getS(3) != null) { - dontAssignNull = getSelf().getS(3); - } - } - - void NestedBAD3() { - if (getSelf().getSelf().getS(3) != null) { - dontAssignNull = getSelf().getS(3); - } - } - } - - class TestContainsKey { - void testMapContainsKey(java.util.Map m) { - if (m.containsKey(3)) { - m.get(3).isEmpty(); - } - } - - void testMapContainsKeyInsideWhileLoop(java.util.Map m) { - while (true) { - if (m.containsKey(3)) { - m.get(3).isEmpty(); - } - } - } - - void testImmutableMapContainsKey(com.google.common.collect.ImmutableMap m) { - if (m.containsKey(3)) { - m.get(3).isEmpty(); - } - } - } - - // Test Map.put() - class TestPut { - String dontAssignNull = ""; - - public void putConstString(java.util.Map map, String key) { - map.put(key, "abc"); - dontAssignNull = map.get(key); - } - - public void putNull(java.util.Map map, String key) { - map.put(key, "abc"); - map.put(key, null); - dontAssignNull = map.get(key); - } - - public void putWithContainsKey(java.util.Map map, String key) { - if (!map.containsKey(key)) { - map.put(key, "abc"); - } - dontAssignNull = map.get(key); - } - } - - // support assignments of null to @InjectView fields, generated by butterknife - class SupportButterKnife { - @InjectView String s; - - SupportButterKnife() {} - - void dereferencingIsOK() { - int n = s.length(); - } - - void assignNullIsOK() { - s = null; - } - } - - void methodWithNullableCapturedParameterBad_FN(@Nullable Object parameter) { - Object object = - new Object() { - void foo() { - parameter.toString(); - } - }; - } -} diff --git a/infer/tests/codetoanalyze/java/nullsafe-default/MapNullability.java b/infer/tests/codetoanalyze/java/nullsafe-default/MapNullability.java new file mode 100644 index 000000000..899414c7f --- /dev/null +++ b/infer/tests/codetoanalyze/java/nullsafe-default/MapNullability.java @@ -0,0 +1,140 @@ +/* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +package codetoanalyze.java.nullsafe_default; + +import javax.annotation.Nullable; + +/** Check how we model the behavior of Map nullability */ +public class MapNullability { + + class TestThatGetIsAllowedOnlyAfterContainsKeyWasChecked { + + void usingGetAfterKeyWasCheckedIsOK(java.util.Map m) { + if (m.containsKey(3)) { + m.get(3).isEmpty(); + } + } + + void usingGetWithoutCheckingKeyIsBAD(java.util.Map m) { + m.get(3).isEmpty(); + } + + void usingGetAfterWrongKeyWasCheckedIsBAD(java.util.Map m) { + if (m.containsKey(3)) { + m.get(4).isEmpty(); + } + } + + void usingGetAfterKeyWasCheckedInWhileLoopIsOK(java.util.Map m) { + while (true) { + if (m.containsKey(3)) { + m.get(3).isEmpty(); + } + } + } + + void usingGetAfterWrongKeyWasCheckedInWhileLoopIsBAD(java.util.Map m) { + while (true) { + if (m.containsKey(3)) { + m.get(4).isEmpty(); + } + } + } + + void immutableMap_usingGetAfterKeyWasCheckedIsOK( + com.google.common.collect.ImmutableMap m) { + if (m.containsKey(3)) { + m.get(3).isEmpty(); + } + } + + void immutableMap_usingGetAfterWrongKeyWasCheckedIsBAD( + com.google.common.collect.ImmutableMap m) { + if (m.containsKey(3)) { + m.get(4).isEmpty(); + } + } + } + + public class TestThatGetAfterPutIsAllowed { + String dontAssignNull = ""; + + public void getAfterPutIsOK(java.util.Map map, String key) { + map.put(key, "abc"); + dontAssignNull = map.get(key); + } + + public void getWithoutPutIsBAD(java.util.Map map, String key) { + dontAssignNull = map.get(key); + } + + public void getAfterPutWrongKeyIsBAD( + java.util.Map map, String key, String wrongKey) { + map.put(key, "abc"); + dontAssignNull = map.get(wrongKey); + } + + public void getAfterPutSeveralKeysIsOK(java.util.Map map) { + map.put("key1", "value1"); + map.put("key2", "value1"); + dontAssignNull = map.get("key2"); + dontAssignNull = map.get("key1"); + dontAssignNull = map.get("key2"); + map.put("key3", "value1"); + dontAssignNull = map.get("key1"); + dontAssignNull = map.get("key2"); + dontAssignNull = map.get("key3"); + } + + public void getAfterPutSeveralKeysButGetWrongOneIsBAD(java.util.Map map) { + map.put("key1", "value1"); + map.put("key2", "value1"); + dontAssignNull = map.get("key2"); // OK + dontAssignNull = map.get("wrong_key"); // BAD + } + + public void getAfterPutNonnullIsOK(java.util.Map map, String nonnullValue) { + map.put("key", nonnullValue); + dontAssignNull = map.get("key"); + } + + public void getAfterPutNullableIsBAD( + java.util.Map map, @Nullable String nullableValue) { + map.put("key", nullableValue); + dontAssignNull = map.get("key"); + } + + public void overwriteKeyByNullIsBAD(java.util.Map map, String key) { + map.put(key, "abc"); + map.put(key, null); // Parameter not nullable + dontAssignNull = map.get(key); // BAD + } + + public void overwriteKeyByNonnullIsOK(java.util.Map map, String key) { + map.put(key, null); // Parameter not nullable + map.put(key, "abc"); + dontAssignNull = map.get(key); // OK + } + + public void getAfterConditionalPutIsOK(java.util.Map map, String key) { + if (!map.containsKey(key)) { + map.put(key, "abc"); + } + // OK: map either already contained a key, or we've just put it here! + dontAssignNull = map.get(key); + } + + public void getAfterConditionalPutWrongKeyIsBAD( + java.util.Map map, String key, String wrongKey) { + if (!map.containsKey(key)) { + map.put(wrongKey, "abc"); + } + dontAssignNull = map.get(key); + } + } +} diff --git a/infer/tests/codetoanalyze/java/nullsafe-default/NestedFieldAccess.java b/infer/tests/codetoanalyze/java/nullsafe-default/NestedFieldAccess.java new file mode 100644 index 000000000..a13147ac8 --- /dev/null +++ b/infer/tests/codetoanalyze/java/nullsafe-default/NestedFieldAccess.java @@ -0,0 +1,209 @@ +/* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +package codetoanalyze.java.nullsafe_default; + +import javax.annotation.Nullable; + +public class NestedFieldAccess { + + class C { + @Nullable String s; + } + + class CC { + @Nullable C c; + } + + class CCC { + @Nullable CC cc; + } + + /** + * Tests nullability check patterns for f1.f2.f3, when all components in the chain are nullable. + * (it should require checking of all components in the chain) + */ + public class TestNullableChains { + @Nullable String s; + C myc; + + TestNullableChains() { + myc = new C(); + } + + void field_AccessAfterNullCheckIsOK() { + if (s != null) { + int n = s.length(); + } + } + + void field_AccessWithoutNullCheckIsBad() { + int n = s.length(); + } + + void nestedField_AccessAfterNullCheckIsOK() { + if (myc.s != null) { + int n = myc.s.length(); + } + } + + void nestedField_AccessWithoutNullCheckIsBad() { + int n = myc.s.length(); + } + + void param_AccessAfterNullCheckIsOK(C c) { + if (c.s != null) { + int n = c.s.length(); + } + } + + void param_AccessWithoutNullCheckIsBad(C c) { + int n = c.s.length(); + } + + void local_AccessAfterNullCheckIsOK() { + C c = new C(); + if (c.s != null) { + int n = c.s.length(); + } + } + + void local_AccessWithoutNullCheckIsBad() { + C c = new C(); + int n = c.s.length(); + } + + void deep_AccessWithNullCheckIsOK(CC cc) { + if (cc.c != null && cc.c.s != null) { + int n = cc.c.s.length(); + } + } + + void deep_AccessWithoutNullCheckIsBad(CC cc) { + if (cc.c != null /* && cc.c.s != null */) { + int n = cc.c.s.length(); + } + } + + void veryDeep_AccessWithNullCheckIsOK(CCC ccc) { + if (ccc.cc != null && ccc.cc.c != null && ccc.cc.c.s != null) { + int n = ccc.cc.c.s.length(); + } + } + + void veryDeep_AccessWithoutNullCheckIsBad(CCC ccc) { + if (ccc.cc != null && ccc.cc.c != null /* && ccc.cc.c.s != null */) { + int n = ccc.cc.c.s.length(); + } + } + + void veryDeep_AccessViaOrEarlyReturnIsOK(@Nullable CCC ccc) { + if (ccc == null || ccc.cc == null || ccc.cc.c == null || ccc.cc.c.s == null) { + } else { + int n = ccc.cc.c.s.length(); + } + } + + void veryDeep_IncompleteAccessViaOrEarlyReturnIsBad(@Nullable CCC ccc) { + if (ccc == null || ccc.cc == null || ccc.cc.c == null /*|| ccc.cc.c.s == null*/) { + } else { + int n = ccc.cc.c.s.length(); + } + } + } + + /** + * Tests nullability patterns for chains a().a().a().a().nullable(). Basically nullsafe needs to + * realize that objects returned by a().a() and a().a().a() are different so it should not learn + * anything about the nullability of one based on evidence about the other one. + */ + class TestFunctionsIdempotent { + @Nullable String s; + String dontAssignNull = ""; + + @Nullable + String nullable(int n) { + return s; + } + + TestFunctionsIdempotent getSelf() { + return this; + } + + void chainOf0VsChainOf0IsOK() { + if (nullable(3) != null) { + dontAssignNull = nullable(3); + } + } + + void chainOf0VsChainOf0ParamsMismatchIsBad() { + if (nullable(3) != null) { + dontAssignNull = nullable(4); + } + } + + void otherObjVsItselfIsOK(TestFunctionsIdempotent otherObj) { + if (otherObj.nullable(3) != null) { + dontAssignNull = otherObj.nullable(3); + } + } + + void otherObjVsItselfIsOKParamsMismatchIsBAD(TestFunctionsIdempotent otherObj) { + if (otherObj.nullable(3) != null) { + dontAssignNull = otherObj.nullable(4); + } + } + + void selfVsOtherObjectIsBAD(TestFunctionsIdempotent otherObj) { + if (otherObj.nullable(3) != null) { + dontAssignNull = nullable(3); + } + } + + void chainOf0VsChainOf1IsBad() { + if (nullable(3) != null) { + dontAssignNull = getSelf().nullable(3); + } + } + + void chainOf1VsChainOf0IsBad() { + if (getSelf().nullable(3) != null) { + dontAssignNull = nullable(3); + } + } + + void chainOf1VsChainOf1IsOK() { + if (getSelf().nullable(3) != null) { + dontAssignNull = getSelf().nullable(3); + } + } + + void chainOf1VsChainOf1ParamMismatchIsBad() { + if (getSelf().nullable(3) != null) { + dontAssignNull = getSelf().nullable(4); + } + } + + void chainOf2VsChainOf2IsOK() { + if (getSelf().getSelf().nullable(3) != null) { + dontAssignNull = getSelf().getSelf().nullable(3); + } + } + + void chainOf1VsChainOf2IsBad() { + if (getSelf().nullable(3) != null) { + dontAssignNull = getSelf().getSelf().nullable(3); + } + } + + void chainOf2VsChainOf1IsBad() { + if (getSelf().getSelf().nullable(3) != null) { + dontAssignNull = getSelf().nullable(3); + } + } + } +} diff --git a/infer/tests/codetoanalyze/java/nullsafe-default/issues.exp b/infer/tests/codetoanalyze/java/nullsafe-default/issues.exp index e4cf5611f..5a5b58f1c 100644 --- a/infer/tests/codetoanalyze/java/nullsafe-default/issues.exp +++ b/infer/tests/codetoanalyze/java/nullsafe-default/issues.exp @@ -1,4 +1,10 @@ codetoanalyze/java/nullsafe-default/ActivityFieldNotInitialized.java, codetoanalyze.java.nullsafe_default.ActivityFieldNotInitialized$BadActivityWithOnCreate.(codetoanalyze.java.nullsafe_default.ActivityFieldNotInitialized), 0, ERADICATE_FIELD_NOT_INITIALIZED, no_bucket, WARNING, [Field `ActivityFieldNotInitialized$BadActivityWithOnCreate.field` is not initialized in the constructor and is not declared `@Nullable`] +codetoanalyze/java/nullsafe-default/ButterKnife.java, codetoanalyze.java.nullsafe_default.ButterKnife$TestNotInitialized.(codetoanalyze.java.nullsafe_default.ButterKnife), 0, ERADICATE_FIELD_NOT_INITIALIZED, no_bucket, WARNING, [Field `ButterKnife$TestNotInitialized.notInitializedNormalIsBAD` is not initialized in the constructor and is not declared `@Nullable`] +codetoanalyze/java/nullsafe-default/ButterKnife.java, codetoanalyze.java.nullsafe_default.ButterKnife.assignNullToNormalIsBAD():void, 1, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field `ButterKnife.normal` can be null but is not declared `@Nullable`. (Origin: null constant at line 76)] +codetoanalyze/java/nullsafe-default/ButterKnife.java, codetoanalyze.java.nullsafe_default.ButterKnife.convertingToNotNullableForNullableIsBAD():java.lang.String, 0, ERADICATE_RETURN_NOT_NULLABLE, no_bucket, WARNING, [Method `convertingToNotNullableForNullableIsBAD()` may return null but it is not annotated with `@Nullable`. (Origin: field ButterKnife.nullable at line 47)] +codetoanalyze/java/nullsafe-default/ButterKnife.java, codetoanalyze.java.nullsafe_default.ButterKnife.dereferencingNullableIsBAD():void, 1, ERADICATE_NULLABLE_DEREFERENCE, no_bucket, WARNING, [The value of `ButterKnife.nullable` in the call to `length()` is nullable and is not locally checked for null. (Origin: field ButterKnife.nullable at line 33)] +codetoanalyze/java/nullsafe-default/ButterKnife.java, codetoanalyze.java.nullsafe_default.ButterKnife.passingToNullableForNullableIsBAD():void, 1, ERADICATE_PARAMETER_NOT_NULLABLE, no_bucket, WARNING, [`ButterKnife.f(...)` needs a non-null value in parameter 1 but argument `ButterKnife.nullable` can be null. (Origin: field ButterKnife.nullable at line 61)] +codetoanalyze/java/nullsafe-default/CapturedParam.java, codetoanalyze.java.nullsafe_default.CapturedParam.dereferencingNullableIsBAD(java.lang.Object):void, 1, ERADICATE_NULLABLE_DEREFERENCE, no_bucket, WARNING, [The value of `parameter` in the call to `toString()` is nullable and is not locally checked for null. (Origin: method parameter parameter)] codetoanalyze/java/nullsafe-default/CustomAnnotations.java, codetoanalyze.java.nullsafe_default.CustomAnnotations$TestModeledTrueOnNull.testIsEmptyOrNullBad(java.lang.String):void, 2, ERADICATE_NULLABLE_DEREFERENCE, no_bucket, WARNING, [The value of `string` in the call to `contains(...)` is nullable and is not locally checked for null. (Origin: method parameter string)] codetoanalyze/java/nullsafe-default/CustomAnnotations.java, codetoanalyze.java.nullsafe_default.CustomAnnotations$TestPropagatesNullable.m12Bad1():void, 1, ERADICATE_NULLABLE_DEREFERENCE, no_bucket, WARNING, [The value of `m12(...)` in the call to `length()` is nullable and is not locally checked for null. (Origin: call to m12(...) at line 114)] codetoanalyze/java/nullsafe-default/CustomAnnotations.java, codetoanalyze.java.nullsafe_default.CustomAnnotations$TestPropagatesNullable.m12Bad2():void, 1, ERADICATE_NULLABLE_DEREFERENCE, no_bucket, WARNING, [The value of `m12(...)` in the call to `length()` is nullable and is not locally checked for null. (Origin: call to m12(...) at line 118)] @@ -16,18 +22,11 @@ codetoanalyze/java/nullsafe-default/FieldNotInitialized.java, codetoanalyze.java codetoanalyze/java/nullsafe-default/FieldNotInitialized.java, codetoanalyze.java.nullsafe_default.FieldNotInitialized$Swap.(codetoanalyze.java.nullsafe_default.FieldNotInitialized), 0, ERADICATE_FIELD_NOT_INITIALIZED, no_bucket, WARNING, [Field `FieldNotInitialized$Swap.o1` is not initialized in the constructor and is not declared `@Nullable`] codetoanalyze/java/nullsafe-default/FieldNotInitialized.java, codetoanalyze.java.nullsafe_default.FieldNotInitialized$WriteItself.(codetoanalyze.java.nullsafe_default.FieldNotInitialized), 0, ERADICATE_FIELD_NOT_INITIALIZED, no_bucket, WARNING, [Field `FieldNotInitialized$WriteItself.o` is not initialized in the constructor and is not declared `@Nullable`] codetoanalyze/java/nullsafe-default/FieldNotInitialized.java, codetoanalyze.java.nullsafe_default.FieldNotInitialized.(), 0, ERADICATE_FIELD_NOT_INITIALIZED, no_bucket, WARNING, [Field `FieldNotInitialized.a` is not initialized in the constructor and is not declared `@Nullable`] -codetoanalyze/java/nullsafe-default/FieldNotNullable.java, codetoanalyze.java.nullsafe_default.FieldNotNullable.(java.lang.Integer), -25, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field `FieldNotNullable.static_s` can be null but is not declared `@Nullable`. (Origin: null constant at line 44)] -codetoanalyze/java/nullsafe-default/FieldNotNullable.java, codetoanalyze.java.nullsafe_default.FieldNotNullable.(java.lang.String), -2, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field `FieldNotNullable.static_s` can be null but is not declared `@Nullable`. (Origin: null constant at line 44)] -codetoanalyze/java/nullsafe-default/FieldNotNullable.java, codetoanalyze.java.nullsafe_default.FieldNotNullable.setYNull():void, 1, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field `FieldNotNullable.y` can be null but is not declared `@Nullable`. (Origin: null constant at line 62)] +codetoanalyze/java/nullsafe-default/FieldNotNullable.java, codetoanalyze.java.nullsafe_default.FieldNotNullable.(java.lang.Integer), -25, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field `FieldNotNullable.static_s` can be null but is not declared `@Nullable`. (Origin: null constant at line 41)] +codetoanalyze/java/nullsafe-default/FieldNotNullable.java, codetoanalyze.java.nullsafe_default.FieldNotNullable.(java.lang.String), -2, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field `FieldNotNullable.static_s` can be null but is not declared `@Nullable`. (Origin: null constant at line 41)] +codetoanalyze/java/nullsafe-default/FieldNotNullable.java, codetoanalyze.java.nullsafe_default.FieldNotNullable.setYNull():void, 1, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field `FieldNotNullable.y` can be null but is not declared `@Nullable`. (Origin: null constant at line 59)] codetoanalyze/java/nullsafe-default/FieldNotNullable.java, codetoanalyze.java.nullsafe_default.FieldNotNullable.setYNullable(java.lang.String):void, 1, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field `FieldNotNullable.y` can be null but is not declared `@Nullable`. (Origin: method parameter s)] codetoanalyze/java/nullsafe-default/FieldNotNullable.java, codetoanalyze.java.nullsafe_default.FragmentExample.(), 0, ERADICATE_FIELD_NOT_INITIALIZED, no_bucket, WARNING, [Field `FragmentExample.view` is not initialized in the constructor and is not declared `@Nullable`] -codetoanalyze/java/nullsafe-default/FieldNotNullable.java, codetoanalyze.java.nullsafe_default.NestedFieldAccess$TestFunctionsIdempotent.FlatBAD1(codetoanalyze.java.nullsafe_default.NestedFieldAccess$TestFunctionsIdempotent):void, 2, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field `NestedFieldAccess$TestFunctionsIdempotent.dontAssignNull` can be null but is not declared `@Nullable`. (Origin: call to getS(...) at line 258)] -codetoanalyze/java/nullsafe-default/FieldNotNullable.java, codetoanalyze.java.nullsafe_default.NestedFieldAccess$TestFunctionsIdempotent.FlatBAD2(codetoanalyze.java.nullsafe_default.NestedFieldAccess$TestFunctionsIdempotent):void, 2, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field `NestedFieldAccess$TestFunctionsIdempotent.dontAssignNull` can be null but is not declared `@Nullable`. (Origin: call to getS(...) at line 264)] -codetoanalyze/java/nullsafe-default/FieldNotNullable.java, codetoanalyze.java.nullsafe_default.NestedFieldAccess$TestFunctionsIdempotent.NestedBAD1():void, 2, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field `NestedFieldAccess$TestFunctionsIdempotent.dontAssignNull` can be null but is not declared `@Nullable`. (Origin: call to getS(...) at line 282)] -codetoanalyze/java/nullsafe-default/FieldNotNullable.java, codetoanalyze.java.nullsafe_default.NestedFieldAccess$TestFunctionsIdempotent.NestedBAD2():void, 2, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field `NestedFieldAccess$TestFunctionsIdempotent.dontAssignNull` can be null but is not declared `@Nullable`. (Origin: call to getS(...) at line 288)] -codetoanalyze/java/nullsafe-default/FieldNotNullable.java, codetoanalyze.java.nullsafe_default.NestedFieldAccess$TestFunctionsIdempotent.NestedBAD3():void, 2, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field `NestedFieldAccess$TestFunctionsIdempotent.dontAssignNull` can be null but is not declared `@Nullable`. (Origin: call to getS(...) at line 294)] -codetoanalyze/java/nullsafe-default/FieldNotNullable.java, codetoanalyze.java.nullsafe_default.NestedFieldAccess$TestPut.putNull(java.util.Map,java.lang.String):void, 2, ERADICATE_PARAMETER_NOT_NULLABLE, no_bucket, WARNING, [`Map.put(...)` needs a non-null value in parameter 2 but argument `null` can be null. (Origin: null constant at line 332)] -codetoanalyze/java/nullsafe-default/FieldNotNullable.java, codetoanalyze.java.nullsafe_default.NestedFieldAccess$TestPut.putNull(java.util.Map,java.lang.String):void, 3, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field `NestedFieldAccess$TestPut.dontAssignNull` can be null but is not declared `@Nullable`. (Origin: null constant at line 332)] codetoanalyze/java/nullsafe-default/FieldNotNullable.java, codetoanalyze.java.nullsafe_default.TestInitializerBuilder.build():codetoanalyze.java.nullsafe_default.TestInitializer, 2, ERADICATE_CONDITION_REDUNDANT, no_bucket, WARNING, [The condition TestInitializerBuilder.required1 is always true according to the existing annotations.] codetoanalyze/java/nullsafe-default/FieldNotNullable.java, codetoanalyze.java.nullsafe_default.TestInitializerBuilder.build():codetoanalyze.java.nullsafe_default.TestInitializer, 2, ERADICATE_CONDITION_REDUNDANT, no_bucket, WARNING, [The condition TestInitializerBuilder.required2 is always true according to the existing annotations.] codetoanalyze/java/nullsafe-default/InconsistentSubclassAnnotation.java, codetoanalyze.java.nullsafe_default.ExtendsExternalLibrary.externalMethod2(java.lang.Object):void, 0, ERADICATE_INCONSISTENT_SUBCLASS_PARAMETER_ANNOTATION, no_bucket, WARNING, [First parameter `object` of method `ExtendsExternalLibrary.externalMethod2(...)` is not `@Nullable` but is declared `@Nullable`in the parent class method `SomeExternalClass.externalMethod2(...)`.] @@ -42,6 +41,34 @@ codetoanalyze/java/nullsafe-default/LibraryCalls.java, codetoanalyze.java.nullsa codetoanalyze/java/nullsafe-default/LibraryCalls.java, codetoanalyze.java.nullsafe_default.LibraryCalls.badReferenceDereference(java.lang.ref.Reference):java.lang.String, 1, ERADICATE_NULLABLE_DEREFERENCE, no_bucket, WARNING, [The value of `ref.get()` in the call to `toString()` is nullable and is not locally checked for null. (Origin: call to get() modelled in modelTables.ml at line 19)] codetoanalyze/java/nullsafe-default/LibraryCalls.java, codetoanalyze.java.nullsafe_default.LibraryCalls.badSoftReferenceDereference(java.lang.ref.SoftReference):java.lang.String, 1, ERADICATE_NULLABLE_DEREFERENCE, no_bucket, WARNING, [The value of `ref.get()` in the call to `toString()` is nullable and is not locally checked for null. (Origin: call to get() modelled in modelTables.ml at line 31)] codetoanalyze/java/nullsafe-default/LibraryCalls.java, codetoanalyze.java.nullsafe_default.LibraryCalls.badWeakReferenceDereference(java.lang.ref.WeakReference):java.lang.String, 1, ERADICATE_NULLABLE_DEREFERENCE, no_bucket, WARNING, [The value of `ref.get()` in the call to `toString()` is nullable and is not locally checked for null. (Origin: call to get() modelled in modelTables.ml at line 23)] +codetoanalyze/java/nullsafe-default/MapNullability.java, codetoanalyze.java.nullsafe_default.MapNullability$TestThatGetAfterPutIsAllowed.getAfterConditionalPutWrongKeyIsBAD(java.util.Map,java.lang.String,java.lang.String):void, 5, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field `MapNullability$TestThatGetAfterPutIsAllowed.dontAssignNull` can be null but is not declared `@Nullable`. (Origin: call to get(...) modelled in modelTables.ml at line 137)] +codetoanalyze/java/nullsafe-default/MapNullability.java, codetoanalyze.java.nullsafe_default.MapNullability$TestThatGetAfterPutIsAllowed.getAfterPutNullableIsBAD(java.util.Map,java.lang.String):void, 2, ERADICATE_PARAMETER_NOT_NULLABLE, no_bucket, WARNING, [`Map.put(...)` needs a non-null value in parameter 2 but argument `nullableValue` can be null. (Origin: method parameter nullableValue)] +codetoanalyze/java/nullsafe-default/MapNullability.java, codetoanalyze.java.nullsafe_default.MapNullability$TestThatGetAfterPutIsAllowed.getAfterPutNullableIsBAD(java.util.Map,java.lang.String):void, 3, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field `MapNullability$TestThatGetAfterPutIsAllowed.dontAssignNull` can be null but is not declared `@Nullable`. (Origin: method parameter nullableValue)] +codetoanalyze/java/nullsafe-default/MapNullability.java, codetoanalyze.java.nullsafe_default.MapNullability$TestThatGetAfterPutIsAllowed.getAfterPutSeveralKeysButGetWrongOneIsBAD(java.util.Map):void, 4, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field `MapNullability$TestThatGetAfterPutIsAllowed.dontAssignNull` can be null but is not declared `@Nullable`. (Origin: call to get(...) modelled in modelTables.ml at line 98)] +codetoanalyze/java/nullsafe-default/MapNullability.java, codetoanalyze.java.nullsafe_default.MapNullability$TestThatGetAfterPutIsAllowed.getAfterPutWrongKeyIsBAD(java.util.Map,java.lang.String,java.lang.String):void, 3, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field `MapNullability$TestThatGetAfterPutIsAllowed.dontAssignNull` can be null but is not declared `@Nullable`. (Origin: call to get(...) modelled in modelTables.ml at line 79)] +codetoanalyze/java/nullsafe-default/MapNullability.java, codetoanalyze.java.nullsafe_default.MapNullability$TestThatGetAfterPutIsAllowed.getWithoutPutIsBAD(java.util.Map,java.lang.String):void, 1, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field `MapNullability$TestThatGetAfterPutIsAllowed.dontAssignNull` can be null but is not declared `@Nullable`. (Origin: call to get(...) modelled in modelTables.ml at line 73)] +codetoanalyze/java/nullsafe-default/MapNullability.java, codetoanalyze.java.nullsafe_default.MapNullability$TestThatGetAfterPutIsAllowed.overwriteKeyByNonnullIsOK(java.util.Map,java.lang.String):void, 1, ERADICATE_PARAMETER_NOT_NULLABLE, no_bucket, WARNING, [`Map.put(...)` needs a non-null value in parameter 2 but argument `null` can be null. (Origin: null constant at line 119)] +codetoanalyze/java/nullsafe-default/MapNullability.java, codetoanalyze.java.nullsafe_default.MapNullability$TestThatGetAfterPutIsAllowed.overwriteKeyByNullIsBAD(java.util.Map,java.lang.String):void, 2, ERADICATE_PARAMETER_NOT_NULLABLE, no_bucket, WARNING, [`Map.put(...)` needs a non-null value in parameter 2 but argument `null` can be null. (Origin: null constant at line 114)] +codetoanalyze/java/nullsafe-default/MapNullability.java, codetoanalyze.java.nullsafe_default.MapNullability$TestThatGetAfterPutIsAllowed.overwriteKeyByNullIsBAD(java.util.Map,java.lang.String):void, 3, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field `MapNullability$TestThatGetAfterPutIsAllowed.dontAssignNull` can be null but is not declared `@Nullable`. (Origin: null constant at line 114)] +codetoanalyze/java/nullsafe-default/MapNullability.java, codetoanalyze.java.nullsafe_default.MapNullability$TestThatGetIsAllowedOnlyAfterContainsKeyWasChecked.immutableMap_usingGetAfterWrongKeyWasCheckedIsBAD(com.google.common.collect.ImmutableMap):void, 3, ERADICATE_NULLABLE_DEREFERENCE, no_bucket, WARNING, [The value of `m.get(...)` in the call to `isEmpty()` is nullable and is not locally checked for null. (Origin: call to get(...) modelled in modelTables.ml at line 59)] +codetoanalyze/java/nullsafe-default/MapNullability.java, codetoanalyze.java.nullsafe_default.MapNullability$TestThatGetIsAllowedOnlyAfterContainsKeyWasChecked.usingGetAfterWrongKeyWasCheckedInWhileLoopIsBAD(java.util.Map):void, 3, ERADICATE_NULLABLE_DEREFERENCE, no_bucket, WARNING, [The value of `m.get(...)` in the call to `isEmpty()` is nullable and is not locally checked for null. (Origin: call to get(...) modelled in modelTables.ml at line 44)] +codetoanalyze/java/nullsafe-default/MapNullability.java, codetoanalyze.java.nullsafe_default.MapNullability$TestThatGetIsAllowedOnlyAfterContainsKeyWasChecked.usingGetAfterWrongKeyWasCheckedIsBAD(java.util.Map):void, 2, ERADICATE_NULLABLE_DEREFERENCE, no_bucket, WARNING, [The value of `m.get(...)` in the call to `isEmpty()` is nullable and is not locally checked for null. (Origin: call to get(...) modelled in modelTables.ml at line 29)] +codetoanalyze/java/nullsafe-default/MapNullability.java, codetoanalyze.java.nullsafe_default.MapNullability$TestThatGetIsAllowedOnlyAfterContainsKeyWasChecked.usingGetWithoutCheckingKeyIsBAD(java.util.Map):void, 1, ERADICATE_NULLABLE_DEREFERENCE, no_bucket, WARNING, [The value of `m.get(...)` in the call to `isEmpty()` is nullable and is not locally checked for null. (Origin: call to get(...) modelled in modelTables.ml at line 24)] +codetoanalyze/java/nullsafe-default/NestedFieldAccess.java, codetoanalyze.java.nullsafe_default.NestedFieldAccess$TestFunctionsIdempotent.chainOf0VsChainOf0ParamsMismatchIsBad():void, 2, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field `NestedFieldAccess$TestFunctionsIdempotent.dontAssignNull` can be null but is not declared `@Nullable`. (Origin: call to nullable(...) at line 145)] +codetoanalyze/java/nullsafe-default/NestedFieldAccess.java, codetoanalyze.java.nullsafe_default.NestedFieldAccess$TestFunctionsIdempotent.chainOf0VsChainOf1IsBad():void, 2, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field `NestedFieldAccess$TestFunctionsIdempotent.dontAssignNull` can be null but is not declared `@Nullable`. (Origin: call to nullable(...) at line 169)] +codetoanalyze/java/nullsafe-default/NestedFieldAccess.java, codetoanalyze.java.nullsafe_default.NestedFieldAccess$TestFunctionsIdempotent.chainOf1VsChainOf0IsBad():void, 2, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field `NestedFieldAccess$TestFunctionsIdempotent.dontAssignNull` can be null but is not declared `@Nullable`. (Origin: call to nullable(...) at line 175)] +codetoanalyze/java/nullsafe-default/NestedFieldAccess.java, codetoanalyze.java.nullsafe_default.NestedFieldAccess$TestFunctionsIdempotent.chainOf1VsChainOf1ParamMismatchIsBad():void, 2, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field `NestedFieldAccess$TestFunctionsIdempotent.dontAssignNull` can be null but is not declared `@Nullable`. (Origin: call to nullable(...) at line 187)] +codetoanalyze/java/nullsafe-default/NestedFieldAccess.java, codetoanalyze.java.nullsafe_default.NestedFieldAccess$TestFunctionsIdempotent.chainOf1VsChainOf2IsBad():void, 2, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field `NestedFieldAccess$TestFunctionsIdempotent.dontAssignNull` can be null but is not declared `@Nullable`. (Origin: call to nullable(...) at line 199)] +codetoanalyze/java/nullsafe-default/NestedFieldAccess.java, codetoanalyze.java.nullsafe_default.NestedFieldAccess$TestFunctionsIdempotent.chainOf2VsChainOf1IsBad():void, 2, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field `NestedFieldAccess$TestFunctionsIdempotent.dontAssignNull` can be null but is not declared `@Nullable`. (Origin: call to nullable(...) at line 205)] +codetoanalyze/java/nullsafe-default/NestedFieldAccess.java, codetoanalyze.java.nullsafe_default.NestedFieldAccess$TestFunctionsIdempotent.otherObjVsItselfIsOKParamsMismatchIsBAD(codetoanalyze.java.nullsafe_default.NestedFieldAccess$TestFunctionsIdempotent):void, 2, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field `NestedFieldAccess$TestFunctionsIdempotent.dontAssignNull` can be null but is not declared `@Nullable`. (Origin: call to nullable(...) at line 157)] +codetoanalyze/java/nullsafe-default/NestedFieldAccess.java, codetoanalyze.java.nullsafe_default.NestedFieldAccess$TestFunctionsIdempotent.selfVsOtherObjectIsBAD(codetoanalyze.java.nullsafe_default.NestedFieldAccess$TestFunctionsIdempotent):void, 2, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field `NestedFieldAccess$TestFunctionsIdempotent.dontAssignNull` can be null but is not declared `@Nullable`. (Origin: call to nullable(...) at line 163)] +codetoanalyze/java/nullsafe-default/NestedFieldAccess.java, codetoanalyze.java.nullsafe_default.NestedFieldAccess$TestNullableChains.deep_AccessWithoutNullCheckIsBad(codetoanalyze.java.nullsafe_default.NestedFieldAccess$CC):void, 2, ERADICATE_NULLABLE_DEREFERENCE, no_bucket, WARNING, [The value of `cc.c.s` in the call to `length()` is nullable and is not locally checked for null. (Origin: field NestedFieldAccess$C.s at line 88)] +codetoanalyze/java/nullsafe-default/NestedFieldAccess.java, codetoanalyze.java.nullsafe_default.NestedFieldAccess$TestNullableChains.field_AccessWithoutNullCheckIsBad():void, 1, ERADICATE_NULLABLE_DEREFERENCE, no_bucket, WARNING, [The value of `NestedFieldAccess$TestNullableChains.s` in the call to `length()` is nullable and is not locally checked for null. (Origin: field NestedFieldAccess$TestNullableChains.s at line 45)] +codetoanalyze/java/nullsafe-default/NestedFieldAccess.java, codetoanalyze.java.nullsafe_default.NestedFieldAccess$TestNullableChains.local_AccessWithoutNullCheckIsBad():void, 2, ERADICATE_NULLABLE_DEREFERENCE, no_bucket, WARNING, [The value of `c.s` in the call to `length()` is nullable and is not locally checked for null. (Origin: field NestedFieldAccess$C.s at line 77)] +codetoanalyze/java/nullsafe-default/NestedFieldAccess.java, codetoanalyze.java.nullsafe_default.NestedFieldAccess$TestNullableChains.nestedField_AccessWithoutNullCheckIsBad():void, 1, ERADICATE_NULLABLE_DEREFERENCE, no_bucket, WARNING, [The value of `NestedFieldAccess$TestNullableChains.myc.s` in the call to `length()` is nullable and is not locally checked for null. (Origin: field NestedFieldAccess$C.s at line 55)] +codetoanalyze/java/nullsafe-default/NestedFieldAccess.java, codetoanalyze.java.nullsafe_default.NestedFieldAccess$TestNullableChains.param_AccessWithoutNullCheckIsBad(codetoanalyze.java.nullsafe_default.NestedFieldAccess$C):void, 1, ERADICATE_NULLABLE_DEREFERENCE, no_bucket, WARNING, [The value of `c.s` in the call to `length()` is nullable and is not locally checked for null. (Origin: field NestedFieldAccess$C.s at line 65)] +codetoanalyze/java/nullsafe-default/NestedFieldAccess.java, codetoanalyze.java.nullsafe_default.NestedFieldAccess$TestNullableChains.veryDeep_AccessWithoutNullCheckIsBad(codetoanalyze.java.nullsafe_default.NestedFieldAccess$CCC):void, 2, ERADICATE_NULLABLE_DEREFERENCE, no_bucket, WARNING, [The value of `ccc.cc.c.s` in the call to `length()` is nullable and is not locally checked for null. (Origin: field NestedFieldAccess$C.s at line 100)] +codetoanalyze/java/nullsafe-default/NestedFieldAccess.java, codetoanalyze.java.nullsafe_default.NestedFieldAccess$TestNullableChains.veryDeep_IncompleteAccessViaOrEarlyReturnIsBad(codetoanalyze.java.nullsafe_default.NestedFieldAccess$CCC):void, 3, ERADICATE_NULLABLE_DEREFERENCE, no_bucket, WARNING, [The value of `ccc.cc.c.s` in the call to `length()` is nullable and is not locally checked for null. (Origin: field NestedFieldAccess$C.s at line 114)] codetoanalyze/java/nullsafe-default/NullFieldAccess.java, codetoanalyze.java.nullsafe_default.NullFieldAccess.arrayAccess():java.lang.Object, 1, ERADICATE_NULLABLE_DEREFERENCE, no_bucket, WARNING, [Object `NullFieldAccess.objects` is nullable and is not locally checked for null when accessing element at index `0`. (Origin: field NullFieldAccess.objects at line 56)] codetoanalyze/java/nullsafe-default/NullFieldAccess.java, codetoanalyze.java.nullsafe_default.NullFieldAccess.arrayLength():int, 1, ERADICATE_NULLABLE_DEREFERENCE, no_bucket, WARNING, [Object `NullFieldAccess.objects` is nullable and is not locally checked for null when accessing field `length`. (Origin: field NullFieldAccess.objects at line 52)] codetoanalyze/java/nullsafe-default/NullFieldAccess.java, codetoanalyze.java.nullsafe_default.NullFieldAccess.useInterface(codetoanalyze.java.nullsafe_default.NullFieldAccess$I):int, 2, ERADICATE_NULLABLE_DEREFERENCE, no_bucket, WARNING, [Object `c` is nullable and is not locally checked for null when accessing field `NullFieldAccess$C.n`. (Origin: field NullFieldAccess$I.c at line 45)]