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_global_number;
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 kMaybeAConstToo = sizeof(T);
57  const int kIsAConstToo = 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 from_a_method = FunctionNotMarkedConstexpr(number);
61  const bool from_a_templated_method =
62      TemplatedFunctionNotMarkedConstexpr(number);
63  // A complex statement of const things is const.
64  const bool kComplexConst = number || (number + 1);
65  // A complex statement with a non-const thing is not const.
66  const bool complex_not_const = number || (g_global_number + 1);
67  // A const built from other consts is a const.
68  const bool kConstFromAConst = kComplexConst || number;
69}
70
71template <int number, typename... T>
72void F() {
73  // These are const but hacker_case so we leave them alone.
74  const int maybe_a_const = sizeof...(T);
75  const int is_a_const = number;
76  // These are const expressions so they get a k prefix.
77  const int kMaybeAConstToo = sizeof...(T);
78  const int kIsAConstToo = number;
79}
80
81namespace test_member_in_template {
82
83template <typename T>
84class HasAMember {
85 public:
86  HasAMember() {}
87  HasAMember(const T&) {}
88
89  void UsesMember() { const int not_const = i_; }
90  void AlsoUsesMember();
91
92 private:
93  int i_;
94};
95
96template <typename T>
97void HasAMember<T>::AlsoUsesMember() {
98  const int not_const = i_;
99}
100
101template <typename T>
102static void BasedOnSubType(const HasAMember<T>& t) {
103  const HasAMember<T> problematic_not_const(t);
104}
105
106void Run() {
107  HasAMember<int>().UsesMember();
108
109  BasedOnSubType<int>(HasAMember<int>());
110  enum E { A };
111  BasedOnSubType<E>(HasAMember<E>());
112}
113}
114
115namespace test_template_arg_is_function {
116
117void F(int x) {}
118
119template <typename T, void g(T)>
120void H(T x) {
121  g(x);
122}
123
124void Test() {
125  // f should be rewritten.
126  H<int, F>(0);
127  // Non-Blink should stay the same.
128  H<int, not_blink::function>(1);
129
130  // The int one makes the methods called from F() considered as constexpr, and
131  // can be collapsed to not have template arguments before it reaches the AST.
132  F<int, 10>();
133  // The enum one makes them not constexpr, as it doesn't collapse away the
134  // template stuff as much. This can lead to conflicting decisions about
135  // the names inside F() vs the above instantiation.
136  enum E { A };
137  F<E, 11>();
138}
139
140}  // namespace test_template_arg_is_function
141
142namespace test_template_arg_is_method {
143
144class Class {
145 public:
146  void Method() {}
147};
148
149template <typename T, void (T::*g)()>
150void H(T&& x) {
151  (x.*g)();
152}
153
154void Test() {
155  // method should be rewritten.
156  H<Class, &Class::Method>(Class());
157  // Non-Blink should stay the same.
158  H<not_blink::Class, &not_blink::Class::method>(not_blink::Class());
159}
160
161}  // namespace test_template_arg_is_method
162
163namespace test_template_arg_is_function_template {
164
165namespace nested {
166template <typename T>
167void F(T) {}
168}
169
170template <typename T, void g(T)>
171void H(T x) {
172  g(x);
173}
174
175void Test() {
176  // f should be rewritten.
177  H<int, nested::F>(0);
178  // Non-Blink should stay the same.
179  H<int, not_blink::functionTemplate>(1);
180}
181
182}  // namespace test_template_arg_is_function_template
183
184namespace test_template_arg_is_method_template_in_non_member_context {
185
186struct Class {
187  template <typename T>
188  static void F(T) {}
189};
190
191template <typename T, void g(T)>
192void H(T x) {
193  g(x);
194}
195
196void Test() {
197  // f should be rewritten.
198  H<int, Class::F>(0);
199  // Non-Blink should stay the same.
200  H<int, not_blink::Class::staticMethodTemplate>(1);
201}
202
203}  // test_template_arg_is_method_template_in_non_member_context
204
205namespace test_inherited_field {
206
207template <typename T>
208class BaseClass {
209 public:
210  unsigned long size_;
211};
212
213template <typename T>
214class DerivedClass : protected BaseClass<T> {
215 private:
216  using Base = BaseClass<T>;
217  // https://crbug.com/640016: Need to rewrite |m_size| into |size_|.
218  using Base::size_;
219  void Method() { size_ = 123; }
220};
221
222}  // namespace test_inherited_field
223
224namespace test_template_arg_is_method_template_in_member_context {
225
226struct Class {
227  template <typename T>
228  static void F(T) {}
229};
230
231struct Class2 {
232  template <typename T>
233  void F(T x) {
234    // f should be rewritten.
235    Class c;
236    c.F(x);
237    // Non-Blink should stay the same.
238    not_blink::Class c2;
239    c2.method(x);
240  }
241};
242
243}  // namespace test_template_arg_is_method_template_in_member_context
244
245namespace test_unnamed_arg {
246
247template <typename T>
248class Class {
249 public:
250  // Test for https://crbug.com/598141 - shouldn't rewrite
251  //    ...int);
252  // into
253  //    ...intdata_size;
254  void F(int);
255};
256
257template <typename T>
258void Class<T>::F(int data_size){};
259
260void Foo() {
261  Class<char>().F(123);
262};
263
264}  // namespace test_unnamed_arg
265
266namespace cxx_dependent_scope_member_expr_testing {
267
268class PartitionAllocator {
269 public:
270  static void Method() {}
271};
272
273template <typename Allocator = PartitionAllocator>
274class Vector {
275 public:
276  // https://crbug.com/582315: |Allocator::method| is a
277  // CXXDependentScopeMemberExpr.
278  void AnotherMethod() {
279    if (std::is_class<Allocator>::value)  // Shouldn't rename |value|
280      Allocator::Method();                // Should rename |method| -> |Method|.
281  }
282};
283
284template <typename Allocator = PartitionAllocator>
285void Test() {
286  // https://crbug.com/582315: |Allocator::method| is a
287  // DependentScopeDeclRefExpr.
288  if (std::is_class<Allocator>::value)  // Shouldn't rename |value|.
289    Allocator::Method();                // Should rename |method|.
290}
291
292class InterceptingCanvasBase : public ::not_blink::Class {
293 public:
294  virtual void VirtualMethodInBlink(){};
295};
296
297template <typename DerivedCanvas>
298class InterceptingCanvas : public InterceptingCanvasBase {
299 public:
300  void virtualMethod() override {
301    this->Class::virtualMethod();  // https://crbug.com/582315#c19
302    this->InterceptingCanvasBase::VirtualMethodInBlink();
303  }
304};
305
306template <typename T>
307class ThreadSpecific {
308 public:
309  T* operator->();
310  operator T*();
311};
312
313template <typename T>
314inline ThreadSpecific<T>::operator T*() {
315  return nullptr;
316}
317
318template <typename T>
319inline T* ThreadSpecific<T>::operator->() {
320  return operator T*();
321}
322
323class Class {
324 public:
325  virtual void VirtualMethodInBlink() {}
326};
327
328}  // namespace cxx_dependent_scope_member_expr_testing
329
330namespace blacklisting_of_renaming_of_begin_method {
331
332template <typename T>
333class IntrusiveHeap {
334 public:
335  // https://crbug.com/672353: |begin| shouldn't be rewritten to |Begin|.
336  const T* begin() const { return nullptr; }
337};
338
339}  // namespace blacklisting_of_renaming_of_begin_method
340
341}  // namespace blink
342
343namespace not_blink {
344
345namespace cxx_dependent_scope_member_expr_testing {
346
347class Base : public ::blink::cxx_dependent_scope_member_expr_testing::Class {
348 public:
349  virtual void virtualMethod() {}
350};
351
352template <typename T>
353class Derived : public Base {
354 public:
355  void virtualMethod() override {
356    this->Class::VirtualMethodInBlink();
357    this->Base::virtualMethod();
358  }
359};
360
361}  // namespace cxx_dependent_scope_member_expr_testing
362
363namespace blink_methods_called_from_mojo_traits_are_not_rewritten {
364
365template <typename V>
366struct MapTraits;
367
368template <typename V>
369struct MapTraits<blink::test_unnamed_arg::Class<V>> {
370  static void SetToEmpty(blink::test_unnamed_arg::Class<V>* output) {
371    // Need to rewrite |f| to |F| below (because this method name
372    // does get rewritten when processing blink::test_unnamed_arg::Class).
373    // See also https://crbug.com/670434.
374    output->F(123);
375  }
376};
377
378}  // namespace blink_methods_called_from_mojo_traits_are_not_rewritten
379
380}  // namespace not_blink
381