blob: 8deb2dcec302ad230b7842e7e90987092ba8405c [file] [log] [blame]
// 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/helpers.h"
#include <algorithm>
#include <cstdint>
#include <limits>
#include <vector>
#include "absl/container/flat_hash_set.h"
#include "absl/log/absl_check.h"
#include "absl/log/absl_log.h"
#include "absl/strings/ascii.h"
#include "absl/strings/escaping.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_format.h"
#include "absl/strings/str_replace.h"
#include "absl/strings/str_split.h"
#include "absl/strings/string_view.h"
#include "absl/strings/substitute.h"
#include "google/protobuf/compiler/java/name_resolver.h"
#include "google/protobuf/compiler/versions.h"
#include "google/protobuf/descriptor.pb.h"
#include "google/protobuf/io/printer.h"
#include "google/protobuf/io/strtod.h"
#include "google/protobuf/wire_format.h"
// Must be last.
#include "google/protobuf/port_def.inc"
namespace google {
namespace protobuf {
namespace compiler {
namespace java {
using ::google::protobuf::internal::WireFormat;
using ::google::protobuf::internal::WireFormatLite;
const char kThickSeparator[] =
"// ===================================================================\n";
const char kThinSeparator[] =
"// -------------------------------------------------------------------\n";
void PrintGeneratedAnnotation(io::Printer* printer, char delimiter,
absl::string_view annotation_file,
Options options) {
if (annotation_file.empty()) {
return;
}
std::string ptemplate =
"@javax.annotation.Generated(value=\"protoc\", comments=\"annotations:";
ptemplate.push_back(delimiter);
ptemplate.append("annotation_file");
ptemplate.push_back(delimiter);
ptemplate.append("\")\n");
printer->Print(ptemplate.c_str(), "annotation_file", annotation_file);
}
void PrintEnumVerifierLogic(
io::Printer* printer, const FieldDescriptor* descriptor,
const absl::flat_hash_map<absl::string_view, std::string>& variables,
absl::string_view var_name, absl::string_view terminating_string,
bool enforce_lite) {
std::string enum_verifier_string =
enforce_lite ? absl::StrCat(var_name, ".internalGetVerifier()")
: absl::StrCat(
"new com.google.protobuf.Internal.EnumVerifier() {\n"
" @java.lang.Override\n"
" public boolean isInRange(int number) {\n"
" return ",
var_name,
".forNumber(number) != null;\n"
" }\n"
" }");
printer->Print(variables,
absl::StrCat(enum_verifier_string, terminating_string));
}
void PrintGencodeVersionValidator(io::Printer* printer, bool oss_runtime,
absl::string_view java_class_name) {
const auto& version = GetProtobufJavaVersion(oss_runtime);
printer->Print(
"com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion(\n"
" com.google.protobuf.RuntimeVersion.RuntimeDomain.$domain$,\n"
" $major$,\n"
" $minor$,\n"
" $patch$,\n"
" $suffix$,\n"
" $location$);\n",
"domain", oss_runtime ? "PUBLIC" : "GOOGLE_INTERNAL", "major",
absl::StrCat("/* major= */ ", version.major()), "minor",
absl::StrCat("/* minor= */ ", version.minor()), "patch",
absl::StrCat("/* patch= */ ", version.patch()), "suffix",
absl::StrCat("/* suffix= */ \"", version.suffix(), "\""), "location",
absl::StrCat(java_class_name, ".class.getName()"));
}
std::string UnderscoresToCamelCase(absl::string_view input,
bool cap_next_letter) {
ABSL_CHECK(!input.empty());
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;
}
}
// Add a trailing "_" if the name should be altered.
if (input[input.size() - 1] == '#') {
result += '_';
}
return result;
}
std::string ToCamelCase(absl::string_view input, bool lower_first) {
bool capitalize_next = !lower_first;
std::string result;
result.reserve(input.size());
for (char i : input) {
if (i == '_') {
capitalize_next = true;
} else if (capitalize_next) {
result.push_back(absl::ascii_toupper(i));
capitalize_next = false;
} else {
result.push_back(i);
}
}
// Lower-case the first letter.
if (lower_first && !result.empty()) {
result[0] = absl::ascii_tolower(result[0]);
}
return result;
}
// 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) {
static const auto& kKotlinForbiddenNames =
*new absl::flat_hash_set<absl::string_view>({
"as", "as?", "break", "class", "continue", "do",
"else", "false", "for", "fun", "if", "in",
"!in", "interface", "is", "!is", "null", "object",
"package", "return", "super", "this", "throw", "true",
"try", "typealias", "typeof", "val", "var", "when",
"while",
});
return kKotlinForbiddenNames.contains(field_name);
}
std::string EscapeKotlinKeywords(std::string name) {
std::vector<std::string> escaped_packages;
std::vector<std::string> packages = absl::StrSplit(name, "."); // NOLINT
for (absl::string_view package : packages) {
if (IsForbiddenKotlin(package)) {
escaped_packages.push_back(absl::StrCat("`", package, "`"));
} else {
escaped_packages.emplace_back(package);
}
}
return absl::StrJoin(escaped_packages, ".");
}
std::string UniqueFileScopeIdentifier(const Descriptor* descriptor) {
return absl::StrCat(
"static_", absl::StrReplaceAll(descriptor->full_name(), {{".", "_"}}));
}
std::string CamelCaseFieldName(const FieldDescriptor* field) {
std::string fieldName = UnderscoresToCamelCase(field);
if ('0' <= fieldName[0] && fieldName[0] <= '9') {
return absl::StrCat("_", fieldName);
}
return fieldName;
}
std::string FileClassName(const FileDescriptor* file, bool immutable) {
return ClassNameResolver().GetFileClassName(file, immutable);
}
std::string JavaPackageToDir(std::string package_name) {
std::string package_dir = absl::StrReplaceAll(package_name, {{".", "/"}});
if (!package_dir.empty()) absl::StrAppend(&package_dir, "/");
return package_dir;
}
std::string ExtraMessageInterfaces(const Descriptor* descriptor) {
return absl::StrCat("// @@protoc_insertion_point(message_implements:",
descriptor->full_name(), ")");
}
std::string ExtraBuilderInterfaces(const Descriptor* descriptor) {
return absl::StrCat("// @@protoc_insertion_point(builder_implements:",
descriptor->full_name(), ")");
}
std::string ExtraMessageOrBuilderInterfaces(const Descriptor* descriptor) {
return absl::StrCat("// @@protoc_insertion_point(interface_extends:",
descriptor->full_name(), ")");
}
std::string FieldConstantName(const FieldDescriptor* field) {
std::string name = absl::StrCat(field->name(), "_FIELD_NUMBER");
absl::AsciiStrToUpper(&name);
return name;
}
FieldDescriptor::Type GetType(const FieldDescriptor* field) {
return field->type();
}
JavaType GetJavaType(const FieldDescriptor* field) {
switch (GetType(field)) {
case FieldDescriptor::TYPE_INT32:
case FieldDescriptor::TYPE_UINT32:
case FieldDescriptor::TYPE_SINT32:
case FieldDescriptor::TYPE_FIXED32:
case FieldDescriptor::TYPE_SFIXED32:
return JAVATYPE_INT;
case FieldDescriptor::TYPE_INT64:
case FieldDescriptor::TYPE_UINT64:
case FieldDescriptor::TYPE_SINT64:
case FieldDescriptor::TYPE_FIXED64:
case FieldDescriptor::TYPE_SFIXED64:
return JAVATYPE_LONG;
case FieldDescriptor::TYPE_FLOAT:
return JAVATYPE_FLOAT;
case FieldDescriptor::TYPE_DOUBLE:
return JAVATYPE_DOUBLE;
case FieldDescriptor::TYPE_BOOL:
return JAVATYPE_BOOLEAN;
case FieldDescriptor::TYPE_STRING:
return JAVATYPE_STRING;
case FieldDescriptor::TYPE_BYTES:
return JAVATYPE_BYTES;
case FieldDescriptor::TYPE_ENUM:
return JAVATYPE_ENUM;
case FieldDescriptor::TYPE_GROUP:
case FieldDescriptor::TYPE_MESSAGE:
return JAVATYPE_MESSAGE;
// No default because we want the compiler to complain if any new
// types are added.
}
ABSL_LOG(FATAL) << "Can't get here.";
return JAVATYPE_INT;
}
absl::string_view PrimitiveTypeName(JavaType type) {
switch (type) {
case JAVATYPE_INT:
return "int";
case JAVATYPE_LONG:
return "long";
case JAVATYPE_FLOAT:
return "float";
case JAVATYPE_DOUBLE:
return "double";
case JAVATYPE_BOOLEAN:
return "boolean";
case JAVATYPE_STRING:
return "java.lang.String";
case JAVATYPE_BYTES:
return "com.google.protobuf.ByteString";
case JAVATYPE_ENUM:
return {};
case JAVATYPE_MESSAGE:
return {};
// No default because we want the compiler to complain if any new
// JavaTypes are added.
}
ABSL_LOG(FATAL) << "Can't get here.";
return {};
}
absl::string_view PrimitiveTypeName(const FieldDescriptor* descriptor) {
return PrimitiveTypeName(GetJavaType(descriptor));
}
absl::string_view BoxedPrimitiveTypeName(JavaType type) {
switch (type) {
case JAVATYPE_INT:
return "java.lang.Integer";
case JAVATYPE_LONG:
return "java.lang.Long";
case JAVATYPE_FLOAT:
return "java.lang.Float";
case JAVATYPE_DOUBLE:
return "java.lang.Double";
case JAVATYPE_BOOLEAN:
return "java.lang.Boolean";
case JAVATYPE_STRING:
return "java.lang.String";
case JAVATYPE_BYTES:
return "com.google.protobuf.ByteString";
case JAVATYPE_ENUM:
return {};
case JAVATYPE_MESSAGE:
return {};
// No default because we want the compiler to complain if any new
// JavaTypes are added.
}
ABSL_LOG(FATAL) << "Can't get here.";
return {};
}
absl::string_view BoxedPrimitiveTypeName(const FieldDescriptor* descriptor) {
return BoxedPrimitiveTypeName(GetJavaType(descriptor));
}
absl::string_view KotlinTypeName(JavaType type) {
switch (type) {
case JAVATYPE_INT:
return "kotlin.Int";
case JAVATYPE_LONG:
return "kotlin.Long";
case JAVATYPE_FLOAT:
return "kotlin.Float";
case JAVATYPE_DOUBLE:
return "kotlin.Double";
case JAVATYPE_BOOLEAN:
return "kotlin.Boolean";
case JAVATYPE_STRING:
return "kotlin.String";
case JAVATYPE_BYTES:
return "com.google.protobuf.ByteString";
case JAVATYPE_ENUM:
return {};
case JAVATYPE_MESSAGE:
return {};
// No default because we want the compiler to complain if any new
// JavaTypes are added.
}
ABSL_LOG(FATAL) << "Can't get here.";
return {};
}
std::string GetOneofStoredType(const FieldDescriptor* field) {
const JavaType javaType = GetJavaType(field);
switch (javaType) {
case JAVATYPE_ENUM:
return "java.lang.Integer";
case JAVATYPE_MESSAGE:
return ClassNameResolver().GetClassName(field->message_type(), true);
default:
return std::string(BoxedPrimitiveTypeName(javaType));
}
}
absl::string_view FieldTypeName(FieldDescriptor::Type field_type) {
switch (field_type) {
case FieldDescriptor::TYPE_INT32:
return "INT32";
case FieldDescriptor::TYPE_UINT32:
return "UINT32";
case FieldDescriptor::TYPE_SINT32:
return "SINT32";
case FieldDescriptor::TYPE_FIXED32:
return "FIXED32";
case FieldDescriptor::TYPE_SFIXED32:
return "SFIXED32";
case FieldDescriptor::TYPE_INT64:
return "INT64";
case FieldDescriptor::TYPE_UINT64:
return "UINT64";
case FieldDescriptor::TYPE_SINT64:
return "SINT64";
case FieldDescriptor::TYPE_FIXED64:
return "FIXED64";
case FieldDescriptor::TYPE_SFIXED64:
return "SFIXED64";
case FieldDescriptor::TYPE_FLOAT:
return "FLOAT";
case FieldDescriptor::TYPE_DOUBLE:
return "DOUBLE";
case FieldDescriptor::TYPE_BOOL:
return "BOOL";
case FieldDescriptor::TYPE_STRING:
return "STRING";
case FieldDescriptor::TYPE_BYTES:
return "BYTES";
case FieldDescriptor::TYPE_ENUM:
return "ENUM";
case FieldDescriptor::TYPE_GROUP:
return "GROUP";
case FieldDescriptor::TYPE_MESSAGE:
return "MESSAGE";
// No default because we want the compiler to complain if any new
// types are added.
}
ABSL_LOG(FATAL) << "Can't get here.";
return {};
}
bool AllAscii(absl::string_view text) {
for (int i = 0; i < text.size(); i++) {
if ((text[i] & 0x80) != 0) {
return false;
}
}
return true;
}
std::string DefaultValue(const FieldDescriptor* field, bool immutable,
ClassNameResolver* name_resolver, Options options) {
// Switch on CppType since we need to know which default_value_* method
// of FieldDescriptor to call.
switch (field->cpp_type()) {
case FieldDescriptor::CPPTYPE_INT32:
return absl::StrCat(field->default_value_int32());
case FieldDescriptor::CPPTYPE_UINT32:
// Need to print as a signed int since Java has no unsigned.
return absl::StrCat(static_cast<int32_t>(field->default_value_uint32()));
case FieldDescriptor::CPPTYPE_INT64:
return absl::StrCat(field->default_value_int64(), "L");
case FieldDescriptor::CPPTYPE_UINT64:
return absl::StrCat(static_cast<int64_t>(field->default_value_uint64())) +
"L";
case FieldDescriptor::CPPTYPE_DOUBLE: {
double value = field->default_value_double();
if (value == std::numeric_limits<double>::infinity()) {
return "Double.POSITIVE_INFINITY";
} else if (value == -std::numeric_limits<double>::infinity()) {
return "Double.NEGATIVE_INFINITY";
} else if (value != value) {
return "Double.NaN";
} else {
return absl::StrCat(io::SimpleDtoa(value), "D");
}
}
case FieldDescriptor::CPPTYPE_FLOAT: {
float value = field->default_value_float();
if (value == std::numeric_limits<float>::infinity()) {
return "Float.POSITIVE_INFINITY";
} else if (value == -std::numeric_limits<float>::infinity()) {
return "Float.NEGATIVE_INFINITY";
} else if (value != value) {
return "Float.NaN";
} else {
return absl::StrCat(io::SimpleFtoa(value), "F");
}
}
case FieldDescriptor::CPPTYPE_BOOL:
return field->default_value_bool() ? "true" : "false";
case FieldDescriptor::CPPTYPE_STRING:
if (GetType(field) == FieldDescriptor::TYPE_BYTES) {
if (field->has_default_value()) {
// See comments in Internal.java for gory details.
return absl::Substitute(
"com.google.protobuf.Internal.bytesDefaultValue(\"$0\")",
absl::CEscape(field->default_value_string()));
} else {
return "com.google.protobuf.ByteString.EMPTY";
}
} else {
if (AllAscii(field->default_value_string())) {
// All chars are ASCII. In this case CEscape() works fine.
return absl::StrCat(
"\"", absl::CEscape(field->default_value_string()), "\"");
} else {
// See comments in Internal.java for gory details.
return absl::Substitute(
"com.google.protobuf.Internal.stringDefaultValue(\"$0\")",
absl::CEscape(field->default_value_string()));
}
}
case FieldDescriptor::CPPTYPE_ENUM:
return absl::StrCat(
name_resolver->GetClassName(field->enum_type(), immutable), ".",
field->default_value_enum()->name());
case FieldDescriptor::CPPTYPE_MESSAGE:
return absl::StrCat(
name_resolver->GetClassName(field->message_type(), immutable),
".getDefaultInstance()");
// No default because we want the compiler to complain if any new
// types are added.
}
ABSL_LOG(FATAL) << "Can't get here.";
return "";
}
bool IsDefaultValueJavaDefault(const FieldDescriptor* field) {
// Switch on CppType since we need to know which default_value_* method
// of FieldDescriptor to call.
switch (field->cpp_type()) {
case FieldDescriptor::CPPTYPE_INT32:
return field->default_value_int32() == 0;
case FieldDescriptor::CPPTYPE_UINT32:
return field->default_value_uint32() == 0;
case FieldDescriptor::CPPTYPE_INT64:
return field->default_value_int64() == 0L;
case FieldDescriptor::CPPTYPE_UINT64:
return field->default_value_uint64() == 0L;
case FieldDescriptor::CPPTYPE_DOUBLE:
return field->default_value_double() == 0.0;
case FieldDescriptor::CPPTYPE_FLOAT:
return field->default_value_float() == 0.0;
case FieldDescriptor::CPPTYPE_BOOL:
return field->default_value_bool() == false;
case FieldDescriptor::CPPTYPE_ENUM:
return field->default_value_enum()->number() == 0;
case FieldDescriptor::CPPTYPE_STRING:
case FieldDescriptor::CPPTYPE_MESSAGE:
return false;
// No default because we want the compiler to complain if any new
// types are added.
}
ABSL_LOG(FATAL) << "Can't get here.";
return false;
}
bool IsByteStringWithCustomDefaultValue(const FieldDescriptor* field) {
return GetJavaType(field) == JAVATYPE_BYTES &&
field->default_value_string() != "";
}
constexpr absl::string_view bit_masks[] = {
"0x00000001", "0x00000002", "0x00000004", "0x00000008",
"0x00000010", "0x00000020", "0x00000040", "0x00000080",
"0x00000100", "0x00000200", "0x00000400", "0x00000800",
"0x00001000", "0x00002000", "0x00004000", "0x00008000",
"0x00010000", "0x00020000", "0x00040000", "0x00080000",
"0x00100000", "0x00200000", "0x00400000", "0x00800000",
"0x01000000", "0x02000000", "0x04000000", "0x08000000",
"0x10000000", "0x20000000", "0x40000000", "0x80000000",
};
std::string GetBitFieldName(int index) {
return absl::StrCat("bitField", index, "_");
}
std::string GetBitFieldNameForBit(int bitIndex) {
return GetBitFieldName(bitIndex / 32);
}
namespace {
std::string GenerateGetBitInternal(absl::string_view prefix, int bitIndex) {
std::string varName = absl::StrCat(prefix, GetBitFieldNameForBit(bitIndex));
int bitInVarIndex = bitIndex % 32;
return absl::StrCat("((", varName, " & ", bit_masks[bitInVarIndex],
") != 0)");
}
std::string GenerateSetBitInternal(absl::string_view prefix, int bitIndex) {
std::string varName = absl::StrCat(prefix, GetBitFieldNameForBit(bitIndex));
int bitInVarIndex = bitIndex % 32;
return absl::StrCat(varName, " |= ", bit_masks[bitInVarIndex]);
}
} // namespace
std::string GenerateGetBit(int bitIndex) {
return GenerateGetBitInternal("", bitIndex);
}
std::string GenerateSetBit(int bitIndex) {
return GenerateSetBitInternal("", bitIndex);
}
std::string GenerateClearBit(int bitIndex) {
std::string varName = GetBitFieldNameForBit(bitIndex);
int bitInVarIndex = bitIndex % 32;
return absl::StrCat(varName, " = (", varName, " & ~",
bit_masks[bitInVarIndex], ")");
}
std::string GenerateGetBitFromLocal(int bitIndex) {
return GenerateGetBitInternal("from_", bitIndex);
}
std::string GenerateSetBitToLocal(int bitIndex) {
return GenerateSetBitInternal("to_", bitIndex);
}
std::string GenerateGetBitMutableLocal(int bitIndex) {
return GenerateGetBitInternal("mutable_", bitIndex);
}
std::string GenerateSetBitMutableLocal(int bitIndex) {
return GenerateSetBitInternal("mutable_", bitIndex);
}
bool IsReferenceType(JavaType type) {
switch (type) {
case JAVATYPE_INT:
return false;
case JAVATYPE_LONG:
return false;
case JAVATYPE_FLOAT:
return false;
case JAVATYPE_DOUBLE:
return false;
case JAVATYPE_BOOLEAN:
return false;
case JAVATYPE_STRING:
return true;
case JAVATYPE_BYTES:
return true;
case JAVATYPE_ENUM:
return true;
case JAVATYPE_MESSAGE:
return true;
// No default because we want the compiler to complain if any new
// JavaTypes are added.
}
ABSL_LOG(FATAL) << "Can't get here.";
return false;
}
absl::string_view GetCapitalizedType(const FieldDescriptor* field,
bool immutable, Options options) {
switch (GetType(field)) {
case FieldDescriptor::TYPE_INT32:
return "Int32";
case FieldDescriptor::TYPE_UINT32:
return "UInt32";
case FieldDescriptor::TYPE_SINT32:
return "SInt32";
case FieldDescriptor::TYPE_FIXED32:
return "Fixed32";
case FieldDescriptor::TYPE_SFIXED32:
return "SFixed32";
case FieldDescriptor::TYPE_INT64:
return "Int64";
case FieldDescriptor::TYPE_UINT64:
return "UInt64";
case FieldDescriptor::TYPE_SINT64:
return "SInt64";
case FieldDescriptor::TYPE_FIXED64:
return "Fixed64";
case FieldDescriptor::TYPE_SFIXED64:
return "SFixed64";
case FieldDescriptor::TYPE_FLOAT:
return "Float";
case FieldDescriptor::TYPE_DOUBLE:
return "Double";
case FieldDescriptor::TYPE_BOOL:
return "Bool";
case FieldDescriptor::TYPE_STRING:
return "String";
case FieldDescriptor::TYPE_BYTES: {
return "Bytes";
}
case FieldDescriptor::TYPE_ENUM:
return "Enum";
case FieldDescriptor::TYPE_GROUP:
return "Group";
case FieldDescriptor::TYPE_MESSAGE:
return "Message";
// No default because we want the compiler to complain if any new
// types are added.
}
ABSL_LOG(FATAL) << "Can't get here.";
return {};
}
// For encodings with fixed sizes, returns that size in bytes. Otherwise
// returns -1.
int FixedSize(FieldDescriptor::Type type) {
switch (type) {
case FieldDescriptor::TYPE_INT32:
return -1;
case FieldDescriptor::TYPE_INT64:
return -1;
case FieldDescriptor::TYPE_UINT32:
return -1;
case FieldDescriptor::TYPE_UINT64:
return -1;
case FieldDescriptor::TYPE_SINT32:
return -1;
case FieldDescriptor::TYPE_SINT64:
return -1;
case FieldDescriptor::TYPE_FIXED32:
return WireFormatLite::kFixed32Size;
case FieldDescriptor::TYPE_FIXED64:
return WireFormatLite::kFixed64Size;
case FieldDescriptor::TYPE_SFIXED32:
return WireFormatLite::kSFixed32Size;
case FieldDescriptor::TYPE_SFIXED64:
return WireFormatLite::kSFixed64Size;
case FieldDescriptor::TYPE_FLOAT:
return WireFormatLite::kFloatSize;
case FieldDescriptor::TYPE_DOUBLE:
return WireFormatLite::kDoubleSize;
case FieldDescriptor::TYPE_BOOL:
return WireFormatLite::kBoolSize;
case FieldDescriptor::TYPE_ENUM:
return -1;
case FieldDescriptor::TYPE_STRING:
return -1;
case FieldDescriptor::TYPE_BYTES:
return -1;
case FieldDescriptor::TYPE_GROUP:
return -1;
case FieldDescriptor::TYPE_MESSAGE:
return -1;
// No default because we want the compiler to complain if any new
// types are added.
}
ABSL_LOG(FATAL) << "Can't get here.";
return -1;
}
// Sort the fields of the given Descriptor by number into a new[]'d array
// and return it. The caller should delete the returned array.
const FieldDescriptor** SortFieldsByNumber(const Descriptor* descriptor) {
const FieldDescriptor** fields =
new const FieldDescriptor*[descriptor->field_count()];
for (int i = 0; i < descriptor->field_count(); i++) {
fields[i] = descriptor->field(i);
}
std::sort(fields, fields + descriptor->field_count(),
FieldOrderingByNumber());
return fields;
}
// Returns true if the message type has any required fields. If it doesn't,
// we can optimize out calls to its isInitialized() method.
//
// already_seen is used to avoid checking the same type multiple times
// (and also to protect against recursion).
bool HasRequiredFields(const Descriptor* type,
absl::flat_hash_set<const Descriptor*>* already_seen) {
if (already_seen->count(type) > 0) {
// The type is already in cache. This means that either:
// a. The type has no required fields.
// b. We are in the midst of checking if the type has required fields,
// somewhere up the stack. In this case, we know that if the type
// has any required fields, they'll be found when we return to it,
// and the whole call to HasRequiredFields() will return true.
// Therefore, we don't have to check if this type has required fields
// here.
return false;
}
already_seen->insert(type);
// If the type has extensions, an extension with message type could contain
// required fields, so we have to be conservative and assume such an
// extension exists.
if (type->extension_range_count() > 0) return true;
for (int i = 0; i < type->field_count(); i++) {
const FieldDescriptor* field = type->field(i);
if (field->is_required()) {
return true;
}
if (GetJavaType(field) == JAVATYPE_MESSAGE) {
if (HasRequiredFields(field->message_type(), already_seen)) {
return true;
}
}
}
return false;
}
bool HasRequiredFields(const Descriptor* type) {
absl::flat_hash_set<const Descriptor*> already_seen;
return HasRequiredFields(type, &already_seen);
}
bool IsRealOneof(const FieldDescriptor* descriptor) {
return descriptor->real_containing_oneof();
}
bool HasRepeatedFields(const Descriptor* descriptor) {
for (int i = 0; i < descriptor->field_count(); ++i) {
const FieldDescriptor* field = descriptor->field(i);
if (field->is_repeated()) {
return true;
}
}
return false;
}
// Encode an unsigned 32-bit value into a sequence of UTF-16 characters.
//
// If the value is in [0x0000, 0xD7FF], we encode it with a single character
// with the same numeric value.
//
// If the value is larger than 0xD7FF, we encode its lowest 13 bits into a
// character in the range [0xE000, 0xFFFF] by combining these 13 bits with
// 0xE000 using logic-or. Then we shift the value to the right by 13 bits, and
// encode the remaining value by repeating this same process until we get to
// a value in [0x0000, 0xD7FF] where we will encode it using a character with
// the same numeric value.
//
// Note that we only use code points in [0x0000, 0xD7FF] and [0xE000, 0xFFFF].
// There will be no surrogate pairs in the encoded character sequence.
void WriteUInt32ToUtf16CharSequence(uint32_t number,
std::vector<uint16_t>* output) {
// For values in [0x0000, 0xD7FF], only use one char to encode it.
if (number < 0xD800) {
output->push_back(static_cast<uint16_t>(number));
return;
}
// Encode into multiple chars. All except the last char will be in the range
// [0xE000, 0xFFFF], and the last char will be in the range [0x0000, 0xD7FF].
// Note that we don't use any value in range [0xD800, 0xDFFF] because they
// have to come in pairs and the encoding is just more space-efficient w/o
// them.
while (number >= 0xD800) {
// [0xE000, 0xFFFF] can represent 13 bits of info.
output->push_back(static_cast<uint16_t>(0xE000 | (number & 0x1FFF)));
number >>= 13;
}
output->push_back(static_cast<uint16_t>(number));
}
// Escape a UTF-16 character to be embedded in a Java string.
void EscapeUtf16ToString(uint16_t code, std::string* output) {
if (code == '\t') {
output->append("\\t");
} else if (code == '\b') {
output->append("\\b");
} else if (code == '\n') {
output->append("\\n");
} else if (code == '\r') {
output->append("\\r");
} else if (code == '\f') {
output->append("\\f");
} else if (code == '\'') {
output->append("\\'");
} else if (code == '\"') {
output->append("\\\"");
} else if (code == '\\') {
output->append("\\\\");
} else if (code >= 0x20 && code <= 0x7f) {
output->push_back(static_cast<char>(code));
} else {
output->append(absl::StrFormat("\\u%04x", code));
}
}
const FieldDescriptor* MapKeyField(const FieldDescriptor* descriptor) {
ABSL_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, descriptor->type());
const Descriptor* message = descriptor->message_type();
ABSL_CHECK(message->options().map_entry());
return message->map_key();
}
const FieldDescriptor* MapValueField(const FieldDescriptor* descriptor) {
ABSL_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, descriptor->type());
const Descriptor* message = descriptor->message_type();
ABSL_CHECK(message->options().map_entry());
return message->map_value();
}
} // namespace java
} // namespace compiler
} // namespace protobuf
} // namespace google
#include "google/protobuf/port_undef.inc"