1// RUN: %check_clang_tidy %s misc-throw-by-value-catch-by-reference %t -- -- -fcxx-exceptions
2
3
4class logic_error {
5public:
6 logic_error(const char *message) {}
7};
8
9typedef logic_error *logic_ptr;
10typedef logic_ptr logic_double_typedef;
11
12int lastException;
13
14template <class T> struct remove_reference { typedef T type; };
15template <class T> struct remove_reference<T &> { typedef T type; };
16template <class T> struct remove_reference<T &&> { typedef T type; };
17
18template <typename T> typename remove_reference<T>::type &&move(T &&arg) {
19 return static_cast<typename remove_reference<T>::type &&>(arg);
20}
21
22logic_error CreateException() { return logic_error("created"); }
23
24void testThrowFunc() {
25 throw new logic_error("by pointer");
26 // 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]
27 logic_ptr tmp = new logic_error("by pointer");
28 throw tmp;
29 // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: throw expression should throw anonymous temporary values instead [misc-throw-by-value-catch-by-reference]
30 // 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]
31 throw logic_error("by value");
32 auto *literal = "test";
33 throw logic_error(literal);
34 throw "test string literal";
35 throw L"throw wide string literal";
36 const char *characters = 0;
37 throw characters;
38 // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: throw expression should throw anonymous temporary values instead [misc-throw-by-value-catch-by-reference]
39 // 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]
40 logic_error lvalue("lvalue");
41 throw lvalue;
42 // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: throw expression should throw anonymous temporary values instead [misc-throw-by-value-catch-by-reference]
43
44 throw move(arg&: lvalue);
45 int &ex = lastException;
46 throw ex;
47 // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: throw expression should throw anonymous temporary values instead [misc-throw-by-value-catch-by-reference]
48 throw CreateException();
49}
50
51void throwReferenceFunc(logic_error &ref) { throw ref; }
52
53void catchByPointer() {
54 try {
55 testThrowFunc();
56 } catch (logic_error *e) {
57 // 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]
58 }
59}
60
61void catchByValue() {
62 try {
63 testThrowFunc();
64 } catch (logic_error e) {
65 // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: catch handler catches by value; should catch by reference instead [misc-throw-by-value-catch-by-reference]
66 }
67}
68
69void catchByReference() {
70 try {
71 testThrowFunc();
72 } catch (logic_error &e) {
73 }
74}
75
76void catchByConstReference() {
77 try {
78 testThrowFunc();
79 } catch (const logic_error &e) {
80 }
81}
82
83void catchTypedef() {
84 try {
85 testThrowFunc();
86 } catch (logic_ptr) {
87 // 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]
88 }
89}
90
91void catchAll() {
92 try {
93 testThrowFunc();
94 } catch (...) {
95 }
96}
97
98void catchLiteral() {
99 try {
100 testThrowFunc();
101 } catch (const char *) {
102 } catch (const wchar_t *) {
103 // disabled for now until it is clear
104 // how to enable them in the test
105 //} catch (const char16_t*) {
106 //} catch (const char32_t*) {
107 }
108}
109
110// catching fundamentals should not warn
111void catchFundamental() {
112 try {
113 testThrowFunc();
114 } catch (int) {
115 } catch (double) {
116 } catch (unsigned long) {
117 }
118}
119
120struct TrivialType {
121 double x;
122 double y;
123};
124
125void catchTrivial() {
126 try {
127 testThrowFunc();
128 } catch (TrivialType) {
129 }
130}
131
132typedef logic_error &fine;
133void additionalTests() {
134 try {
135 } catch (int i) { // ok
136 throw i; // ok
137 } catch (fine e) { // ok
138 throw e; // ok
139 } catch (logic_error *e) {
140 // 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]
141 throw e; // ok, despite throwing a pointer
142 } catch (...) { // ok
143 throw; // ok
144 }
145}
146
147struct S {};
148
149S &returnByReference();
150S returnByValue();
151
152void f() {
153 throw returnByReference(); // Should diagnose
154 // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: throw expression should throw anonymous temporary values instead [misc-throw-by-value-catch-by-reference]
155 throw returnByValue(); // Should not diagnose
156}
157

source code of clang-tools-extra/test/clang-tidy/checkers/misc/throw-by-value-catch-by-reference.cpp