Split bootstrapped java_features.proto to keep it from leaking out.

This can cause ODR violations in downstream users who link against both the bootstrapped proto and transitive C++ gencode of java_features.proto.  Once protoc is split up, we can turn the bootstrapped proto into a real cc_proto_library target and avoid this problem altogether.

PiperOrigin-RevId: 630099889
diff --git a/src/google/protobuf/compiler/java/BUILD.bazel b/src/google/protobuf/compiler/java/BUILD.bazel
index 39f862f..208977f 100644
--- a/src/google/protobuf/compiler/java/BUILD.bazel
+++ b/src/google/protobuf/compiler/java/BUILD.bazel
@@ -35,7 +35,6 @@
     hdrs = [
         "context.h",
         "doc_comment.h",
-        "generator.h",
         "helpers.h",
         "name_resolver.h",
         "names.h",
@@ -48,7 +47,6 @@
         "//src/google/protobuf/compiler/java:__subpackages__",
     ],
     deps = [
-        ":java_features_bootstrap",
         "//src/google/protobuf",
         "//src/google/protobuf:port",
         "//src/google/protobuf/compiler:code_generator",
@@ -65,6 +63,25 @@
 )
 
 cc_library(
+    name = "internal_helpers",
+    srcs = ["internal_helpers.cc"],
+    hdrs = [
+        "generator.h",
+        "internal_helpers.h",
+    ],
+    strip_include_prefix = "/src",
+    visibility = ["//src/google/protobuf/compiler/java:__subpackages__"],
+    deps = [
+        ":helpers",
+        ":java_features_bootstrap",
+        "//src/google/protobuf",
+        "//src/google/protobuf:port",
+        "//src/google/protobuf/compiler:code_generator",
+        "@com_google_absl//absl/log:absl_log",
+    ],
+)
+
+cc_library(
     name = "java_features_bootstrap",
     srcs = ["java_features.pb.cc"],
     hdrs = ["java_features.pb.h"],
diff --git a/src/google/protobuf/compiler/java/helpers.cc b/src/google/protobuf/compiler/java/helpers.cc
index 826d9f8..8deb2dc 100644
--- a/src/google/protobuf/compiler/java/helpers.cc
+++ b/src/google/protobuf/compiler/java/helpers.cc
@@ -878,86 +878,6 @@
   output->push_back(static_cast<uint16_t>(number));
 }
 
