[ObjC] First pass at bringing back helpers.cc

There are still some things not related to naming in naming.h, but they are
current exposed for gRPC to use.
pull/10720/head
Thomas Van Lenten 2 years ago
parent 53d8b03643
commit 2b3a6d2cdc
  1. 1
      src/file_lists.cmake
  2. 1
      src/google/protobuf/compiler/objectivec/BUILD.bazel
  3. 1
      src/google/protobuf/compiler/objectivec/enum.cc
  4. 1
      src/google/protobuf/compiler/objectivec/enum_field.cc
  5. 1
      src/google/protobuf/compiler/objectivec/extension.cc
  6. 1
      src/google/protobuf/compiler/objectivec/field.cc
  7. 1
      src/google/protobuf/compiler/objectivec/file.cc
  8. 1
      src/google/protobuf/compiler/objectivec/generator.cc
  9. 885
      src/google/protobuf/compiler/objectivec/helpers.cc
  10. 168
      src/google/protobuf/compiler/objectivec/helpers.h
  11. 1
      src/google/protobuf/compiler/objectivec/helpers_unittest.cc
  12. 1
      src/google/protobuf/compiler/objectivec/map_field.cc
  13. 1
      src/google/protobuf/compiler/objectivec/message.cc
  14. 1
      src/google/protobuf/compiler/objectivec/message_field.cc
  15. 752
      src/google/protobuf/compiler/objectivec/names.cc
  16. 194
      src/google/protobuf/compiler/objectivec/names.h
  17. 1
      src/google/protobuf/compiler/objectivec/oneof.cc
  18. 1
      src/google/protobuf/compiler/objectivec/primitive_field.cc

