blob: 120b07eecc71ef93dfd6dc258fa1f8eb8acea0a7 [file] [log] [blame]
// 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 by value; should 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
}