C++ Code generator

PiperOrigin-RevId: 486158566
pull/13171/head
Protobuf Team Bot 2 years ago committed by Copybara-Service
parent fd14316f38
commit 306123e2e8
  1. 9
      WORKSPACE
  2. 6
      bazel/workspace_deps.bzl
  3. 2
      benchmarks/BUILD
  4. 2
      benchmarks/build_defs.bzl
  5. 98
      protos/BUILD
  6. 39
      protos/bazel/BUILD
  7. 346
      protos/bazel/upb_cc_proto_library.bzl
  8. 108
      protos/protos.cc
  9. 407
      protos/protos.h
  10. 44
      protos/protos_internal.h
  11. 55
      protos/protos_internal_test.cc
  12. 85
      protos_generator/BUILD
  13. 722
      protos_generator/gen_accessors.cc
  14. 46
      protos_generator/gen_accessors.h
  15. 126
      protos_generator/gen_enums.cc
  16. 44
      protos_generator/gen_enums.h
  17. 110
      protos_generator/gen_extensions.cc
  18. 49
      protos_generator/gen_extensions.h
  19. 380
      protos_generator/gen_messages.cc
  20. 47
      protos_generator/gen_messages.h
  21. 203
      protos_generator/gen_utils.cc
  22. 81
      protos_generator/gen_utils.h
  23. 85
      protos_generator/output.cc
  24. 172
      protos_generator/output.h
  25. 306
      protos_generator/protoc-gen-upb-protos.cc
  26. 118
      protos_generator/tests/BUILD
  27. 19
      protos_generator/tests/child_model.proto
  28. 10
      protos_generator/tests/legacy-name.proto
  29. 8
      protos_generator/tests/no_package.proto
  30. 10
      protos_generator/tests/test_enum.proto
  31. 12
      protos_generator/tests/test_extension.proto
  32. 582
      protos_generator/tests/test_generated.cc
  33. 149
      protos_generator/tests/test_model.proto
  34. 8
      upbc/BUILD
  35. 2
      upbc/protoc-gen-upb.cc

@ -52,6 +52,15 @@ http_archive(
urls = ["https://github.com/bazelbuild/rules_fuzzing/archive/v0.3.2.zip"],
)
http_archive(
name = "com_google_absl",
sha256 = "e7fdfe0bed87702a22c5b73b6b5fe08bedd25f17d617e52df6061b0f47d480b0",
strip_prefix = "abseil-cpp-e6044634dd7caec2d79a13aecc9e765023768757",
urls = [
"https://github.com/abseil/abseil-cpp/archive/e6044634dd7caec2d79a13aecc9e765023768757.tar.gz"
],
)
load("@rules_fuzzing//fuzzing:repositories.bzl", "rules_fuzzing_dependencies")
rules_fuzzing_dependencies()

