1// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-config suppress-inlined-defensive-checks=true -verify %s
2
3typedef signed char BOOL;
4typedef struct objc_class *Class;
5typedef struct objc_object {
6  Class isa;
7} *id;
8@protocol NSObject  - (BOOL)isEqual:(id)object; @end
9@interface NSObject <NSObject> {}
10+(id)alloc;
11+(id)new;
12-(id)init;
13-(id)autorelease;
14-(id)copy;
15- (Class)class;
16-(id)retain;
17@end
18
19// Check that inline defensive checks is triggered for null expressions
20// within CompoundLiteralExpr.
21typedef union {
22  struct dispatch_object_s *_do;
23  struct dispatch_source_s *_ds;
24} dispatch_object_t __attribute__((__transparent_union__));
25typedef struct dispatch_source_s *dispatch_source_t;
26
27extern __attribute__((visibility("default"))) __attribute__((__nonnull__)) __attribute__((__nothrow__))
28void
29dispatch_resume(dispatch_object_t object);
30
31@interface AppDelegate : NSObject {
32@protected
33	dispatch_source_t p;
34}
35@end
36@implementation AppDelegate
37- (void)updateDeleteTimer {
38	if (p != ((void*)0))
39		;
40}
41- (void)createAndStartDeleteTimer {
42  [self updateDeleteTimer];
43  dispatch_resume(p); // no warning
44}
45@end
46
47// Test nil receiver suppression.
48// We only suppress on nil receiver if the nil value is directly causing the bug.
49@interface Foo {
50@public
51  int x;
52}
53- (Foo *)getFooPtr;
54@end
55
56Foo *retNil() {
57  return 0;
58}
59
60Foo *retInputOrNil(Foo *p) {
61  if (p)
62    return p;
63  return 0;
64}
65
66void idc(Foo *p) {
67  if (p)
68    ;
69}
70
71int testNilReceiver(Foo* fPtr) {
72  if (fPtr)
73    ;
74  // On a path where fPtr is nil, mem should be nil.
75  Foo *mem = [fPtr getFooPtr];
76  return mem->x; // expected-warning {{Access to instance variable 'x' results in a dereference of a null pointer}}
77}
78
79int suppressNilReceiverRetNullCond(Foo* fPtr) {
80  unsigned zero = 0;
81  fPtr = retInputOrNil(fPtr);
82  // On a path where fPtr is nzil, mem should be nil.
83  Foo *mem = [fPtr getFooPtr];
84  return mem->x;
85}
86
87int suppressNilReceiverRetNullCondCast(id fPtr) {
88  unsigned zero = 0;
89  fPtr = retInputOrNil(fPtr);
90  // On a path where fPtr is nzil, mem should be nil.
91  Foo *mem = ((id)([(Foo*)(fPtr) getFooPtr]));
92  return mem->x;
93}
94
95int dontSuppressNilReceiverRetNullCond(Foo* fPtr) {
96  unsigned zero = 0;
97  fPtr = retInputOrNil(fPtr);
98  // On a path where fPtr is nil, mem should be nil.
99  // The warning is not suppressed because the receiver being nil is not
100  // directly related to the value that triggers the warning.
101  Foo *mem = [fPtr getFooPtr];
102  if (!mem)
103    return 5/zero; // expected-warning {{Division by zero}}
104  return 0;
105}
106
107int dontSuppressNilReceiverRetNull(Foo* fPtr) {
108  unsigned zero = 0;
109  fPtr = retNil();
110  // On a path where fPtr is nil, mem should be nil.
111  // The warning is not suppressed because the receiver being nil is not
112  // directly related to the value that triggers the warning.
113  Foo *mem = [fPtr getFooPtr];
114  if (!mem)
115    return 5/zero; // expected-warning {{Division by zero}}
116  return 0;
117}
118
119int dontSuppressNilReceiverIDC(Foo* fPtr) {
120  unsigned zero = 0;
121  idc(fPtr);
122  // On a path where fPtr is nil, mem should be nil.
123  // The warning is not suppressed because the receiver being nil is not
124  // directly related to the value that triggers the warning.
125  Foo *mem = [fPtr getFooPtr];
126  if (!mem)
127    return 5/zero; // expected-warning {{Division by zero}}
128  return 0;
129}
130