This commit is contained in:
Yamozha
2021-04-02 02:24:13 +03:00
parent c23950b545
commit 7256d79e2c
31493 changed files with 3036630 additions and 0 deletions

View File

@ -0,0 +1,79 @@
load("@fbsource//tools/build_defs:platform_defs.bzl", "CXX")
load(
"@fbsource//tools/build_defs/apple:flag_defs.bzl",
"get_preprocessor_flags_for_build_mode",
)
load(
"//tools/build_defs/oss:rn_defs.bzl",
"ANDROID",
"APPLE",
"fb_xplat_cxx_test",
"get_apple_compiler_flags",
"get_apple_inspector_flags",
"rn_xplat_cxx_library",
"subdir_glob",
)
APPLE_COMPILER_FLAGS = get_apple_compiler_flags()
rn_xplat_cxx_library(
name = "debug",
srcs = glob(
["**/*.cpp"],
exclude = glob(["tests/**/*.cpp"]),
),
headers = glob(
["**/*.h"],
exclude = glob(["tests/**/*.h"]),
),
header_namespace = "",
exported_headers = subdir_glob(
[
("", "*.h"),
],
prefix = "react/debug",
),
compiler_flags = [
"-fexceptions",
"-frtti",
"-std=c++14",
"-Wall",
],
fbobjc_compiler_flags = APPLE_COMPILER_FLAGS,
fbobjc_labels = ["supermodule:ios/default/public.react_native.infra"],
fbobjc_preprocessor_flags = get_preprocessor_flags_for_build_mode() + get_apple_inspector_flags(),
force_static = True,
macosx_tests_override = [],
platforms = (ANDROID, APPLE, CXX),
preprocessor_flags = [
"-DLOG_TAG=\"ReactNative\"",
"-DWITH_FBSYSTRACE=1",
],
tests = [":tests"],
visibility = ["PUBLIC"],
deps = [
"//xplat/fbsystrace:fbsystrace",
"//xplat/folly:headers_only",
"//xplat/folly:memory",
"//xplat/folly:molly",
],
)
fb_xplat_cxx_test(
name = "tests",
srcs = glob(["tests/**/*.cpp"]),
headers = glob(["tests/**/*.h"]),
compiler_flags = [
"-fexceptions",
"-frtti",
"-std=c++14",
"-Wall",
],
contacts = ["oncall+react_native@xmail.facebook.com"],
platforms = (ANDROID, APPLE, CXX),
deps = [
":debug",
"//xplat/folly:molly",
"//xplat/third-party/gmock:gtest",
],
)

View File

