1//===- unittests/Analysis/FlowSensitive/SmartPointerAccessorCachingTest.cpp ==//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "clang/Analysis/FlowSensitive/SmartPointerAccessorCaching.h"
10
11#include "clang/ASTMatchers/ASTMatchFinder.h"
12#include "clang/Testing/TestAST.h"
13#include "llvm/ADT/StringRef.h"
14#include "gtest/gtest.h"
15
16namespace clang::dataflow {
17namespace {
18
19using clang::ast_matchers::match;
20
21template <typename MatcherT>
22bool matches(llvm::StringRef Decls, llvm::StringRef TestInput,
23 MatcherT Matcher) {
24 TestAST InputAST(Decls.str() + TestInput.str());
25 return !match(Matcher, InputAST.context()).empty();
26}
27
28TEST(SmartPointerAccessorCachingTest, MatchesClassWithStarArrowGet) {
29 llvm::StringRef Decls(R"cc(
30 namespace std {
31 template <class T>
32 struct unique_ptr {
33 T* operator->() const;
34 T& operator*() const;
35 T* get() const;
36 };
37 } // namespace std
38
39 template <class T>
40 using UniquePtrAlias = std::unique_ptr<T>;
41
42 struct S { int i; };
43 )cc");
44
45 EXPECT_TRUE(matches(Decls,
46 "int target(std::unique_ptr<S> P) { return (*P).i; }",
47 isSmartPointerLikeOperatorStar()));
48 EXPECT_TRUE(matches(Decls,
49 "int target(std::unique_ptr<S> P) { return (*P).i; }",
50 isPointerLikeOperatorStar()));
51
52 EXPECT_TRUE(matches(Decls,
53 "int target(std::unique_ptr<S> P) { return P->i; }",
54 isSmartPointerLikeOperatorArrow()));
55 EXPECT_TRUE(matches(Decls,
56 "int target(std::unique_ptr<S> P) { return P->i; }",
57 isPointerLikeOperatorArrow()));
58
59 EXPECT_TRUE(matches(Decls,
60 "int target(std::unique_ptr<S> P) { return P.get()->i; }",
61 isSmartPointerLikeGetMethodCall()));
62
63 EXPECT_TRUE(matches(Decls, "int target(UniquePtrAlias<S> P) { return P->i; }",
64 isSmartPointerLikeOperatorArrow()));
65 EXPECT_TRUE(matches(Decls, "int target(UniquePtrAlias<S> P) { return P->i; }",
66 isPointerLikeOperatorArrow()));
67}
68
69TEST(SmartPointerAccessorCachingTest, MatchesClassWithStarArrow) {
70 llvm::StringRef Decls(R"cc(
71 namespace std {
72 template <class T>
73 struct unique_ptr {
74 T* operator->() const;
75 T& operator*() const;
76 };
77 } // namespace std
78
79 template <class T>
80 using UniquePtrAlias = std::unique_ptr<T>;
81
82 struct S { int i; };
83 )cc");
84
85 EXPECT_FALSE(matches(Decls,
86 "int target(std::unique_ptr<S> P) { return (*P).i; }",
87 isSmartPointerLikeOperatorStar()));
88 EXPECT_TRUE(matches(Decls,
89 "int target(std::unique_ptr<S> P) { return (*P).i; }",
90 isPointerLikeOperatorStar()));
91
92 EXPECT_FALSE(matches(Decls,
93 "int target(std::unique_ptr<S> P) { return P->i; }",
94 isSmartPointerLikeOperatorArrow()));
95 EXPECT_TRUE(matches(Decls,
96 "int target(std::unique_ptr<S> P) { return P->i; }",
97 isPointerLikeOperatorArrow()));
98
99 EXPECT_FALSE(matches(Decls,
100 "int target(UniquePtrAlias<S> P) { return P->i; }",
101 isSmartPointerLikeOperatorArrow()));
102 EXPECT_TRUE(matches(Decls, "int target(UniquePtrAlias<S> P) { return P->i; }",
103 isPointerLikeOperatorArrow()));
104}
105
106TEST(SmartPointerAccessorCachingTest, NoMatchIfUnexpectedReturnTypes) {
107 llvm::StringRef Decls(R"cc(
108 namespace std {
109 // unique_ptr isn't really like this, but we aren't matching by name
110 template <class T, class U>
111 struct unique_ptr {
112 U* operator->() const;
113 T& operator*() const;
114 T* get() const;
115 };
116 } // namespace std
117
118 struct S { int i; };
119 struct T { int j; };
120 )cc");
121
122 EXPECT_FALSE(matches(Decls,
123 "int target(std::unique_ptr<S, T> P) { return (*P).i; }",
124 isSmartPointerLikeOperatorStar()));
125 EXPECT_FALSE(matches(Decls,
126 "int target(std::unique_ptr<S, T> P) { return (*P).i; }",
127 isPointerLikeOperatorStar()));
128
129 EXPECT_FALSE(matches(Decls,
130 "int target(std::unique_ptr<S, T> P) { return P->j; }",
131 isSmartPointerLikeOperatorArrow()));
132 EXPECT_FALSE(matches(Decls,
133 "int target(std::unique_ptr<S, T> P) { return P->j; }",
134 isPointerLikeOperatorArrow()));
135 // The class matching arguably accidentally matches, just because the
136 // instantiation is with S, S. Hopefully doesn't happen too much in real code
137 // with such operator* and operator-> overloads.
138 EXPECT_TRUE(matches(Decls,
139 "int target(std::unique_ptr<S, S> P) { return P->i; }",
140 isSmartPointerLikeOperatorArrow()));
141 EXPECT_TRUE(matches(Decls,
142 "int target(std::unique_ptr<S, S> P) { return P->i; }",
143 isPointerLikeOperatorArrow()));
144}
145
146TEST(SmartPointerAccessorCachingTest, NoMatchIfBinaryStar) {
147 llvm::StringRef Decls(R"cc(
148 namespace std {
149 template <class T>
150 struct unique_ptr {
151 T* operator->() const;
152 T& operator*(int x) const;
153 T* get() const;
154 };
155 } // namespace std
156
157 struct S { int i; };
158 )cc");
159
160 EXPECT_FALSE(
161 matches(Decls, "int target(std::unique_ptr<S> P) { return (P * 10).i; }",
162 isSmartPointerLikeOperatorStar()));
163 EXPECT_FALSE(
164 matches(Decls, "int target(std::unique_ptr<S> P) { return (P * 10).i; }",
165 isPointerLikeOperatorStar()));
166}
167
168TEST(SmartPointerAccessorCachingTest, NoMatchIfNoConstOverloads) {
169 llvm::StringRef Decls(R"cc(
170 namespace std {
171 template <class T>
172 struct unique_ptr {
173 T* operator->();
174 T& operator*();
175 T* get();
176 };
177 } // namespace std
178
179 struct S { int i; };
180 )cc");
181
182 EXPECT_FALSE(matches(Decls,
183 "int target(std::unique_ptr<S> P) { return (*P).i; }",
184 isSmartPointerLikeOperatorStar()));
185 EXPECT_FALSE(matches(Decls,
186 "int target(std::unique_ptr<S> P) { return (*P).i; }",
187 isPointerLikeOperatorStar()));
188
189 EXPECT_FALSE(matches(Decls,
190 "int target(std::unique_ptr<S> P) { return P->i; }",
191 isSmartPointerLikeOperatorArrow()));
192 EXPECT_FALSE(matches(Decls,
193 "int target(std::unique_ptr<S> P) { return P->i; }",
194 isPointerLikeOperatorArrow()));
195
196 EXPECT_FALSE(
197 matches(Decls, "int target(std::unique_ptr<S> P) { return P.get()->i; }",
198 isSmartPointerLikeGetMethodCall()));
199}
200
201TEST(SmartPointerAccessorCachingTest, NoMatchIfNoStarMethod) {
202 llvm::StringRef Decls(R"cc(
203 namespace std {
204 template <class T>
205 struct unique_ptr {
206 T* operator->();
207 T* get();
208 };
209 } // namespace std
210
211 struct S { int i; };
212 )cc");
213
214 EXPECT_FALSE(matches(Decls,
215 "int target(std::unique_ptr<S> P) { return P->i; }",
216 isSmartPointerLikeOperatorArrow()));
217 EXPECT_FALSE(matches(Decls,
218 "int target(std::unique_ptr<S> P) { return P->i; }",
219 isPointerLikeOperatorArrow()));
220
221 EXPECT_FALSE(matches(Decls,
222 "int target(std::unique_ptr<S> P) { return P->i; }",
223 isSmartPointerLikeGetMethodCall()));
224}
225
226TEST(SmartPointerAccessorCachingTest, MatchesWithValueAndNonConstOverloads) {
227 llvm::StringRef Decls(R"cc(
228 namespace std {
229 template <class T>
230 struct optional {
231 const T* operator->() const;
232 T* operator->();
233 const T& operator*() const;
234 T& operator*();
235 const T& value() const;
236 T& value();
237 };
238 } // namespace std
239
240 struct S { int i; };
241 )cc");
242
243 EXPECT_TRUE(matches(
244 Decls, "int target(std::optional<S> &NonConst) { return (*NonConst).i; }",
245 isSmartPointerLikeOperatorStar()));
246 EXPECT_TRUE(matches(
247 Decls, "int target(std::optional<S> &NonConst) { return (*NonConst).i; }",
248 isPointerLikeOperatorStar()));
249
250 EXPECT_TRUE(matches(
251 Decls, "int target(const std::optional<S> &Const) { return (*Const).i; }",
252 isSmartPointerLikeOperatorStar()));
253 EXPECT_TRUE(matches(
254 Decls, "int target(const std::optional<S> &Const) { return (*Const).i; }",
255 isPointerLikeOperatorStar()));
256
257 EXPECT_TRUE(matches(
258 Decls, "int target(std::optional<S> &NonConst) { return NonConst->i; }",
259 isSmartPointerLikeOperatorArrow()));
260 EXPECT_TRUE(matches(
261 Decls, "int target(std::optional<S> &NonConst) { return NonConst->i; }",
262 isPointerLikeOperatorArrow()));
263
264 EXPECT_TRUE(matches(
265 Decls, "int target(const std::optional<S> &Const) { return Const->i; }",
266 isSmartPointerLikeOperatorArrow()));
267 EXPECT_TRUE(matches(
268 Decls, "int target(const std::optional<S> &Const) { return Const->i; }",
269 isPointerLikeOperatorArrow()));
270
271 EXPECT_TRUE(matches(
272 Decls,
273 "int target(std::optional<S> &NonConst) { return NonConst.value().i; }",
274 isSmartPointerLikeValueMethodCall()));
275 EXPECT_TRUE(matches(
276 Decls,
277 "int target(const std::optional<S> &Const) { return Const.value().i; }",
278 isSmartPointerLikeValueMethodCall()));
279}
280
281TEST(SmartPointerAccessorCachingTest, MatchesWithTypeAliases) {
282 llvm::StringRef Decls(R"cc(
283 template <class T>
284 struct HasGetAndValue {
285 using pointer_t = T*;
286 using reference_t = T&;
287
288 const pointer_t operator->() const;
289 pointer_t operator->();
290 const reference_t operator*() const;
291 reference_t operator*();
292 const reference_t value() const;
293 reference_t value();
294 const pointer_t get() const;
295 pointer_t get();
296 };
297
298 struct S { int i; };
299 )cc");
300
301 EXPECT_TRUE(matches(
302 Decls,
303 "int target(HasGetAndValue<S> &NonConst) { return (*NonConst).i; }",
304 isSmartPointerLikeOperatorStar()));
305 EXPECT_TRUE(matches(
306 Decls,
307 "int target(HasGetAndValue<S> &NonConst) { return (*NonConst).i; }",
308 isPointerLikeOperatorStar()));
309
310 EXPECT_TRUE(matches(
311 Decls,
312 "int target(const HasGetAndValue<S> &Const) { return (*Const).i; }",
313 isSmartPointerLikeOperatorStar()));
314 EXPECT_TRUE(matches(
315 Decls,
316 "int target(const HasGetAndValue<S> &Const) { return (*Const).i; }",
317 isPointerLikeOperatorStar()));
318
319 EXPECT_TRUE(matches(
320 Decls, "int target(HasGetAndValue<S> &NonConst) { return NonConst->i; }",
321 isSmartPointerLikeOperatorArrow()));
322 EXPECT_TRUE(matches(
323 Decls, "int target(HasGetAndValue<S> &NonConst) { return NonConst->i; }",
324 isPointerLikeOperatorArrow()));
325
326 EXPECT_TRUE(matches(
327 Decls, "int target(const HasGetAndValue<S> &Const) { return Const->i; }",
328 isSmartPointerLikeOperatorArrow()));
329 EXPECT_TRUE(matches(
330 Decls, "int target(const HasGetAndValue<S> &Const) { return Const->i; }",
331 isPointerLikeOperatorArrow()));
332
333 EXPECT_TRUE(matches(
334 Decls,
335 "int target(HasGetAndValue<S> &NonConst) { return NonConst.value().i; }",
336 isSmartPointerLikeValueMethodCall()));
337 EXPECT_TRUE(matches(
338 Decls,
339 "int target(const HasGetAndValue<S> &Const) { return Const.value().i; }",
340 isSmartPointerLikeValueMethodCall()));
341 EXPECT_TRUE(matches(
342 Decls,
343 "int target(HasGetAndValue<S> &NonConst) { return NonConst.get()->i; }",
344 isSmartPointerLikeGetMethodCall()));
345 EXPECT_TRUE(matches(
346 Decls,
347 "int target(const HasGetAndValue<S> &Const) { return Const.get()->i; }",
348 isSmartPointerLikeGetMethodCall()));
349}
350
351TEST(SmartPointerAccessorCachingTest, Renamed) {
352 llvm::StringRef Decls(R"cc(
353 namespace std {
354 template <class T>
355 struct unique_ptr {
356 T* operator->() const;
357 T& operator*() const;
358 T* Get() const;
359 T& Value() const;
360 };
361 } // namespace std
362
363 template <class T>
364 using UniquePtrAlias = std::unique_ptr<T>;
365
366 struct S { int i; };
367 )cc");
368
369 EXPECT_TRUE(matches(Decls,
370 "int target(std::unique_ptr<S> P) { return (*P).i; }",
371 isPointerLikeOperatorStar()));
372
373 EXPECT_TRUE(matches(Decls,
374 "int target(std::unique_ptr<S> P) { return P->i; }",
375 isPointerLikeOperatorArrow()));
376
377 EXPECT_TRUE(matches(Decls,
378 "int target(std::unique_ptr<S> P) { return P.Get()->i; }",
379 isSmartPointerLikeGetMethodCall("Get")));
380 EXPECT_TRUE(matches(Decls,
381 "int target(UniquePtrAlias<S> P) { return P.Get()->i; }",
382 isSmartPointerLikeGetMethodCall("Get")));
383
384 EXPECT_TRUE(
385 matches(Decls, "int target(std::unique_ptr<S> P) { return P.Value().i; }",
386 isSmartPointerLikeValueMethodCall("Value")));
387 EXPECT_TRUE(matches(Decls,
388 "int target(UniquePtrAlias<S> P) { return P.Value().i; }",
389 isSmartPointerLikeValueMethodCall("Value")));
390
391 EXPECT_TRUE(matches(Decls, "int target(UniquePtrAlias<S> P) { return P->i; }",
392 isPointerLikeOperatorArrow()));
393}
394
395} // namespace
396} // namespace clang::dataflow
397

Provided by KDAB

Privacy Policy
Update your C++ knowledge – Modern C++11/14/17 Training
Find out more

source code of clang/unittests/Analysis/FlowSensitive/SmartPointerAccessorCachingTest.cpp