]> granicus.if.org Git - clang/blob - test/Analysis/lambdas.mm
6247f28870fb859219a347a457ec28f7a54b842d
[clang] / test / Analysis / lambdas.mm
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
3 int 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
16 @implementation Sub
17 - (void)callMethodOnSuperInCXXLambda; {
18   // Explicit capture.
19   [self]() {
20     [super superMethod];
21   }();
22
23   // Implicit capture.
24   [=]() {
25     [super superMethod];
26   }();
27 }
28
29 - (void)swapIvars {
30   int tmp = _ivar1;
31   _ivar1 = _ivar2;
32   _ivar2 = tmp;
33 }
34
35 - (void)callMethodOnSelfInCXXLambda; {
36   _ivar1 = 7;
37   _ivar2 = 8;
38   [self]() {
39     [self swapIvars];
40   }();
41
42   clang_analyzer_eval(_ivar1 == 8); // expected-warning{{TRUE}}
43   clang_analyzer_eval(_ivar2 == 7); // expected-warning{{TRUE}}
44 }
45
46 @end
47
48 int getValue();
49 void useValue(int v);
50
51 void castToBlockNoDeadStore() {
52   int v = getValue(); // no-warning
53
54   (void)(void(^)())[v]() { // This capture should count as a use, so no dead store warning above.
55   };
56 }
57
58 void takesBlock(void(^block)());
59
60 void passToFunctionTakingBlockNoDeadStore() {
61   int v = 7; // no-warning
62   int x = 8; // no-warning
63   takesBlock([&v, x]() {
64     (void)v;
65   });
66 }
67
68 void castToBlockAndInline() {
69   int result = ((int(^)(int))[](int p) {
70     return p;
71   })(7);
72
73   clang_analyzer_eval(result == 7); // expected-warning{{TRUE}}
74 }
75
76 void castToBlockWithCaptureAndInline() {
77   int y = 7;
78
79   auto lambda = [y]{ return y; };
80   int(^block)() = lambda;
81
82   int result = block();
83   clang_analyzer_eval(result == 7); // expected-warning{{TRUE}}
84 }
85
86 void castMutableLambdaToBlock() {
87   int x = 0;
88
89   auto lambda = [x]() mutable {
90     x = x + 1;
91     return x;
92    };
93
94   // The block should copy the lambda before capturing.
95   int(^block)() = lambda;
96
97   int r1 = block();
98   clang_analyzer_eval(r1 == 1); // expected-warning{{TRUE}}
99
100   int r2 = block();
101   clang_analyzer_eval(r2 == 2); // expected-warning{{TRUE}}
102
103   // Because block copied the lambda, r3 should be 1.
104   int r3 = lambda();
105   clang_analyzer_eval(r3 == 1); // expected-warning{{TRUE}}
106
107   // Aliasing the block shouldn't copy the lambda.
108   int(^blockAlias)() = block;
109
110   int r4 = blockAlias();
111   clang_analyzer_eval(r4 == 3); // expected-warning{{TRUE}}
112
113   int r5 = block();
114   clang_analyzer_eval(r5 == 4); // expected-warning{{TRUE}}
115
116   // Another copy of lambda
117   int(^blockSecondCopy)() = lambda;
118   int r6 = blockSecondCopy();
119   clang_analyzer_eval(r6 == 2); // expected-warning{{TRUE}}
120 }
121
122 void castLambdaInLocalBlock() {
123   // Make sure we don't emit a spurious diagnostic about the address of a block
124   // escaping in the implicit conversion operator method for lambda-to-block
125   // conversions.
126   auto lambda = []{ }; // no-warning
127
128   void(^block)() = lambda;
129   (void)block;
130 }