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);