-int GetExperimentalJavaFieldTypeForSingular(const FieldDescriptor* field) {
-  // j/c/g/protobuf/FieldType.java lists field types in a slightly different
-  // order from FieldDescriptor::Type so we can't do a simple cast.
-  //
-  // TODO: Make j/c/g/protobuf/FieldType.java follow the same order.
-  int result = field->type();
-  if (result == FieldDescriptor::TYPE_GROUP) {
-    return 17;
-  } else if (result < FieldDescriptor::TYPE_GROUP) {
-    return result - 1;
-  } else {
-    return result - 2;
-  }
-}
-
-int GetExperimentalJavaFieldTypeForRepeated(const FieldDescriptor* field) {
-  if (field->type() == FieldDescriptor::TYPE_GROUP) {
-    return 49;
-  } else {
-    return GetExperimentalJavaFieldTypeForSingular(field) + 18;
-  }
-}
-
-int GetExperimentalJavaFieldTypeForPacked(const FieldDescriptor* field) {
-  int result = field->type();
-  if (result < FieldDescriptor::TYPE_STRING) {
-    return result + 34;
-  } else if (result > FieldDescriptor::TYPE_BYTES) {
-    return result + 30;
-  } else {
-    ABSL_LOG(FATAL) << field->full_name() << " can't be packed.";
-    return 0;
-  }
-}
-
-int GetExperimentalJavaFieldType(const FieldDescriptor* field) {
-  static const int kMapFieldType = 50;
-  static const int kOneofFieldTypeOffset = 51;
-
-  static const int kRequiredBit = 0x100;
-  static const int kUtf8CheckBit = 0x200;
-  static const int kCheckInitialized = 0x400;
-  static const int kLegacyEnumIsClosedBit = 0x800;
-  static const int kHasHasBit = 0x1000;
-  int extra_bits = field->is_required() ? kRequiredBit : 0;
-  if (field->type() == FieldDescriptor::TYPE_STRING && CheckUtf8(field)) {
-    extra_bits |= kUtf8CheckBit;
-  }
-  if (field->is_required() || (GetJavaType(field) == JAVATYPE_MESSAGE &&
-                               HasRequiredFields(field->message_type()))) {
-    extra_bits |= kCheckInitialized;
-  }
-  if (HasHasbit(field)) {
-    extra_bits |= kHasHasBit;
-  }
-  if (GetJavaType(field) == JAVATYPE_ENUM && !SupportUnknownEnumValue(field)) {
-    extra_bits |= kLegacyEnumIsClosedBit;
-  }
-
-  if (field->is_map()) {
-    if (!SupportUnknownEnumValue(MapValueField(field))) {
-      const FieldDescriptor* value = field->message_type()->map_value();
-      if (GetJavaType(value) == JAVATYPE_ENUM) {
-        extra_bits |= kLegacyEnumIsClosedBit;
-      }
-    }
-    return kMapFieldType | extra_bits;
-  } else if (field->is_packed()) {
-    return GetExperimentalJavaFieldTypeForPacked(field) | extra_bits;
-  } else if (field->is_repeated()) {
-    return GetExperimentalJavaFieldTypeForRepeated(field) | extra_bits;
-  } else if (IsRealOneof(field)) {
-    return (GetExperimentalJavaFieldTypeForSingular(field) +
-            kOneofFieldTypeOffset) |
-           extra_bits;
-  } else {
-    return GetExperimentalJavaFieldTypeForSingular(field) | extra_bits;
-  }
-}
-
 // Escape a UTF-16 character to be embedded in a Java string.
 void EscapeUtf16ToString(uint16_t code, std::string* output) {
   if (code == '\t') {
diff --git a/src/google/protobuf/compiler/java/helpers.h b/src/google/protobuf/compiler/java/helpers.h
index ed27eae..52b4017 100644
--- a/src/google/protobuf/compiler/java/helpers.h
+++ b/src/google/protobuf/compiler/java/helpers.h
@@ -16,8 +16,6 @@
 #include <string>
 
 #include "absl/strings/string_view.h"
-#include "google/protobuf/compiler/java/generator.h"
-#include "google/protobuf/compiler/java/java_features.pb.h"
 #include "google/protobuf/compiler/java/names.h"
 #include "google/protobuf/compiler/java/options.h"
 #include "google/protobuf/descriptor.h"
@@ -344,18 +342,6 @@
   return internal::cpp::HasHasbit(descriptor);
 }
 
-// Whether unknown enum values are kept (i.e., not stored in UnknownFieldSet
-// but in the message and can be queried using additional getters that return
-// ints.
-inline bool SupportUnknownEnumValue(const FieldDescriptor* field) {
-  if (JavaGenerator::GetResolvedSourceFeatures(*field)
-          .GetExtension(pb::java)
-          .legacy_closed_enum()) {
-    return false;
-  }
-  return field->enum_type() != nullptr && !field->enum_type()->is_closed();
-}
-
 // Check whether a message has repeated fields.
 bool HasRepeatedFields(const Descriptor* descriptor);
 
@@ -375,18 +361,6 @@
   return descriptor->name() == "google/protobuf/wrappers.proto";
 }
 
-inline bool CheckUtf8(const FieldDescriptor* descriptor) {
-  if (JavaGenerator::GetResolvedSourceFeatures(*descriptor)
-          .GetExtension(pb::java)
-          .utf8_validation() == pb::JavaFeatures::VERIFY) {
-    return true;
-  }
-  return JavaGenerator::GetResolvedSourceFeatures(*descriptor)
-                 .utf8_validation() == FeatureSet::VERIFY ||
-         // For legacy syntax. This is not allowed under Editions.
-         descriptor->file()->options().java_string_check_utf8();
-}
-
 void WriteUInt32ToUtf16CharSequence(uint32_t number,
                                     std::vector<uint16_t>* output);
 
