157 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			157 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			C++
		
	
	
	
| // RUN: %check_clang_tidy %s misc-throw-by-value-catch-by-reference %t -- -- -std=c++11 -fcxx-exceptions
 | |
| 
 | |
| 
 | |
| class logic_error {
 | |
| public:
 | |
|   logic_error(const char *message) {}
 | |
| };
 | |
| 
 | |
| typedef logic_error *logic_ptr;
 | |
| typedef logic_ptr logic_double_typedef;
 | |
| 
 | |
| int lastException;
 | |
| 
 | |
| template <class T> struct remove_reference { typedef T type; };
 | |
| template <class T> struct remove_reference<T &> { typedef T type; };
 | |
| template <class T> struct remove_reference<T &&> { typedef T type; };
 | |
| 
 | |
| template <typename T> typename remove_reference<T>::type &&move(T &&arg) {
 | |
|   return static_cast<typename remove_reference<T>::type &&>(arg);
 | |
| }
 | |
| 
 | |
| logic_error CreateException() { return logic_error("created"); }
 | |
| 
 | |
| void testThrowFunc() {
 | |
|   throw new logic_error("by pointer");
 | |
|   // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: throw expression throws a pointer; it should throw a non-pointer value instead [misc-throw-by-value-catch-by-reference]
 | |
|   logic_ptr tmp = new logic_error("by pointer");
 | |
|   throw tmp;
 | |
|   // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: throw expression should throw anonymous temporary values instead [misc-throw-by-value-catch-by-reference]
 | |
|   // CHECK-MESSAGES: :[[@LINE-2]]:9: warning: throw expression throws a pointer; it should throw a non-pointer value instead [misc-throw-by-value-catch-by-reference]
 | |
|   throw logic_error("by value");
 | |
|   auto *literal = "test";
 | |
|   throw logic_error(literal);
 | |
|   throw "test string literal";
 | |
|   throw L"throw wide string literal";
 | |
|   const char *characters = 0;
 | |
|   throw characters;
 | |
|   // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: throw expression should throw anonymous temporary values instead [misc-throw-by-value-catch-by-reference]
 | |
|   // CHECK-MESSAGES: :[[@LINE-2]]:9: warning: throw expression throws a pointer; it should throw a non-pointer value instead [misc-throw-by-value-catch-by-reference]
 | |
|   logic_error lvalue("lvalue");
 | |
|   throw lvalue;
 | |
|   // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: throw expression should throw anonymous temporary values instead [misc-throw-by-value-catch-by-reference]
 | |
| 
 | |
|   throw move(lvalue);
 | |
|   int &ex = lastException;
 | |
|   throw ex;
 | |
|   // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: throw expression should throw anonymous temporary values instead [misc-throw-by-value-catch-by-reference]
 | |
|   throw CreateException();
 | |
| }
 | |
| 
 | |
| void throwReferenceFunc(logic_error &ref) { throw ref; }
 | |
| 
 | |
| void catchByPointer() {
 | |
|   try {
 | |
|     testThrowFunc();
 | |
|   } catch (logic_error *e) {
 | |
|     // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: catch handler catches a pointer value; should throw a non-pointer value and catch by reference instead [misc-throw-by-value-catch-by-reference]
 | |
|   }
 | |
| }
 | |
| 
 | |
| void catchByValue() {
 | |
|   try {
 | |
|     testThrowFunc();
 | |
|   } catch (logic_error e) {
 | |
|     // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: catch handler catches a pointer value; should throw a non-pointer value and catch by reference instead [misc-throw-by-value-catch-by-reference]
 | |
|   }
 | |
| }
 | |
| 
 | |
| void catchByReference() {
 | |
|   try {
 | |
|     testThrowFunc();
 | |
|   } catch (logic_error &e) {
 | |
|   }
 | |
| }
 | |
| 
 | |
| void catchByConstReference() {
 | |
|   try {
 | |
|     testThrowFunc();
 | |
|   } catch (const logic_error &e) {
 | |
|   }
 | |
| }
 | |
| 
 | |
| void catchTypedef() {
 | |
|   try {
 | |
|     testThrowFunc();
 | |
|   } catch (logic_ptr) {
 | |
|     // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: catch handler catches a pointer value; should throw a non-pointer value and catch by reference instead [misc-throw-by-value-catch-by-reference]
 | |
|   }
 | |
| }
 | |
| 
 | |
| void catchAll() {
 | |
|   try {
 | |
|     testThrowFunc();
 | |
|   } catch (...) {
 | |
|   }
 | |
| }
 | |
| 
 | |
| void catchLiteral() {
 | |
|   try {
 | |
|     testThrowFunc();
 | |
|   } catch (const char *) {
 | |
|   } catch (const wchar_t *) {
 | |
|     // disabled for now until it is clear
 | |
|     // how to enable them in the test
 | |
|     //} catch (const char16_t*) {
 | |
|     //} catch (const char32_t*) {
 | |
|   }
 | |
| }
 | |
| 
 | |
| // catching fundamentals should not warn
 | |
| void catchFundamental() {
 | |
|   try {
 | |
|     testThrowFunc();
 | |
|   } catch (int) {
 | |
|   } catch (double) {
 | |
|   } catch (unsigned long) {
 | |
|   }
 | |
| }
 | |
| 
 | |
| struct TrivialType {
 | |
|   double x;
 | |
|   double y;
 | |
| };
 | |
| 
 | |
| void catchTrivial() {
 | |
|   try {
 | |
|     testThrowFunc();
 | |
|   } catch (TrivialType) {
 | |
|   }
 | |
| }
 | |
| 
 | |
| typedef logic_error &fine;
 | |
| void additionalTests() {
 | |
|   try {
 | |
|   } catch (int i) {  // ok
 | |
|     throw i;         // ok
 | |
|   } catch (fine e) { // ok
 | |
|     throw e;         // ok
 | |
|   } catch (logic_error *e) {
 | |
|     // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: catch handler catches a pointer value; should throw a non-pointer value and catch by reference instead [misc-throw-by-value-catch-by-reference]
 | |
|     throw e;      // ok, despite throwing a pointer
 | |
|   } catch (...) { // ok
 | |
|     throw;        // ok
 | |
|   }
 | |
| }
 | |
| 
 | |
| struct S {};
 | |
| 
 | |
| S &returnByReference();
 | |
| S returnByValue();
 | |
| 
 | |
| void f() {
 | |
|   throw returnByReference(); // Should diagnose
 | |
|   // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: throw expression should throw anonymous temporary values instead [misc-throw-by-value-catch-by-reference]
 | |
|   throw returnByValue(); // Should not diagnose
 | |
| }
 |