blob: d2b8e7b3535615e7017c1e29444b9e58b04cc2c6 [file] [log] [blame]
Dominic Chen184c6242017-03-03 18:02:02 +00001// RUN: %clang_analyze_cc1 -std=c++11 -fblocks -Wno-objc-root-class -analyzer-checker=core,deadcode,debug.ExprInspection -analyzer-config inline-lambdas=true -verify %s
Devin Coughlin1d405832015-11-15 17:48:22 +00002
3int clang_analyzer_eval(int);
4
5@interface Super
6- (void)superMethod;
7@end
8
9@interface Sub : Super {
10 int _ivar1;
11 int _ivar2;
12}
13@end
14
Devin Coughlin1d405832015-11-15 17:48:22 +000015@implementation Sub
16- (void)callMethodOnSuperInCXXLambda; {
17 // Explicit capture.
18 [self]() {
19 [super superMethod];
20 }();
21
22 // Implicit capture.
23 [=]() {
24 [super superMethod];
25 }();
26}
27
Devin Coughlinc289b742016-02-23 22:26:04 +000028// Make sure to properly handle super-calls when a block captures
29// a local variable named 'self'.
30- (void)callMethodOnSuperInCXXLambdaWithRedefinedSelf; {
31 /*__weak*/ Sub *weakSelf = self;
32 // Implicit capture. (Sema outlaws explicit capture of a redefined self
33 // and a call to super [which uses the original self]).
34 [=]() {
35 Sub *self = weakSelf;
36 [=]() {
37 [super superMethod];
38 }();
39 }();
40}
41
Devin Coughlin1d405832015-11-15 17:48:22 +000042- (void)swapIvars {
43 int tmp = _ivar1;
44 _ivar1 = _ivar2;
45 _ivar2 = tmp;
46}
47
48- (void)callMethodOnSelfInCXXLambda; {
49 _ivar1 = 7;
50 _ivar2 = 8;
51 [self]() {
52 [self swapIvars];
53 }();
54
55 clang_analyzer_eval(_ivar1 == 8); // expected-warning{{TRUE}}
56 clang_analyzer_eval(_ivar2 == 7); // expected-warning{{TRUE}}
57}
58
59@end
Devin Coughlinb6029b72015-11-25 22:35:37 +000060
61int getValue();
62void useValue(int v);
63
64void castToBlockNoDeadStore() {
65 int v = getValue(); // no-warning
66
67 (void)(void(^)())[v]() { // This capture should count as a use, so no dead store warning above.
68 };
69}
70
71void takesBlock(void(^block)());
72
73void passToFunctionTakingBlockNoDeadStore() {
74 int v = 7; // no-warning
75 int x = 8; // no-warning
76 takesBlock([&v, x]() {
77 (void)v;
78 });
79}
80
81void castToBlockAndInline() {
82 int result = ((int(^)(int))[](int p) {
83 return p;
84 })(7);
85
Devin Coughlinebeed882015-12-04 05:00:36 +000086 clang_analyzer_eval(result == 7); // expected-warning{{TRUE}}
87}
88
89void castToBlockWithCaptureAndInline() {
90 int y = 7;
91
92 auto lambda = [y]{ return y; };
93 int(^block)() = lambda;
94
95 int result = block();
96 clang_analyzer_eval(result == 7); // expected-warning{{TRUE}}
97}
98
99void castMutableLambdaToBlock() {
100 int x = 0;
101
102 auto lambda = [x]() mutable {
103 x = x + 1;
104 return x;
105 };
106
107 // The block should copy the lambda before capturing.
108 int(^block)() = lambda;
109
110 int r1 = block();
111 clang_analyzer_eval(r1 == 1); // expected-warning{{TRUE}}
112
113 int r2 = block();
114 clang_analyzer_eval(r2 == 2); // expected-warning{{TRUE}}
115
116 // Because block copied the lambda, r3 should be 1.
117 int r3 = lambda();
118 clang_analyzer_eval(r3 == 1); // expected-warning{{TRUE}}
119
120 // Aliasing the block shouldn't copy the lambda.
121 int(^blockAlias)() = block;
122
123 int r4 = blockAlias();
124 clang_analyzer_eval(r4 == 3); // expected-warning{{TRUE}}
125
126 int r5 = block();
127 clang_analyzer_eval(r5 == 4); // expected-warning{{TRUE}}
128
129 // Another copy of lambda
130 int(^blockSecondCopy)() = lambda;
131 int r6 = blockSecondCopy();
132 clang_analyzer_eval(r6 == 2); // expected-warning{{TRUE}}
Devin Coughlinb6029b72015-11-25 22:35:37 +0000133}
134
135void castLambdaInLocalBlock() {
Devin Coughlindfde6552015-12-03 19:41:24 +0000136 // Make sure we don't emit a spurious diagnostic about the address of a block
137 // escaping in the implicit conversion operator method for lambda-to-block
138 // conversions.
139 auto lambda = []{ }; // no-warning
Devin Coughlinb6029b72015-11-25 22:35:37 +0000140
141 void(^block)() = lambda;
142 (void)block;
143}