@@ -398,16 +372,6 @@
 // Escape a UTF-16 character so it can be embedded in a Java string literal.
 void EscapeUtf16ToString(uint16_t code, std::string* output);
 
-// Only the lowest two bytes of the return value are used. The lowest byte
-// is the integer value of a j/c/g/protobuf/FieldType enum. For the other
-// byte:
-//    bit 0: whether the field is required.
-//    bit 1: whether the field requires UTF-8 validation.
-//    bit 2: whether the field needs isInitialized check.
-//    bit 3: whether the field is a map field with proto2 enum value.
-//    bits 4-7: unused
-int GetExperimentalJavaFieldType(const FieldDescriptor* field);
-
 // To get the total number of entries need to be built for experimental runtime
 // and the first field number that are not in the table part
 std::pair<int, int> GetTableDrivenNumberOfEntriesAndLookUpStartFieldNumber(
diff --git a/src/google/protobuf/compiler/java/immutable/BUILD.bazel b/src/google/protobuf/compiler/java/immutable/BUILD.bazel
index a65a03a..baa679e 100644
--- a/src/google/protobuf/compiler/java/immutable/BUILD.bazel
+++ b/src/google/protobuf/compiler/java/immutable/BUILD.bazel
@@ -35,6 +35,7 @@
         "//src/google/protobuf:port",
         "//src/google/protobuf/compiler/java:generator_common",
         "//src/google/protobuf/compiler/java:helpers",
+        "//src/google/protobuf/compiler/java:internal_helpers",
         "//src/google/protobuf/io:printer",
         "@com_google_absl//absl/container:flat_hash_map",
         "@com_google_absl//absl/log:absl_check",
diff --git a/src/google/protobuf/compiler/java/immutable/enum_field.cc b/src/google/protobuf/compiler/java/immutable/enum_field.cc
index 2cb734f..399b8fe 100644
--- a/src/google/protobuf/compiler/java/immutable/enum_field.cc
+++ b/src/google/protobuf/compiler/java/immutable/enum_field.cc
@@ -22,6 +22,7 @@
 #include "google/protobuf/compiler/java/doc_comment.h"
 #include "google/protobuf/compiler/java/field_common.h"
 #include "google/protobuf/compiler/java/helpers.h"
+#include "google/protobuf/compiler/java/internal_helpers.h"
 #include "google/protobuf/compiler/java/name_resolver.h"
 #include "google/protobuf/io/printer.h"
 #include "google/protobuf/wire_format.h"
diff --git a/src/google/protobuf/compiler/java/immutable/map_field.cc b/src/google/protobuf/compiler/java/immutable/map_field.cc
index 02e8587..1016f74 100644
--- a/src/google/protobuf/compiler/java/immutable/map_field.cc
+++ b/src/google/protobuf/compiler/java/immutable/map_field.cc
@@ -15,6 +15,7 @@
 #include "google/protobuf/compiler/java/doc_comment.h"
 #include "google/protobuf/compiler/java/field_common.h"
 #include "google/protobuf/compiler/java/helpers.h"
+#include "google/protobuf/compiler/java/internal_helpers.h"
 #include "google/protobuf/compiler/java/name_resolver.h"
 #include "google/protobuf/io/printer.h"
 
diff --git a/src/google/protobuf/compiler/java/immutable/string_field.cc b/src/google/protobuf/compiler/java/immutable/string_field.cc
index c9ac5f4..3c47fb6 100644
--- a/src/google/protobuf/compiler/java/immutable/string_field.cc
+++ b/src/google/protobuf/compiler/java/immutable/string_field.cc
@@ -22,6 +22,7 @@
 #include "google/protobuf/compiler/java/doc_comment.h"
 #include "google/protobuf/compiler/java/field_common.h"
 #include "google/protobuf/compiler/java/helpers.h"
+#include "google/protobuf/compiler/java/internal_helpers.h"
 #include "google/protobuf/compiler/java/name_resolver.h"
 #include "google/protobuf/io/printer.h"
 #include "google/protobuf/wire_format.h"
diff --git a/src/google/protobuf/compiler/java/internal_helpers.cc b/src/google/protobuf/compiler/java/internal_helpers.cc
new file mode 100644
index 0000000..06dae86
--- /dev/null
+++ b/src/google/protobuf/compiler/java/internal_helpers.cc
@@ -0,0 +1,114 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file or at
+// https://developers.google.com/open-source/licenses/bsd
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include "google/protobuf/compiler/java/internal_helpers.h"
+
+#include "absl/log/absl_log.h"
+#include "google/protobuf/compiler/java/helpers.h"
+#include "google/protobuf/compiler/java/name_resolver.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 {
+
+int GetExperimentalJavaFieldTypeForSingular(const FieldDescriptor* field) {
+  // j/c/g/protobuf/FieldType.java lists field types in a slightly different
+  // order from FieldDescriptor::Type so we can't do a simple cast.
+  //
+  // TODO: Make j/c/g/protobuf/FieldType.java follow the same order.
+  int result = field->type();
+  if (result == FieldDescriptor::TYPE_GROUP) {
+    return 17;
+  } else if (result < FieldDescriptor::TYPE_GROUP) {
+    return result - 1;
+  } else {
+    return result - 2;
+  }
+}
+
+int GetExperimentalJavaFieldTypeForRepeated(const FieldDescriptor* field) {
+  if (field->type() == FieldDescriptor::TYPE_GROUP) {
+    return 49;
+  } else {
+    return GetExperimentalJavaFieldTypeForSingular(field) + 18;
+  }
+}
+
+int GetExperimentalJavaFieldTypeForPacked(const FieldDescriptor* field) {
+  int result = field->type();
+  if (result < FieldDescriptor::TYPE_STRING) {
+    return result + 34;
+  } else if (result > FieldDescriptor::TYPE_BYTES) {
+    return result + 30;
+  } else {
+    ABSL_LOG(FATAL) << field->full_name() << " can't be packed.";
+    return 0;
+  }
+}
+}  // namespace
+
+int GetExperimentalJavaFieldType(const FieldDescriptor* field) {
+  static const int kMapFieldType = 50;
+  static const int kOneofFieldTypeOffset = 51;
+
+  static const int kRequiredBit = 0x100;
+  static const int kUtf8CheckBit = 0x200;
+  static const int kCheckInitialized = 0x400;
+  static const int kLegacyEnumIsClosedBit = 0x800;
+  static const int kHasHasBit = 0x1000;
+  int extra_bits = field->is_required() ? kRequiredBit : 0;
+  if (field->type() == FieldDescriptor::TYPE_STRING && CheckUtf8(field)) {
+    extra_bits |= kUtf8CheckBit;
+  }
+  if (field->is_required() || (GetJavaType(field) == JAVATYPE_MESSAGE &&
+                               HasRequiredFields(field->message_type()))) {
+    extra_bits |= kCheckInitialized;
+  }
+  if (HasHasbit(field)) {
+    extra_bits |= kHasHasBit;
+  }
+  if (GetJavaType(field) == JAVATYPE_ENUM && !SupportUnknownEnumValue(field)) {
+    extra_bits |= kLegacyEnumIsClosedBit;
+  }
+
+  if (field->is_map()) {
+    if (!SupportUnknownEnumValue(MapValueField(field))) {
+      const FieldDescriptor* value = field->message_type()->map_value();
+      if (GetJavaType(value) == JAVATYPE_ENUM) {
+        extra_bits |= kLegacyEnumIsClosedBit;
+      }
+    }
+    return kMapFieldType | extra_bits;
+  } else if (field->is_packed()) {
+    return GetExperimentalJavaFieldTypeForPacked(field) | extra_bits;
+  } else if (field->is_repeated()) {
+    return GetExperimentalJavaFieldTypeForRepeated(field) | extra_bits;
+  } else if (IsRealOneof(field)) {
+    return (GetExperimentalJavaFieldTypeForSingular(field) +
+            kOneofFieldTypeOffset) |
+           extra_bits;
+  } else {
+    return GetExperimentalJavaFieldTypeForSingular(field) | extra_bits;
+  }
+}
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#include "google/protobuf/port_undef.inc"
diff --git a/src/google/protobuf/compiler/java/internal_helpers.h b/src/google/protobuf/compiler/java/internal_helpers.h
new file mode 100644
index 0000000..e2534b9
--- /dev/null
+++ b/src/google/protobuf/compiler/java/internal_helpers.h
@@ -0,0 +1,69 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file or at
+// https://developers.google.com/open-source/licenses/bsd
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_INTERNAL_HELPERS_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_INTERNAL_HELPERS_H__
+
+#include "google/protobuf/compiler/java/generator.h"
+#include "google/protobuf/compiler/java/java_features.pb.h"
+#include "google/protobuf/compiler/java/names.h"
+#include "google/protobuf/descriptor.h"
+#include "google/protobuf/descriptor.pb.h"
+
+// Must be last.
+#include "google/protobuf/port_def.inc"
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+// Whether unknown enum values are kept (i.e., not stored in UnknownFieldSet
+// but in the message and can be queried using additional getters that return
+// ints.
+inline bool SupportUnknownEnumValue(const FieldDescriptor* field) {
+  if (JavaGenerator::GetResolvedSourceFeatures(*field)
+          .GetExtension(pb::java)
+          .legacy_closed_enum()) {
+    return false;
+  }
+  return field->enum_type() != nullptr && !field->enum_type()->is_closed();
+}
+
+inline bool CheckUtf8(const FieldDescriptor* descriptor) {
+  if (JavaGenerator::GetResolvedSourceFeatures(*descriptor)
+          .GetExtension(pb::java)
+          .utf8_validation() == pb::JavaFeatures::VERIFY) {
+    return true;
+  }
+  return JavaGenerator::GetResolvedSourceFeatures(*descriptor)
+                 .utf8_validation() == FeatureSet::VERIFY ||
+         // For legacy syntax. This is not allowed under Editions.
+         descriptor->file()->options().java_string_check_utf8();
+}
+
+// Only the lowest two bytes of the return value are used. The lowest byte
+// is the integer value of a j/c/g/protobuf/FieldType enum. For the other
+// byte:
+//    bit 0: whether the field is required.
+//    bit 1: whether the field requires UTF-8 validation.
+//    bit 2: whether the field needs isInitialized check.
+//    bit 3: whether the field is a map field with proto2 enum value.
+//    bits 4-7: unused
+int GetExperimentalJavaFieldType(const FieldDescriptor* field);
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#include "google/protobuf/port_undef.inc"
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_INTERNAL_HELPERS_H__
diff --git a/src/google/protobuf/compiler/java/lite/BUILD.bazel b/src/google/protobuf/compiler/java/lite/BUILD.bazel
index 7904d4b..a26f8f9 100644
--- a/src/google/protobuf/compiler/java/lite/BUILD.bazel
+++ b/src/google/protobuf/compiler/java/lite/BUILD.bazel
@@ -30,6 +30,7 @@
         "//src/google/protobuf:port",
         "//src/google/protobuf/compiler/java:generator_common",
         "//src/google/protobuf/compiler/java:helpers",
