397 lines · cpp
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-exception6//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 std38 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 std78 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 name110 template <class T, class U>111 struct unique_ptr {112 U* operator->() const;113 T& operator*() const;114 T* get() const;115 };116 } // namespace std117 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 the136 // instantiation is with S, S. Hopefully doesn't happen too much in real code137 // 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 std156 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 std178 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 std210 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 std239 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 std362 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} // namespace396} // namespace clang::dataflow397