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 <typename A>
41 class Klazz {
42 public:
Klazz(A)43   Klazz(A) {}
44 };
45 
46 class Clazz {
47  public:
p2()48   Clazz *const p2() {
49     // CHECK-MESSAGES: [[@LINE-1]]:3: warning: return type 'Clazz *const' is 'co
50     // CHECK-FIXES: Clazz *p2() {
51     return this;
52   }
53 
54   Clazz *const p3();
55   // CHECK-FIXES: Clazz *p3();
56 
p4() const57   const int p4() const {
58     // CHECK-MESSAGES: [[@LINE-1]]:3: warning: return type 'const int' is 'const
59     // CHECK-FIXES: int p4() const {
60     return 4;
61   }
62 
63   const Klazz<const int>* const p5() const;
64   // CHECK-FIXES: const Klazz<const int>* p5() const;
65 
operator ++(int x)66   const Clazz operator++(int x) {  //  p12
67   // CHECK-MESSAGES: [[@LINE-1]]:3: warning: return type 'const Clazz' is 'const
68   // CHECK-FIXES: Clazz operator++(int x) {
69   }
70 
71   struct Strukt {
72     int i;
73   };
74 
p6()75   const Strukt p6() {}
76   // CHECK-MESSAGES: [[@LINE-1]]:3: warning: return type 'const Clazz::Strukt' i
77   // CHECK-FIXES: Strukt p6() {}
78 
79   // No warning is emitted here, because this is only the declaration.  The
80   // warning will be associated with the definition, below.
81   const Strukt* const p7();
82   // CHECK-FIXES: const Strukt* p7();
83 
84   // const-qualifier is the first `const` token, but not the first token.
p8()85   static const int p8() {}
86   // CHECK-MESSAGES: [[@LINE-1]]:3: warning: return type 'const int' is 'const'-
87   // CHECK-FIXES: static int p8() {}
88 
p9()89   static const Strukt p9() {}
90   // CHECK-MESSAGES: [[@LINE-1]]:3: warning: return type 'const Clazz::Strukt' i
91   // CHECK-FIXES: static Strukt p9() {}
92 
n0() const93   int n0() const { return 0; }
94   const Klazz<const int>& n11(const Klazz<const int>) const;
95 };
96 
p3()97 Clazz *const Clazz::p3() {
98   // CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'Clazz *const' is 'cons
99   // CHECK-FIXES: Clazz *Clazz::p3() {
100   return this;
101 }
102 
p5() const103 const Klazz<const int>* const Clazz::p5() const {}
104 // CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const Klazz<const int> *
105 // CHECK-FIXES: const Klazz<const int>* Clazz::p5() const {}
106 
p7()107 const Clazz::Strukt* const Clazz::p7() {}
108 // CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const Clazz::Strukt *con
109 // CHECK-FIXES: const Clazz::Strukt* Clazz::p7() {}
110 
111 Clazz *const p10();
112 // CHECK-FIXES: Clazz *p10();
113 
p10()114 Clazz *const p10() {
115   // CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'Clazz *const' is 'cons
116   // CHECK-FIXES: Clazz *p10() {
117   return new Clazz();
118 }
119 
120 const Clazz bar;
p11()121 const Clazz *const p11() {
122   // CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const Clazz *const' is
123   // CHECK-FIXES: const Clazz *p11() {
124   return &bar;
125 }
126 
p12()127 const Klazz<const int> p12() {}
128 // CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const Klazz<const int>'
129 // CHECK-FIXES: Klazz<const int> p12() {}
130 
p13()131 const Klazz<const int>* const p13() {}
132 // CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const Klazz<const int> *
133 // CHECK-FIXES: const Klazz<const int>* p13() {}
134 
135 // re-declaration of p15.
136 const int p15();
137 // CHECK-FIXES: int p15();
138 
p15()139 const int p15() {
140 // CHECK-MESSAGES: [[@LINE-1]]:1: warning:
141 // CHECK-FIXES: int p15() {
142   return 0;
143 }
144 
145 // Exercise the lexer.
146 
p16()147 const /* comment */ /* another comment*/ int p16() { return 0; }
148 // CHECK-MESSAGES: [[@LINE-1]]:1: warning:
149 // CHECK-FIXES: /* comment */ /* another comment*/ int p16() { return 0; }
150 
151 /* comment */ const
152 // CHECK-MESSAGES: [[@LINE-1]]:15: warning:
153 // CHECK-FIXES: /* comment */
154 // more
p17()155 /* another comment*/ int p17() { return 0; }
156 
157 // Test cases where the `const` token lexically is hidden behind some form of
158 // indirection.
159 
160 #define CONSTINT const int
p18()161 CONSTINT p18() {}
162 // CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const int' is 'const'-qu
163 
164 #define CONST const
p19()165 CONST int p19() {}
166 // CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const int' is 'const'-qu
167 
168 using ty = const int;
p21()169 ty p21() {}
170 // CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'ty' (aka 'const int') is
171 
172 typedef const int ty2;
p22()173 ty2 p22() {}
174 // CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'ty2' (aka 'const int') i
175 
176 // Declaration uses a macro, while definition doesn't.  In this case, we won't
177 // fix the declaration, and will instead issue a warning.
178 CONST int p23();
179 // CHECK-NOTE: [[@LINE-1]]:1: note: could not transform this declaration
180 
181 const int p23();
182 // CHECK-FIXES: int p23();
183 
p23()184 const int p23() { return 3; }
185 // CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const int' is 'const'-qu
186 // CHECK-FIXES: int p23() { return 3; }
187 
p24()188 int const p24() { return 3; }
189 // CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const int' is 'const'-qu
190 // CHECK-FIXES: int p24() { return 3; }
191 
p25(const int * p)192 int const * const p25(const int* p) { return p; }
193 // CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const int *const' is 'co
194 // CHECK-FIXES: int const * p25(const int* p) { return p; }
195 
196 // We cannot (yet) fix instances that use trailing return types, but we can
197 // warn.
p26()198 auto p26() -> const int { return 3; }
199 // CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const int' is 'const'-qu
p27()200 auto p27() -> int const { return 3; }
201 // CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const int' is 'const'-qu
202 
p28()203 std::add_const<int>::type p28() { return 3; }
204 // CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'std::add_const<int>::typ
205 
206 // p29, p30 are based on
207 // llvm/projects/test-suite/SingleSource/Benchmarks/Misc-C++-EH/spirit.cpp:
208 template <class T>
p29(T const & t)209 Klazz<T const> const p29(T const &t) { return {}; }
210 // CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const Klazz<const T>' is
211 // CHECK-FIXES: Klazz<T const> p29(T const &t) { return {}; }
212 
p30(char const * s)213 Klazz<char const *> const p30(char const *s) { return s; }
214 // CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const Klazz<const char *
215 // CHECK-FIXES: Klazz<char const *> p30(char const *s) { return s; }
216 
217 const int n1 = 1;
218 const Clazz n2 = Clazz();
219 const Clazz* n3 = new Clazz();
220 Clazz *const n4 = new Clazz();
221 const Clazz *const n5 = new Clazz();
222 constexpr int n6 = 6;
n7()223 constexpr int n7() { return 8; }
224 const int eight = 8;
n8()225 constexpr const int* n8() { return &eight; }
226 Klazz<const int> n9();
227 const Klazz<const int>* n10();
n11(const Klazz<const int>) const228 const Klazz<const int>& Clazz::n11(const Klazz<const int>) const {}
229 
230 // Declaration only.
231 const int n14();
232 
233 int **const * n_multiple_ptr();
234 int *const & n_pointer_ref();
235