xref: /aosp_15_r20/external/clang/test/Analysis/lambdas.mm (revision 67e74705e28f6214e480b399dd47ea732279e315)
1*67e74705SXin Li// 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*67e74705SXin Li
3*67e74705SXin Liint clang_analyzer_eval(int);
4*67e74705SXin Li
5*67e74705SXin Li@interface Super
6*67e74705SXin Li- (void)superMethod;
7*67e74705SXin Li@end
8*67e74705SXin Li
9*67e74705SXin Li@interface Sub : Super {
10*67e74705SXin Li  int _ivar1;
11*67e74705SXin Li  int _ivar2;
12*67e74705SXin Li}
13*67e74705SXin Li@end
14*67e74705SXin Li
15*67e74705SXin Li@implementation Sub
16*67e74705SXin Li- (void)callMethodOnSuperInCXXLambda; {
17*67e74705SXin Li  // Explicit capture.
18*67e74705SXin Li  [self]() {
19*67e74705SXin Li    [super superMethod];
20*67e74705SXin Li  }();
21*67e74705SXin Li
22*67e74705SXin Li  // Implicit capture.
23*67e74705SXin Li  [=]() {
24*67e74705SXin Li    [super superMethod];
25*67e74705SXin Li  }();
26*67e74705SXin Li}
27*67e74705SXin Li
28*67e74705SXin Li// Make sure to properly handle super-calls when a block captures
29*67e74705SXin Li// a local variable named 'self'.
30*67e74705SXin Li- (void)callMethodOnSuperInCXXLambdaWithRedefinedSelf; {
31*67e74705SXin Li  /*__weak*/ Sub *weakSelf = self;
32*67e74705SXin Li  // Implicit capture. (Sema outlaws explicit capture of a redefined self
33*67e74705SXin Li  // and a call to super [which uses the original self]).
34*67e74705SXin Li  [=]() {
35*67e74705SXin Li    Sub *self = weakSelf;
36*67e74705SXin Li    [=]() {
37*67e74705SXin Li      [super superMethod];
38*67e74705SXin Li    }();
39*67e74705SXin Li  }();
40*67e74705SXin Li}
41*67e74705SXin Li
42*67e74705SXin Li- (void)swapIvars {
43*67e74705SXin Li  int tmp = _ivar1;
44*67e74705SXin Li  _ivar1 = _ivar2;
45*67e74705SXin Li  _ivar2 = tmp;
46*67e74705SXin Li}
47*67e74705SXin Li
48*67e74705SXin Li- (void)callMethodOnSelfInCXXLambda; {
49*67e74705SXin Li  _ivar1 = 7;
50*67e74705SXin Li  _ivar2 = 8;
51*67e74705SXin Li  [self]() {
52*67e74705SXin Li    [self swapIvars];
53*67e74705SXin Li  }();
54*67e74705SXin Li
55*67e74705SXin Li  clang_analyzer_eval(_ivar1 == 8); // expected-warning{{TRUE}}
56*67e74705SXin Li  clang_analyzer_eval(_ivar2 == 7); // expected-warning{{TRUE}}
57*67e74705SXin Li}
58*67e74705SXin Li
59*67e74705SXin Li@end
60*67e74705SXin Li
61*67e74705SXin Liint getValue();
62*67e74705SXin Livoid useValue(int v);
63*67e74705SXin Li
64*67e74705SXin Livoid castToBlockNoDeadStore() {
65*67e74705SXin Li  int v = getValue(); // no-warning
66*67e74705SXin Li
67*67e74705SXin Li  (void)(void(^)())[v]() { // This capture should count as a use, so no dead store warning above.
68*67e74705SXin Li  };
69*67e74705SXin Li}
70*67e74705SXin Li
71*67e74705SXin Livoid takesBlock(void(^block)());
72*67e74705SXin Li
73*67e74705SXin Livoid passToFunctionTakingBlockNoDeadStore() {
74*67e74705SXin Li  int v = 7; // no-warning
75*67e74705SXin Li  int x = 8; // no-warning
76*67e74705SXin Li  takesBlock([&v, x]() {
77*67e74705SXin Li    (void)v;
78*67e74705SXin Li  });
79*67e74705SXin Li}
80*67e74705SXin Li
81*67e74705SXin Livoid castToBlockAndInline() {
82*67e74705SXin Li  int result = ((int(^)(int))[](int p) {
83*67e74705SXin Li    return p;
84*67e74705SXin Li  })(7);
85*67e74705SXin Li
86*67e74705SXin Li  clang_analyzer_eval(result == 7); // expected-warning{{TRUE}}
87*67e74705SXin Li}
88*67e74705SXin Li
89*67e74705SXin Livoid castToBlockWithCaptureAndInline() {
90*67e74705SXin Li  int y = 7;
91*67e74705SXin Li
92*67e74705SXin Li  auto lambda = [y]{ return y; };
93*67e74705SXin Li  int(^block)() = lambda;
94*67e74705SXin Li
95*67e74705SXin Li  int result = block();
96*67e74705SXin Li  clang_analyzer_eval(result == 7); // expected-warning{{TRUE}}
97*67e74705SXin Li}
98*67e74705SXin Li
99*67e74705SXin Livoid castMutableLambdaToBlock() {
100*67e74705SXin Li  int x = 0;
101*67e74705SXin Li
102*67e74705SXin Li  auto lambda = [x]() mutable {
103*67e74705SXin Li    x = x + 1;
104*67e74705SXin Li    return x;
105*67e74705SXin Li   };
106*67e74705SXin Li
107*67e74705SXin Li  // The block should copy the lambda before capturing.
108*67e74705SXin Li  int(^block)() = lambda;
109*67e74705SXin Li
110*67e74705SXin Li  int r1 = block();
111*67e74705SXin Li  clang_analyzer_eval(r1 == 1); // expected-warning{{TRUE}}
112*67e74705SXin Li
113*67e74705SXin Li  int r2 = block();
114*67e74705SXin Li  clang_analyzer_eval(r2 == 2); // expected-warning{{TRUE}}
115*67e74705SXin Li
116*67e74705SXin Li  // Because block copied the lambda, r3 should be 1.
117*67e74705SXin Li  int r3 = lambda();
118*67e74705SXin Li  clang_analyzer_eval(r3 == 1); // expected-warning{{TRUE}}
119*67e74705SXin Li
120*67e74705SXin Li  // Aliasing the block shouldn't copy the lambda.
121*67e74705SXin Li  int(^blockAlias)() = block;
122*67e74705SXin Li
123*67e74705SXin Li  int r4 = blockAlias();
124*67e74705SXin Li  clang_analyzer_eval(r4 == 3); // expected-warning{{TRUE}}
125*67e74705SXin Li
126*67e74705SXin Li  int r5 = block();
127*67e74705SXin Li  clang_analyzer_eval(r5 == 4); // expected-warning{{TRUE}}
128*67e74705SXin Li
129*67e74705SXin Li  // Another copy of lambda
130*67e74705SXin Li  int(^blockSecondCopy)() = lambda;
131*67e74705SXin Li  int r6 = blockSecondCopy();
132*67e74705SXin Li  clang_analyzer_eval(r6 == 2); // expected-warning{{TRUE}}
133*67e74705SXin Li}
134*67e74705SXin Li
135*67e74705SXin Livoid castLambdaInLocalBlock() {
136*67e74705SXin Li  // Make sure we don't emit a spurious diagnostic about the address of a block
137*67e74705SXin Li  // escaping in the implicit conversion operator method for lambda-to-block
138*67e74705SXin Li  // conversions.
139*67e74705SXin Li  auto lambda = []{ }; // no-warning
140*67e74705SXin Li
141*67e74705SXin Li  void(^block)() = lambda;
142*67e74705SXin Li  (void)block;
143*67e74705SXin Li}
144