// Copyright 2016 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. #include <type_traits> namespace not_blink { void function(int x) {} class Class { public: void method() {} virtual void virtualMethod() {} template <typename T> void methodTemplate(T) {} template <typename T> static void staticMethodTemplate(T) {} }; template <typename T> void functionTemplate(T x) {} template <typename T = Class> void functionTemplate2() { T::staticMethodTemplate(123); } template <typename T = Class> class TemplatedClass { public: void anotherMethod() { T::staticMethodTemplate(123); } }; } // not_blink namespace blink { bool FunctionNotMarkedConstexpr(int a) { return a == 4 || a == 10; } template <typename T> bool TemplatedFunctionNotMarkedConstexpr(T t) { return !!t; } int g_global_number; template <typename T, int number> void F() { // These are const but hacker_case so we leave them alone. const int maybe_a_const = sizeof(T); const int is_a_const = number; // These are const expressions so they get a k prefix. const int kMaybeAConstToo = sizeof(T); const int kIsAConstToo = number; // These are built from calls to functions which produces inconsistent // results so they should not be considered const to be safe. const bool from_a_method = FunctionNotMarkedConstexpr(number); const bool from_a_templated_method = TemplatedFunctionNotMarkedConstexpr(number); // A complex statement of const things is const. const bool kComplexConst = number || (number + 1); // A complex statement with a non-const thing is not const. const bool complex_not_const = number || (g_global_number + 1); // A const built from other consts is a const. const bool kConstFromAConst = kComplexConst || number; } template <int number, typename... T> void F() { // These are const but hacker_case so we leave them alone. const int maybe_a_const = sizeof...(T); const int is_a_const = number; // These are const expressions so they get a k prefix. const int kMaybeAConstToo = sizeof...(T); const int kIsAConstToo = number; } namespace test_member_in_template { template <typename T> class HasAMember { public: HasAMember() {} HasAMember(const T&) {} void UsesMember() { const int not_const = i_; } void AlsoUsesMember(); private: int i_; }; template <typename T> void HasAMember<T>::AlsoUsesMember() { const int not_const = i_; } template <typename T> static void BasedOnSubType(const HasAMember<T>& t) { const HasAMember<T> problematic_not_const(t); } void Run() { HasAMember<int>().UsesMember(); BasedOnSubType<int>(HasAMember<int>()); enum E { A }; BasedOnSubType<E>(HasAMember<E>()); } } namespace test_template_arg_is_function { void F(int x) {} template <typename T, void g(T)> void H(T x) { g(x); } void Test() { // f should be rewritten. H<int, F>(0); // Non-Blink should stay the same. H<int, not_blink::function>(1); // The int one makes the methods called from F() considered as constexpr, and // can be collapsed to not have template arguments before it reaches the AST. F<int, 10>(); // The enum one makes them not constexpr, as it doesn't collapse away the // template stuff as much. This can lead to conflicting decisions about // the names inside F() vs the above instantiation. enum E { A }; F<E, 11>(); } } // namespace test_template_arg_is_function namespace test_template_arg_is_method { class Class { public: void Method() {} }; template <typename T, void (T::*g)()> void H(T&& x) { (x.*g)(); } void Test() { // method should be rewritten. H<Class, &Class::Method>(Class()); // Non-Blink should stay the same. H<not_blink::Class, ¬_blink::Class::method>(not_blink::Class()); } } // namespace test_template_arg_is_method namespace test_template_arg_is_function_template { namespace nested { template <typename T> void F(T) {} } template <typename T, void g(T)> void H(T x) { g(x); } void Test() { // f should be rewritten. H<int, nested::F>(0); // Non-Blink should stay the same. H<int, not_blink::functionTemplate>(1); } } // namespace test_template_arg_is_function_template namespace test_template_arg_is_method_template_in_non_member_context { struct Class { template <typename T> static void F(T) {} }; template <typename T, void g(T)> void H(T x) { g(x); } void Test() { // f should be rewritten. H<int, Class::F>(0); // Non-Blink should stay the same. H<int, not_blink::Class::staticMethodTemplate>(1); } } // test_template_arg_is_method_template_in_non_member_context namespace test_inherited_field { template <typename T> class BaseClass { public: unsigned long size_; }; template <typename T> class DerivedClass : protected BaseClass<T> { private: using Base = BaseClass<T>; // https://crbug.com/640016: Need to rewrite |m_size| into |size_|. using Base::size_; void Method() { size_ = 123; } }; } // namespace test_inherited_field namespace test_template_arg_is_method_template_in_member_context { struct Class { template <typename T> static void F(T) {} }; struct Class2 { template <typename T> void F(T x) { // f should be rewritten. Class c; c.F(x); // Non-Blink should stay the same. not_blink::Class c2; c2.method(x); } }; } // namespace test_template_arg_is_method_template_in_member_context namespace test_unnamed_arg { template <typename T> class Class { public: // Test for https://crbug.com/598141 - shouldn't rewrite // ...int); // into // ...intdata_size; void F(int); }; template <typename T> void Class<T>::F(int data_size){}; void Foo() { Class<char>().F(123); }; } // namespace test_unnamed_arg namespace cxx_dependent_scope_member_expr_testing { class PartitionAllocator { public: static void Method() {} }; template <typename Allocator = PartitionAllocator> class Vector { public: // https://crbug.com/582315: |Allocator::method| is a // CXXDependentScopeMemberExpr. void AnotherMethod() { if (std::is_class<Allocator>::value) // Shouldn't rename |value| Allocator::Method(); // Should rename |method| -> |Method|. } }; template <typename Allocator = PartitionAllocator> void Test() { // https://crbug.com/582315: |Allocator::method| is a // DependentScopeDeclRefExpr. if (std::is_class<Allocator>::value) // Shouldn't rename |value|. Allocator::Method(); // Should rename |method|. } class InterceptingCanvasBase : public ::not_blink::Class { public: virtual void VirtualMethodInBlink(){}; }; template <typename DerivedCanvas> class InterceptingCanvas : public InterceptingCanvasBase { public: void virtualMethod() override { this->Class::virtualMethod(); // https://crbug.com/582315#c19 this->InterceptingCanvasBase::VirtualMethodInBlink(); } }; template <typename T> class ThreadSpecific { public: T* operator->(); operator T*(); }; template <typename T> inline ThreadSpecific<T>::operator T*() { return nullptr; } template <typename T> inline T* ThreadSpecific<T>::operator->() { return operator T*(); } class Class { public: virtual void VirtualMethodInBlink() {} }; } // namespace cxx_dependent_scope_member_expr_testing namespace blacklisting_of_renaming_of_begin_method { template <typename T> class IntrusiveHeap { public: // https://crbug.com/672353: |begin| shouldn't be rewritten to |Begin|. const T* begin() const { return nullptr; } }; } // namespace blacklisting_of_renaming_of_begin_method namespace specializations { template <unsigned long sizeOfValue> int ToV8SignedIntegerInternal(long value); template <> int ToV8SignedIntegerInternal<4>(long value) { return 123 + value; } template <> int ToV8SignedIntegerInternal<8>(long value) { return 456 + value; } int ToV8(int value) { return ToV8SignedIntegerInternal<sizeof value>(value); } int ToV8(long value) { return ToV8SignedIntegerInternal<sizeof value>(value); } } // namespace specializations } // namespace blink namespace not_blink { namespace cxx_dependent_scope_member_expr_testing { class Base : public ::blink::cxx_dependent_scope_member_expr_testing::Class { public: virtual void virtualMethod() {} }; template <typename T> class Derived : public Base { public: void virtualMethod() override { this->Class::VirtualMethodInBlink(); this->Base::virtualMethod(); } }; } // namespace cxx_dependent_scope_member_expr_testing namespace blink_methods_called_from_mojo_traits_are_not_rewritten { template <typename V> struct MapTraits; template <typename V> struct MapTraits<blink::test_unnamed_arg::Class<V>> { static void SetToEmpty(blink::test_unnamed_arg::Class<V>* output) { // Need to rewrite |f| to |F| below (because this method name // does get rewritten when processing blink::test_unnamed_arg::Class). // See also https://crbug.com/670434. output->F(123); } }; } // namespace blink_methods_called_from_mojo_traits_are_not_rewritten } // namespace not_blink