1 | // RUN: %check_clang_tidy %s misc-throw-by-value-catch-by-reference %t -- -- -fcxx-exceptions |
2 | |
3 | |
4 | class logic_error { |
5 | public: |
6 | logic_error(const char *message) {} |
7 | }; |
8 | |
9 | typedef logic_error *logic_ptr; |
10 | typedef logic_ptr logic_double_typedef; |
11 | |
12 | int lastException; |
13 | |
14 | template <class T> struct remove_reference { typedef T type; }; |
15 | template <class T> struct remove_reference<T &> { typedef T type; }; |
16 | template <class T> struct remove_reference<T &&> { typedef T type; }; |
17 | |
18 | template <typename T> typename remove_reference<T>::type &&move(T &&arg) { |
19 | return static_cast<typename remove_reference<T>::type &&>(arg); |
20 | } |
21 | |
22 | logic_error CreateException() { return logic_error("created" ); } |
23 | |
24 | void 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 | |
51 | void throwReferenceFunc(logic_error &ref) { throw ref; } |
52 | |
53 | void 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 | |
61 | void 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 | |
69 | void catchByReference() { |
70 | try { |
71 | testThrowFunc(); |
72 | } catch (logic_error &e) { |
73 | } |
74 | } |
75 | |
76 | void catchByConstReference() { |
77 | try { |
78 | testThrowFunc(); |
79 | } catch (const logic_error &e) { |
80 | } |
81 | } |
82 | |
83 | void 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 | |
91 | void catchAll() { |
92 | try { |
93 | testThrowFunc(); |
94 | } catch (...) { |
95 | } |
96 | } |
97 | |
98 | void 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 |
111 | void catchFundamental() { |
112 | try { |
113 | testThrowFunc(); |
114 | } catch (int) { |
115 | } catch (double) { |
116 | } catch (unsigned long) { |
117 | } |
118 | } |
119 | |
120 | struct TrivialType { |
121 | double x; |
122 | double y; |
123 | }; |
124 | |
125 | void catchTrivial() { |
126 | try { |
127 | testThrowFunc(); |
128 | } catch (TrivialType) { |
129 | } |
130 | } |
131 | |
132 | typedef logic_error &fine; |
133 | void 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 | |
147 | struct S {}; |
148 | |
149 | S &returnByReference(); |
150 | S returnByValue(); |
151 | |
152 | void 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 | |