forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			144 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
			
		
		
	
	
			144 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
| // 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
 | |
| 
 | |
| int clang_analyzer_eval(int);
 | |
| 
 | |
| @interface Super
 | |
| - (void)superMethod;
 | |
| @end
 | |
| 
 | |
| @interface Sub : Super {
 | |
|   int _ivar1;
 | |
|   int _ivar2;
 | |
| }
 | |
| @end
 | |
| 
 | |
| @implementation Sub
 | |
| - (void)callMethodOnSuperInCXXLambda; {
 | |
|   // Explicit capture.
 | |
|   [self]() {
 | |
|     [super superMethod];
 | |
|   }();
 | |
| 
 | |
|   // Implicit capture.
 | |
|   [=]() {
 | |
|     [super superMethod];
 | |
|   }();
 | |
| }
 | |
| 
 | |
| // Make sure to properly handle super-calls when a block captures
 | |
| // a local variable named 'self'.
 | |
| - (void)callMethodOnSuperInCXXLambdaWithRedefinedSelf; {
 | |
|   /*__weak*/ Sub *weakSelf = self;
 | |
|   // Implicit capture. (Sema outlaws explicit capture of a redefined self
 | |
|   // and a call to super [which uses the original self]).
 | |
|   [=]() {
 | |
|     Sub *self = weakSelf;
 | |
|     [=]() {
 | |
|       [super superMethod];
 | |
|     }();
 | |
|   }();
 | |
| }
 | |
| 
 | |
| - (void)swapIvars {
 | |
|   int tmp = _ivar1;
 | |
|   _ivar1 = _ivar2;
 | |
|   _ivar2 = tmp;
 | |
| }
 | |
| 
 | |
| - (void)callMethodOnSelfInCXXLambda; {
 | |
|   _ivar1 = 7;
 | |
|   _ivar2 = 8;
 | |
|   [self]() {
 | |
|     [self swapIvars];
 | |
|   }();
 | |
| 
 | |
|   clang_analyzer_eval(_ivar1 == 8); // expected-warning{{TRUE}}
 | |
|   clang_analyzer_eval(_ivar2 == 7); // expected-warning{{TRUE}}
 | |
| }
 | |
| 
 | |
| @end
 | |
| 
 | |
| int getValue();
 | |
| void useValue(int v);
 | |
| 
 | |
| void castToBlockNoDeadStore() {
 | |
|   int v = getValue(); // no-warning
 | |
| 
 | |
|   (void)(void(^)())[v]() { // This capture should count as a use, so no dead store warning above.
 | |
|   };
 | |
| }
 | |
| 
 | |
| void takesBlock(void(^block)());
 | |
| 
 | |
| void passToFunctionTakingBlockNoDeadStore() {
 | |
|   int v = 7; // no-warning
 | |
|   int x = 8; // no-warning
 | |
|   takesBlock([&v, x]() {
 | |
|     (void)v;
 | |
|   });
 | |
| }
 | |
| 
 | |
| void castToBlockAndInline() {
 | |
|   int result = ((int(^)(int))[](int p) {
 | |
|     return p;
 | |
|   })(7);
 | |
| 
 | |
|   clang_analyzer_eval(result == 7); // expected-warning{{TRUE}}
 | |
| }
 | |
| 
 | |
| void castToBlockWithCaptureAndInline() {
 | |
|   int y = 7;
 | |
| 
 | |
|   auto lambda = [y]{ return y; };
 | |
|   int(^block)() = lambda;
 | |
| 
 | |
|   int result = block();
 | |
|   clang_analyzer_eval(result == 7); // expected-warning{{TRUE}}
 | |
| }
 | |
| 
 | |
| void castMutableLambdaToBlock() {
 | |
|   int x = 0;
 | |
| 
 | |
|   auto lambda = [x]() mutable {
 | |
|     x = x + 1;
 | |
|     return x;
 | |
|    };
 | |
| 
 | |
|   // The block should copy the lambda before capturing.
 | |
|   int(^block)() = lambda;
 | |
| 
 | |
|   int r1 = block();
 | |
|   clang_analyzer_eval(r1 == 1); // expected-warning{{TRUE}}
 | |
| 
 | |
|   int r2 = block();
 | |
|   clang_analyzer_eval(r2 == 2); // expected-warning{{TRUE}}
 | |
| 
 | |
|   // Because block copied the lambda, r3 should be 1.
 | |
|   int r3 = lambda();
 | |
|   clang_analyzer_eval(r3 == 1); // expected-warning{{TRUE}}
 | |
| 
 | |
|   // Aliasing the block shouldn't copy the lambda.
 | |
|   int(^blockAlias)() = block;
 | |
| 
 | |
|   int r4 = blockAlias();
 | |
|   clang_analyzer_eval(r4 == 3); // expected-warning{{TRUE}}
 | |
| 
 | |
|   int r5 = block();
 | |
|   clang_analyzer_eval(r5 == 4); // expected-warning{{TRUE}}
 | |
| 
 | |
|   // Another copy of lambda
 | |
|   int(^blockSecondCopy)() = lambda;
 | |
|   int r6 = blockSecondCopy();
 | |
|   clang_analyzer_eval(r6 == 2); // expected-warning{{TRUE}}
 | |
| }
 | |
| 
 | |
| void castLambdaInLocalBlock() {
 | |
|   // Make sure we don't emit a spurious diagnostic about the address of a block
 | |
|   // escaping in the implicit conversion operator method for lambda-to-block
 | |
|   // conversions.
 | |
|   auto lambda = []{ }; // no-warning
 | |
| 
 | |
|   void(^block)() = lambda;
 | |
|   (void)block;
 | |
| }
 |