@ -0,0 +1,154 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "DebugStringConvertible.h"
#include <folly/Conv.h>
#include <folly/Format.h>
namespace facebook {
namespace react {
#if RN_DEBUG_STRING_CONVERTIBLE
std::string DebugStringConvertible::getDebugChildrenDescription(
DebugStringConvertibleOptions options) const {
if (options.depth >= options.maximumDepth) {
return "";
}
options.depth++;
auto trailing = options.format ? std::string{"\n"} : std::string{""};
auto childrenString = std::string{""};
for (auto child : getDebugChildren()) {
if (!child) {
continue;
}
childrenString += child->getDebugDescription(options) + trailing;
}
if (!childrenString.empty() && !trailing.empty()) {
// Removing trailing fragment.
childrenString.erase(childrenString.end() - 1);
}
return childrenString;
}
std::string DebugStringConvertible::getDebugPropsDescription(
DebugStringConvertibleOptions options) const {
if (options.depth >= options.maximumDepth) {
return "";
}
options.depth++;
auto propsString = std::string{""};
for (auto prop : getDebugProps()) {
if (!prop) {
continue;
}
auto name = prop->getDebugName();
auto value = prop->getDebugValue();
auto children = prop->getDebugPropsDescription(options);
auto valueAndChildren =
value + (children.empty() ? "" : "(" + children + ")");
propsString +=
" " + name + (valueAndChildren.empty() ? "" : "=" + valueAndChildren);
}
if (!propsString.empty()) {
// Removing leading space character.
propsString.erase(propsString.begin());
}
return propsString;
}
std::string DebugStringConvertible::getDebugDescription(
DebugStringConvertibleOptions options) const {
auto nameString = getDebugName();
auto valueString = getDebugValue();
// Convention:
// If `name` and `value` are empty, `description` is also empty.
if (nameString.empty() && valueString.empty()) {
return "";
}
// Convention:
// If `name` is empty and `value` isn't empty, `description` equals `value`.
if (nameString.empty()) {
return valueString;
}
auto childrenString = getDebugChildrenDescription(options);
auto propsString = getDebugPropsDescription(options);
auto leading =
options.format ? std::string(options.depth * 2, ' ') : std::string{""};
auto trailing = options.format ? std::string{"\n"} : std::string{""};
return leading + "<" + nameString +
(valueString.empty() ? "" : "=" + valueString) +
(propsString.empty() ? "" : " " + propsString) +
(childrenString.empty() ? "/>"
: ">" + trailing + childrenString + trailing +
leading + "</" + nameString + ">");
}
std::string DebugStringConvertible::getDebugName() const {
return "Node";
}
std::string DebugStringConvertible::getDebugValue() const {
return "";
}
SharedDebugStringConvertibleList DebugStringConvertible::getDebugChildren()
const {
return SharedDebugStringConvertibleList();
}
SharedDebugStringConvertibleList DebugStringConvertible::getDebugProps() const {
return SharedDebugStringConvertibleList();
}
/*
* `toString`-family implementation.
*/
std::string toString(std::string const &value) {
return value;
}
std::string toString(int const &value) {
return folly::to<std::string>(value);
}
std::string toString(bool const &value) {
return folly::to<std::string>(value);
}
std::string toString(float const &value) {
return folly::to<std::string>(value);
}
std::string toString(double const &value) {
return folly::to<std::string>(value);
}
std::string toString(void const *value) {
if (value == nullptr) {
return "null";
}
return folly::sformat("0x{0:016x}", reinterpret_cast<size_t>(value));
}
#endif
} // namespace react
} // namespace facebook

View File

