1 #include "../clang-tidy/utils/DeclRefExprUtils.h"
2 #include "ClangTidyDiagnosticConsumer.h"
3 #include "ClangTidyTest.h"
4 #include "clang/ASTMatchers/ASTMatchFinder.h"
5 #include "clang/ASTMatchers/ASTMatchers.h"
6 #include "clang/Tooling/Tooling.h"
7 #include "gtest/gtest.h"
13 using namespace clang::ast_matchers
;
15 template <int Indirections
>
16 class ConstReferenceDeclRefExprsTransform
: public ClangTidyCheck
{
18 ConstReferenceDeclRefExprsTransform(StringRef CheckName
,
19 ClangTidyContext
*Context
)
20 : ClangTidyCheck(CheckName
, Context
) {}
22 void registerMatchers(MatchFinder
*Finder
) override
{
23 Finder
->addMatcher(varDecl(hasName("target")).bind("var"), this);
26 void check(const MatchFinder::MatchResult
&Result
) override
{
27 const auto *D
= Result
.Nodes
.getNodeAs
<VarDecl
>("var");
28 using utils::decl_ref_expr::constReferenceDeclRefExprs
;
29 const auto const_decrefexprs
= constReferenceDeclRefExprs(
30 *D
, *cast
<FunctionDecl
>(D
->getDeclContext())->getBody(),
31 *Result
.Context
, Indirections
);
33 for (const DeclRefExpr
*const Expr
: const_decrefexprs
) {
35 diag(Expr
->getBeginLoc(), "const usage")
36 << FixItHint::CreateInsertion(Expr
->getBeginLoc(), "/*const*/");
44 template <int Indirections
> void RunTest(StringRef Snippet
) {
46 StringRef CommonCode
= R
"(
52 void constMethod() const;
53 void nonConstMethod();
55 static void staticMethod();
57 void operator()(ConstTag) const;
58 void operator()(NonConstTag);
61 void operator[](int) const;
64 const int& at(int) const;
67 int& weird_overload();
68 const double& weird_overload() const;
70 bool operator==(const S&) const;
73 // We consider a mutation of the `*ptr_member` to be a const use of
74 // `*this`. This is consistent with the semantics of `const`-qualified
75 // methods, which prevent modifying `ptr_member` but not `*ptr_member`.
80 struct Derived : public S {
88 void usePtrConstPtr(S* const*);
89 void useConstRef(const S&);
90 void useConstPtr(const S*);
91 void useConstPtrRef(const S*&);
92 void useConstPtrPtr(const S**);
93 void useConstPtrConstRef(const S* const&);
94 void useConstPtrConstPtr(const S* const*);
98 void useIntConstRef(const int&);
100 void useIntConstPtr(const int*);
104 std::string Code
= (CommonCode
+ Snippet
).str();
106 llvm::SmallVector
<StringRef
, 1> Parts
;
107 StringRef(Code
).split(Parts
, "/*const*/");
110 runCheckOnCode
<ConstReferenceDeclRefExprsTransform
<Indirections
>>(
114 TEST(ConstReferenceDeclRefExprsTest
, ConstValueVar
) {
116 void f(const S target) {
117 useVal(/*const*/target);
118 useConstRef(/*const*/target);
119 useConstPtr(&/*const*/target);
120 useConstPtrConstRef(&/*const*/target);
121 /*const*/target.constMethod();
122 /*const*/target.staticMethod();
123 /*const*/target(ConstTag{});
125 useConstRef((/*const*/target));
126 (/*const*/target).constMethod();
127 /*const*/target.staticMethod();
128 (void)(/*const*/target == /*const*/target);
129 (void)/*const*/target;
130 (void)&/*const*/target;
131 (void)*&/*const*/target;
133 S copy1 = /*const*/target;
134 S copy2(/*const*/target);
135 /*const*/target.int_member;
136 useInt(/*const*/target.int_member);
137 useIntConstRef(/*const*/target.int_member);
138 useIntPtr(/*const*/target.ptr_member);
139 useIntConstPtr(&/*const*/target.int_member);
141 const S& const_target_ref = /*const*/target;
142 const S* const_target_ptr = &/*const*/target;
147 TEST(ConstReferenceDeclRefExprsTest
, ConstRefVar
) {
149 void f(const S& target) {
150 useVal(/*const*/target);
151 useConstRef(/*const*/target);
152 useConstPtr(&/*const*/target);
153 useConstPtrConstRef(&/*const*/target);
154 /*const*/target.constMethod();
155 /*const*/target.staticMethod();
156 /*const*/target(ConstTag{});
158 useConstRef((/*const*/target));
159 (/*const*/target).constMethod();
160 (void)(/*const*/target == /*const*/target);
161 (void)/*const*/target;
162 (void)&/*const*/target;
163 (void)*&/*const*/target;
165 S copy1 = /*const*/target;
166 S copy2(/*const*/target);
167 /*const*/target.int_member;
168 useInt(/*const*/target.int_member);
169 useIntConstRef(/*const*/target.int_member);
170 useIntPtr(/*const*/target.ptr_member);
171 useIntConstPtr(&/*const*/target.int_member);
172 (void)/*const*/target.at(3);
174 const S& const_target_ref = /*const*/target;
175 const S* const_target_ptr = &/*const*/target;
176 (void)/*const*/target.at(3);
181 TEST(ConstReferenceDeclRefExprsTest
, DEBUGREMOVEME
) {
183 void f(S target, const S& other) {
184 S* target_ptr = ⌖
189 TEST(ConstReferenceDeclRefExprsTest
, ValueVar
) {
191 void f(S target, const S& other) {
192 useConstRef(/*const*/target);
193 useVal(/*const*/target);
194 useConstPtr(&/*const*/target);
195 useConstPtrConstRef(&/*const*/target);
196 /*const*/target.constMethod();
197 /*const*/target.staticMethod();
198 target.nonConstMethod();
199 /*const*/target(ConstTag{});
201 /*const*/target(ConstTag{});
202 target(NonConstTag{});
205 useConstRef((/*const*/target));
206 (/*const*/target).constMethod();
207 (void)(/*const*/target == /*const*/target);
208 (void)(/*const*/target == other);
209 (void)/*const*/target;
210 (void)&/*const*/target;
211 (void)*&/*const*/target;
213 S copy1 = /*const*/target;
214 S copy2(/*const*/target);
215 /*const*/target.int_member;
216 useInt(/*const*/target.int_member);
217 useIntConstRef(/*const*/target.int_member);
218 useIntPtr(/*const*/target.ptr_member);
219 useIntConstPtr(&/*const*/target.int_member);
221 const S& const_target_ref = /*const*/target;
222 const S* const_target_ptr = &/*const*/target;
223 S* target_ptr = ⌖
225 (void)/*const*/target.at(3);
227 const int civ = /*const*/target.at(3);
228 const int& cir = /*const*/target.at(3);
229 int& ir = target.at(3);
231 target.weird_overload();
236 TEST(ConstReferenceDeclRefExprsTest
, RefVar
) {
239 useVal(/*const*/target);
241 useConstRef(/*const*/target);
242 useConstPtr(&/*const*/target);
243 useConstPtrConstRef(&/*const*/target);
244 /*const*/target.constMethod();
245 /*const*/target.staticMethod();
246 target.nonConstMethod();
247 /*const*/target(ConstTag{});
249 useConstRef((/*const*/target));
250 (/*const*/target).constMethod();
251 (void)(/*const*/target == /*const*/target);
252 (void)/*const*/target;
253 (void)&/*const*/target;
254 (void)*&/*const*/target;
256 S copy1 = /*const*/target;
257 S copy2(/*const*/target);
258 /*const*/target.int_member;
259 useInt(/*const*/target.int_member);
260 useIntConstRef(/*const*/target.int_member);
261 useIntPtr(/*const*/target.ptr_member);
262 useIntConstPtr(&/*const*/target.int_member);
264 (void)(&/*const*/target)->int_member;
265 useIntRef((&target)->int_member);
267 const S& const_target_ref = /*const*/target;
268 const S* const_target_ptr = &/*const*/target;
269 S* target_ptr = ⌖
271 (void)/*const*/target.at(3);
273 const int civ = /*const*/target.at(3);
274 const int& cir = /*const*/target.at(3);
275 int& ir = target.at(3);
277 target.weird_overload();
282 TEST(ConstReferenceDeclRefExprsTest
, PtrVar
) {
285 useVal(*/*const*/target);
287 useConstRef(*/*const*/target);
288 useConstPtr(/*const*/target);
289 useConstPtrConstRef(/*const*/target);
290 usePtrConstPtr(&target);
291 /*const*/target->constMethod();
292 /*const*/target->staticMethod();
293 target->nonConstMethod();
294 (*/*const*/target)(ConstTag{});
295 (*/*const*/target)[42];
296 /*const*/target->operator[](42);
297 useConstRef((*/*const*/target));
298 (/*const*/target)->constMethod();
299 (void)(*/*const*/target == */*const*/target);
300 (void)*/*const*/target;
301 (void)/*const*/target;
303 S copy1 = */*const*/target;
304 S copy2(*/*const*/target);
305 /*const*/target->int_member;
306 useInt(/*const*/target->int_member);
307 useIntConstRef(/*const*/target->int_member);
308 useIntPtr(/*const*/target->ptr_member);
309 useIntConstPtr(&/*const*/target->int_member);
311 const S& const_target_ref = */*const*/target;
312 const S* const_target_ptr = /*const*/target;
313 S* target_ptr = target; // FIXME: we could chect const usage of `target_ptr`
315 (void)/*const*/target->at(3);
317 const int civ = /*const*/target->at(3);
318 const int& cir = /*const*/target->at(3);
319 int& ir = target->at(3);
321 target->weird_overload();
326 TEST(ConstReferenceDeclRefExprsTest
, ConstPtrVar
) {
328 void f(const S* target) {
329 useVal(*/*const*/target);
330 useConstRef(*/*const*/target);
331 useConstPtr(/*const*/target);
332 useConstPtrRef(/*const*/target);
333 useConstPtrPtr(&/*const*/target);
334 useConstPtrConstPtr(&/*const*/target);
335 useConstPtrConstRef(/*const*/target);
336 /*const*/target->constMethod();
337 /*const*/target->staticMethod();
338 (*/*const*/target)(ConstTag{});
339 (*/*const*/target)[42];
340 /*const*/target->operator[](42);
341 (void)(*/*const*/target == */*const*/target);
342 (void)/*const*/target;
343 (void)*/*const*/target;
345 if(/*const*/target) {}
346 S copy1 = */*const*/target;
347 S copy2(*/*const*/target);
348 /*const*/target->int_member;
349 useInt(/*const*/target->int_member);
350 useIntConstRef(/*const*/target->int_member);
351 useIntPtr(/*const*/target->ptr_member);
352 useIntConstPtr(&/*const*/target->int_member);
354 const S& const_target_ref = */*const*/target;
355 const S* const_target_ptr = /*const*/target;
357 (void)/*const*/target->at(3);
358 const int civ = /*const*/target->at(3);
359 const int& cir = /*const*/target->at(3);
364 TEST(ConstReferenceDeclRefExprsTest
, ConstPtrPtrVar
) {
366 void f(const S** target) {
367 useVal(**/*const*/target);
368 useConstRef(**/*const*/target);
369 useConstPtr(*/*const*/target);
370 useConstPtrRef(*/*const*/target);
371 useConstPtrPtr(/*const*/target);
372 useConstPtrConstPtr(/*const*/target);
373 useConstPtrConstRef(*/*const*/target);
374 (void)/*const*/target;
375 (void)*/*const*/target;
376 (void)**/*const*/target;
378 if(/*const*/target) {}
379 if(*/*const*/target) {}
380 S copy1 = **/*const*/target;
381 S copy2(**/*const*/target);
382 (*/*const*/target)->int_member;
383 useInt((*/*const*/target)->int_member);
384 useIntConstRef((*/*const*/target)->int_member);
385 useIntPtr((*/*const*/target)->ptr_member);
386 useIntConstPtr(&(*/*const*/target)->int_member);
388 const S& const_target_ref = **/*const*/target;
389 const S* const_target_ptr = */*const*/target;
394 TEST(ConstReferenceDeclRefExprsTest
, ConstPtrConstPtrVar
) {
396 void f(const S* const* target) {
397 useVal(**/*const*/target);
398 useConstRef(**/*const*/target);
399 useConstPtr(*/*const*/target);
400 useConstPtrConstPtr(/*const*/target);
401 useConstPtrConstRef(*/*const*/target);
402 (void)/*const*/target;
403 (void)*/*const*/target;
404 (void)**/*const*/target;
406 if(/*const*/target) {}
407 if(*/*const*/target) {}
408 S copy1 = **/*const*/target;
409 S copy2(**/*const*/target);
410 (*/*const*/target)->int_member;
411 useInt((*/*const*/target)->int_member);
412 useIntConstRef((*/*const*/target)->int_member);
413 useIntPtr((*/*const*/target)->ptr_member);
414 useIntConstPtr(&(*/*const*/target)->int_member);
416 const S& const_target_ref = **/*const*/target;
417 const S* const_target_ptr = */*const*/target;