@ -356,6 +356,7 @@ set(libprotoc_srcs
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/field.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/file.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/generator.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/helpers.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/map_field.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/message.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/message_field.cc

@ -44,6 +44,7 @@ cc_library(
"field.cc",
"file.cc",
"generator.cc",
"helpers.cc",
"map_field.cc",
"message.cc",
"message_field.cc",

@ -36,6 +36,7 @@
#include "absl/strings/escaping.h"
#include "absl/strings/str_cat.h"
#include "google/protobuf/compiler/objectivec/names.h"
#include "google/protobuf/compiler/objectivec/helpers.h"
#include "google/protobuf/io/printer.h"

@ -32,6 +32,7 @@
#include <string>
#include "google/protobuf/compiler/objectivec/enum_field.h"
#include "google/protobuf/compiler/objectivec/names.h"
#include "google/protobuf/compiler/objectivec/helpers.h"
#include "google/protobuf/io/printer.h"

@ -33,6 +33,7 @@
#include <iostream>
#include "absl/strings/str_cat.h"
#include "google/protobuf/compiler/objectivec/names.h"
#include "google/protobuf/compiler/objectivec/helpers.h"
#include "google/protobuf/descriptor.pb.h"
#include "google/protobuf/io/printer.h"

@ -34,6 +34,7 @@
#include "absl/strings/str_cat.h"
#include "google/protobuf/compiler/objectivec/enum_field.h"
#include "google/protobuf/compiler/objectivec/names.h"
#include "google/protobuf/compiler/objectivec/helpers.h"
#include "google/protobuf/compiler/objectivec/map_field.h"
#include "google/protobuf/compiler/objectivec/message_field.h"

@ -38,6 +38,7 @@
#include "absl/strings/str_cat.h"
#include "google/protobuf/compiler/objectivec/enum.h"
#include "google/protobuf/compiler/objectivec/extension.h"
#include "google/protobuf/compiler/objectivec/names.h"
#include "google/protobuf/compiler/objectivec/helpers.h"
#include "google/protobuf/compiler/objectivec/message.h"
#include "google/protobuf/io/printer.h"

@ -39,6 +39,7 @@
#include "absl/strings/str_split.h"
#include "absl/strings/strip.h"
#include "google/protobuf/compiler/objectivec/file.h"
#include "google/protobuf/compiler/objectivec/names.h"
#include "google/protobuf/compiler/objectivec/helpers.h"
#include "google/protobuf/io/printer.h"
#include "google/protobuf/io/zero_copy_stream.h"

@ -0,0 +1,885 @@
// 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/code_generator.h"
#include "google/protobuf/stubs/strutil.h"
#include "absl/strings/ascii.h"
#include "absl/strings/escaping.h"
#include "absl/strings/str_replace.h"
#include "absl/strings/str_split.h"
#include "google/protobuf/compiler/objectivec/helpers.h"
#include "google/protobuf/compiler/objectivec/names.h"
#include "google/protobuf/io/printer.h"
#include "google/protobuf/io/zero_copy_stream_impl.h"
// NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some
// error cases, so it seems to be ok to use as a back door for errors.
namespace google {
namespace protobuf {
namespace compiler {
namespace objectivec {
std::string EscapeTrigraphs(absl::string_view to_escape) {
return absl::StrReplaceAll(to_escape, {{"?", "\\?"}});
}
namespace {
std::string GetZeroEnumNameForFlagType(const FlagType flag_type) {
switch(flag_type) {
case FLAGTYPE_DESCRIPTOR_INITIALIZATION:
return "GPBDescriptorInitializationFlag_None";
case FLAGTYPE_EXTENSION:
return "GPBExtensionNone";
case FLAGTYPE_FIELD:
return "GPBFieldNone";
default:
GOOGLE_LOG(FATAL) << "Can't get here.";
return "0";
}
}
std::string GetEnumNameForFlagType(const FlagType flag_type) {
switch(flag_type) {
case FLAGTYPE_DESCRIPTOR_INITIALIZATION:
return "GPBDescriptorInitializationFlags";
case FLAGTYPE_EXTENSION:
return "GPBExtensionOptions";
case FLAGTYPE_FIELD:
return "GPBFieldFlags";
default:
GOOGLE_LOG(FATAL) << "Can't get here.";
return std::string();
}
}
std::string HandleExtremeFloatingPoint(std::string val,
bool add_float_suffix) {
if (val == "nan") {
return "NAN";
} else if (val == "inf") {
return "INFINITY";
} else if (val == "-inf") {
return "-INFINITY";
} else {
// float strings with ., e or E need to have f appended
if (add_float_suffix && (val.find('.') != std::string::npos ||
val.find('e') != std::string::npos ||
val.find('E') != std::string::npos)) {
val += "f";
}
return val;
}
}
} // namespace
std::string GetCapitalizedType(const FieldDescriptor* field) {
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";
}
// Some compilers report reaching end of function even though all cases of
// the enum are handed in the switch.
GOOGLE_LOG(FATAL) << "Can't get here.";
return std::string();
}
ObjectiveCType GetObjectiveCType(FieldDescriptor::Type field_type) {
switch (field_type) {
case FieldDescriptor::TYPE_INT32:
case FieldDescriptor::TYPE_SINT32:
case FieldDescriptor::TYPE_SFIXED32:
return OBJECTIVECTYPE_INT32;
case FieldDescriptor::TYPE_UINT32:
case FieldDescriptor::TYPE_FIXED32:
return OBJECTIVECTYPE_UINT32;
case FieldDescriptor::TYPE_INT64:
case FieldDescriptor::TYPE_SINT64:
case FieldDescriptor::TYPE_SFIXED64:
return OBJECTIVECTYPE_INT64;
case FieldDescriptor::TYPE_UINT64:
case FieldDescriptor::TYPE_FIXED64:
return OBJECTIVECTYPE_UINT64;
case FieldDescriptor::TYPE_FLOAT:
return OBJECTIVECTYPE_FLOAT;
case FieldDescriptor::TYPE_DOUBLE:
return OBJECTIVECTYPE_DOUBLE;
case FieldDescriptor::TYPE_BOOL:
return OBJECTIVECTYPE_BOOLEAN;
case FieldDescriptor::TYPE_STRING:
return OBJECTIVECTYPE_STRING;
case FieldDescriptor::TYPE_BYTES:
return OBJECTIVECTYPE_DATA;
case FieldDescriptor::TYPE_ENUM:
return OBJECTIVECTYPE_ENUM;
case FieldDescriptor::TYPE_GROUP:
case FieldDescriptor::TYPE_MESSAGE:
return OBJECTIVECTYPE_MESSAGE;
}
// Some compilers report reaching end of function even though all cases of
// the enum are handed in the switch.
GOOGLE_LOG(FATAL) << "Can't get here.";
return OBJECTIVECTYPE_INT32;
}
bool IsPrimitiveType(const FieldDescriptor* field) {
ObjectiveCType type = GetObjectiveCType(field);
switch (type) {
case OBJECTIVECTYPE_INT32:
case OBJECTIVECTYPE_UINT32:
case OBJECTIVECTYPE_INT64:
case OBJECTIVECTYPE_UINT64:
case OBJECTIVECTYPE_FLOAT:
case OBJECTIVECTYPE_DOUBLE:
case OBJECTIVECTYPE_BOOLEAN:
case OBJECTIVECTYPE_ENUM:
return true;
break;
default:
return false;
}
}
std::string GPBGenericValueFieldName(const FieldDescriptor* field) {
// Returns the field within the GPBGenericValue union to use for the given
// field.
if (field->is_repeated()) {
return "valueMessage";
}
switch (field->cpp_type()) {
case FieldDescriptor::CPPTYPE_INT32:
return "valueInt32";
case FieldDescriptor::CPPTYPE_UINT32:
return "valueUInt32";
case FieldDescriptor::CPPTYPE_INT64:
return "valueInt64";
case FieldDescriptor::CPPTYPE_UINT64:
return "valueUInt64";
case FieldDescriptor::CPPTYPE_FLOAT:
return "valueFloat";
case FieldDescriptor::CPPTYPE_DOUBLE:
return "valueDouble";
case FieldDescriptor::CPPTYPE_BOOL:
return "valueBool";
case FieldDescriptor::CPPTYPE_STRING:
if (field->type() == FieldDescriptor::TYPE_BYTES) {
return "valueData";
} else {
return "valueString";
}
case FieldDescriptor::CPPTYPE_ENUM:
return "valueEnum";
case FieldDescriptor::CPPTYPE_MESSAGE:
return "valueMessage";
}
// Some compilers report reaching end of function even though all cases of
// the enum are handed in the switch.
GOOGLE_LOG(FATAL) << "Can't get here.";
return std::string();
}
std::string DefaultValue(const FieldDescriptor* field) {
// Repeated fields don't have defaults.
if (field->is_repeated()) {
return "nil";
}
// Switch on cpp_type since we need to know which default_value_* method
// of FieldDescriptor to call.
switch (field->cpp_type()) {
case FieldDescriptor::CPPTYPE_INT32:
// gcc and llvm reject the decimal form of kint32min and kint64min.
if (field->default_value_int32() == INT_MIN) {
return "-0x80000000";
}
return absl::StrCat(field->default_value_int32());
case FieldDescriptor::CPPTYPE_UINT32:
return absl::StrCat(field->default_value_uint32()) + "U";
case FieldDescriptor::CPPTYPE_INT64:
// gcc and llvm reject the decimal form of kint32min and kint64min.
if (field->default_value_int64() == LLONG_MIN) {
return "-0x8000000000000000LL";
}
return absl::StrCat(field->default_value_int64()) + "LL";
case FieldDescriptor::CPPTYPE_UINT64:
return absl::StrCat(field->default_value_uint64()) + "ULL";
case FieldDescriptor::CPPTYPE_DOUBLE:
return HandleExtremeFloatingPoint(
SimpleDtoa(field->default_value_double()), false);
case FieldDescriptor::CPPTYPE_FLOAT:
return HandleExtremeFloatingPoint(
SimpleFtoa(field->default_value_float()), true);
case FieldDescriptor::CPPTYPE_BOOL:
return field->default_value_bool() ? "YES" : "NO";
case FieldDescriptor::CPPTYPE_STRING: {
const bool has_default_value = field->has_default_value();
const std::string& default_string = field->default_value_string();
if (!has_default_value || default_string.length() == 0) {
// If the field is defined as being the empty string,
// then we will just assign to nil, as the empty string is the
// default for both strings and data.
return "nil";
}
if (field->type() == FieldDescriptor::TYPE_BYTES) {
// We want constant fields in our data structures so we can
// declare them as static. To achieve this we cheat and stuff
// a escaped c string (prefixed with a length) into the data
// field, and cast it to an (NSData*) so it will compile.
// The runtime library knows how to handle it.
// Must convert to a standard byte order for packing length into
// a cstring.
uint32_t length = ghtonl(default_string.length());
std::string bytes((const char*)&length, sizeof(length));
bytes.append(default_string);
return "(NSData*)\"" + EscapeTrigraphs(absl::CEscape(bytes)) + "\"";
} else {
return "@\"" + EscapeTrigraphs(absl::CEscape(default_string)) + "\"";
}
}
case FieldDescriptor::CPPTYPE_ENUM:
return EnumValueName(field->default_value_enum());
case FieldDescriptor::CPPTYPE_MESSAGE:
return "nil";
}
// Some compilers report reaching end of function even though all cases of
// the enum are handed in the switch.
GOOGLE_LOG(FATAL) << "Can't get here.";
return std::string();
}
bool HasNonZeroDefaultValue(const FieldDescriptor* field) {
// Repeated fields don't have defaults.
if (field->is_repeated()) {
return false;
}
// As much as checking field->has_default_value() seems useful, it isn't
// because of enums. proto2 syntax allows the first item in an enum (the
// default) to be non zero. So checking field->has_default_value() would
// result in missing this non zero default. See MessageWithOneBasedEnum in
// objectivec/Tests/unittest_objc.proto for a test Message to confirm this.
// Some proto file set the default to the zero value, so make sure the value
// isn't the zero case.
switch (field->cpp_type()) {
case FieldDescriptor::CPPTYPE_INT32:
return field->default_value_int32() != 0;
case FieldDescriptor::CPPTYPE_UINT32:
return field->default_value_uint32() != 0U;
case FieldDescriptor::CPPTYPE_INT64:
return field->default_value_int64() != 0LL;
case FieldDescriptor::CPPTYPE_UINT64:
return field->default_value_uint64() != 0ULL;
case FieldDescriptor::CPPTYPE_DOUBLE:
return field->default_value_double() != 0.0;
case FieldDescriptor::CPPTYPE_FLOAT:
return field->default_value_float() != 0.0f;
case FieldDescriptor::CPPTYPE_BOOL:
return field->default_value_bool();
case FieldDescriptor::CPPTYPE_STRING: {
const std::string& default_string = field->default_value_string();
return default_string.length() != 0;
}
case FieldDescriptor::CPPTYPE_ENUM:
return field->default_value_enum()->number() != 0;
case FieldDescriptor::CPPTYPE_MESSAGE:
return false;
}
// Some compilers report reaching end of function even though all cases of
// the enum are handed in the switch.
GOOGLE_LOG(FATAL) << "Can't get here.";
return false;
}
std::string BuildFlagsString(const FlagType flag_type,
const std::vector<std::string>& strings) {
if (strings.empty()) {
return GetZeroEnumNameForFlagType(flag_type);
} else if (strings.size() == 1) {
return strings[0];
}
std::string string("(" + GetEnumNameForFlagType(flag_type) + ")(");
for (size_t i = 0; i != strings.size(); ++i) {
if (i > 0) {
string.append(" | ");
}
string.append(strings[i]);
}
string.append(")");
return string;
}
std::string ObjCClass(const std::string& class_name) {
return std::string("GPBObjCClass(") + class_name + ")";
}
std::string ObjCClassDeclaration(const std::string& class_name) {
return std::string("GPBObjCClassDeclaration(") + class_name + ");";
}
std::string BuildCommentsString(const SourceLocation& location,
bool prefer_single_line) {
const std::string& comments = location.leading_comments.empty()
? location.trailing_comments
: location.leading_comments;
std::vector<std::string> lines;
lines = absl::StrSplit(comments, "\n", absl::AllowEmpty());
while (!lines.empty() && lines.back().empty()) {
lines.pop_back();
}
// If there are no comments, just return an empty string.
if (lines.empty()) {
return "";
}
std::string prefix;
std::string suffix;
std::string final_comments;
std::string epilogue;
bool add_leading_space = false;
if (prefer_single_line && lines.size() == 1) {
prefix = "/** ";
suffix = " */\n";
} else {
prefix = "* ";
suffix = "\n";
final_comments += "/**\n";
epilogue = " **/\n";
add_leading_space = true;
}
for (size_t i = 0; i < lines.size(); i++) {
std::string line = absl::StrReplaceAll(
absl::StripPrefix(lines[i], " "),
{// HeaderDoc and appledoc use '\' and '@' for markers; escape them.
{"\\", "\\\\"},
{"@", "\\@"},
// Decouple / from * to not have inline comments inside comments.
{"/*", "/\\*"},
{"*/", "*\\/"}});
line = prefix + line;
absl::StripAsciiWhitespace(&line);
// If not a one line, need to add the first space before *, as
// absl::StripAsciiWhitespace would have removed it.
line = (add_leading_space ? " " : "") + line;
final_comments += line + suffix;
}
final_comments += epilogue;
return final_comments;
}
TextFormatDecodeData::TextFormatDecodeData() { }
TextFormatDecodeData::~TextFormatDecodeData() { }
void TextFormatDecodeData::AddString(int32_t key,
const std::string& input_for_decode,
const std::string& desired_output) {
for (std::vector<DataEntry>::const_iterator i = entries_.begin();
i != entries_.end(); ++i) {
if (i->first == key) {
std::cerr << "error: duplicate key (" << key
<< ") making TextFormat data, input: \"" << input_for_decode
<< "\", desired: \"" << desired_output << "\"." << std::endl;
std::cerr.flush();
abort();
}
}
const std::string& data = TextFormatDecodeData::DecodeDataForString(
input_for_decode, desired_output);
entries_.push_back(DataEntry(key, data));
}
std::string TextFormatDecodeData::Data() const {
std::ostringstream data_stringstream;
if (num_entries() > 0) {
io::OstreamOutputStream data_outputstream(&data_stringstream);
io::CodedOutputStream output_stream(&data_outputstream);
output_stream.WriteVarint32(num_entries());
for (std::vector<DataEntry>::const_iterator i = entries_.begin();
i != entries_.end(); ++i) {
output_stream.WriteVarint32(i->first);
output_stream.WriteString(i->second);
}
}
data_stringstream.flush();
return data_stringstream.str();
}
namespace {
// Helper to build up the decode data for a string.
class DecodeDataBuilder {
public:
DecodeDataBuilder() { Reset(); }
bool AddCharacter(const char desired, const char input);
void AddUnderscore() {
Push();
need_underscore_ = true;
}
std::string Finish() {
Push();
return decode_data_;
}
private:
static constexpr uint8_t kAddUnderscore = 0x80;
static constexpr uint8_t kOpAsIs = 0x00;
static constexpr uint8_t kOpFirstUpper = 0x40;
static constexpr uint8_t kOpFirstLower = 0x20;
static constexpr uint8_t kOpAllUpper = 0x60;
static constexpr int kMaxSegmentLen = 0x1f;
void AddChar(const char desired) {
++segment_len_;
is_all_upper_ &= absl::ascii_isupper(desired);
}
void Push() {
uint8_t op = (op_ | segment_len_);
if (need_underscore_) op |= kAddUnderscore;
if (op != 0) {
decode_data_ += (char)op;
}
Reset();
}
bool AddFirst(const char desired, const char input) {
if (desired == input) {
op_ = kOpAsIs;
} else if (desired == absl::ascii_toupper(input)) {
op_ = kOpFirstUpper;
} else if (desired == absl::ascii_tolower(input)) {
op_ = kOpFirstLower;
} else {
// Can't be transformed to match.
return false;
}
AddChar(desired);
return true;
}
void Reset() {
need_underscore_ = false;
op_ = 0;
segment_len_ = 0;
is_all_upper_ = true;
}
bool need_underscore_;
bool is_all_upper_;
uint8_t op_;
int segment_len_;
std::string decode_data_;
};
bool DecodeDataBuilder::AddCharacter(const char desired, const char input) {
// If we've hit the max size, push to start a new segment.
if (segment_len_ == kMaxSegmentLen) {
Push();
}
if (segment_len_ == 0) {
return AddFirst(desired, input);
}
// Desired and input match...
if (desired == input) {
// If we aren't transforming it, or we're upper casing it and it is
// supposed to be uppercase; just add it to the segment.
if ((op_ != kOpAllUpper) || absl::ascii_isupper(desired)) {
AddChar(desired);
return true;
}
// Add the current segment, and start the next one.
Push();
return AddFirst(desired, input);
}
// If we need to uppercase, and everything so far has been uppercase,
// promote op to AllUpper.
if ((desired == absl::ascii_toupper(input)) && is_all_upper_) {
op_ = kOpAllUpper;
AddChar(desired);
return true;
}
// Give up, push and start a new segment.
Push();
return AddFirst(desired, input);
}
// If decode data can't be generated, a directive for the raw string
// is used instead.
std::string DirectDecodeString(const std::string& str) {
std::string result;
result += (char)'\0'; // Marker for full string.
result += str;
result += (char)'\0'; // End of string.
return result;
}
} // namespace
// static
std::string TextFormatDecodeData::DecodeDataForString(
const std::string& input_for_decode, const std::string& desired_output) {
if (input_for_decode.empty() || desired_output.empty()) {
std::cerr << "error: got empty string for making TextFormat data, input: \""
<< input_for_decode << "\", desired: \"" << desired_output << "\"."
<< std::endl;
std::cerr.flush();
abort();
}
if ((input_for_decode.find('\0') != std::string::npos) ||
(desired_output.find('\0') != std::string::npos)) {
std::cerr << "error: got a null char in a string for making TextFormat data,"
<< " input: \"" << absl::CEscape(input_for_decode) << "\", desired: \""
<< absl::CEscape(desired_output) << "\"." << std::endl;
std::cerr.flush();
abort();
}
DecodeDataBuilder builder;
// Walk the output building it from the input.
int x = 0;
for (int y = 0; y < desired_output.size(); y++) {
const char d = desired_output[y];
if (d == '_') {
builder.AddUnderscore();
continue;
}
if (x >= input_for_decode.size()) {
// Out of input, no way to encode it, just return a full decode.
return DirectDecodeString(desired_output);
}
if (builder.AddCharacter(d, input_for_decode[x])) {
++x; // Consumed one input
} else {
// Couldn't transform for the next character, just return a full decode.
return DirectDecodeString(desired_output);
}
}
if (x != input_for_decode.size()) {
// Extra input (suffix from name sanitizing?), just return a full decode.
return DirectDecodeString(desired_output);
}
// Add the end marker.
return builder.Finish() + (char)'\0';
}
namespace {
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_;
};
bool ProtoFrameworkCollector::ConsumeLine(
const absl::string_view& line, std::string* out_error) {
int offset = line.find(':');
if (offset == absl::string_view::npos) {
*out_error =
std::string("Framework/proto file mapping line without colon sign: '") +
std::string(line) + "'.";
return false;
}
absl::string_view framework_name = line.substr(0, offset);
absl::string_view proto_file_list = line.substr(offset + 1);
TrimWhitespace(&framework_name);
int start = 0;
while (start < proto_file_list.length()) {
offset = proto_file_list.find(',', start);
if (offset == absl::string_view::npos) {
offset = proto_file_list.length();
}
absl::string_view proto_file = proto_file_list.substr(start, offset - start);
TrimWhitespace(&proto_file);
if (!proto_file.empty()) {
std::map<std::string, std::string>::iterator existing_entry =
map_->find(std::string(proto_file));
if (existing_entry != map_->end()) {
std::cerr << "warning: duplicate proto file reference, replacing "
"framework entry for '"
<< std::string(proto_file) << "' with '" << std::string(framework_name)
<< "' (was '" << existing_entry->second << "')." << std::endl;
std::cerr.flush();
}
if (proto_file.find(' ') != absl::string_view::npos) {
std::cerr << "note: framework mapping file had a proto file with a "
"space in, hopefully that isn't a missing comma: '"
<< std::string(proto_file) << "'" << std::endl;
std::cerr.flush();
}
(*map_)[std::string(proto_file)] = std::string(framework_name);
}
start = offset + 1;
}
return true;
}
}
ImportWriter::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)
: generate_for_named_framework_(generate_for_named_framework),
named_framework_to_proto_path_mappings_path_(
named_framework_to_proto_path_mappings_path),
runtime_import_prefix_(runtime_import_prefix),
include_wkt_imports_(include_wkt_imports),
need_to_parse_mapping_file_(true) {}
ImportWriter::~ImportWriter() {}
void ImportWriter::AddFile(const FileDescriptor* file,
const std::string& header_extension) {
if (IsProtobufLibraryBundledProtoFile(file)) {
// The imports of the WKTs are only needed within the library itself,
// in other cases, they get skipped because the generated code already
// import GPBProtocolBuffers.h and hence proves them.
if (include_wkt_imports_) {
const std::string header_name =
"GPB" + FilePathBasename(file) + header_extension;
protobuf_imports_.push_back(header_name);
}
return;
}
// Lazy parse any mappings.
if (need_to_parse_mapping_file_) {
ParseFrameworkMappings();
}
std::map<std::string, std::string>::iterator proto_lookup =
proto_file_to_framework_name_.find(file->name());
if (proto_lookup != proto_file_to_framework_name_.end()) {
other_framework_imports_.push_back(
proto_lookup->second + "/" +
FilePathBasename(file) + header_extension);
return;
}
if (!generate_for_named_framework_.empty()) {
other_framework_imports_.push_back(
generate_for_named_framework_ + "/" +
FilePathBasename(file) + header_extension);
return;
}
other_imports_.push_back(FilePath(file) + header_extension);
}
void ImportWriter::Print(io::Printer* printer) const {
bool add_blank_line = false;
if (!protobuf_imports_.empty()) {
PrintRuntimeImports(printer, protobuf_imports_, runtime_import_prefix_);
add_blank_line = true;
}
if (!other_framework_imports_.empty()) {
if (add_blank_line) {
printer->Print("\n");
}
for (std::vector<std::string>::const_iterator iter =
other_framework_imports_.begin();
iter != other_framework_imports_.end(); ++iter) {
printer->Print(
"#import <$header$>\n",
"header", *iter);
}
add_blank_line = true;
}
if (!other_imports_.empty()) {
if (add_blank_line) {
printer->Print("\n");
}
for (std::vector<std::string>::const_iterator iter = other_imports_.begin();
iter != other_imports_.end(); ++iter) {
printer->Print(
"#import \"$header$\"\n",
"header", *iter);
}
}
}
void ImportWriter::PrintRuntimeImports(
io::Printer* printer, const std::vector<std::string>& header_to_import,
const std::string& runtime_import_prefix, bool default_cpp_symbol) {
// Given an override, use that.
if (!runtime_import_prefix.empty()) {
for (const auto& header : header_to_import) {
printer->Print(
" #import \"$import_prefix$/$header$\"\n",
"import_prefix", runtime_import_prefix,
"header", header);
}
return;
}
const std::string framework_name(ProtobufLibraryFrameworkName);
const std::string cpp_symbol(ProtobufFrameworkImportSymbol(framework_name));
if (default_cpp_symbol) {
printer->Print(
"// This CPP symbol can be defined to use imports that match up to the framework\n"
"// imports needed when using CocoaPods.\n"
"#if !defined($cpp_symbol$)\n"
" #define $cpp_symbol$ 0\n"
"#endif\n"
"\n",
"cpp_symbol", cpp_symbol);
}
printer->Print(
"#if $cpp_symbol$\n",
"cpp_symbol", cpp_symbol);
for (const auto& header : header_to_import) {
printer->Print(
" #import <$framework_name$/$header$>\n",
"framework_name", framework_name,
"header", header);
}
printer->Print(
"#else\n");
for (const auto& header : header_to_import) {
printer->Print(
" #import \"$header$\"\n",
"header", header);
}
printer->Print(
"#endif\n");
}
void ImportWriter::ParseFrameworkMappings() {
need_to_parse_mapping_file_ = false;
if (named_framework_to_proto_path_mappings_path_.empty()) {
return; // Nothing to do.
}
ProtoFrameworkCollector collector(&proto_file_to_framework_name_);
std::string parse_error;
if (!ParseSimpleFile(named_framework_to_proto_path_mappings_path_,
&collector, &parse_error)) {
std::cerr << "error parsing " << named_framework_to_proto_path_mappings_path_
<< " : " << parse_error << std::endl;
std::cerr.flush();
}
}
} // namespace objectivec
} // namespace compiler
} // namespace protobuf
} // namespace google

