| // Copyright 2023 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| #include <algorithm> |
| #include <map> |
| #include <memory> |
| #include <numeric> |
| #include <vector> |
| |
| #include "base/memory/raw_ptr.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| |
| #define RAW_PTR_EXCLUSION __attribute__((annotate("raw_ptr_exclusion"))) |
| |
| struct S {}; |
| |
| class A { |
| public: |
| A() : member(init()) {} |
| |
| A(const std::vector<raw_ptr<S>>& arg, const std::vector<const char*>& arg2) |
| : member(arg), member2(arg2) {} |
| |
| A(const std::vector<raw_ptr<S>>* arg) : member(*arg) {} |
| |
| std::vector<raw_ptr<S>> init() { return {}; } |
| |
| std::vector<raw_ptr<S>> do_something(std::vector<raw_ptr<S>>& a, |
| S* i, |
| std::vector<raw_ptr<S>>& b); |
| |
| void set(const std::vector<raw_ptr<S>> arg); |
| |
| private: |
| std::vector<raw_ptr<S>> member; |
| std::vector<const char*> member2; |
| }; |
| |
| std::vector<raw_ptr<S>> A::do_something(std::vector<raw_ptr<S>>& a, |
| S* i, |
| std::vector<raw_ptr<S>>& b) { |
| a.push_back(i); |
| member = b; |
| b = a; |
| return a; |
| } |
| |
| void A::set(const std::vector<raw_ptr<S>> arg) { |
| member = arg; |
| } |
| |
| class B { |
| public: |
| B() = default; |
| |
| std::vector<raw_ptr<S>> get() { return member; } |
| |
| std::vector<raw_ptr<S>> get2(); |
| |
| private: |
| std::vector<raw_ptr<S>> member; |
| }; |
| |
| std::vector<raw_ptr<S>> B::get2() { |
| return member; |
| } |
| |
| class C { |
| public: |
| C() = default; |
| |
| const std::vector<raw_ptr<S>>& get() { return member; } |
| |
| private: |
| std::vector<raw_ptr<S>> member; |
| }; |
| |
| class D { |
| public: |
| D() = default; |
| |
| std::vector<raw_ptr<S>>* get() { return &member; } |
| |
| private: |
| std::vector<raw_ptr<S>> member; |
| }; |
| |
| class E { |
| public: |
| E() = default; |
| |
| void set(const std::vector<raw_ptr<S>>& arg) { member = arg; } |
| |
| private: |
| std::vector<raw_ptr<S>> member; |
| }; |
| |
| class F { |
| public: |
| F() = default; |
| |
| void init() { |
| std::vector<raw_ptr<S>> temp; |
| temp.push_back(nullptr); |
| member = temp; |
| |
| { |
| std::vector<raw_ptr<S>>::iterator it; |
| it = temp.begin(); |
| ++it; |
| } |
| |
| { |
| std::vector<raw_ptr<S>>::iterator it = temp.begin(); |
| ++it; |
| } |
| } |
| |
| private: |
| std::vector<raw_ptr<S>> member; |
| }; |
| |
| class G { |
| public: |
| G() = default; |
| |
| void init() { |
| std::vector<raw_ptr<S>> temp = member; |
| temp.push_back(nullptr); |
| } |
| |
| private: |
| std::vector<raw_ptr<S>> member; |
| }; |
| |
| class H { |
| public: |
| H() = default; |
| |
| std::vector<raw_ptr<S>> init() { |
| std::vector<raw_ptr<S>> temp; |
| temp = member; |
| temp.push_back(nullptr); |
| |
| std::vector<raw_ptr<S>> temp2; |
| temp2 = temp; |
| return temp2; |
| } |
| |
| private: |
| std::vector<raw_ptr<S>> member; |
| }; |
| |
| class I { |
| public: |
| I() = default; |
| |
| std::vector<raw_ptr<S>> init() { |
| std::vector<raw_ptr<S>> temp; |
| temp = std::move(member); |
| temp.push_back(nullptr); |
| return temp; |
| } |
| |
| private: |
| std::vector<raw_ptr<S>> member; |
| }; |
| |
| class J { |
| public: |
| J() = default; |
| |
| void init() { |
| prepare(member); |
| prepare2(&member); |
| prepare(get()); |
| prepare(*get_2()); |
| } |
| |
| std::vector<raw_ptr<S>>& get() { return member; } |
| |
| std::vector<raw_ptr<S>>* get_2() { return &member; } |
| |
| void prepare(std::vector<raw_ptr<S>>& v) { v.push_back(nullptr); } |
| |
| void prepare2(std::vector<raw_ptr<S>>* v) { v->push_back(nullptr); } |
| |
| private: |
| std::vector<raw_ptr<S>> member; |
| }; |
| |
| class K { |
| public: |
| K() = default; |
| |
| std::vector<raw_ptr<S>> init() { |
| std::vector<raw_ptr<S>> temp; |
| temp.swap(member); |
| return temp; |
| } |
| |
| std::vector<raw_ptr<S>> init2() { |
| std::vector<raw_ptr<S>> temp; |
| std::swap(temp, member); |
| return temp; |
| } |
| |
| private: |
| std::vector<raw_ptr<S>> member; |
| }; |
| |
| class L { |
| public: |
| L() = default; |
| |
| std::vector<raw_ptr<S>> init() { |
| std::vector<raw_ptr<S>> temp; |
| temp.push_back(nullptr); |
| member.swap(temp); |
| return temp; |
| } |
| |
| std::vector<raw_ptr<S>> init2() { |
| std::vector<raw_ptr<S>> temp; |
| temp.push_back(nullptr); |
| std::swap(member, temp); |
| return temp; |
| } |
| |
| private: |
| std::vector<raw_ptr<S>> member; |
| }; |
| |
| class M { |
| public: |
| M() = default; |
| void set(std::vector<raw_ptr<S>>* v) { *v = member; } |
| |
| private: |
| std::vector<raw_ptr<S>> member; |
| }; |
| |
| class N { |
| public: |
| N() : member() {} |
| |
| std::vector<raw_ptr<S>>* get() { |
| std::vector<raw_ptr<S>>* temp; |
| temp = &member; |
| return temp; |
| } |
| |
| std::vector<raw_ptr<S>>* get_() { return get(); } |
| |
| std::vector<raw_ptr<S>> get__() { return *get(); } |
| |
| std::vector<raw_ptr<S>> get2() { |
| std::vector<raw_ptr<S>>* temp; |
| temp = get(); |
| |
| std::vector<raw_ptr<S>>* temp2 = get(); |
| (void)temp2; |
| |
| std::vector<raw_ptr<S>> temp3; |
| temp3 = *get(); |
| (void)temp3; |
| |
| std::vector<raw_ptr<S>> temp4 = *get(); |
| (void)temp4; |
| return *temp; |
| } |
| |
| const std::vector<raw_ptr<S>>* get3() { |
| std::vector<raw_ptr<S>>* temp = &member; |
| return temp; |
| } |
| |
| std::vector<raw_ptr<S>> get4() { |
| std::vector<raw_ptr<S>>* temp; |
| temp = &member; |
| |
| std::vector<raw_ptr<S>>* temp2 = temp; |
| |
| std::vector<raw_ptr<S>>** temp3 = &temp2; |
| (void)temp3; |
| |
| std::vector<raw_ptr<S>>& ref = *temp; |
| (void)ref; |
| return *temp2; |
| } |
| |
| const std::vector<raw_ptr<S>>& get5() { |
| std::vector<raw_ptr<S>>* temp; |
| temp = &member; |
| return *temp; |
| } |
| |
| private: |
| std::vector<raw_ptr<S>> member; |
| }; |
| |
| struct obj { |
| std::vector<raw_ptr<S>> member; |
| std::vector<raw_ptr<std::map<int, int>>> member2; |
| }; |
| |
| struct obj2 { |
| RAW_PTR_EXCLUSION std::vector<S*> member; |
| }; |
| |
| struct obj3 { |
| // No rewrite expected as this is assigned to obj2::member which is annotated |
| // with RAW_PTR_EXCLUSION. |
| std::vector<S*> member; |
| }; |
| |
| namespace temporary { |
| std::vector<raw_ptr<S>> ge_t() { |
| return {}; |
| } |
| std::vector<raw_ptr<S>>* ge_t_ptr() { |
| return nullptr; |
| } |
| } // namespace temporary |
| |
| void fct() { |
| std::vector<raw_ptr<S>> temp; |
| std::vector<raw_ptr<S>> temp3; |
| std::vector<raw_ptr<S>> temp2{temp}; |
| obj o{temp3}; |
| std::vector<const char*> t; |
| A a(temp, t); |
| (void)a; |
| |
| { |
| std::vector<raw_ptr<S>> temp; |
| A a2(temp, t); |
| (void)a2; |
| } |
| |
| { |
| obj p{temporary::ge_t()}; |
| (void)p; |
| |
| obj q{*temporary::ge_t_ptr()}; |
| (void)q; |
| } |
| |
| { |
| std::vector<raw_ptr<S>> temp4; |
| std::vector<const char*> s; |
| std::make_unique<A>(temp4, s); |
| } |
| |
| { |
| std::vector<raw_ptr<S>> temp4; |
| std::vector<const char*> s; |
| A* a = new A(temp4, s); |
| (void)a; |
| } |
| |
| { |
| std::vector<S*> t; |
| // creates a link between obj2::member and obj3::member through t; |
| // this leads to obj3::member to not be rewritten as it becomes reachable |
| // from a RAW_PTR_EXCLUSION annotated field. |
| obj3 o3{t}; |
| obj2 o2{t}; |
| } |
| } |
| |
| class O { |
| public: |
| O() : member() {} |
| |
| std::vector<raw_ptr<S>> f() { |
| std::vector<raw_ptr<S>> temp; |
| temp = std::move(member); |
| return temp; |
| } |
| |
| std::vector<raw_ptr<S>> f2() { |
| std::vector<raw_ptr<S>> temp = std::move(member); |
| temp.push_back(nullptr); |
| |
| for (S* v : temp) { |
| (void)v; |
| } |
| |
| for (S* v : member) { |
| (void)v; |
| } |
| |
| for (const S* const v : member) { |
| (void)v; |
| } |
| |
| auto temp2 = temp; |
| for (S* v : temp2) { |
| (void)v; |
| } |
| |
| for (const S* v : temp2) { |
| (void)v; |
| } |
| |
| for (const S* const v : temp2) { |
| (void)v; |
| } |
| |
| auto* ptr1 = temp2[0].get(); |
| (void)ptr1; |
| |
| auto* ptr2 = temp2.front().get(); |
| (void)ptr2; |
| |
| auto* ptr3 = temp2.back().get(); |
| (void)ptr3; |
| |
| int index = 0; |
| auto* ptr4 = temp2.at(index).get(); |
| (void)ptr4; |
| |
| return temp2; |
| } |
| |
| std::vector<raw_ptr<S>> g() { return std::move(member); } |
| |
| std::vector<raw_ptr<S>> g2() { |
| std::vector<raw_ptr<S>> temp; |
| temp.push_back(nullptr); |
| |
| auto* var = temp.front().get(); |
| (void)var; |
| |
| auto* var2 = temp.back().get(); |
| (void)var2; |
| |
| int index = 0; |
| auto* var3 = temp[index].get(); |
| (void)var3; |
| return (temp.size() > member.size()) ? std::move(temp) : std::move(member); |
| } |
| |
| private: |
| std::vector<raw_ptr<S>> member; |
| }; |
| |
| class P { |
| public: |
| P(std::vector<raw_ptr<S>> arg) : member(std::move(arg)) {} |
| |
| P(std::vector<raw_ptr<S>>* arg) : member(*arg) {} |
| |
| private: |
| std::vector<raw_ptr<S>> member; |
| }; |
| |
| namespace { |
| std::vector<raw_ptr<S>>* get_ptr() { |
| return nullptr; |
| } |
| void p_fct() { |
| { |
| std::vector<raw_ptr<S>> temp; |
| P p(&temp); |
| (void)p; |
| } |
| |
| { |
| P p(*get_ptr()); |
| (void)p; |
| } |
| } |
| } // namespace |
| |
| class Parent { |
| public: |
| Parent() = default; |
| |
| virtual std::vector<raw_ptr<S>> get(); |
| |
| protected: |
| std::vector<raw_ptr<S>> member; |
| }; |
| |
| std::vector<raw_ptr<S>> Parent::get() { |
| return member; |
| } |
| |
| class Child : public Parent { |
| public: |
| Child() = default; |
| |
| std::vector<raw_ptr<S>> get() override; |
| }; |
| |
| std::vector<raw_ptr<S>> Child::get() { |
| return std::vector<raw_ptr<S>>{}; |
| } |
| |
| namespace n { |
| template <class T> |
| void do_something(std::vector<raw_ptr<T>>& v) { |
| v.push_back(nullptr); |
| } |
| |
| class BCD { |
| public: |
| BCD(const std::vector<raw_ptr<int>>& arg); |
| |
| void dod() { |
| do_something(member); |
| auto lambda = [this]() -> std::vector<raw_ptr<int>> { return member; }; |
| lambda(); |
| |
| functor f; |
| f(member); |
| |
| auto lambda2 = [](const std::vector<raw_ptr<int>>& v) { |
| for (int* i : v) { |
| (void)i; |
| } |
| }; |
| |
| lambda2(member); |
| } |
| |
| private: |
| struct functor { |
| void operator()(const std::vector<raw_ptr<int>>& v) { |
| for (int* i : v) { |
| (void)i; |
| } |
| } |
| }; |
| std::vector<raw_ptr<int>> member; |
| }; |
| |
| BCD::BCD(const std::vector<raw_ptr<int>>& arg) : member(arg) {} |
| } // namespace n |
| |
| // No change needed here |
| void any_function(std::vector<int*>& v) { |
| v.push_back(nullptr); |
| } |
| |
| // These should be rewritten but are not for now. |
| namespace templated_stuff { |
| template <class T> |
| void do_something(std::vector<T*>& t) { |
| t.push_back(nullptr); |
| } |
| |
| template <typename T> |
| class A { |
| public: |
| A(const std::vector<T*>& arg) : v(arg) {} |
| |
| virtual const std::vector<T*>& get() { |
| do_something(v); |
| return v; |
| } |
| |
| protected: |
| std::vector<T*> v; |
| }; |
| |
| void fctttttt() { |
| A<int> a({}); |
| std::vector<int*> temp = a.get(); |
| temp.push_back(nullptr); |
| } |
| |
| } // namespace templated_stuff |
| |
| namespace { |
| namespace A { |
| struct SA { |
| int count; |
| }; |
| } // namespace A |
| |
| namespace B { |
| struct S { |
| // Expected rewrite: std::vector<raw_ptr<const A::SA>> member; |
| std::vector<raw_ptr<const A::SA>> member; |
| |
| bool fct() { |
| // This tests whether we properly trim (anonymous namespace):: from the type |
| // while conserving constness. |
| // Expected rewrite: for(const A::SA* i : member) |
| for (const A::SA* i : member) { |
| (void)i; |
| } |
| |
| return std::any_of( |
| member.begin(), member.end(), |
| // Expected rewrite: [](const A::SA* item) { return item != nullptr; }); |
| [](const A::SA* item) { return item != nullptr; }); |
| } |
| |
| std::vector<raw_ptr<const A::SA>>::iterator fct2() { |
| return std::find_if( |
| member.begin(), member.end(), |
| // Expected rewrite: [](const A::SA* item) { return item == nullptr; }); |
| [](const A::SA* item) { return item == nullptr; }); |
| } |
| |
| bool fct3() { |
| return std::all_of( |
| member.begin(), member.end(), |
| // Expected rewrite: [](const A::SA* item) { return item != nullptr; }); |
| [](const A::SA* item) { return item != nullptr; }); |
| } |
| |
| int fct4() { |
| return std::accumulate(member.begin(), member.end(), 1, |
| // Expected rewrite: [](int num, const A::SA* item) { |
| [](int num, const A::SA* item) { |
| return (item != nullptr) ? 1 + num : 0; |
| }); |
| } |
| |
| int fct5() { |
| return std::count_if( |
| member.begin(), member.end(), |
| // Expected rewrite: [](const A::SA* item) { return item != nullptr; }); |
| [](const A::SA* item) { return item != nullptr; }); |
| } |
| |
| void fct6() { |
| std::vector<int> copy; |
| std::transform( |
| member.begin(), member.end(), std::back_inserter(copy), |
| // Expected rewrite: [](const A::SA* item) { return item->count; }); |
| [](const A::SA* item) { return item->count; }); |
| } |
| |
| std::vector<const A::SA*> fct7() { |
| std::vector<const A::SA*> copy; |
| std::copy_if( |
| member.begin(), member.end(), std::back_inserter(copy), |
| // Expected rewrite: [](const A::SA* item) { return item != nullptr; }); |
| [](const A::SA* item) { return item != nullptr; }); |
| return copy; |
| } |
| }; |
| } // namespace B |
| } // namespace |
| |
| namespace { |
| class AA { |
| public: |
| // No rewrite expected as this is not reachable from a fieldDecl. |
| using VECTOR = std::vector<S*>; |
| |
| // Expected rewrite: using VECTOR2 = std::vector<raw_ptr<S>>; |
| using VECTOR2 = std::vector<raw_ptr<S>>; |
| |
| // Expected rewrite: set(std::vector<raw_ptr<int>> arg) |
| virtual void set(std::vector<raw_ptr<int>> arg) = 0; |
| |
| // Expected rewrite: get(std::vector<raw_ptr<int>>& arg) |
| virtual void get(std::vector<raw_ptr<int>>& arg) const = 0; |
| |
| // Expected rewrite: get2(std::vector<raw_ptr<int>>* arg) |
| virtual void get2(std::vector<raw_ptr<int>>* arg) const = 0; |
| |
| virtual void get3(VECTOR& arg) const = 0; |
| |
| virtual void get4(VECTOR2& arg) const = 0; |
| |
| // No rewrite expected as the argument is not connected/reachable from a |
| // rewritten field. |
| virtual void GetNotifications(std::vector<const int*>* a) const = 0; |
| |
| // No rewrite expected as the argument is not connected/reachable from a |
| // rewritten field. |
| virtual void GetNotifications2(std::vector<const int*> a) const = 0; |
| |
| // No rewrite expected as the argument is not connected/reachable from a |
| // rewritten field. |
| virtual void GetNotifications3(std::vector<const int*>& a) const = 0; |
| }; |
| |
| class BB : public AA { |
| public: |
| // Expected rewrite: set(std::vector<raw_ptr<int>> arg) |
| void set(std::vector<raw_ptr<int>> arg) override { member = arg; } |
| |
| // Expected rewrite: get(std::vector<raw_ptr<int>>& arg) |
| void get(std::vector<raw_ptr<int>>& arg) const override { arg = member; } |
| |
| // Expected rewrite: get2(std::vector<raw_ptr<int>>* arg) |
| void get2(std::vector<raw_ptr<int>>* arg) const override { *arg = member; } |
| |
| void get3(VECTOR& arg) const override {} |
| |
| // Expected rewrite: get4(std::vector<raw_ptr<S>>& arg) |
| void get4(std::vector<raw_ptr<S>>& arg) const override { arg = member2; } |
| |
| // No rewrite expected as the argument is not connected/reachable from a |
| // rewritten field. |
| void GetNotifications(std::vector<const int*>*) const override {} |
| |
| // No rewrite expected as the argument is not connected/reachable from a |
| // rewritten field. |
| void GetNotifications2(std::vector<const int*> a) const override {} |
| |
| // No rewrite expected as the argument is not connected/reachable from a |
| // rewritten field. |
| void GetNotifications3(std::vector<const int*>& a) const override {} |
| |
| private: |
| // Expected rewrite: std::vector<raw_ptr<int>> member; |
| std::vector<raw_ptr<int>> member; |
| VECTOR2 member2; |
| }; |
| |
| class Mocked1 : public AA { |
| public: |
| // Expected rewrite: void, set, (std::vector<raw_ptr<int>>) |
| MOCK_METHOD(void, set, (std::vector<raw_ptr<int>>)); |
| |
| // Expected rewrite: get, void(std::vector<raw_ptr<int>>&) |
| MOCK_CONST_METHOD1(get, void(std::vector<raw_ptr<int>>&)); |
| |
| // Expected rewrite: get2, void(std::vector<raw_ptr<int>>*) |
| MOCK_CONST_METHOD1(get2, void(std::vector<raw_ptr<int>>*)); |
| |
| // No rewrite expected as the argument is not connected/reachable from a |
| // rewritten field. |
| MOCK_CONST_METHOD1(get3, void(std::vector<S*>&)); |
| |
| // Expected rewrite: get4, void(std::vector<raw_ptr<S>>&) |
| MOCK_CONST_METHOD1(get4, void(std::vector<raw_ptr<S>>&)); |
| |
| // No rewrite expected as the argument is not connected/reachable from a |
| // rewritten field. |
| MOCK_CONST_METHOD1(GetNotifications, void(std::vector<const int*>*)); |
| |
| // No rewrite expected as the argument is not connected/reachable from a |
| // rewritten field. |
| MOCK_CONST_METHOD1(GetNotifications2, void(std::vector<const int*>&)); |
| |
| // No rewrite expected as the argument is not connected/reachable from a |
| // rewritten field. |
| MOCK_CONST_METHOD1(GetNotifications3, void(std::vector<const int*>)); |
| }; |
| |
| class Mocked2 : public AA { |
| public: |
| // Expected rewrite: set, void(std::vector<raw_ptr<int>> arg) |
| MOCK_METHOD1(set, void(std::vector<raw_ptr<int>> args)); |
| |
| // Expected rewrite: get, void(std::vector<raw_ptr<int>>&) |
| MOCK_CONST_METHOD1(get, void(std::vector<raw_ptr<int>>&)); |
| |
| // Expected rewrite: get2, void(std::vector<raw_ptr<int>>*) |
| MOCK_CONST_METHOD1(get2, void(std::vector<raw_ptr<int>>*)); |
| |
| // No rewrite expected as the argument is not connected/reachable from a |
| // rewritten field. |
| MOCK_CONST_METHOD1(get3, void(VECTOR&)); |
| |
| // Expected rewrite: get4, void(std::vector<raw_ptr<S>>&) |
| MOCK_CONST_METHOD1(get4, void(std::vector<raw_ptr<S>>&)); |
| |
| // No rewrite expected as the argument is not connected/reachable from a |
| // rewritten field. |
| MOCK_CONST_METHOD1(GetNotifications, void(std::vector<const int*>*)); |
| |
| // No rewrite expected as the argument is not connected/reachable from a |
| // rewritten field. |
| MOCK_CONST_METHOD1(GetNotifications2, void(std::vector<const int*>&)); |
| |
| // No rewrite expected as the argument is not connected/reachable from a |
| // rewritten field. |
| MOCK_CONST_METHOD1(GetNotifications3, void(std::vector<const int*>)); |
| }; |
| |
| } // namespace |