xref: /llvm-project/clang-tools-extra/unittests/clang-tidy/DeclRefExprUtilsTest.cpp (revision 415a82c64afa0047383caf471aa872fdb0e2658d)
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"
8 
9 namespace clang {
10 namespace tidy {
11 
12 namespace {
13 using namespace clang::ast_matchers;
14 
15 template <int Indirections>
16 class ConstReferenceDeclRefExprsTransform : public ClangTidyCheck {
17 public:
ConstReferenceDeclRefExprsTransform(StringRef CheckName,ClangTidyContext * Context)18   ConstReferenceDeclRefExprsTransform(StringRef CheckName,
19                                       ClangTidyContext *Context)
20       : ClangTidyCheck(CheckName, Context) {}
21 
registerMatchers(MatchFinder * Finder)22   void registerMatchers(MatchFinder *Finder) override {
23     Finder->addMatcher(varDecl(hasName("target")).bind("var"), this);
24   }
25 
check(const MatchFinder::MatchResult & Result)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);
32 
33     for (const DeclRefExpr *const Expr : const_decrefexprs) {
34       assert(Expr);
35       diag(Expr->getBeginLoc(), "const usage")
36           << FixItHint::CreateInsertion(Expr->getBeginLoc(), "/*const*/");
37     }
38   }
39 };
40 } // namespace
41 
42 namespace test {
43 
RunTest(StringRef Snippet)44 template <int Indirections> void RunTest(StringRef Snippet) {
45 
46   StringRef CommonCode = R"(
47     struct ConstTag{};
48     struct NonConstTag{};
49     struct Tag1{};
50 
51     struct S {
52       void constMethod() const;
53       void nonConstMethod();
54 
55       static void staticMethod();
56 
57       void operator()(ConstTag) const;
58       void operator()(NonConstTag);
59 
60       void operator[](int);
61       void operator[](int) const;
62 
63       int& at(int);
64       const int& at(int) const;
65       const int& at(Tag1);
66 
67       int& weird_overload();
68       const double& weird_overload() const;
69 
70       bool operator==(const S&) const;
71 
72       int int_member;
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`.
76       int* ptr_member;
77 
78     };
79 
80     struct Derived : public S {
81 
82     };
83 
84     void useVal(S);
85     void useRef(S&);
86     void usePtr(S*);
87     void usePtrPtr(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*);
95 
96     void useInt(int);
97     void useIntRef(int&);
98     void useIntConstRef(const int&);
99     void useIntPtr(int*);
100     void useIntConstPtr(const int*);
101 
102     )";
103 
104   std::string Code = (CommonCode + Snippet).str();
105 
106   llvm::SmallVector<StringRef, 1> Parts;
107   StringRef(Code).split(Parts, "/*const*/");
108 
109   EXPECT_EQ(Code,
110             runCheckOnCode<ConstReferenceDeclRefExprsTransform<Indirections>>(
111                 join(Parts, "")));
112 }
113 
TEST(ConstReferenceDeclRefExprsTest,ConstValueVar)114 TEST(ConstReferenceDeclRefExprsTest, ConstValueVar) {
115   RunTest<0>(R"(
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{});
124       /*const*/target[42];
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;
132       /*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);
140 
141       const S& const_target_ref = /*const*/target;
142       const S* const_target_ptr = &/*const*/target;
143     }
144 )");
145 }
146 
TEST(ConstReferenceDeclRefExprsTest,ConstRefVar)147 TEST(ConstReferenceDeclRefExprsTest, ConstRefVar) {
148   RunTest<0>(R"(
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{});
157       /*const*/target[42];
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;
164       /*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);
173 
174       const S& const_target_ref = /*const*/target;
175       const S* const_target_ptr = &/*const*/target;
176       (void)/*const*/target.at(3);
177     }
178 )");
179 }
180 
TEST(ConstReferenceDeclRefExprsTest,DEBUGREMOVEME)181 TEST(ConstReferenceDeclRefExprsTest, DEBUGREMOVEME) {
182   RunTest<0>(R"(
183     void f(S target, const S& other) {
184       S* target_ptr = &target;
185     }
186 )");
187 }
188 
TEST(ConstReferenceDeclRefExprsTest,ValueVar)189 TEST(ConstReferenceDeclRefExprsTest, ValueVar) {
190   RunTest<0>(R"(
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{});
200       /*const*/target[42];
201       /*const*/target(ConstTag{});
202       target(NonConstTag{});
203       useRef(target);
204       usePtr(&target);
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;
212       /*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);
220 
221       const S& const_target_ref = /*const*/target;
222       const S* const_target_ptr = &/*const*/target;
223       S* target_ptr = &target;
224 
225       (void)/*const*/target.at(3);
226       ++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);
230       target.at(Tag1{});
231       target.weird_overload();
232     }
233 )");
234 }
235 
TEST(ConstReferenceDeclRefExprsTest,RefVar)236 TEST(ConstReferenceDeclRefExprsTest, RefVar) {
237   RunTest<0>(R"(
238     void f(S& target) {
239       useVal(/*const*/target);
240       usePtr(&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{});
248       /*const*/target[42];
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;
255       /*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);
263 
264       (void)(&/*const*/target)->int_member;
265       useIntRef((&target)->int_member);
266 
267       const S& const_target_ref = /*const*/target;
268       const S* const_target_ptr = &/*const*/target;
269       S* target_ptr = &target;
270 
271       (void)/*const*/target.at(3);
272       ++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);
276       target.at(Tag1{});
277       target.weird_overload();
278     }
279 )");
280 }
281 
TEST(ConstReferenceDeclRefExprsTest,PtrVar)282 TEST(ConstReferenceDeclRefExprsTest, PtrVar) {
283   RunTest<1>(R"(
284     void f(S* target) {
285       useVal(*/*const*/target);
286       usePtr(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;
302       /*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);
310 
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`
314 
315       (void)/*const*/target->at(3);
316       ++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);
320       target->at(Tag1{});
321       target->weird_overload();
322     }
323 )");
324 }
325 
TEST(ConstReferenceDeclRefExprsTest,ConstPtrVar)326 TEST(ConstReferenceDeclRefExprsTest, ConstPtrVar) {
327   RunTest<1>(R"(
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;
344       /*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);
353 
354       const S& const_target_ref = */*const*/target;
355       const S* const_target_ptr = /*const*/target;
356 
357       (void)/*const*/target->at(3);
358       const int civ = /*const*/target->at(3);
359       const int& cir = /*const*/target->at(3);
360     }
361 )");
362 }
363 
TEST(ConstReferenceDeclRefExprsTest,ConstPtrPtrVar)364 TEST(ConstReferenceDeclRefExprsTest, ConstPtrPtrVar) {
365   RunTest<2>(R"(
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;
377       /*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);
387 
388       const S& const_target_ref = **/*const*/target;
389       const S* const_target_ptr = */*const*/target;
390     }
391 )");
392 }
393 
TEST(ConstReferenceDeclRefExprsTest,ConstPtrConstPtrVar)394 TEST(ConstReferenceDeclRefExprsTest, ConstPtrConstPtrVar) {
395   RunTest<2>(R"(
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;
405       /*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);
415 
416       const S& const_target_ref = **/*const*/target;
417       const S* const_target_ptr = */*const*/target;
418     }
419 )");
420 }
421 
422 } // namespace test
423 } // namespace tidy
424 } // namespace clang
425