Replace json dependency with llvm::json
PiperOrigin-RevId: 434896655
diff --git a/rs_bindings_from_cc/cmdline.cc b/rs_bindings_from_cc/cmdline.cc
index eaf9357..26d75cb 100644
--- a/rs_bindings_from_cc/cmdline.cc
+++ b/rs_bindings_from_cc/cmdline.cc
@@ -11,8 +11,9 @@
#include <vector>
#include "third_party/absl/flags/flag.h"
+#include "third_party/absl/strings/str_cat.h"
#include "third_party/absl/strings/substitute.h"
-#include "third_party/json/include/nlohmann/json.hpp"
+#include "third_party/llvm/llvm-project/llvm/include/llvm/Support/JSON.h"
#include "util/task/status_macros.h"
ABSL_FLAG(bool, do_nothing, false,
@@ -42,6 +43,21 @@
namespace rs_bindings_from_cc {
+namespace {
+
+struct TargetAndHeaders {
+ std::string target;
+ std::vector<std::string> headers;
+};
+
+bool fromJSON(const llvm::json::Value& json, TargetAndHeaders& out,
+ llvm::json::Path path) {
+ llvm::json::ObjectMapper mapper(json, path);
+ return mapper && mapper.map("t", out.target) && mapper.map("h", out.headers);
+}
+
+} // namespace
+
absl::StatusOr<Cmdline> Cmdline::Create() {
return CreateFromArgs(
absl::GetFlag(FLAGS_cc_out), absl::GetFlag(FLAGS_rs_out),
@@ -79,56 +95,33 @@
if (targets_and_headers_str.empty()) {
return absl::InvalidArgumentError("please specify --targets_and_headers");
}
- nlohmann::json targets_and_headers =
- nlohmann::json::parse(std::move(targets_and_headers_str),
- /* cb= */ nullptr,
- /* allow_exceptions= */ false);
- if (!targets_and_headers.is_array()) {
+ auto targets_and_headers = llvm::json::parse<std::vector<TargetAndHeaders>>(
+ std::move(targets_and_headers_str));
+ if (auto err = targets_and_headers.takeError()) {
return absl::InvalidArgumentError(
- "Expected `--targets_and_headers` to be a JSON array of objects");
+ absl::StrCat("Malformed `--targets_and_headers` argument: ",
+ toString(std::move(err))));
}
- for (const auto& target_and_headers : targets_and_headers) {
- if (!target_and_headers.contains("t")) {
- return absl::InvalidArgumentError(
- "Missing `t` field in an `--targets_and_headers` object");
- }
- if (!target_and_headers["t"].is_string()) {
- return absl::InvalidArgumentError(
- "Expected `t` fields of `--targets_and_headers` to be a string");
- }
- if (!target_and_headers.contains("h")) {
- return absl::InvalidArgumentError(
- "Missing `h` field in an `--targets_and_headers` object");
- }
- if (!target_and_headers["h"].is_array()) {
- return absl::InvalidArgumentError(
- "Expected `h` fields of `--targets_and_headers` to be an array");
- }
- BlazeLabel target{std::string(target_and_headers["t"])};
- if (target.value().empty()) {
+ for (const TargetAndHeaders& it : *targets_and_headers) {
+ const std::string& target = it.target;
+ if (target.empty()) {
return absl::InvalidArgumentError(
"Expected `t` fields of `--targets_and_headers` to be a non-empty "
"string");
}
- for (const auto& header : target_and_headers["h"]) {
- if (!header.is_string()) {
- return absl::InvalidArgumentError(
- "Expected `h` fields of `--targets_and_headers` to be an array of "
- "strings");
- }
- std::string header_str(header);
- if (header_str.empty()) {
+ for (const std::string& header : it.headers) {
+ if (header.empty()) {
return absl::InvalidArgumentError(
"Expected `h` fields of `--targets_and_headers` to be an array of "
"non-empty strings");
}
const auto [it, inserted] = cmdline.headers_to_targets_.insert(
- std::make_pair(HeaderName(header_str), target));
+ std::make_pair(HeaderName(header), BlazeLabel(target)));
if (!inserted) {
return absl::InvalidArgumentError(absl::Substitute(
"The `--targets_and_headers` cmdline argument assigns "
"`$0` header to two conflicting targets: `$1` vs `$2`",
- header_str, target.value(), it->second.value()));
+ header, target, it->second.value()));
}
}
}
diff --git a/rs_bindings_from_cc/cmdline_test.cc b/rs_bindings_from_cc/cmdline_test.cc
index a05dbca..8dd5fdc 100644
--- a/rs_bindings_from_cc/cmdline_test.cc
+++ b/rs_bindings_from_cc/cmdline_test.cc
@@ -57,10 +57,10 @@
}
TEST(CmdlineTest, TargetsAndHeadersInvalidJson) {
- ASSERT_THAT(
- TestCmdline({"h1"}, "#!$%"),
- StatusIs(absl::StatusCode::kInvalidArgument,
- AllOf(HasSubstr("--targets_and_headers"), HasSubstr("array"))));
+ ASSERT_THAT(TestCmdline({"h1"}, "#!$%"),
+ StatusIs(absl::StatusCode::kInvalidArgument,
+ AllOf(HasSubstr("--targets_and_headers"),
+ HasSubstr("Invalid JSON"))));
}
TEST(CmdlineTest, TargetsAndHeadersIntInsteadOfTopLevelArray) {
@@ -80,21 +80,21 @@
ASSERT_THAT(TestCmdline({"h1"}, R"([{"t": "t1", "h": 123}])"),
StatusIs(absl::StatusCode::kInvalidArgument,
AllOf(HasSubstr("--targets_and_headers"),
- HasSubstr("`h`"), HasSubstr("array"))));
+ HasSubstr(".h"), HasSubstr("array"))));
}
TEST(CmdlineTest, TargetsAndHeadersMissingTarget) {
ASSERT_THAT(TestCmdline({"h1"}, R"([{"h": ["h1", "h2"]}])"),
StatusIs(absl::StatusCode::kInvalidArgument,
AllOf(HasSubstr("--targets_and_headers"),
- HasSubstr("`t`"), HasSubstr("Missing"))));
+ HasSubstr(".t"), HasSubstr("missing"))));
}
TEST(CmdlineTest, TargetsAndHeadersMissingHeader) {
ASSERT_THAT(TestCmdline({"h1"}, R"([{"t": "t1"}])"),
StatusIs(absl::StatusCode::kInvalidArgument,
AllOf(HasSubstr("--targets_and_headers"),
- HasSubstr("`h`"), HasSubstr("Missing"))));
+ HasSubstr(".h"), HasSubstr("missing"))));
}
TEST(CmdlineTest, TargetsAndHeadersEmptyHeader) {
@@ -115,14 +115,14 @@
ASSERT_THAT(TestCmdline({"h1"}, R"([{"t": 123, "h": ["h1", "h2"]}])"),
StatusIs(absl::StatusCode::kInvalidArgument,
AllOf(HasSubstr("--targets_and_headers"),
- HasSubstr("`t`"), HasSubstr("string"))));
+ HasSubstr(".t"), HasSubstr("string"))));
}
TEST(CmdlineTest, TargetsAndHeadersIntInsteadOfHeader) {
ASSERT_THAT(TestCmdline({"h1"}, R"([{"t": "t1", "h": [123, "h2"]}])"),
StatusIs(absl::StatusCode::kInvalidArgument,
AllOf(HasSubstr("--targets_and_headers"),
- HasSubstr("`h`"), HasSubstr("string"))));
+ HasSubstr(".h"), HasSubstr("string"))));
}
TEST(CmdlineTest, TargetsAndHeadersDuplicateHeader) {
diff --git a/rs_bindings_from_cc/importer.cc b/rs_bindings_from_cc/importer.cc
index 05bb5dd..aad9d40 100644
--- a/rs_bindings_from_cc/importer.cc
+++ b/rs_bindings_from_cc/importer.cc
@@ -47,6 +47,7 @@
#include "third_party/llvm/llvm-project/llvm/include/llvm/ADT/Optional.h"
#include "third_party/llvm/llvm-project/llvm/include/llvm/ADT/SmallPtrSet.h"
#include "third_party/llvm/llvm-project/llvm/include/llvm/Support/Casting.h"
+#include "third_party/llvm/llvm-project/llvm/include/llvm/Support/ErrorHandling.h"
#include "third_party/llvm/llvm-project/llvm/include/llvm/Support/Regex.h"
#include "util/task/status_macros.h"
@@ -154,10 +155,10 @@
}
const clang::CXXRecordDecl* base_record_decl =
ABSL_DIE_IF_NULL(base_specifier.getType()->getAsCXXRecordDecl());
- std::optional<int64_t> offset = {0};
+ llvm::Optional<int64_t> offset = {0};
for (const clang::CXXBasePathElement& base_path_element : path) {
if (base_path_element.Base->isVirtual()) {
- offset = std::nullopt;
+ offset.reset();
break;
}
*offset +=
@@ -166,7 +167,7 @@
base_path_element.Base->getType()->getAsCXXRecordDecl()))
.getQuantity()};
}
- DCHECK(!offset.has_value() || *offset >= 0)
+ DCHECK(!offset.hasValue() || *offset >= 0)
<< "Concrete base classes should have non-negative offsets.";
bases.push_back(
BaseClass{.base_record_id = GenerateDeclId(base_record_decl),
@@ -414,20 +415,18 @@
if (i > 0) {
const auto& prev = items[i - 1];
if (are_equal(item, prev)) {
- std::string prev_json =
- std::visit([&](auto&& item) { return item.ToJson().dump(); },
- std::get<2>(prev));
- std::string curr_json =
- std::visit([&](auto&& item) { return item.ToJson().dump(); },
- std::get<2>(item));
+ llvm::json::Value prev_json = std::visit(
+ [&](auto&& item) { return item.ToJson(); }, std::get<2>(prev));
+ llvm::json::Value curr_json = std::visit(
+ [&](auto&& item) { return item.ToJson(); }, std::get<2>(item));
if (prev_json != curr_json) {
- LOG(FATAL) << "Non-deterministic order of IR items: " << prev_json
- << " -VS- " << curr_json;
+ llvm::report_fatal_error(
+ llvm::formatv("Non-deterministic order of IR items: {0} -VS- {1}",
+ prev_json, curr_json));
} else {
// TODO(lukasza): Avoid generating duplicate IR items. Currently
// known example: UnsupportedItem: name=std::signbit; message=
// Items contained in namespaces are not supported yet.
- LOG(WARNING) << "Duplicated IR item: " << curr_json;
continue;
}
}
@@ -612,7 +611,7 @@
lifetime_params.begin(), lifetime_params.end(),
[](const Lifetime& l1, const Lifetime& l2) { return l1.name < l2.name; });
- std::optional<MemberFuncMetadata> member_func_metadata;
+ llvm::Optional<MemberFuncMetadata> member_func_metadata;
if (auto* method_decl =
clang::dyn_cast<clang::CXXMethodDecl>(function_decl)) {
switch (method_decl->getAccess()) {
@@ -625,7 +624,8 @@
// TODO(lukasza): Revisit this for protected methods.
return LookupResult();
}
- std::optional<MemberFuncMetadata::InstanceMethodMetadata> instance_metadata;
+ llvm::Optional<MemberFuncMetadata::InstanceMethodMetadata>
+ instance_metadata;
if (method_decl->isInstance()) {
MemberFuncMetadata::ReferenceQualification reference;
switch (method_decl->getRefQualifier()) {
@@ -749,7 +749,7 @@
const clang::ASTRecordLayout& layout = ctx_.getASTRecordLayout(record_decl);
- std::optional<size_t> base_size = std::nullopt;
+ llvm::Optional<size_t> base_size;
bool override_alignment = record_decl->hasAttr<clang::AlignedAttr>();
if (record_decl->getNumBases() != 0) {
// The size of the base class subobjects is easy to compute, so long as we
@@ -907,7 +907,8 @@
return !patterns_to_ignore.match(line);
}
-std::optional<std::string> Importer::GetComment(const clang::Decl* decl) const {
+llvm::Optional<std::string> Importer::GetComment(
+ const clang::Decl* decl) const {
// This does currently not distinguish between different types of comments.
// In general it is not possible in C++ to reliably only extract doc comments.
// This is going to be a heuristic that needs to be tuned over time.
@@ -923,9 +924,8 @@
raw_comment->getFormattedText(sm, sm.getDiagnostics());
std::string cleaned_comment_text = absl::StrJoin(
absl::StrSplit(raw_comment_text, '\n', ShouldKeepCommentLine), "\n");
- return cleaned_comment_text.empty()
- ? std::nullopt
- : std::optional<std::string>(std::move(cleaned_comment_text));
+ if (cleaned_comment_text.empty()) return {};
+ return cleaned_comment_text;
}
SourceLoc Importer::ConvertSourceLocation(clang::SourceLocation loc) const {
diff --git a/rs_bindings_from_cc/importer.h b/rs_bindings_from_cc/importer.h
index e5b9a91..ac6d2f8 100644
--- a/rs_bindings_from_cc/importer.h
+++ b/rs_bindings_from_cc/importer.h
@@ -159,7 +159,7 @@
}
// Gets the doc comment of the declaration.
- std::optional<std::string> GetComment(const clang::Decl* decl) const;
+ llvm::Optional<std::string> GetComment(const clang::Decl* decl) const;
// Converts the Clang type `qual_type` into an equivalent `MappedType`.
// Lifetimes for the type can optionally be specified using `lifetimes`.
diff --git a/rs_bindings_from_cc/importer_test.cc b/rs_bindings_from_cc/importer_test.cc
index fba5014..04fbdf4 100644
--- a/rs_bindings_from_cc/importer_test.cc
+++ b/rs_bindings_from_cc/importer_test.cc
@@ -114,10 +114,10 @@
// Matches an RsType or CcType that has the given decl_id.
MATCHER_P(DeclIdIs, decl_id, "") {
- if (arg.decl_id.has_value() && *arg.decl_id == decl_id) return true;
+ if (arg.decl_id.hasValue() && *arg.decl_id == decl_id) return true;
*result_listener << "actual decl_id: ";
- if (arg.decl_id.has_value()) {
+ if (arg.decl_id.hasValue()) {
*result_listener << *arg.decl_id;
} else {
*result_listener << "std::nullopt";
diff --git a/rs_bindings_from_cc/ir.cc b/rs_bindings_from_cc/ir.cc
index 060f316..a949ad5 100644
--- a/rs_bindings_from_cc/ir.cc
+++ b/rs_bindings_from_cc/ir.cc
@@ -16,65 +16,57 @@
#include "base/integral_types.h"
#include "third_party/absl/strings/string_view.h"
#include "rs_bindings_from_cc/bazel_types.h"
-#include "third_party/json/src/json.hpp"
+#include "third_party/llvm/llvm-project/llvm/include/llvm/Support/JSON.h"
#include "util/intops/strong_int.h"
namespace rs_bindings_from_cc {
template <class T>
-static std::vector<nlohmann::json> VectorToJson(const std::vector<T>& v) {
- std::vector<nlohmann::json> result;
- result.reserve(v.size());
- for (const T& t : v) {
- result.push_back(t.ToJson());
- }
- return result;
+llvm::json::Value toJSON(const T& t) {
+ return t.ToJson();
}
-nlohmann::json HeaderName::ToJson() const {
- nlohmann::json result;
- result["name"] = name_;
- return result;
+template <typename TTag, typename TInt>
+llvm::json::Value toJSON(const util_intops::StrongInt<TTag, TInt> strong_int) {
+ return llvm::json::Value(strong_int.value());
}
-nlohmann::json Lifetime::ToJson() const {
- nlohmann::json result;
- result["name"] = name;
- result["id"] = id.value();
- return result;
+template <typename TTag>
+llvm::json::Value toJSON(const gtl::labs::StringType<TTag> string_type) {
+ return llvm::json::Value(string_type.value());
}
-nlohmann::json RsType::ToJson() const {
- nlohmann::json result;
-
- if (decl_id.has_value()) {
- result["decl_id"] = decl_id->value();
- } else {
- result["name"] = name;
- }
- std::vector<nlohmann::json> json_lifetime_args;
- json_lifetime_args.reserve(lifetime_args.size());
- for (const LifetimeId& lifetime_id : lifetime_args) {
- json_lifetime_args.push_back(lifetime_id.value());
- }
- result["lifetime_args"] = json_lifetime_args;
- result["type_args"] = VectorToJson(type_args);
-
- return result;
+llvm::json::Value HeaderName::ToJson() const {
+ return llvm::json::Object{
+ {"name", name_},
+ };
}
-nlohmann::json CcType::ToJson() const {
- nlohmann::json result;
+llvm::json::Value Lifetime::ToJson() const {
+ return llvm::json::Object{
+ {"name", name},
+ {"id", id},
+ };
+}
- if (decl_id.has_value()) {
- result["decl_id"] = decl_id->value();
- } else {
- result["name"] = name;
- }
- result["is_const"] = is_const;
- result["type_args"] = VectorToJson(type_args);
+llvm::json::Value RsType::ToJson() const {
+ return llvm::json::Object{
+ {"name", decl_id.hasValue() ? llvm::json::Value(nullptr)
+ : llvm::json::Value(name)},
+ {"lifetime_args", lifetime_args},
+ {"type_args", type_args},
+ {"decl_id", decl_id},
+ };
+}
- return result;
+llvm::json::Value CcType::ToJson() const {
+ return llvm::json::Object{
+ {"name", decl_id.hasValue() ? llvm::json::Value(nullptr)
+ : llvm::json::Value(name)},
+ {"is_const", is_const},
+ {"type_args", type_args},
+ {"decl_id", decl_id},
+ };
}
static MappedType PointerOrReferenceTo(MappedType pointee_type,
@@ -175,32 +167,30 @@
};
}
-nlohmann::json MappedType::ToJson() const {
- nlohmann::json result;
-
- result["rs_type"] = rs_type.ToJson();
- result["cc_type"] = cc_type.ToJson();
-
- return result;
+llvm::json::Value MappedType::ToJson() const {
+ return llvm::json::Object{
+ {"rs_type", rs_type},
+ {"cc_type", cc_type},
+ };
}
-nlohmann::json Identifier::ToJson() const {
- nlohmann::json result;
- result["identifier"] = identifier_;
- return result;
+llvm::json::Value Identifier::ToJson() const {
+ return llvm::json::Object{
+ {"identifier", identifier_},
+ };
}
-nlohmann::json IntegerConstant::ToJson() const {
- nlohmann::json result;
- result["is_negative"] = is_negative_;
- result["wrapped_value"] = wrapped_value_;
- return result;
+llvm::json::Value IntegerConstant::ToJson() const {
+ return llvm::json::Object{
+ {"is_negative", is_negative_},
+ {"wrapped_value", wrapped_value_},
+ };
}
-nlohmann::json Operator::ToJson() const {
- nlohmann::json result;
- result["name"] = name_;
- return result;
+llvm::json::Value Operator::ToJson() const {
+ return llvm::json::Object{
+ {"name", name_},
+ };
}
static std::string SpecialNameToString(SpecialName special_name) {
@@ -212,81 +202,80 @@
}
}
-nlohmann::json ToJson(const UnqualifiedIdentifier& unqualified_identifier) {
- nlohmann::json result;
+llvm::json::Value toJSON(const UnqualifiedIdentifier& unqualified_identifier) {
if (auto* id = std::get_if<Identifier>(&unqualified_identifier)) {
- result["Identifier"] = id->ToJson();
+ return llvm::json::Object{
+ {"Identifier", *id},
+ };
} else if (auto* op = std::get_if<Operator>(&unqualified_identifier)) {
- result["Operator"] = op->ToJson();
+ return llvm::json::Object{
+ {"Operator", *op},
+ };
} else {
SpecialName special_name = std::get<SpecialName>(unqualified_identifier);
- result[SpecialNameToString(special_name)] = nullptr;
+ return llvm::json::Object{
+ {SpecialNameToString(special_name), nullptr},
+ };
}
- return result;
}
-nlohmann::json FuncParam::ToJson() const {
- nlohmann::json result;
- result["type"] = type.ToJson();
- result["identifier"] = identifier.ToJson();
- return result;
+llvm::json::Value FuncParam::ToJson() const {
+ return llvm::json::Object{
+ {"type", type},
+ {"identifier", identifier},
+ };
}
std::ostream& operator<<(std::ostream& o, const SpecialName& special_name) {
return o << SpecialNameToString(special_name);
}
-nlohmann::json MemberFuncMetadata::ToJson() const {
- nlohmann::json meta;
-
- meta["record_id"] = record_id.value();
-
- if (instance_method_metadata.has_value()) {
- nlohmann::json instance;
-
- absl::string_view reference;
- switch (instance_method_metadata->reference) {
- case MemberFuncMetadata::kLValue:
- reference = "LValue";
- break;
- case MemberFuncMetadata::kRValue:
- reference = "RValue";
- break;
- case MemberFuncMetadata::kUnqualified:
- reference = "Unqualified";
- break;
- }
- instance["reference"] = reference;
- instance["is_const"] = instance_method_metadata->is_const;
- instance["is_virtual"] = instance_method_metadata->is_virtual;
- instance["is_explicit_ctor"] = instance_method_metadata->is_explicit_ctor;
-
- meta["instance_method_metadata"] = std::move(instance);
+llvm::json::Value MemberFuncMetadata::InstanceMethodMetadata::ToJson() const {
+ const char* reference_str = nullptr;
+ switch (reference) {
+ case MemberFuncMetadata::kLValue:
+ reference_str = "LValue";
+ break;
+ case MemberFuncMetadata::kRValue:
+ reference_str = "RValue";
+ break;
+ case MemberFuncMetadata::kUnqualified:
+ reference_str = "Unqualified";
+ break;
}
- return meta;
+ return llvm::json::Object{
+ {"reference", reference_str},
+ {"is_const", is_const},
+ {"is_virtual", is_virtual},
+ {"is_explicit_ctor", is_explicit_ctor},
+ };
}
-nlohmann::json Func::ToJson() const {
- nlohmann::json func;
- func["name"] = rs_bindings_from_cc::ToJson(name);
- func["owning_target"] = owning_target.value();
- if (doc_comment) {
- func["doc_comment"] = *doc_comment;
- }
- func["mangled_name"] = mangled_name;
- func["return_type"] = return_type.ToJson();
- func["params"] = VectorToJson(params);
- func["lifetime_params"] = VectorToJson(lifetime_params);
- func["is_inline"] = is_inline;
- if (member_func_metadata.has_value()) {
- func["member_func_metadata"] = member_func_metadata->ToJson();
- }
- func["source_loc"] = source_loc.ToJson();
+llvm::json::Value MemberFuncMetadata::ToJson() const {
+ return llvm::json::Object{
+ {"record_id", record_id},
+ {"instance_method_metadata", instance_method_metadata},
+ };
+}
- nlohmann::json item;
- item["Func"] = std::move(func);
- return item;
+llvm::json::Value Func::ToJson() const {
+ llvm::json::Object func{
+ {"name", name},
+ {"owning_target", owning_target},
+ {"doc_comment", doc_comment},
+ {"mangled_name", mangled_name},
+ {"return_type", return_type},
+ {"params", params},
+ {"lifetime_params", lifetime_params},
+ {"is_inline", is_inline},
+ {"member_func_metadata", member_func_metadata},
+ {"source_loc", source_loc},
+ };
+
+ return llvm::json::Object{
+ {"Func", std::move(func)},
+ };
}
static std::string AccessToString(AccessSpecifier access) {
@@ -304,18 +293,15 @@
return o << AccessToString(access);
}
-nlohmann::json Field::ToJson() const {
- nlohmann::json result;
-
- result["identifier"] = identifier.ToJson();
- if (doc_comment) {
- result["doc_comment"] = *doc_comment;
- }
- result["type"] = type.ToJson();
- result["access"] = AccessToString(access);
- result["offset"] = offset;
- result["is_no_unique_address"] = is_no_unique_address;
- return result;
+llvm::json::Value Field::ToJson() const {
+ return llvm::json::Object{
+ {"identifier", identifier},
+ {"doc_comment", doc_comment},
+ {"type", type},
+ {"access", AccessToString(access)},
+ {"offset", offset},
+ {"is_no_unique_address", is_no_unique_address},
+ };
}
static std::string SpecialMemberDefinitionToString(
@@ -337,125 +323,119 @@
return o << SpecialMemberDefinitionToString(definition);
}
-nlohmann::json SpecialMemberFunc::ToJson() const {
- nlohmann::json result;
- result["definition"] = SpecialMemberDefinitionToString(definition);
- result["access"] = AccessToString(access);
- return result;
+llvm::json::Value SpecialMemberFunc::ToJson() const {
+ return llvm::json::Object{
+ {"definition", SpecialMemberDefinitionToString(definition)},
+ {"access", AccessToString(access)},
+ };
}
-nlohmann::json BaseClass::ToJson() const {
- nlohmann::json base;
- base["base_record_id"] = base_record_id.value();
- if (offset.has_value()) {
- base["offset"] = *offset;
- }
- return base;
-}
-nlohmann::json Record::ToJson() const {
- nlohmann::json record;
- record["rs_name"] = rs_name;
- record["cc_name"] = cc_name;
- record["id"] = id.value();
- record["owning_target"] = owning_target.value();
- if (doc_comment) {
- record["doc_comment"] = *doc_comment;
- }
- record["unambiguous_public_bases"] = VectorToJson(unambiguous_public_bases);
- record["fields"] = VectorToJson(fields);
- record["lifetime_params"] = VectorToJson(lifetime_params);
- record["size"] = size;
- record["alignment"] = alignment;
- if (base_size) {
- record["base_size"] = *base_size;
- }
- record["override_alignment"] = override_alignment;
- record["copy_constructor"] = copy_constructor.ToJson();
- record["move_constructor"] = move_constructor.ToJson();
- record["destructor"] = destructor.ToJson();
- record["is_trivial_abi"] = is_trivial_abi;
- record["is_final"] = is_final;
-
- nlohmann::json item;
- item["Record"] = std::move(record);
- return item;
+llvm::json::Value BaseClass::ToJson() const {
+ return llvm::json::Object{
+ {"base_record_id", base_record_id},
+ {"offset", offset},
+ };
}
-nlohmann::json Enumerator::ToJson() const {
- nlohmann::json result;
- result["identifier"] = identifier.ToJson();
- result["value"] = value.ToJson();
- return result;
+llvm::json::Value Record::ToJson() const {
+ llvm::json::Object record{
+ {"rs_name", rs_name},
+ {"cc_name", cc_name},
+ {"id", id},
+ {"owning_target", owning_target},
+ {"doc_comment", doc_comment},
+ {"unambiguous_public_bases", unambiguous_public_bases},
+ {"fields", fields},
+ {"lifetime_params", lifetime_params},
+ {"size", size},
+ {"alignment", alignment},
+ {"base_size", base_size},
+ {"override_alignment", override_alignment},
+ {"copy_constructor", copy_constructor},
+ {"move_constructor", move_constructor},
+ {"destructor", destructor},
+ {"is_trivial_abi", is_trivial_abi},
+ {"is_final", is_final},
+ };
+
+ return llvm::json::Object{
+ {"Record", std::move(record)},
+ };
}
-nlohmann::json Enum::ToJson() const {
- nlohmann::json enum_ir;
- enum_ir["identifier"] = identifier.ToJson();
- enum_ir["id"] = id.value();
- enum_ir["owning_target"] = owning_target.value();
- enum_ir["underlying_type"] = underlying_type.ToJson();
- enum_ir["enumerators"] = VectorToJson(enumerators);
-
- nlohmann::json item;
- item["Enum"] = std::move(enum_ir);
- return item;
+llvm::json::Value Enumerator::ToJson() const {
+ return llvm::json::Object{
+ {"identifier", identifier},
+ {"value", value},
+ };
}
-nlohmann::json TypeAlias::ToJson() const {
- nlohmann::json type_alias;
- type_alias["identifier"] = identifier.ToJson();
- type_alias["id"] = id.value();
- type_alias["owning_target"] = owning_target.value();
- if (doc_comment) {
- type_alias["doc_comment"] = *doc_comment;
- }
- type_alias["underlying_type"] = underlying_type.ToJson();
+llvm::json::Value Enum::ToJson() const {
+ llvm::json::Object enum_ir{
+ {"identifier", identifier}, {"id", id},
+ {"owning_target", owning_target}, {"underlying_type", underlying_type},
+ {"enumerators", enumerators},
+ };
- nlohmann::json item;
- item["TypeAlias"] = std::move(type_alias);
- return item;
+ return llvm::json::Object{
+ {"Enum", std::move(enum_ir)},
+ };
}
-nlohmann::json SourceLoc::ToJson() const {
- nlohmann::json source_loc;
- source_loc["filename"] = filename;
- source_loc["line"] = line;
- source_loc["column"] = column;
- return source_loc;
+llvm::json::Value TypeAlias::ToJson() const {
+ llvm::json::Object type_alias{
+ {"identifier", identifier}, {"id", id},
+ {"owning_target", owning_target}, {"doc_comment", doc_comment},
+ {"underlying_type", underlying_type},
+ };
+
+ return llvm::json::Object{
+ {"TypeAlias", std::move(type_alias)},
+ };
}
-nlohmann::json UnsupportedItem::ToJson() const {
- nlohmann::json unsupported;
- unsupported["name"] = name;
- unsupported["message"] = message;
- unsupported["source_loc"] = source_loc.ToJson();
-
- nlohmann::json item;
- item["UnsupportedItem"] = std::move(unsupported);
- return item;
+llvm::json::Value SourceLoc::ToJson() const {
+ return llvm::json::Object{
+ {"filename", filename},
+ {"line", line},
+ {"column", column},
+ };
}
-nlohmann::json Comment::ToJson() const {
- nlohmann::json comment;
- comment["text"] = text;
+llvm::json::Value UnsupportedItem::ToJson() const {
+ llvm::json::Object unsupported{
+ {"name", name},
+ {"message", message},
+ {"source_loc", source_loc},
+ };
- nlohmann::json item;
- item["Comment"] = std::move(comment);
- return item;
+ return llvm::json::Object{
+ {"UnsupportedItem", std::move(unsupported)},
+ };
}
-nlohmann::json IR::ToJson() const {
- std::vector<nlohmann::json> json_items;
+llvm::json::Value Comment::ToJson() const {
+ llvm::json::Object comment{
+ {"text", text},
+ };
+
+ return llvm::json::Object{
+ {"Comment", std::move(comment)},
+ };
+}
+
+llvm::json::Value IR::ToJson() const {
+ std::vector<llvm::json::Value> json_items;
json_items.reserve(items.size());
for (const auto& item : items) {
std::visit([&](auto&& item) { json_items.push_back(item.ToJson()); }, item);
}
- nlohmann::json result;
- result["used_headers"] = VectorToJson(used_headers);
- result["current_target"] = current_target.value();
- result["items"] = std::move(json_items);
- return result;
+ return llvm::json::Object{
+ {"used_headers", used_headers},
+ {"current_target", current_target},
+ {"items", std::move(json_items)},
+ };
}
} // namespace rs_bindings_from_cc
diff --git a/rs_bindings_from_cc/ir.h b/rs_bindings_from_cc/ir.h
index 9f43088..159d9d2 100644
--- a/rs_bindings_from_cc/ir.h
+++ b/rs_bindings_from_cc/ir.h
@@ -25,8 +25,10 @@
#include "base/logging.h"
#include "third_party/absl/strings/string_view.h"
#include "rs_bindings_from_cc/bazel_types.h"
-#include "third_party/json/src/json.hpp"
#include "third_party/llvm/llvm-project/llvm/include/llvm/ADT/APSInt.h"
+#include "third_party/llvm/llvm-project/llvm/include/llvm/ADT/Optional.h"
+#include "third_party/llvm/llvm-project/llvm/include/llvm/Support/FormatVariadic.h"
+#include "third_party/llvm/llvm-project/llvm/include/llvm/Support/JSON.h"
#include "util/intops/strong_int.h"
namespace rs_bindings_from_cc {
@@ -50,7 +52,7 @@
absl::string_view IncludePath() const { return name_; }
- nlohmann::json ToJson() const;
+ llvm::json::Value ToJson() const;
template <typename H>
friend H AbslHashValue(H h, const HeaderName& header_name) {
@@ -68,7 +70,7 @@
}
inline std::ostream& operator<<(std::ostream& o, const HeaderName& h) {
- return o << std::setw(internal::kJsonIndent) << h.ToJson();
+ return o << std::string(llvm::formatv("{0:2}", h.ToJson()));
}
// An int uniquely representing a Decl. Since our IR goes through the JSON
@@ -82,7 +84,7 @@
// A lifetime.
struct Lifetime {
- nlohmann::json ToJson() const;
+ llvm::json::Value ToJson() const;
// Lifetime name. Unlike syn::Lifetime, this does not include the apostrophe.
//
@@ -95,13 +97,13 @@
};
inline std::ostream& operator<<(std::ostream& o, const Lifetime& l) {
- return o << std::setw(internal::kJsonIndent) << l.ToJson();
+ return o << std::string(llvm::formatv("{0:2}", l.ToJson()));
}
// A C++ type involved in the bindings. It has the knowledge of how the type
// is spelled in C++.
struct CcType {
- nlohmann::json ToJson() const;
+ llvm::json::Value ToJson() const;
// The name of the type. Examples:
// - "int32_t", "std::ptrdiff_t", "long long", "bool"
@@ -114,8 +116,9 @@
std::string name;
// Id of a decl that this type corresponds to. `nullopt` when `name` is
- // non-empty.
- std::optional<DeclId> decl_id = std::nullopt;
+ // non-empty. `llvm::Optional` is used because it integrates better with
+ // `llvm::json` library than `std::optional`.
+ llvm::Optional<DeclId> decl_id;
// The C++ const-qualification for the type.
//
@@ -135,7 +138,7 @@
// A Rust type involved in the bindings. It has the knowledge of how the type
// is spelled in Rust.
struct RsType {
- nlohmann::json ToJson() const;
+ llvm::json::Value ToJson() const;
// The name of the type. Examples:
// - "i32" or "bool"
@@ -152,8 +155,9 @@
std::string name;
// Id of a decl that this type corresponds to. `nullopt` when `name` is
- // non-empty.
- std::optional<DeclId> decl_id = std::nullopt;
+ // non-empty. `llvm::Optional` is used because it integrates better with
+ // `llvm::json` library than `std::optional`.
+ llvm::Optional<DeclId> decl_id;
// Lifetime arguments for a generic type. Examples:
// *mut i32 has no lifetime arguments
@@ -173,7 +177,7 @@
};
inline std::ostream& operator<<(std::ostream& o, const RsType& type) {
- return o << std::setw(internal::kJsonIndent) << type.ToJson();
+ return o << std::string(llvm::formatv("{0:2}", type.ToJson()));
}
// A type involved in the bindings. The rs_type and cc_type will be treated
@@ -215,14 +219,14 @@
bool IsVoid() const { return rs_type.name == "()"; }
- nlohmann::json ToJson() const;
+ llvm::json::Value ToJson() const;
RsType rs_type;
CcType cc_type;
};
inline std::ostream& operator<<(std::ostream& o, const MappedType& type) {
- return o << std::setw(internal::kJsonIndent) << type.ToJson();
+ return o << std::string(llvm::formatv("{0:2}", type.ToJson()));
}
// An identifier involved in bindings.
@@ -248,7 +252,7 @@
absl::string_view Ident() const { return identifier_; }
- nlohmann::json ToJson() const;
+ llvm::json::Value ToJson() const;
private:
std::string identifier_;
@@ -272,7 +276,7 @@
IntegerConstant(const IntegerConstant& other) = default;
IntegerConstant& operator=(const IntegerConstant& other) = default;
- nlohmann::json ToJson() const;
+ llvm::json::Value ToJson() const;
private:
// value < 0
@@ -290,7 +294,7 @@
absl::string_view Name() const { return name_; }
- nlohmann::json ToJson() const;
+ llvm::json::Value ToJson() const;
private:
std::string name_;
@@ -309,14 +313,14 @@
// FuncParam of a C++ function `void Foo(int32_t a);` will be
// `FuncParam{.type=Type{"i32", "int32_t"}, .identifier=Identifier("foo"))`.
struct FuncParam {
- nlohmann::json ToJson() const;
+ llvm::json::Value ToJson() const;
MappedType type;
Identifier identifier;
};
inline std::ostream& operator<<(std::ostream& o, const FuncParam& param) {
- return o << std::setw(internal::kJsonIndent) << param.ToJson();
+ return o << std::string(llvm::formatv("{0:2}", param.ToJson()));
}
enum SpecialName {
@@ -333,7 +337,7 @@
// them differently. After all, they are not invoked or defined like normal
// functions.
using UnqualifiedIdentifier = std::variant<Identifier, Operator, SpecialName>;
-nlohmann::json ToJson(const UnqualifiedIdentifier& unqualified_identifier);
+llvm::json::Value toJSON(const UnqualifiedIdentifier& unqualified_identifier);
struct MemberFuncMetadata {
enum ReferenceQualification : char {
@@ -347,6 +351,8 @@
// constructors and 2) `is_const` and `is_virtual` never applies to
// constructors.
struct InstanceMethodMetadata {
+ llvm::json::Value ToJson() const;
+
ReferenceQualification reference = kUnqualified;
bool is_const = false;
bool is_virtual = false;
@@ -355,7 +361,7 @@
bool is_explicit_ctor = false;
};
- nlohmann::json ToJson() const;
+ llvm::json::Value ToJson() const;
// The type that this is a member function for.
DeclId record_id;
@@ -363,12 +369,15 @@
// Qualifiers for the instance method.
//
// If null, this is a static method.
- std::optional<InstanceMethodMetadata> instance_method_metadata;
+ //
+ // `llvm::Optional` is used because it integrates better with `llvm::json`
+ // library than `std::optional`.
+ llvm::Optional<InstanceMethodMetadata> instance_method_metadata;
};
// Source code location
struct SourceLoc {
- nlohmann::json ToJson() const;
+ llvm::json::Value ToJson() const;
std::string filename;
uint64 line;
@@ -376,28 +385,28 @@
};
inline std::ostream& operator<<(std::ostream& o, const SourceLoc& r) {
- return o << std::setw(internal::kJsonIndent) << r.ToJson();
+ return o << std::string(llvm::formatv("{0:2}", r.ToJson()));
}
// A function involved in the bindings.
struct Func {
- nlohmann::json ToJson() const;
+ llvm::json::Value ToJson() const;
UnqualifiedIdentifier name;
BlazeLabel owning_target;
- std::optional<std::string> doc_comment;
+ llvm::Optional<std::string> doc_comment;
std::string mangled_name;
MappedType return_type;
std::vector<FuncParam> params;
std::vector<Lifetime> lifetime_params;
bool is_inline;
// If null, this is not a member function.
- std::optional<MemberFuncMetadata> member_func_metadata;
+ llvm::Optional<MemberFuncMetadata> member_func_metadata;
SourceLoc source_loc;
};
inline std::ostream& operator<<(std::ostream& o, const Func& f) {
- return o << std::setw(internal::kJsonIndent) << f.ToJson();
+ return o << std::string(llvm::formatv("{0:2}", f.ToJson()));
}
// Access specifier for a member or base class.
@@ -411,10 +420,10 @@
// A field (non-static member variable) of a record.
struct Field {
- nlohmann::json ToJson() const;
+ llvm::json::Value ToJson() const;
Identifier identifier;
- std::optional<std::string> doc_comment;
+ llvm::Optional<std::string> doc_comment;
MappedType type;
AccessSpecifier access;
// Field offset in bits.
@@ -424,7 +433,7 @@
};
inline std::ostream& operator<<(std::ostream& o, const Field& f) {
- return o << std::setw(internal::kJsonIndent) << f.ToJson();
+ return o << std::string(llvm::formatv("{0:2}", f.ToJson()));
}
// Information about special member functions.
@@ -450,7 +459,7 @@
kDeleted,
};
- nlohmann::json ToJson() const;
+ llvm::json::Value ToJson() const;
Definition definition = Definition::kTrivial;
AccessSpecifier access = AccessSpecifier::kPublic;
@@ -460,23 +469,26 @@
const SpecialMemberFunc::Definition& definition);
inline std::ostream& operator<<(std::ostream& o, const SpecialMemberFunc& f) {
- return o << std::setw(internal::kJsonIndent) << f.ToJson();
+ return o << std::string(llvm::formatv("{0:2}", f.ToJson()));
}
// A base class subobject of a struct or class.
struct BaseClass {
- nlohmann::json ToJson() const;
+ llvm::json::Value ToJson() const;
DeclId base_record_id;
// The offset the base class subobject is located at. This is always nonempty
// for nonvirtual inheritance, and always empty if a virtual base class is
// anywhere in the inheritance chain.
- std::optional<int64_t> offset;
+ //
+ // `llvm::Optional` is used because it integrates better with `llvm::json`
+ // library than `std::optional`.
+ llvm::Optional<int64_t> offset;
};
// A record (struct, class, union).
struct Record {
- nlohmann::json ToJson() const;
+ llvm::json::Value ToJson() const;
// `rs_name` and `cc_name` are typically equal, but they may be different for
// template instantiations (when `cc_name` is similar to `MyStruct<int>` and
@@ -486,7 +498,7 @@
DeclId id;
BlazeLabel owning_target;
- std::optional<std::string> doc_comment;
+ llvm::Optional<std::string> doc_comment;
std::vector<BaseClass> unambiguous_public_bases;
std::vector<Field> fields;
std::vector<Lifetime> lifetime_params;
@@ -497,7 +509,10 @@
// The size of the base class subobjects, or null if there are none.
//
// More information: docs/struct_layout
- std::optional<size_t> base_size = std::nullopt;
+ //
+ // `llvm::Optional` is used because it integrates better with `llvm::json`
+ // library than `std::optional`.
+ llvm::Optional<size_t> base_size;
// True if the alignment may differ from what the fields would imply.
//
@@ -532,14 +547,14 @@
};
struct Enumerator {
- nlohmann::json ToJson() const;
+ llvm::json::Value ToJson() const;
Identifier identifier;
IntegerConstant value;
};
struct Enum {
- nlohmann::json ToJson() const;
+ llvm::json::Value ToJson() const;
Identifier identifier;
DeclId id;
@@ -549,27 +564,27 @@
};
inline std::ostream& operator<<(std::ostream& o, const Record& r) {
- return o << std::setw(internal::kJsonIndent) << r.ToJson();
+ return o << std::string(llvm::formatv("{0:2}", r.ToJson()));
}
// A type alias (defined either using `typedef` or `using`).
struct TypeAlias {
- nlohmann::json ToJson() const;
+ llvm::json::Value ToJson() const;
Identifier identifier;
DeclId id;
BlazeLabel owning_target;
- std::optional<std::string> doc_comment;
+ llvm::Optional<std::string> doc_comment;
MappedType underlying_type;
};
inline std::ostream& operator<<(std::ostream& o, const TypeAlias& t) {
- return o << std::setw(internal::kJsonIndent) << t.ToJson();
+ return o << std::string(llvm::formatv("{0:2}", t.ToJson()));
}
// A placeholder for an item that we can't generate bindings for (yet)
struct UnsupportedItem {
- nlohmann::json ToJson() const;
+ llvm::json::Value ToJson() const;
// TODO(forster): We could show the original declaration in the generated
// message (potentially also for successfully imported items).
@@ -584,23 +599,23 @@
};
inline std::ostream& operator<<(std::ostream& o, const UnsupportedItem& r) {
- return o << std::setw(internal::kJsonIndent) << r.ToJson();
+ return o << std::string(llvm::formatv("{0:2}", r.ToJson()));
}
struct Comment {
- nlohmann::json ToJson() const;
+ llvm::json::Value ToJson() const;
std::string text;
};
inline std::ostream& operator<<(std::ostream& o, const Comment& r) {
- return o << std::setw(internal::kJsonIndent) << r.ToJson();
+ return o << std::string(llvm::formatv("{0:2}", r.ToJson()));
}
// A complete intermediate representation of bindings for publicly accessible
// declarations of a single C++ library.
struct IR {
- nlohmann::json ToJson() const;
+ llvm::json::Value ToJson() const;
template <typename T>
std::vector<const T*> get_items_if() const {
@@ -624,7 +639,7 @@
};
inline std::ostream& operator<<(std::ostream& o, const IR& ir) {
- return o << std::setw(internal::kJsonIndent) << ir.ToJson();
+ return o << std::string(llvm::formatv("{0:2}", ir.ToJson()));
}
} // namespace rs_bindings_from_cc
diff --git a/rs_bindings_from_cc/json_from_cc.cc b/rs_bindings_from_cc/json_from_cc.cc
index 7909cd3..b1df4a4 100644
--- a/rs_bindings_from_cc/json_from_cc.cc
+++ b/rs_bindings_from_cc/json_from_cc.cc
@@ -10,7 +10,9 @@
#include "rs_bindings_from_cc/ffi_types.h"
#include "rs_bindings_from_cc/ir.h"
#include "rs_bindings_from_cc/ir_from_cc.h"
-#include "third_party/json/src/json.hpp"
+#include "third_party/llvm/llvm-project/llvm/include/llvm/Support/ErrorHandling.h"
+#include "third_party/llvm/llvm-project/llvm/include/llvm/Support/FormatVariadic.h"
+#include "third_party/llvm/llvm-project/llvm/include/llvm/Support/JSON.h"
namespace rs_bindings_from_cc {
@@ -37,7 +39,7 @@
// messages. If we start using this for production, then we should bridge the
// error code into Rust.
CHECK(ir.ok()) << "- IrFromCc reported an error: " << ir.status().message();
- std::string json = ir->ToJson().dump();
+ std::string json = llvm::formatv("{0}", ir->ToJson());
return AllocFfiU8SliceBox(MakeFfiU8Slice(json));
}
diff --git a/rs_bindings_from_cc/rs_bindings_from_cc.cc b/rs_bindings_from_cc/rs_bindings_from_cc.cc
index 05b2952..1060f6c 100644
--- a/rs_bindings_from_cc/rs_bindings_from_cc.cc
+++ b/rs_bindings_from_cc/rs_bindings_from_cc.cc
@@ -21,7 +21,8 @@
#include "rs_bindings_from_cc/ir.h"
#include "rs_bindings_from_cc/ir_from_cc.h"
#include "rs_bindings_from_cc/src_code_gen.h"
-#include "third_party/json/src/json.hpp"
+#include "third_party/llvm/llvm-project/llvm/include/llvm/Support/FormatVariadic.h"
+#include "third_party/llvm/llvm-project/llvm/include/llvm/Support/JSON.h"
#include "third_party/llvm/llvm-project/llvm/include/llvm/Support/raw_ostream.h"
#include "util/task/status_macros.h"
@@ -66,8 +67,8 @@
std::vector<absl::string_view>(argv, argv + argc)));
if (!cmdline.ir_out().empty()) {
- RETURN_IF_ERROR(
- SetFileContents(cmdline.ir_out(), ir.ToJson().dump(/*indent=*/2)));
+ RETURN_IF_ERROR(SetFileContents(
+ cmdline.ir_out(), std::string(llvm::formatv("{0:2}", ir.ToJson()))));
}
rs_bindings_from_cc::Bindings bindings =
diff --git a/rs_bindings_from_cc/src_code_gen.cc b/rs_bindings_from_cc/src_code_gen.cc
index 35cc9ef..893aff3 100644
--- a/rs_bindings_from_cc/src_code_gen.cc
+++ b/rs_bindings_from_cc/src_code_gen.cc
@@ -8,8 +8,9 @@
#include "rs_bindings_from_cc/ffi_types.h"
#include "rs_bindings_from_cc/ir.h"
-#include "third_party/json/src/json.hpp"
#include "third_party/llvm/llvm-project/clang/include/clang/Format/Format.h"
+#include "third_party/llvm/llvm-project/llvm/include/llvm/Support/FormatVariadic.h"
+#include "third_party/llvm/llvm-project/llvm/include/llvm/Support/JSON.h"
namespace rs_bindings_from_cc {
@@ -48,7 +49,7 @@
}
Bindings GenerateBindings(const IR& ir) {
- std::string json = ir.ToJson().dump();
+ std::string json = llvm::formatv("{0}", ir.ToJson());
FfiBindings ffi_bindings = GenerateBindingsImpl(MakeFfiU8Slice(json));
Bindings bindings = MakeBindingsFromFfiBindings(ffi_bindings);
FreeFfiBindings(ffi_bindings);