// 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 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