You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
210 lines
4.9 KiB
210 lines
4.9 KiB
5 years ago
|
/*
|
||
|
* 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);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|