brintos

brintos / llvm-project-archived public Read only

0
0
Text · 13.2 KiB · 5d3d5b0 Raw
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