@ -0,0 +1,364 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <climits>
#include <memory>
#include <string>
#include <unordered_set>
#include <vector>
namespace facebook {
namespace react {
#ifndef NDEBUG
#define RN_DEBUG_STRING_CONVERTIBLE 1
#endif
#if RN_DEBUG_STRING_CONVERTIBLE
class DebugStringConvertible;
using SharedDebugStringConvertible =
std::shared_ptr<const DebugStringConvertible>;
using SharedDebugStringConvertibleList =
std::vector<SharedDebugStringConvertible>;
struct DebugStringConvertibleOptions {
bool format{true};
int depth{0};
int maximumDepth{INT_MAX};
};
/*
* Abstract class describes conformance to DebugStringConvertible concept
* and implements basic recursive debug string assembly algorithm.
* Use this as a base class for providing a debugging textual representation
* of your class.
*
* The `DebugStringConvertible` *class* is obsolete. Whenever possible prefer
* implementing standalone functions that conform to the informal
* `DebugStringConvertible`-like interface instead of extending this class.
*/
class DebugStringConvertible {
public:
virtual ~DebugStringConvertible() = default;
// Returns a name of the object.
// Default implementation returns "Node".
virtual std::string getDebugName() const;
// Returns a value associate with the object.
// Default implementation returns an empty string.
virtual std::string getDebugValue() const;
// Returns a list of `DebugStringConvertible` objects which can be considered
// as *children* of the object.
// Default implementation returns an empty list.
virtual SharedDebugStringConvertibleList getDebugChildren() const;
// Returns a list of `DebugStringConvertible` objects which can be considered
// as *properties* of the object.
// Default implementation returns an empty list.
virtual SharedDebugStringConvertibleList getDebugProps() const;
// Returns a string which represents the object in a human-readable way.
// Default implementation returns a description of the subtree
// rooted at this node, represented in XML-like format.
virtual std::string getDebugDescription(
DebugStringConvertibleOptions options = {}) const;
// Do same as `getDebugDescription` but return only *children* and
// *properties* parts (which are used in `getDebugDescription`).
virtual std::string getDebugPropsDescription(
DebugStringConvertibleOptions options = {}) const;
virtual std::string getDebugChildrenDescription(
DebugStringConvertibleOptions options = {}) const;
};
#else
class DebugStringConvertible {};
#endif
#if RN_DEBUG_STRING_CONVERTIBLE
/*
* Set of particular-format-opinionated functions that convert base types to
* `std::string`; practically incapsulate `folly:to<>` and `folly::format`.
*/
std::string toString(std::string const &value);
std::string toString(int const &value);
std::string toString(bool const &value);
std::string toString(float const &value);
std::string toString(double const &value);
std::string toString(void const *value);
/*
* *Informal* `DebugStringConvertible` interface.
*
* The interface consts of several functions which are designed to be composable
* and reusable relying on C++ overloading mechanism. Implement appropriate
* versions of those functions for your custom type to enable conformance to the
* interface:
*
* - `getDebugName`: Returns a name of the object. Default implementation
* returns "Node".
*
* - `getDebugValue`: Returns a value associate with the object. Default
* implementation returns an empty string.
*
* - `getDebugChildren`: Returns a list of `DebugStringConvertible`-compatible
* objects which can be considered as *children* of the object. Default
* implementation returns an empty list.
*
* - `getDebugProps`: Returns a list of `DebugStringConvertible` objects which
* can be considered as *properties* of the object. Default implementation
* returns an empty list.
*
* - `getDebugDescription`: Returns a string which represents the object in a
* human-readable way. Default implementation returns a description of the
* subtree rooted at this node, represented in XML-like format using functions
* above to form the tree.
*/
/*
* Universal implementation of `getDebugDescription`-family functions for all
* types.
*/
template <typename T>
std::string getDebugName(T const &object) {
return "Node";
}
template <typename T>
std::string getDebugValue(T const &object) {
return "";
}
template <typename T>
std::vector<T> getDebugChildren(
T const &object,
DebugStringConvertibleOptions options) {
return {};
}
template <typename T>
std::vector<T> getDebugProps(
T const &object,
DebugStringConvertibleOptions options) {
return {};
}
template <typename T>
std::string getDebugPropsDescription(
T const &object,
DebugStringConvertibleOptions options) {
if (options.depth >= options.maximumDepth) {
return "";
}
std::string propsString = "";
options.depth++;
for (auto prop : getDebugProps(object, options)) {
auto name = getDebugName(prop);
auto value = getDebugValue(prop);
auto children = getDebugPropsDescription(prop, options);
auto valueAndChildren =
value + (children.empty() ? "" : "(" + children + ")");
propsString +=
" " + name + (valueAndChildren.empty() ? "" : "=" + valueAndChildren);
}
if (!propsString.empty()) {
// Removing leading space character.
propsString.erase(propsString.begin());
}
return propsString;
}
template <typename T>
std::string getDebugChildrenDescription(
T const &object,
DebugStringConvertibleOptions options) {
if (options.depth >= options.maximumDepth) {
return "";
}
auto trailing = options.format ? std::string{"\n"} : std::string{""};
auto childrenString = std::string{""};
options.depth++;
for (auto child : getDebugChildren(object, options)) {
childrenString += getDebugDescription(child, options) + trailing;
}
if (!childrenString.empty() && !trailing.empty()) {
// Removing trailing fragment.
childrenString.erase(childrenString.end() - 1);
}
return childrenString;
}
template <typename T>
std::string getDebugDescription(
T const &object,
DebugStringConvertibleOptions options) {
auto nameString = getDebugName(object);
auto valueString = getDebugValue(object);
// Convention:
// If `name` and `value` are empty, `description` is also empty.
if (nameString.empty() && valueString.empty()) {
return "";
}
// Convention:
// If `name` is empty and `value` isn't empty, `description` equals `value`.
if (nameString.empty()) {
return valueString;
}
auto childrenString = getDebugChildrenDescription(object, options);
auto propsString = getDebugPropsDescription(object, options);
auto leading =
options.format ? std::string(options.depth * 2, ' ') : std::string{""};
auto trailing = options.format ? std::string{"\n"} : std::string{""};
return leading + "<" + nameString +
(valueString.empty() ? "" : "=" + valueString) +
(propsString.empty() ? "" : " " + propsString) +
(childrenString.empty() ? "/>"
: ">" + trailing + childrenString + trailing +
leading + "</" + nameString + ">");
}
/*
* Functions of `getDebugDescription`-family for primitive types.
*/
// `int`
inline std::string getDebugDescription(
int number,
DebugStringConvertibleOptions options) {
return toString(number);
}
// `float`
inline std::string getDebugDescription(
float number,
DebugStringConvertibleOptions options) {
return toString(number);
}
// `double`
inline std::string getDebugDescription(
double number,
DebugStringConvertibleOptions options) {
return toString(number);
}
// `bool`
inline std::string getDebugDescription(
bool boolean,
DebugStringConvertibleOptions options) {
return toString(boolean);
}
// `void *`
inline std::string getDebugDescription(
void *pointer,
DebugStringConvertibleOptions options) {
return toString(pointer);
}
// `std::string`
inline std::string getDebugDescription(
std::string const &string,
DebugStringConvertibleOptions options) {
return string;
}
// `std::vector<T>`
template <typename T, typename... Ts>
std::string getDebugName(std::vector<T, Ts...> const &vector) {
return "List";
}
template <typename T, typename... Ts>
std::vector<T, Ts...> getDebugChildren(
std::vector<T, Ts...> const &vector,
DebugStringConvertibleOptions options) {
return vector;
}
// `std::unordered_set<T>`
template <typename T, typename... Ts>
std::string getDebugName(std::unordered_set<T, Ts...> const &set) {
return "Set";
}
template <typename T, typename... Ts>
std::vector<T> getDebugChildren(
std::unordered_set<T, Ts...> const &set,
DebugStringConvertibleOptions options) {
auto vector = std::vector<T>{};
vector.insert(vector.end(), set.begin(), set.end());
return vector;
}
// `std::shared_ptr<T>`
template <typename T>
inline std::string getDebugDescription(
std::shared_ptr<T> const &pointer,
DebugStringConvertibleOptions options) {
return getDebugDescription((void *)pointer.get(), options) + "(shared)";
}
// `std::weak_ptr<T>`
template <typename T>
inline std::string getDebugDescription(
std::weak_ptr<T> const &pointer,
DebugStringConvertibleOptions options) {
return getDebugDescription((void *)pointer.lock().get(), options) + "(weak)";
}
// `std::unique_ptr<T>`
template <typename T>
inline std::string getDebugDescription(
std::unique_ptr<T const> const &pointer,
DebugStringConvertibleOptions options) {
return getDebugDescription((void *)pointer.get(), options) + "(unique)";
}
/*
* Trivial container for `name` and `value` pair that supports
* static `DebugStringConvertible` informal interface.
*/
struct DebugStringConvertibleObject {
std::string name;
std::string value;
};
inline std::string getDebugName(DebugStringConvertibleObject const &object) {
return object.name;
}
inline std::string getDebugValue(DebugStringConvertibleObject const &object) {
return object.value;
}
#endif
} // namespace react
} // namespace facebook

