[Upb C++] Split name-related functions from gen_utils.{h,cc} into names.{h,cc}. Also create a separate build target for output.{h,cc} (though it's kept private, since we prefer protobuf/io/printer.h for newer code).

PiperOrigin-RevId: 535333251
diff --git a/protos_generator/BUILD b/protos_generator/BUILD
index 2414ff5..acc0c1a 100644
--- a/protos_generator/BUILD
+++ b/protos_generator/BUILD
@@ -42,7 +42,10 @@
     copts = UPB_DEFAULT_CPPOPTS,
     visibility = ["//visibility:public"],
     deps = [
+        ":gen_utils",
         ":generator",
+        ":names",
+        ":output",
         "//upbc:file_layout",
         "@com_google_protobuf//:protobuf",
         "@com_google_protobuf//src/google/protobuf/compiler:code_generator",
@@ -57,8 +60,6 @@
         "gen_extensions.cc",
         "gen_messages.cc",
         "gen_repeated_fields.cc",
-        "gen_utils.cc",
-        "output.cc",
     ],
     hdrs = [
         "gen_accessors.h",
@@ -66,22 +67,53 @@
         "gen_extensions.h",
         "gen_messages.h",
         "gen_repeated_fields.h",
-        "gen_utils.h",
-        "output.h",
     ],
     visibility = ["//visibility:private"],
     deps = [
-        "//:message_copy",
+        ":gen_utils",
+        ":names",
+        ":output",
+        "@com_google_absl//absl/container:flat_hash_set",
+        "@com_google_absl//absl/strings",
         "//upbc:common",
         "//upbc:file_layout",
         "//upbc:keywords",
         "//upbc:names",
-        "@com_google_absl//absl/container:flat_hash_map",
-        "@com_google_absl//absl/container:flat_hash_set",
-        "@com_google_absl//absl/log:absl_check",
+        "@com_google_protobuf//:protobuf",
+    ],
+)
+
+cc_library(
+    name = "output",
+    srcs = ["output.cc"],
+    hdrs = ["output.h"],
+    visibility = ["//visibility:private"],
+    deps = [
         "@com_google_absl//absl/log:absl_log",
         "@com_google_absl//absl/strings",
         "@com_google_protobuf//:protobuf",
+    ],
+)
+
+cc_library(
+    name = "gen_utils",
+    srcs = ["gen_utils.cc"],
+    hdrs = ["gen_utils.h"],
+    visibility = ["//visibility:public"],
+    deps = [
+        "@com_google_absl//absl/strings",
+        "@com_google_protobuf//:protobuf",
         "@com_google_protobuf//src/google/protobuf/compiler:code_generator",
     ],
 )
+
+cc_library(
+    name = "names",
+    srcs = ["names.cc"],
+    hdrs = ["names.h"],
+    visibility = ["//visibility:private"],
+    deps = [
+        ":output",
+        "//upbc:keywords",
+    ],
+)
diff --git a/protos_generator/gen_accessors.cc b/protos_generator/gen_accessors.cc
index bd3898b..f7324e8 100644
--- a/protos_generator/gen_accessors.cc
+++ b/protos_generator/gen_accessors.cc
@@ -34,6 +34,7 @@
 #include "google/protobuf/descriptor.h"
 #include "protos_generator/gen_repeated_fields.h"
 #include "protos_generator/gen_utils.h"
+#include "protos_generator/names.h"
 #include "protos_generator/output.h"
 #include "upbc/common.h"
 #include "upbc/keywords.h"
diff --git a/protos_generator/gen_enums.cc b/protos_generator/gen_enums.cc
index e1ad32b..6e2aa39 100644
--- a/protos_generator/gen_enums.cc
+++ b/protos_generator/gen_enums.cc
@@ -33,6 +33,7 @@
 #include "google/protobuf/descriptor.pb.h"
 #include "google/protobuf/descriptor.h"
 #include "protos_generator/gen_utils.h"