@ -33,25 +33,177 @@
#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_HELPERS_H__
#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_HELPERS_H__
#include "google/protobuf/compiler/objectivec/names.h"
#include <string>
#include <vector>
// clang-format off
#include "google/protobuf/port_def.inc"
// clang-format on
#include "google/protobuf/descriptor.h"
#include "google/protobuf/descriptor.pb.h"
namespace google {
namespace protobuf {
namespace compiler {
namespace objectivec {
// TODO(thomasvl) Move internal helpers in names.h back to here. Currently
// the dependencies are too interwoven to easily split up.
inline bool HasPreservingUnknownEnumSemantics(const FileDescriptor* file) {
return file->syntax() == FileDescriptor::SYNTAX_PROTO3;
}
inline bool IsMapEntryMessage(const Descriptor* descriptor) {
return descriptor->options().map_entry();
}
// Escape C++ trigraphs by escaping question marks to "\?".
std::string EscapeTrigraphs(absl::string_view to_escape);
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
};
std::string GetCapitalizedType(const FieldDescriptor* field);
ObjectiveCType GetObjectiveCType(FieldDescriptor::Type field_type);
inline ObjectiveCType GetObjectiveCType(const FieldDescriptor* field) {
return GetObjectiveCType(field->type());
}
bool IsPrimitiveType(const FieldDescriptor* field);
inline bool IsReferenceType(const FieldDescriptor* field) {
return !IsPrimitiveType(field);
}
std::string GPBGenericValueFieldName(const FieldDescriptor* field);
std::string DefaultValue(const FieldDescriptor* field);
bool HasNonZeroDefaultValue(const FieldDescriptor* field);
std::string BuildFlagsString(const FlagType type, const std::vector<std::string>& strings);
// Returns a symbol that can be used in C code to refer to an Objective C
// class without initializing the class.
std::string 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 ObjCClassDeclaration(const std::string& class_name);
// Builds HeaderDoc/appledoc style comments out of the comments in the .proto
// file.
std::string BuildCommentsString(const SourceLocation& location,
bool prefer_single_line);
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 "";
}
}
// Generate decode data needed for ObjC's GPBDecodeTextFormatName() to transform
// the input into the expected output.
class 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 class for parsing framework import mappings and generating
// import statements.
class 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:
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_HELPERS_H__

@ -28,6 +28,7 @@
// (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/objectivec/names.h"
#include "google/protobuf/compiler/objectivec/helpers.h"
#include "google/protobuf/io/zero_copy_stream_impl_lite.h"
#include <gtest/gtest.h>

@ -32,6 +32,7 @@
#include <string>
#include "google/protobuf/compiler/objectivec/map_field.h"
#include "google/protobuf/compiler/objectivec/names.h"
#include "google/protobuf/compiler/objectivec/helpers.h"
#include "google/protobuf/io/printer.h"

@ -38,6 +38,7 @@
#include "absl/strings/str_cat.h"
#include "google/protobuf/compiler/objectivec/enum.h"
#include "google/protobuf/compiler/objectivec/extension.h"
#include "google/protobuf/compiler/objectivec/names.h"
#include "google/protobuf/compiler/objectivec/helpers.h"
#include "google/protobuf/descriptor.pb.h"
#include "google/protobuf/io/printer.h"

@ -32,6 +32,7 @@
#include <string>
#include "google/protobuf/compiler/objectivec/message_field.h"
#include "google/protobuf/compiler/objectivec/names.h"
#include "google/protobuf/compiler/objectivec/helpers.h"
#include "google/protobuf/io/printer.h"

@ -43,21 +43,13 @@
#include <vector>
#include "google/protobuf/compiler/code_generator.h"
#include "google/protobuf/stubs/strutil.h"
#include "absl/strings/ascii.h"
#include "absl/strings/escaping.h"
#include "absl/strings/str_replace.h"
#include "absl/strings/str_split.h"
#include "absl/strings/strip.h"
#include "google/protobuf/compiler/objectivec/names.h"
#include "google/protobuf/compiler/objectivec/nsobject_methods.h"
#include "google/protobuf/descriptor.pb.h"
#include "google/protobuf/io/coded_stream.h"
#include "google/protobuf/io/io_win32.h"
#include "google/protobuf/io/printer.h"
#include "google/protobuf/io/zero_copy_stream_impl.h"
#include "google/protobuf/port.h"
#include "google/protobuf/stubs/common.h"
// NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some
// error cases, so it seems to be ok to use as a back door for errors.
@ -267,24 +259,6 @@ void SetForcedPackagePrefix(const std::string& prefix) {
g_prefix_mode.set_forced_package_prefix(prefix);
}
Options::Options() {
// While there are generator options, also support env variables to help with
// build systems where it isn't as easy to hook in for add the generation
// options when invoking protoc.
const char* file_path = getenv("GPB_OBJC_EXPECTED_PACKAGE_PREFIXES");
if (file_path) {
expected_prefixes_path = file_path;
}
const char* suppressions = getenv("GPB_OBJC_EXPECTED_PACKAGE_PREFIXES_SUPPRESSIONS");
if (suppressions) {
expected_prefixes_suppressions =
absl::StrSplit(suppressions, ";", absl::SkipEmpty());
}
prefixes_must_be_registered =
BoolFromEnvVar("GPB_OBJC_PREFIXES_MUST_BE_REGISTERED", false);
require_prefixes = BoolFromEnvVar("GPB_OBJC_REQUIRE_PREFIXES", false);
}
namespace {
std::unordered_set<std::string> MakeWordsMap(const char* const words[],
@ -534,34 +508,6 @@ bool IsSpecialNamePrefix(const std::string& name,
return false;
}
std::string GetZeroEnumNameForFlagType(const FlagType flag_type) {
switch(flag_type) {
case FLAGTYPE_DESCRIPTOR_INITIALIZATION:
return "GPBDescriptorInitializationFlag_None";
case FLAGTYPE_EXTENSION:
return "GPBExtensionNone";
case FLAGTYPE_FIELD:
return "GPBFieldNone";
default:
GOOGLE_LOG(FATAL) << "Can't get here.";
return "0";
}
}
std::string GetEnumNameForFlagType(const FlagType flag_type) {
switch(flag_type) {
case FLAGTYPE_DESCRIPTOR_INITIALIZATION:
return "GPBDescriptorInitializationFlags";
case FLAGTYPE_EXTENSION:
return "GPBExtensionOptions";
case FLAGTYPE_FIELD:
return "GPBFieldFlags";
default:
GOOGLE_LOG(FATAL) << "Can't get here.";
return std::string();
}
}
void MaybeUnQuote(absl::string_view* input) {
if ((input->length() >= 2) &&
((*input->data() == '\'' || *input->data() == '"')) &&
@ -573,11 +519,6 @@ void MaybeUnQuote(absl::string_view* input) {
} // namespace
// Escape C++ trigraphs by escaping question marks to \?
std::string EscapeTrigraphs(absl::string_view to_escape) {
return absl::StrReplaceAll(to_escape, {{"?", "\\?"}});
}
void TrimWhitespace(absl::string_view* input) {
while (!input->empty() && absl::ascii_isspace(*input->data())) {
input->remove_prefix(1);
@ -869,14 +810,6 @@ std::string OneofNameCapitalized(const OneofDescriptor* descriptor) {
return result;
}
std::string ObjCClass(const std::string& class_name) {
return std::string("GPBObjCClass(") + class_name + ")";
}
std::string ObjCClassDeclaration(const std::string& class_name) {
return std::string("GPBObjCClassDeclaration(") + class_name + ");";
}
std::string UnCamelCaseFieldName(const std::string& name, const FieldDescriptor* field) {
absl::string_view worker(name);
if (absl::EndsWith(worker, "_p")) {
@ -911,369 +844,6 @@ std::string UnCamelCaseFieldName(const std::string& name, const FieldDescriptor*
}
}
std::string GetCapitalizedType(const FieldDescriptor* field) {
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";
}
// Some compilers report reaching end of function even though all cases of
// the enum are handed in the switch.
GOOGLE_LOG(FATAL) << "Can't get here.";
return std::string();
}
ObjectiveCType GetObjectiveCType(FieldDescriptor::Type field_type) {
switch (field_type) {
case FieldDescriptor::TYPE_INT32:
case FieldDescriptor::TYPE_SINT32:
case FieldDescriptor::TYPE_SFIXED32:
return OBJECTIVECTYPE_INT32;
case FieldDescriptor::TYPE_UINT32:
case FieldDescriptor::TYPE_FIXED32:
return OBJECTIVECTYPE_UINT32;
case FieldDescriptor::TYPE_INT64:
case FieldDescriptor::TYPE_SINT64:
case FieldDescriptor::TYPE_SFIXED64:
return OBJECTIVECTYPE_INT64;
case FieldDescriptor::TYPE_UINT64:
case FieldDescriptor::TYPE_FIXED64:
return OBJECTIVECTYPE_UINT64;
case FieldDescriptor::TYPE_FLOAT:
return OBJECTIVECTYPE_FLOAT;
case FieldDescriptor::TYPE_DOUBLE:
return OBJECTIVECTYPE_DOUBLE;
case FieldDescriptor::TYPE_BOOL:
return OBJECTIVECTYPE_BOOLEAN;
case FieldDescriptor::TYPE_STRING:
return OBJECTIVECTYPE_STRING;
case FieldDescriptor::TYPE_BYTES:
return OBJECTIVECTYPE_DATA;
case FieldDescriptor::TYPE_ENUM:
return OBJECTIVECTYPE_ENUM;
case FieldDescriptor::TYPE_GROUP:
case FieldDescriptor::TYPE_MESSAGE:
return OBJECTIVECTYPE_MESSAGE;
}
// Some compilers report reaching end of function even though all cases of
// the enum are handed in the switch.
GOOGLE_LOG(FATAL) << "Can't get here.";
return OBJECTIVECTYPE_INT32;
}
bool IsPrimitiveType(const FieldDescriptor* field) {
ObjectiveCType type = GetObjectiveCType(field);
switch (type) {
case OBJECTIVECTYPE_INT32:
case OBJECTIVECTYPE_UINT32:
case OBJECTIVECTYPE_INT64:
case OBJECTIVECTYPE_UINT64:
case OBJECTIVECTYPE_FLOAT:
case OBJECTIVECTYPE_DOUBLE:
case OBJECTIVECTYPE_BOOLEAN:
case OBJECTIVECTYPE_ENUM:
return true;
break;
default:
return false;
}
}
bool IsReferenceType(const FieldDescriptor* field) {
return !IsPrimitiveType(field);
}
static std::string HandleExtremeFloatingPoint(std::string val,
bool add_float_suffix) {
if (val == "nan") {
return "NAN";
} else if (val == "inf") {
return "INFINITY";
} else if (val == "-inf") {
return "-INFINITY";
} else {
// float strings with ., e or E need to have f appended
if (add_float_suffix && (val.find('.') != std::string::npos ||
val.find('e') != std::string::npos ||
val.find('E') != std::string::npos)) {
val += "f";
}
return val;
}
}
std::string GPBGenericValueFieldName(const FieldDescriptor* field) {
// Returns the field within the GPBGenericValue union to use for the given
// field.
if (field->is_repeated()) {
return "valueMessage";
}
switch (field->cpp_type()) {
case FieldDescriptor::CPPTYPE_INT32:
return "valueInt32";
case FieldDescriptor::CPPTYPE_UINT32:
return "valueUInt32";
case FieldDescriptor::CPPTYPE_INT64:
return "valueInt64";
case FieldDescriptor::CPPTYPE_UINT64:
return "valueUInt64";
case FieldDescriptor::CPPTYPE_FLOAT:
return "valueFloat";
case FieldDescriptor::CPPTYPE_DOUBLE:
return "valueDouble";
case FieldDescriptor::CPPTYPE_BOOL:
return "valueBool";
case FieldDescriptor::CPPTYPE_STRING:
if (field->type() == FieldDescriptor::TYPE_BYTES) {
return "valueData";
} else {
return "valueString";
}
case FieldDescriptor::CPPTYPE_ENUM:
return "valueEnum";
case FieldDescriptor::CPPTYPE_MESSAGE:
return "valueMessage";
}
// Some compilers report reaching end of function even though all cases of
// the enum are handed in the switch.
GOOGLE_LOG(FATAL) << "Can't get here.";
return std::string();
}
std::string DefaultValue(const FieldDescriptor* field) {
// Repeated fields don't have defaults.
if (field->is_repeated()) {
return "nil";
}
// Switch on cpp_type since we need to know which default_value_* method
// of FieldDescriptor to call.
switch (field->cpp_type()) {
case FieldDescriptor::CPPTYPE_INT32:
// gcc and llvm reject the decimal form of kint32min and kint64min.
if (field->default_value_int32() == INT_MIN) {
return "-0x80000000";
}
return absl::StrCat(field->default_value_int32());
case FieldDescriptor::CPPTYPE_UINT32:
return absl::StrCat(field->default_value_uint32()) + "U";
case FieldDescriptor::CPPTYPE_INT64:
// gcc and llvm reject the decimal form of kint32min and kint64min.
if (field->default_value_int64() == LLONG_MIN) {
return "-0x8000000000000000LL";
}
return absl::StrCat(field->default_value_int64()) + "LL";
case FieldDescriptor::CPPTYPE_UINT64:
return absl::StrCat(field->default_value_uint64()) + "ULL";
case FieldDescriptor::CPPTYPE_DOUBLE:
return HandleExtremeFloatingPoint(
SimpleDtoa(field->default_value_double()), false);
case FieldDescriptor::CPPTYPE_FLOAT:
return HandleExtremeFloatingPoint(
SimpleFtoa(field->default_value_float()), true);
case FieldDescriptor::CPPTYPE_BOOL:
return field->default_value_bool() ? "YES" : "NO";
case FieldDescriptor::CPPTYPE_STRING: {
const bool has_default_value = field->has_default_value();
const std::string& default_string = field->default_value_string();
if (!has_default_value || default_string.length() == 0) {
// If the field is defined as being the empty string,
// then we will just assign to nil, as the empty string is the
// default for both strings and data.
return "nil";
}
if (field->type() == FieldDescriptor::TYPE_BYTES) {
// We want constant fields in our data structures so we can
// declare them as static. To achieve this we cheat and stuff
// a escaped c string (prefixed with a length) into the data
// field, and cast it to an (NSData*) so it will compile.
// The runtime library knows how to handle it.
// Must convert to a standard byte order for packing length into
// a cstring.
uint32_t length = ghtonl(default_string.length());
std::string bytes((const char*)&length, sizeof(length));
bytes.append(default_string);
return "(NSData*)\"" + EscapeTrigraphs(absl::CEscape(bytes)) + "\"";
} else {
return "@\"" + EscapeTrigraphs(absl::CEscape(default_string)) + "\"";
}
}
case FieldDescriptor::CPPTYPE_ENUM:
return EnumValueName(field->default_value_enum());
case FieldDescriptor::CPPTYPE_MESSAGE:
return "nil";
}
// Some compilers report reaching end of function even though all cases of
// the enum are handed in the switch.
GOOGLE_LOG(FATAL) << "Can't get here.";
return std::string();
}
bool HasNonZeroDefaultValue(const FieldDescriptor* field) {
// Repeated fields don't have defaults.
if (field->is_repeated()) {
return false;
}
// As much as checking field->has_default_value() seems useful, it isn't
// because of enums. proto2 syntax allows the first item in an enum (the
// default) to be non zero. So checking field->has_default_value() would
// result in missing this non zero default. See MessageWithOneBasedEnum in
// objectivec/Tests/unittest_objc.proto for a test Message to confirm this.
// Some proto file set the default to the zero value, so make sure the value
// isn't the zero case.
switch (field->cpp_type()) {
case FieldDescriptor::CPPTYPE_INT32:
return field->default_value_int32() != 0;
case FieldDescriptor::CPPTYPE_UINT32:
return field->default_value_uint32() != 0U;
case FieldDescriptor::CPPTYPE_INT64:
return field->default_value_int64() != 0LL;
case FieldDescriptor::CPPTYPE_UINT64:
return field->default_value_uint64() != 0ULL;
case FieldDescriptor::CPPTYPE_DOUBLE:
return field->default_value_double() != 0.0;
case FieldDescriptor::CPPTYPE_FLOAT:
return field->default_value_float() != 0.0f;
case FieldDescriptor::CPPTYPE_BOOL:
return field->default_value_bool();
case FieldDescriptor::CPPTYPE_STRING: {
const std::string& default_string = field->default_value_string();
return default_string.length() != 0;
}
case FieldDescriptor::CPPTYPE_ENUM:
return field->default_value_enum()->number() != 0;
case FieldDescriptor::CPPTYPE_MESSAGE:
return false;
}
// Some compilers report reaching end of function even though all cases of
// the enum are handed in the switch.
GOOGLE_LOG(FATAL) << "Can't get here.";
return false;
}
std::string BuildFlagsString(const FlagType flag_type,
const std::vector<std::string>& strings) {
if (strings.empty()) {
return GetZeroEnumNameForFlagType(flag_type);
} else if (strings.size() == 1) {
return strings[0];
}
std::string string("(" + GetEnumNameForFlagType(flag_type) + ")(");
for (size_t i = 0; i != strings.size(); ++i) {
if (i > 0) {
string.append(" | ");
}
string.append(strings[i]);
}
string.append(")");
return string;
}
std::string BuildCommentsString(const SourceLocation& location,
bool prefer_single_line) {
const std::string& comments = location.leading_comments.empty()
? location.trailing_comments
: location.leading_comments;
std::vector<std::string> lines;
lines = absl::StrSplit(comments, "\n", absl::AllowEmpty());
while (!lines.empty() && lines.back().empty()) {
lines.pop_back();
}
// If there are no comments, just return an empty string.
if (lines.empty()) {
return "";
}
std::string prefix;
std::string suffix;
std::string final_comments;
std::string epilogue;
bool add_leading_space = false;
if (prefer_single_line && lines.size() == 1) {
prefix = "/** ";
suffix = " */\n";
} else {
prefix = "* ";
suffix = "\n";
final_comments += "/**\n";
epilogue = " **/\n";
add_leading_space = true;
}
for (size_t i = 0; i < lines.size(); i++) {
std::string line = absl::StrReplaceAll(
absl::StripPrefix(lines[i], " "),
{// HeaderDoc and appledoc use '\' and '@' for markers; escape them.
{"\\", "\\\\"},
{"@", "\\@"},
// Decouple / from * to not have inline comments inside comments.
{"/*", "/\\*"},
{"*/", "*\\/"}});
line = prefix + line;
absl::StripAsciiWhitespace(&line);
// If not a one line, need to add the first space before *, as
// absl::StripAsciiWhitespace would have removed it.
line = (add_leading_space ? " " : "") + line;
final_comments += line + suffix;
}
final_comments += epilogue;
return final_comments;
}
// Making these a generator option for folks that don't use CocoaPods, but do
// want to put the library in a framework is an interesting question. The
// problem is it means changing sources shipped with the library to actually
@ -1506,6 +1076,24 @@ bool ValidateObjCClassPrefix(
} // namespace
Options::Options() {
// While there are generator options, also support env variables to help with
// build systems where it isn't as easy to hook in for add the generation
// options when invoking protoc.
const char* file_path = getenv("GPB_OBJC_EXPECTED_PACKAGE_PREFIXES");
if (file_path) {
expected_prefixes_path = file_path;
}
const char* suppressions = getenv("GPB_OBJC_EXPECTED_PACKAGE_PREFIXES_SUPPRESSIONS");
if (suppressions) {
expected_prefixes_suppressions =
absl::StrSplit(suppressions, ";", absl::SkipEmpty());
}
prefixes_must_be_registered =
BoolFromEnvVar("GPB_OBJC_PREFIXES_MUST_BE_REGISTERED", false);
require_prefixes = BoolFromEnvVar("GPB_OBJC_REQUIRE_PREFIXES", false);
}
bool ValidateObjCClassPrefixes(const std::vector<const FileDescriptor*>& files,
std::string* out_error) {
// Options's ctor load from the environment.
@ -1554,47 +1142,6 @@ bool ValidateObjCClassPrefixes(const std::vector<const FileDescriptor*>& files,
return true;
}
TextFormatDecodeData::TextFormatDecodeData() { }
TextFormatDecodeData::~TextFormatDecodeData() { }
void TextFormatDecodeData::AddString(int32_t key,
const std::string& input_for_decode,
const std::string& desired_output) {
for (std::vector<DataEntry>::const_iterator i = entries_.begin();
i != entries_.end(); ++i) {
if (i->first == key) {
std::cerr << "error: duplicate key (" << key
<< ") making TextFormat data, input: \"" << input_for_decode
<< "\", desired: \"" << desired_output << "\"." << std::endl;
std::cerr.flush();
abort();
}
}
const std::string& data = TextFormatDecodeData::DecodeDataForString(
input_for_decode, desired_output);
entries_.push_back(DataEntry(key, data));
}
std::string TextFormatDecodeData::Data() const {
std::ostringstream data_stringstream;
if (num_entries() > 0) {
io::OstreamOutputStream data_outputstream(&data_stringstream);
io::CodedOutputStream output_stream(&data_outputstream);
output_stream.WriteVarint32(num_entries());
for (std::vector<DataEntry>::const_iterator i = entries_.begin();
i != entries_.end(); ++i) {
output_stream.WriteVarint32(i->first);
output_stream.WriteString(i->second);
}
}
data_stringstream.flush();
return data_stringstream.str();
}
namespace {
@ -1703,69 +1250,8 @@ bool DecodeDataBuilder::AddCharacter(const char desired, const char input) {
return AddFirst(desired, input);
}
// If decode data can't be generated, a directive for the raw string
// is used instead.
std::string DirectDecodeString(const std::string& str) {
std::string result;
result += (char)'\0'; // Marker for full string.
result += str;
result += (char)'\0'; // End of string.
return result;
}
} // namespace
// static
std::string TextFormatDecodeData::DecodeDataForString(
const std::string& input_for_decode, const std::string& desired_output) {
if (input_for_decode.empty() || desired_output.empty()) {
std::cerr << "error: got empty string for making TextFormat data, input: \""
<< input_for_decode << "\", desired: \"" << desired_output << "\"."
<< std::endl;
std::cerr.flush();
abort();
}
if ((input_for_decode.find('\0') != std::string::npos) ||
(desired_output.find('\0') != std::string::npos)) {
std::cerr << "error: got a null char in a string for making TextFormat data,"
<< " input: \"" << absl::CEscape(input_for_decode) << "\", desired: \""
<< absl::CEscape(desired_output) << "\"." << std::endl;
std::cerr.flush();
abort();
}
DecodeDataBuilder builder;
// Walk the output building it from the input.
int x = 0;
for (int y = 0; y < desired_output.size(); y++) {
const char d = desired_output[y];
if (d == '_') {
builder.AddUnderscore();
continue;
}
if (x >= input_for_decode.size()) {
// Out of input, no way to encode it, just return a full decode.
return DirectDecodeString(desired_output);
}
if (builder.AddCharacter(d, input_for_decode[x])) {
++x; // Consumed one input
} else {
// Couldn't transform for the next character, just return a full decode.
return DirectDecodeString(desired_output);
}
}
if (x != input_for_decode.size()) {
// Extra input (suffix from name sanitizing?), just return a full decode.
return DirectDecodeString(desired_output);
}
// Add the end marker.
return builder.Finish() + (char)'\0';
}
namespace {
class Parser {
@ -1887,208 +1373,6 @@ bool ParseSimpleStream(io::ZeroCopyInputStream& input_stream,
return true;
}
ImportWriter::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)
: generate_for_named_framework_(generate_for_named_framework),
named_framework_to_proto_path_mappings_path_(
named_framework_to_proto_path_mappings_path),
runtime_import_prefix_(runtime_import_prefix),
include_wkt_imports_(include_wkt_imports),
need_to_parse_mapping_file_(true) {}
ImportWriter::~ImportWriter() {}
void ImportWriter::AddFile(const FileDescriptor* file,
const std::string& header_extension) {
if (IsProtobufLibraryBundledProtoFile(file)) {
// The imports of the WKTs are only needed within the library itself,
// in other cases, they get skipped because the generated code already
// import GPBProtocolBuffers.h and hence proves them.
if (include_wkt_imports_) {
const std::string header_name =
"GPB" + FilePathBasename(file) + header_extension;
protobuf_imports_.push_back(header_name);
}
return;
}
// Lazy parse any mappings.
if (need_to_parse_mapping_file_) {
ParseFrameworkMappings();
}
std::map<std::string, std::string>::iterator proto_lookup =
proto_file_to_framework_name_.find(file->name());
if (proto_lookup != proto_file_to_framework_name_.end()) {
other_framework_imports_.push_back(
proto_lookup->second + "/" +
FilePathBasename(file) + header_extension);
return;
}
if (!generate_for_named_framework_.empty()) {
other_framework_imports_.push_back(
generate_for_named_framework_ + "/" +
FilePathBasename(file) + header_extension);
return;
}
other_imports_.push_back(FilePath(file) + header_extension);
}
void ImportWriter::Print(io::Printer* printer) const {
bool add_blank_line = false;
if (!protobuf_imports_.empty()) {
PrintRuntimeImports(printer, protobuf_imports_, runtime_import_prefix_);
add_blank_line = true;
}
if (!other_framework_imports_.empty()) {
if (add_blank_line) {
printer->Print("\n");
}
for (std::vector<std::string>::const_iterator iter =
other_framework_imports_.begin();
iter != other_framework_imports_.end(); ++iter) {
printer->Print(
"#import <$header$>\n",
"header", *iter);
}
add_blank_line = true;
}
if (!other_imports_.empty()) {
if (add_blank_line) {
printer->Print("\n");
}
for (std::vector<std::string>::const_iterator iter = other_imports_.begin();
iter != other_imports_.end(); ++iter) {
printer->Print(
"#import \"$header$\"\n",
"header", *iter);
}
}
}
void ImportWriter::PrintRuntimeImports(
io::Printer* printer, const std::vector<std::string>& header_to_import,
const std::string& runtime_import_prefix, bool default_cpp_symbol) {
// Given an override, use that.
if (!runtime_import_prefix.empty()) {
for (const auto& header : header_to_import) {
printer->Print(
" #import \"$import_prefix$/$header$\"\n",
"import_prefix", runtime_import_prefix,
"header", header);
}
return;
}
const std::string framework_name(ProtobufLibraryFrameworkName);
const std::string cpp_symbol(ProtobufFrameworkImportSymbol(framework_name));
if (default_cpp_symbol) {
printer->Print(
"// This CPP symbol can be defined to use imports that match up to the framework\n"
"// imports needed when using CocoaPods.\n"
"#if !defined($cpp_symbol$)\n"
" #define $cpp_symbol$ 0\n"
"#endif\n"
"\n",
"cpp_symbol", cpp_symbol);
}
printer->Print(
"#if $cpp_symbol$\n",
"cpp_symbol", cpp_symbol);
for (const auto& header : header_to_import) {
printer->Print(
" #import <$framework_name$/$header$>\n",
"framework_name", framework_name,
"header", header);
}
printer->Print(
"#else\n");
for (const auto& header : header_to_import) {
printer->Print(
" #import \"$header$\"\n",
"header", header);
}
printer->Print(
"#endif\n");
}
void ImportWriter::ParseFrameworkMappings() {
need_to_parse_mapping_file_ = false;
if (named_framework_to_proto_path_mappings_path_.empty()) {
return; // Nothing to do.
}
ProtoFrameworkCollector collector(&proto_file_to_framework_name_);
std::string parse_error;
if (!ParseSimpleFile(named_framework_to_proto_path_mappings_path_,
&collector, &parse_error)) {
std::cerr << "error parsing " << named_framework_to_proto_path_mappings_path_
<< " : " << parse_error << std::endl;
std::cerr.flush();
}
}
bool ImportWriter::ProtoFrameworkCollector::ConsumeLine(
const absl::string_view& line, std::string* out_error) {
int offset = line.find(':');
if (offset == absl::string_view::npos) {
*out_error =
std::string("Framework/proto file mapping line without colon sign: '") +
std::string(line) + "'.";
return false;
}
absl::string_view framework_name = line.substr(0, offset);
absl::string_view proto_file_list = line.substr(offset + 1);
TrimWhitespace(&framework_name);
int start = 0;
while (start < proto_file_list.length()) {
offset = proto_file_list.find(',', start);
if (offset == absl::string_view::npos) {
offset = proto_file_list.length();
}
absl::string_view proto_file = proto_file_list.substr(start, offset - start);
TrimWhitespace(&proto_file);
if (!proto_file.empty()) {
std::map<std::string, std::string>::iterator existing_entry =
map_->find(std::string(proto_file));
if (existing_entry != map_->end()) {
std::cerr << "warning: duplicate proto file reference, replacing "
"framework entry for '"
<< std::string(proto_file) << "' with '" << std::string(framework_name)
<< "' (was '" << existing_entry->second << "')." << std::endl;
std::cerr.flush();
}
if (proto_file.find(' ') != absl::string_view::npos) {
std::cerr << "note: framework mapping file had a proto file with a "
"space in, hopefully that isn't a missing comma: '"
<< std::string(proto_file) << "'" << std::endl;
std::cerr.flush();
}
(*map_)[std::string(proto_file)] = std::string(framework_name);
}
start = offset + 1;
}
return true;
}
} // namespace objectivec
} // namespace compiler
} // namespace protobuf

@ -37,7 +37,6 @@
#include <vector>
#include "google/protobuf/descriptor.h"
#include "google/protobuf/descriptor.pb.h"
#include "google/protobuf/io/zero_copy_stream.h"
// clang-format off
@ -70,19 +69,6 @@ void PROTOC_EXPORT SetProtoPackagePrefixExceptionList(
std::string PROTOC_EXPORT GetForcedPackagePrefix();
void PROTOC_EXPORT SetForcedPackagePrefix(const std::string& prefix);
// Generator Prefix Validation Options (see 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);
@ -144,108 +130,10 @@ 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;
@ -254,10 +142,25 @@ extern PROTOC_EXPORT const char* const ProtobufLibraryFrameworkName;
std::string PROTOC_EXPORT
ProtobufFrameworkImportSymbol(const std::string& framework_name);
// ---------------------------------------------------------------------------
// These aren't really "naming" related, but can be useful for something
// building on top of ObjC Protos to be able to share the knowledge/enforcement.
// Checks if the file is one of the proto's bundled with the library.
bool PROTOC_EXPORT
IsProtobufLibraryBundledProtoFile(const FileDescriptor* file);
// Generator Prefix Validation Options (see 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;
};
// 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.
@ -269,29 +172,6 @@ bool PROTOC_EXPORT ValidateObjCClassPrefixes(
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:
@ -309,50 +189,6 @@ bool PROTOC_EXPORT ParseSimpleStream(io::ZeroCopyInputStream& input_stream,
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

@ -34,6 +34,7 @@
#include <string>
#include "absl/strings/str_cat.h"
#include "google/protobuf/compiler/objectivec/names.h"
#include "google/protobuf/compiler/objectivec/helpers.h"
#include "google/protobuf/io/printer.h"

@ -34,6 +34,7 @@
#include <string>
#include "absl/strings/str_cat.h"
#include "google/protobuf/compiler/objectivec/names.h"
#include "google/protobuf/compiler/objectivec/helpers.h"
#include "google/protobuf/io/printer.h"

Loading…
Cancel
Save