View File

@ -0,0 +1,43 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "DebugStringConvertibleItem.h"
namespace facebook {
namespace react {
#if RN_DEBUG_STRING_CONVERTIBLE
DebugStringConvertibleItem::DebugStringConvertibleItem(
const std::string &name,
const std::string &value,
const SharedDebugStringConvertibleList &props,
const SharedDebugStringConvertibleList &children)
: name_(name), value_(value), debugProps_(props), children_(children) {}
std::string DebugStringConvertibleItem::getDebugName() const {
return name_;
}
std::string DebugStringConvertibleItem::getDebugValue() const {
return value_;
}
SharedDebugStringConvertibleList DebugStringConvertibleItem::getDebugProps()
const {
return debugProps_;
}
SharedDebugStringConvertibleList DebugStringConvertibleItem::getDebugChildren()
const {
return children_;
}
#endif
} // namespace react
} // namespace facebook

View File

@ -0,0 +1,47 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <string>
#include <react/debug/DebugStringConvertible.h>
namespace facebook {
namespace react {
#if RN_DEBUG_STRING_CONVERTIBLE
// Trivial implementation of `DebugStringConvertible` abstract class
// with a stored output; useful for assembling `DebugStringConvertible` values
// in custom implementations of `getDebugChildren` and `getDebugProps`.
class DebugStringConvertibleItem : public DebugStringConvertible {
public:
DebugStringConvertibleItem(const DebugStringConvertibleItem &item) = default;
DebugStringConvertibleItem(
const std::string &name = "",
const std::string &value = "",
const SharedDebugStringConvertibleList &props = {},
const SharedDebugStringConvertibleList &children = {});
std::string getDebugName() const override;
std::string getDebugValue() const override;
SharedDebugStringConvertibleList getDebugChildren() const override;
SharedDebugStringConvertibleList getDebugProps() const override;
private:
std::string name_;
std::string value_;
SharedDebugStringConvertibleList debugProps_;
SharedDebugStringConvertibleList children_;
};
#endif
} // namespace react
} // namespace facebook

