1// Copyright 2016 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <type_traits>
6
7namespace not_blink {
8
9void function(int x) {}
10
11class Class {
12 public:
13  void method() {}
14  virtual void virtualMethod() {}
15  template <typename T>
16  void methodTemplate(T) {}
17  template <typename T>
18  static void staticMethodTemplate(T) {}
19};
20
21template <typename T>
22void functionTemplate(T x) {}
23
24template <typename T = Class>
25void functionTemplate2() {
26  T::staticMethodTemplate(123);
27}
28
29template <typename T = Class>
30class TemplatedClass {
31 public:
32  void anotherMethod() { T::staticMethodTemplate(123); }
33};
34
35}  // not_blink
36
37namespace blink {
38
39bool functionNotMarkedConstexpr(int a) {
40  return a == 4 || a == 10;
41}
42
43template <typename T>
44bool templatedFunctionNotMarkedConstexpr(T t) {
45  return !!t;
46}
47
48int g_globalNumber;
49
50template <typename T, int number>
51void F() {
52  // These are const but hacker_case so we leave them alone.
53  const int maybe_a_const = sizeof(T);
54  const int is_a_const = number;
55  // These are const expressions so they get a k prefix.
56  const int maybeAConstToo = sizeof(T);
57  const int isAConstToo = number;
58  // These are built from calls to functions which produces inconsistent
59  // results so they should not be considered const to be safe.
60  const bool fromAMethod = functionNotMarkedConstexpr(number);
61  const bool fromATemplatedMethod = templatedFunctionNotMarkedConstexpr(number);
62  // A complex statement of const things is const.
63  const bool complexConst = number || (number + 1);
64  // A complex statement with a non-const thing is not const.
65  const bool complexNotConst = number || (g_globalNumber + 1);
66  // A const built from other consts is a const.
67  const bool constFromAConst = complexConst || number;
68}
69
70template <int number, typename... T>
71void F() {
72  // These are const but hacker_case so we leave them alone.
73  const int maybe_a_const = sizeof...(T);
74  const int is_a_const = number;
75  // These are const expressions so they get a k prefix.
76  const int maybeAConstToo = sizeof...(T);
77  const int isAConstToo = number;
78}
79
80namespace test_member_in_template {
81
82template <typename T>
83class HasAMember {
84 public:
85  HasAMember() {}
86  HasAMember(const T&) {}
87
88  void usesMember() { const int notConst = m_i; }
89  void alsoUsesMember();
90
91 private:
92  int m_i;
93};
94
95template <typename T>
96void HasAMember<T>::alsoUsesMember() {
97  const int notConst = m_i;
98}
99
100template <typename T>
101static void basedOnSubType(const HasAMember<T>& t) {
102  const HasAMember<T> problematicNotConst(t);
103}
104
105void Run() {
106  HasAMember<int>().usesMember();
107
108  basedOnSubType<int>(HasAMember<int>());
109  enum E { A };
110  basedOnSubType<E>(HasAMember<E>());
111}
112}
113
114namespace test_template_arg_is_function {
115
116void f(int x) {}
117
118template <typename T, void g(T)>
119void h(T x) {
120  g(x);
121}
122
123void test() {
124  // f should be rewritten.
125  h<int, f>(0);
126  // Non-Blink should stay the same.
127  h<int, not_blink::function>(1);
128
129  // The int one makes the methods called from F() considered as constexpr, and
130  // can be collapsed to not have template arguments before it reaches the AST.
131  F<int, 10>();
132  // The enum one makes them not constexpr, as it doesn't collapse away the
133  // template stuff as much. This can lead to conflicting decisions about
134  // the names inside F() vs the above instantiation.
135  enum E { A };
136  F<E, 11>();
137}
138
139}  // namespace test_template_arg_is_function
140
141namespace test_template_arg_is_method {
142
143class Class {
144 public:
145  void method() {}
146};
147
148template <typename T, void (T::*g)()>
149void h(T&& x) {
150  (x.*g)();
151}
152
153void test() {
154  // method should be rewritten.
155  h<Class, &Class::method>(Class());
156  // Non-Blink should stay the same.
157  h<not_blink::Class, &not_blink::Class::method>(not_blink::Class());
158}
159
160}  // namespace test_template_arg_is_method
161
162namespace test_template_arg_is_function_template {
163
164namespace nested {
165template <typename T>
166void f(T) {}
167}
168
169template <typename T, void g(T)>
170void h(T x) {
171  g(x);
172}
173
174void test() {
175  // f should be rewritten.
176  h<int, nested::f>(0);
177  // Non-Blink should stay the same.
178  h<int, not_blink::functionTemplate>(1);
179}
180
181}  // namespace test_template_arg_is_function_template
182
183namespace test_template_arg_is_method_template_in_non_member_context {
184
185struct Class {
186  template <typename T>
187  static void f(T) {}
188};
189
190template <typename T, void g(T)>
191void h(T x) {
192  g(x);
193}
194
195void test() {
196  // f should be rewritten.
197  h<int, Class::f>(0);
198  // Non-Blink should stay the same.
199  h<int, not_blink::Class::staticMethodTemplate>(1);
200}
201
202}  // test_template_arg_is_method_template_in_non_member_context
203
204namespace test_inherited_field {
205
206template <typename T>
207class BaseClass {
208 public:
209  unsigned long m_size;
210};
211
212template <typename T>
213class DerivedClass : protected BaseClass<T> {
214 private:
215  using Base = BaseClass<T>;
216  // https://crbug.com/640016: Need to rewrite |m_size| into |size_|.
217  using Base::m_size;
218  void method() { m_size = 123; }
219};
220
221}  // namespace test_inherited_field
222
223namespace test_template_arg_is_method_template_in_member_context {
224
225struct Class {
226  template <typename T>
227  static void f(T) {}
228};
229
230struct Class2 {
231  template <typename T>
232  void f(T x) {
233    // f should be rewritten.
234    Class c;
235    c.f(x);
236    // Non-Blink should stay the same.
237    not_blink::Class c2;
238    c2.method(x);
239  }
240};
241
242}  // namespace test_template_arg_is_method_template_in_member_context
243
244namespace test_unnamed_arg {
245
246template <typename T>
247class Class {
248 public:
249  // Test for https://crbug.com/598141 - shouldn't rewrite
250  //    ...int);
251  // into
252  //    ...intdata_size;
253  void f(int);
254};
255
256template <typename T>
257void Class<T>::f(int dataSize){};
258
259void foo() {
260  Class<char>().f(123);
261};
262
263}  // namespace test_unnamed_arg
264
265namespace cxx_dependent_scope_member_expr_testing {
266
267class PartitionAllocator {
268 public:
269  static void method() {}
270};
271
272template <typename Allocator = PartitionAllocator>
273class Vector {
274 public:
275  // https://crbug.com/582315: |Allocator::method| is a
276  // CXXDependentScopeMemberExpr.
277  void anotherMethod() {
278    if (std::is_class<Allocator>::value)  // Shouldn't rename |value|
279      Allocator::method();                // Should rename |method| -> |Method|.
280  }
281};
282
283template <typename Allocator = PartitionAllocator>
284void test() {
285  // https://crbug.com/582315: |Allocator::method| is a
286  // DependentScopeDeclRefExpr.
287  if (std::is_class<Allocator>::value)  // Shouldn't rename |value|.
288    Allocator::method();                // Should rename |method|.
289}
290
291class InterceptingCanvasBase : public ::not_blink::Class {
292 public:
293  virtual void virtualMethodInBlink(){};
294};
295
296template <typename DerivedCanvas>
297class InterceptingCanvas : public InterceptingCanvasBase {
298 public:
299  void virtualMethod() override {
300    this->Class::virtualMethod();  // https://crbug.com/582315#c19
301    this->InterceptingCanvasBase::virtualMethodInBlink();
302  }
303};
304
305template <typename T>
306class ThreadSpecific {
307 public:
308  T* operator->();
309  operator T*();
310};
311
312template <typename T>
313inline ThreadSpecific<T>::operator T*() {
314  return nullptr;
315}
316
317template <typename T>
318inline T* ThreadSpecific<T>::operator->() {
319  return operator T*();
320}
321
322class Class {
323 public:
324  virtual void virtualMethodInBlink() {}
325};
326
327}  // namespace cxx_dependent_scope_member_expr_testing
328
329namespace blacklisting_of_renaming_of_begin_method {
330
331template <typename T>
332class IntrusiveHeap {
333 public:
334  // https://crbug.com/672353: |begin| shouldn't be rewritten to |Begin|.
335  const T* begin() const { return nullptr; }
336};
337
338}  // namespace blacklisting_of_renaming_of_begin_method
339
340}  // namespace blink
341
342namespace not_blink {
343
344namespace cxx_dependent_scope_member_expr_testing {
345
346class Base : public ::blink::cxx_dependent_scope_member_expr_testing::Class {
347 public:
348  virtual void virtualMethod() {}
349};
350
351template <typename T>
352class Derived : public Base {
353 public:
354  void virtualMethod() override {
355    this->Class::virtualMethodInBlink();
356    this->Base::virtualMethod();
357  }
358};
359
360}  // namespace cxx_dependent_scope_member_expr_testing
361
362namespace blink_methods_called_from_mojo_traits_are_not_rewritten {
363
364template <typename V>
365struct MapTraits;
366
367template <typename V>
368struct MapTraits<blink::test_unnamed_arg::Class<V>> {
369  static void SetToEmpty(blink::test_unnamed_arg::Class<V>* output) {
370    // Need to rewrite |f| to |F| below (because this method name
371    // does get rewritten when processing blink::test_unnamed_arg::Class).
372    // See also https://crbug.com/670434.
373    output->f(123);
374  }
375};
376
377}  // namespace blink_methods_called_from_mojo_traits_are_not_rewritten
378
379}  // namespace not_blink
380