@ -15,9 +15,9 @@ def upb_deps():
maybe(
http_archive,
name = "com_google_absl",
url = "https://github.com/abseil/abseil-cpp/archive/b9b925341f9e90f5e7aa0cf23f036c29c7e454eb.zip",
strip_prefix = "abseil-cpp-b9b925341f9e90f5e7aa0cf23f036c29c7e454eb",
sha256 = "bb2a0b57c92b6666e8acb00f4cbbfce6ddb87e83625fb851b0e78db581340617",
url = "https://github.com/abseil/abseil-cpp/archive/e6044634dd7caec2d79a13aecc9e765023768757.tar.gz",
strip_prefix = "abseil-cpp-e6044634dd7caec2d79a13aecc9e765023768757",
sha256 = "e7fdfe0bed87702a22c5b73b6b5fe08bedd25f17d617e52df6061b0f47d480b0",
)
maybe(

@ -24,7 +24,7 @@
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# begin:google_only
# load("//tools/build_defs/proto/cpp:cc_proto_library.bzl", "cc_proto_library")
# load("@rules_cc//cc:defs.bzl", "cc_proto_library")
# end:google_only
load(

@ -24,7 +24,7 @@
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# begin:google_only
# load("//tools/build_defs/proto/cpp:cc_proto_library.bzl", _cc_proto_library = "cc_proto_library")
# load("@rules_cc//cc:defs.bzl", _cc_proto_library = "cc_proto_library")
#
# _is_google3 = True
# end:google_only

@ -0,0 +1,98 @@
# Copyright (c) 2009-2021, Google LLC
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# * Neither the name of Google LLC nor the
# names of its contributors may be used to endorse or promote products
# derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
load(
"//bazel:build_defs.bzl",
"UPB_DEFAULT_CPPOPTS",
)
load(
"//protos/bazel:upb_cc_proto_library.bzl",
"upb_cc_proto_library_copts",
)
licenses(["notice"])
cc_library(
name = "protos",
srcs = ["protos.cc"],
hdrs = ["protos.h"],
copts = UPB_DEFAULT_CPPOPTS,
visibility = ["//visibility:public"],
deps = [
"//:mini_table",
"//:upb",
"@com_google_absl//absl/status",
"@com_google_absl//absl/status:statusor",
"@com_google_absl//absl/strings:str_format",
],
)
cc_library(
name = "protos_internal",
hdrs = ["protos_internal.h"],
copts = UPB_DEFAULT_CPPOPTS,
visibility = ["//visibility:public"],
deps = [
":protos",
"//:mini_table",
"//:upb",
"@com_google_absl//absl/status",
"@com_google_absl//absl/status:statusor",
"@com_google_absl//absl/strings:str_format",
],
)
# Common support code for C++ generated code.
cc_library(
name = "generated_protos_support__only_for_generated_code_do_not_use__i_give_permission_to_break_me",
hdrs = [
"protos_internal.h",
],
copts = UPB_DEFAULT_CPPOPTS,
visibility = ["//visibility:public"],
deps = [
":protos",
":protos_internal",
],
)
cc_test(
name = "protos_internal_test",
srcs = ["protos_internal_test.cc"],
copts = UPB_DEFAULT_CPPOPTS,
deps = [
":protos_internal",
"//:upb",
"//protos_generator/tests:test_model_upb_cc_proto",
"//protos_generator/tests:test_model_upb_proto",
"@com_google_googletest//:gtest_main",
],
)
upb_cc_proto_library_copts(
name = "upb_cc_proto_library_copts__for_generated_code_only_do_not_use",
copts = UPB_DEFAULT_CPPOPTS,
visibility = ["//visibility:public"],
)

@ -0,0 +1,39 @@
# Copyright (c) 2009-2021, Google LLC
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# * Neither the name of Google LLC nor the
# names of its contributors may be used to endorse or promote products
# derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
licenses(["notice"])
bzl_library(
name = "upb_cc_proto_library_bzl",
srcs = ["upb_cc_proto_library.bzl"],
visibility = ["//visibility:public"],
deps = [
"@bazel_skylib//lib:paths",
"//bazel:upb_proto_library_bzl",
"@bazel_tools//tools/cpp:toolchain_utils.bzl",
],
)

@ -0,0 +1,346 @@
# Copyright (c) 2009-2021, Google LLC
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# * Neither the name of Google LLC nor the
# names of its contributors may be used to endorse or promote products
# derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""Public rules for using upb protos:
- upb_cc_proto_library()
"""
load("@bazel_skylib//lib:paths.bzl", "paths")
load("//bazel:upb_proto_library.bzl", "GeneratedSrcsInfo", "UpbWrappedCcInfo", "UpbWrappedGeneratedSrcsInfo", "upb_proto_library_aspect")
# begin:google_only
# load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain", "use_cpp_toolchain")
#
# end:google_only
# begin:github_only
# Compatibility code for Bazel 4.x. Remove this when we drop support for Bazel 4.x.
load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain")
def use_cpp_toolchain():
return ["@bazel_tools//tools/cpp:toolchain_type"]
# end:github_only
# Generic support code #########################################################
# begin:github_only
_is_google3 = False
# end:github_only
# begin:google_only
# _is_google3 = True
# end:google_only
def _get_real_short_path(file):
# For some reason, files from other archives have short paths that look like:
# ../com_google_protobuf/google/protobuf/descriptor.proto
short_path = file.short_path
if short_path.startswith("../"):
second_slash = short_path.index("/", 3)
short_path = short_path[second_slash + 1:]
# Sometimes it has another few prefixes like:
# _virtual_imports/any_proto/google/protobuf/any.proto
# benchmarks/_virtual_imports/100_msgs_proto/benchmarks/100_msgs.proto
# We want just google/protobuf/any.proto.
virtual_imports = "_virtual_imports/"
if virtual_imports in short_path:
short_path = short_path.split(virtual_imports)[1].split("/", 1)[1]
return short_path
def _get_real_root(file):
real_short_path = _get_real_short_path(file)
return file.path[:-len(real_short_path) - 1]
def _generate_output_file(ctx, src, extension):
real_short_path = _get_real_short_path(src)
real_short_path = paths.relativize(real_short_path, ctx.label.package)
output_filename = paths.replace_extension(real_short_path, extension)
ret = ctx.actions.declare_file(output_filename)
return ret
def _filter_none(elems):
out = []
for elem in elems:
if elem:
out.append(elem)
return out
def _cc_library_func(ctx, name, hdrs, srcs, copts, dep_ccinfos):
"""Like cc_library(), but callable from rules.
Args:
ctx: Rule context.
name: Unique name used to generate output files.
hdrs: Public headers that can be #included from other rules.
srcs: C/C++ source files.
copts: Additional options for cc compilation.
dep_ccinfos: CcInfo providers of dependencies we should build/link against.
Returns:
CcInfo provider for this compilation.
"""
compilation_contexts = [info.compilation_context for info in dep_ccinfos]
linking_contexts = [info.linking_context for info in dep_ccinfos]
toolchain = find_cpp_toolchain(ctx)
feature_configuration = cc_common.configure_features(
ctx = ctx,
cc_toolchain = toolchain,
requested_features = ctx.features,
unsupported_features = ctx.disabled_features,
)
blaze_only_args = {}
if _is_google3:
blaze_only_args["grep_includes"] = ctx.file._grep_includes
(compilation_context, compilation_outputs) = cc_common.compile(
actions = ctx.actions,
feature_configuration = feature_configuration,
cc_toolchain = toolchain,
name = name,
srcs = srcs,
public_hdrs = hdrs,
user_compile_flags = copts,
compilation_contexts = compilation_contexts,
**blaze_only_args
)
# buildifier: disable=unused-variable
(linking_context, linking_outputs) = cc_common.create_linking_context_from_compilation_outputs(
actions = ctx.actions,
name = name,
feature_configuration = feature_configuration,
cc_toolchain = toolchain,
compilation_outputs = compilation_outputs,
linking_contexts = linking_contexts,
**blaze_only_args
)
return CcInfo(
compilation_context = compilation_context,
linking_context = linking_context,
)
# Build setting for whether fasttable code generation is enabled ###############
FastTableEnabledInfo = provider(
"Provides fasttable configuration to compiler",
fields = {
"enabled": "whether fasttable is enabled",
},
)
def fasttable_enabled_impl(ctx):
raw_setting = ctx.build_setting_value
if raw_setting:
# TODO(haberman): check that the target CPU supports fasttable.
pass
return FastTableEnabledInfo(enabled = raw_setting)
upb_fasttable_enabled = rule(
implementation = fasttable_enabled_impl,
build_setting = config.bool(flag = True),
)
# Dummy rule to expose select() copts to aspects ##############################
UpbCcProtoLibraryCoptsInfo = provider(
"Provides copts for upb cc proto targets",
fields = {
"copts": "copts for upb_cc_proto_library()",
},
)
def upb_cc_proto_library_copts_impl(ctx):
return UpbCcProtoLibraryCoptsInfo(copts = ctx.attr.copts)
upb_cc_proto_library_copts = rule(
implementation = upb_cc_proto_library_copts_impl,
attrs = {"copts": attr.string_list(default = [])},
)
_UpbCcWrappedCcInfo = provider("Provider for cc_info for protos", fields = ["cc_info"])
_WrappedCcGeneratedSrcsInfo = provider("Provider for generated sources", fields = ["srcs"])
def _compile_upb_cc_protos(ctx, generator, proto_info, proto_sources):
if len(proto_sources) == 0:
return GeneratedSrcsInfo(srcs = [], hdrs = [])
tool = getattr(ctx.executable, "_gen_" + generator)
srcs = [_generate_output_file(ctx, name, ".upb.proto.cc") for name in proto_sources]
hdrs = [_generate_output_file(ctx, name, ".upb.proto.h") for name in proto_sources]
hdrs += [_generate_output_file(ctx, name, ".upb.fwd.h") for name in proto_sources]
transitive_sets = proto_info.transitive_descriptor_sets.to_list()
fasttable_enabled = (hasattr(ctx.attr, "_fasttable_enabled") and
ctx.attr._fasttable_enabled[FastTableEnabledInfo].enabled)
codegen_params = "fasttable:" if fasttable_enabled else ""
ctx.actions.run(
inputs = depset(
direct = [proto_info.direct_descriptor_set],
transitive = [proto_info.transitive_descriptor_sets],
),
tools = [tool],
outputs = srcs + hdrs,
executable = ctx.executable._protoc,
arguments = [
"--" + generator + "_out=" + codegen_params + _get_real_root(srcs[0]),
"--plugin=protoc-gen-" + generator + "=" + tool.path,
"--descriptor_set_in=" + ctx.configuration.host_path_separator.join([f.path for f in transitive_sets]),
] +
[_get_real_short_path(file) for file in proto_sources],
progress_message = "Generating upb cc protos for :" + ctx.label.name,
)
return GeneratedSrcsInfo(srcs = srcs, hdrs = hdrs)
def _upb_cc_proto_rule_impl(ctx):
if len(ctx.attr.deps) != 1:
fail("only one deps dependency allowed.")
dep = ctx.attr.deps[0]
if _WrappedCcGeneratedSrcsInfo in dep:
srcs = dep[_WrappedCcGeneratedSrcsInfo].srcs
elif UpbWrappedGeneratedSrcsInfo in dep:
srcs = dep[UpbWrappedGeneratedSrcsInfo].srcs
else:
fail("proto_library rule must generate UpbWrappedGeneratedSrcsInfo or " +
"_WrappedCcGeneratedSrcsInfo (aspect should have handled this).")
if _UpbCcWrappedCcInfo in dep:
cc_info = dep[_UpbCcWrappedCcInfo].cc_info
elif UpbWrappedCcInfo in dep:
cc_info = dep[UpbWrappedCcInfo].cc_info
else:
fail("proto_library rule must generate UpbWrappedCcInfo or " +
"_UpbCcWrappedCcInfo (aspect should have handled this).")
lib = cc_info.linking_context.linker_inputs.to_list()[0].libraries[0]
files = _filter_none([
lib.static_library,
lib.pic_static_library,
lib.dynamic_library,
])
return [
DefaultInfo(files = depset(files + srcs.hdrs + srcs.srcs)),
srcs,
cc_info,
]
def _upb_cc_proto_aspect_impl(target, ctx, generator, cc_provider, file_provider):
proto_info = target[ProtoInfo]
files = _compile_upb_cc_protos(ctx, generator, proto_info, proto_info.direct_sources)
deps = ctx.rule.attr.deps + getattr(ctx.attr, "_" + generator)
dep_ccinfos = [dep[CcInfo] for dep in deps if CcInfo in dep]
dep_ccinfos += [dep[UpbWrappedCcInfo].cc_info for dep in deps if UpbWrappedCcInfo in dep]
dep_ccinfos += [dep[_UpbCcWrappedCcInfo].cc_info for dep in deps if _UpbCcWrappedCcInfo in dep]
if UpbWrappedCcInfo not in target:
fail("Target should have UpbWrappedCcInfo provider")
dep_ccinfos.append(target[UpbWrappedCcInfo].cc_info)
cc_info = _cc_library_func(
ctx = ctx,
name = ctx.rule.attr.name + "." + generator,
hdrs = files.hdrs,
srcs = files.srcs,
copts = ctx.attr._ccopts[UpbCcProtoLibraryCoptsInfo].copts,
dep_ccinfos = dep_ccinfos,
)
return [cc_provider(cc_info = cc_info), file_provider(srcs = files)]
def _upb_cc_proto_library_aspect_impl(target, ctx):
return _upb_cc_proto_aspect_impl(target, ctx, "upbprotos", _UpbCcWrappedCcInfo, _WrappedCcGeneratedSrcsInfo)
def _maybe_add(d):
if _is_google3:
d["_grep_includes"] = attr.label(
allow_single_file = True,
cfg = "exec",
default = "@bazel_tools//tools/cpp:grep-includes",
)
return d
_upb_cc_proto_library_aspect = aspect(
attrs = _maybe_add({
"_ccopts": attr.label(
default = "//protos:upb_cc_proto_library_copts__for_generated_code_only_do_not_use",
),
"_gen_upbprotos": attr.label(
executable = True,
cfg = "exec",
default = "//protos_generator:protoc-gen-upb-protos",
),
"_protoc": attr.label(
executable = True,
cfg = "exec",
default = "@com_google_protobuf//:protoc",
),
"_cc_toolchain": attr.label(
default = "@bazel_tools//tools/cpp:current_cc_toolchain",
),
"_upbprotos": attr.label_list(
default = [
# TODO: Add dependencies for cc runtime (absl/string etc..)
"//:generated_cpp_support__only_for_generated_code_do_not_use__i_give_permission_to_break_me",
"//protos:generated_protos_support__only_for_generated_code_do_not_use__i_give_permission_to_break_me",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/status:statusor",
"//protos",
],
),
}),
implementation = _upb_cc_proto_library_aspect_impl,
provides = [
_UpbCcWrappedCcInfo,
_WrappedCcGeneratedSrcsInfo,
],
required_aspect_providers = [
UpbWrappedCcInfo,
UpbWrappedGeneratedSrcsInfo,
],
attr_aspects = ["deps"],
fragments = ["cpp"],
toolchains = use_cpp_toolchain(),
incompatible_use_toolchain_transition = True,
)
upb_cc_proto_library = rule(
output_to_genfiles = True,
implementation = _upb_cc_proto_rule_impl,
attrs = {
"deps": attr.label_list(
aspects = [
upb_proto_library_aspect,
_upb_cc_proto_library_aspect,
],
allow_rules = ["proto_library"],
providers = [ProtoInfo],
),
"_ccopts": attr.label(
default = "//protos:upb_cc_proto_library_copts__for_generated_code_only_do_not_use",
),
},
)

@ -0,0 +1,108 @@
/*
* Copyright (c) 2009-2021, Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Google LLC nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "protos/protos.h"
#include "absl/strings/str_format.h"
namespace protos {
// begin:google_only
// absl::Status MessageAllocationError(SourceLocation loc) {
// return absl::Status(absl::StatusCode::kInternal,
// "Upb message allocation error", loc);
// }
//
// absl::Status ExtensionNotFoundError(int extension_number, SourceLocation loc) {
// return absl::Status(
// absl::StatusCode::kInternal,
// absl::StrFormat("Extension %d not found", extension_number), loc);
// }
//
// absl::Status MessageEncodeError(upb_EncodeStatus status, SourceLocation loc) {
// return absl::Status(absl::StatusCode::kInternal,
// absl::StrFormat("Upb message encoding error %d", status),
// loc
//
// );
// }
//
// absl::Status MessageDecodeError(upb_DecodeStatus status, SourceLocation loc
//
// ) {
// return absl::Status(absl::StatusCode::kInternal,
// absl::StrFormat("Upb message parse error %d", status), loc
//
// );
// }
// end:google_only
// begin:github_only
absl::Status MessageAllocationError(SourceLocation loc) {
return absl::Status(absl::StatusCode::kUnknown,
"Upb message allocation error");
}
absl::Status ExtensionNotFoundError(int ext_number, SourceLocation loc) {
return absl::Status(absl::StatusCode::kUnknown,
absl::StrFormat("Extension %d not found", ext_number));
}
absl::Status MessageEncodeError(upb_EncodeStatus s, SourceLocation loc) {
return absl::Status(absl::StatusCode::kUnknown, "Encoding error");
}
absl::Status MessageDecodeError(upb_DecodeStatus status, SourceLocation loc
) {
return absl::Status(absl::StatusCode::kUnknown, "Upb message parse error");
}
// end:github_only
namespace internal {
upb_ExtensionRegistry* GetUpbExtensions(
const ExtensionRegistry& extension_registry) {
return extension_registry.registry_;
}
absl::StatusOr<absl::string_view> Serialize(const upb_Message* message,
const upb_MiniTable* mini_table,
upb_Arena* arena, int options) {
size_t len;
char* ptr;
upb_EncodeStatus status =
upb_Encode(message, mini_table, options, arena, &ptr, &len);
if (status == kUpb_EncodeStatus_Ok) {
return absl::string_view(ptr, len);
}
return MessageEncodeError(status);
}
} // namespace internal
} // namespace protos

@ -0,0 +1,407 @@
/*
* Copyright (c) 2009-2021, Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Google LLC nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef UPB_PROTOS_PROTOS_H_
#define UPB_PROTOS_PROTOS_H_
#include <type_traits>
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "upb/decode.h"
#include "upb/encode.h"
#include "upb/mini_table.h"
#include "upb/upb.hpp"
namespace protos {
using Arena = ::upb::Arena;
class ExtensionRegistry;
template <typename T>
using Proxy = std::conditional_t<std::is_const<T>::value,
typename std::remove_const_t<T>::CProxy,
typename T::Proxy>;
// Provides convenient access to Proxy and CProxy message types.
//
// Using rebinding and handling of const, Ptr<Message> and Ptr<const Message>
// allows copying const with T* const and avoids using non-copyable Proxy types
// directly.
template <typename T>
class Ptr final {
public:
Ptr() = delete;
// Implicit conversions
Ptr(T* m) : p_(m) {} // NOLINT
Ptr(const Proxy<T>* p) : p_(*p) {} // NOLINT
Ptr(Proxy<T> p) : p_(p) {} // NOLINT
Ptr(const Ptr& m) = default;
Ptr& operator=(Ptr v) & {
Proxy<T>::Rebind(p_, v.p_);
return *this;
}
Proxy<T> operator*() const { return p_; }
Proxy<T>* operator->() const {
return const_cast<Proxy<T>*>(std::addressof(p_));
}
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wclass-conversion"
#endif
template <typename U = T, std::enable_if_t<!std::is_const<U>::value, int> = 0>
operator Ptr<const T>() const {
Proxy<const T> p(p_);
return Ptr<const T>(&p);
}
#ifdef __clang__
#pragma clang diagnostic pop
#endif
private:
Ptr(void* msg, upb_Arena* arena) : p_(msg, arena) {} // NOLINT
friend class Ptr<const T>;
friend typename T::Access;
Proxy<T> p_;
};
inline absl::string_view UpbStrToStringView(upb_StringView str) {
return absl::string_view(str.data, str.size);
}
// TODO: update bzl and move to upb runtime / protos.cc.
inline upb_StringView UpbStrFromStringView(absl::string_view str,
upb_Arena* arena) {
upb_alloc* alloc = upb_Arena_Alloc(arena);
const size_t str_size = str.size();
char* buffer = static_cast<char*>(upb_malloc(alloc, str_size));
memcpy(buffer, str.data(), str_size);
return upb_StringView_FromDataAndSize(buffer, str_size);
}
template <typename T>
typename T::Proxy CreateMessage(::protos::Arena& arena) {
return typename T::Proxy(upb_Message_New(T::minitable(), arena.ptr()),
arena.ptr());
}
// begin:github_only
// This type exists to work around an absl type that has not yet been
// released.
struct SourceLocation {
static SourceLocation current() { return {}; }
absl::string_view file_name() { return "<unknown>"; }
int line() { return 0; }
};
// end:github_only
// begin:google_only
// using SourceLocation = absl::SourceLocation;
// end:google_only
absl::Status MessageAllocationError(
SourceLocation loc = SourceLocation::current());
absl::Status ExtensionNotFoundError(
int extension_number, SourceLocation loc = SourceLocation::current());
absl::Status MessageDecodeError(upb_DecodeStatus status,
SourceLocation loc = SourceLocation::current());
absl::Status MessageEncodeError(upb_EncodeStatus status,
SourceLocation loc = SourceLocation::current());
namespace internal {
template <typename T>
T CreateMessage() {
return T();
}
template <typename T>
typename T::Proxy CreateMessageProxy(void* msg, upb_Arena* arena) {
return typename T::Proxy(msg, arena);
}
template <typename T>
typename T::CProxy CreateMessage(upb_Message* msg) {
return typename T::CProxy(msg);
}
class ExtensionMiniTableProvider {
public:
ExtensionMiniTableProvider(const upb_MiniTable_Extension* mini_table_ext)
: mini_table_ext_(mini_table_ext) {}
const upb_MiniTable_Extension* mini_table_ext() const {
return mini_table_ext_;
}
private:
const upb_MiniTable_Extension* mini_table_ext_;
};
// -------------------------------------------------------------------
// ExtensionIdentifier
// This is the type of actual extension objects. E.g. if you have:
// extend Foo {
// optional MyExtension bar = 1234;
// }
// then "bar" will be defined in C++ as:
// ExtensionIdentifier<Foo, MyExtension> bar(&namespace_bar_ext);
template <typename ExtendeeType, typename ExtensionType>
class ExtensionIdentifier : public ExtensionMiniTableProvider {
public:
using Extension = ExtensionType;
using Extendee = ExtendeeType;
ExtensionIdentifier(const upb_MiniTable_Extension* mini_table_ext)
: ExtensionMiniTableProvider(mini_table_ext) {}
};
template <typename T>
void* GetInternalMsg(const T& message) {
return message.msg();
}
template <typename T>
void* GetInternalMsg(const Ptr<T>& message) {
return message->msg();
}
template <typename T>
upb_Arena* GetArena(const T& message) {
return static_cast<upb_Arena*>(message.GetInternalArena());
}
template <typename T>
upb_Arena* GetArena(const Ptr<T>& message) {
return static_cast<upb_Arena*>(message->GetInternalArena());
}
upb_ExtensionRegistry* GetUpbExtensions(
const ExtensionRegistry& extension_registry);
absl::StatusOr<absl::string_view> Serialize(const upb_Message* message,
const upb_MiniTable* mini_table,
upb_Arena* arena, int options);
} // namespace internal
class ExtensionRegistry {
public:
ExtensionRegistry(
const std::vector<const ::protos::internal::ExtensionMiniTableProvider*>
extensions,
const upb::Arena& arena)
: registry_(upb_ExtensionRegistry_New(arena.ptr())) {
if (registry_) {
for (const auto& ext_provider : extensions) {
const auto* ext = ext_provider->mini_table_ext();
bool success = upb_ExtensionRegistry_AddArray(registry_, &ext, 1);
if (!success) {
registry_ = nullptr;
break;
}
}
}
}
private:
friend upb_ExtensionRegistry* ::protos::internal::GetUpbExtensions(
const ExtensionRegistry& extension_registry);
upb_ExtensionRegistry* registry_;
};
template <typename T>
using EnableIfProtosClass = std::enable_if_t<
std::is_base_of<typename T::Access, T>::value &&
std::is_base_of<typename T::Access, typename T::ExtendableType>::value>;
template <typename T>
using EnableIfMutableProto = std::enable_if_t<!std::is_const<T>::value>;
template <typename T, typename Extendee, typename Extension,
typename = EnableIfProtosClass<T>>
bool HasExtension(
const T& message,
const ::protos::internal::ExtensionIdentifier<Extendee, Extension>& id) {
return _upb_Message_Getext(message.msg(), id.mini_table_ext()) != nullptr;
}
template <typename T, typename Extendee, typename Extension,
typename = EnableIfProtosClass<T>>
bool HasExtension(
const Ptr<T>& message,
const ::protos::internal::ExtensionIdentifier<Extendee, Extension>& id) {
return _upb_Message_Getext(message->msg(), id.mini_table_ext()) != nullptr;
}
template <typename T, typename Extendee, typename Extension,
typename = EnableIfProtosClass<T>, typename = EnableIfMutableProto<T>>
void ClearExtension(
const Ptr<T>& message,
const ::protos::internal::ExtensionIdentifier<Extendee, Extension>& id) {
_upb_Message_Clearext(message->msg(), id.mini_table_ext());
}
template <typename T, typename Extendee, typename Extension,
typename = EnableIfProtosClass<T>>
void ClearExtension(
const T& message,
const ::protos::internal::ExtensionIdentifier<Extendee, Extension>& id) {
_upb_Message_Clearext(message.msg(), id.mini_table_ext());
}
template <typename T, typename Extendee, typename Extension,
typename = EnableIfProtosClass<T>>
absl::Status SetExtension(
const T& message,
const ::protos::internal::ExtensionIdentifier<Extendee, Extension>& id,
Extension& value) {
auto* message_arena = static_cast<upb_Arena*>(message.GetInternalArena());
upb_Message_Extension* msg_ext = _upb_Message_GetOrCreateExtension(
message.msg(), id.mini_table_ext(), message_arena);
if (!msg_ext) {
return MessageAllocationError();
}
auto* extension_arena = static_cast<upb_Arena*>(value.GetInternalArena());
if (message_arena != extension_arena) {
upb_Arena_Fuse(message_arena, extension_arena);
}
msg_ext->data.ptr = value.msg();
return absl::OkStatus();
}
template <typename T, typename Extendee, typename Extension,
typename = EnableIfProtosClass<T>, typename = EnableIfMutableProto<T>>
absl::Status SetExtension(
const Ptr<T>& message,
const ::protos::internal::ExtensionIdentifier<Extendee, Extension>& id,
Extension& value) {
auto* message_arena = static_cast<upb_Arena*>(message->GetInternalArena());
upb_Message_Extension* msg_ext = _upb_Message_GetOrCreateExtension(
message->msg(), id.mini_table_ext(), message_arena);
if (!msg_ext) {
return MessageAllocationError();
}
auto* extension_arena = static_cast<upb_Arena*>(message->GetInternalArena());
if (message_arena != extension_arena) {
upb_Arena_Fuse(message_arena, extension_arena);
}
msg_ext->data.ptr = ::protos::internal::GetInternalMsg(value);
return absl::OkStatus();
}
template <typename T, typename Extendee, typename Extension,
typename = EnableIfProtosClass<T>>
absl::StatusOr<Ptr<const Extension>> GetExtension(
const T& message,
const ::protos::internal::ExtensionIdentifier<Extendee, Extension>& id) {
const upb_Message_Extension* ext =
_upb_Message_Getext(message.msg(), id.mini_table_ext());
if (!ext) {
return ExtensionNotFoundError(id.mini_table_ext()->field.number);
}
return Ptr<const Extension>(
::protos::internal::CreateMessage<Extension>(ext->data.ptr));
}
template <typename T, typename Extendee, typename Extension,
typename = EnableIfProtosClass<T>>
absl::StatusOr<Ptr<const Extension>> GetExtension(
const Ptr<T>& message,
const ::protos::internal::ExtensionIdentifier<Extendee, Extension>& id) {
const upb_Message_Extension* ext =
_upb_Message_Getext(message->msg(), id.mini_table_ext());
if (!ext) {
return ExtensionNotFoundError(id.mini_table_ext()->field.number);
}
return Ptr<const Extension>(
::protos::internal::CreateMessage<Extension>(ext->data.ptr));
}
template <typename T>
bool Parse(T& message, absl::string_view bytes) {
_upb_Message_Clear(message.msg(), T::minitable());
auto* arena = static_cast<upb_Arena*>(message.GetInternalArena());
return upb_Decode(bytes.data(), bytes.size(), message.msg(), T::minitable(),
/* extreg= */ nullptr, /* options= */ 0,
arena) == kUpb_DecodeStatus_Ok;
}
template <typename T>
absl::StatusOr<T> Parse(absl::string_view bytes, int options = 0) {
T message;
auto* arena = static_cast<upb_Arena*>(message.GetInternalArena());
upb_DecodeStatus status =
upb_Decode(bytes.data(), bytes.size(), message.msg(), T::minitable(),
/* extreg= */ nullptr, /* options= */ 0, arena);
if (status == kUpb_DecodeStatus_Ok) {
return message;
}
return MessageDecodeError(status);
}
template <typename T>
absl::StatusOr<T> Parse(absl::string_view bytes,
const ::protos::ExtensionRegistry& extension_registry,
int options = 0) {
T message;
auto* arena = static_cast<upb_Arena*>(message.GetInternalArena());
upb_DecodeStatus status =
upb_Decode(bytes.data(), bytes.size(), message.msg(), T::minitable(),
::protos::internal::GetUpbExtensions(extension_registry),
/* options= */ 0, arena);
if (status == kUpb_DecodeStatus_Ok) {
return message;
}
return MessageDecodeError(status);
}
template <typename T>
absl::StatusOr<absl::string_view> Serialize(const T& message, upb::Arena& arena,
int options = 0) {
return ::protos::internal::Serialize(message.msg(), T::minitable(),
arena.ptr(), options);
}
template <typename T>
absl::StatusOr<absl::string_view> Serialize(Ptr<const T> message,
upb::Arena& arena,
int options = 0) {
return ::protos::internal::Serialize(message->msg(), T::minitable(),
arena.ptr(), options);
}
} // namespace protos
#endif // UPB_PROTOS_PROTOS_H_

@ -0,0 +1,44 @@
/*
* Copyright (c) 2009-2021, Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Google LLC nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef UPB_PROTOS_PROTOS_INTERNAL_H_
#define UPB_PROTOS_PROTOS_INTERNAL_H_
#include "protos/protos.h"
namespace protos::internal {
// Moves ownership of a message created in a source arena.
//
// Utility function to provide a way to move ownership across languages or VMs.
template <typename T>
T MoveMessage(upb_Message* msg, upb_Arena* arena) {
return T(msg, arena);
}
} // namespace protos::internal
#endif

@ -0,0 +1,55 @@
// Copyright (c) 2009-2021, Google LLC
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of Google LLC nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "protos/protos_internal.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "protos_generator/tests/test_model.upb.h"
#include "protos_generator/tests/test_model.upb.proto.h"
#include "upb/arena.h"
namespace protos::testing {
namespace {
using ::protos_generator::test::protos::TestModel;
TEST(CppGeneratedCode, InternalMoveMessage) {
// Generate message (simulating message created in another VM/language)
upb_Arena* source_arena = upb_Arena_New();
protos_generator_test_TestModel* message =
protos_generator_test_TestModel_new(source_arena);
protos_generator_test_TestModel_set_int_value_with_default(message, 123);
EXPECT_NE(message, nullptr);
// Move ownership.
TestModel model =
protos::internal::MoveMessage<TestModel>(message, source_arena);
// Now that we have moved ownership, free original arena.
upb_Arena_Free(source_arena);
EXPECT_EQ(model.int_value_with_default(), 123);
}
} // namespace
} // namespace protos::testing

@ -0,0 +1,85 @@
# Copyright (c) 2009-2021, Google LLC
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# * Neither the name of Google LLC nor the
# names of its contributors may be used to endorse or promote products
# derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
load(
"//bazel:build_defs.bzl",
"UPB_DEFAULT_CPPOPTS",
)
licenses(["notice"])
cc_binary(
name = "protoc-gen-upb-protos",
srcs = [
"protoc-gen-upb-protos.cc",
],
copts = UPB_DEFAULT_CPPOPTS,
visibility = ["//visibility:public"],
deps = [
":generator",
"//:mini_table",
"//upbc:file_layout",
"@com_google_absl//absl/base:core_headers",
"@com_google_absl//absl/container:flat_hash_map",
"@com_google_absl//absl/container:flat_hash_set",
"@com_google_absl//absl/strings",
"@com_google_protobuf//:protobuf",
"@com_google_protobuf//src/google/protobuf/compiler:code_generator",
],
)
cc_library(
name = "generator",
srcs = [
"gen_accessors.cc",
"gen_enums.cc",
"gen_extensions.cc",
"gen_messages.cc",
"gen_utils.cc",
"output.cc",
],
hdrs = [
"gen_accessors.h",
"gen_enums.h",
"gen_extensions.h",
"gen_messages.h",
"gen_utils.h",
"output.h",
],
visibility = ["//visibility:private"],
deps = [
"//upbc:common",
"//upbc:file_layout",
"//upbc:keywords",
"@com_google_absl//absl/base:log_severity",
"@com_google_absl//absl/container:flat_hash_map",
"@com_google_absl//absl/container:flat_hash_set",
"@com_google_absl//absl/log",
"@com_google_absl//absl/log:check",
"@com_google_absl//absl/strings",
"@com_google_protobuf//:protobuf",
"@com_google_protobuf//src/google/protobuf/compiler:code_generator",
],
)

@ -0,0 +1,722 @@
// Copyright (c) 2009-2021, Google LLC
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of Google LLC nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "protos_generator/gen_accessors.h"
#include "google/protobuf/descriptor.h"
#include "absl/container/flat_hash_set.h"
#include "absl/strings/match.h"
#include "absl/strings/string_view.h"
#include "protos_generator/gen_utils.h"
#include "protos_generator/output.h"
#include "upbc/file_layout.h"
#include "upbc/keywords.h"
namespace protos_generator {
namespace protobuf = ::google::protobuf;
using FileLayout = ::upbc::FileLayout;
using NameToFieldDescriptorMap =
absl::flat_hash_map<absl::string_view, const protobuf::FieldDescriptor*>;
void WriteFieldAccessorHazzer(const protobuf::Descriptor* desc,
const protobuf::FieldDescriptor* field,
const absl::string_view resolved_field_name,
const FileLayout& layout, Output& output);
void WriteFieldAccessorClear(const protobuf::Descriptor* desc,
const protobuf::FieldDescriptor* field,
const absl::string_view resolved_field_name,
const FileLayout& layout, Output& output);
void WriteMapFieldAccessors(const protobuf::Descriptor* desc,
const protobuf::FieldDescriptor* field,
const absl::string_view resolved_field_name,
Output& output);
void WriteMapAccessorDefinitions(const protobuf::Descriptor* message,
const protobuf::FieldDescriptor* field,
const absl::string_view resolved_field_name,
const absl::string_view class_name,
Output& output);
void WriteRepeatedMessageAccessor(const protobuf::Descriptor* message,
const protobuf::FieldDescriptor* field,
const absl::string_view resolved_field_name,
absl::string_view class_name, Output& output);
void WriteRepeatedStringAccessor(const protobuf::Descriptor* message,
const protobuf::FieldDescriptor* field,
const absl::string_view resolved_field_name,
const absl::string_view class_name,
Output& output);
void WriteRepeatedScalarAccessor(const protobuf::Descriptor* message,
const protobuf::FieldDescriptor* field,
const absl::string_view resolved_field_name,
absl::string_view class_name, Output& output);
// Returns C++ class member name by resolving naming conflicts across
// proto field names (such as clear_ prefixes) and keyword collisions.
//
// The Upb C generator prefixes all accessors with package and class names
// avoiding collisions. Therefore we need to use raw field names when calling
// into C accessors but need to fully resolve conflicts for C++ class members.
std::string ResolveFieldName(const protobuf::FieldDescriptor* field,
const NameToFieldDescriptorMap& field_names);
NameToFieldDescriptorMap CreateFieldNameMap(
const protobuf::Descriptor* message) {
NameToFieldDescriptorMap field_names;
for (int i = 0; i < message->field_count(); i++) {
const protobuf::FieldDescriptor* field = message->field(i);
field_names.emplace(field->name(), field);
}
return field_names;
}
void WriteFieldAccessorsInHeader(const protobuf::Descriptor* desc,
Output& output) {
FileLayout layout(desc->file());
// Generate const methods.
OutputIndenter i(output);
auto field_names = CreateFieldNameMap(desc);
for (auto field : ::upbc::FieldNumberOrder(desc)) {
std::string resolved_field_name = ResolveFieldName(field, field_names);
absl::string_view upbc_name = field->name();
WriteFieldAccessorHazzer(desc, field, resolved_field_name, layout, output);
WriteFieldAccessorClear(desc, field, resolved_field_name, layout, output);
if (field->is_map()) {
WriteMapFieldAccessors(desc, field, resolved_field_name, output);
} else if (desc->options().map_entry()) {
// TODO(b/237399867) Implement map entry
} else if (field->is_repeated()) {
output(
R"cc(
inline size_t $1_size() const {
size_t len;
$0_$2(msg_, &len);
return len;
}
inline void clear_$1() { $0_clear_$2(msg_); }
)cc",
MessageName(desc), resolved_field_name, upbc_name);
if (field->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_MESSAGE) {
output(
R"cc(
$1 $2(size_t index) const;
absl::StatusOr<$0> add_$2();
$0 mutable_$3(size_t index) const;
)cc",
MessagePtrConstType(field, /* const */ false),
MessagePtrConstType(field, /* const */ true), resolved_field_name,
upbc_name);
} else {
output(
R"cc(
$0 $1(size_t index) const;
bool add_$1($0 val);
void set_$1(size_t index, $0 val);
bool resize_$1(size_t len);
)cc",
CppConstType(field), resolved_field_name);
}
} else {
// non-repeated.
if (field->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_STRING) {
output(R"cc(
$0 $1() const;
void set_$1($0 value);
)cc",
CppConstType(field), resolved_field_name);
} else if (field->cpp_type() ==
protobuf::FieldDescriptor::CPPTYPE_MESSAGE) {
output(R"cc(
$1 $2() const;
$0 mutable_$3();
)cc",
MessagePtrConstType(field, /* const */ false),
MessagePtrConstType(field, /* const */ true),
resolved_field_name, upbc_name);
} else {
output(
R"cc(
inline $0 $1() const { return $2_$3(msg_); }
inline void set_$1($0 value) { return $2_set_$3(msg_, value); }
)cc",
CppConstType(field), resolved_field_name, MessageName(desc),
upbc_name);
}
}
}
}
void WriteFieldAccessorHazzer(const protobuf::Descriptor* desc,
const protobuf::FieldDescriptor* field,
const absl::string_view resolved_field_name,
const FileLayout& layout, Output& output) {
// Generate hazzer (if any).
if (layout.HasHasbit(field) || field->real_containing_oneof()) {
absl::string_view upbc_name = field->name();
// Has presence.
output("inline bool has_$0() const { return $1_has_$2(msg_); }\n",
resolved_field_name, MessageName(desc), upbc_name);
}
}
void WriteFieldAccessorClear(const protobuf::Descriptor* desc,
const protobuf::FieldDescriptor* field,
const absl::string_view resolved_field_name,
const FileLayout& layout, Output& output) {
if (layout.HasHasbit(field) || field->real_containing_oneof()) {
absl::string_view upbc_name = field->name();
output("void clear_$0() { $2_clear_$1(msg_); }\n", resolved_field_name,
upbc_name, MessageName(desc));
}
}
void WriteMapFieldAccessors(const protobuf::Descriptor* desc,
const protobuf::FieldDescriptor* field,
const absl::string_view resolved_field_name,
Output& output) {
const protobuf::Descriptor* entry = field->message_type();
const protobuf::FieldDescriptor* key = entry->FindFieldByNumber(1);
const protobuf::FieldDescriptor* val = entry->FindFieldByNumber(2);
absl::string_view upbc_name = field->name();
output(
R"cc(
inline size_t $0_size() const { return $1_$3_size(msg_); }
inline void clear_$0() { $1_clear_$3(msg_); }
void delete_$0($2 key);
)cc",
resolved_field_name, MessageName(desc), CppConstType(key), upbc_name);
if (val->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_MESSAGE) {
output(
R"cc(
bool set_$0($1 key, $3 value);
bool set_$0($1 key, $4 value);
absl::StatusOr<$3> get_$0($1 key);
)cc",
resolved_field_name, CppConstType(key), CppConstType(val),
MessagePtrConstType(val, /* is_const */ true),
MessagePtrConstType(val, /* is_const */ false));
} else {
output(
R"cc(
bool set_$0($1 key, $2 value);
absl::StatusOr<$2> get_$0($1 key);
)cc",
resolved_field_name, CppConstType(key), CppConstType(val));
}
}
void WriteAccessorsInSource(const protobuf::Descriptor* desc,
const FileLayout& layout, Output& output) {
std::string class_name = ClassName(desc);
absl::StrAppend(&class_name, "Access");
output("namespace internal {\n");
const char arena_expression[] = "arena_";
auto field_names = CreateFieldNameMap(desc);
// Generate const methods.
OutputIndenter i(output);
for (auto field : ::upbc::FieldNumberOrder(desc)) {
std::string resolved_field_name = ResolveFieldName(field, field_names);
if (field->is_map()) {
WriteMapAccessorDefinitions(desc, field, resolved_field_name, class_name,
output);
} else if (desc->options().map_entry()) {
// TODO(b/237399867) Implement map entry
} else if (field->is_repeated()) {
if (field->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_MESSAGE) {
WriteRepeatedMessageAccessor(desc, field, resolved_field_name,
class_name, output);
} else if (field->cpp_type() ==
protobuf::FieldDescriptor::CPPTYPE_STRING) {
WriteRepeatedStringAccessor(desc, field, resolved_field_name,
class_name, output);
} else {
WriteRepeatedScalarAccessor(desc, field, resolved_field_name,
class_name, output);
}
} else {
absl::string_view upbc_name = field->name();
// non-repeated field.
if (field->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_STRING) {
output(
R"cc(
$1 $0::$2() const {
return ::protos::UpbStrToStringView($3_$4(msg_));
}
)cc",
class_name, CppConstType(field), resolved_field_name,
MessageName(desc), upbc_name);
// Set string.
output(
R"cc(
void $0::set_$2($1 value) {
$4_set_$3(msg_, ::protos::UpbStrFromStringView(value, $5));
}
)cc",
class_name, CppConstType(field), resolved_field_name, upbc_name,
MessageName(desc), arena_expression);
} else if (field->cpp_type() ==
protobuf::FieldDescriptor::CPPTYPE_MESSAGE) {
output(
R"cc(
$1 $0::$2() const {
if (!has_$2()) {
return $4::default_instance();
}
return ::protos::internal::CreateMessage<$4>((upb_Message*)($3_$5(msg_)));
}
)cc",
class_name, MessagePtrConstType(field, /* is_const */ true),
resolved_field_name, MessageName(desc),
MessageBaseType(field, /* maybe_const */ false), upbc_name);
output(
R"cc(
$1 $0::mutable_$2() {
return ::protos::internal::CreateMessageProxy<$4>(
(upb_Message*)($3_mutable_$5(msg_, $6)), $6);
}
)cc",
class_name, MessagePtrConstType(field, /* is_const */ false),
resolved_field_name, MessageName(desc),
MessageBaseType(field, /* maybe_const */ false), upbc_name,
arena_expression);
}
}
}
output("\n");
output("} // namespace internal\n\n");
}
void WriteRepeatedMessageAccessor(const protobuf::Descriptor* message,
const protobuf::FieldDescriptor* field,
const absl::string_view resolved_field_name,
const absl::string_view class_name,
Output& output) {
const char arena_expression[] = "arena_";
absl::string_view upbc_name = field->name();
output(
R"cc(
$1 $0::$2(size_t index) const {
size_t len;
auto* ptr = $3_$5(msg_, &len);
assert(0 <= index && index < len);
return ::protos::internal::CreateMessage<$4>((upb_Message*)*(ptr + index));
}
)cc",
class_name, MessagePtrConstType(field, /* is_const */ true),
resolved_field_name, MessageName(message),
MessageBaseType(field, /* maybe_const */ false), upbc_name);
output(
R"cc(
absl::StatusOr<$1> $0::add_$2() {
auto new_msg = $3_add_$6(msg_, $5);
if (!new_msg) {
return ::protos::MessageAllocationError();
}
return ::protos::internal::CreateMessageProxy<$4>((upb_Message*)new_msg, $5);
}
)cc",
class_name, MessagePtrConstType(field, /* const */ false),
resolved_field_name, MessageName(message),
MessageBaseType(field, /* maybe_const */ false), arena_expression,
upbc_name);
output(
R"cc(
$1 $0::mutable_$2(size_t index) const {
size_t len;
auto* ptr = $3_$6(msg_, &len);
assert(0 <= index && index < len);
return ::protos::internal::CreateMessageProxy<$4>(
(upb_Message*)*(ptr + index), $5);
}
)cc",
class_name, MessagePtrConstType(field, /* is_const */ false),
resolved_field_name, MessageName(message),
MessageBaseType(field, /* maybe_const */ false), arena_expression,
upbc_name);
}
void WriteRepeatedStringAccessor(const protobuf::Descriptor* message,
const protobuf::FieldDescriptor* field,
const absl::string_view resolved_field_name,
const absl::string_view class_name,
Output& output) {
absl::string_view upbc_name = field->name();
output(
R"cc(
$1 $0::$2(size_t index) const {
size_t len;
auto* ptr = $3_mutable_$4(msg_, &len);
assert(0 <= index && index < len);
return ::protos::UpbStrToStringView(*(ptr + index));
}
)cc",
class_name, CppConstType(field), resolved_field_name,
MessageName(message), upbc_name);
output(
R"cc(
bool $0::resize_$1(size_t len) {
return $2_resize_$3(msg_, len, arena_);
}
)cc",
class_name, resolved_field_name, MessageName(message), upbc_name);
output(
R"cc(
bool $0::add_$2($1 val) {
return $3_add_$4(msg_, ::protos::UpbStrFromStringView(val, arena_), arena_);
}
)cc",
class_name, CppConstType(field), resolved_field_name,
MessageName(message), upbc_name);
output(
R"cc(
void $0::set_$2(size_t index, $1 val) {
size_t len;
auto* ptr = $3_mutable_$4(msg_, &len);
assert(0 <= index && index < len);
*(ptr + index) = ::protos::UpbStrFromStringView(val, arena_);
}
)cc",
class_name, CppConstType(field), resolved_field_name,
MessageName(message), upbc_name);
}
void WriteRepeatedScalarAccessor(const protobuf::Descriptor* message,
const protobuf::FieldDescriptor* field,
const absl::string_view resolved_field_name,
const absl::string_view class_name,
Output& output) {
absl::string_view upbc_name = field->name();
output(
R"cc(
$1 $0::$2(size_t index) const {
size_t len;
auto* ptr = $3_mutable_$4(msg_, &len);
assert(0 <= index && index < len);
return *(ptr + index);
}
)cc",
class_name, CppConstType(field), resolved_field_name,
MessageName(message), upbc_name);
output(
R"cc(
bool $0::resize_$1(size_t len) {
return $2_resize_$3(msg_, len, arena_);
}
)cc",
class_name, resolved_field_name, MessageName(message), upbc_name);
output(
R"cc(
bool $0::add_$2($1 val) { return $3_add_$4(msg_, val, arena_); }
)cc",
class_name, CppConstType(field), resolved_field_name,
MessageName(message), upbc_name);
output(
R"cc(
void $0::set_$2(size_t index, $1 val) {
size_t len;
auto* ptr = $3_mutable_$4(msg_, &len);
assert(0 <= index && index < len);
*(ptr + index) = val;
}
)cc",
class_name, CppConstType(field), resolved_field_name,
MessageName(message), upbc_name);
}
void WriteMapAccessorDefinitions(const protobuf::Descriptor* message,
const protobuf::FieldDescriptor* field,
const absl::string_view resolved_field_name,
const absl::string_view class_name,
Output& output) {
const protobuf::Descriptor* entry = field->message_type();
const protobuf::FieldDescriptor* key = entry->FindFieldByNumber(1);
const protobuf::FieldDescriptor* val = entry->FindFieldByNumber(2);
absl::string_view upbc_name = field->name();
absl::string_view converted_key_name = "key";
absl::string_view optional_conversion_code = "";
if (key->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_STRING) {
// Insert conversion from absl::string_view to upb_StringView.
// Creates upb_StringView on stack to prevent allocation.
converted_key_name = "upb_key";
optional_conversion_code =
"upb_StringView upb_key = {key.data(), key.size()};\n";
}
if (val->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_MESSAGE) {
output(
R"cc(
bool $0::set_$1($2 key, $3 value) {
$6return $4_$8_set(msg_, $7, ($5*)value->msg(), arena_);
}
)cc",
class_name, resolved_field_name, CppConstType(key),
MessagePtrConstType(val, /* is_const */ true), MessageName(message),
MessageName(val->message_type()), optional_conversion_code,
converted_key_name, upbc_name);
output(
R"cc(
bool $0::set_$1($2 key, $3 value) {
$6return $4_$8_set(msg_, $7, ($5*)value->msg(), arena_);
}
)cc",
class_name, resolved_field_name, CppConstType(key),
MessagePtrConstType(val, /* is_const */ false), MessageName(message),
MessageName(val->message_type()), optional_conversion_code,
converted_key_name, upbc_name);
output(
R"cc(
absl::StatusOr<$3> $0::get_$1($2 key) {
$5* msg_value;
$7bool success = $4_$9_get(msg_, $8, &msg_value);
if (success) {
return ::protos::internal::CreateMessage<$6>(msg_value);
}
return absl::NotFoundError("");
}
)cc",
class_name, resolved_field_name, CppConstType(key),
MessagePtrConstType(val, /* is_const */ true), MessageName(message),
MessageName(val->message_type()),
QualifiedClassName(val->message_type()), optional_conversion_code,
converted_key_name, upbc_name);
output(
R"cc(
void $0::delete_$1($2 key) { $6$4_$8_delete(msg_, $7); }
)cc",
class_name, resolved_field_name, CppConstType(key),
MessagePtrConstType(val, /* is_const */ false), MessageName(message),
MessageName(val->message_type()), optional_conversion_code,
converted_key_name, upbc_name);
} else if (val->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_STRING) {
output(
R"cc(
bool $0::set_$1($2 key, $3 value) {
$5return $4_$7_set(msg_, $6,
::protos::UpbStrFromStringView(value, arena_),
arena_);
}
)cc",
class_name, resolved_field_name, CppConstType(key), CppConstType(val),
MessageName(message), optional_conversion_code, converted_key_name,
upbc_name);
output(
R"cc(
absl::StatusOr<$3> $0::get_$1($2 key) {
upb_StringView value;
$5bool success = $4_$7_get(msg_, $6, &value);
if (success) {
return absl::string_view(value.data, value.size);
}
return absl::NotFoundError("");
}
)cc",
class_name, resolved_field_name, CppConstType(key), CppConstType(val),
MessageName(message), optional_conversion_code, converted_key_name,
upbc_name);
output(
R"cc(
void $0::delete_$1($2 key) { $5$4_$7_delete(msg_, $6); }
)cc",
class_name, resolved_field_name, CppConstType(key), CppConstType(val),
MessageName(message), optional_conversion_code, converted_key_name,
upbc_name);
} else {
output(
R"cc(
bool $0::set_$1($2 key, $3 value) {
$5return $4_$7_set(msg_, $6, value, arena_);
}
)cc",
class_name, resolved_field_name, CppConstType(key), CppConstType(val),
MessageName(message), optional_conversion_code, converted_key_name,
upbc_name);
output(
R"cc(
absl::StatusOr<$3> $0::get_$1($2 key) {
$3 value;
$5bool success = $4_$7_get(msg_, $6, &value);
if (success) {
return value;
}
return absl::NotFoundError("");
}
)cc",
class_name, resolved_field_name, CppConstType(key), CppConstType(val),
MessageName(message), optional_conversion_code, converted_key_name,
upbc_name);
output(
R"cc(
void $0::delete_$1($2 key) { $5$4_$7_delete(msg_, $6); }
)cc",
class_name, resolved_field_name, CppConstType(key), CppConstType(val),
MessageName(message), optional_conversion_code, converted_key_name,
upbc_name);
}
}
void WriteUsingAccessorsInHeader(const protobuf::Descriptor* desc,
MessageClassType handle_type, Output& output) {
FileLayout layout(desc->file());
bool read_only = handle_type == MessageClassType::kMessageCProxy;
// Generate const methods.
OutputIndenter i(output);
std::string class_name = ClassName(desc);
auto field_names = CreateFieldNameMap(desc);
for (auto field : ::upbc::FieldNumberOrder(desc)) {
std::string resolved_field_name = ResolveFieldName(field, field_names);
// Generate hazzer (if any).
if (layout.HasHasbit(field) || field->real_containing_oneof()) {
// Has presence.
output("using $0Access::has_$1;\n", class_name, resolved_field_name);
}
// Generate clear.
if (layout.HasHasbit(field) || field->real_containing_oneof()) {
output("using $0Access::clear_$1;\n", class_name, resolved_field_name);
}
if (field->is_map()) {
output(
R"cc(
using $0Access::$1_size;
using $0Access::clear_$1;
using $0Access::delete_$1;
using $0Access::get_$1;
using $0Access::set_$1;
)cc",
class_name, resolved_field_name);
} else if (desc->options().map_entry()) {
// TODO(b/237399867) Implement map entry
} else if (field->is_repeated()) {
if (field->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_MESSAGE) {
output(
R"cc(
using $0Access::$1;
using $0Access::$1_size;
using $0Access::mutable_$1;
)cc",
class_name, resolved_field_name);
if (!read_only) {
output(
R"cc(
using $0Access::add_$1;
using $0Access::clear_$1;
)cc",
class_name, resolved_field_name);
}
} else {
output(
R"cc(
using $0Access::$1;
using $0Access::$1_size;
)cc",
class_name, resolved_field_name);
if (!read_only) {
output(
R"cc(
using $0Access::add_$1;
using $0Access::clear_$1;
using $0Access::resize_$1;
using $0Access::set_$1;
)cc",
class_name, resolved_field_name);
}
}
} else {
if (field->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_MESSAGE) {
output("using $0Access::$1;\n", ClassName(desc), resolved_field_name);
if (!read_only) {
output("using $0Access::mutable_$1;\n", class_name,
resolved_field_name);
}
} else {
output("using $0Access::$1;\n", class_name, resolved_field_name);
if (!read_only) {
output("using $0Access::set_$1;\n", class_name, resolved_field_name);
}
}
}
}
output("using $0Access::msg;\n", class_name);
}
std::string ResolveFieldName(const protobuf::FieldDescriptor* field,
const NameToFieldDescriptorMap& field_names) {
// C++ implementation specific reserved names.
static const auto& kReservedNames =
*new absl::flat_hash_set<absl::string_view>({
"msg",
"msg_",
"arena",
"arena_",
});
// List of generated accessor prefixes to check against.
// Example:
// optional repeated string phase = 236;
// optional bool clear_phase = 237;
static constexpr absl::string_view kAccessorPrefixes[] = {
"clear_",
"delete_",
"add_",
"resize_",
};
absl::string_view field_name = field->name();
if (kReservedNames.count(field_name) > 0) {
if (absl::EndsWith(field_name, "_")) {
return absl::StrCat(field_name, "_");
} else {
return absl::StrCat(field_name, "__");
}
}
for (const auto prefix : kAccessorPrefixes) {
// If field name starts with a prefix such as clear_ and the proto
// contains a field name with trailing end, depending on type of field
// (repeated, map, message) we have a conflict to resolve.
if (absl::StartsWith(field_name, prefix)) {
auto match = field_names.find(field_name.substr(prefix.size()));
if (match != field_names.end()) {
const auto* candidate = match->second;
if (candidate->is_repeated() || candidate->is_map()) {
return absl::StrCat(field_name, "_");
}
}
}
}
return upbc::ResolveKeywordConflict(std::string(field_name));
}
} // namespace protos_generator

@ -0,0 +1,46 @@
// Copyright (c) 2009-2021, Google LLC
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of Google LLC nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef UPB_PROTOS_GENERATOR_ACCESSORS_H_
#define UPB_PROTOS_GENERATOR_ACCESSORS_H_
#include "google/protobuf/descriptor.h"
#include "protos_generator/gen_utils.h"
#include "protos_generator/output.h"
#include "upbc/file_layout.h"
namespace protos_generator {
namespace protobuf = ::google::protobuf;
void WriteFieldAccessorsInHeader(const protobuf::Descriptor* desc,
Output& output);
void WriteAccessorsInSource(const protobuf::Descriptor* desc,
const ::upbc::FileLayout& layout, Output& output);
void WriteUsingAccessorsInHeader(const protobuf::Descriptor* desc,
MessageClassType handle_type, Output& output);
} // namespace protos_generator
#endif // UPB_PROTOS_GENERATOR_ACCESSORS_H_

@ -0,0 +1,126 @@
// Copyright (c) 2009-2021, Google LLC
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of Google LLC nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "protos_generator/gen_enums.h"
#include "google/protobuf/descriptor.pb.h"
#include "google/protobuf/descriptor.h"
namespace protos_generator {
namespace protobuf = ::google::protobuf;
// Convert enum value to C++ literal.
//
// In C++, an value of -2147483648 gets interpreted as the negative of
// 2147483648, and since 2147483648 can't fit in an integer, this produces a
// compiler warning. This works around that issue.
std::string EnumInt32ToString(int number) {
if (number == std::numeric_limits<int32_t>::min()) {
// This needs to be special-cased, see explanation here:
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=52661
return absl::StrCat(number + 1, " - 1");
} else {
return absl::StrCat(number);
}
}
std::string EnumTypeName(const protobuf::EnumDescriptor* enum_descriptor) {
auto containing_type = enum_descriptor->containing_type();
if (containing_type == nullptr) {
// enums types with no package name are prefixed with protos_ to prevent
// conflicts with generated C headers.
if (enum_descriptor->file()->package().empty()) {
return absl::StrCat("protos_", ToCIdent(enum_descriptor->name()));
}
return ToCIdent(enum_descriptor->name());
} else {
return ToCIdent(
absl::StrCat(containing_type->name(), "_", enum_descriptor->name()));
}
}
std::string EnumValueSymbolInNameSpace(
const protobuf::EnumDescriptor* desc,
const protobuf::EnumValueDescriptor* value) {
auto containing_type = desc->containing_type();
if (containing_type != nullptr) {
return ToCIdent(absl::StrCat(containing_type->name(), "_", desc->name(),
"_", value->name()));
} else {
// protos enum values with no package name are prefixed with protos_ to
// prevent conflicts with generated C headers.
if (desc->file()->package().empty()) {
return absl::StrCat("protos_", ToCIdent(value->name()));
}
return ToCIdent(value->name());
}
}
void WriteEnumValues(const protobuf::EnumDescriptor* desc, Output& output) {
std::vector<const protobuf::EnumValueDescriptor*> values;
auto value_count = desc->value_count();
values.reserve(value_count);
for (int i = 0; i < value_count; i++) {
values.push_back(desc->value(i));
}
std::sort(values.begin(), values.end(),
[](const protobuf::EnumValueDescriptor* a,
const protobuf::EnumValueDescriptor* b) {
return a->number() < b->number();
});
for (size_t i = 0; i < values.size(); i++) {
auto value = values[i];
output(" $0", EnumValueSymbolInNameSpace(desc, value));
if (value->options().deprecated()) {
output(" ABSL_DEPRECATED(\"Proto enum $0\")",
EnumValueSymbolInNameSpace(desc, value));
}
output(" = $0", EnumInt32ToString(value->number()));
if (i != values.size() - 1) {
output(",");
}
output("\n");
}
}
void WriteEnumDeclarations(
const std::vector<const protobuf::EnumDescriptor*>& enums, Output& output) {
for (auto enumdesc : enums) {
output("enum $0 : int {\n", EnumTypeName(enumdesc));
WriteEnumValues(enumdesc, output);
output("};\n\n");
}
}
void WriteHeaderEnumForwardDecls(
std::vector<const protobuf::EnumDescriptor*>& enums, Output& output) {
for (const auto* enumdesc : enums) {
output("enum $0 : int;\n", EnumTypeName(enumdesc));
}
}
} // namespace protos_generator

@ -0,0 +1,44 @@
// Copyright (c) 2009-2021, Google LLC
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of Google LLC nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef UPB_PROTOS_GENERATOR_ENUMS_H_
#define UPB_PROTOS_GENERATOR_ENUMS_H_
#include "google/protobuf/descriptor.h"
#include "protos_generator/output.h"
namespace protos_generator {
namespace protobuf = ::google::protobuf;
std::string EnumTypeName(const protobuf::EnumDescriptor* enum_descriptor);
void WriteHeaderEnumForwardDecls(
std::vector<const protobuf::EnumDescriptor*>& enums, Output& output);
void WriteEnumDeclarations(
const std::vector<const protobuf::EnumDescriptor*>& enums, Output& output);
} // namespace protos_generator
#endif // UPB_PROTOS_GENERATOR_ENUMS_H_

@ -0,0 +1,110 @@
// Copyright (c) 2009-2021, Google LLC
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of Google LLC nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "protos_generator/gen_extensions.h"
#include "absl/strings/str_cat.h"
#include "protos_generator/gen_utils.h"
namespace protos_generator {
namespace protobuf = ::google::protobuf;
std::string ExtensionIdentifierBase(const protobuf::FieldDescriptor* ext) {
assert(ext->is_extension());
std::string ext_scope;
if (ext->extension_scope()) {
return MessageName(ext->extension_scope());
} else {
return ToCIdent(ext->file()->package());
}
}
std::string ContainingTypeName(const protobuf::FieldDescriptor* ext) {
return ext->containing_type()->file() != ext->file()
? QualifiedClassName(ext->containing_type())
: ClassName(ext->containing_type());
}
void WriteExtensionIdentifierHeader(const protobuf::FieldDescriptor* ext,
Output& output) {
std::string mini_table_name =
absl::StrCat(ExtensionIdentifierBase(ext), "_", ext->name(), "_ext");
if (ext->extension_scope()) {
output(R"cc(
static ::protos::internal::ExtensionIdentifier<$0, $1> $2;
)cc",
ContainingTypeName(ext), CppTypeParameterName(ext), ext->name());
} else {
output(
R"cc(
extern ::protos::internal::ExtensionIdentifier<$0, $1> $2;
)cc",
ContainingTypeName(ext), CppTypeParameterName(ext), ext->name());
}
}
void WriteExtensionIdentifiersHeader(
const std::vector<const protobuf::FieldDescriptor*>& extensions,
Output& output) {
for (const auto* ext : extensions) {
if (!ext->extension_scope()) {
WriteExtensionIdentifierHeader(ext, output);
}
}
}
void WriteExtensionIdentifier(const protobuf::FieldDescriptor* ext,
Output& output) {
std::string mini_table_name =
absl::StrCat(ExtensionIdentifierBase(ext), "_", ext->name(), "_ext");
if (ext->extension_scope()) {
output(
R"cc(
::protos::internal::ExtensionIdentifier<$0, $3> $4::$2(&$1);
)cc",
ContainingTypeName(ext), mini_table_name, ext->name(),
CppTypeParameterName(ext), ClassName(ext->extension_scope()));
} else {
output(
R"cc(
::protos::internal::ExtensionIdentifier<$0, $3> $2(&$1);
)cc",
ContainingTypeName(ext), mini_table_name, ext->name(),
CppTypeParameterName(ext));
}
}
void WriteExtensionIdentifiers(
const std::vector<const protobuf::FieldDescriptor*>& extensions,
Output& output) {
for (const auto* ext : extensions) {
if (!ext->extension_scope()) {
WriteExtensionIdentifier(ext, output);
}
}
}
} // namespace protos_generator

@ -0,0 +1,49 @@
// Copyright (c) 2009-2021, Google LLC
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of Google LLC nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef UPB_PROTOS_GENERATOR_GEN_EXTENSIONS_H_
#define UPB_PROTOS_GENERATOR_GEN_EXTENSIONS_H_
#include "google/protobuf/descriptor.h"
#include "protos_generator/output.h"
namespace protos_generator {
namespace protobuf = ::google::protobuf;
void WriteExtensionIdentifiersHeader(
const std::vector<const protobuf::FieldDescriptor*>& extensions,
Output& output);
void WriteExtensionIdentifierHeader(const protobuf::FieldDescriptor* ext,
Output& output);
void WriteExtensionIdentifiers(
const std::vector<const protobuf::FieldDescriptor*>& extensions,
Output& output);
void WriteExtensionIdentifier(const protobuf::FieldDescriptor* ext,
Output& output);
} // namespace protos_generator
#endif // UPB_PROTOS_GENERATOR_GEN_EXTENSIONS_H_

@ -0,0 +1,380 @@
/*
* Copyright (c) 2009-2021, Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Google LLC nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "protos_generator/gen_messages.h"
#include "google/protobuf/descriptor.pb.h"
#include "google/protobuf/descriptor.h"
#include "protos_generator/gen_accessors.h"
#include "protos_generator/gen_extensions.h"
#include "protos_generator/gen_utils.h"
#include "protos_generator/output.h"
#include "upbc/common.h"
#include "upbc/file_layout.h"
namespace protos_generator {
namespace protobuf = ::google::protobuf;
void WriteModelAccessDeclaration(const protobuf::Descriptor* descriptor,
Output& output);
void WriteModelPublicDeclaration(
const protobuf::Descriptor* descriptor,
const std::vector<const protobuf::FieldDescriptor*>& file_exts,
Output& output);
void WriteExtensionIdentifiersInClassHeader(
const protobuf::Descriptor* message,
const std::vector<const protobuf::FieldDescriptor*>& file_exts,
Output& output);
void WriteModelProxyDeclaration(const protobuf::Descriptor* descriptor,
Output& output);
void WriteModelCProxyDeclaration(const protobuf::Descriptor* descriptor,
Output& output);
void WriteInternalForwardDeclarationsInHeader(
const protobuf::Descriptor* message, Output& output);
void WriteDefaultInstanceHeader(const protobuf::Descriptor* message,
Output& output);
void WriteExtensionIdentifiersImplementation(
const protobuf::Descriptor* message,
const std::vector<const protobuf::FieldDescriptor*>& file_exts,
Output& output);
// Writes message class declarations into .upb.proto.h.
//
// For each proto Foo, FooAccess and FooProxy/FooCProxy are generated
// that are exposed to users as Foo , Ptr<Foo> and Ptr<const Foo>.
void WriteMessageClassDeclarations(
const protobuf::Descriptor* descriptor,
const std::vector<const protobuf::FieldDescriptor*>& file_exts,
Output& output) {
if (IsMapEntryMessage(descriptor)) {
// Skip map entry generation. Low level accessors for maps are
// generated that don't require a separate map type.
return;
}
// Forward declaration of Proto Class for GCC handling of free friend method.
output("class $0;", ClassName(descriptor));
output("namespace internal {\n");
WriteModelAccessDeclaration(descriptor, output);
output("\n");
WriteInternalForwardDeclarationsInHeader(descriptor, output);
output("\n");
output("} // namespace internal\n");
WriteModelPublicDeclaration(descriptor, file_exts, output);
output("namespace internal {\n");
WriteModelProxyDeclaration(descriptor, output);
WriteModelCProxyDeclaration(descriptor, output);
output("} // namespace internal\n");
}
void WriteModelAccessDeclaration(const protobuf::Descriptor* descriptor,
Output& output) {
output(
R"cc(
class $0Access {
public:
$0Access() {}
$0Access($1* msg, upb_Arena* arena) : msg_(msg), arena_(arena) {} // NOLINT
$0Access(const $1* msg, upb_Arena* arena)
: msg_(const_cast<$1*>(msg)), arena_(arena) {} // NOLINT
void* GetInternalArena() const { return arena_; }
)cc",
ClassName(descriptor), MessageName(descriptor));
WriteFieldAccessorsInHeader(descriptor, output);
output.Indent();
output(
R"cc(
private:
void* msg() const { return msg_; }
friend class $2;
friend class $0Proxy;
friend class $0CProxy;
friend void* ::protos::internal::GetInternalMsg<$2>(const $2& message);
friend void* ::protos::internal::GetInternalMsg<$2>(
const ::protos::Ptr<$2>& message);
$1* msg_;
upb_Arena* arena_;
)cc",
ClassName(descriptor), MessageName(descriptor),
QualifiedClassName(descriptor));
output.Outdent();
output("};\n");
}
void WriteModelPublicDeclaration(
const protobuf::Descriptor* descriptor,
const std::vector<const protobuf::FieldDescriptor*>& file_exts,
Output& output) {
output(
R"cc(
class $0 final : private internal::$0Access {
public:
using Access = internal::$0Access;
using Proxy = internal::$0Proxy;
using CProxy = internal::$0CProxy;
$0();
$0(const $0& m) = delete;
$0& operator=(const $0& m) = delete;
$0($0&& m)
: Access(m.msg_, m.arena_),
owned_arena_(std::move(m.owned_arena_)) {}
$0& operator=($0&& m) {
msg_ = m.msg_;
arena_ = m.arena_;
m.msg_ = nullptr;
m.arena_ = nullptr;
owned_arena_ = std::move(m.owned_arena_);
return *this;
}
)cc",
ClassName(descriptor));
WriteUsingAccessorsInHeader(descriptor, MessageClassType::kMessage, output);
WriteDefaultInstanceHeader(descriptor, output);
WriteExtensionIdentifiersInClassHeader(descriptor, file_exts, output);
output.Indent();
output.Indent();
if (descriptor->extension_range_count()) {
// for typetrait checking
output("using ExtendableType = $0;\n", ClassName(descriptor));
}
// Note: free function friends that are templates such as ::protos::Parse
// require explicit <$2> type parameter in declaration to be able to compile
// with gcc otherwise the compiler will fail with
// "has not been declared within namespace" error. Even though there is a
// namespace qualifier, cross namespace matching fails.
output(
R"cc(
static const upb_MiniTable* minitable();
using $0Access::GetInternalArena;
private:
$0(upb_Message* msg, upb_Arena* arena) : $0Access() {
msg_ = ($1*)msg;
arena_ = owned_arena_.ptr();
upb_Arena_Fuse(arena_, arena);
}
::protos::Arena owned_arena_;
friend Proxy;
friend CProxy;
friend absl::StatusOr<$2>(::protos::Parse<$2>(absl::string_view bytes,
int options));
friend absl::StatusOr<$2>(::protos::Parse<$2>(
absl::string_view bytes,
const ::protos::ExtensionRegistry& extension_registry,
int options));
friend upb_Arena* ::protos::internal::GetArena<$0>(const $0& message);
friend upb_Arena* ::protos::internal::GetArena<$0>(
const ::protos::Ptr<$0>& message);
friend $0(::protos::internal::MoveMessage<$0>(upb_Message* msg,
upb_Arena* arena));
)cc",
ClassName(descriptor), MessageName(descriptor),
QualifiedClassName(descriptor));
output.Outdent();
output("};\n\n");
}
void WriteModelProxyDeclaration(const protobuf::Descriptor* descriptor,
Output& output) {
// Foo::Proxy.
output(
R"cc(
class $0Proxy final : private internal::$0Access {
public:
$0Proxy() = delete;
$0Proxy(const $0Proxy& m) : internal::$0Access() {
msg_ = m.msg_;
arena_ = m.arena_;
}
$0Proxy operator=(const $0Proxy& m) {
msg_ = m.msg_;
arena_ = m.arena_;
return *this;
}
using $0Access::GetInternalArena;
)cc",
ClassName(descriptor));
WriteUsingAccessorsInHeader(descriptor, MessageClassType::kMessageProxy,
output);
output("\n");
output.Indent(1);
output(
R"cc(
private:
$0Proxy(void* msg, upb_Arena* arena) : internal::$0Access(($1*)msg, arena) {}
friend $0::Proxy(::protos::CreateMessage<$0>(::protos::Arena& arena));
friend $0::Proxy(::protos::internal::CreateMessageProxy<$0>(
upb_Message*, upb_Arena*));
friend class $0CProxy;
friend class $0Access;
friend class ::protos::Ptr<$0>;
friend class ::protos::Ptr<const $0>;
friend upb_Arena* ::protos::internal::GetArena<$2>(const $2& message);
friend upb_Arena* ::protos::internal::GetArena<$2>(
const ::protos::Ptr<$2>& message);
static void Rebind($0Proxy& lhs, const $0Proxy& rhs) {
lhs.msg_ = rhs.msg_;
lhs.arena_ = rhs.arena_;
}
)cc",
ClassName(descriptor), MessageName(descriptor),
QualifiedClassName(descriptor));
output.Outdent(1);
output("};\n\n");
}
void WriteModelCProxyDeclaration(const protobuf::Descriptor* descriptor,
Output& output) {
// Foo::CProxy.
output(
R"cc(
class $0CProxy final : private internal::$0Access {
public:
$0CProxy() = delete;
$0CProxy(const $0* m) : internal::$0Access(m->msg_, nullptr) {}
using $0Access::GetInternalArena;
)cc",
ClassName(descriptor), MessageName(descriptor));
WriteUsingAccessorsInHeader(descriptor, MessageClassType::kMessageProxy,
output);
output.Indent(1);
output(
R"cc(
private:
$0CProxy(void* msg) : internal::$0Access(($1*)msg, nullptr){};
friend $0::CProxy(::protos::internal::CreateMessage<$0>(upb_Message* msg));
friend class ::protos::Ptr<$0>;
friend class ::protos::Ptr<const $0>;
static void Rebind($0CProxy& lhs, const $0CProxy& rhs) {
lhs.msg_ = rhs.msg_;
lhs.arena_ = rhs.arena_;
}
)cc",
ClassName(descriptor), MessageName(descriptor));
output.Outdent(1);
output("};\n\n");
}
void WriteDefaultInstanceHeader(const protobuf::Descriptor* message,
Output& output) {
output(" static ::protos::Ptr<const $0> default_instance();\n",
ClassName(message));
}
void WriteMessageImplementation(
const protobuf::Descriptor* descriptor,
const std::vector<const protobuf::FieldDescriptor*>& file_exts,
Output& output) {
bool message_is_map_entry = descriptor->options().map_entry();
if (!message_is_map_entry) {
// Constructor.
output(
R"cc(
$0::$0() : $0Access() {
arena_ = owned_arena_.ptr();
msg_ = $1_new(arena_);
}
)cc",
ClassName(descriptor), MessageName(descriptor));
// Minitable
OutputIndenter i(output);
output(
R"cc(
const upb_MiniTable* $0::minitable() { return &$1; }
)cc",
ClassName(descriptor), ::upbc::MessageInit(descriptor));
}
::upbc::FileLayout layout(descriptor->file());
WriteAccessorsInSource(descriptor, layout, output);
if (!message_is_map_entry) {
output(
R"cc(
struct $0DefaultTypeInternal {
$1* msg;
};
$0DefaultTypeInternal _$0_default_instance_ =
$0DefaultTypeInternal{$1_new(upb_Arena_New())};
)cc",
ClassName(descriptor), MessageName(descriptor));
output(
R"cc(
::protos::Ptr<const $0> $0::default_instance() {
return ::protos::internal::CreateMessage<$0>(
(upb_Message *)_$0_default_instance_.msg);
}
)cc",
ClassName(descriptor));
}
}
void WriteInternalForwardDeclarationsInHeader(
const protobuf::Descriptor* message, Output& output) {
// Write declaration for internal re-usable default_instance without
// leaking implementation.
output(
R"cc(
struct $0DefaultTypeInternal;
extern $0DefaultTypeInternal _$0_default_instance_;
)cc",
ClassName(message));
}
void WriteExtensionIdentifiersInClassHeader(
const protobuf::Descriptor* message,
const std::vector<const protobuf::FieldDescriptor*>& file_exts,
Output& output) {
for (auto* ext : file_exts) {
if (ext->extension_scope() &&
ext->extension_scope()->full_name() == message->full_name()) {
WriteExtensionIdentifierHeader(ext, output);
}
}
}
void WriteExtensionIdentifiersImplementation(
const protobuf::Descriptor* message,
const std::vector<const protobuf::FieldDescriptor*>& file_exts,
Output& output) {
for (auto* ext : file_exts) {
if (ext->extension_scope() &&
ext->extension_scope()->full_name() == message->full_name()) {
WriteExtensionIdentifier(ext, output);
}
}
}
} // namespace protos_generator

@ -0,0 +1,47 @@
/*
* Copyright (c) 2009-2021, Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Google LLC nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef UPB_PROTOS_GENERATOR_GEN_MESSAGES_H_
#define UPB_PROTOS_GENERATOR_GEN_MESSAGES_H_
#include "google/protobuf/descriptor.h"
#include "protos_generator/output.h"
namespace protos_generator {
namespace protobuf = ::google::protobuf;
void WriteMessageClassDeclarations(
const protobuf::Descriptor* descriptor,
const std::vector<const protobuf::FieldDescriptor*>& file_exts,
Output& output);
void WriteMessageImplementation(
const protobuf::Descriptor* descriptor,
const std::vector<const protobuf::FieldDescriptor*>& file_exts,
Output& output);
} // namespace protos_generator
#endif // UPB_PROTOS_GENERATOR_GEN_MESSAGES_H_

@ -0,0 +1,203 @@
/*
* Copyright (c) 2009-2021, Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Google LLC nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "protos_generator/gen_utils.h"
#include <string>
#include "absl/strings/str_cat.h"
// begin:google_only
// #include "absl/log/check.h"
// #include "absl/strings/str_replace.h"
// end:google_only
#include "absl/strings/str_split.h"
#include "upbc/keywords.h"
namespace protos_generator {
namespace protobuf = ::google::protobuf;
// begin:github_only
#ifndef DCHECK
#ifndef NDEBUG
#define DCHECK(condition) if(!(condition)) LOG(FATAL);
#else
#define DCHECK(condition) if(!(true || condition)) LOG(FATAL);
#endif
#endif
// end:github_only
std::string DotsToColons(const std::string& name) {
return absl::StrReplaceAll(name, {{".", "::"}});
}
std::string Namespace(const std::string& package) {
if (package.empty()) return "";
return "::" + DotsToColons(package);
}
// Return the qualified C++ name for a file level symbol.
std::string QualifiedFileLevelSymbol(const protobuf::FileDescriptor* file,
const std::string& name) {
if (file->package().empty()) {
return absl::StrCat("::", name);
}
// Append ::protos postfix to package name.
return absl::StrCat(Namespace(file->package()), "::protos::", name);
}
std::string ClassName(const protobuf::Descriptor* descriptor) {
const protobuf::Descriptor* parent = descriptor->containing_type();
std::string res;
if (parent) res += ClassName(parent) + "_";
absl::StrAppend(&res, descriptor->name());
return ::upbc::ResolveKeywordConflict(res);
}
std::string QualifiedClassName(const protobuf::Descriptor* descriptor) {
return QualifiedFileLevelSymbol(descriptor->file(), ClassName(descriptor));
}
std::string QualifiedInternalClassName(const protobuf::Descriptor* descriptor) {
return QualifiedFileLevelSymbol(
descriptor->file(), absl::StrCat("internal::", ClassName(descriptor)));
}
std::string CppSourceFilename(const google::protobuf::FileDescriptor* file) {
return StripExtension(file->name()) + ".upb.proto.cc";
}
std::string UpbCFilename(const google::protobuf::FileDescriptor* file) {
return StripExtension(file->name()) + ".upb.h";
}
std::string ForwardingHeaderFilename(const google::protobuf::FileDescriptor* file) {
return StripExtension(file->name()) + ".upb.fwd.h";
}
std::string CppHeaderFilename(const google::protobuf::FileDescriptor* file) {
return StripExtension(file->name()) + ".upb.proto.h";
}
std::string NamespaceFromPackageName(absl::string_view package_name) {
return absl::StrCat(absl::StrReplaceAll(package_name, {{".", "::"}}),
"::protos");
}
void WriteStartNamespace(const protobuf::FileDescriptor* file, Output& output) {
// Skip namespace generation if package name is not specified.
if (file->package().empty()) {
return;
}
output("namespace $0 {\n\n", NamespaceFromPackageName(file->package()));
}
void WriteEndNamespace(const protobuf::FileDescriptor* file, Output& output) {
if (file->package().empty()) {
return;
}
output("} // namespace $0\n\n", NamespaceFromPackageName(file->package()));
}
std::string CppTypeInternal(const protobuf::FieldDescriptor* field,
bool is_const, bool is_type_parameter) {
std::string maybe_const = is_const ? "const " : "";
switch (field->cpp_type()) {
case protobuf::FieldDescriptor::CPPTYPE_MESSAGE: {
if (is_type_parameter) {
return absl::StrCat(maybe_const,
QualifiedClassName(field->message_type()));
} else {
return absl::StrCat(maybe_const,
QualifiedClassName(field->message_type()), "*");
}
}
case protobuf::FieldDescriptor::CPPTYPE_BOOL:
return "bool";
case protobuf::FieldDescriptor::CPPTYPE_FLOAT:
return "float";
case protobuf::FieldDescriptor::CPPTYPE_INT32:
case protobuf::FieldDescriptor::CPPTYPE_ENUM:
return "int32_t";
case protobuf::FieldDescriptor::CPPTYPE_UINT32:
return "uint32_t";
case protobuf::FieldDescriptor::CPPTYPE_DOUBLE:
return "double";
case protobuf::FieldDescriptor::CPPTYPE_INT64:
return "int64_t";
case protobuf::FieldDescriptor::CPPTYPE_UINT64:
return "uint64_t";
case protobuf::FieldDescriptor::CPPTYPE_STRING:
return "absl::string_view";
default:
LOG(FATAL) << "Unexpected type: " << field->cpp_type();
}
}
std::string CppConstType(const protobuf::FieldDescriptor* field) {
return CppTypeInternal(field, /* is_const= */ true,
/* is_type_parameter= */ false);
}
std::string CppTypeParameterName(const protobuf::FieldDescriptor* field) {
return CppTypeInternal(field, /* is_const= */ false,
/* is_type_parameter= */ true);
}
std::string MessageBaseType(const protobuf::FieldDescriptor* field,
bool is_const) {
DCHECK(field->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_MESSAGE);
std::string maybe_const = is_const ? "const " : "";
return maybe_const + QualifiedClassName(field->message_type());
}
std::string MessagePtrConstType(const protobuf::FieldDescriptor* field,
bool is_const) {
DCHECK(field->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_MESSAGE);
std::string maybe_const = is_const ? "const " : "";
return "::protos::Ptr<" + maybe_const +
QualifiedClassName(field->message_type()) + ">";
}
std::string MessageCProxyType(const protobuf::FieldDescriptor* field,
bool is_const) {
DCHECK(field->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_MESSAGE);
std::string maybe_const = is_const ? "const " : "";
return maybe_const + QualifiedInternalClassName(field->message_type()) +
"CProxy";
}
std::string MessageProxyType(const protobuf::FieldDescriptor* field,
bool is_const) {
DCHECK(field->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_MESSAGE);
std::string maybe_const = is_const ? "const " : "";
return maybe_const + QualifiedInternalClassName(field->message_type()) +
"Proxy";
}
} // namespace protos_generator

@ -0,0 +1,81 @@
/*
* Copyright (c) 2009-2021, Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Google LLC nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef UPB_PROTOS_GENERATOR_GEN_UTILS_H_
#define UPB_PROTOS_GENERATOR_GEN_UTILS_H_
#include "google/protobuf/compiler/code_generator.h"
#include "google/protobuf/compiler/plugin.h"
#include "google/protobuf/descriptor.pb.h"
#include "google/protobuf/descriptor.h"
#include "google/protobuf/wire_format.h"
#include "absl/container/flat_hash_map.h"
#include "protos_generator/output.h"
namespace protos_generator {
namespace protobuf = ::google::protobuf;
enum class MessageClassType {
kMessage,
kMessageCProxy,
kMessageProxy,
kMessageAccess,
};
std::string ClassName(const protobuf::Descriptor* descriptor);
std::string QualifiedClassName(const protobuf::Descriptor* descriptor);
std::string QualifiedInternalClassName(const protobuf::Descriptor* descriptor);
inline bool IsMapEntryMessage(const protobuf::Descriptor* descriptor) {
return descriptor->options().map_entry();
}
std::string CppSourceFilename(const google::protobuf::FileDescriptor* file);
std::string ForwardingHeaderFilename(const google::protobuf::FileDescriptor* file);
std::string UpbCFilename(const google::protobuf::FileDescriptor* file);
std::string CppHeaderFilename(const google::protobuf::FileDescriptor* file);
void WriteStartNamespace(const protobuf::FileDescriptor* file, Output& output);
void WriteEndNamespace(const protobuf::FileDescriptor* file, Output& output);
std::string CppConstType(const protobuf::FieldDescriptor* field);
std::string CppTypeParameterName(const protobuf::FieldDescriptor* field);
std::string MessageBaseType(const protobuf::FieldDescriptor* field,
bool is_const);
// Generate protos::Ptr<const Model> to be used in accessors as public
// signatures.
std::string MessagePtrConstType(const protobuf::FieldDescriptor* field,
bool is_const);
std::string MessageCProxyType(const protobuf::FieldDescriptor* field,
bool is_const);
std::string MessageProxyType(const protobuf::FieldDescriptor* field,
bool is_const);
} // namespace protos_generator
#endif // UPB_PROTOS_GENERATOR_GEN_UTILS_H_

@ -0,0 +1,85 @@
// Copyright (c) 2009-2021, Google LLC
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of Google LLC nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "protos_generator/output.h"
#include "absl/strings/str_replace.h"
namespace protos_generator {
namespace {
namespace protobuf = ::google::protobuf;
} // namespace
std::string StripExtension(absl::string_view fname) {
size_t lastdot = fname.find_last_of('.');
if (lastdot == std::string::npos) {
return std::string(fname);
}
return std::string(fname.substr(0, lastdot));
}
std::string ToCIdent(absl::string_view str) {
return absl::StrReplaceAll(str, {{".", "_"}, {"/", "_"}, {"-", "_"}});
}
std::string ToPreproc(absl::string_view str) {
return absl::AsciiStrToUpper(ToCIdent(str));
}
void EmitFileWarning(const protobuf::FileDescriptor* file, Output& output) {
output(
R"cc(
/* This file was generated by protos_generator (the upb C++ compiler) "
from the input
* file:
*
* $0
*
* Do not edit -- your changes will be discarded when the file is
* regenerated. */
)cc",
file->name());
output("\n");
}
std::string MessageName(const protobuf::Descriptor* descriptor) {
return ToCIdent(descriptor->full_name());
}
std::string FileLayoutName(const google::protobuf::FileDescriptor* file) {
return ToCIdent(file->name()) + "_upb_file_layout";
}
std::string CHeaderFilename(const google::protobuf::FileDescriptor* file) {
return StripExtension(file->name()) + ".upb.h";
}
std::string CSourceFilename(const google::protobuf::FileDescriptor* file) {
return StripExtension(file->name()) + ".upb.c";
}
} // namespace protos_generator

@ -0,0 +1,172 @@
/*
* Copyright (c) 2009-2021, Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Google LLC nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef UPB_PROTOS_GENERATOR_OUTPUT_H
#define UPB_PROTOS_GENERATOR_OUTPUT_H
#include <vector>
#include "google/protobuf/io/zero_copy_stream.h"
#include "google/protobuf/descriptor.h"
#include "absl/base/log_severity.h"
#include "absl/log/log.h"
#include "absl/strings/str_replace.h"
#include "absl/strings/substitute.h"
namespace protos_generator {
class Output {
public:
Output(google::protobuf::io::ZeroCopyOutputStream* stream) : stream_(stream) {}
~Output() { stream_->BackUp((int)buffer_size_); }
template <class... Arg>
void operator()(absl::string_view format, const Arg&... arg) {
Write(absl::Substitute(format, arg...));
}
// Indentation size in characters.
static constexpr size_t kIndentationSize = 2;
void Indent() { Indent(kIndentationSize); }
void Indent(size_t size) { indent_ += size; }
void Outdent() { Outdent(kIndentationSize); }
void Outdent(size_t size) {
if (indent_ < size) {
LOG(FATAL) << "mismatched Output indent/unindent calls";
}
indent_ -= size;
}
private:
void Write(absl::string_view data) {
std::string stripped;
if (absl::StartsWith(data, "\n ")) {
size_t indent = data.substr(1).find_first_not_of(' ');
if (indent > indent_) {
indent -= indent_;
}
if (indent != absl::string_view::npos) {
// Remove indentation from all lines.
auto line_prefix = data.substr(0, indent + 1);
// The final line has an extra newline and is indented two less, eg.
// R"cc(
// UPB_INLINE $0 $1_$2(const $1 *msg) {
// return $1_has_$2(msg) ? *UPB_PTR_AT(msg, $3, $0) : $4;
// }
// )cc",
std::string last_line_prefix = std::string(line_prefix);
last_line_prefix.resize(last_line_prefix.size() - 2);
data.remove_prefix(line_prefix.size());
stripped = absl::StrReplaceAll(
data, {{line_prefix, "\n"}, {last_line_prefix, "\n"}});
data = stripped;
}
} else {
WriteIndent();
}
WriteRaw(data);
}
void WriteRaw(absl::string_view data) {
while (!data.empty()) {
RefreshOutput();
size_t to_write = std::min(data.size(), buffer_size_);
memcpy(output_buffer_, data.data(), to_write);
data.remove_prefix(to_write);
output_buffer_ += to_write;
buffer_size_ -= to_write;
}
}
void WriteIndent() {
if (indent_ == 0) {
return;
}
size_t size = indent_;
while (size > buffer_size_) {
if (buffer_size_ > 0) {
memset(output_buffer_, ' ', buffer_size_);
}
size -= buffer_size_;
buffer_size_ = 0;
RefreshOutput();
}
memset(output_buffer_, ' ', size);
output_buffer_ += size;
buffer_size_ -= size;
}
void RefreshOutput() {
while (buffer_size_ == 0) {
void* void_buffer;
int size;
if (!stream_->Next(&void_buffer, &size)) {
fprintf(stderr, "upbc: Failed to write to to output\n");
abort();
}
output_buffer_ = static_cast<char*>(void_buffer);
buffer_size_ = size;
}
}
google::protobuf::io::ZeroCopyOutputStream* stream_;
char* output_buffer_ = nullptr;
size_t buffer_size_ = 0;
// Current indentation size in characters.
size_t indent_ = 0;
friend class OutputIndenter;
};
class OutputIndenter {
public:
OutputIndenter(Output& output)
: OutputIndenter(output, Output::kIndentationSize) {}
OutputIndenter(Output& output, size_t indent_size)
: indent_size_(indent_size), output_(output) {
output.Indent(indent_size);
}
~OutputIndenter() { output_.Outdent(indent_size_); }
private:
size_t indent_size_;
Output& output_;
};
std::string StripExtension(absl::string_view fname);
std::string ToCIdent(absl::string_view str);
std::string ToPreproc(absl::string_view str);
void EmitFileWarning(const google::protobuf::FileDescriptor* file, Output& output);
std::string MessageName(const google::protobuf::Descriptor* descriptor);
std::string FileLayoutName(const google::protobuf::FileDescriptor* file);
std::string CHeaderFilename(const google::protobuf::FileDescriptor* file);
std::string CSourceFilename(const google::protobuf::FileDescriptor* file);
} // namespace protos_generator
#endif // UPB_PROTOS_GENERATOR_OUTPUT_H

@ -0,0 +1,306 @@
// Copyright (c) 2009-2021, Google LLC
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of Google LLC nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <memory>
#include "google/protobuf/compiler/code_generator.h"
#include "google/protobuf/compiler/plugin.h"
#include "google/protobuf/descriptor.pb.h"
#include "protos_generator/gen_enums.h"
#include "protos_generator/gen_extensions.h"
#include "protos_generator/gen_messages.h"
#include "protos_generator/gen_utils.h"
#include "protos_generator/output.h"
#include "upbc/file_layout.h"
namespace protos_generator {
namespace {
namespace protoc = ::google::protobuf::compiler;
namespace protobuf = ::google::protobuf;
using FileDescriptor = ::google::protobuf::FileDescriptor;
using FileLayout = ::upbc::FileLayout;
void WriteSource(const FileLayout& layout, Output& output,
bool fasttable_enabled);
void WriteHeader(const FileLayout& layout, Output& output);
void WriteForwardingHeader(const FileLayout& layout, Output& output);
void WriteMessageImplementations(const protobuf::FileDescriptor* file,
Output& output);
void WriteTypedefForwardingHeader(
const protobuf::FileDescriptor* file,
const std::vector<const protobuf::Descriptor*>& file_messages,
Output& output);
void WriteHeaderMessageForwardDecls(
const protobuf::FileDescriptor* file,
const std::vector<const protobuf::Descriptor*>& file_messages,
const std::vector<const protobuf::FieldDescriptor*>& file_exts,
Output& output);
class Generator : public protoc::CodeGenerator {
public:
~Generator() override {}
bool Generate(const protobuf::FileDescriptor* file,
const std::string& parameter, protoc::GeneratorContext* context,
std::string* error) const override;
uint64_t GetSupportedFeatures() const override {
return FEATURE_PROTO3_OPTIONAL;
}
};
bool Generator::Generate(const protobuf::FileDescriptor* file,
const std::string& parameter,
protoc::GeneratorContext* context,
std::string* error) const {
bool fasttable_enabled = false;
std::vector<std::pair<std::string, std::string>> params;
google::protobuf::compiler::ParseGeneratorParameter(parameter, &params);
for (const auto& pair : params) {
if (pair.first == "fasttable") {
fasttable_enabled = true;
} else {
*error = "Unknown parameter: " + pair.first;
return false;
}
}
FileLayout layout(file);
// Write model.upb.fwd.h
Output forwarding_header_output(
context->Open(ForwardingHeaderFilename(file)));
WriteForwardingHeader(layout, forwarding_header_output);
// Write model.upb.proto.h
Output header_output(context->Open(CppHeaderFilename(file)));
WriteHeader(layout, header_output);
// Write model.upb.proto.cc
Output cc_output(context->Open(CppSourceFilename(file)));
WriteSource(layout, cc_output, fasttable_enabled);
return true;
}
// The forwarding header defines Access/Proxy/CProxy for message classes
// used to include when referencing dependencies to prevent transitive
// dependency headers from being included.
void WriteForwardingHeader(const FileLayout& layout, Output& output) {
const protobuf::FileDescriptor* file = layout.descriptor();
EmitFileWarning(file, output);
output(
R"cc(
#ifndef $0_UPB_FWD_H_
#define $0_UPB_FWD_H_
)cc",
ToPreproc(file->name()));
output("\n");
const std::vector<const protobuf::Descriptor*> this_file_messages =
::upbc::SortedMessages(file);
WriteTypedefForwardingHeader(file, this_file_messages, output);
output("#endif /* $0_UPB_FWD_H_ */\n", ToPreproc(file->name()));
}
void WriteHeader(const FileLayout& layout, Output& output) {
const protobuf::FileDescriptor* file = layout.descriptor();
EmitFileWarning(file, output);
output(
R"cc(
#ifndef $0_UPB_PROTO_H_
#define $0_UPB_PROTO_H_
#include "protos/protos.h"
#include "protos/protos_internal.h"
#include "upb/upb.hpp"
#include "absl/strings/string_view.h"
#include "absl/status/statusor.h"
#include "upb/msg_internal.h"
)cc",
ToPreproc(file->name()));
// Import headers for proto public dependencies.
for (int i = 0; i < file->public_dependency_count(); i++) {
if (i == 0) {
output("// Public Imports.\n");
}
output("#include \"$0\"\n", CppHeaderFilename(file->public_dependency(i)));
if (i == file->public_dependency_count() - 1) {
output("\n");
}
}
output("#include \"upb/port_def.inc\"\n");
const std::vector<const protobuf::Descriptor*> this_file_messages =
::upbc::SortedMessages(file);
const std::vector<const protobuf::FieldDescriptor*> this_file_exts =
::upbc::SortedExtensions(file);
if (!this_file_messages.empty()) {
output("\n");
}
WriteHeaderMessageForwardDecls(file, this_file_messages, this_file_exts,
output);
WriteStartNamespace(file, output);
std::vector<const protobuf::EnumDescriptor*> this_file_enums =
::upbc::SortedEnums(file);
// Write Class and Enums.
WriteEnumDeclarations(this_file_enums, output);
output("\n");
for (auto message : this_file_messages) {
WriteMessageClassDeclarations(message, this_file_exts, output);
}
output("\n");
WriteExtensionIdentifiersHeader(this_file_exts, output);
output("\n");
WriteEndNamespace(file, output);
output("\n#include \"upb/port_undef.inc\"\n\n");
// End of "C" section.
output("#endif /* $0_UPB_PROTO_H_ */\n", ToPreproc(file->name()));
}
// Writes a .upb.cc source file.
void WriteSource(const FileLayout& layout, Output& output,
bool fasttable_enabled) {
const protobuf::FileDescriptor* file = layout.descriptor();
EmitFileWarning(file, output);
output(
R"cc(
#include <stddef.h>
#include "absl/strings/string_view.h"
#include "upb/msg_internal.h"
#include "protos/protos.h"
#include "$0"
)cc",
CppHeaderFilename(file));
for (int i = 0; i < file->dependency_count(); i++) {
output("#include \"$0\"\n", CppHeaderFilename(file->dependency(i)));
}
output("#include \"upb/port_def.inc\"\n");
WriteStartNamespace(file, output);
WriteMessageImplementations(file, output);
const std::vector<const protobuf::FieldDescriptor*> this_file_exts =
::upbc::SortedExtensions(file);
WriteExtensionIdentifiers(this_file_exts, output);
WriteEndNamespace(file, output);
output("#include \"upb/port_undef.inc\"\n\n");
}
void WriteMessageImplementations(const protobuf::FileDescriptor* file,
Output& output) {
const std::vector<const protobuf::FieldDescriptor*> file_exts =
::upbc::SortedExtensions(file);
const std::vector<const protobuf::Descriptor*> this_file_messages =
::upbc::SortedMessages(file);
for (auto message : this_file_messages) {
WriteMessageImplementation(message, file_exts, output);
}
}
void WriteTypedefForwardingHeader(
const protobuf::FileDescriptor* file,
const std::vector<const protobuf::Descriptor*>& file_messages,
Output& output) {
WriteStartNamespace(file, output);
// Forward-declare types defined in this file.
for (auto message : file_messages) {
output(
R"cc(
class $0;
namespace internal {
class $0Access;
class $0Proxy;
class $0CProxy;
} // namespace internal
)cc",
ClassName(message));
}
output("\n");
WriteEndNamespace(file, output);
}
/// Writes includes for upb C minitables and fwd.h for transitive typedefs.
void WriteHeaderMessageForwardDecls(
const protobuf::FileDescriptor* file,
const std::vector<const protobuf::Descriptor*>& file_messages,
const std::vector<const protobuf::FieldDescriptor*>& file_exts,
Output& output) {
// Import forward-declaration of types defined in this file.
output("#include \"$0\"\n", UpbCFilename(file));
output("#include \"$0\"\n", ForwardingHeaderFilename(file));
// Forward-declare types not in this file, but used as submessages.
// Order by full name for consistent ordering.
std::map<std::string, const protobuf::Descriptor*> forward_messages;
for (auto* message : file_messages) {
for (int i = 0; i < message->field_count(); i++) {
const protobuf::FieldDescriptor* field = message->field(i);
if (field->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_MESSAGE &&
field->file() != field->message_type()->file()) {
forward_messages[field->message_type()->full_name()] =
field->message_type();
}
}
}
for (auto* ext : file_exts) {
if (ext->file() != ext->containing_type()->file()) {
forward_messages[ext->containing_type()->full_name()] =
ext->containing_type();
if (ext->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_MESSAGE) {
forward_messages[ext->message_type()->full_name()] =
ext->message_type();
}
}
}
std::map<std::string, const protobuf::FileDescriptor*> files_to_import;
for (const auto& pair : forward_messages) {
files_to_import[ForwardingHeaderFilename(pair.second->file())] = file;
}
for (const auto& pair : files_to_import) {
output("#include \"$0\"\n", UpbCFilename(pair.second));
output("#include \"$0\"\n", pair.first);
}
output("\n");
}
} // namespace
} // namespace protos_generator
int main(int argc, char** argv) {
protos_generator::Generator generator_cc;
return google::protobuf::compiler::PluginMain(argc, argv, &generator_cc);
}

@ -0,0 +1,118 @@
# Copyright (c) 2009-2021, Google LLC
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# * Neither the name of Google LLC nor the
# names of its contributors may be used to endorse or promote products
# derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
load(
"//bazel:build_defs.bzl",
"UPB_DEFAULT_CPPOPTS",
)
load(
"//protos/bazel:upb_cc_proto_library.bzl",
"upb_cc_proto_library",
)
load(
"//bazel:upb_proto_library.bzl",
"upb_proto_library",
)
load(
"@rules_cc//cc:defs.bzl",
"cc_proto_library",
)
licenses(["notice"])
proto_library(
name = "test_model_proto",
srcs = [
"child_model.proto",
"test_enum.proto",
"test_extension.proto",
"test_model.proto",
],
)
proto_library(
name = "no_package_proto",
srcs = [
"no_package.proto",
],
)
upb_proto_library(
name = "test_model_upb_proto",
visibility = [
"//protos:__pkg__",
],
deps = [":test_model_proto"],
)
upb_cc_proto_library(
name = "test_model_upb_cc_proto",
visibility = [
"//protos:__pkg__",
"//protos_generator/nc_tests:__pkg__",
],
deps = [":test_model_proto"],
)
upb_cc_proto_library(
name = "no_package_upb_cc_proto",
deps = [":no_package_proto"],
)
cc_proto_library(
name = "test_model_cc_proto",
deps = [":test_model_proto"],
)
# begin:google_only
# proto_library(
# name = "legacy_name_proto",
# srcs = [
# "legacy-name.proto",
# ],
# )
#
# upb_cc_proto_library(
# name = "legacy_name_test_proto",
# visibility = ["//protos_generator/nc_tests:__pkg__"],
# deps = [":legacy_name_proto"],
# )
# end:google_only
cc_test(
name = "test_generated_cc_code",
srcs = ["test_generated.cc"],
copts = UPB_DEFAULT_CPPOPTS,
deps = [
# begin:google_only
# ":legacy_name_test_proto",
# end:google_only
":no_package_upb_cc_proto",
":test_model_upb_cc_proto",
":test_model_upb_proto",
"@com_google_googletest//:gtest_main",
"//:upb",
],
)

@ -0,0 +1,19 @@
syntax = "proto3";
package protos_generator.test;
import public "protos_generator/tests/test_enum.proto";
message ChildModel1 {
optional bool child_b1 = 44;
optional string child_str1 = 56;
}
message ChildModel3 {
string sub_key = 1;
bool bool1 = 2;
int32 i32 = 3;
optional string opt_str = 4;
optional bool opt_bool = 5;
optional int32 opt_i32 = 6;
}

@ -0,0 +1,10 @@
syntax = "proto3";
package protos_generator.test;
// option java_multiple_files = true;
enum LegacyEnum {
PHASE_DEFAULT = 0;
PHASE_BUSY = 1;
}

@ -0,0 +1,8 @@
syntax = "proto2";
// option java_multiple_files = true;
enum EnumWithNoPackage {
CELSIUS = 1;
FAHRENHEIT = 2;
}

@ -0,0 +1,10 @@
syntax = "proto3";
package protos_generator.test;
enum TestEnum {
DEVICE_UNKNOWN = 0;
DEVICE_KEYBOARD = 1;
DEVICE_MOUSE = 2;
DEVICE_MONITOR = 3;
}

@ -0,0 +1,12 @@
syntax = "proto2";
package protos_generator.test.someotherpackage;
import "protos_generator/tests/test_model.proto";
// Define extension that is extending proto outside this package with a type
// defined in different file.
extend TestModel {
optional ThemeExtension styling = 13001;
}

@ -0,0 +1,582 @@
// Copyright (c) 2009-2021, Google LLC
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of Google LLC nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <limits>
#include "gtest/gtest.h"
#include "protos_generator/tests/child_model.upb.proto.h"
#include "protos_generator/tests/no_package.upb.proto.h"
#include "protos_generator/tests/test_model.upb.proto.h"
#include "upb/string_view.h"
using ::protos_generator::test::protos::ChildModel1;
using ::protos_generator::test::protos::other_ext;
using ::protos_generator::test::protos::RED;
using ::protos_generator::test::protos::TestEnum;
using ::protos_generator::test::protos::TestModel;
using ::protos_generator::test::protos::TestModel_Category_IMAGES;
using ::protos_generator::test::protos::TestModel_Category_NEWS;
using ::protos_generator::test::protos::TestModel_Category_VIDEO;
using ::protos_generator::test::protos::theme;
using ::protos_generator::test::protos::ThemeExtension;
TEST(CppGeneratedCode, Constructor) { TestModel test_model; }
TEST(CppGeneratedCode, MessageEnum) { EXPECT_EQ(5, TestModel_Category_IMAGES); }
TEST(CppGeneratedCode, ImportedEnum) { EXPECT_EQ(3, TestEnum::DEVICE_MONITOR); }
TEST(CppGeneratedCode, Enum) { EXPECT_EQ(1, RED); }
TEST(CppGeneratedCode, EnumNoPackage) { EXPECT_EQ(1, ::protos_CELSIUS); }
TEST(CppGeneratedCode, ArenaConstructor) {
::protos::Arena arena;
auto testModel = ::protos::CreateMessage<TestModel>(arena);
EXPECT_EQ(false, testModel.has_b1());
}
TEST(CppGeneratedCode, Booleans) {
::protos::Arena arena;
auto testModel = ::protos::CreateMessage<TestModel>(arena);
EXPECT_FALSE(testModel.b1());
testModel.set_b1(true);
EXPECT_TRUE(testModel.b1());
testModel.set_b1(false);
EXPECT_FALSE(testModel.b1());
testModel.set_b1(true);
EXPECT_TRUE(testModel.b1());
testModel.clear_b1();
EXPECT_FALSE(testModel.has_b1());
}
TEST(CppGeneratedCode, ScalarInt32) {
::protos::Arena arena;
auto testModel = ::protos::CreateMessage<TestModel>(arena);
// Test int32 defaults.
EXPECT_EQ(testModel.value(), 0);
EXPECT_FALSE(testModel.has_value());
// Floating point defautls.
EXPECT_EQ(std::numeric_limits<float>::infinity(),
testModel.float_value_with_default());
EXPECT_EQ(-std::numeric_limits<double>::infinity(),
testModel.double_value_with_default());
// Set value.
testModel.set_value(5);
EXPECT_TRUE(testModel.has_value());
EXPECT_EQ(testModel.value(), 5);
// Change value.
testModel.set_value(10);
EXPECT_TRUE(testModel.has_value());
EXPECT_EQ(testModel.value(), 10);
// Clear value.
testModel.clear_value();
EXPECT_FALSE(testModel.has_value());
EXPECT_EQ(testModel.value(), 0);
}
const char kTestStr1[] = "abcdefg";
const char kTestStr2[] = "just another test string";
TEST(CppGeneratedCode, Strings) {
TestModel testModel;
testModel.set_str1(kTestStr1);
testModel.set_str2(kTestStr2);
EXPECT_EQ(testModel.str1(), kTestStr1);
EXPECT_EQ(testModel.str2(), kTestStr2);
EXPECT_TRUE(testModel.has_str1());
EXPECT_TRUE(testModel.has_str2());
testModel.clear_str1();
EXPECT_FALSE(testModel.has_str1());
EXPECT_TRUE(testModel.has_str2());
}
TEST(CppGeneratedCode, ScalarUInt32) {
::protos::Arena arena;
auto testModel = ::protos::CreateMessage<TestModel>(arena);
// Test defaults.
EXPECT_EQ(testModel.optional_uint32(), 0);
EXPECT_FALSE(testModel.has_optional_uint32());
// Set value.
testModel.set_optional_uint32(0xA0001000);
EXPECT_TRUE(testModel.has_optional_uint32());
EXPECT_EQ(testModel.optional_uint32(), 0xA0001000);
// Change value.
testModel.set_optional_uint32(0x70002000);
EXPECT_TRUE(testModel.has_optional_uint32());
EXPECT_EQ(testModel.optional_uint32(), 0x70002000);
// Clear value.
testModel.clear_optional_uint32();
EXPECT_FALSE(testModel.has_optional_uint32());
EXPECT_EQ(testModel.optional_uint32(), 0);
}
TEST(CppGeneratedCode, ScalarInt64) {
::protos::Arena arena;
auto testModel = ::protos::CreateMessage<TestModel>(arena);
// Test defaults.
EXPECT_EQ(testModel.optional_int64(), 0);
EXPECT_FALSE(testModel.has_optional_int64());
// Set value.
testModel.set_optional_int64(0xFF00CCDDA0001000);
EXPECT_TRUE(testModel.has_optional_int64());
EXPECT_EQ(testModel.optional_int64(), 0xFF00CCDDA0001000);
// Change value.
testModel.set_optional_int64(0xFF00CCDD70002000);
EXPECT_TRUE(testModel.has_optional_int64());
EXPECT_EQ(testModel.optional_int64(), 0xFF00CCDD70002000);
// Clear value.
testModel.clear_optional_int64();
EXPECT_FALSE(testModel.has_optional_int64());
EXPECT_EQ(testModel.optional_int64(), 0);
// Set after clear.
testModel.set_optional_int64(0xFF00CCDDA0001000);
EXPECT_TRUE(testModel.has_optional_int64());
EXPECT_EQ(testModel.optional_int64(), 0xFF00CCDDA0001000);
}
TEST(CppGeneratedCode, ScalarFloat) {
::protos::Arena arena;
auto testModel = ::protos::CreateMessage<TestModel>(arena);
// Test defaults.
EXPECT_EQ(testModel.optional_float(), 0.0f);
EXPECT_FALSE(testModel.has_optional_float());
EXPECT_EQ(std::numeric_limits<float>::infinity(),
testModel.float_value_with_default());
EXPECT_EQ(-std::numeric_limits<double>::infinity(),
testModel.double_value_with_default());
// Set value.
testModel.set_optional_float(3.14159265f);
EXPECT_TRUE(testModel.has_optional_float());
EXPECT_NEAR(testModel.optional_float(), 3.14159265f, 1e-9f);
// Change value.
testModel.set_optional_float(-2.0f);
EXPECT_TRUE(testModel.has_optional_float());
EXPECT_NEAR(testModel.optional_float(), -2, 1e-9f);
// Clear value.
testModel.clear_optional_float();
EXPECT_FALSE(testModel.has_optional_float());
EXPECT_EQ(testModel.optional_float(), 0.0f);
// Set after clear.
testModel.set_optional_float(3.14159265f);
EXPECT_TRUE(testModel.has_optional_float());
EXPECT_NEAR(testModel.optional_float(), 3.14159265f, 1e-9f);
}
TEST(CppGeneratedCode, ScalarDouble) {
::protos::Arena arena;
auto testModel = ::protos::CreateMessage<TestModel>(arena);
// Test defaults.
EXPECT_EQ(testModel.optional_double(), 0.0);
EXPECT_FALSE(testModel.has_optional_double());
// Set value.
testModel.set_optional_double(3.141592653589793);
EXPECT_TRUE(testModel.has_optional_double());
EXPECT_NEAR(testModel.optional_double(), 3.141592653589793, 1e-16f);
// Change value.
testModel.set_optional_double(-1.0);
EXPECT_TRUE(testModel.has_optional_double());
EXPECT_NEAR(testModel.optional_double(), -1.0, 1e-16f);
// Clear value.
testModel.clear_optional_double();
EXPECT_FALSE(testModel.has_optional_double());
EXPECT_EQ(testModel.optional_double(), 0.0f);
// Set after clear.
testModel.set_optional_double(3.141592653589793);
EXPECT_TRUE(testModel.has_optional_double());
EXPECT_NEAR(testModel.optional_double(), 3.141592653589793, 1e-16f);
}
TEST(CppGeneratedCode, Enums) {
::protos::Arena arena;
auto testModel = ::protos::CreateMessage<TestModel>(arena);
// Check enum default value.
EXPECT_EQ(TestModel_Category_IMAGES, 5);
// Test defaults.
EXPECT_FALSE(testModel.has_category());
EXPECT_EQ(testModel.category(), TestModel_Category_IMAGES);
// Set value.
testModel.set_category(TestModel_Category_NEWS);
EXPECT_TRUE(testModel.has_category());
EXPECT_EQ(testModel.category(), TestModel_Category_NEWS);
// Change value.
testModel.set_category(TestModel_Category_VIDEO);
EXPECT_TRUE(testModel.has_category());
EXPECT_EQ(testModel.category(), TestModel_Category_VIDEO);
// Clear value.
testModel.clear_category();
EXPECT_FALSE(testModel.has_category());
EXPECT_EQ(testModel.category(), TestModel_Category_IMAGES);
// Set after clear.
testModel.set_category(TestModel_Category_VIDEO);
EXPECT_TRUE(testModel.has_category());
EXPECT_EQ(testModel.category(), TestModel_Category_VIDEO);
}
TEST(CppGeneratedCode, FieldWithDefaultValue) {
::protos::Arena arena;
auto testModel = ::protos::CreateMessage<TestModel>(arena);
EXPECT_FALSE(testModel.has_int_value_with_default());
EXPECT_EQ(testModel.int_value_with_default(), 65);
testModel.set_int_value_with_default(10);
EXPECT_EQ(testModel.int_value_with_default(), 10);
EXPECT_FALSE(testModel.has_string_value_with_default());
EXPECT_EQ(testModel.string_value_with_default(), "hello");
testModel.set_string_value_with_default("new string");
EXPECT_EQ(testModel.string_value_with_default(), "new string");
}
TEST(CppGeneratedCode, OneOfFields) {
::protos::Arena arena;
auto test_model = ::protos::CreateMessage<TestModel>(arena);
EXPECT_FALSE(test_model.has_oneof_member1());
EXPECT_FALSE(test_model.has_oneof_member2());
test_model.set_oneof_member1("one of string");
EXPECT_TRUE(test_model.has_oneof_member1());
EXPECT_FALSE(test_model.has_oneof_member2());
EXPECT_EQ(test_model.oneof_member1(), "one of string");
test_model.set_oneof_member2(true);
EXPECT_FALSE(test_model.has_oneof_member1());
EXPECT_TRUE(test_model.has_oneof_member2());
EXPECT_EQ(test_model.oneof_member2(), true);
test_model.clear_oneof_member2();
EXPECT_FALSE(test_model.has_oneof_member1());
EXPECT_FALSE(test_model.has_oneof_member2());
EXPECT_EQ(test_model.oneof_member1(), "");
EXPECT_EQ(test_model.oneof_member2(), false);
}
TEST(CppGeneratedCode, Messages) {
::protos::Arena arena;
auto test_model = ::protos::CreateMessage<TestModel>(arena);
EXPECT_EQ(false, test_model.has_child_model_1());
auto child_model = test_model.child_model_1();
EXPECT_EQ(false, child_model->has_child_b1());
EXPECT_EQ(false, child_model->child_b1());
auto mutable_child = test_model.mutable_child_model_1();
mutable_child->set_child_b1(true);
EXPECT_EQ(true, mutable_child->has_child_b1());
EXPECT_EQ(true, mutable_child->child_b1());
// The View should not change due to mutation since it
// is default_instance.
EXPECT_EQ(false, child_model->has_child_b1());
// Readonly View should now show change.
child_model = test_model.child_model_1();
EXPECT_EQ(true, child_model->has_child_b1());
EXPECT_EQ(true, child_model->child_b1());
// Clear message field.
EXPECT_EQ(true, test_model.has_child_model_1());
test_model.clear_child_model_1();
EXPECT_EQ(false, test_model.has_child_model_1());
}
TEST(CppGeneratedCode, NestedMessages) {
::protos::Arena arena;
auto test_model = ::protos::CreateMessage<TestModel>(arena);
auto nested_child = test_model.nested_child_1();
EXPECT_EQ(0, nested_child->nested_child_name().size());
auto mutable_nested_child = test_model.mutable_nested_child_1();
EXPECT_EQ(false, mutable_nested_child->has_nested_child_name());
mutable_nested_child->set_nested_child_name(kTestStr1);
EXPECT_EQ(true, mutable_nested_child->has_nested_child_name());
}
TEST(CppGeneratedCode, RepeatedMessages) {
::protos::Arena arena;
auto test_model = ::protos::CreateMessage<TestModel>(arena);
EXPECT_EQ(0, test_model.child_model_2_size());
// Should be able to clear repeated field when empty.
test_model.clear_child_model_2();
EXPECT_EQ(0, test_model.child_model_2_size());
// Add 2 children.
auto new_child = test_model.add_child_model_2();
EXPECT_EQ(true, new_child.ok());
new_child.value()->set_child_str1(kTestStr1);
new_child = test_model.add_child_model_2();
EXPECT_EQ(true, new_child.ok());
new_child.value()->set_child_str1(kTestStr2);
EXPECT_EQ(2, test_model.child_model_2_size());
// Mutable access.
auto mutable_first = test_model.mutable_child_model_2(0);
EXPECT_EQ(mutable_first->child_str1(), kTestStr1);
mutable_first->set_child_str1("change1");
auto mutable_second = test_model.mutable_child_model_2(1);
EXPECT_EQ(mutable_second->child_str1(), kTestStr2);
mutable_second->set_child_str1("change2");
// Check mutations using views.
auto view_first = test_model.child_model_2(0);
EXPECT_EQ(view_first->child_str1(), "change1");
auto view_second = test_model.child_model_2(1);
EXPECT_EQ(view_second->child_str1(), "change2");
}
TEST(CppGeneratedCode, RepeatedScalar) {
::protos::Arena arena;
auto test_model = ::protos::CreateMessage<TestModel>(arena);
EXPECT_EQ(0, test_model.value_array_size());
// Should be able to clear repeated field when empty.
test_model.clear_value_array();
EXPECT_EQ(0, test_model.value_array_size());
// Add 2 children.
EXPECT_EQ(true, test_model.add_value_array(5));
EXPECT_EQ(true, test_model.add_value_array(6));
EXPECT_EQ(2, test_model.value_array_size());
EXPECT_EQ(5, test_model.value_array(0));
EXPECT_EQ(6, test_model.value_array(1));
EXPECT_EQ(true, test_model.resize_value_array(3));
EXPECT_EQ(3, test_model.value_array_size());
test_model.set_value_array(2, 7);
EXPECT_EQ(5, test_model.value_array(0));
EXPECT_EQ(6, test_model.value_array(1));
EXPECT_EQ(7, test_model.value_array(2));
}
TEST(CppGeneratedCode, RepeatedStrings) {
::protos::Arena arena;
auto test_model = ::protos::CreateMessage<TestModel>(arena);
EXPECT_EQ(0, test_model.repeated_string_size());
// Should be able to clear repeated field when empty.
test_model.clear_repeated_string();
EXPECT_EQ(0, test_model.repeated_string_size());
// Add 2 children.
EXPECT_EQ(true, test_model.add_repeated_string("Hello"));
EXPECT_EQ(true, test_model.add_repeated_string("World"));
EXPECT_EQ(2, test_model.repeated_string_size());
EXPECT_EQ("Hello", test_model.repeated_string(0));
EXPECT_EQ("World", test_model.repeated_string(1));
EXPECT_EQ(true, test_model.resize_repeated_string(3));
EXPECT_EQ(3, test_model.repeated_string_size());
test_model.set_repeated_string(2, "Test");
EXPECT_EQ("Hello", test_model.repeated_string(0));
EXPECT_EQ("World", test_model.repeated_string(1));
EXPECT_EQ("Test", test_model.repeated_string(2));
}
TEST(CppGeneratedCode, MessageMapInt32KeyMessageValue) {
const int key_test_value = 3;
::protos::Arena arena;
auto test_model = ::protos::CreateMessage<TestModel>(arena);
EXPECT_EQ(0, test_model.child_map_size());
test_model.clear_child_map();
EXPECT_EQ(0, test_model.child_map_size());
auto child_model1 = ::protos::CreateMessage<ChildModel1>(arena);
child_model1.set_child_str1("abc");
test_model.set_child_map(key_test_value, child_model1);
auto map_result = test_model.get_child_map(key_test_value);
EXPECT_EQ(true, map_result.ok());
EXPECT_EQ("abc", map_result.value()->child_str1());
test_model.delete_child_map(key_test_value);
auto map_result_after_delete = test_model.get_child_map(key_test_value);
EXPECT_EQ(false, map_result_after_delete.ok());
}
TEST(CppGeneratedCode, MessageMapStringKeyAndStringValue) {
::protos::Arena arena;
auto test_model = ::protos::CreateMessage<TestModel>(arena);
EXPECT_EQ(0, test_model.str_to_str_map_size());
test_model.clear_str_to_str_map();
EXPECT_EQ(0, test_model.str_to_str_map_size());
test_model.set_str_to_str_map("first", "abc");
test_model.set_str_to_str_map("second", "def");
auto result = test_model.get_str_to_str_map("second");
EXPECT_EQ(true, result.ok());
EXPECT_EQ("def", result.value());
test_model.delete_str_to_str_map("first");
auto result_after_delete = test_model.get_str_to_str_map("first");
EXPECT_EQ(false, result_after_delete.ok());
}
TEST(CppGeneratedCode, MessageMapStringKeyAndInt32Value) {
::protos::Arena arena;
auto test_model = ::protos::CreateMessage<TestModel>(arena);
EXPECT_EQ(0, test_model.str_to_int_map_size());
test_model.clear_str_to_int_map();
EXPECT_EQ(0, test_model.str_to_int_map_size());
test_model.set_str_to_int_map("first", 10);
test_model.set_str_to_int_map("second", 20);
auto result = test_model.get_str_to_int_map("second");
EXPECT_EQ(true, result.ok());
EXPECT_EQ(20, result.value());
test_model.delete_str_to_int_map("first");
auto result_after_delete = test_model.get_str_to_int_map("first");
EXPECT_EQ(false, result_after_delete.ok());
}
TEST(CppGeneratedCode, HasExtension) {
TestModel model;
EXPECT_EQ(false, ::protos::HasExtension(model, theme));
}
TEST(CppGeneratedCode, HasExtensionPtr) {
TestModel model;
EXPECT_EQ(false, ::protos::HasExtension(model.recursive_child(), theme));
}
TEST(CppGeneratedCode, ClearExtensionWithEmptyExtension) {
TestModel model;
EXPECT_EQ(false, ::protos::HasExtension(model, theme));
::protos::ClearExtension(model, theme);
EXPECT_EQ(false, ::protos::HasExtension(model, theme));
}
TEST(CppGeneratedCode, ClearExtensionWithEmptyExtensionPtr) {
TestModel model;
::protos::Ptr<TestModel> recursive_child = model.mutable_recursive_child();
::protos::ClearExtension(recursive_child, theme);
EXPECT_EQ(false, ::protos::HasExtension(recursive_child, theme));
}
TEST(CppGeneratedCode, SetExtension) {
TestModel model;
ThemeExtension extension1;
extension1.set_ext_name("Hello World");
EXPECT_EQ(false, ::protos::HasExtension(model, theme));
EXPECT_EQ(true, ::protos::SetExtension(model, theme, extension1).ok());
EXPECT_EQ(true, ::protos::HasExtension(model, theme));
}
TEST(CppGeneratedCode, SetExtensionOnMutableChild) {
TestModel model;
ThemeExtension extension1;
extension1.set_ext_name("Hello World");
EXPECT_EQ(false,
::protos::HasExtension(model.mutable_recursive_child(), theme));
EXPECT_EQ(true, ::protos::SetExtension(model.mutable_recursive_child(), theme,
extension1)
.ok());
EXPECT_EQ(true,
::protos::HasExtension(model.mutable_recursive_child(), theme));
}
TEST(CppGeneratedCode, GetExtension) {
TestModel model;
ThemeExtension extension1;
extension1.set_ext_name("Hello World");
EXPECT_EQ(false, ::protos::HasExtension(model, theme));
EXPECT_EQ(true, ::protos::SetExtension(model, theme, extension1).ok());
EXPECT_EQ("Hello World",
::protos::GetExtension(model, theme).value()->ext_name());
}
TEST(CppGeneratedCode, GetExtensionOnMutableChild) {
TestModel model;
ThemeExtension extension1;
extension1.set_ext_name("Hello World");
::protos::Ptr<TestModel> mutable_recursive_child =
model.mutable_recursive_child();
EXPECT_EQ(false, ::protos::HasExtension(mutable_recursive_child, theme));
EXPECT_EQ(
true,
::protos::SetExtension(mutable_recursive_child, theme, extension1).ok());
EXPECT_EQ("Hello World",
::protos::GetExtension(mutable_recursive_child, theme)
.value()
->ext_name());
}
TEST(CppGeneratedCode, GetExtensionOnImmutableChild) {
TestModel model;
ThemeExtension extension1;
extension1.set_ext_name("Hello World");
::protos::Ptr<TestModel> mutable_recursive_child =
model.mutable_recursive_child();
EXPECT_EQ(false, ::protos::HasExtension(mutable_recursive_child, theme));
EXPECT_EQ(
true,
::protos::SetExtension(mutable_recursive_child, theme, extension1).ok());
::protos::Ptr<const TestModel> recursive_child = model.recursive_child();
EXPECT_EQ("Hello World",
::protos::GetExtension(recursive_child, theme).value()->ext_name());
}
TEST(CppGeneratedCode, SerializeUsingArena) {
TestModel model;
model.set_str1("Hello World");
::upb::Arena arena;
absl::StatusOr<absl::string_view> bytes = ::protos::Serialize(model, arena);
EXPECT_EQ(true, bytes.ok());
TestModel parsed_model = ::protos::Parse<TestModel>(bytes.value()).value();
EXPECT_EQ("Hello World", parsed_model.str1());
}
TEST(CppGeneratedCode, SerializeNestedMessageUsingArena) {
TestModel model;
model.mutable_recursive_child()->set_str1("Hello World");
::upb::Arena arena;
::protos::Ptr<const TestModel> child = model.recursive_child();
absl::StatusOr<absl::string_view> bytes = ::protos::Serialize(child, arena);
EXPECT_EQ(true, bytes.ok());
TestModel parsed_model = ::protos::Parse<TestModel>(bytes.value()).value();
EXPECT_EQ("Hello World", parsed_model.str1());
}
TEST(CppGeneratedCode, Parse) {
TestModel model;
model.set_str1("Test123");
ThemeExtension extension1;
extension1.set_ext_name("Hello World");
EXPECT_EQ(true, ::protos::SetExtension(model, theme, extension1).ok());
::upb::Arena arena;
auto bytes = ::protos::Serialize(model, arena);
EXPECT_EQ(true, bytes.ok());
TestModel parsed_model = ::protos::Parse<TestModel>(bytes.value()).value();
EXPECT_EQ("Test123", parsed_model.str1());
// Should not return an extension since we did not pass ExtensionRegistry.
EXPECT_EQ(false, ::protos::GetExtension(parsed_model, theme).ok());
}
TEST(CppGeneratedCode, ParseWithExtensionRegistry) {
TestModel model;
model.set_str1("Test123");
ThemeExtension extension1;
extension1.set_ext_name("Hello World");
EXPECT_EQ(true, ::protos::SetExtension(model, theme, extension1).ok());
::upb::Arena arena;
auto bytes = ::protos::Serialize(model, arena);
EXPECT_EQ(true, bytes.ok());
::protos::ExtensionRegistry extensions({&theme, &other_ext}, arena);
TestModel parsed_model =
::protos::Parse<TestModel>(bytes.value(), extensions).value();
EXPECT_EQ("Test123", parsed_model.str1());
EXPECT_EQ(true, ::protos::GetExtension(parsed_model, theme).ok());
}
TEST(CppGeneratedCode, NameCollisions) {
TestModel model;
model.set_template_("test");
EXPECT_EQ("test", model.template_());
model.set_arena__("test");
EXPECT_EQ("test", model.arena__());
}

@ -0,0 +1,149 @@
syntax = "proto2";
package protos_generator.test;
import "protos_generator/tests/child_model.proto";
message TestModelContainer {
repeated TestModel models = 1;
optional ChildModel3 proto_3_child = 2;
}
message TestModel {
optional int32 value = 1;
repeated int32 value_array = 2; // _UPB_MODE_ARRAY
repeated int32 value_packed_array = 3
[packed = true]; // _UPB_MODE_ARRAY | _UPB_MODE_IS_PACKED
repeated int32 value_deprec = 4 [deprecated = true];
optional string str1 = 115;
optional bool b1 = 9;
optional bool b2 = 10;
optional string str2 = 50;
optional string str3 = 11;
optional float optional_float = 14;
optional double optional_double = 15;
optional int64 optional_int64 = 16;
optional uint32 optional_uint32 = 17;
optional uint64 optional_uint64 = 18;
optional sint32 optional_sint32 = 19;
optional sint64 optional_sint64 = 20;
optional fixed32 optional_fixed32 = 21;
optional fixed64 optional_fixed64 = 22;
optional sfixed32 optional_sfixed32 = 23;
optional sfixed64 optional_sfixed64 = 24;
repeated int64 repeated_int64 = 25;
repeated uint64 repeated_uint64 = 26;
repeated fixed64 repeated_fixed64 = 27;
repeated sfixed64 repeated_sfixed64 = 28;
repeated bool repeated_bool = 29;
repeated string repeated_string = 35;
optional bytes optional_bytes = 36;
message NestedChild {
optional string nested_child_name = 211;
}
optional NestedChild nested_child_1 = 212;
optional ChildModel1 child_model_1 = 222;
repeated ChildModel1 child_model_2 = 223;
optional ChildModel1 bar = 224;
oneof child_oneof1 {
string oneof_member1 = 98;
bool oneof_member2 = 99;
}
optional int32 int_value_with_default = 31
[default = 65]; // Not supported yet
optional string string_value_with_default = 32
[default = "hello"]; // Not supported yet
optional float float_value_with_default = 33 [default = inf];
optional float double_value_with_default = 34 [default = -inf];
map<int32, ChildModel1> child_map = 225;
optional TestModel recursive_child = 226;
map<string, ChildModel1> child_str_map = 227;
map<string, int32> str_to_int_map = 228;
map<string, string> str_to_str_map = 229;
extend TestAnnotation {
optional OtherExtension in_message_ext = 15000;
}
enum Category {
IMAGES = 5;
NEWS = 6;
VIDEO = 7;
RADIO = 8 [deprecated = true];
}
optional Category category = 37;
// keyword collisions (double, template, ...)
oneof type {
string string = 230;
int64 int64 = 231;
double double = 232;
}
optional string template = 233;
optional string msg = 234;
optional string arena = 235;
// Tests publicly imported enum.
optional TestEnum imported_enum = 238;
// TODO(243705098) accessor name collision with field name
// optional repeated string phase = 236;
// optional bool clear_phase = 237;
extensions 10000 to max;
}
// Old version with fewer fields to test backward/forward compatibility.
message TestModelContainerV1 {
repeated TestModelV1 models = 1;
}
message TestModelV1 {
optional int32 value = 1;
repeated int32 value2 = 2;
repeated int32 value3 = 3 [packed = true];
repeated int32 value4 = 4 [deprecated = true];
optional bool b1 = 9;
optional bool b2 = 10;
optional string str2 = 50;
}
enum PrimaryColors {
RED = 1;
GREEN = 2;
BLUE = 3;
}
// TestModel extension.
message ThemeExtension {
optional string ext_name = 1;
optional bool ext_bool = 2;
}
extend TestModel {
optional ThemeExtension theme = 12001;
}
message OtherExtension {
optional string ext2_name = 1;
}
extend TestModel {
optional OtherExtension other_ext = 12002;
}
message TestAnnotation {
extensions 10000 to max;
}
message TestMessageHasEnum {
optional EnumDeclaredAfterMessage enum_declared_after_message = 1;
}
enum EnumDeclaredAfterMessage {
ZERO = 0;
ONE = 1;
TWO = 2;
THREE = 3;
}

@ -75,7 +75,7 @@ cc_library(
"common.h",
],
copts = UPB_DEFAULT_CPPOPTS,
visibility = ["//third_party/upb/protos_generator:__pkg__"],
visibility = ["//protos_generator:__pkg__"],
deps = [
"@com_google_absl//absl/strings",
"@com_google_protobuf//:protobuf",
@ -91,7 +91,7 @@ cc_library(
"file_layout.h",
],
copts = UPB_DEFAULT_CPPOPTS,
visibility = ["//third_party/upb/protos_generator:__pkg__"],
visibility = ["//protos_generator:__pkg__"],
deps = [
":common",
"//:mini_table",
@ -112,7 +112,7 @@ cc_library(
"keywords.h",
],
copts = UPB_DEFAULT_CPPOPTS,
visibility = ["//third_party/upb/protos_generator:__pkg__"],
visibility = ["//protos_generator:__pkg__"],
)
cc_library(
@ -124,7 +124,7 @@ cc_library(
"names.h",
],
copts = UPB_DEFAULT_CPPOPTS,
visibility = ["//third_party/upb/protos_generator:__pkg__"],
visibility = ["//protos_generator:__pkg__"],
deps = [
"@com_google_absl//absl/container:flat_hash_map",
"@com_google_absl//absl/strings",

@ -141,7 +141,7 @@ std::string SizeLg2(const protobuf::FieldDescriptor* field) {
case protobuf::FieldDescriptor::CPPTYPE_ENUM:
return std::to_string(2);
case protobuf::FieldDescriptor::CPPTYPE_BOOL:
return std::to_string(1);
return std::to_string(0);
case protobuf::FieldDescriptor::CPPTYPE_FLOAT:
return std::to_string(2);
case protobuf::FieldDescriptor::CPPTYPE_INT32:

Loading…
Cancel
Save