1// RUN: %clang_cc1 -std=c++11 -fsyntax-only -fblocks -Wno-objc-root-class -analyze -analyzer-checker=core,deadcode,debug.ExprInspection -analyzer-config inline-lambdas=true -verify %s
2
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
15@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
28// 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
42- (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
60
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
86  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}}
133}
134
135void castLambdaInLocalBlock() {
136  // 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
140
141  void(^block)() = lambda;
142  (void)block;
143}
144