1 // RUN: %check_clang_tidy %s readability-const-return-type %t
2
3 // p# = positive test
4 // n# = negative test
5
6 namespace std {
7 template< class T >
8 struct add_cv { typedef const volatile T type; };
9
10 template< class T> struct add_const { typedef const T type; };
11
12 template< class T> struct add_volatile { typedef volatile T type; };
13 }
14
p1()15 const int p1() {
16 // CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const int' is 'const'-qualified at the top level, which may reduce code readability without improving const correctness
17 // CHECK-FIXES: int p1() {
18 return 1;
19 }
20
21 const int p15();
22 // CHECK-FIXES: int p15();
23
24 template <typename T>
p31(T v)25 const int p31(T v) { return 2; }
26 // CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const int' is 'const'-qu
27 // CHECK-FIXES: int p31(T v) { return 2; }
28
29 // We detect const-ness even without instantiating T.
30 template <typename T>
p32(T t)31 const T p32(T t) { return t; }
32 // CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const T' is 'const'-qual
33 // CHECK-FIXES: T p32(T t) { return t; }
34
35 // However, if the return type is itself a template instantiation, Clang does
36 // not consider it const-qualified without knowing `T`.
37 template <typename T>
n15(T v)38 typename std::add_const<T>::type n15(T v) { return v; }
39
40 template <bool B>
41 struct MyStruct {};
42
43 template <typename A>
44 class Klazz {
45 public:
Klazz(A)46 Klazz(A) {}
47 };
48
49 class Clazz {
50 public:
p2()51 Clazz *const p2() {
52 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: return type 'Clazz *const' is 'co
53 // CHECK-FIXES: Clazz *p2() {
54 return this;
55 }
56
57 Clazz *const p3();
58 // CHECK-FIXES: Clazz *p3();
59
p4() const60 const int p4() const {
61 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: return type 'const int' is 'const
62 // CHECK-FIXES: int p4() const {
63 return 4;
64 }
65
66 const Klazz<const int>* const p5() const;
67 // CHECK-FIXES: const Klazz<const int>* p5() const;
68
operator ++(int x)69 const Clazz operator++(int x) { // p12
70 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: return type 'const Clazz' is 'const
71 // CHECK-FIXES: Clazz operator++(int x) {
72 }
73
74 struct Strukt {
75 int i;
76 };
77
p6()78 const Strukt p6() {}
79 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: return type 'const Clazz::Strukt' i
80 // CHECK-FIXES: Strukt p6() {}
81
82 // No warning is emitted here, because this is only the declaration. The
83 // warning will be associated with the definition, below.
84 const Strukt* const p7();
85 // CHECK-FIXES: const Strukt* p7();
86
87 // const-qualifier is the first `const` token, but not the first token.
p8()88 static const int p8() {}
89 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: return type 'const int' is 'const'-
90 // CHECK-FIXES: static int p8() {}
91
p9()92 static const Strukt p9() {}
93 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: return type 'const Clazz::Strukt' i
94 // CHECK-FIXES: static Strukt p9() {}
95
n0() const96 int n0() const { return 0; }
97 const Klazz<const int>& n11(const Klazz<const int>) const;
98 };
99
p3()100 Clazz *const Clazz::p3() {
101 // CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'Clazz *const' is 'cons
102 // CHECK-FIXES: Clazz *Clazz::p3() {
103 return this;
104 }
105
p5() const106 const Klazz<const int>* const Clazz::p5() const {}
107 // CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const Klazz<const int> *
108 // CHECK-FIXES: const Klazz<const int>* Clazz::p5() const {}
109
p7()110 const Clazz::Strukt* const Clazz::p7() {}
111 // CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const Clazz::Strukt *con
112 // CHECK-FIXES: const Clazz::Strukt* Clazz::p7() {}
113
114 Clazz *const p10();
115 // CHECK-FIXES: Clazz *p10();
116
p10()117 Clazz *const p10() {
118 // CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'Clazz *const' is 'cons
119 // CHECK-FIXES: Clazz *p10() {
120 return new Clazz();
121 }
122
123 const Clazz bar;
p11()124 const Clazz *const p11() {
125 // CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const Clazz *const' is
126 // CHECK-FIXES: const Clazz *p11() {
127 return &bar;
128 }
129
p12()130 const Klazz<const int> p12() {}
131 // CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const Klazz<const int>'
132 // CHECK-FIXES: Klazz<const int> p12() {}
133
p33()134 const Klazz<const Klazz<const int>> p33() {}
135 // CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const Klazz<
136 // CHECK-FIXES: Klazz<const Klazz<const int>> p33() {}
137
p13()138 const Klazz<const int>* const p13() {}
139 // CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const Klazz<const int> *
140 // CHECK-FIXES: const Klazz<const int>* p13() {}
141
p14()142 const Klazz<const int>* const volatile p14() {}
143 // CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const Klazz<const int> *
144 // CHECK-FIXES: const Klazz<const int>* volatile p14() {}
145
146 const MyStruct<0 < 1> p34() {}
147 // CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const MyStruct<0 < 1>'
148 // CHECK-FIXES: MyStruct<0 < 1> p34() {}
149
150 MyStruct<0 < 1> const p35() {}
151 // CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const MyStruct<0 < 1>'
152 // CHECK-FIXES: MyStruct<0 < 1> p35() {}
153
154 Klazz<MyStruct<0 < 1> const> const p36() {}
155 // CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const Klazz<const MyStru
156 // CHECK-FIXES: Klazz<MyStruct<0 < 1> const> p36() {}
157
158 const Klazz<MyStruct<0 < 1> const> *const p37() {}
159 // CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const Klazz<const MyStru
160 // CHECK-FIXES: const Klazz<MyStruct<0 < 1> const> *p37() {}
161
162 Klazz<const MyStruct<0 < 1>> const p38() {}
163 // CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const Klazz<const MyStru
164 // CHECK-FIXES: Klazz<const MyStruct<0 < 1>> p38() {}
165
166 const Klazz<const MyStruct<0 < 1>> p39() {}
167 // CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const Klazz<
168 // CHECK-FIXES: Klazz<const MyStruct<0 < 1>> p39() {}
169
p40()170 const Klazz<const MyStruct<(0 > 1)>> p40() {}
171 // CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const Klazz<const MyStru
172 // CHECK-FIXES: Klazz<const MyStruct<(0 > 1)>> p40() {}
173
174 // re-declaration of p15.
175 const int p15();
176 // CHECK-FIXES: int p15();
177
p15()178 const int p15() {
179 // CHECK-MESSAGES: [[@LINE-1]]:1: warning:
180 // CHECK-FIXES: int p15() {
181 return 0;
182 }
183
184 // Exercise the lexer.
185
p16()186 const /* comment */ /* another comment*/ int p16() { return 0; }
187 // CHECK-MESSAGES: [[@LINE-1]]:1: warning:
188 // CHECK-FIXES: /* comment */ /* another comment*/ int p16() { return 0; }
189
190 /* comment */ const
191 // CHECK-MESSAGES: [[@LINE-1]]:15: warning:
192 // CHECK-FIXES: /* comment */
193 // more
p17()194 /* another comment*/ int p17() { return 0; }
195
196 // Test cases where the `const` token lexically is hidden behind some form of
197 // indirection.
198
199 #define CONSTINT const int
p18()200 CONSTINT p18() {}
201 // CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const int' is 'const'-qu
202
203 #define CONST const
p19()204 CONST int p19() {}
205 // CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const int' is 'const'-qu
206
207 using ty = const int;
p21()208 ty p21() {}
209 // CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'ty' (aka 'const int') is
210
211 typedef const int ty2;
p22()212 ty2 p22() {}
213 // CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'ty2' (aka 'const int') i
214
215 // Declaration uses a macro, while definition doesn't. In this case, we won't
216 // fix the declaration, and will instead issue a warning.
217 CONST int p23();
218 // CHECK-NOTE: [[@LINE-1]]:1: note: could not transform this declaration
219
220 const int p23();
221 // CHECK-FIXES: int p23();
222
p23()223 const int p23() { return 3; }
224 // CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const int' is 'const'-qu
225 // CHECK-FIXES: int p23() { return 3; }
226
p24()227 int const p24() { return 3; }
228 // CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const int' is 'const'-qu
229 // CHECK-FIXES: int p24() { return 3; }
230
p25(const int * p)231 int const * const p25(const int* p) { return p; }
232 // CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const int *const' is 'co
233 // CHECK-FIXES: int const * p25(const int* p) { return p; }
234
235 // We cannot (yet) fix instances that use trailing return types, but we can
236 // warn.
p26()237 auto p26() -> const int { return 3; }
238 // CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const int' is 'const'-qu
p27()239 auto p27() -> int const { return 3; }
240 // CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const int' is 'const'-qu
241
p28()242 std::add_const<int>::type p28() { return 3; }
243 // CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'std::add_const<int>::typ
244
245 // p29, p30 are based on
246 // llvm/projects/test-suite/SingleSource/Benchmarks/Misc-C++-EH/spirit.cpp:
247 template <class T>
p29(T const & t)248 Klazz<T const> const p29(T const &t) { return {}; }
249 // CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const Klazz<const T>' is
250 // CHECK-FIXES: Klazz<T const> p29(T const &t) { return {}; }
251
p30(char const * s)252 Klazz<char const *> const p30(char const *s) { return s; }
253 // CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const Klazz<const char *
254 // CHECK-FIXES: Klazz<char const *> p30(char const *s) { return s; }
255
256 const int n1 = 1;
257 const Clazz n2 = Clazz();
258 const Clazz* n3 = new Clazz();
259 Clazz *const n4 = new Clazz();
260 const Clazz *const n5 = new Clazz();
261 constexpr int n6 = 6;
n7()262 constexpr int n7() { return 8; }
263 const int eight = 8;
n8()264 constexpr const int* n8() { return &eight; }
265 Klazz<const int> n9();
266 const Klazz<const int>* n10();
n11(const Klazz<const int>) const267 const Klazz<const int>& Clazz::n11(const Klazz<const int>) const {}
268
269 // Declaration only.
270 const int n14();
271
272 int **const * n_multiple_ptr();
273 int *const & n_pointer_ref();
274