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
9namespace clang {
10namespace tidy {
11
12namespace {
13using namespace clang::ast_matchers;
14
15template <int Indirections>
16class ConstReferenceDeclRefExprsTransform : public ClangTidyCheck {
17public:
18 ConstReferenceDeclRefExprsTransform(StringRef CheckName,
19 ClangTidyContext *Context)
20 : ClangTidyCheck(CheckName, Context) {}
21
22 void registerMatchers(MatchFinder *Finder) override {
23 Finder->addMatcher(varDecl(hasName(Name: "target")).bind(ID: "var"), this);
24 }
25
26 void check(const MatchFinder::MatchResult &Result) override {
27 const auto *D = Result.Nodes.getNodeAs<VarDecl>(ID: "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
42namespace test {
43
44template <int Indirections> void RunTest(StringRef Snippet) {
45
46 StringRef CommonCode = R"(
47 struct ConstTag{};
48 struct NonConstTag{};
49
50 struct S {
51 void constMethod() const;
52 void nonConstMethod();
53
54 static void staticMethod();
55
56 void operator()(ConstTag) const;
57 void operator()(NonConstTag);
58
59 void operator[](int);
60 void operator[](int) const;
61
62 bool operator==(const S&) const;
63
64 int int_member;
65 // We consider a mutation of the `*ptr_member` to be a const use of
66 // `*this`. This is consistent with the semantics of `const`-qualified
67 // methods, which prevent modifying `ptr_member` but not `*ptr_member`.
68 int* ptr_member;
69
70 };
71
72 struct Derived : public S {
73
74 };
75
76 void useVal(S);
77 void useRef(S&);
78 void usePtr(S*);
79 void usePtrPtr(S**);
80 void usePtrConstPtr(S* const*);
81 void useConstRef(const S&);
82 void useConstPtr(const S*);
83 void useConstPtrRef(const S*&);
84 void useConstPtrPtr(const S**);
85 void useConstPtrConstRef(const S* const&);
86 void useConstPtrConstPtr(const S* const*);
87
88 void useInt(int);
89 void useIntRef(int&);
90 void useIntConstRef(const int&);
91 void useIntPtr(int*);
92 void useIntConstPtr(const int*);
93
94 )";
95
96 std::string Code = (CommonCode + Snippet).str();
97
98 llvm::SmallVector<StringRef, 1> Parts;
99 StringRef(Code).split(A&: Parts, Separator: "/*const*/");
100
101 EXPECT_EQ(Code,
102 runCheckOnCode<ConstReferenceDeclRefExprsTransform<Indirections>>(
103 join(Parts, "")));
104}
105
106TEST(ConstReferenceDeclRefExprsTest, ConstValueVar) {
107 RunTest<0>(Snippet: R"(
108 void f(const S target) {
109 useVal(/*const*/target);
110 useConstRef(/*const*/target);
111 useConstPtr(&/*const*/target);
112 useConstPtrConstRef(&/*const*/target);
113 /*const*/target.constMethod();
114 /*const*/target.staticMethod();
115 /*const*/target(ConstTag{});
116 /*const*/target[42];
117 useConstRef((/*const*/target));
118 (/*const*/target).constMethod();
119 /*const*/target.staticMethod();
120 (void)(/*const*/target == /*const*/target);
121 (void)/*const*/target;
122 (void)&/*const*/target;
123 (void)*&/*const*/target;
124 /*const*/target;
125 S copy1 = /*const*/target;
126 S copy2(/*const*/target);
127 /*const*/target.int_member;
128 useInt(/*const*/target.int_member);
129 useIntConstRef(/*const*/target.int_member);
130 useIntPtr(/*const*/target.ptr_member);
131 useIntConstPtr(&/*const*/target.int_member);
132
133 const S& const_target_ref = /*const*/target;
134 const S* const_target_ptr = &/*const*/target;
135 }
136)");
137}
138
139TEST(ConstReferenceDeclRefExprsTest, ConstRefVar) {
140 RunTest<0>(Snippet: R"(
141 void f(const S& target) {
142 useVal(/*const*/target);
143 useConstRef(/*const*/target);
144 useConstPtr(&/*const*/target);
145 useConstPtrConstRef(&/*const*/target);
146 /*const*/target.constMethod();
147 /*const*/target.staticMethod();
148 /*const*/target(ConstTag{});
149 /*const*/target[42];
150 useConstRef((/*const*/target));
151 (/*const*/target).constMethod();
152 (void)(/*const*/target == /*const*/target);
153 (void)/*const*/target;
154 (void)&/*const*/target;
155 (void)*&/*const*/target;
156 /*const*/target;
157 S copy1 = /*const*/target;
158 S copy2(/*const*/target);
159 /*const*/target.int_member;
160 useInt(/*const*/target.int_member);
161 useIntConstRef(/*const*/target.int_member);
162 useIntPtr(/*const*/target.ptr_member);
163 useIntConstPtr(&/*const*/target.int_member);
164
165 const S& const_target_ref = /*const*/target;
166 const S* const_target_ptr = &/*const*/target;
167 }
168)");
169}
170
171TEST(ConstReferenceDeclRefExprsTest, DEBUGREMOVEME) {
172 RunTest<0>(Snippet: R"(
173 void f(S target, const S& other) {
174 S* target_ptr = &target;
175 }
176)");
177}
178
179TEST(ConstReferenceDeclRefExprsTest, ValueVar) {
180 RunTest<0>(Snippet: R"(
181 void f(S target, const S& other) {
182 useConstRef(/*const*/target);
183 useVal(/*const*/target);
184 useConstPtr(&/*const*/target);
185 useConstPtrConstRef(&/*const*/target);
186 /*const*/target.constMethod();
187 /*const*/target.staticMethod();
188 target.nonConstMethod();
189 /*const*/target(ConstTag{});
190 target[42];
191 /*const*/target(ConstTag{});
192 target(NonConstTag{});
193 useRef(target);
194 usePtr(&target);
195 useConstRef((/*const*/target));
196 (/*const*/target).constMethod();
197 (void)(/*const*/target == /*const*/target);
198 (void)(/*const*/target == other);
199 (void)/*const*/target;
200 (void)&/*const*/target;
201 (void)*&/*const*/target;
202 /*const*/target;
203 S copy1 = /*const*/target;
204 S copy2(/*const*/target);
205 /*const*/target.int_member;
206 useInt(/*const*/target.int_member);
207 useIntConstRef(/*const*/target.int_member);
208 useIntPtr(/*const*/target.ptr_member);
209 useIntConstPtr(&/*const*/target.int_member);
210
211 const S& const_target_ref = /*const*/target;
212 const S* const_target_ptr = &/*const*/target;
213 S* target_ptr = &target;
214 }
215)");
216}
217
218TEST(ConstReferenceDeclRefExprsTest, RefVar) {
219 RunTest<0>(Snippet: R"(
220 void f(S& target) {
221 useVal(/*const*/target);
222 usePtr(&target);
223 useConstRef(/*const*/target);
224 useConstPtr(&/*const*/target);
225 useConstPtrConstRef(&/*const*/target);
226 /*const*/target.constMethod();
227 /*const*/target.staticMethod();
228 target.nonConstMethod();
229 /*const*/target(ConstTag{});
230 target[42];
231 useConstRef((/*const*/target));
232 (/*const*/target).constMethod();
233 (void)(/*const*/target == /*const*/target);
234 (void)/*const*/target;
235 (void)&/*const*/target;
236 (void)*&/*const*/target;
237 /*const*/target;
238 S copy1 = /*const*/target;
239 S copy2(/*const*/target);
240 /*const*/target.int_member;
241 useInt(/*const*/target.int_member);
242 useIntConstRef(/*const*/target.int_member);
243 useIntPtr(/*const*/target.ptr_member);
244 useIntConstPtr(&/*const*/target.int_member);
245
246 (void)(&/*const*/target)->int_member;
247 useIntRef((&target)->int_member);
248
249 const S& const_target_ref = /*const*/target;
250 const S* const_target_ptr = &/*const*/target;
251 S* target_ptr = &target;
252 }
253)");
254}
255
256TEST(ConstReferenceDeclRefExprsTest, PtrVar) {
257 RunTest<1>(Snippet: R"(
258 void f(S* target) {
259 useVal(*/*const*/target);
260 usePtr(target);
261 useConstRef(*/*const*/target);
262 useConstPtr(/*const*/target);
263 useConstPtrConstRef(/*const*/target);
264 usePtrConstPtr(&target);
265 /*const*/target->constMethod();
266 /*const*/target->staticMethod();
267 target->nonConstMethod();
268 (*/*const*/target)(ConstTag{});
269 (*target)[42];
270 target->operator[](42);
271 useConstRef((*/*const*/target));
272 (/*const*/target)->constMethod();
273 (void)(*/*const*/target == */*const*/target);
274 (void)*/*const*/target;
275 (void)/*const*/target;
276 /*const*/target;
277 S copy1 = */*const*/target;
278 S copy2(*/*const*/target);
279 /*const*/target->int_member;
280 useInt(/*const*/target->int_member);
281 useIntConstRef(/*const*/target->int_member);
282 useIntPtr(/*const*/target->ptr_member);
283 useIntConstPtr(&/*const*/target->int_member);
284
285 const S& const_target_ref = */*const*/target;
286 const S* const_target_ptr = /*const*/target;
287 S* target_ptr = target; // FIXME: we could chect const usage of `target_ptr`.
288 }
289)");
290}
291
292TEST(ConstReferenceDeclRefExprsTest, ConstPtrVar) {
293 RunTest<1>(Snippet: R"(
294 void f(const S* target) {
295 useVal(*/*const*/target);
296 useConstRef(*/*const*/target);
297 useConstPtr(/*const*/target);
298 useConstPtrRef(/*const*/target);
299 useConstPtrPtr(&/*const*/target);
300 useConstPtrConstPtr(&/*const*/target);
301 useConstPtrConstRef(/*const*/target);
302 /*const*/target->constMethod();
303 /*const*/target->staticMethod();
304 (*/*const*/target)(ConstTag{});
305 (*/*const*/target)[42];
306 /*const*/target->operator[](42);
307 (void)(*/*const*/target == */*const*/target);
308 (void)/*const*/target;
309 (void)*/*const*/target;
310 /*const*/target;
311 if(/*const*/target) {}
312 S copy1 = */*const*/target;
313 S copy2(*/*const*/target);
314 /*const*/target->int_member;
315 useInt(/*const*/target->int_member);
316 useIntConstRef(/*const*/target->int_member);
317 useIntPtr(/*const*/target->ptr_member);
318 useIntConstPtr(&/*const*/target->int_member);
319
320 const S& const_target_ref = */*const*/target;
321 const S* const_target_ptr = /*const*/target;
322 }
323)");
324}
325
326TEST(ConstReferenceDeclRefExprsTest, ConstPtrPtrVar) {
327 RunTest<2>(Snippet: 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 (void)/*const*/target;
337 (void)*/*const*/target;
338 (void)**/*const*/target;
339 /*const*/target;
340 if(/*const*/target) {}
341 if(*/*const*/target) {}
342 S copy1 = **/*const*/target;
343 S copy2(**/*const*/target);
344 (*/*const*/target)->int_member;
345 useInt((*/*const*/target)->int_member);
346 useIntConstRef((*/*const*/target)->int_member);
347 useIntPtr((*/*const*/target)->ptr_member);
348 useIntConstPtr(&(*/*const*/target)->int_member);
349
350 const S& const_target_ref = **/*const*/target;
351 const S* const_target_ptr = */*const*/target;
352 }
353)");
354}
355
356TEST(ConstReferenceDeclRefExprsTest, ConstPtrConstPtrVar) {
357 RunTest<2>(Snippet: R"(
358 void f(const S* const* target) {
359 useVal(**/*const*/target);
360 useConstRef(**/*const*/target);
361 useConstPtr(*/*const*/target);
362 useConstPtrConstPtr(/*const*/target);
363 useConstPtrConstRef(*/*const*/target);
364 (void)/*const*/target;
365 (void)*/*const*/target;
366 (void)**/*const*/target;
367 /*const*/target;
368 if(/*const*/target) {}
369 if(*/*const*/target) {}
370 S copy1 = **/*const*/target;
371 S copy2(**/*const*/target);
372 (*/*const*/target)->int_member;
373 useInt((*/*const*/target)->int_member);
374 useIntConstRef((*/*const*/target)->int_member);
375 useIntPtr((*/*const*/target)->ptr_member);
376 useIntConstPtr(&(*/*const*/target)->int_member);
377
378 const S& const_target_ref = **/*const*/target;
379 const S* const_target_ptr = */*const*/target;
380 }
381)");
382}
383
384} // namespace test
385} // namespace tidy
386} // namespace clang
387

source code of clang-tools-extra/unittests/clang-tidy/DeclRefExprUtilsTest.cpp