View File

@ -0,0 +1,51 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#ifdef WITH_FBSYSTRACE
#include <fbsystrace.h>
#endif
namespace facebook {
namespace react {
/**
* This is a convenience class to avoid lots of verbose profiling
* #ifdefs. If WITH_FBSYSTRACE is not defined, the optimizer will
* remove this completely. If it is defined, it will behave as
* FbSystraceSection, with the right tag provided. Use two separate classes to
* to ensure that the ODR rule isn't violated, that is, if WITH_FBSYSTRACE has
* different values in different files, there is no inconsistency in the sizes
* of defined symbols.
*/
#ifdef WITH_FBSYSTRACE
struct ConcreteSystraceSection {
public:
template <typename... ConvertsToStringPiece>
explicit ConcreteSystraceSection(
const char *name,
ConvertsToStringPiece &&... args)
: m_section(TRACE_TAG_REACT_CXX_BRIDGE, name, args...) {}
private:
fbsystrace::FbSystraceSection m_section;
};
using SystraceSection = ConcreteSystraceSection;
#else
struct DummySystraceSection {
public:
template <typename... ConvertsToStringPiece>
explicit DummySystraceSection(
const char *name,
ConvertsToStringPiece &&... args) {}
};
using SystraceSection = DummySystraceSection;
#endif
} // namespace react
} // namespace facebook

View File

@ -0,0 +1,66 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <limits>
#include <memory>
#include <string>
#include <vector>
#include <react/debug/DebugStringConvertible.h>
#include <react/debug/DebugStringConvertibleItem.h>
namespace facebook {
namespace react {
#if RN_DEBUG_STRING_CONVERTIBLE
template <typename T>
inline SharedDebugStringConvertible
debugStringConvertibleItem(std::string name, T value, T defaultValue = {}) {
if (value == defaultValue) {
return nullptr;
}
return std::make_shared<DebugStringConvertibleItem>(name, toString(value));
}
template <typename T>
inline SharedDebugStringConvertible debugStringConvertibleItem(
std::string name,
folly::Optional<T> value,
T defaultValue = {}) {
if (!value.hasValue()) {
return nullptr;
}
return debugStringConvertibleItem(
name, value.value_or(defaultValue), defaultValue);
}
inline SharedDebugStringConvertibleList operator+(
const SharedDebugStringConvertibleList &lhs,
const SharedDebugStringConvertibleList &rhs) {
auto result = SharedDebugStringConvertibleList{};
std::move(lhs.begin(), lhs.end(), std::back_inserter(result));
std::move(rhs.begin(), rhs.end(), std::back_inserter(result));
return result;
}
inline SharedDebugStringConvertible debugStringConvertibleItem(
std::string name,
DebugStringConvertible value,
std::string defaultValue) {
return debugStringConvertibleItem(
name, value.getDebugDescription(), defaultValue);
}
#endif
} // namespace react
} // namespace facebook

