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