+        "//src/google/protobuf/compiler/java:internal_helpers",
         "//src/google/protobuf/io:printer",
         "@com_google_absl//absl/container:flat_hash_map",
         "@com_google_absl//absl/log:absl_check",
@@ -66,6 +67,7 @@
         "//src/google/protobuf:port",
         "//src/google/protobuf/compiler/java:generator_common",
         "//src/google/protobuf/compiler/java:helpers",
+        "//src/google/protobuf/compiler/java:internal_helpers",
         "//src/google/protobuf/compiler/java/immutable:service",
         "//src/google/protobuf/io",
         "//src/google/protobuf/io:printer",
diff --git a/src/google/protobuf/compiler/java/lite/enum_field.cc b/src/google/protobuf/compiler/java/lite/enum_field.cc
index f2fb340..01d3ea6 100644
--- a/src/google/protobuf/compiler/java/lite/enum_field.cc
+++ b/src/google/protobuf/compiler/java/lite/enum_field.cc
@@ -17,11 +17,11 @@
 #include "absl/container/flat_hash_map.h"
 #include "absl/log/absl_check.h"
 #include "absl/strings/str_cat.h"
-#include "absl/strings/str_join.h"
 #include "google/protobuf/compiler/java/context.h"
 #include "google/protobuf/compiler/java/doc_comment.h"
 #include "google/protobuf/compiler/java/field_common.h"
 #include "google/protobuf/compiler/java/helpers.h"
