chromium/tools/clang/rewrite_raw_ptr_fields/tests/gen-global-scope-test.cc

// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// This file (and other gen-*-test.cc files) tests generation of output for
// --field-filter-file and therefore the expectations file
// (gen-global-scope-expected.txt) needs to be compared against the raw
// output of the rewriter (rather than against the actual edits result).  This
// makes the test incompatible with other tests, which require passing
// --apply-edits switch to test_tool.py and so to disable the test it is named
// *-test.cc rather than *-original.cc.
//
// To run the test use tools/clang/rewrite_raw_ptr_fields/tests/run_all_tests.py

// Chromium is built with a warning/error that global and static variables
// may only have trivial destructors.  See also:
// https://google.github.io/styleguide/cppguide.html#Static_and_Global_Variables
// go/totw/110#destruction
//
// If raw_ptr has a non-trivial destructor (e.g. if it is implemented via
// BackupRefPtr) then raw_ptr cannot be used as the type of fields in structs
// that are (recursively/transitively) the type of a global variable:
//     struct MyStruct {       //    Presence of raw_ptr might mean that
//       raw_ptr<int> ptr;  // <- MyStruct has a non-trivial destructor.
//     };
//     MyStruct g_struct;  // <- Error if MyStruct has a non-trivial destructor.
//
// To account for the constraints described above, the rewriter tool should
// avoid rewriting some of the fields below.
#include "base/containers/span.h"

namespace global_variables_test {

struct MyStruct {
  MyStruct(int& r) : ref(r), ref2(r) {}
  // Expected to be emitted in automated-fields-to-ignore.txt, because
  // of |g_struct| below.
  int* ptr;
  int& ref;
  base::span<int> span_member;

  // Verification that *all* fields of a struct are covered (e.g. that the
  // |forEach| matcher is used instead of the |has| matcher).
  int* ptr2;
  int& ref2;
  base::span<int> span_member2;
};
int num = 11;
MyStruct g_struct(num);

}  // namespace global_variables_test

namespace static_variables_test {

struct MyStruct {
  MyStruct(int& r) : ref(r) {}
  // Expected to be emitted in automated-fields-to-ignore.txt, because
  // of |s_struct| below.
  int* ptr;
  int& ref;
  base::span<int> span_member;
};

void foo() {
  static int n = 11;
  static MyStruct s_struct(n);
}

}  // namespace static_variables_test

namespace nested_struct_test {

struct MyStruct {
  MyStruct(int& r) : ref(r) {}
  // Expected to be emitted in automated-fields-to-ignore.txt, because
  // of |g_outer_struct| below.
  int* ptr;
  int& ref;
  base::span<int> span_member;
};

struct MyOuterStruct {
  MyOuterStruct(int& r) : inner_struct(r) {}
  MyStruct inner_struct;
};
static int n = 42;
static MyOuterStruct g_outer_struct(n);

}  // namespace nested_struct_test

namespace nested_in_array_test {

struct MyStruct {
  MyStruct(int& r) : ref(r) {}
  // Expected to be emitted in automated-fields-to-ignore.txt, because
  // of |g_outer_array| below.
  int* ptr;
  int& ref;
  base::span<int> span_member;
};
static int num = 42;
static MyStruct g_outer_struct[] = {num, num, num};

}  // namespace nested_in_array_test

namespace nested_template_test {

template <typename T>
struct MyStruct {
  MyStruct(T& r) : ref(r), ref2(r) {}
  // Expected to be emitted in automated-fields-to-ignore.txt, because
  // of |g_outer_struct| below.
  T* ptr;

  T* ptr2;

  T& ref;

  T& ref2;

  base::span<int> span_member;
};

struct MyOuterStruct {
  MyOuterStruct(int& r) : inner_struct(r) {}
  MyStruct<int> inner_struct;
};

static int num = 42;
static MyOuterStruct g_outer_struct(num);

}  // namespace nested_template_test

namespace pointer_nesting_test {

struct MyStruct {
  // Should not be emitted in automated-fields-to-ignore.txt, because
  // |inner_struct| field below is a pointer.  (i.e. this is a test that
  // |hasNestedFieldDecl| matcher doesn't recurse/traverse over pointers)
  int* ptr;
  base::span<int> span_member;
};

struct MyOuterStruct {
  // Expected to be emitted in automated-fields-to-ignore.txt, because
  // of |g_outer_struct| below.
  MyStruct* inner_struct;
  base::span<int> span_member;
};

static MyOuterStruct g_outer_struct;

}  // namespace pointer_nesting_test