/* * 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. */ bool star(); class T { public: int x; T* field; public: int* _Nullable mayReturnNullPointer() { if (star()) { return nullptr; } else { return new int; } } public: T* _Nullable mayReturnNullObject() { if (star()) { return nullptr; } else { return this; } } public: T* doesNotReturnNullObject() { return new T(); } public: void doSomething() {} }; void assignNullableValueBad(T* t) { int* p = t->mayReturnNullPointer(); *p = 42; } void reassigningNullablePointerOkay(T* t) { int* p = t->mayReturnNullPointer(); p = new int; // does not report here *p = 42; // does not report here } void reassigningNullablePointerToNullOkay(T* t) { int* p = t->mayReturnNullPointer(); p = nullptr; // does not report here } void callMethodOnNullableObjectBad(T* t) { t->mayReturnNullObject()->doSomething(); } void callMethodOnNullableObjectOkay(T* t) { T* p = t->mayReturnNullObject(); if (p != nullptr) { p->doSomething(); } } void dereferenceFieldOfNullableObjectBad(T* t) { T* p = t->mayReturnNullObject(); p->x = 42; } void methodCallOnFieldOfNullableObjectBad(T* t) { T* p = t->mayReturnNullObject(); p->field->doSomething(); } void avoidDoubleReportingBad(T* t) { T* p = t->mayReturnNullObject(); p->doSomething(); // reports here p->doSomething(); // does not report here } void nullableAssignmentInOneBranchBad(T* t) { T* p; if (star()) { p = t->mayReturnNullObject(); } else { p = t->doesNotReturnNullObject(); } p->doSomething(); // reports here } void methodCheckedForNullOkay(T* t) { if (t->mayReturnNullObject() != nullptr) { t->mayReturnNullObject()->doSomething(); // does not report here } } void methodCheckedForNullAndReturnOkay(T* t) { if (t->mayReturnNullObject() == nullptr) { return; } t->mayReturnNullObject()->doSomething(); // does not report here } void reportsViolationOutsideOfNullCheckBad(T* t) { if (t->mayReturnNullObject() != nullptr) { t->mayReturnNullObject()->doSomething(); // does not report here } t->mayReturnNullObject()->doSomething(); // reports here } void reportsViolationInNullBranchBad(T* t) { if (t->mayReturnNullObject() == nullptr) { t->mayReturnNullObject()->doSomething(); // reports here } } void reportsViolationInNotNullElseBranchBad(T* t) { if (t->mayReturnNullObject() != nullptr) { } else { t->mayReturnNullObject()->doSomething(); // reports here } } void methodAlwaysCheckedForNullOkay(T* t) { if (star() && t->mayReturnNullObject() != nullptr) { t->mayReturnNullObject()->doSomething(); // does not report here } } void methodNotAlwaysCheckedForNullBad(T* t) { if (star() || t->mayReturnNullObject() != nullptr) { t->mayReturnNullObject()->doSomething(); // reports here } } void onlyReportOnceBad(T* t) { t->mayReturnNullObject()->doSomething(); // reports here // ... t->mayReturnNullObject()->doSomething(); // does not report here } void dereferenceOfAliasesCheckedForNullOkay(T* t) { T* s = t->mayReturnNullObject(); T* r = s; if (r != nullptr) { s->doSomething(); } } void pointerTestOkay(T* t) { T* p = t->mayReturnNullObject(); if (p) { p->doSomething(); } } void pointerTestBad(T* t) { T* p = t->mayReturnNullObject(); if (p) { // ... } p->doSomething(); } void methodTestedForNullOkay(T* t) { if (t->mayReturnNullObject()) { t->mayReturnNullObject()->doSomething(); } }