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