| // Copyright 2020 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| // Test for template specializations. |
| // |
| // In template specializations template parameters (e.g. |T| or |T2| in |
| // MyTemplate below) get substituted with an actual class (e.g. |SomeClass| or |
| // |int|). In an *implicit* specialization, these substitutions are "overlaid" |
| // / "overimposed" on top of the template definition and this can lead to |
| // generating conflicting replacements - for example the same |t_ptr_field| |
| // definition can get replaced with: |
| // 1. T* t_ptr_field -> raw_ptr<T> t_ptr_field // expected |
| // 2. T* t_ptr_field -> raw_ptr<SomeClass> t_ptr_field // undesired |
| // |
| // To avoid generating conflicting replacements, the rewriter excludes implicit |
| // template specializations via |implicit_field_decl_matcher|. |
| // |
| // Note that rewrites in *explicit* template specializations are still |
| // desirable. For example, see the |T2* t2_ptr_field| in |MyTemplate<int, T2>| |
| // partial template specialization. |
| |
| #include "base/memory/raw_ptr.h" |
| |
| class SomeClass; |
| class SomeClass2; |
| |
| template <typename T, typename T2> |
| class MyTemplate { |
| // Expected rewrite: raw_ptr<T> t_ptr_field; |
| raw_ptr<T> t_ptr_field; |
| |
| // Expected rewrite: raw_ptr<SomeClass> some_class_ptr_field; |
| raw_ptr<SomeClass> some_class_ptr_field; |
| |
| // No rewrite expected. |
| int int_field; |
| }; |
| |
| // Partial *explicit* specialization. |
| template <typename T2> |
| class MyTemplate<int, T2> { |
| // Expected rewrite: raw_ptr<T2> t2_ptr_field; |
| raw_ptr<T2> t2_ptr_field; |
| |
| // Expected rewrite: raw_ptr<SomeClass> some_class_ptr_field; |
| raw_ptr<SomeClass> some_class_ptr_field; |
| |
| // Expected rewrite: raw_ptr<int> int_ptr_field; |
| raw_ptr<int> int_ptr_field; |
| |
| // No rewrite expected. |
| int int_field; |
| }; |
| |
| // Full *explicit* specialization. |
| template <> |
| class MyTemplate<int, SomeClass2> { |
| // Expected rewrite: raw_ptr<int> int_ptr_field; |
| raw_ptr<int> int_ptr_field; |
| |
| // Expected rewrite: raw_ptr<SomeClass2> some_class2_ptr_field; |
| raw_ptr<SomeClass2> some_class2_ptr_field; |
| |
| // No rewrite expected. |
| int int_field; |
| }; |
| |
| // The class definitions below trigger an implicit template specialization of |
| // MyTemplate. |
| class TemplateDerived : public MyTemplate<SomeClass, int> {}; |
| class TemplateDerived2 : public MyTemplate<SomeClass2, int> {}; |
| |
| // Test where excluding SubstTemplateTypeParmType pointees is not sufficient, |
| // because the pointee is not |T|, but |TemplateSelfPointerTest<T>| like in |
| // the fields below. |
| // |
| // This test forces using |
| // classTemplateSpecializationDecl(isImplicitSpecialization()) |
| // in the definition of |implicit_field_decl_matcher|. |
| // Note that no |hasAncestor| matcher is necessary - compare with |
| // nested_iterator_test below. |
| namespace self_pointer_test { |
| |
| template <typename T> |
| class TemplateSelfPointerTest { |
| // Early versions of the rewriter used to rewrite the type below to three |
| // conflicting replacements: |
| // 1. raw_ptr<TemplateSelfPointerTest<bool>> |
| // 2. raw_ptr<TemplateSelfPointerTest<SomeClass2>> |
| // 3. raw_ptr<TemplateSelfPointerTest<T>> |
| // |
| // Something similar would have happened in //base/scoped_generic.h (in the |
| // nested Receiver class): |
| // ScopedGeneric* scoped_generic_; |
| // |
| // Expected rewrite: raw_ptr<TemplateSelfPointerTest<T>> |
| raw_ptr<TemplateSelfPointerTest<T>> ptr_field_; |
| |
| // Similar test to the above. Something similar would have happened in |
| // //base/id_map.h (in the nested Iterator class): |
| // IDMap<V, K>* map_; |
| // |
| // Expected rewrite: raw_ptr<TemplateSelfPointerTest<T>> |
| raw_ptr<TemplateSelfPointerTest<T>> ptr_field2_; |
| }; |
| |
| void foo() { |
| // Variable declarations below trigger an implicit template specialization of |
| // TemplateSelfPointerTest. |
| TemplateSelfPointerTest<bool> foo; |
| TemplateSelfPointerTest<SomeClass2> bar; |
| } |
| |
| } // namespace self_pointer_test |
| |
| // Test against overlapping replacement that occurred in Chromium in places |
| // like: |
| // - //components/url_pattern_index/string_splitter.h |
| // |const StringSplitter* splitter_| in nested Iterator class |
| // - //base/callback_list.h |
| // |CallbackListBase<CallbackType>* list_| in nested Iterator class |
| // - //mojo/public/cpp/bindings/receiver_set.h |
| // |ReceiverSetBase* const receiver_set_| in nested Entry class |
| // |
| // This test forces using |
| // hasAncestor(classTemplateSpecializationDecl(isImplicitSpecialization())) |
| // in the definition of |implicit_field_decl_matcher|. |
| namespace nested_iterator_test { |
| |
| template <typename T> |
| class StringSplitter { |
| public: |
| class Iterator { |
| public: |
| Iterator(const StringSplitter& splitter) : splitter_(&splitter) {} |
| |
| private: |
| // Danger of an overlapping replacement (when substituting |
| // |StringSplitter<T>| for |StringSplitter<int>| in an implicit template |
| // specialization triggered by the |foo2| function below. |
| // |
| // Expected rewrite: raw_ptr<const StringSplitter<T>> splitter_ |
| raw_ptr<const StringSplitter<T>> splitter_; |
| }; |
| |
| Iterator begin() const { return Iterator(*this); } |
| }; |
| |
| void foo2() { |
| StringSplitter<int> splitter; |
| auto iterator = splitter.begin(); |
| } |
| |
| } // namespace nested_iterator_test |
| |
| // Example based on base/trace_event/memory_usage_estimator.h where a function |
| // template |EstimateMemoryUsage| had a nested struct |SharedPointer| definition |
| // with a pointer field |value| that was leading to conflicting replacements. |
| namespace template_function { |
| |
| template <typename T> |
| void foo(T* arg) { |
| struct NestedStruct { |
| // Expected rewrite: raw_ptr<T> ptr_field; |
| raw_ptr<T> ptr_field; |
| |
| // Expected rewrite: raw_ptr<MyTemplate<T, T>> ptr_field2; |
| raw_ptr<MyTemplate<T, T>> ptr_field2; |
| } var; |
| |
| var.ptr_field = nullptr; |
| } |
| |
| void bar() { |
| // Triggering implicit specializations of foo that in the past led the |
| // rewriter to generate conflicting replacements. |
| int i = 123; |
| SomeClass* p = nullptr; |
| foo(p); |
| foo(&i); |
| } |
| |
| } // namespace template_function |