Add an -analyzer-config 'nullability:NoDiagnoseCallsToSystemHeaders' option to the nullability checker. When enabled, this option causes the analyzer to not report about passing null/nullable values to functions and methods declared in system headers. This option is motivated by the observation that large projects may have many nullability warnings. These projects may find warnings about nullability annotations that they have explicitly added themselves higher priority to fix than warnings on calls to system libraries. llvm-svn: 262763
171 lines
5.0 KiB
Plaintext
171 lines
5.0 KiB
Plaintext
// RUN: %clang_cc1 -analyze -fobjc-arc -analyzer-checker=core,nullability.NullPassedToNonnull,nullability.NullReturnedFromNonnull -DNOSYSTEMHEADERS=0 -verify %s
|
|
// RUN: %clang_cc1 -analyze -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 is 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 {{Null is 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 = 0;
|
|
return local; // expected-warning {{Null is returned from a function that is expected to return a non-null value}}
|
|
}
|
|
|
|
TestObject * _Nonnull returnsNilObjCInstanceIndirectlyWithSupressingCast() {
|
|
TestObject *local = 0;
|
|
return (TestObject * _Nonnull)local; // no-warning
|
|
}
|
|
|
|
TestObject * _Nonnull returnsNilObjCInstanceDirectly() {
|
|
return nil; // expected-warning {{Null is 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 {{Null is 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{{Null 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{{Null passed to a callee that requires a non-null 1st parameter}}
|
|
#endif
|
|
}
|