| // RUN: %clang_analyze_cc1 -fobjc-arc -analyzer-checker=core,nullability.NullPassedToNonnull,nullability.NullReturnedFromNonnull -DNOSYSTEMHEADERS=0 -verify %s | |
| // RUN: %clang_analyze_cc1 -fobjc-arc -analyzer-checker=core,nullability.NullPassedToNonnull,nullability.NullReturnedFromNonnull -analyzer-config nullability:NoDiagnoseCallsToSystemHeaders=true -DNOSYSTEMHEADERS=1 -verify %s | |
| #include "Inputs/system-header-simulator-for-nullability.h" | |
| int getRandom(); | |
| typedef struct Dummy { int val; } Dummy; | |
| void takesNullable(Dummy *_Nullable); | |
| void takesNonnull(Dummy *_Nonnull); | |
| Dummy *_Nullable returnsNullable(); | |
| void testBasicRules() { | |
| // The tracking of nullable values is turned off. | |
| Dummy *p = returnsNullable(); | |
| takesNonnull(p); // no warning | |
| Dummy *q = 0; | |
| if (getRandom()) { | |
| takesNullable(q); | |
| takesNonnull(q); // expected-warning {{Null passed to a callee that requires a non-null 1st parameter}} | |
| } | |
| } | |
| Dummy *_Nonnull testNullReturn() { | |
| Dummy *p = 0; | |
| return p; // expected-warning {{Null returned from a function that is expected to return a non-null value}} | |
| } | |
| void onlyReportFirstPreconditionViolationOnPath() { | |
| Dummy *p = 0; | |
| takesNonnull(p); // expected-warning {{Null passed to a callee that requires a non-null 1st parameter}} | |
| takesNonnull(p); // No warning. | |
| // Passing null to nonnull is a sink. Stop the analysis. | |
| int i = 0; | |
| i = 5 / i; // no warning | |
| (void)i; | |
| } | |
| Dummy *_Nonnull doNotWarnWhenPreconditionIsViolatedInTopFunc( | |
| Dummy *_Nonnull p) { | |
| if (!p) { | |
| Dummy *ret = | |
| 0; // avoid compiler warning (which is not generated by the analyzer) | |
| if (getRandom()) | |
| return ret; // no warning | |
| else | |
| return p; // no warning | |
| } else { | |
| return p; | |
| } | |
| } | |
| Dummy *_Nonnull doNotWarnWhenPreconditionIsViolated(Dummy *_Nonnull p) { | |
| if (!p) { | |
| Dummy *ret = | |
| 0; // avoid compiler warning (which is not generated by the analyzer) | |
| if (getRandom()) | |
| return ret; // no warning | |
| else | |
| return p; // no warning | |
| } else { | |
| return p; | |
| } | |
| } | |
| void testPreconditionViolationInInlinedFunction(Dummy *p) { | |
| doNotWarnWhenPreconditionIsViolated(p); | |
| } | |
| void inlinedNullable(Dummy *_Nullable p) { | |
| if (p) return; | |
| } | |
| void inlinedNonnull(Dummy *_Nonnull p) { | |
| if (p) return; | |
| } | |
| void inlinedUnspecified(Dummy *p) { | |
| if (p) return; | |
| } | |
| Dummy *_Nonnull testDefensiveInlineChecks(Dummy * p) { | |
| switch (getRandom()) { | |
| case 1: inlinedNullable(p); break; | |
| case 2: inlinedNonnull(p); break; | |
| case 3: inlinedUnspecified(p); break; | |
| } | |
| if (getRandom()) | |
| takesNonnull(p); | |
| return p; | |
| } | |
| @interface TestObject : NSObject | |
| @end | |
| TestObject *_Nonnull getNonnullTestObject(); | |
| void testObjCARCImplicitZeroInitialization() { | |
| TestObject * _Nonnull implicitlyZeroInitialized; // no-warning | |
| implicitlyZeroInitialized = getNonnullTestObject(); | |
| } | |
| void testObjCARCExplicitZeroInitialization() { | |
| TestObject * _Nonnull explicitlyZeroInitialized = nil; // expected-warning {{nil assigned to a pointer which is expected to have non-null value}} | |
| } | |
| // Under ARC, returned expressions of ObjC objects types are are implicitly | |
| // cast to _Nonnull when the functions return type is _Nonnull, so make | |
| // sure this doesn't implicit cast doesn't suppress a legitimate warning. | |
| TestObject * _Nonnull returnsNilObjCInstanceIndirectly() { | |
| TestObject *local = nil; | |
| return local; // expected-warning {{nil returned from a function that is expected to return a non-null value}} | |
| } | |
| TestObject * _Nonnull returnsNilObjCInstanceIndirectlyWithSupressingCast() { | |
| TestObject *local = nil; | |
| return (TestObject * _Nonnull)local; // no-warning | |
| } | |
| TestObject * _Nonnull returnsNilObjCInstanceDirectly() { | |
| return nil; // expected-warning {{nil returned from a function that is expected to return a non-null value}} | |
| } | |
| TestObject * _Nonnull returnsNilObjCInstanceDirectlyWithSuppressingCast() { | |
| return (TestObject * _Nonnull)nil; // no-warning | |
| } | |
| @interface SomeClass : NSObject | |
| @end | |
| @implementation SomeClass (MethodReturn) | |
| - (SomeClass * _Nonnull)testReturnsNilInNonnull { | |
| SomeClass *local = nil; | |
| return local; // expected-warning {{nil returned from a method that is expected to return a non-null value}} | |
| } | |
| - (SomeClass * _Nonnull)testReturnsCastSuppressedNilInNonnull { | |
| SomeClass *local = nil; | |
| return (SomeClass * _Nonnull)local; // no-warning | |
| } | |
| - (SomeClass * _Nonnull)testReturnsNilInNonnullWhenPreconditionViolated:(SomeClass * _Nonnull) p { | |
| SomeClass *local = nil; | |
| if (!p) // Pre-condition violated here. | |
| return local; // no-warning | |
| else | |
| return p; // no-warning | |
| } | |
| @end | |
| void callFunctionInSystemHeader() { | |
| NSString *s; | |
| s = nil; | |
| NSSystemFunctionTakingNonnull(s); | |
| #if !NOSYSTEMHEADERS | |
| // expected-warning@-2{{nil passed to a callee that requires a non-null 1st parameter}} | |
| #endif | |
| } | |
| void callMethodInSystemHeader() { | |
| NSString *s; | |
| s = nil; | |
| NSSystemClass *sc = [[NSSystemClass alloc] init]; | |
| [sc takesNonnull:s]; | |
| #if !NOSYSTEMHEADERS | |
| // expected-warning@-2{{nil passed to a callee that requires a non-null 1st parameter}} | |
| #endif | |
| } |