+#include "google/protobuf/compiler/java/internal_helpers.h"
 #include "google/protobuf/compiler/java/name_resolver.h"
 #include "google/protobuf/io/printer.h"
 #include "google/protobuf/wire_format.h"
diff --git a/src/google/protobuf/compiler/java/lite/map_field.cc b/src/google/protobuf/compiler/java/lite/map_field.cc
index 74fc93f..044a99c 100644
--- a/src/google/protobuf/compiler/java/lite/map_field.cc
+++ b/src/google/protobuf/compiler/java/lite/map_field.cc
@@ -14,6 +14,7 @@
 #include "google/protobuf/compiler/java/doc_comment.h"
 #include "google/protobuf/compiler/java/field_common.h"
 #include "google/protobuf/compiler/java/helpers.h"
+#include "google/protobuf/compiler/java/internal_helpers.h"
 #include "google/protobuf/compiler/java/name_resolver.h"
 #include "google/protobuf/io/printer.h"
 
diff --git a/src/google/protobuf/compiler/java/lite/message_field.cc b/src/google/protobuf/compiler/java/lite/message_field.cc
index 7c5cc3c..e6245bd 100644
--- a/src/google/protobuf/compiler/java/lite/message_field.cc
+++ b/src/google/protobuf/compiler/java/lite/message_field.cc
@@ -19,6 +19,7 @@
 #include "google/protobuf/compiler/java/doc_comment.h"
 #include "google/protobuf/compiler/java/field_common.h"
 #include "google/protobuf/compiler/java/helpers.h"