View File

@ -0,0 +1,84 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include <memory>
#include <gtest/gtest.h>
#include <react/debug/DebugStringConvertibleItem.h>
using namespace facebook::react;
TEST(DebugStringConvertibleTest, handleSimpleNode) {
SharedDebugStringConvertibleList empty;
auto item = std::make_shared<DebugStringConvertibleItem>(
"View", "hello", empty, empty);
ASSERT_STREQ(item->getDebugName().c_str(), "View");
ASSERT_STREQ(item->getDebugValue().c_str(), "hello");
ASSERT_STREQ(item->getDebugDescription().c_str(), "<View=hello/>");
}
TEST(DebugStringConvertibleTest, handleSimpleNodeWithProps) {
SharedDebugStringConvertibleList empty;
SharedDebugStringConvertibleList props = {
std::make_shared<DebugStringConvertibleItem>("x", "1", empty, empty)};
auto item = std::make_shared<DebugStringConvertibleItem>(
"View", "hello", props, empty);
ASSERT_STREQ(item->getDebugName().c_str(), "View");
ASSERT_STREQ(item->getDebugValue().c_str(), "hello");
ASSERT_STREQ(item->getDebugDescription().c_str(), "<View=hello x=1/>");
}
TEST(DebugStringConvertibleTest, handleSimpleNodeWithChildren) {
SharedDebugStringConvertibleList empty;
SharedDebugStringConvertibleList children = {
std::make_shared<DebugStringConvertibleItem>("Child", "a", empty, empty)};
auto item = std::make_shared<DebugStringConvertibleItem>(
"View", "hello", empty, children);
ASSERT_STREQ(item->getDebugName().c_str(), "View");
ASSERT_STREQ(item->getDebugValue().c_str(), "hello");
ASSERT_STREQ(
item->getDebugDescription().c_str(),
"<View=hello>\n <Child=a/>\n</View>");
}
TEST(DebugStringConvertibleTest, handleNestedNode) {
SharedDebugStringConvertibleList empty;
SharedDebugStringConvertibleList props = {
std::make_shared<DebugStringConvertibleItem>("x", "1", empty, empty)};
SharedDebugStringConvertibleList children = {
std::make_shared<DebugStringConvertibleItem>("Child", "a", props, empty)};
auto item = std::make_shared<DebugStringConvertibleItem>(
"View", "hello", props, children);
ASSERT_STREQ(item->getDebugName().c_str(), "View");
ASSERT_STREQ(item->getDebugValue().c_str(), "hello");
ASSERT_STREQ(
item->getDebugDescription().c_str(),
"<View=hello x=1>\n <Child=a x=1/>\n</View>");
}
TEST(DebugStringConvertibleTest, handleNodeWithComplexProps) {
SharedDebugStringConvertibleList empty;
SharedDebugStringConvertibleList subProps = {
std::make_shared<DebugStringConvertibleItem>(
"height", "100", empty, empty),
std::make_shared<DebugStringConvertibleItem>(
"width", "200", empty, empty)};
SharedDebugStringConvertibleList props = {
std::make_shared<DebugStringConvertibleItem>("x", "1", subProps, empty)};
auto item = std::make_shared<DebugStringConvertibleItem>(
"View", "hello", props, empty);
ASSERT_STREQ(item->getDebugName().c_str(), "View");
ASSERT_STREQ(item->getDebugValue().c_str(), "hello");
ASSERT_STREQ(
item->getDebugDescription().c_str(),
"<View=hello x=1(height=100 width=200)/>");
}