xref: /llvm-project/clang/unittests/Analysis/FlowSensitive/SmartPointerAccessorCachingTest.cpp (revision 54309b1c2f7a9acdb91ae1735cf4eb0877eadfc0)
1*54309b1cSJan Voung //===- unittests/Analysis/FlowSensitive/SmartPointerAccessorCachingTest.cpp ==//
2*54309b1cSJan Voung //
3*54309b1cSJan Voung // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*54309b1cSJan Voung // See https://llvm.org/LICENSE.txt for license information.
5*54309b1cSJan Voung // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*54309b1cSJan Voung //
7*54309b1cSJan Voung //===----------------------------------------------------------------------===//
8*54309b1cSJan Voung 
9*54309b1cSJan Voung #include "clang/Analysis/FlowSensitive/SmartPointerAccessorCaching.h"
10*54309b1cSJan Voung 
11*54309b1cSJan Voung #include "clang/ASTMatchers/ASTMatchFinder.h"
12*54309b1cSJan Voung #include "clang/Testing/TestAST.h"
13*54309b1cSJan Voung #include "llvm/ADT/StringRef.h"
14*54309b1cSJan Voung #include "gtest/gtest.h"
15*54309b1cSJan Voung 
16*54309b1cSJan Voung namespace clang::dataflow {
17*54309b1cSJan Voung namespace {
18*54309b1cSJan Voung 
19*54309b1cSJan Voung using clang::ast_matchers::match;
20*54309b1cSJan Voung 
21*54309b1cSJan Voung template <typename MatcherT>
22*54309b1cSJan Voung bool matches(llvm::StringRef Decls, llvm::StringRef TestInput,
23*54309b1cSJan Voung              MatcherT Matcher) {
24*54309b1cSJan Voung   TestAST InputAST(Decls.str() + TestInput.str());
25*54309b1cSJan Voung   return !match(Matcher, InputAST.context()).empty();
26*54309b1cSJan Voung }
27*54309b1cSJan Voung 
28*54309b1cSJan Voung TEST(SmartPointerAccessorCachingTest, MatchesClassWithStarArrowGet) {
29*54309b1cSJan Voung   llvm::StringRef Decls(R"cc(
30*54309b1cSJan Voung     namespace std {
31*54309b1cSJan Voung     template <class T>
32*54309b1cSJan Voung     struct unique_ptr {
33*54309b1cSJan Voung       T* operator->() const;
34*54309b1cSJan Voung       T& operator*() const;
35*54309b1cSJan Voung       T* get() const;
36*54309b1cSJan Voung     };
37*54309b1cSJan Voung     }  // namespace std
38*54309b1cSJan Voung 
39*54309b1cSJan Voung     template <class T>
40*54309b1cSJan Voung     using UniquePtrAlias = std::unique_ptr<T>;
41*54309b1cSJan Voung 
42*54309b1cSJan Voung     struct S { int i; };
43*54309b1cSJan Voung   )cc");
44*54309b1cSJan Voung 
45*54309b1cSJan Voung   EXPECT_TRUE(matches(Decls,
46*54309b1cSJan Voung                       "int target(std::unique_ptr<S> P) { return (*P).i; }",
47*54309b1cSJan Voung                       isSmartPointerLikeOperatorStar()));
48*54309b1cSJan Voung   EXPECT_TRUE(matches(Decls,
49*54309b1cSJan Voung                       "int target(std::unique_ptr<S> P) { return P->i; }",
50*54309b1cSJan Voung                       isSmartPointerLikeOperatorArrow()));
51*54309b1cSJan Voung   EXPECT_TRUE(matches(Decls,
52*54309b1cSJan Voung                       "int target(std::unique_ptr<S> P) { return P.get()->i; }",
53*54309b1cSJan Voung                       isSmartPointerLikeGetMethodCall()));
54*54309b1cSJan Voung 
55*54309b1cSJan Voung   EXPECT_TRUE(matches(Decls, "int target(UniquePtrAlias<S> P) { return P->i; }",
56*54309b1cSJan Voung                       isSmartPointerLikeOperatorArrow()));
57*54309b1cSJan Voung }
58*54309b1cSJan Voung 
59*54309b1cSJan Voung TEST(SmartPointerAccessorCachingTest, NoMatchIfUnexpectedReturnTypes) {
60*54309b1cSJan Voung   llvm::StringRef Decls(R"cc(
61*54309b1cSJan Voung     namespace std {
62*54309b1cSJan Voung     // unique_ptr isn't really like this, but we aren't matching by name
63*54309b1cSJan Voung     template <class T, class U>
64*54309b1cSJan Voung     struct unique_ptr {
65*54309b1cSJan Voung       U* operator->() const;
66*54309b1cSJan Voung       T& operator*() const;
67*54309b1cSJan Voung       T* get() const;
68*54309b1cSJan Voung     };
69*54309b1cSJan Voung     }  // namespace std
70*54309b1cSJan Voung 
71*54309b1cSJan Voung     struct S { int i; };
72*54309b1cSJan Voung     struct T { int j; };
73*54309b1cSJan Voung   )cc");
74*54309b1cSJan Voung 
75*54309b1cSJan Voung   EXPECT_FALSE(matches(Decls,
76*54309b1cSJan Voung                        "int target(std::unique_ptr<S, T> P) { return (*P).i; }",
77*54309b1cSJan Voung                        isSmartPointerLikeOperatorStar()));
78*54309b1cSJan Voung   EXPECT_FALSE(matches(Decls,
79*54309b1cSJan Voung                        "int target(std::unique_ptr<S, T> P) { return P->j; }",
80*54309b1cSJan Voung                        isSmartPointerLikeOperatorArrow()));
81*54309b1cSJan Voung   // The class matching arguably accidentally matches, just because the
82*54309b1cSJan Voung   // instantiation is with S, S. Hopefully doesn't happen too much in real code
83*54309b1cSJan Voung   // with such operator* and operator-> overloads.
84*54309b1cSJan Voung   EXPECT_TRUE(matches(Decls,
85*54309b1cSJan Voung                       "int target(std::unique_ptr<S, S> P) { return P->i; }",
86*54309b1cSJan Voung                       isSmartPointerLikeOperatorArrow()));
87*54309b1cSJan Voung }
88*54309b1cSJan Voung 
89*54309b1cSJan Voung TEST(SmartPointerAccessorCachingTest, NoMatchIfBinaryStar) {
90*54309b1cSJan Voung   llvm::StringRef Decls(R"cc(
91*54309b1cSJan Voung     namespace std {
92*54309b1cSJan Voung     template <class T>
93*54309b1cSJan Voung     struct unique_ptr {
94*54309b1cSJan Voung       T* operator->() const;
95*54309b1cSJan Voung       T& operator*(int x) const;
96*54309b1cSJan Voung       T* get() const;
97*54309b1cSJan Voung     };
98*54309b1cSJan Voung     }  // namespace std
99*54309b1cSJan Voung 
100*54309b1cSJan Voung     struct S { int i; };
101*54309b1cSJan Voung   )cc");
102*54309b1cSJan Voung 
103*54309b1cSJan Voung   EXPECT_FALSE(
104*54309b1cSJan Voung       matches(Decls, "int target(std::unique_ptr<S> P) { return (P * 10).i; }",
105*54309b1cSJan Voung               isSmartPointerLikeOperatorStar()));
106*54309b1cSJan Voung }
107*54309b1cSJan Voung 
108*54309b1cSJan Voung TEST(SmartPointerAccessorCachingTest, NoMatchIfNoConstOverloads) {
109*54309b1cSJan Voung   llvm::StringRef Decls(R"cc(
110*54309b1cSJan Voung     namespace std {
111*54309b1cSJan Voung     template <class T>
112*54309b1cSJan Voung     struct unique_ptr {
113*54309b1cSJan Voung       T* operator->();
114*54309b1cSJan Voung       T& operator*();
115*54309b1cSJan Voung       T* get();
116*54309b1cSJan Voung     };
117*54309b1cSJan Voung     }  // namespace std
118*54309b1cSJan Voung 
119*54309b1cSJan Voung     struct S { int i; };
120*54309b1cSJan Voung   )cc");
121*54309b1cSJan Voung 
122*54309b1cSJan Voung   EXPECT_FALSE(matches(Decls,
123*54309b1cSJan Voung                        "int target(std::unique_ptr<S> P) { return (*P).i; }",
124*54309b1cSJan Voung                        isSmartPointerLikeOperatorStar()));
125*54309b1cSJan Voung   EXPECT_FALSE(matches(Decls,
126*54309b1cSJan Voung                        "int target(std::unique_ptr<S> P) { return P->i; }",
127*54309b1cSJan Voung                        isSmartPointerLikeOperatorArrow()));
128*54309b1cSJan Voung   EXPECT_FALSE(
129*54309b1cSJan Voung       matches(Decls, "int target(std::unique_ptr<S> P) { return P.get()->i; }",
130*54309b1cSJan Voung               isSmartPointerLikeGetMethodCall()));
131*54309b1cSJan Voung }
132*54309b1cSJan Voung 
133*54309b1cSJan Voung TEST(SmartPointerAccessorCachingTest, NoMatchIfNoStarMethod) {
134*54309b1cSJan Voung   llvm::StringRef Decls(R"cc(
135*54309b1cSJan Voung     namespace std {
136*54309b1cSJan Voung     template <class T>
137*54309b1cSJan Voung     struct unique_ptr {
138*54309b1cSJan Voung       T* operator->();
139*54309b1cSJan Voung       T* get();
140*54309b1cSJan Voung     };
141*54309b1cSJan Voung     }  // namespace std
142*54309b1cSJan Voung 
143*54309b1cSJan Voung     struct S { int i; };
144*54309b1cSJan Voung   )cc");
145*54309b1cSJan Voung 
146*54309b1cSJan Voung   EXPECT_FALSE(matches(Decls,
147*54309b1cSJan Voung                        "int target(std::unique_ptr<S> P) { return P->i; }",
148*54309b1cSJan Voung                        isSmartPointerLikeOperatorArrow()));
149*54309b1cSJan Voung   EXPECT_FALSE(matches(Decls,
150*54309b1cSJan Voung                        "int target(std::unique_ptr<S> P) { return P->i; }",
151*54309b1cSJan Voung                        isSmartPointerLikeGetMethodCall()));
152*54309b1cSJan Voung }
153*54309b1cSJan Voung 
154*54309b1cSJan Voung TEST(SmartPointerAccessorCachingTest, MatchesWithValueAndNonConstOverloads) {
155*54309b1cSJan Voung   llvm::StringRef Decls(R"cc(
156*54309b1cSJan Voung     namespace std {
157*54309b1cSJan Voung     template <class T>
158*54309b1cSJan Voung     struct optional {
159*54309b1cSJan Voung       const T* operator->() const;
160*54309b1cSJan Voung       T* operator->();
161*54309b1cSJan Voung       const T& operator*() const;
162*54309b1cSJan Voung       T& operator*();
163*54309b1cSJan Voung       const T& value() const;
164*54309b1cSJan Voung       T& value();
165*54309b1cSJan Voung     };
166*54309b1cSJan Voung     }  // namespace std
167*54309b1cSJan Voung 
168*54309b1cSJan Voung     struct S { int i; };
169*54309b1cSJan Voung   )cc");
170*54309b1cSJan Voung 
171*54309b1cSJan Voung   EXPECT_TRUE(matches(
172*54309b1cSJan Voung       Decls, "int target(std::optional<S> &NonConst) { return (*NonConst).i; }",
173*54309b1cSJan Voung       isSmartPointerLikeOperatorStar()));
174*54309b1cSJan Voung   EXPECT_TRUE(matches(
175*54309b1cSJan Voung       Decls, "int target(const std::optional<S> &Const) { return (*Const).i; }",
176*54309b1cSJan Voung       isSmartPointerLikeOperatorStar()));
177*54309b1cSJan Voung   EXPECT_TRUE(matches(
178*54309b1cSJan Voung       Decls, "int target(std::optional<S> &NonConst) { return NonConst->i; }",
179*54309b1cSJan Voung       isSmartPointerLikeOperatorArrow()));
180*54309b1cSJan Voung   EXPECT_TRUE(matches(
181*54309b1cSJan Voung       Decls, "int target(const std::optional<S> &Const) { return Const->i; }",
182*54309b1cSJan Voung       isSmartPointerLikeOperatorArrow()));
183*54309b1cSJan Voung   EXPECT_TRUE(matches(
184*54309b1cSJan Voung       Decls,
185*54309b1cSJan Voung       "int target(std::optional<S> &NonConst) { return NonConst.value().i; }",
186*54309b1cSJan Voung       isSmartPointerLikeValueMethodCall()));
187*54309b1cSJan Voung   EXPECT_TRUE(matches(
188*54309b1cSJan Voung       Decls,
189*54309b1cSJan Voung       "int target(const std::optional<S> &Const) { return Const.value().i; }",
190*54309b1cSJan Voung       isSmartPointerLikeValueMethodCall()));
191*54309b1cSJan Voung }
192*54309b1cSJan Voung 
193*54309b1cSJan Voung } // namespace
194*54309b1cSJan Voung } // namespace clang::dataflow
195