| // Copyright 2022 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <iostream> |
| #include <sstream> |
| #include <string> |
| #include <vector> |
| |
| #include "base/memory/raw_ref.h" |
| |
| struct MySubStruct { |
| MySubStruct(const int& num); |
| int member; |
| virtual int get_member() const { return member; } |
| virtual ~MySubStruct() = default; |
| |
| struct inner_s { |
| inner_s(const inner_s&); |
| // Expected rewrite: const raw_ref<int> inner_int; |
| const raw_ref<int> inner_int; |
| }; |
| }; |
| |
| // This was added due to a bug in the matcher that was doing erroneous rewrites |
| // here. No rewrite expected. |
| MySubStruct::inner_s::inner_s(const inner_s&) = default; |
| |
| struct MyStruct { |
| MyStruct(MySubStruct& s) : ref(s) {} |
| |
| // No rewrite expected for `other.ref` since `ref` itself with become a |
| // raw_ref. |
| MyStruct(const MyStruct& other) : ref(other.ref) {} |
| |
| const MySubStruct& get() const; |
| // Expected rewrite: const raw_ref<MySubStruct> ref; |
| const raw_ref<MySubStruct> ref; |
| }; |
| |
| template <class T> |
| struct MyTemplatedStruct { |
| MyTemplatedStruct(T& t) : ref(t) {} |
| |
| // No rewrite expected for `other.ref` since `ref` itself with become a |
| // raw_ref. |
| MyTemplatedStruct(const MyTemplatedStruct& other) : ref(other.ref) {} |
| |
| // Expected rewrite: ref->member |
| void setSubmember(int n) { ref->member = n; } |
| |
| // Expected rewrite: return *ref; |
| T& get() { return *ref; } |
| |
| const T& get() const; |
| // Expected rewrite: return *ref; |
| T get_by_value() const { return *ref; } |
| |
| // Expected rewrite: ref->get_member(); |
| int getInt() { return ref->get_member(); } |
| |
| // Expected rewrite: const raw_ref<T> ref; |
| const raw_ref<T> ref; |
| }; |
| |
| template <class T> |
| void func(T& ref, const T& ref2) {} |
| |
| int main() { |
| MySubStruct sub{1}; |
| MyStruct s(sub); |
| // Expected rewrite: s.ref->member; |
| s.ref->member = 11; |
| // Expected rewrite: s.ref->get_member(); |
| s.ref->get_member(); |
| |
| // Expected rewrite: MyStruct* s2 = new MyStruct(*s.ref); |
| MyStruct* s2 = new MyStruct(*s.ref); |
| |
| MyTemplatedStruct<MySubStruct> my_template_inst(sub); |
| my_template_inst.setSubmember(1234); |
| |
| // Expected rewrites: |
| // func(*my_template_inst.ref, my_template_inst.get()); |
| func(*my_template_inst.ref, my_template_inst.get()); |
| // func(my_template_inst.get(), *my_template_inst.ref); |
| func(my_template_inst.get(), *my_template_inst.ref); |
| // func(*my_template_inst.ref, *my_template_inst.ref); |
| func(*my_template_inst.ref, *my_template_inst.ref); |
| |
| // Expected rewrite: MySubStruct* ptr = &*s.ref; |
| MySubStruct* ptr = &*s.ref; |
| |
| // Expected rewrite: |
| // auto &ref = *s.ref, &ref2 = *s.ref; |
| auto &ref = *s.ref, &ref2 = *s.ref; |
| |
| int a = 0; |
| int b = 0; |
| |
| struct { |
| // Expected rewrite: const raw_ref<int> in; |
| const raw_ref<int> in; |
| // Expected rewrite: const raw_ref<int> out; |
| const raw_ref<int> out; |
| // Expected rewrite: |
| // report_lists[]{{raw_ref(a), raw_ref(b)}, {raw_ref(a), raw_ref(b)}}; |
| } report_lists[]{{raw_ref(a), raw_ref(b)}, {raw_ref(a), raw_ref(b)}}; |
| |
| // Reference members of nested anonymous structs declared in a |
| // function body are rewritten because they can end up on the heap. |
| struct A { |
| struct { |
| const raw_ref<int> i; |
| } member; |
| }; |
| |
| // Expected rewrite: A obj{raw_ref(a)}; |
| A obj{raw_ref(a)}; |
| (*obj.member.i)++; |
| |
| // Expected rewrite: A obj{.member = {raw_ref(a)}}; |
| A obj2{.member = {raw_ref(a)}}; |
| (*obj2.member.i)++; |
| ++(*obj2.member.i); |
| (*obj2.member.i)--; |
| --(*obj2.member.i); |
| |
| // No rewrite expected here for obj2.member.i since A::member::i itself will |
| // be rewritten into raw_ref. |
| A obj3{obj2.member.i}; |
| (*obj3.member.i)++; |
| |
| static struct { |
| // Expected rewrite: const raw_ref<int> member; |
| const raw_ref<int> member; |
| // Expected rewrite: st{raw_ref(a)}; |
| } st{raw_ref(a)}; |
| |
| struct Temp { |
| Temp(int& ref) : member(ref) {} |
| // Expected rewrite: const raw_ref<int> member; |
| const raw_ref<int> member; |
| }; |
| // No need to add raw_ref() around `a` here because the constructor will be |
| // called. |
| Temp tmp{a}; |
| (*tmp.member)++; |
| |
| struct StringRefObj { |
| const raw_ref<const std::string> member; |
| }; |
| |
| // No need to add raw_ref() around "abcde" here because it results in a |
| // temporary string object. A manual fix need to be applied. |
| StringRefObj r{"abcde"}; |
| (void)r; |
| } |
| |
| struct B { |
| struct { |
| // Expected rewrite: const raw_ref<int> i; |
| const raw_ref<int> i; |
| } member; |
| }; |
| |
| template <typename T> |
| const T& MyTemplatedStruct<T>::get() const { |
| // Expected rewrite: return *ref; |
| return *ref; |
| } |
| |
| const MySubStruct& MyStruct::get() const { |
| // Expected rewrite: return *ref; |
| return *ref; |
| } |
| |
| struct key_compare { |
| bool operator()(const int& a, const int& b) const { return a < b; } |
| }; |
| |
| struct KeyValueCompare { |
| // The key comparison object must outlive this class. |
| explicit KeyValueCompare(const key_compare& comp) : comp_(comp) {} |
| |
| bool operator()(const int& lhs, const int& rhs) const { |
| // Expected rewrite: return (*comp_)(lhs, rhs); |
| return (*comp_)(lhs, rhs); |
| } |
| |
| template <typename T, typename U> |
| bool operator()(const T& lhs, const U& rhs) const { |
| // Expected rewrite: return (*comp_)(lhs, rhs); |
| return (*comp_)(lhs, rhs); |
| } |
| |
| private: |
| const raw_ref<const key_compare> comp_; |
| }; |
| |
| struct KeyValueCompare2 { |
| // The key comparison object must outlive this class. |
| explicit KeyValueCompare2(const key_compare& comp) : comp_(comp) {} |
| |
| template <typename T, typename U> |
| bool operator()(const T& lhs, const U& rhs) const { |
| // Expected rewrite: return (*comp_)(lhs, rhs); |
| return (*comp_)(lhs, rhs); |
| } |
| |
| private: |
| const raw_ref<const key_compare> comp_; |
| }; |
| |
| template <typename T> |
| void doSomething(T& t) { |
| (void)t; |
| } |
| |
| template <typename T> |
| struct VectorMemberRef { |
| void iterate() { |
| for (T& t : *v) { |
| doSomething(t); |
| } |
| } |
| |
| T get_first() { return (*v)[0]; } |
| |
| const raw_ref<std::vector<T>> v; |
| }; |
| |
| struct MyStruct2 { |
| MyStruct2(const MyStruct2& other) |
| : // No rewrite expected for `other.int_ref` since `int_ref` itself with |
| // become a raw_ref. |
| int_ref(other.int_ref), |
| // Expected rewrite: i(*other.int_ref) |
| i(*other.int_ref), |
| func_ref(other.func_ref), |
| ref_to_array_of_ints(other.ref_to_array_of_ints) {} |
| |
| // Expected rewrite: const raw_ref<int> int_ref; |
| const raw_ref<int> int_ref; |
| int i; |
| // Function references are not rewritten. |
| int (&func_ref)(); |
| // References to arrays are not rewritten. |
| int (&ref_to_array_of_ints)[123]; |
| }; |