xref: /llvm-project/clang/unittests/Analysis/FlowSensitive/SmartPointerAccessorCachingTest.cpp (revision 54309b1c2f7a9acdb91ae1735cf4eb0877eadfc0)
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 
16 namespace clang::dataflow {
17 namespace {
18 
19 using clang::ast_matchers::match;
20 
21 template <typename MatcherT>
22 bool 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 
28 TEST(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                       isSmartPointerLikeOperatorArrow()));
51   EXPECT_TRUE(matches(Decls,
52                       "int target(std::unique_ptr<S> P) { return P.get()->i; }",
53                       isSmartPointerLikeGetMethodCall()));
54 
55   EXPECT_TRUE(matches(Decls, "int target(UniquePtrAlias<S> P) { return P->i; }",
56                       isSmartPointerLikeOperatorArrow()));
57 }
58 
59 TEST(SmartPointerAccessorCachingTest, NoMatchIfUnexpectedReturnTypes) {
60   llvm::StringRef Decls(R"cc(
61     namespace std {
62     // unique_ptr isn't really like this, but we aren't matching by name
63     template <class T, class U>
64     struct unique_ptr {
65       U* operator->() const;
66       T& operator*() const;
67       T* get() const;
68     };
69     }  // namespace std
70 
71     struct S { int i; };
72     struct T { int j; };
73   )cc");
74 
75   EXPECT_FALSE(matches(Decls,
76                        "int target(std::unique_ptr<S, T> P) { return (*P).i; }",
77                        isSmartPointerLikeOperatorStar()));
78   EXPECT_FALSE(matches(Decls,
79                        "int target(std::unique_ptr<S, T> P) { return P->j; }",
80                        isSmartPointerLikeOperatorArrow()));
81   // The class matching arguably accidentally matches, just because the
82   // instantiation is with S, S. Hopefully doesn't happen too much in real code
83   // with such operator* and operator-> overloads.
84   EXPECT_TRUE(matches(Decls,
85                       "int target(std::unique_ptr<S, S> P) { return P->i; }",
86                       isSmartPointerLikeOperatorArrow()));
87 }
88 
89 TEST(SmartPointerAccessorCachingTest, NoMatchIfBinaryStar) {
90   llvm::StringRef Decls(R"cc(
91     namespace std {
92     template <class T>
93     struct unique_ptr {
94       T* operator->() const;
95       T& operator*(int x) const;
96       T* get() const;
97     };
98     }  // namespace std
99 
100     struct S { int i; };
101   )cc");
102 
103   EXPECT_FALSE(
104       matches(Decls, "int target(std::unique_ptr<S> P) { return (P * 10).i; }",
105               isSmartPointerLikeOperatorStar()));
106 }
107 
108 TEST(SmartPointerAccessorCachingTest, NoMatchIfNoConstOverloads) {
109   llvm::StringRef Decls(R"cc(
110     namespace std {
111     template <class T>
112     struct unique_ptr {
113       T* operator->();
114       T& operator*();
115       T* get();
116     };
117     }  // namespace std
118 
119     struct S { int i; };
120   )cc");
121 
122   EXPECT_FALSE(matches(Decls,
123                        "int target(std::unique_ptr<S> P) { return (*P).i; }",
124                        isSmartPointerLikeOperatorStar()));
125   EXPECT_FALSE(matches(Decls,
126                        "int target(std::unique_ptr<S> P) { return P->i; }",
127                        isSmartPointerLikeOperatorArrow()));
128   EXPECT_FALSE(
129       matches(Decls, "int target(std::unique_ptr<S> P) { return P.get()->i; }",
130               isSmartPointerLikeGetMethodCall()));
131 }
132 
133 TEST(SmartPointerAccessorCachingTest, NoMatchIfNoStarMethod) {
134   llvm::StringRef Decls(R"cc(
135     namespace std {
136     template <class T>
137     struct unique_ptr {
138       T* operator->();
139       T* get();
140     };
141     }  // namespace std
142 
143     struct S { int i; };
144   )cc");
145 
146   EXPECT_FALSE(matches(Decls,
147                        "int target(std::unique_ptr<S> P) { return P->i; }",
148                        isSmartPointerLikeOperatorArrow()));
149   EXPECT_FALSE(matches(Decls,
150                        "int target(std::unique_ptr<S> P) { return P->i; }",
151                        isSmartPointerLikeGetMethodCall()));
152 }
153 
154 TEST(SmartPointerAccessorCachingTest, MatchesWithValueAndNonConstOverloads) {
155   llvm::StringRef Decls(R"cc(
156     namespace std {
157     template <class T>
158     struct optional {
159       const T* operator->() const;
160       T* operator->();
161       const T& operator*() const;
162       T& operator*();
163       const T& value() const;
164       T& value();
165     };
166     }  // namespace std
167 
168     struct S { int i; };
169   )cc");
170 
171   EXPECT_TRUE(matches(
172       Decls, "int target(std::optional<S> &NonConst) { return (*NonConst).i; }",
173       isSmartPointerLikeOperatorStar()));
174   EXPECT_TRUE(matches(
175       Decls, "int target(const std::optional<S> &Const) { return (*Const).i; }",
176       isSmartPointerLikeOperatorStar()));
177   EXPECT_TRUE(matches(
178       Decls, "int target(std::optional<S> &NonConst) { return NonConst->i; }",
179       isSmartPointerLikeOperatorArrow()));
180   EXPECT_TRUE(matches(
181       Decls, "int target(const std::optional<S> &Const) { return Const->i; }",
182       isSmartPointerLikeOperatorArrow()));
183   EXPECT_TRUE(matches(
184       Decls,
185       "int target(std::optional<S> &NonConst) { return NonConst.value().i; }",
186       isSmartPointerLikeValueMethodCall()));
187   EXPECT_TRUE(matches(
188       Decls,
189       "int target(const std::optional<S> &Const) { return Const.value().i; }",
190       isSmartPointerLikeValueMethodCall()));
191 }
192 
193 } // namespace
194 } // namespace clang::dataflow
195