1// 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 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