+#include "google/protobuf/compiler/java/internal_helpers.h"
 #include "google/protobuf/compiler/java/name_resolver.h"
 #include "google/protobuf/io/printer.h"
 #include "google/protobuf/wire_format.h"
diff --git a/src/google/protobuf/compiler/java/lite/primitive_field.cc b/src/google/protobuf/compiler/java/lite/primitive_field.cc
index 69924c9..fc898f6 100644
--- a/src/google/protobuf/compiler/java/lite/primitive_field.cc
+++ b/src/google/protobuf/compiler/java/lite/primitive_field.cc
@@ -21,6 +21,7 @@
 #include "google/protobuf/compiler/java/doc_comment.h"
 #include "google/protobuf/compiler/java/field_common.h"
 #include "google/protobuf/compiler/java/helpers.h"
+#include "google/protobuf/compiler/java/internal_helpers.h"
 #include "google/protobuf/compiler/java/name_resolver.h"
 #include "google/protobuf/wire_format.h"
 
diff --git a/src/google/protobuf/compiler/java/lite/string_field.cc b/src/google/protobuf/compiler/java/lite/string_field.cc
index 833f415..9c91576 100644
--- a/src/google/protobuf/compiler/java/lite/string_field.cc
+++ b/src/google/protobuf/compiler/java/lite/string_field.cc
@@ -22,6 +22,7 @@
 #include "google/protobuf/compiler/java/doc_comment.h"
 #include "google/protobuf/compiler/java/field_common.h"
 #include "google/protobuf/compiler/java/helpers.h"
+#include "google/protobuf/compiler/java/internal_helpers.h"
 #include "google/protobuf/compiler/java/name_resolver.h"
 #include "google/protobuf/wire_format.h"