Open up visibility for some compiler internals (#10608)

* Expose language-specific naming utilities in Bazel for downstream code generators

* Expose language generators without exposing implementation details

* Update cmake configs

* Revert "Expose language generators without exposing implementation details"

This reverts commit b073d9b4ebf28b825a6340ea0dfc60f1e43ae4c1.

* Give gRPC privileged access to our python generator

* Naming cleanup

* Add linkage for public names.h helpers

* Fixing build/merge issues

* Fix extension docstring
pull/10662/head
Mike Kruskal 2 years ago committed by GitHub
parent d58d471117
commit 01fe22219a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 8
      pkg/BUILD.bazel
  2. 9
      src/file_lists.cmake
  3. 1
      src/google/protobuf/compiler/BUILD.bazel
  4. 1
      src/google/protobuf/compiler/command_line_interface_unittest.cc
  5. 38
      src/google/protobuf/compiler/cpp/BUILD.bazel
  6. 15
      src/google/protobuf/compiler/csharp/BUILD.bazel
  7. 2
      src/google/protobuf/compiler/csharp/csharp_field_base.cc
  8. 3
      src/google/protobuf/compiler/csharp/csharp_generator.cc
  9. 167
      src/google/protobuf/compiler/csharp/csharp_helpers.cc
  10. 22
      src/google/protobuf/compiler/csharp/csharp_helpers.h
  11. 2
      src/google/protobuf/compiler/csharp/csharp_message.cc
  12. 2
      src/google/protobuf/compiler/csharp/csharp_reflection_class.cc
  13. 2
      src/google/protobuf/compiler/csharp/csharp_source_generator_base.cc
  14. 225
      src/google/protobuf/compiler/csharp/names.cc
  15. 42
      src/google/protobuf/compiler/csharp/names.h
  16. 43
      src/google/protobuf/compiler/java/BUILD.bazel
  17. 6
      src/google/protobuf/compiler/java/context.cc
  18. 15
      src/google/protobuf/compiler/java/context.h
  19. 136
      src/google/protobuf/compiler/java/helpers.cc
  20. 31
      src/google/protobuf/compiler/java/helpers.h
  21. 194
      src/google/protobuf/compiler/java/names.cc
  22. 26
      src/google/protobuf/compiler/java/names.h
  23. 32
      src/google/protobuf/compiler/objectivec/BUILD.bazel
  24. 2
      src/google/protobuf/compiler/objectivec/names.cc
  25. 363
      src/google/protobuf/compiler/objectivec/names.h
  26. 312
      src/google/protobuf/compiler/objectivec/objectivec_helpers.h
  27. 15
      src/google/protobuf/compiler/php/BUILD.bazel
  28. 144
      src/google/protobuf/compiler/php/names.cc
  29. 73
      src/google/protobuf/compiler/php/names.h
  30. 116
      src/google/protobuf/compiler/php/php_generator.cc
  31. 8
      src/google/protobuf/compiler/php/php_generator.h
  32. 1
      src/google/protobuf/compiler/python/BUILD.bazel

@ -402,10 +402,18 @@ cc_dist_library(
"//src/google/protobuf/compiler:code_generator",
"//src/google/protobuf/compiler:command_line_interface",
"//src/google/protobuf/compiler/cpp",
"//src/google/protobuf/compiler/cpp:names",
"//src/google/protobuf/compiler/cpp:names_internal",
"//src/google/protobuf/compiler/csharp",
"//src/google/protobuf/compiler/csharp:names",
"//src/google/protobuf/compiler/java",
"//src/google/protobuf/compiler/java:names",
"//src/google/protobuf/compiler/java:names_internal",
"//src/google/protobuf/compiler/objectivec",
"//src/google/protobuf/compiler/objectivec:names",
"//src/google/protobuf/compiler/objectivec:names_internal",
"//src/google/protobuf/compiler/php",
"//src/google/protobuf/compiler/php:names",
"//src/google/protobuf/compiler/python",
"//src/google/protobuf/compiler/ruby",
],

@ -318,6 +318,7 @@ set(libprotoc_srcs
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_source_generator_base.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_wrapper_field.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/csharp/names.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/context.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/doc_comment.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/enum.cc
@ -342,24 +343,26 @@ set(libprotoc_srcs
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/message_lite.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/message_serialization.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/name_resolver.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/names.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/primitive_field.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/primitive_field_lite.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/service.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/shared_code_generator.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/string_field.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/string_field_lite.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/names.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_enum.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_extension.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_field.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_file.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_generator.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_message.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_message_field.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_oneof.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/php/names.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/php/php_generator.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/plugin.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/plugin.pb.cc
@ -402,7 +405,6 @@ set(libprotoc_hdrs
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_map_field.h
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_message.h
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_message_field.h
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_names.h
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_options.h
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_primitive_field.h
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_reflection_class.h
@ -411,6 +413,7 @@ set(libprotoc_hdrs
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.h
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_source_generator_base.h
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_wrapper_field.h
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/csharp/names.h
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/context.h
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/doc_comment.h
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/enum.h
@ -443,6 +446,7 @@ set(libprotoc_hdrs
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/shared_code_generator.h
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/string_field.h
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/string_field_lite.h
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/names.h
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_enum.h
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_enum_field.h
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_extension.h
@ -457,6 +461,7 @@ set(libprotoc_hdrs
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_oneof.h
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_options.h
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.h
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/php/names.h
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/php/php_generator.h
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/plugin.h
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/plugin.pb.h

@ -244,6 +244,7 @@ cc_test(
":command_line_interface",
":mock_code_generator",
"//:protobuf",
"//src/google/protobuf/compiler/cpp:names",
"//src/google/protobuf:cc_test_protos",
"//src/google/protobuf:test_util2",
"//src/google/protobuf/io",

@ -66,6 +66,7 @@
#include "google/protobuf/compiler/command_line_interface.h"
#include "google/protobuf/compiler/mock_code_generator.h"
#include "google/protobuf/compiler/subprocess.h"
#include "google/protobuf/compiler/cpp/names.h"
#include "google/protobuf/descriptor.h"
#include "google/protobuf/io/io_win32.h"
#include "google/protobuf/io/printer.h"

@ -7,6 +7,38 @@ load("@rules_pkg//:mappings.bzl", "pkg_files", "strip_prefix")
load("@rules_proto//proto:defs.bzl", "proto_library")
load("//build_defs:cpp_opts.bzl", "COPTS")
cc_library(
name = "names",
hdrs = ["names.h"],
copts = COPTS,
include_prefix = "google/protobuf/compiler/cpp",
visibility = ["//visibility:public"],
deps = [
":names_internal",
"//src/google/protobuf/compiler:code_generator",
"//src/google/protobuf:protobuf_nowkt",
],
)
cc_library(
name = "names_internal",
hdrs = [
"helpers.h",
"names.h",
"options.h",
],
srcs = [
"helpers.cc",
],
copts = COPTS,
include_prefix = "google/protobuf/compiler/cpp",
visibility = ["//pkg:__pkg__"],
deps = [
"//src/google/protobuf/compiler:code_generator",
"//src/google/protobuf:protobuf_nowkt",
],
)
cc_library(
name = "cpp",
srcs = [
@ -16,7 +48,6 @@ cc_library(
"field.cc",
"file.cc",
"generator.cc",
"helpers.cc",
"map_field.cc",
"message.cc",
"message_field.cc",
@ -33,13 +64,10 @@ cc_library(
"field.h",
"file.h",
"generator.h",
"helpers.h",
"map_field.h",
"message.h",
"message_field.h",
"message_layout_helper.h",
"names.h",
"options.h",
"padding_optimizer.h",
"parse_function_generator.h",
"primitive_field.h",
@ -53,6 +81,8 @@ cc_library(
"//src/google/protobuf/compiler:__pkg__",
],
deps = [
":names_internal",
":names",
"//src/google/protobuf:protobuf_nowkt",
"//src/google/protobuf/compiler:code_generator",
"@com_google_absl//absl/base:core_headers",

@ -6,6 +6,19 @@ load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test")
load("@rules_pkg//:mappings.bzl", "pkg_files", "strip_prefix")
load("//build_defs:cpp_opts.bzl", "COPTS")
cc_library(
name = "names",
hdrs = ["names.h"],
srcs = ["names.cc"],
copts = COPTS,
include_prefix = "google/protobuf/compiler/csharp",
visibility = ["//visibility:public"],
deps = [
"//src/google/protobuf:protobuf_nowkt",
"@com_google_absl//absl/strings",
],
)
cc_library(
name = "csharp",
srcs = [
@ -36,7 +49,6 @@ cc_library(
"csharp_map_field.h",
"csharp_message.h",
"csharp_message_field.h",
"csharp_names.h",
"csharp_options.h",
"csharp_primitive_field.h",
"csharp_reflection_class.h",
@ -56,6 +68,7 @@ cc_library(
"//src/google/protobuf/compiler:__pkg__",
],
deps = [
":names",
"//src/google/protobuf:protobuf_nowkt",
"//src/google/protobuf/compiler:code_generator",
"@com_google_absl//absl/container:flat_hash_set",

@ -38,7 +38,7 @@
#include "google/protobuf/descriptor.h"
#include "google/protobuf/wire_format.h"
#include "google/protobuf/compiler/csharp/csharp_helpers.h"
#include "google/protobuf/compiler/csharp/csharp_names.h"
#include "google/protobuf/compiler/csharp/names.h"
#include "google/protobuf/descriptor.pb.h"
#include "google/protobuf/io/coded_stream.h"
#include "google/protobuf/io/printer.h"

@ -34,9 +34,10 @@
#include "google/protobuf/compiler/code_generator.h"
#include "google/protobuf/descriptor.h"
#include "google/protobuf/compiler/csharp/csharp_names.h"
#include "google/protobuf/compiler/csharp/csharp_helpers.h"
#include "google/protobuf/compiler/csharp/csharp_options.h"
#include "google/protobuf/compiler/csharp/csharp_reflection_class.h"
#include "google/protobuf/compiler/csharp/names.h"
#include "google/protobuf/descriptor.pb.h"
#include "google/protobuf/io/printer.h"
#include "google/protobuf/io/zero_copy_stream.h"

@ -47,13 +47,13 @@
#include "google/protobuf/compiler/csharp/csharp_field_base.h"
#include "google/protobuf/compiler/csharp/csharp_map_field.h"
#include "google/protobuf/compiler/csharp/csharp_message_field.h"
#include "google/protobuf/compiler/csharp/csharp_names.h"
#include "google/protobuf/compiler/csharp/csharp_options.h"
#include "google/protobuf/compiler/csharp/csharp_primitive_field.h"
#include "google/protobuf/compiler/csharp/csharp_repeated_enum_field.h"
#include "google/protobuf/compiler/csharp/csharp_repeated_message_field.h"
#include "google/protobuf/compiler/csharp/csharp_repeated_primitive_field.h"
#include "google/protobuf/compiler/csharp/csharp_wrapper_field.h"
#include "google/protobuf/compiler/csharp/names.h"
#include "google/protobuf/descriptor.pb.h"
// Must be last.
@ -110,102 +110,6 @@ CSharpType GetCSharpType(FieldDescriptor::Type type) {
return (CSharpType) -1;
}
std::string StripDotProto(const std::string& proto_file) {
int lastindex = proto_file.find_last_of('.');
return proto_file.substr(0, lastindex);
}
std::string GetFileNamespace(const FileDescriptor* descriptor) {
if (descriptor->options().has_csharp_namespace()) {
return descriptor->options().csharp_namespace();
}
return UnderscoresToCamelCase(descriptor->package(), true, true);
}
// Returns the Pascal-cased last part of the proto file. For example,
// input of "google/protobuf/foo_bar.proto" would result in "FooBar".
std::string GetFileNameBase(const FileDescriptor* descriptor) {
std::string proto_file = descriptor->name();
int lastslash = proto_file.find_last_of('/');
std::string base = proto_file.substr(lastslash + 1);
return UnderscoresToPascalCase(StripDotProto(base));
}
std::string GetReflectionClassUnqualifiedName(const FileDescriptor* descriptor) {
// TODO: Detect collisions with existing messages,
// and append an underscore if necessary.
return GetFileNameBase(descriptor) + "Reflection";
}
std::string GetExtensionClassUnqualifiedName(const FileDescriptor* descriptor) {
// TODO: Detect collisions with existing messages,
// and append an underscore if necessary.
return GetFileNameBase(descriptor) + "Extensions";
}
// TODO(jtattermusch): can we reuse a utility function?
std::string UnderscoresToCamelCase(const std::string& input,
bool cap_next_letter,
bool preserve_period) {
std::string result;
// Note: I distrust ctype.h due to locales.
for (int i = 0; i < input.size(); i++) {
if ('a' <= input[i] && input[i] <= 'z') {
if (cap_next_letter) {
result += input[i] + ('A' - 'a');
} else {
result += input[i];
}
cap_next_letter = false;
} else if ('A' <= input[i] && input[i] <= 'Z') {
if (i == 0 && !cap_next_letter) {
// Force first letter to lower-case unless explicitly told to
// capitalize it.
result += input[i] + ('a' - 'A');
} else {
// Capital letters after the first are left as-is.
result += input[i];
}
cap_next_letter = false;
} else if ('0' <= input[i] && input[i] <= '9') {
result += input[i];
cap_next_letter = true;
} else {
cap_next_letter = true;
if (input[i] == '.' && preserve_period) {
result += '.';
}
}
}
// Add a trailing "_" if the name should be altered.
if (input.size() > 0 && input[input.size() - 1] == '#') {
result += '_';
}
// https://github.com/protocolbuffers/protobuf/issues/8101
// To avoid generating invalid identifiers - if the input string
// starts with _<digit> (or multiple underscores then digit) then
// we need to preserve the underscore as an identifier cannot start
// with a digit.
// This check is being done after the loop rather than before
// to handle the case where there are multiple underscores before the
// first digit. We let them all be consumed so we can see if we would
// start with a digit.
// Note: not preserving leading underscores for all otherwise valid identifiers
// so as to not break anything that relies on the existing behaviour
if (result.size() > 0 && ('0' <= result[0] && result[0] <= '9')
&& input.size() > 0 && input[0] == '_')
{
result.insert(0, 1, '_');
}
return result;
}
std::string UnderscoresToPascalCase(const std::string& input) {
return UnderscoresToCamelCase(input, true);
}
// Convert a string which is expected to be SHOUTY_CASE (but may not be *precisely* shouty)
// into a PascalCase string. Precise rules implemented:
@ -342,32 +246,6 @@ uint GetGroupEndTag(const Descriptor* descriptor) {
return 0;
}
std::string ToCSharpName(const std::string& name, const FileDescriptor* file) {
std::string result = GetFileNamespace(file);
if (!result.empty()) {
result += '.';
}
std::string classname;
if (file->package().empty()) {
classname = name;
} else {
// Strip the proto package from full_name since we've replaced it with
// the C# namespace.
classname = name.substr(file->package().size() + 1);
}
result += absl::StrReplaceAll(classname, {{".", ".Types."}});
return "global::" + result;
}
std::string GetReflectionClassName(const FileDescriptor* descriptor) {
std::string result = GetFileNamespace(descriptor);
if (!result.empty()) {
result += '.';
}
result += GetReflectionClassUnqualifiedName(descriptor);
return "global::" + result;
}
std::string GetFullExtensionName(const FieldDescriptor* descriptor) {
if (descriptor->extension_scope()) {
return GetClassName(descriptor->extension_scope()) + ".Extensions." + GetPropertyName(descriptor);
@ -377,14 +255,6 @@ std::string GetFullExtensionName(const FieldDescriptor* descriptor) {
}
}
std::string GetClassName(const Descriptor* descriptor) {
return ToCSharpName(descriptor->full_name(), descriptor->file());
}
std::string GetClassName(const EnumDescriptor* descriptor) {
return ToCSharpName(descriptor->full_name(), descriptor->file());
}
// Groups are hacky: The name of the field is just the lower-cased name
// of the group type. In C#, though, we would like to retain the original
// capitalization of the type name.
@ -437,41 +307,6 @@ std::string GetOneofCaseName(const FieldDescriptor* descriptor) {
return property_name == "None" ? "None_" : property_name;
}
std::string GetOutputFile(const FileDescriptor* descriptor,
const std::string file_extension,
const bool generate_directories,
const std::string base_namespace,
std::string* error) {
std::string relative_filename = GetFileNameBase(descriptor) + file_extension;
if (!generate_directories) {
return relative_filename;
}
std::string ns = GetFileNamespace(descriptor);
std::string namespace_suffix = ns;
if (!base_namespace.empty()) {
// Check that the base_namespace is either equal to or a leading part of
// the file namespace. This isn't just a simple prefix; "Foo.B" shouldn't
// be regarded as a prefix of "Foo.Bar". The simplest option is to add "."
// to both.
std::string extended_ns = ns + ".";
if (extended_ns.find(base_namespace + ".") != 0) {
*error = "Namespace " + ns + " is not a prefix namespace of base namespace " + base_namespace;
return ""; // This will be ignored, because we've set an error.
}
namespace_suffix = ns.substr(base_namespace.length());
if (namespace_suffix.find('.') == 0) {
namespace_suffix = namespace_suffix.substr(1);
}
}
std::string namespace_dir =
absl::StrReplaceAll(namespace_suffix, {{".", "/"}});
if (!namespace_dir.empty()) {
namespace_dir += "/";
}
return namespace_dir + relative_filename;
}
// TODO: c&p from Java protoc plugin
// For encodings with fixed sizes, returns that size in bytes. Otherwise
// returns -1.

@ -38,6 +38,7 @@
#include <string>
#include "google/protobuf/compiler/code_generator.h"
#include "google/protobuf/compiler/csharp/names.h"
#include "google/protobuf/descriptor.h"
#include "google/protobuf/port.h"
#include "google/protobuf/stubs/common.h"
@ -72,15 +73,6 @@ enum CSharpType {
// Converts field type to corresponding C# type.
CSharpType GetCSharpType(FieldDescriptor::Type type);
std::string StripDotProto(const std::string& proto_file);
// Gets unqualified name of the reflection class
std::string GetReflectionClassUnqualifiedName(const FileDescriptor* descriptor);
// Gets unqualified name of the extension class
std::string GetExtensionClassUnqualifiedName(const FileDescriptor* descriptor);
std::string GetClassName(const EnumDescriptor* descriptor);
std::string GetFieldName(const FieldDescriptor* descriptor);
std::string GetFieldConstantName(const FieldDescriptor* field);
@ -91,18 +83,6 @@ std::string GetOneofCaseName(const FieldDescriptor* descriptor);
int GetFixedSize(FieldDescriptor::Type type);
// Note that we wouldn't normally want to export this (we're not expecting
// it to be used outside libprotoc itself) but this exposes it for testing.
std::string PROTOC_EXPORT UnderscoresToCamelCase(const std::string& input,
bool cap_next_letter,
bool preserve_period);
inline std::string UnderscoresToCamelCase(const std::string& input, bool cap_next_letter) {
return UnderscoresToCamelCase(input, cap_next_letter, false);
}
std::string UnderscoresToPascalCase(const std::string& input);
// Note that we wouldn't normally want to export this (we're not expecting
// it to be used outside libprotoc itself) but this exposes it for testing.
std::string PROTOC_EXPORT GetEnumValueName(const std::string& enum_name,

@ -40,7 +40,7 @@
#include "google/protobuf/compiler/csharp/csharp_enum.h"
#include "google/protobuf/compiler/csharp/csharp_field_base.h"
#include "google/protobuf/compiler/csharp/csharp_helpers.h"
#include "google/protobuf/compiler/csharp/csharp_names.h"
#include "google/protobuf/compiler/csharp/names.h"
#include "google/protobuf/compiler/csharp/csharp_options.h"
#include "google/protobuf/descriptor.h"
#include "google/protobuf/descriptor.pb.h"

@ -38,7 +38,7 @@
#include "google/protobuf/compiler/csharp/csharp_field_base.h"
#include "google/protobuf/compiler/csharp/csharp_helpers.h"
#include "google/protobuf/compiler/csharp/csharp_message.h"
#include "google/protobuf/compiler/csharp/csharp_names.h"
#include "google/protobuf/compiler/csharp/names.h"
#include "google/protobuf/compiler/csharp/csharp_options.h"
#include "google/protobuf/descriptor.h"
#include "google/protobuf/descriptor.pb.h"

@ -35,7 +35,7 @@
#include "google/protobuf/compiler/code_generator.h"
#include "google/protobuf/descriptor.h"
#include "google/protobuf/compiler/csharp/csharp_helpers.h"
#include "google/protobuf/compiler/csharp/csharp_names.h"
#include "google/protobuf/compiler/csharp/names.h"
#include "google/protobuf/compiler/csharp/csharp_options.h"
#include "google/protobuf/descriptor.pb.h"
#include "google/protobuf/io/printer.h"

@ -0,0 +1,225 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// 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 Inc. 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 THE COPYRIGHT
// OWNER OR CONTRIBUTORS 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.
// Author: kenton@google.com (Kenton Varda)
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
#include "google/protobuf/compiler/csharp/names.h"
#include <string>
#include "absl/strings/str_replace.h"
#include "google/protobuf/compiler/csharp/names.h"
#include "google/protobuf/descriptor.pb.h"
// Must be last.
#include "google/protobuf/port_def.inc"
namespace google {
namespace protobuf {
namespace compiler {
namespace csharp {
namespace {
std::string StripDotProto(const std::string& proto_file) {
int lastindex = proto_file.find_last_of('.');
return proto_file.substr(0, lastindex);
}
// Returns the Pascal-cased last part of the proto file. For example,
// input of "google/protobuf/foo_bar.proto" would result in "FooBar".
std::string GetFileNameBase(const FileDescriptor* descriptor) {
std::string proto_file = descriptor->name();
int lastslash = proto_file.find_last_of('/');
std::string base = proto_file.substr(lastslash + 1);
return UnderscoresToPascalCase(StripDotProto(base));
}
std::string ToCSharpName(const std::string& name, const FileDescriptor* file) {
std::string result = GetFileNamespace(file);
if (!result.empty()) {
result += '.';
}
std::string classname;
if (file->package().empty()) {
classname = name;
} else {
// Strip the proto package from full_name since we've replaced it with
// the C# namespace.
classname = name.substr(file->package().size() + 1);
}
result += absl::StrReplaceAll(classname, {{".", ".Types."}});
return "global::" + result;
}
} // namespace
std::string GetFileNamespace(const FileDescriptor* descriptor) {
if (descriptor->options().has_csharp_namespace()) {
return descriptor->options().csharp_namespace();
}
return UnderscoresToCamelCase(descriptor->package(), true, true);
}
std::string GetClassName(const Descriptor* descriptor) {
return ToCSharpName(descriptor->full_name(), descriptor->file());
}
std::string GetClassName(const EnumDescriptor* descriptor) {
return ToCSharpName(descriptor->full_name(), descriptor->file());
}
std::string GetReflectionClassUnqualifiedName(const FileDescriptor* descriptor) {
// TODO: Detect collisions with existing messages,
// and append an underscore if necessary.
return GetFileNameBase(descriptor) + "Reflection";
}
std::string GetReflectionClassName(const FileDescriptor* descriptor) {
std::string result = GetFileNamespace(descriptor);
if (!result.empty()) {
result += '.';
}
result += GetReflectionClassUnqualifiedName(descriptor);
return "global::" + result;
}
std::string GetExtensionClassUnqualifiedName(const FileDescriptor* descriptor) {
// TODO: Detect collisions with existing messages,
// and append an underscore if necessary.
return GetFileNameBase(descriptor) + "Extensions";
}
std::string GetOutputFile(const FileDescriptor* descriptor,
const std::string file_extension,
const bool generate_directories,
const std::string base_namespace,
std::string* error) {
std::string relative_filename = GetFileNameBase(descriptor) + file_extension;
if (!generate_directories) {
return relative_filename;
}
std::string ns = GetFileNamespace(descriptor);
std::string namespace_suffix = ns;
if (!base_namespace.empty()) {
// Check that the base_namespace is either equal to or a leading part of
// the file namespace. This isn't just a simple prefix; "Foo.B" shouldn't
// be regarded as a prefix of "Foo.Bar". The simplest option is to add "."
// to both.
std::string extended_ns = ns + ".";
if (extended_ns.find(base_namespace + ".") != 0) {
*error = "Namespace " + ns + " is not a prefix namespace of base namespace " + base_namespace;
return ""; // This will be ignored, because we've set an error.
}
namespace_suffix = ns.substr(base_namespace.length());
if (namespace_suffix.find('.') == 0) {
namespace_suffix = namespace_suffix.substr(1);
}
}
std::string namespace_dir =
absl::StrReplaceAll(namespace_suffix, {{".", "/"}});
if (!namespace_dir.empty()) {
namespace_dir += "/";
}
return namespace_dir + relative_filename;
}
std::string UnderscoresToPascalCase(const std::string& input) {
return UnderscoresToCamelCase(input, true);
}
// TODO(jtattermusch): can we reuse a utility function?
std::string UnderscoresToCamelCase(const std::string& input,
bool cap_next_letter,
bool preserve_period) {
std::string result;
// Note: I distrust ctype.h due to locales.
for (int i = 0; i < input.size(); i++) {
if ('a' <= input[i] && input[i] <= 'z') {
if (cap_next_letter) {
result += input[i] + ('A' - 'a');
} else {
result += input[i];
}
cap_next_letter = false;
} else if ('A' <= input[i] && input[i] <= 'Z') {
if (i == 0 && !cap_next_letter) {
// Force first letter to lower-case unless explicitly told to
// capitalize it.
result += input[i] + ('a' - 'A');
} else {
// Capital letters after the first are left as-is.
result += input[i];
}
cap_next_letter = false;
} else if ('0' <= input[i] && input[i] <= '9') {
result += input[i];
cap_next_letter = true;
} else {
cap_next_letter = true;
if (input[i] == '.' && preserve_period) {
result += '.';
}
}
}
// Add a trailing "_" if the name should be altered.
if (input.size() > 0 && input[input.size() - 1] == '#') {
result += '_';
}
// https://github.com/protocolbuffers/protobuf/issues/8101
// To avoid generating invalid identifiers - if the input string
// starts with _<digit> (or multiple underscores then digit) then
// we need to preserve the underscore as an identifier cannot start
// with a digit.
// This check is being done after the loop rather than before
// to handle the case where there are multiple underscores before the
// first digit. We let them all be consumed so we can see if we would
// start with a digit.
// Note: not preserving leading underscores for all otherwise valid identifiers
// so as to not break anything that relies on the existing behaviour
if (result.size() > 0 && ('0' <= result[0] && result[0] <= '9')
&& input.size() > 0 && input[0] == '_')
{
result.insert(0, 1, '_');
}
return result;
}
} // namespace csharp
} // namespace compiler
} // namespace protobuf
} // namespace google
#include "google/protobuf/port_undef.inc"

@ -71,9 +71,35 @@ std::string PROTOC_EXPORT GetClassName(const Descriptor* descriptor);
// descriptor != NULL
//
// Returns:
// The fully-qualified name of the C# class that provides
// access to the file descriptor. Proto compiler generates
// The fully-qualified C# enum class name.
std::string GetClassName(const EnumDescriptor* descriptor);
// Requires:
// descriptor != NULL
//
// Returns:
// The unqualified name of the C# class that provides access to the file
// descriptor. Proto compiler generates
// such class for each .proto file processed.
std::string GetReflectionClassUnqualifiedName(const FileDescriptor* descriptor);
// Gets unqualified name of the extension class
// Requires:
// descriptor != NULL
//
// Returns:
// The unqualified name of the generated C# extensions class that provide
// access to extensions. Proto compiler generates such class for each
// .proto file processed that contains extensions.
std::string GetExtensionClassUnqualifiedName(const FileDescriptor* descriptor);
// Requires:
// descriptor != NULL
//
// Returns:
// The fully-qualified name of the C# class that provides access to the file
// descriptor. Proto compiler generates such class for each .proto file
// processed.
std::string PROTOC_EXPORT
GetReflectionClassName(const FileDescriptor* descriptor);
@ -97,6 +123,18 @@ std::string PROTOC_EXPORT GetOutputFile(const FileDescriptor* descriptor,
const std::string base_namespace,
std::string* error);
std::string UnderscoresToPascalCase(const std::string& input);
// Note that we wouldn't normally want to export this (we're not expecting
// it to be used outside libprotoc itself) but this exposes it for testing.
std::string PROTOC_EXPORT UnderscoresToCamelCase(const std::string& input,
bool cap_next_letter,
bool preserve_period);
inline std::string UnderscoresToCamelCase(const std::string& input, bool cap_next_letter) {
return UnderscoresToCamelCase(input, cap_next_letter, false);
}
} // namespace csharp
} // namespace compiler
} // namespace protobuf

@ -6,6 +6,41 @@ load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test")
load("@rules_pkg//:mappings.bzl", "pkg_files", "strip_prefix")
load("//build_defs:cpp_opts.bzl", "COPTS")
cc_library(
name = "names",
hdrs = ["names.h"],
copts = COPTS,
include_prefix = "google/protobuf/compiler/java",
visibility = ["//visibility:public"],
deps = [
":names_internal",
"//src/google/protobuf:protobuf_nowkt",
],
)
cc_library(
name = "names_internal",
hdrs = [
"helpers.h",
"name_resolver.h",
"names.h",
"options.h",
],
srcs = [
"helpers.cc",
"name_resolver.cc",
"names.cc",
],
copts = COPTS,
include_prefix = "google/protobuf/compiler/java",
visibility = ["//pkg:__pkg__"],
deps = [
"//src/google/protobuf/compiler:code_generator",
"//src/google/protobuf:protobuf_nowkt",
"@com_google_absl//absl/container:flat_hash_set",
],
)
cc_library(
name = "java",
srcs = [
@ -21,7 +56,6 @@ cc_library(
"file.cc",
"generator.cc",
"generator_factory.cc",
"helpers.cc",
"kotlin_generator.cc",
"map_field.cc",
"map_field_lite.cc",
@ -32,7 +66,6 @@ cc_library(
"message_field_lite.cc",
"message_lite.cc",
"message_serialization.cc",
"name_resolver.cc",
"primitive_field.cc",
"primitive_field_lite.cc",
"service.cc",
@ -53,7 +86,6 @@ cc_library(
"file.h",
"generator.h",
"generator_factory.h",
"helpers.h",
"kotlin_generator.h",
"map_field.h",
"map_field_lite.h",
@ -64,9 +96,6 @@ cc_library(
"message_field_lite.h",
"message_lite.h",
"message_serialization.h",
"name_resolver.h",
"names.h",
"options.h",
"primitive_field.h",
"primitive_field_lite.h",
"service.h",
@ -81,6 +110,8 @@ cc_library(
"//src/google/protobuf/compiler:__pkg__",
],
deps = [
":names_internal",
":names",
"//src/google/protobuf:protobuf_nowkt",
"//src/google/protobuf/compiler:code_generator",
"@com_google_absl//absl/container:flat_hash_set",

@ -131,10 +131,10 @@ void Context::InitializeFieldGeneratorInfoForFields(
std::vector<std::string> conflict_reason(fields.size());
for (int i = 0; i < fields.size(); ++i) {
const FieldDescriptor* field = fields[i];
const std::string& name = UnderscoresToCapitalizedCamelCase(field);
const std::string& name = CapitalizedFieldName(field);
for (int j = i + 1; j < fields.size(); ++j) {
const FieldDescriptor* other = fields[j];
const std::string& other_name = UnderscoresToCapitalizedCamelCase(other);
const std::string& other_name = CapitalizedFieldName(other);
if (name == other_name) {
is_conflict[i] = is_conflict[j] = true;
conflict_reason[i] = conflict_reason[j] =
@ -155,7 +155,7 @@ void Context::InitializeFieldGeneratorInfoForFields(
const FieldDescriptor* field = fields[i];
FieldGeneratorInfo info;
info.name = CamelCaseFieldName(field);
info.capitalized_name = UnderscoresToCapitalizedCamelCase(field);
info.capitalized_name = CapitalizedFieldName(field);
// For fields conflicting with some other fields, we append the field
// number to their field names in generated code to avoid conflicts.
if (is_conflict[i]) {

@ -35,6 +35,7 @@
#include <vector>
#include "absl/container/flat_hash_map.h"
#include "google/protobuf/compiler/java/helpers.h"
#include "google/protobuf/compiler/java/options.h"
#include "google/protobuf/port.h"
@ -106,6 +107,20 @@ class Context {
Options options_;
};
template <typename Descriptor>
void MaybePrintGeneratedAnnotation(Context* context, io::Printer* printer,
Descriptor* descriptor, bool immutable,
const std::string& suffix = "") {
if (IsOwnFile(descriptor, immutable)) {
PrintGeneratedAnnotation(printer, '$',
context->options().annotate_code
? AnnotationFileName(descriptor, suffix)
: "",
context->options());
}
}
} // namespace java
} // namespace compiler
} // namespace protobuf

@ -51,7 +51,6 @@
#include "absl/strings/string_view.h"
#include "absl/strings/substitute.h"
#include "google/protobuf/compiler/java/name_resolver.h"
#include "google/protobuf/compiler/java/names.h"
#include "google/protobuf/descriptor.pb.h"
// Must be last.
@ -70,75 +69,6 @@ const char kThickSeparator[] =
const char kThinSeparator[] =
"// -------------------------------------------------------------------\n";
namespace {
const char* DefaultPackage(Options options) {
return options.opensource_runtime ? "" : "com.google.protos";
}
bool IsReservedName(absl::string_view name) {
static const auto& kReservedNames =
*new absl::flat_hash_set<absl::string_view>({
"abstract", "assert", "boolean", "break", "byte",
"case", "catch", "char", "class", "const",
"continue", "default", "do", "double", "else",
"enum", "extends", "final", "finally", "float",
"for", "goto", "if", "implements", "import",
"instanceof", "int", "interface", "long", "native",
"new", "package", "private", "protected", "public",
"return", "short", "static", "strictfp", "super",
"switch", "synchronized", "this", "throw", "throws",
"transient", "try", "void", "volatile", "while",
});
return kReservedNames.contains(name);
}
bool IsForbidden(const std::string& field_name) {
// Names that should be avoided (in UpperCamelCase format).
// Using them will cause the compiler to generate accessors whose names
// collide with methods defined in base classes.
// Keep this list in sync with specialFieldNames in
// java/core/src/main/java/com/google/protobuf/DescriptorMessageInfoFactory.java
static const auto& kForbiddenNames =
*new absl::flat_hash_set<absl::string_view>({
// java.lang.Object:
"Class",
// com.google.protobuf.MessageLiteOrBuilder:
"DefaultInstanceForType",
// com.google.protobuf.MessageLite:
"ParserForType",
"SerializedSize",
// com.google.protobuf.MessageOrBuilder:
"AllFields",
"DescriptorForType",
"InitializationErrorString",
"UnknownFields",
// obsolete. kept for backwards compatibility of generated code
"CachedSize",
});
return kForbiddenNames.contains(UnderscoresToCamelCase(field_name, true));
}
std::string FieldName(const FieldDescriptor* field) {
std::string field_name;
// Groups are hacky: The name of the field is just the lower-cased name
// of the group type. In Java, though, we would like to retain the original
// capitalization of the type name.
if (GetType(field) == FieldDescriptor::TYPE_GROUP) {
field_name = field->message_type()->name();
} else {
field_name = field->name();
}
if (IsForbidden(field_name)) {
// Append a trailing "#" to indicate that the name should be decorated to
// avoid collision with other names.
field_name += "#";
}
return field_name;
}
} // namespace
void PrintGeneratedAnnotation(io::Printer* printer, char delimiter,
const std::string& annotation_file,
Options options) {
@ -236,30 +166,6 @@ std::string ToCamelCase(const std::string& input, bool lower_first) {
return result;
}
std::string UnderscoresToCamelCase(const FieldDescriptor* field) {
return UnderscoresToCamelCase(FieldName(field), false);
}
std::string UnderscoresToCapitalizedCamelCase(const FieldDescriptor* field) {
return UnderscoresToCamelCase(FieldName(field), true);
}
std::string CapitalizedFieldName(const FieldDescriptor* field) {
return UnderscoresToCapitalizedCamelCase(field);
}
std::string UnderscoresToCamelCase(const MethodDescriptor* method) {
return UnderscoresToCamelCase(method->name(), false);
}
std::string UnderscoresToCamelCaseCheckReserved(const FieldDescriptor* field) {
std::string name = UnderscoresToCamelCase(field);
if (IsReservedName(name)) {
return name + "_";
}
return name;
}
// Names that should be avoided as field names in Kotlin.
// All Kotlin hard keywords are in this list.
bool IsForbiddenKotlin(absl::string_view field_name) {
@ -305,54 +211,12 @@ std::string FileClassName(const FileDescriptor* file, bool immutable) {
return ClassNameResolver().GetFileClassName(file, immutable);
}
std::string FileJavaPackage(const FileDescriptor* file, bool immutable,
Options options) {
std::string result;
if (file->options().has_java_package()) {
result = file->options().java_package();
} else {
result = DefaultPackage(options);
if (!file->package().empty()) {
if (!result.empty()) result += '.';
result += file->package();
}
}
return result;
}
std::string FileJavaPackage(const FileDescriptor* file, Options options) {
return FileJavaPackage(file, true /* immutable */, options);
}
std::string JavaPackageToDir(std::string package_name) {
std::string package_dir = absl::StrReplaceAll(package_name, {{".", "/"}});
if (!package_dir.empty()) package_dir += "/";
return package_dir;
}
std::string ClassName(const Descriptor* descriptor) {
ClassNameResolver name_resolver;
return name_resolver.GetClassName(descriptor, true);
}
std::string ClassName(const EnumDescriptor* descriptor) {
ClassNameResolver name_resolver;
return name_resolver.GetClassName(descriptor, true);
}
std::string ClassName(const ServiceDescriptor* descriptor) {
ClassNameResolver name_resolver;
return name_resolver.GetClassName(descriptor, true);
}
std::string ClassName(const FileDescriptor* descriptor) {
ClassNameResolver name_resolver;
return name_resolver.GetClassName(descriptor, true);
}
std::string ExtraMessageInterfaces(const Descriptor* descriptor) {
std::string interfaces = "// @@protoc_insertion_point(message_implements:" +
descriptor->full_name() + ")";

@ -41,7 +41,7 @@
#include "google/protobuf/io/printer.h"
#include "google/protobuf/descriptor.h"
#include "absl/strings/string_view.h"
#include "google/protobuf/compiler/java/context.h"
#include "google/protobuf/compiler/java/names.h"
#include "google/protobuf/compiler/java/options.h"
#include "google/protobuf/descriptor.pb.h"
@ -84,22 +84,6 @@ void PrintEnumVerifierLogic(io::Printer* printer,
// first letter.
std::string ToCamelCase(const std::string& input, bool lower_first);
// Converts a name to camel-case. If cap_first_letter is true, capitalize the
// first letter.
std::string UnderscoresToCamelCase(const std::string& name,
bool cap_first_letter);
// Converts the field's name to camel-case, e.g. "foo_bar_baz" becomes
// "fooBarBaz" or "FooBarBaz", respectively.
std::string UnderscoresToCamelCase(const FieldDescriptor* field);
std::string UnderscoresToCapitalizedCamelCase(const FieldDescriptor* field);
// Similar, but for method names. (Typically, this merely has the effect
// of lower-casing the first letter of the name.)
std::string UnderscoresToCamelCase(const MethodDescriptor* method);
// Same as UnderscoresToCamelCase, but checks for reserved keywords
std::string UnderscoresToCamelCaseCheckReserved(const FieldDescriptor* field);
// Similar to UnderscoresToCamelCase, but guarantees that the result is a
// complete Java identifier by adding a _ if needed.
std::string CamelCaseFieldName(const FieldDescriptor* field);
@ -205,19 +189,6 @@ std::string AnnotationFileName(const Descriptor* descriptor,
return descriptor->name() + suffix + ".java.pb.meta";
}
template <typename Descriptor>
void MaybePrintGeneratedAnnotation(Context* context, io::Printer* printer,
Descriptor* descriptor, bool immutable,
const std::string& suffix = "") {
if (IsOwnFile(descriptor, immutable)) {
PrintGeneratedAnnotation(printer, '$',
context->options().annotate_code
? AnnotationFileName(descriptor, suffix)
: "",
context->options());
}
}
// Get the unqualified name that should be used for a field's field
// number constant.
std::string FieldConstantName(const FieldDescriptor* field);

@ -0,0 +1,194 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// 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 Inc. 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 THE COPYRIGHT
// OWNER OR CONTRIBUTORS 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.
// Author: kenton@google.com (Kenton Varda)
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
#include "google/protobuf/compiler/java/names.h"
#include <string>
#include "absl/container/flat_hash_set.h"
#include "google/protobuf/compiler/java/helpers.h"
#include "google/protobuf/compiler/java/name_resolver.h"
#include "google/protobuf/compiler/java/names.h"
#include "google/protobuf/compiler/java/options.h"
#include "google/protobuf/descriptor.pb.h"
// Must be last.
#include "google/protobuf/port_def.inc"
namespace google {
namespace protobuf {
namespace compiler {
namespace java {
namespace {
const char* DefaultPackage(Options options) {
return options.opensource_runtime ? "" : "com.google.protos";
}
bool IsReservedName(absl::string_view name) {
static const auto& kReservedNames =
*new absl::flat_hash_set<absl::string_view>({
"abstract", "assert", "boolean", "break", "byte",
"case", "catch", "char", "class", "const",
"continue", "default", "do", "double", "else",
"enum", "extends", "final", "finally", "float",
"for", "goto", "if", "implements", "import",
"instanceof", "int", "interface", "long", "native",
"new", "package", "private", "protected", "public",
"return", "short", "static", "strictfp", "super",
"switch", "synchronized", "this", "throw", "throws",
"transient", "try", "void", "volatile", "while",
});
return kReservedNames.contains(name);
}
bool IsForbidden(const std::string& field_name) {
// Names that should be avoided (in UpperCamelCase format).
// Using them will cause the compiler to generate accessors whose names
// collide with methods defined in base classes.
// Keep this list in sync with specialFieldNames in
// java/core/src/main/java/com/google/protobuf/DescriptorMessageInfoFactory.java
static const auto& kForbiddenNames =
*new absl::flat_hash_set<absl::string_view>({
// java.lang.Object:
"Class",
// com.google.protobuf.MessageLiteOrBuilder:
"DefaultInstanceForType",
// com.google.protobuf.MessageLite:
"ParserForType",
"SerializedSize",
// com.google.protobuf.MessageOrBuilder:
"AllFields",
"DescriptorForType",
"InitializationErrorString",
"UnknownFields",
// obsolete. kept for backwards compatibility of generated code
"CachedSize",
});
return kForbiddenNames.contains(UnderscoresToCamelCase(field_name, true));
}
std::string FieldName(const FieldDescriptor* field) {
std::string field_name;
// Groups are hacky: The name of the field is just the lower-cased name
// of the group type. In Java, though, we would like to retain the original
// capitalization of the type name.
if (GetType(field) == FieldDescriptor::TYPE_GROUP) {
field_name = field->message_type()->name();
} else {
field_name = field->name();
}
if (IsForbidden(field_name)) {
// Append a trailing "#" to indicate that the name should be decorated to
// avoid collision with other names.
field_name += "#";
}
return field_name;
}
} // namespace
std::string ClassName(const Descriptor* descriptor) {
ClassNameResolver name_resolver;
return name_resolver.GetClassName(descriptor, true);
}
std::string ClassName(const EnumDescriptor* descriptor) {
ClassNameResolver name_resolver;
return name_resolver.GetClassName(descriptor, true);
}
std::string ClassName(const ServiceDescriptor* descriptor) {
ClassNameResolver name_resolver;
return name_resolver.GetClassName(descriptor, true);
}
std::string ClassName(const FileDescriptor* descriptor) {
ClassNameResolver name_resolver;
return name_resolver.GetClassName(descriptor, true);
}
std::string FileJavaPackage(const FileDescriptor* file, bool immutable,
Options options) {
std::string result;
if (file->options().has_java_package()) {
result = file->options().java_package();
} else {
result = DefaultPackage(options);
if (!file->package().empty()) {
if (!result.empty()) result += '.';
result += file->package();
}
}
return result;
}
std::string FileJavaPackage(const FileDescriptor* file, Options options) {
return FileJavaPackage(file, true /* immutable */, options);
}
std::string CapitalizedFieldName(const FieldDescriptor* field) {
return UnderscoresToCamelCase(FieldName(field), true);
}
std::string UnderscoresToCamelCase(const FieldDescriptor* field) {
return UnderscoresToCamelCase(FieldName(field), false);
}
std::string UnderscoresToCapitalizedCamelCase(const FieldDescriptor* field) {
return UnderscoresToCamelCase(FieldName(field), true);
}
std::string UnderscoresToCamelCase(const MethodDescriptor* method) {
return UnderscoresToCamelCase(method->name(), false);
}
std::string UnderscoresToCamelCaseCheckReserved(const FieldDescriptor* field) {
std::string name = UnderscoresToCamelCase(field);
if (IsReservedName(name)) {
return name + "_";
}
return name;
}
} // namespace java
} // namespace compiler
} // namespace protobuf
} // namespace google
#include "google/protobuf/port_undef.inc"

@ -40,6 +40,7 @@
#include <string>
#include "google/protobuf/descriptor.h"
#include "google/protobuf/compiler/java/options.h"
namespace google {
@ -96,6 +97,31 @@ std::string FileJavaPackage(const FileDescriptor* descriptor,
// Capitalized camel case name field name.
std::string CapitalizedFieldName(const FieldDescriptor* descriptor);
// Returns:
// Converts a name to camel-case. If cap_first_letter is true, capitalize the
// first letter.
std::string UnderscoresToCamelCase(const std::string& name,
bool cap_first_letter);
// Requires:
// field != NULL
// Returns:
// Converts the field's name to camel-case, e.g. "foo_bar_baz" becomes
// "fooBarBaz" or "FooBarBaz", respectively.
std::string UnderscoresToCamelCase(const FieldDescriptor* field);
// Requires:
// method != NULL
// Returns:
// Similar, but for method names. (Typically, this merely has the effect
// of lower-casing the first letter of the name.)
std::string UnderscoresToCamelCase(const MethodDescriptor* method);
// Requires:
// field != NULL
// Returns:
// Same as UnderscoresToCamelCase, but checks for reserved keywords
std::string UnderscoresToCamelCaseCheckReserved(const FieldDescriptor* field);
} // namespace java
} // namespace compiler
} // namespace protobuf

@ -6,6 +6,35 @@ load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test")
load("@rules_pkg//:mappings.bzl", "pkg_files", "strip_prefix")
load("//build_defs:cpp_opts.bzl", "COPTS")
cc_library(
name = "names",
hdrs = ["names.h"],
copts = COPTS,
include_prefix = "google/protobuf/compiler/objectivec",
visibility = ["//visibility:public"],
deps = [
":names_internal",
],
)
cc_library(
name = "names_internal",
hdrs = [
"names.h",
"objectivec_nsobject_methods.h",
],
srcs = [
"names.cc",
],
copts = COPTS,
include_prefix = "google/protobuf/compiler/objectivec",
visibility = ["//pkg:__pkg__"],
deps = [
"//src/google/protobuf/compiler:code_generator",
"//src/google/protobuf:protobuf_nowkt",
],
)
cc_library(
name = "objectivec",
srcs = [
@ -15,7 +44,6 @@ cc_library(
"objectivec_field.cc",
"objectivec_file.cc",
"objectivec_generator.cc",
"objectivec_helpers.cc",
"objectivec_map_field.cc",
"objectivec_message.cc",
"objectivec_message_field.cc",
@ -33,7 +61,6 @@ cc_library(
"objectivec_map_field.h",
"objectivec_message.h",
"objectivec_message_field.h",
"objectivec_nsobject_methods.h",
"objectivec_oneof.h",
"objectivec_options.h",
"objectivec_primitive_field.h",
@ -45,6 +72,7 @@ cc_library(
"//src/google/protobuf/compiler:__pkg__",
],
deps = [
":names",
"//src/google/protobuf:protobuf_nowkt",
"//src/google/protobuf/compiler:code_generator",
"@com_google_absl//absl/strings",

@ -49,7 +49,7 @@
#include "absl/strings/str_replace.h"
#include "absl/strings/str_split.h"
#include "absl/strings/strip.h"
#include "google/protobuf/compiler/objectivec/objectivec_helpers.h"
#include "google/protobuf/compiler/objectivec/names.h"
#include "google/protobuf/compiler/objectivec/objectivec_nsobject_methods.h"
#include "google/protobuf/descriptor.pb.h"
#include "google/protobuf/io/coded_stream.h"

@ -0,0 +1,363 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// 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 Inc. 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 THE COPYRIGHT
// OWNER OR CONTRIBUTORS 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.
// Helper functions for generating ObjectiveC code.
#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_NAMES_H__
#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_NAMES_H__
#include <string>
#include <vector>
#include "google/protobuf/descriptor.h"
#include "google/protobuf/descriptor.pb.h"
#include "google/protobuf/io/zero_copy_stream.h"
// clang-format off
#include "google/protobuf/port_def.inc"
// clang-format on
namespace google {
namespace protobuf {
namespace compiler {
namespace objectivec {
// Get/Set the path to a file to load for objc class prefix lookups.
std::string PROTOC_EXPORT GetPackageToPrefixMappingsPath();
void PROTOC_EXPORT SetPackageToPrefixMappingsPath(
const std::string& file_path);
// Get/Set if the proto package should be used to make the default prefix for
// symbols. This will then impact most of the type naming apis below. It is done
// as a global to not break any other generator reusing the methods since they
// are exported.
bool PROTOC_EXPORT UseProtoPackageAsDefaultPrefix();
void PROTOC_EXPORT SetUseProtoPackageAsDefaultPrefix(bool on_or_off);
// Get/Set the path to a file to load as exceptions when
// `UseProtoPackageAsDefaultPrefix()` is `true`. An empty string means there
// should be no exceptions.
std::string PROTOC_EXPORT GetProtoPackagePrefixExceptionList();
void PROTOC_EXPORT SetProtoPackagePrefixExceptionList(
const std::string& file_path);
// Get/Set a prefix to add before the prefix generated from the package name.
// This is only used when UseProtoPackageAsDefaultPrefix() is True.
std::string PROTOC_EXPORT GetForcedPackagePrefix();
void PROTOC_EXPORT SetForcedPackagePrefix(const std::string& prefix);
// Generator Prefix Validation Options (see objectivec_generator.cc for a
// description of each):
struct Options {
Options();
std::string expected_prefixes_path;
std::vector<std::string> expected_prefixes_suppressions;
bool prefixes_must_be_registered;
bool require_prefixes;
};
// Escape C++ trigraphs by escaping question marks to "\?".
std::string PROTOC_EXPORT EscapeTrigraphs(absl::string_view to_escape);
// Remove white space from either end of a absl::string_view.
void PROTOC_EXPORT TrimWhitespace(absl::string_view* input);
// Returns true if the name requires a ns_returns_not_retained attribute applied
// to it.
bool PROTOC_EXPORT IsRetainedName(const std::string& name);
// Returns true if the name starts with "init" and will need to have special
// handling under ARC.
bool PROTOC_EXPORT IsInitName(const std::string& name);
// Returns true if the name requires a cf_returns_not_retained attribute applied
// to it.
bool PROTOC_EXPORT IsCreateName(const std::string& name);
// Gets the objc_class_prefix or the prefix made from the proto package.
std::string PROTOC_EXPORT FileClassPrefix(const FileDescriptor* file);
// Gets the path of the file we're going to generate (sans the .pb.h
// extension). The path will be dependent on the objectivec package
// declared in the proto package.
std::string PROTOC_EXPORT FilePath(const FileDescriptor* file);
// Just like FilePath(), but without the directory part.
std::string PROTOC_EXPORT FilePathBasename(const FileDescriptor* file);
// Gets the name of the root class we'll generate in the file. This class
// is not meant for external consumption, but instead contains helpers that
// the rest of the classes need
std::string PROTOC_EXPORT FileClassName(const FileDescriptor* file);
// These return the fully-qualified class name corresponding to the given
// descriptor.
std::string PROTOC_EXPORT ClassName(const Descriptor* descriptor);
std::string PROTOC_EXPORT ClassName(const Descriptor* descriptor,
std::string* out_suffix_added);
std::string PROTOC_EXPORT EnumName(const EnumDescriptor* descriptor);
// Returns the fully-qualified name of the enum value corresponding to the
// the descriptor.
std::string PROTOC_EXPORT EnumValueName(const EnumValueDescriptor* descriptor);
// Returns the name of the enum value corresponding to the descriptor.
std::string PROTOC_EXPORT EnumValueShortName(const EnumValueDescriptor* descriptor);
// Reverse what an enum does.
std::string PROTOC_EXPORT UnCamelCaseEnumShortName(const std::string& name);
// Returns the name to use for the extension (used as the method off the file's
// Root class).
std::string PROTOC_EXPORT ExtensionMethodName(const FieldDescriptor* descriptor);
// Returns the transformed field name.
std::string PROTOC_EXPORT FieldName(const FieldDescriptor* field);
std::string PROTOC_EXPORT FieldNameCapitalized(const FieldDescriptor* field);
// Returns the transformed oneof name.
std::string PROTOC_EXPORT OneofEnumName(const OneofDescriptor* descriptor);
std::string PROTOC_EXPORT OneofName(const OneofDescriptor* descriptor);
std::string PROTOC_EXPORT OneofNameCapitalized(const OneofDescriptor* descriptor);
// Returns a symbol that can be used in C code to refer to an Objective C
// class without initializing the class.
std::string PROTOC_EXPORT ObjCClass(const std::string& class_name);
// Declares an Objective C class without initializing the class so that it can
// be refrerred to by ObjCClass.
std::string PROTOC_EXPORT ObjCClassDeclaration(const std::string& class_name);
inline bool HasPreservingUnknownEnumSemantics(const FileDescriptor* file) {
return file->syntax() == FileDescriptor::SYNTAX_PROTO3;
}
inline bool IsMapEntryMessage(const Descriptor* descriptor) {
return descriptor->options().map_entry();
}
// Reverse of the above.
std::string PROTOC_EXPORT UnCamelCaseFieldName(const std::string& name,
const FieldDescriptor* field);
enum ObjectiveCType {
OBJECTIVECTYPE_INT32,
OBJECTIVECTYPE_UINT32,
OBJECTIVECTYPE_INT64,
OBJECTIVECTYPE_UINT64,
OBJECTIVECTYPE_FLOAT,
OBJECTIVECTYPE_DOUBLE,
OBJECTIVECTYPE_BOOLEAN,
OBJECTIVECTYPE_STRING,
OBJECTIVECTYPE_DATA,
OBJECTIVECTYPE_ENUM,
OBJECTIVECTYPE_MESSAGE
};
enum FlagType {
FLAGTYPE_DESCRIPTOR_INITIALIZATION,
FLAGTYPE_EXTENSION,
FLAGTYPE_FIELD
};
template <class TDescriptor>
std::string GetOptionalDeprecatedAttribute(const TDescriptor* descriptor,
const FileDescriptor* file = NULL,
bool preSpace = true,
bool postNewline = false) {
bool isDeprecated = descriptor->options().deprecated();
// The file is only passed when checking Messages & Enums, so those types
// get tagged. At the moment, it doesn't seem to make sense to tag every
// field or enum value with when the file is deprecated.
bool isFileLevelDeprecation = false;
if (!isDeprecated && file) {
isFileLevelDeprecation = file->options().deprecated();
isDeprecated = isFileLevelDeprecation;
}
if (isDeprecated) {
std::string message;
const FileDescriptor* sourceFile = descriptor->file();
if (isFileLevelDeprecation) {
message = sourceFile->name() + " is deprecated.";
} else {
message = descriptor->full_name() + " is deprecated (see " +
sourceFile->name() + ").";
}
std::string result = std::string("GPB_DEPRECATED_MSG(\"") + message + "\")";
if (preSpace) {
result.insert(0, " ");
}
if (postNewline) {
result.append("\n");
}
return result;
} else {
return "";
}
}
std::string PROTOC_EXPORT GetCapitalizedType(const FieldDescriptor* field);
ObjectiveCType PROTOC_EXPORT
GetObjectiveCType(FieldDescriptor::Type field_type);
inline ObjectiveCType GetObjectiveCType(const FieldDescriptor* field) {
return GetObjectiveCType(field->type());
}
bool PROTOC_EXPORT IsPrimitiveType(const FieldDescriptor* field);
bool PROTOC_EXPORT IsReferenceType(const FieldDescriptor* field);
std::string PROTOC_EXPORT
GPBGenericValueFieldName(const FieldDescriptor* field);
std::string PROTOC_EXPORT DefaultValue(const FieldDescriptor* field);
bool PROTOC_EXPORT HasNonZeroDefaultValue(const FieldDescriptor* field);
std::string PROTOC_EXPORT
BuildFlagsString(const FlagType type, const std::vector<std::string>& strings);
// Builds HeaderDoc/appledoc style comments out of the comments in the .proto
// file.
std::string PROTOC_EXPORT BuildCommentsString(const SourceLocation& location,
bool prefer_single_line);
// The name the commonly used by the library when built as a framework.
// This lines up to the name used in the CocoaPod.
extern PROTOC_EXPORT const char* const ProtobufLibraryFrameworkName;
// Returns the CPP symbol name to use as the gate for framework style imports
// for the given framework name to use.
std::string PROTOC_EXPORT
ProtobufFrameworkImportSymbol(const std::string& framework_name);
// Checks if the file is one of the proto's bundled with the library.
bool PROTOC_EXPORT
IsProtobufLibraryBundledProtoFile(const FileDescriptor* file);
// Checks the prefix for the given files and outputs any warnings as needed. If
// there are flat out errors, then out_error is filled in with the first error
// and the result is false.
bool PROTOC_EXPORT ValidateObjCClassPrefixes(
const std::vector<const FileDescriptor*>& files,
const Options& validation_options, std::string* out_error);
// Same was the other ValidateObjCClassPrefixes() calls, but the options all
// come from the environment variables.
bool PROTOC_EXPORT ValidateObjCClassPrefixes(
const std::vector<const FileDescriptor*>& files, std::string* out_error);
// Generate decode data needed for ObjC's GPBDecodeTextFormatName() to transform
// the input into the expected output.
class PROTOC_EXPORT TextFormatDecodeData {
public:
TextFormatDecodeData();
~TextFormatDecodeData();
TextFormatDecodeData(const TextFormatDecodeData&) = delete;
TextFormatDecodeData& operator=(const TextFormatDecodeData&) = delete;
void AddString(int32_t key, const std::string& input_for_decode,
const std::string& desired_output);
size_t num_entries() const { return entries_.size(); }
std::string Data() const;
static std::string DecodeDataForString(const std::string& input_for_decode,
const std::string& desired_output);
private:
typedef std::pair<int32_t, std::string> DataEntry;
std::vector<DataEntry> entries_;
};
// Helper for parsing simple files.
class PROTOC_EXPORT LineConsumer {
public:
LineConsumer();
virtual ~LineConsumer();
virtual bool ConsumeLine(const absl::string_view& line, std::string* out_error) = 0;
};
bool PROTOC_EXPORT ParseSimpleFile(const std::string& path,
LineConsumer* line_consumer,
std::string* out_error);
bool PROTOC_EXPORT ParseSimpleStream(io::ZeroCopyInputStream& input_stream,
const std::string& stream_name,
LineConsumer* line_consumer,
std::string* out_error);
// Helper class for parsing framework import mappings and generating
// import statements.
class PROTOC_EXPORT ImportWriter {
public:
ImportWriter(const std::string& generate_for_named_framework,
const std::string& named_framework_to_proto_path_mappings_path,
const std::string& runtime_import_prefix,
bool include_wkt_imports);
~ImportWriter();
void AddFile(const FileDescriptor* file, const std::string& header_extension);
void Print(io::Printer* printer) const;
static void PrintRuntimeImports(io::Printer* printer,
const std::vector<std::string>& header_to_import,
const std::string& runtime_import_prefix,
bool default_cpp_symbol = false);
private:
class ProtoFrameworkCollector : public LineConsumer {
public:
ProtoFrameworkCollector(std::map<std::string, std::string>* inout_proto_file_to_framework_name)
: map_(inout_proto_file_to_framework_name) {}
virtual bool ConsumeLine(const absl::string_view& line, std::string* out_error) override;
private:
std::map<std::string, std::string>* map_;
};
void ParseFrameworkMappings();
const std::string generate_for_named_framework_;
const std::string named_framework_to_proto_path_mappings_path_;
const std::string runtime_import_prefix_;
const bool include_wkt_imports_;
std::map<std::string, std::string> proto_file_to_framework_name_;
bool need_to_parse_mapping_file_;
std::vector<std::string> protobuf_imports_;
std::vector<std::string> other_framework_imports_;
std::vector<std::string> other_imports_;
};
} // namespace objectivec
} // namespace compiler
} // namespace protobuf
} // namespace google
#include "google/protobuf/port_undef.inc"
#endif // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_NAMES_H__

@ -33,12 +33,7 @@
#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_HELPERS_H__
#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_HELPERS_H__
#include <string>
#include <vector>
#include "google/protobuf/descriptor.h"
#include "google/protobuf/descriptor.pb.h"
#include "google/protobuf/io/zero_copy_stream.h"
#include "google/protobuf/compiler/objectivec/names.h"
// clang-format off
#include "google/protobuf/port_def.inc"
@ -49,309 +44,8 @@ namespace protobuf {
namespace compiler {
namespace objectivec {
// Get/Set the path to a file to load for objc class prefix lookups.
std::string PROTOC_EXPORT GetPackageToPrefixMappingsPath();
void PROTOC_EXPORT SetPackageToPrefixMappingsPath(
const std::string& file_path);
// Get/Set if the proto package should be used to make the default prefix for
// symbols. This will then impact most of the type naming apis below. It is done
// as a global to not break any other generator reusing the methods since they
// are exported.
bool PROTOC_EXPORT UseProtoPackageAsDefaultPrefix();
void PROTOC_EXPORT SetUseProtoPackageAsDefaultPrefix(bool on_or_off);
// Get/Set the path to a file to load as exceptions when
// `UseProtoPackageAsDefaultPrefix()` is `true`. An empty string means there
// should be no exceptions.
std::string PROTOC_EXPORT GetProtoPackagePrefixExceptionList();
void PROTOC_EXPORT SetProtoPackagePrefixExceptionList(
const std::string& file_path);
// Get/Set a prefix to add before the prefix generated from the package name.
// This is only used when UseProtoPackageAsDefaultPrefix() is True.
std::string PROTOC_EXPORT GetForcedPackagePrefix();
void PROTOC_EXPORT SetForcedPackagePrefix(const std::string& prefix);
// Generator Prefix Validation Options (see objectivec_generator.cc for a
// description of each):
struct Options {
Options();
std::string expected_prefixes_path;
std::vector<std::string> expected_prefixes_suppressions;
bool prefixes_must_be_registered;
bool require_prefixes;
};
// Escape C++ trigraphs by escaping question marks to "\?".
std::string PROTOC_EXPORT EscapeTrigraphs(absl::string_view to_escape);
// Remove white space from either end of a absl::string_view.
void PROTOC_EXPORT TrimWhitespace(absl::string_view* input);
// Returns true if the name requires a ns_returns_not_retained attribute applied
// to it.
bool PROTOC_EXPORT IsRetainedName(const std::string& name);
// Returns true if the name starts with "init" and will need to have special
// handling under ARC.
bool PROTOC_EXPORT IsInitName(const std::string& name);
// Returns true if the name requires a cf_returns_not_retained attribute applied
// to it.
bool PROTOC_EXPORT IsCreateName(const std::string& name);
// Gets the objc_class_prefix or the prefix made from the proto package.
std::string PROTOC_EXPORT FileClassPrefix(const FileDescriptor* file);
// Gets the path of the file we're going to generate (sans the .pb.h
// extension). The path will be dependent on the objectivec package
// declared in the proto package.
std::string PROTOC_EXPORT FilePath(const FileDescriptor* file);
// Just like FilePath(), but without the directory part.
std::string PROTOC_EXPORT FilePathBasename(const FileDescriptor* file);
// Gets the name of the root class we'll generate in the file. This class
// is not meant for external consumption, but instead contains helpers that
// the rest of the classes need
std::string PROTOC_EXPORT FileClassName(const FileDescriptor* file);
// These return the fully-qualified class name corresponding to the given
// descriptor.
std::string PROTOC_EXPORT ClassName(const Descriptor* descriptor);
std::string PROTOC_EXPORT ClassName(const Descriptor* descriptor,
std::string* out_suffix_added);
std::string PROTOC_EXPORT EnumName(const EnumDescriptor* descriptor);
// Returns the fully-qualified name of the enum value corresponding to the
// the descriptor.
std::string PROTOC_EXPORT EnumValueName(const EnumValueDescriptor* descriptor);
// Returns the name of the enum value corresponding to the descriptor.
std::string PROTOC_EXPORT EnumValueShortName(const EnumValueDescriptor* descriptor);
// Reverse what an enum does.
std::string PROTOC_EXPORT UnCamelCaseEnumShortName(const std::string& name);
// Returns the name to use for the extension (used as the method off the file's
// Root class).
std::string PROTOC_EXPORT ExtensionMethodName(const FieldDescriptor* descriptor);
// Returns the transformed field name.
std::string PROTOC_EXPORT FieldName(const FieldDescriptor* field);
std::string PROTOC_EXPORT FieldNameCapitalized(const FieldDescriptor* field);
// Returns the transformed oneof name.
std::string PROTOC_EXPORT OneofEnumName(const OneofDescriptor* descriptor);
std::string PROTOC_EXPORT OneofName(const OneofDescriptor* descriptor);
std::string PROTOC_EXPORT OneofNameCapitalized(const OneofDescriptor* descriptor);
// Returns a symbol that can be used in C code to refer to an Objective C
// class without initializing the class.
std::string PROTOC_EXPORT ObjCClass(const std::string& class_name);
// Declares an Objective C class without initializing the class so that it can
// be refrerred to by ObjCClass.
std::string PROTOC_EXPORT ObjCClassDeclaration(const std::string& class_name);
inline bool HasPreservingUnknownEnumSemantics(const FileDescriptor* file) {
return file->syntax() == FileDescriptor::SYNTAX_PROTO3;
}
inline bool IsMapEntryMessage(const Descriptor* descriptor) {
return descriptor->options().map_entry();
}
// Reverse of the above.
std::string PROTOC_EXPORT UnCamelCaseFieldName(const std::string& name,
const FieldDescriptor* field);
enum ObjectiveCType {
OBJECTIVECTYPE_INT32,
OBJECTIVECTYPE_UINT32,
OBJECTIVECTYPE_INT64,
OBJECTIVECTYPE_UINT64,
OBJECTIVECTYPE_FLOAT,
OBJECTIVECTYPE_DOUBLE,
OBJECTIVECTYPE_BOOLEAN,
OBJECTIVECTYPE_STRING,
OBJECTIVECTYPE_DATA,
OBJECTIVECTYPE_ENUM,
OBJECTIVECTYPE_MESSAGE
};
enum FlagType {
FLAGTYPE_DESCRIPTOR_INITIALIZATION,
FLAGTYPE_EXTENSION,
FLAGTYPE_FIELD
};
template <class TDescriptor>
std::string GetOptionalDeprecatedAttribute(const TDescriptor* descriptor,
const FileDescriptor* file = NULL,
bool preSpace = true,
bool postNewline = false) {
bool isDeprecated = descriptor->options().deprecated();
// The file is only passed when checking Messages & Enums, so those types
// get tagged. At the moment, it doesn't seem to make sense to tag every
// field or enum value with when the file is deprecated.
bool isFileLevelDeprecation = false;
if (!isDeprecated && file) {
isFileLevelDeprecation = file->options().deprecated();
isDeprecated = isFileLevelDeprecation;
}
if (isDeprecated) {
std::string message;
const FileDescriptor* sourceFile = descriptor->file();
if (isFileLevelDeprecation) {
message = sourceFile->name() + " is deprecated.";
} else {
message = descriptor->full_name() + " is deprecated (see " +
sourceFile->name() + ").";
}
std::string result = std::string("GPB_DEPRECATED_MSG(\"") + message + "\")";
if (preSpace) {
result.insert(0, " ");
}
if (postNewline) {
result.append("\n");
}
return result;
} else {
return "";
}
}
std::string PROTOC_EXPORT GetCapitalizedType(const FieldDescriptor* field);
ObjectiveCType PROTOC_EXPORT
GetObjectiveCType(FieldDescriptor::Type field_type);
inline ObjectiveCType GetObjectiveCType(const FieldDescriptor* field) {
return GetObjectiveCType(field->type());
}
bool PROTOC_EXPORT IsPrimitiveType(const FieldDescriptor* field);
bool PROTOC_EXPORT IsReferenceType(const FieldDescriptor* field);
std::string PROTOC_EXPORT
GPBGenericValueFieldName(const FieldDescriptor* field);
std::string PROTOC_EXPORT DefaultValue(const FieldDescriptor* field);
bool PROTOC_EXPORT HasNonZeroDefaultValue(const FieldDescriptor* field);
std::string PROTOC_EXPORT
BuildFlagsString(const FlagType type, const std::vector<std::string>& strings);
// Builds HeaderDoc/appledoc style comments out of the comments in the .proto
// file.
std::string PROTOC_EXPORT BuildCommentsString(const SourceLocation& location,
bool prefer_single_line);
// The name the commonly used by the library when built as a framework.
// This lines up to the name used in the CocoaPod.
extern PROTOC_EXPORT const char* const ProtobufLibraryFrameworkName;
// Returns the CPP symbol name to use as the gate for framework style imports
// for the given framework name to use.
std::string PROTOC_EXPORT
ProtobufFrameworkImportSymbol(const std::string& framework_name);
// Checks if the file is one of the proto's bundled with the library.
bool PROTOC_EXPORT
IsProtobufLibraryBundledProtoFile(const FileDescriptor* file);
// Checks the prefix for the given files and outputs any warnings as needed. If
// there are flat out errors, then out_error is filled in with the first error
// and the result is false.
bool PROTOC_EXPORT ValidateObjCClassPrefixes(
const std::vector<const FileDescriptor*>& files,
const Options& validation_options, std::string* out_error);
// Same was the other ValidateObjCClassPrefixes() calls, but the options all
// come from the environment variables.
bool PROTOC_EXPORT ValidateObjCClassPrefixes(
const std::vector<const FileDescriptor*>& files, std::string* out_error);
// Generate decode data needed for ObjC's GPBDecodeTextFormatName() to transform
// the input into the expected output.
class PROTOC_EXPORT TextFormatDecodeData {
public:
TextFormatDecodeData();
~TextFormatDecodeData();
TextFormatDecodeData(const TextFormatDecodeData&) = delete;
TextFormatDecodeData& operator=(const TextFormatDecodeData&) = delete;
void AddString(int32_t key, const std::string& input_for_decode,
const std::string& desired_output);
size_t num_entries() const { return entries_.size(); }
std::string Data() const;
static std::string DecodeDataForString(const std::string& input_for_decode,
const std::string& desired_output);
private:
typedef std::pair<int32_t, std::string> DataEntry;
std::vector<DataEntry> entries_;
};
// Helper for parsing simple files.
class PROTOC_EXPORT LineConsumer {
public:
LineConsumer();
virtual ~LineConsumer();
virtual bool ConsumeLine(const absl::string_view& line, std::string* out_error) = 0;
};
bool PROTOC_EXPORT ParseSimpleFile(const std::string& path,
LineConsumer* line_consumer,
std::string* out_error);
bool PROTOC_EXPORT ParseSimpleStream(io::ZeroCopyInputStream& input_stream,
const std::string& stream_name,
LineConsumer* line_consumer,
std::string* out_error);
// Helper class for parsing framework import mappings and generating
// import statements.
class PROTOC_EXPORT ImportWriter {
public:
ImportWriter(const std::string& generate_for_named_framework,
const std::string& named_framework_to_proto_path_mappings_path,
const std::string& runtime_import_prefix,
bool include_wkt_imports);
~ImportWriter();
void AddFile(const FileDescriptor* file, const std::string& header_extension);
void Print(io::Printer* printer) const;
static void PrintRuntimeImports(io::Printer* printer,
const std::vector<std::string>& header_to_import,
const std::string& runtime_import_prefix,
bool default_cpp_symbol = false);
private:
class ProtoFrameworkCollector : public LineConsumer {
public:
ProtoFrameworkCollector(std::map<std::string, std::string>* inout_proto_file_to_framework_name)
: map_(inout_proto_file_to_framework_name) {}
virtual bool ConsumeLine(const absl::string_view& line, std::string* out_error) override;
private:
std::map<std::string, std::string>* map_;
};
void ParseFrameworkMappings();
const std::string generate_for_named_framework_;
const std::string named_framework_to_proto_path_mappings_path_;
const std::string runtime_import_prefix_;
const bool include_wkt_imports_;
std::map<std::string, std::string> proto_file_to_framework_name_;
bool need_to_parse_mapping_file_;
std::vector<std::string> protobuf_imports_;
std::vector<std::string> other_framework_imports_;
std::vector<std::string> other_imports_;
};
// TODO(thomasvl) Move internal helpers in names.h back to here. Currently
// the dependencies are too interwoven to easily split up.
} // namespace objectivec
} // namespace compiler

@ -6,6 +6,20 @@ load("@rules_cc//cc:defs.bzl", "cc_library")
load("@rules_pkg//:mappings.bzl", "pkg_files", "strip_prefix")
load("//build_defs:cpp_opts.bzl", "COPTS")
cc_library(
name = "names",
hdrs = ["names.h"],
srcs = ["names.cc"],
copts = COPTS,
include_prefix = "google/protobuf/compiler/php",
visibility = ["//visibility:public"],
deps = [
"//src/google/protobuf:protobuf_nowkt",
"//src/google/protobuf/compiler:code_generator",
"@com_google_absl//absl/strings",
],
)
cc_library(
name = "php",
srcs = ["php_generator.cc"],
@ -17,6 +31,7 @@ cc_library(
"//src/google/protobuf/compiler:__pkg__",
],
deps = [
":names",
"//src/google/protobuf:protobuf_nowkt",
"//src/google/protobuf/compiler:code_generator",
"@com_google_absl//absl/strings",

@ -0,0 +1,144 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// 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 Inc. 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 THE COPYRIGHT
// OWNER OR CONTRIBUTORS 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 "google/protobuf/compiler/php/names.h"
#include <string>
#include "google/protobuf/compiler/code_generator.h"
#include "google/protobuf/compiler/plugin.h"
#include "google/protobuf/descriptor.h"
#include "google/protobuf/descriptor.pb.h"
const char* const kReservedNames[] = {
"abstract", "and", "array", "as", "break",
"callable", "case", "catch", "class", "clone",
"const", "continue", "declare", "default", "die",
"do", "echo", "else", "elseif", "empty",
"enddeclare", "endfor", "endforeach", "endif", "endswitch",
"endwhile", "eval", "exit", "extends", "final",
"finally", "fn", "for", "foreach", "function",
"global", "goto", "if", "implements", "include",
"include_once", "instanceof", "insteadof", "interface", "isset",
"list", "match", "namespace", "new", "or",
"parent", "print", "private", "protected", "public",
"readonly", "require", "require_once", "return", "self",
"static", "switch", "throw", "trait", "try",
"unset", "use", "var", "while", "xor",
"yield", "int", "float", "bool", "string",
"true", "false", "null", "void", "iterable"};
const int kReservedNamesSize = 80;
namespace google {
namespace protobuf {
namespace compiler {
namespace php {
bool IsReservedName(absl::string_view name) {
std::string lower(name);
std::transform(lower.begin(), lower.end(), lower.begin(), ::tolower);
for (int i = 0; i < kReservedNamesSize; i++) {
if (lower == kReservedNames[i]) {
return true;
}
}
return false;
}
std::string ReservedNamePrefix(const std::string& classname,
const FileDescriptor* file) {
if (IsReservedName(classname)) {
if (file->package() == "google.protobuf") {
return "GPB";
} else {
return "PB";
}
}
return "";
}
namespace {
template <typename DescriptorType>
std::string ClassNamePrefixImpl(const std::string& classname,
const DescriptorType* desc) {
const std::string& prefix = (desc->file()->options()).php_class_prefix();
if (!prefix.empty()) {
return prefix;
}
return ReservedNamePrefix(classname, desc->file());
}
template <typename DescriptorType>
std::string GeneratedClassNameImpl(const DescriptorType* desc) {
std::string classname = ClassNamePrefixImpl(desc->name(), desc) + desc->name();
const Descriptor* containing = desc->containing_type();
while (containing != NULL) {
classname = ClassNamePrefixImpl(containing->name(), desc) + containing->name()
+ '\\' + classname;
containing = containing->containing_type();
}
return classname;
}
std::string GeneratedClassNameImpl(const ServiceDescriptor* desc) {
std::string classname = desc->name();
return ClassNamePrefixImpl(classname, desc) + classname;
}
} // namespace
std::string ClassNamePrefix(const std::string& classname,
const Descriptor* desc) {
return ClassNamePrefixImpl(classname, desc);
}
std::string ClassNamePrefix(const std::string& classname,
const EnumDescriptor* desc) {
return ClassNamePrefixImpl(classname, desc);
}
std::string GeneratedClassName(const Descriptor* desc) {
return GeneratedClassNameImpl(desc);
}
std::string GeneratedClassName(const EnumDescriptor* desc) {
return GeneratedClassNameImpl(desc);
}
std::string GeneratedClassName(const ServiceDescriptor* desc) {
return GeneratedClassNameImpl(desc);
}
} // namespace php
} // namespace compiler
} // namespace protobuf
} // namespace google

@ -0,0 +1,73 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// 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 Inc. 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 THE COPYRIGHT
// OWNER OR CONTRIBUTORS 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 GOOGLE_PROTOBUF_COMPILER_PHP_NAMES_H__
#define GOOGLE_PROTOBUF_COMPILER_PHP_NAMES_H__
#include "google/protobuf/descriptor.h"
#include <string>
#include "absl/strings/string_view.h"
#include "google/protobuf/port_def.inc"
namespace google {
namespace protobuf {
namespace compiler {
namespace php {
// Whether or not a name is reserved.
PROTOC_EXPORT bool IsReservedName(absl::string_view name);
// A prefix to stick in front of reserved names to avoid clashes.
PROTOC_EXPORT std::string ReservedNamePrefix(const std::string& classname,
const FileDescriptor* file);
// A prefix to stick in front of all class names.
PROTOC_EXPORT std::string ClassNamePrefix(const std::string& classname,
const Descriptor* desc);
PROTOC_EXPORT std::string ClassNamePrefix(const std::string& classname,
const EnumDescriptor* desc);
// To skip reserved keywords in php, some generated classname are prefixed.
// Other code generators may need following API to figure out the actual
// classname.
PROTOC_EXPORT std::string GeneratedClassName(const Descriptor* desc);
PROTOC_EXPORT std::string GeneratedClassName(const EnumDescriptor* desc);
PROTOC_EXPORT std::string GeneratedClassName(const ServiceDescriptor* desc);
} // namespace php
} // namespace compiler
} // namespace protobuf
} // namespace google
#include "google/protobuf/port_undef.inc"
#endif // GOOGLE_PROTOBUF_COMPILER_PHP_NAMES_H__

@ -50,29 +50,11 @@ const std::string kDescriptorMetadataFile =
"GPBMetadata/Google/Protobuf/Internal/Descriptor.php";
const std::string kDescriptorDirName = "Google/Protobuf/Internal";
const std::string kDescriptorPackageName = "Google\\Protobuf\\Internal";
const char* const kReservedNames[] = {
"abstract", "and", "array", "as", "break",
"callable", "case", "catch", "class", "clone",
"const", "continue", "declare", "default", "die",
"do", "echo", "else", "elseif", "empty",
"enddeclare", "endfor", "endforeach", "endif", "endswitch",
"endwhile", "eval", "exit", "extends", "final",
"finally", "fn", "for", "foreach", "function",
"global", "goto", "if", "implements", "include",
"include_once", "instanceof", "insteadof", "interface", "isset",
"list", "match", "namespace", "new", "or",
"parent", "print", "private", "protected", "public",
"readonly", "require", "require_once", "return", "self",
"static", "switch", "throw", "trait", "try",
"unset", "use", "var", "while", "xor",
"yield", "int", "float", "bool", "string",
"true", "false", "null", "void", "iterable"};
const char* const kValidConstantNames[] = {
"int", "float", "bool", "string", "true",
"false", "null", "void", "iterable", "parent",
"self", "readonly"
};
const int kReservedNamesSize = 80;
const int kValidConstantNamesSize = 12;
const int kFieldSetter = 1;
const int kFieldGetter = 2;
@ -124,31 +106,6 @@ void GenerateServiceDocComment(io::Printer* printer,
void GenerateServiceMethodDocComment(io::Printer* printer,
const MethodDescriptor* method);
std::string ReservedNamePrefix(const std::string& classname,
const FileDescriptor* file) {
bool is_reserved = false;
std::string lower = classname;
std::transform(lower.begin(), lower.end(), lower.begin(), ::tolower);
for (int i = 0; i < kReservedNamesSize; i++) {
if (lower == kReservedNames[i]) {
is_reserved = true;
break;
}
}
if (is_reserved) {
if (file->package() == "google.protobuf") {
return "GPB";
} else {
return "PB";
}
}
return "";
}
template <typename DescriptorType>
std::string DescriptorFullName(const DescriptorType* desc, bool is_internal) {
if (is_internal) {
@ -159,34 +116,6 @@ std::string DescriptorFullName(const DescriptorType* desc, bool is_internal) {
}
}
template <typename DescriptorType>
std::string ClassNamePrefix(const std::string& classname,
const DescriptorType* desc) {
const std::string& prefix = (desc->file()->options()).php_class_prefix();
if (!prefix.empty()) {
return prefix;
}
return ReservedNamePrefix(classname, desc->file());
}
template <typename DescriptorType>
std::string GeneratedClassNameImpl(const DescriptorType* desc) {
std::string classname = ClassNamePrefix(desc->name(), desc) + desc->name();
const Descriptor* containing = desc->containing_type();
while (containing != NULL) {
classname = ClassNamePrefix(containing->name(), desc) + containing->name()
+ '\\' + classname;
containing = containing->containing_type();
}
return classname;
}
std::string GeneratedClassNameImpl(const ServiceDescriptor* desc) {
std::string classname = desc->name();
return ClassNamePrefix(classname, desc) + classname;
}
template <typename DescriptorType>
std::string LegacyGeneratedClassName(const DescriptorType* desc) {
std::string classname = desc->name();
@ -198,31 +127,13 @@ std::string LegacyGeneratedClassName(const DescriptorType* desc) {
return ClassNamePrefix(classname, desc) + classname;
}
std::string ClassNamePrefix(const std::string& classname) {
std::string lower = classname;
std::transform(lower.begin(), lower.end(), lower.begin(), ::tolower);
for (int i = 0; i < kReservedNamesSize; i++) {
if (lower == kReservedNames[i]) {
return "PB";
}
}
return "";
}
std::string ConstantNamePrefix(const std::string& classname) {
bool is_reserved = false;
std::string lower = classname;
std::transform(lower.begin(), lower.end(), lower.begin(), ::tolower);
for (int i = 0; i < kReservedNamesSize; i++) {
if (lower == kReservedNames[i]) {
is_reserved = true;
break;
}
}
is_reserved = IsReservedName(lower);
for (int i = 0; i < kValidConstantNamesSize; i++) {
if (lower == kValidConstantNames[i]) {
@ -257,7 +168,7 @@ std::string RootPhpNamespace(const DescriptorType* desc,
template <typename DescriptorType>
std::string FullClassName(const DescriptorType* desc, const Options& options) {
std::string classname = GeneratedClassNameImpl(desc);
std::string classname = GeneratedClassName(desc);
std::string php_namespace = RootPhpNamespace(desc, options);
if (!php_namespace.empty()) {
return php_namespace + "\\" + classname;
@ -283,6 +194,11 @@ std::string LegacyFullClassName(const DescriptorType* desc,
return classname;
}
std::string PhpNamePrefix(const std::string& classname) {
if (IsReservedName(classname)) return "PB";
return "";
}
std::string PhpName(const std::string& full_name, const Options& options) {
if (options.is_descriptor) {
return kDescriptorPackageName;
@ -296,7 +212,7 @@ std::string PhpName(const std::string& full_name, const Options& options) {
segment += full_name[i] + ('A' - 'a');
cap_next_letter = false;
} else if (full_name[i] == '.') {
result += ClassNamePrefix(segment) + segment + '\\';
result += PhpNamePrefix(segment) + segment + '\\';
segment = "";
cap_next_letter = true;
} else {
@ -304,7 +220,7 @@ std::string PhpName(const std::string& full_name, const Options& options) {
cap_next_letter = false;
}
}
result += ClassNamePrefix(segment) + segment;
result += PhpNamePrefix(segment) + segment;
return result;
}
@ -1312,7 +1228,7 @@ void LegacyGenerateClassFile(const FileDescriptor* file,
Outdent(&printer);
printer.Print("}\n");
printer.Print("class_exists(^new^::class);\n",
"new", GeneratedClassNameImpl(desc));
"new", GeneratedClassName(desc));
printer.Print("@trigger_error('^old^ is deprecated and will be removed in "
"the next major release. Use ^fullname^ instead', E_USER_DEPRECATED);\n\n",
"old", LegacyFullClassName(desc, options),
@ -2342,18 +2258,6 @@ void GenerateCWellKnownTypes(const std::vector<const FileDescriptor*>& files,
} // namespace
std::string GeneratedClassName(const Descriptor* desc) {
return GeneratedClassNameImpl(desc);
}
std::string GeneratedClassName(const EnumDescriptor* desc) {
return GeneratedClassNameImpl(desc);
}
std::string GeneratedClassName(const ServiceDescriptor* desc) {
return GeneratedClassNameImpl(desc);
}
bool Generator::Generate(const FileDescriptor* file,
const std::string& parameter,
GeneratorContext* generator_context,

@ -32,6 +32,7 @@
#define GOOGLE_PROTOBUF_COMPILER_PHP_GENERATOR_H__
#include "google/protobuf/compiler/code_generator.h"
#include "google/protobuf/compiler/php/names.h"
#include "google/protobuf/descriptor.h"
#include <string>
@ -70,13 +71,6 @@ class PROTOC_EXPORT Generator : public CodeGenerator {
std::string* error) const;
};
// To skip reserved keywords in php, some generated classname are prefixed.
// Other code generators may need following API to figure out the actual
// classname.
PROTOC_EXPORT std::string GeneratedClassName(const Descriptor* desc);
PROTOC_EXPORT std::string GeneratedClassName(const EnumDescriptor* desc);
PROTOC_EXPORT std::string GeneratedClassName(const ServiceDescriptor* desc);
inline bool IsWrapperType(const FieldDescriptor* descriptor) {
return descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
descriptor->message_type()->file()->name() == "google/protobuf/wrappers.proto";

@ -23,6 +23,7 @@ cc_library(
visibility = [
"//pkg:__pkg__",
"//src/google/protobuf/compiler:__pkg__",
"@com_github_grpc_grpc//tools/distrib/python/grpcio_tools:__subpackages__",
],
deps = [
"//src/google/protobuf:protobuf_nowkt",

Loading…
Cancel
Save