+#include "protos_generator/names.h"
 
 namespace protos_generator {
 
diff --git a/protos_generator/gen_extensions.cc b/protos_generator/gen_extensions.cc
index 167fa2f..979284d 100644
--- a/protos_generator/gen_extensions.cc
+++ b/protos_generator/gen_extensions.cc
@@ -27,6 +27,7 @@
 
 #include "absl/strings/str_cat.h"
 #include "protos_generator/gen_utils.h"
+#include "protos_generator/names.h"
 
 namespace protos_generator {
 
diff --git a/protos_generator/gen_messages.cc b/protos_generator/gen_messages.cc
index 7715193..8d81fbd 100644
--- a/protos_generator/gen_messages.cc
+++ b/protos_generator/gen_messages.cc
@@ -36,6 +36,7 @@
 #include "protos_generator/gen_enums.h"
 #include "protos_generator/gen_extensions.h"
 #include "protos_generator/gen_utils.h"
+#include "protos_generator/names.h"
 #include "protos_generator/output.h"
 #include "upbc/common.h"
 #include "upbc/file_layout.h"
diff --git a/protos_generator/gen_repeated_fields.cc b/protos_generator/gen_repeated_fields.cc
index 1454c10..2564334 100644
--- a/protos_generator/gen_repeated_fields.cc
+++ b/protos_generator/gen_repeated_fields.cc
@@ -35,6 +35,7 @@
 #include "protos_generator/gen_enums.h"
 #include "protos_generator/gen_extensions.h"
 #include "protos_generator/gen_utils.h"
+#include "protos_generator/names.h"
 #include "protos_generator/output.h"
 #include "upbc/common.h"
 #include "upbc/file_layout.h"
diff --git a/protos_generator/gen_utils.cc b/protos_generator/gen_utils.cc
index 53630fd..b4ecf04 100644
--- a/protos_generator/gen_utils.cc
+++ b/protos_generator/gen_utils.cc
@@ -29,175 +29,14 @@
 
 #include <algorithm>
 #include <string>
+#include <vector>
 
-#include "absl/log/absl_check.h"
-#include "absl/strings/str_cat.h"
-// begin:google_only
-// #include "absl/strings/str_replace.h"
-// end:google_only
-#include "absl/strings/str_split.h"
-#include "upbc/keywords.h"
+#include "absl/strings/ascii.h"
 
 namespace protos_generator {
 
 namespace protobuf = ::google::protobuf;
 
-std::string DotsToColons(const std::string& name) {
-  return absl::StrReplaceAll(name, {{".", "::"}});
-}
-
-std::string Namespace(const std::string& package) {
-  if (package.empty()) return "";
-  return "::" + DotsToColons(package);
-}
-
-// Return the qualified C++ name for a file level symbol.
-std::string QualifiedFileLevelSymbol(const protobuf::FileDescriptor* file,
-                                     const std::string& name) {
-  if (file->package().empty()) {
-    return absl::StrCat("::", name);
-  }
-  // Append ::protos postfix to package name.
-  return absl::StrCat(Namespace(file->package()), "::protos::", name);
-}
-
-std::string ClassName(const protobuf::Descriptor* descriptor) {
-  const protobuf::Descriptor* parent = descriptor->containing_type();
-  std::string res;
-  // Classes in global namespace without package names are prefixed
-  // by protos_ to avoid collision with C compiler structs defined in
-  // proto.upb.h.
-  if ((parent && parent->file()->package().empty()) ||
-      descriptor->file()->package().empty()) {
-    res = std::string(kNoPackageNamePrefix);
-  }
-  if (parent) res += ClassName(parent) + "_";
-  absl::StrAppend(&res, descriptor->name());
-  return ::upbc::ResolveKeywordConflict(res);
-}
-
-std::string QualifiedClassName(const protobuf::Descriptor* descriptor) {
-  return QualifiedFileLevelSymbol(descriptor->file(), ClassName(descriptor));
-}
-
-std::string QualifiedInternalClassName(const protobuf::Descriptor* descriptor) {
-  return QualifiedFileLevelSymbol(
-      descriptor->file(), absl::StrCat("internal::", ClassName(descriptor)));
-}
-
-std::string CppSourceFilename(const google::protobuf::FileDescriptor* file) {
-  return StripExtension(file->name()) + ".upb.proto.cc";
-}
-
-std::string UpbCFilename(const google::protobuf::FileDescriptor* file) {
-  return StripExtension(file->name()) + ".upb.h";
-}
-
-std::string ForwardingHeaderFilename(const google::protobuf::FileDescriptor* file) {
-  return StripExtension(file->name()) + ".upb.fwd.h";
-}
-
-std::string CppHeaderFilename(const google::protobuf::FileDescriptor* file) {
-  return StripExtension(file->name()) + ".upb.proto.h";
-}
-
-std::string NamespaceFromPackageName(absl::string_view package_name) {
-  return absl::StrCat(absl::StrReplaceAll(package_name, {{".", "::"}}),
-                      "::protos");
-}
-
-void WriteStartNamespace(const protobuf::FileDescriptor* file, Output& output) {
-  // Skip namespace generation if package name is not specified.
-  if (file->package().empty()) {
-    return;
-  }
-
-  output("namespace $0 {\n\n", NamespaceFromPackageName(file->package()));
-}
-
-void WriteEndNamespace(const protobuf::FileDescriptor* file, Output& output) {
-  if (file->package().empty()) {
-    return;
-  }
-  output("} //  namespace $0\n\n", NamespaceFromPackageName(file->package()));
-}
-
-std::string CppTypeInternal(const protobuf::FieldDescriptor* field,
-                            bool is_const, bool is_type_parameter) {
-  std::string maybe_const = is_const ? "const " : "";
-  switch (field->cpp_type()) {
-    case protobuf::FieldDescriptor::CPPTYPE_MESSAGE: {
-      if (is_type_parameter) {
-        return absl::StrCat(maybe_const,
-                            QualifiedClassName(field->message_type()));
-      } else {
-        return absl::StrCat(maybe_const,
-                            QualifiedClassName(field->message_type()), "*");
-      }
-    }
-    case protobuf::FieldDescriptor::CPPTYPE_BOOL:
-      return "bool";
-    case protobuf::FieldDescriptor::CPPTYPE_FLOAT:
-      return "float";
-    case protobuf::FieldDescriptor::CPPTYPE_INT32:
-    case protobuf::FieldDescriptor::CPPTYPE_ENUM:
-      return "int32_t";
-    case protobuf::FieldDescriptor::CPPTYPE_UINT32:
-      return "uint32_t";
-    case protobuf::FieldDescriptor::CPPTYPE_DOUBLE:
-      return "double";
-    case protobuf::FieldDescriptor::CPPTYPE_INT64:
-      return "int64_t";
-    case protobuf::FieldDescriptor::CPPTYPE_UINT64:
-      return "uint64_t";
-    case protobuf::FieldDescriptor::CPPTYPE_STRING:
-      return "absl::string_view";
-    default:
-      ABSL_LOG(FATAL) << "Unexpected type: " << field->cpp_type();
-  }
-}
-
-std::string CppConstType(const protobuf::FieldDescriptor* field) {
-  return CppTypeInternal(field, /* is_const= */ true,
-                         /* is_type_parameter= */ false);
-}
-
-std::string CppTypeParameterName(const protobuf::FieldDescriptor* field) {
-  return CppTypeInternal(field, /* is_const= */ false,
-                         /* is_type_parameter= */ true);
-}
-
-std::string MessageBaseType(const protobuf::FieldDescriptor* field,
-                            bool is_const) {
-  ABSL_DCHECK(field->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_MESSAGE);
-  std::string maybe_const = is_const ? "const " : "";
-  return maybe_const + QualifiedClassName(field->message_type());
-}
-
-std::string MessagePtrConstType(const protobuf::FieldDescriptor* field,
-                                bool is_const) {
-  ABSL_DCHECK(field->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_MESSAGE);
-  std::string maybe_const = is_const ? "const " : "";
-  return "::protos::Ptr<" + maybe_const +
-         QualifiedClassName(field->message_type()) + ">";
-}
-
-std::string MessageCProxyType(const protobuf::FieldDescriptor* field,
-                              bool is_const) {
-  ABSL_DCHECK(field->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_MESSAGE);
-  std::string maybe_const = is_const ? "const " : "";
-  return maybe_const + QualifiedInternalClassName(field->message_type()) +
-         "CProxy";
-}
-
-std::string MessageProxyType(const protobuf::FieldDescriptor* field,
-                             bool is_const) {
-  ABSL_DCHECK(field->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_MESSAGE);
-  std::string maybe_const = is_const ? "const " : "";
-  return maybe_const + QualifiedInternalClassName(field->message_type()) +
-         "Proxy";
-}
-
 void AddEnums(const protobuf::Descriptor* message,
               std::vector<const protobuf::EnumDescriptor*>* enums) {
   enums->reserve(enums->size() + message->enum_type_count());
@@ -252,13 +91,19 @@
 
 std::vector<const protobuf::FieldDescriptor*> SortedExtensions(
     const protobuf::FileDescriptor* file) {
+  const int extension_count = file->extension_count();
+  const int message_type_count = file->message_type_count();
+
   std::vector<const protobuf::FieldDescriptor*> ret;
-  for (int i = 0; i < file->extension_count(); i++) {
+  ret.reserve(extension_count + message_type_count);
+
+  for (int i = 0; i < extension_count; i++) {
     ret.push_back(file->extension(i));
   }
-  for (int i = 0; i < file->message_type_count(); i++) {
+  for (int i = 0; i < message_type_count; i++) {
     AddExtensionsFromMessage(file->message_type(i), &ret);
   }
+
   return ret;
 }
 
diff --git a/protos_generator/gen_utils.h b/protos_generator/gen_utils.h
index 394c244..593c06a 100644
--- a/protos_generator/gen_utils.h
+++ b/protos_generator/gen_utils.h
@@ -28,16 +28,12 @@
 #ifndef UPB_PROTOS_GENERATOR_GEN_UTILS_H_
 #define UPB_PROTOS_GENERATOR_GEN_UTILS_H_
 
+#include <string>
 #include <vector>
 
 #include "google/protobuf/descriptor.pb.h"
-#include "absl/container/flat_hash_map.h"
-#include "absl/strings/string_view.h"
 #include "google/protobuf/compiler/code_generator.h"
-#include "google/protobuf/compiler/plugin.h"
 #include "google/protobuf/descriptor.h"
-#include "google/protobuf/wire_format.h"
-#include "protos_generator/output.h"
 
 namespace protos_generator {
 
@@ -50,35 +46,9 @@
   kMessageAccess,
 };
 
-std::string ClassName(const protobuf::Descriptor* descriptor);
-std::string QualifiedClassName(const protobuf::Descriptor* descriptor);
-std::string QualifiedInternalClassName(const protobuf::Descriptor* descriptor);
-
 inline bool IsMapEntryMessage(const protobuf::Descriptor* descriptor) {
   return descriptor->options().map_entry();
 }
-std::string CppSourceFilename(const google::protobuf::FileDescriptor* file);
-std::string ForwardingHeaderFilename(const google::protobuf::FileDescriptor* file);
-std::string UpbCFilename(const google::protobuf::FileDescriptor* file);
-std::string CppHeaderFilename(const google::protobuf::FileDescriptor* file);
-
-void WriteStartNamespace(const protobuf::FileDescriptor* file, Output& output);
-void WriteEndNamespace(const protobuf::FileDescriptor* file, Output& output);
-
-std::string CppConstType(const protobuf::FieldDescriptor* field);
-std::string CppTypeParameterName(const protobuf::FieldDescriptor* field);
-
-std::string MessageBaseType(const protobuf::FieldDescriptor* field,
-                            bool is_const);
-// Generate protos::Ptr<const Model> to be used in accessors as public
-// signatures.
-std::string MessagePtrConstType(const protobuf::FieldDescriptor* field,
-                                bool is_const);
-std::string MessageCProxyType(const protobuf::FieldDescriptor* field,
-                              bool is_const);
-std::string MessageProxyType(const protobuf::FieldDescriptor* field,
-                             bool is_const);
-
 std::vector<const protobuf::EnumDescriptor*> SortedEnums(
     const protobuf::FileDescriptor* file);
 std::vector<const protobuf::Descriptor*> SortedMessages(
@@ -88,8 +58,6 @@
 std::vector<const protobuf::FieldDescriptor*> FieldNumberOrder(
     const protobuf::Descriptor* message);
 
-inline constexpr absl::string_view kNoPackageNamePrefix = "protos_";
-
 std::string ToCamelCase(const std::string& input, bool lower_first);
 
 }  // namespace protos_generator
diff --git a/protos_generator/names.cc b/protos_generator/names.cc
new file mode 100644
index 0000000..0149071
--- /dev/null
+++ b/protos_generator/names.cc
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2009-2021, Google LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Google LLC nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "protos_generator/names.h"
+
+#include <string>
+
+#include "upbc/keywords.h"
+
+namespace protos_generator {
+
+namespace protobuf = ::google::protobuf;
+
+namespace {
+
+std::string NamespaceFromPackageName(absl::string_view package_name) {
+  return absl::StrCat(absl::StrReplaceAll(package_name, {{".", "::"}}),
+                      "::protos");
+}
+
+std::string DotsToColons(const std::string& name) {
+  return absl::StrReplaceAll(name, {{".", "::"}});
+}
+
+std::string Namespace(const std::string& package) {
+  if (package.empty()) return "";
+  return "::" + DotsToColons(package);
+}
+
+// Return the qualified C++ name for a file level symbol.
+std::string QualifiedFileLevelSymbol(const protobuf::FileDescriptor* file,
+                                     const std::string& name) {
+  if (file->package().empty()) {
+    return absl::StrCat("::", name);
+  }
+  // Append ::protos postfix to package name.
+  return absl::StrCat(Namespace(file->package()), "::protos::", name);
+}
+
+std::string CppTypeInternal(const protobuf::FieldDescriptor* field,
+                            bool is_const, bool is_type_parameter) {
+  std::string maybe_const = is_const ? "const " : "";
+  switch (field->cpp_type()) {
+    case protobuf::FieldDescriptor::CPPTYPE_MESSAGE: {
+      if (is_type_parameter) {
+        return absl::StrCat(maybe_const,
+                            QualifiedClassName(field->message_type()));
+      } else {
+        return absl::StrCat(maybe_const,
+                            QualifiedClassName(field->message_type()), "*");
+      }
+    }
+    case protobuf::FieldDescriptor::CPPTYPE_BOOL:
+      return "bool";
+    case protobuf::FieldDescriptor::CPPTYPE_FLOAT:
+      return "float";
+    case protobuf::FieldDescriptor::CPPTYPE_INT32:
+    case protobuf::FieldDescriptor::CPPTYPE_ENUM:
+      return "int32_t";
+    case protobuf::FieldDescriptor::CPPTYPE_UINT32:
+      return "uint32_t";
+    case protobuf::FieldDescriptor::CPPTYPE_DOUBLE:
+      return "double";
+    case protobuf::FieldDescriptor::CPPTYPE_INT64:
+      return "int64_t";
+    case protobuf::FieldDescriptor::CPPTYPE_UINT64:
+      return "uint64_t";
+    case protobuf::FieldDescriptor::CPPTYPE_STRING:
+      return "absl::string_view";
+    default:
+      ABSL_LOG(FATAL) << "Unexpected type: " << field->cpp_type();
+  }
+}
+
+}  // namespace
+
+std::string ClassName(const protobuf::Descriptor* descriptor) {
+  const protobuf::Descriptor* parent = descriptor->containing_type();
+  std::string res;
+  // Classes in global namespace without package names are prefixed
+  // by protos_ to avoid collision with C compiler structs defined in
+  // proto.upb.h.
+  if ((parent && parent->file()->package().empty()) ||
+      descriptor->file()->package().empty()) {
+    res = std::string(kNoPackageNamePrefix);
+  }
+  if (parent) res += ClassName(parent) + "_";
+  absl::StrAppend(&res, descriptor->name());
+  return ::upbc::ResolveKeywordConflict(res);
+}
+
+std::string QualifiedClassName(const protobuf::Descriptor* descriptor) {
+  return QualifiedFileLevelSymbol(descriptor->file(), ClassName(descriptor));
+}
+
+std::string QualifiedInternalClassName(const protobuf::Descriptor* descriptor) {
+  return QualifiedFileLevelSymbol(
+      descriptor->file(), absl::StrCat("internal::", ClassName(descriptor)));
+}
+
+std::string CppSourceFilename(const google::protobuf::FileDescriptor* file) {
+  return StripExtension(file->name()) + ".upb.proto.cc";
+}
+
+std::string ForwardingHeaderFilename(const google::protobuf::FileDescriptor* file) {
+  return StripExtension(file->name()) + ".upb.fwd.h";
+}
+
+std::string UpbCFilename(const google::protobuf::FileDescriptor* file) {
+  return StripExtension(file->name()) + ".upb.h";
+}
+
+std::string CppHeaderFilename(const google::protobuf::FileDescriptor* file) {
+  return StripExtension(file->name()) + ".upb.proto.h";
+}
+
+void WriteStartNamespace(const protobuf::FileDescriptor* file, Output& output) {
+  // Skip namespace generation if package name is not specified.
+  if (file->package().empty()) {
+    return;
+  }
+
+  output("namespace $0 {\n\n", NamespaceFromPackageName(file->package()));
+}
+
+void WriteEndNamespace(const protobuf::FileDescriptor* file, Output& output) {
+  if (file->package().empty()) {
+    return;
+  }
+  output("} //  namespace $0\n\n", NamespaceFromPackageName(file->package()));
+}
+
+std::string CppConstType(const protobuf::FieldDescriptor* field) {
+  return CppTypeInternal(field, /* is_const= */ true,
+                         /* is_type_parameter= */ false);
+}
+
+std::string CppTypeParameterName(const protobuf::FieldDescriptor* field) {
+  return CppTypeInternal(field, /* is_const= */ false,
+                         /* is_type_parameter= */ true);
+}
+
+std::string MessageBaseType(const protobuf::FieldDescriptor* field,
+                            bool is_const) {
+  ABSL_DCHECK(field->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_MESSAGE);
+  std::string maybe_const = is_const ? "const " : "";
+  return maybe_const + QualifiedClassName(field->message_type());
+}
+
+std::string MessagePtrConstType(const protobuf::FieldDescriptor* field,
+                                bool is_const) {
+  ABSL_DCHECK(field->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_MESSAGE);
+  std::string maybe_const = is_const ? "const " : "";
+  return "::protos::Ptr<" + maybe_const +
+         QualifiedClassName(field->message_type()) + ">";
+}
+
+std::string MessageCProxyType(const protobuf::FieldDescriptor* field,
+                              bool is_const) {
+  ABSL_DCHECK(field->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_MESSAGE);
+  std::string maybe_const = is_const ? "const " : "";
+  return maybe_const + QualifiedInternalClassName(field->message_type()) +
+         "CProxy";
+}
+
+std::string MessageProxyType(const protobuf::FieldDescriptor* field,
+                             bool is_const) {
+  ABSL_DCHECK(field->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_MESSAGE);
+  std::string maybe_const = is_const ? "const " : "";
+  return maybe_const + QualifiedInternalClassName(field->message_type()) +
+         "Proxy";
+}
+
+}  // namespace protos_generator
diff --git a/protos_generator/names.h b/protos_generator/names.h
new file mode 100644
index 0000000..afc0419
--- /dev/null
+++ b/protos_generator/names.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2009-2021, Google LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Google LLC nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UPB_PROTOS_GENERATOR_NAMES_H_
+#define UPB_PROTOS_GENERATOR_NAMES_H_
+
+#include <string>
+
+#include "google/protobuf/descriptor.pb.h"
+#include "protos_generator/output.h"
+
+namespace protos_generator {
+
+namespace protobuf = ::google::protobuf;
+
+inline constexpr absl::string_view kNoPackageNamePrefix = "protos_";
+
+std::string ClassName(const protobuf::Descriptor* descriptor);
+std::string QualifiedClassName(const protobuf::Descriptor* descriptor);
+std::string QualifiedInternalClassName(const protobuf::Descriptor* descriptor);
+
+std::string CppSourceFilename(const google::protobuf::FileDescriptor* file);
+std::string ForwardingHeaderFilename(const google::protobuf::FileDescriptor* file);
+std::string UpbCFilename(const google::protobuf::FileDescriptor* file);
+std::string CppHeaderFilename(const google::protobuf::FileDescriptor* file);
+
+void WriteStartNamespace(const protobuf::FileDescriptor* file, Output& output);
+void WriteEndNamespace(const protobuf::FileDescriptor* file, Output& output);
+
+std::string CppConstType(const protobuf::FieldDescriptor* field);
+std::string CppTypeParameterName(const protobuf::FieldDescriptor* field);
+
+std::string MessageBaseType(const protobuf::FieldDescriptor* field,
+                            bool is_const);
+// Generate protos::Ptr<const Model> to be used in accessors as public
+// signatures.
+std::string MessagePtrConstType(const protobuf::FieldDescriptor* field,
+                                bool is_const);
+std::string MessageCProxyType(const protobuf::FieldDescriptor* field,
+                              bool is_const);
+std::string MessageProxyType(const protobuf::FieldDescriptor* field,
+                             bool is_const);
+
+}  // namespace protos_generator
+
+#endif  // UPB_PROTOS_GENERATOR_NAMES_H_
diff --git a/protos_generator/output.cc b/protos_generator/output.cc
index e5a9b79..255f631 100644
--- a/protos_generator/output.cc
+++ b/protos_generator/output.cc
@@ -25,6 +25,8 @@
 
 #include "protos_generator/output.h"
 
+#include <string>
+
 #include "absl/strings/str_replace.h"
 
 namespace protos_generator {
diff --git a/protos_generator/protoc-gen-upb-protos.cc b/protos_generator/protoc-gen-upb-protos.cc
index 462898b..bc39d3e 100644
--- a/protos_generator/protoc-gen-upb-protos.cc
+++ b/protos_generator/protoc-gen-upb-protos.cc
@@ -33,6 +33,7 @@
 #include "protos_generator/gen_extensions.h"
 #include "protos_generator/gen_messages.h"
 #include "protos_generator/gen_utils.h"
+#include "protos_generator/names.h"
 #include "protos_generator/output.h"
 #include "upbc/file_layout.h"