Move the ImportWriter into the ObjC Helpers.

grpc likely needs to provide the same sorta handling, so expose the class so
the logic can be reused.
This commit is contained in:
Thomas Van Lenten 2016-08-23 10:19:03 -04:00
parent 80f65d2df8
commit 93362a5aa5
4 changed files with 203 additions and 206 deletions

View File

@ -54,205 +54,6 @@ const int32 GOOGLE_PROTOBUF_OBJC_GEN_VERSION = 30001;
namespace compiler {
namespace objectivec {
namespace {
class ImportWriter {
public:
ImportWriter(const Options& options)
: options_(options),
need_to_parse_mapping_file_(true) {}
void AddFile(const FileGenerator* file);
void Print(io::Printer *printer) const;
private:
class ProtoFrameworkCollector : public LineConsumer {
public:
ProtoFrameworkCollector(map<string, string>* inout_proto_file_to_framework_name)
: map_(inout_proto_file_to_framework_name) {}
virtual bool ConsumeLine(const StringPiece& line, string* out_error);
private:
map<string, string>* map_;
};
void ParseFrameworkMappings();
const Options options_;
map<string, string> proto_file_to_framework_name_;
bool need_to_parse_mapping_file_;
vector<string> protobuf_framework_imports_;
vector<string> protobuf_non_framework_imports_;
vector<string> other_framework_imports_;
vector<string> other_imports_;
};
void ImportWriter::AddFile(const FileGenerator* file) {
const FileDescriptor* file_descriptor = file->Descriptor();
const string extension(".pbobjc.h");
if (IsProtobufLibraryBundledProtoFile(file_descriptor)) {
protobuf_framework_imports_.push_back(
FilePathBasename(file_descriptor) + extension);
protobuf_non_framework_imports_.push_back(file->Path() + extension);
return;
}
// Lazy parse any mappings.
if (need_to_parse_mapping_file_) {
ParseFrameworkMappings();
}
map<string, string>::iterator proto_lookup =
proto_file_to_framework_name_.find(file_descriptor->name());
if (proto_lookup != proto_file_to_framework_name_.end()) {
other_framework_imports_.push_back(
proto_lookup->second + "/" +
FilePathBasename(file_descriptor) + extension);
return;
}
if (!options_.generate_for_named_framework.empty()) {
other_framework_imports_.push_back(
options_.generate_for_named_framework + "/" +
FilePathBasename(file_descriptor) + extension);
return;
}
other_imports_.push_back(file->Path() + extension);
}
void ImportWriter::Print(io::Printer* printer) const {
assert(protobuf_non_framework_imports_.size() ==
protobuf_framework_imports_.size());
bool add_blank_line = false;
if (protobuf_framework_imports_.size() > 0) {
const string framework_name(ProtobufLibraryFrameworkName);
const string cpp_symbol(ProtobufFrameworkImportSymbol(framework_name));
printer->Print(
"#if $cpp_symbol$\n",
"cpp_symbol", cpp_symbol);
for (vector<string>::const_iterator iter = protobuf_framework_imports_.begin();
iter != protobuf_framework_imports_.end(); ++iter) {
printer->Print(
" #import <$framework_name$/$header$>\n",
"framework_name", framework_name,
"header", *iter);
}
printer->Print(
"#else\n");
for (vector<string>::const_iterator iter = protobuf_non_framework_imports_.begin();
iter != protobuf_non_framework_imports_.end(); ++iter) {
printer->Print(
" #import \"$header$\"\n",
"header", *iter);
}
printer->Print(
"#endif\n");
add_blank_line = true;
}
if (other_framework_imports_.size() > 0) {
if (add_blank_line) {
printer->Print("\n");
}
for (vector<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_.size() > 0) {
if (add_blank_line) {
printer->Print("\n");
}
for (vector<string>::const_iterator iter = other_imports_.begin();
iter != other_imports_.end(); ++iter) {
printer->Print(
" #import \"$header$\"\n",
"header", *iter);
}
}
}
void ImportWriter::ParseFrameworkMappings() {
need_to_parse_mapping_file_ = false;
if (options_.named_framework_to_proto_path_mappings_path.empty()) {
return; // Nothing to do.
}
ProtoFrameworkCollector collector(&proto_file_to_framework_name_);
string parse_error;
if (!ParseSimpleFile(options_.named_framework_to_proto_path_mappings_path,
&collector, &parse_error)) {
cerr << "error parsing " << options_.named_framework_to_proto_path_mappings_path
<< " : " << parse_error << endl;
cerr.flush();
}
}
bool ImportWriter::ProtoFrameworkCollector::ConsumeLine(
const StringPiece& line, string* out_error) {
int offset = line.find(':');
if (offset == StringPiece::npos) {
*out_error =
string("Framework/proto file mapping line without colon sign: '") +
line.ToString() + "'.";
return false;
}
StringPiece framework_name(line, 0, offset);
StringPiece proto_file_list(line, offset + 1, line.length() - offset - 1);
StringPieceTrimWhitespace(&framework_name);
int start = 0;
while (start < proto_file_list.length()) {
offset = proto_file_list.find(',', start);
if (offset == StringPiece::npos) {
offset = proto_file_list.length();
}
StringPiece proto_file(proto_file_list, start, offset - start);
StringPieceTrimWhitespace(&proto_file);
if (proto_file.size() != 0) {
map<string, string>::iterator existing_entry =
map_->find(proto_file.ToString());
if (existing_entry != map_->end()) {
cerr << "warning: duplicate proto file reference, replacing framework entry for '"
<< proto_file.ToString() << "' with '" << framework_name.ToString()
<< "' (was '" << existing_entry->second << "')." << endl;
cerr.flush();
}
if (proto_file.find(' ') != StringPiece::npos) {
cerr << "note: framework mapping file had a proto file with a space in, hopefully that isn't a missing comma: '"
<< proto_file.ToString() << "'" << endl;
cerr.flush();
}
(*map_)[proto_file.ToString()] = framework_name.ToString();
}
start = offset + 1;
}
return true;
}
} // namespace
FileGenerator::FileGenerator(const FileDescriptor *file, const Options& options)
: file_(file),
root_class_name_(FileClassName(file)),
@ -305,7 +106,7 @@ void FileGenerator::GenerateHeader(io::Printer *printer) {
dependency_generators.begin();
iter != dependency_generators.end(); ++iter) {
if ((*iter)->IsPublicDependency()) {
import_writer.AddFile(*iter);
import_writer.AddFile((*iter)->file_);
}
}
import_writer.Print(printer);
@ -410,7 +211,7 @@ void FileGenerator::GenerateSource(io::Printer *printer) {
ImportWriter import_writer(options_);
// #import the header for this proto file.
import_writer.AddFile(this);
import_writer.AddFile(file_);
// #import the headers for anything that a plain dependency of this proto
// file (that means they were just an include, not a "public" include).
@ -420,7 +221,7 @@ void FileGenerator::GenerateSource(io::Printer *printer) {
dependency_generators.begin();
iter != dependency_generators.end(); ++iter) {
if (!(*iter)->IsPublicDependency()) {
import_writer.AddFile(*iter);
import_writer.AddFile((*iter)->file_);
}
}

View File

@ -62,8 +62,6 @@ class FileGenerator {
void GenerateHeader(io::Printer* printer);
const string& RootClassName() const { return root_class_name_; }
const string Path() const { return FilePath(file_); }
const FileDescriptor* Descriptor() const { return file_; }
bool IsPublicDependency() const { return is_public_dep_; }

View File

@ -44,9 +44,10 @@
#include <google/protobuf/stubs/hash.h>
#include <google/protobuf/compiler/objectivec/objectivec_helpers.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/strutil.h>
@ -1433,6 +1434,167 @@ bool ParseSimpleFile(
return parser.Finish();
}
void ImportWriter::AddFile(const FileDescriptor* file) {
const string extension(".pbobjc.h");
const string file_path(FilePath(file));
if (IsProtobufLibraryBundledProtoFile(file)) {
protobuf_framework_imports_.push_back(
FilePathBasename(file) + extension);
protobuf_non_framework_imports_.push_back(file_path + extension);
return;
}
// Lazy parse any mappings.
if (need_to_parse_mapping_file_) {
ParseFrameworkMappings();
}
map<string, 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) + extension);
return;
}
if (!options_.generate_for_named_framework.empty()) {
other_framework_imports_.push_back(
options_.generate_for_named_framework + "/" +
FilePathBasename(file) + extension);
return;
}
other_imports_.push_back(file_path + extension);
}
void ImportWriter::Print(io::Printer* printer) const {
assert(protobuf_non_framework_imports_.size() ==
protobuf_framework_imports_.size());
bool add_blank_line = false;
if (protobuf_framework_imports_.size() > 0) {
const string framework_name(ProtobufLibraryFrameworkName);
const string cpp_symbol(ProtobufFrameworkImportSymbol(framework_name));
printer->Print(
"#if $cpp_symbol$\n",
"cpp_symbol", cpp_symbol);
for (vector<string>::const_iterator iter = protobuf_framework_imports_.begin();
iter != protobuf_framework_imports_.end(); ++iter) {
printer->Print(
" #import <$framework_name$/$header$>\n",
"framework_name", framework_name,
"header", *iter);
}
printer->Print(
"#else\n");
for (vector<string>::const_iterator iter = protobuf_non_framework_imports_.begin();
iter != protobuf_non_framework_imports_.end(); ++iter) {
printer->Print(
" #import \"$header$\"\n",
"header", *iter);
}
printer->Print(
"#endif\n");
add_blank_line = true;
}
if (other_framework_imports_.size() > 0) {
if (add_blank_line) {
printer->Print("\n");
}
for (vector<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_.size() > 0) {
if (add_blank_line) {
printer->Print("\n");
}
for (vector<string>::const_iterator iter = other_imports_.begin();
iter != other_imports_.end(); ++iter) {
printer->Print(
" #import \"$header$\"\n",
"header", *iter);
}
}
}
void ImportWriter::ParseFrameworkMappings() {
need_to_parse_mapping_file_ = false;
if (options_.named_framework_to_proto_path_mappings_path.empty()) {
return; // Nothing to do.
}
ProtoFrameworkCollector collector(&proto_file_to_framework_name_);
string parse_error;
if (!ParseSimpleFile(options_.named_framework_to_proto_path_mappings_path,
&collector, &parse_error)) {
cerr << "error parsing " << options_.named_framework_to_proto_path_mappings_path
<< " : " << parse_error << endl;
cerr.flush();
}
}
bool ImportWriter::ProtoFrameworkCollector::ConsumeLine(
const StringPiece& line, string* out_error) {
int offset = line.find(':');
if (offset == StringPiece::npos) {
*out_error =
string("Framework/proto file mapping line without colon sign: '") +
line.ToString() + "'.";
return false;
}
StringPiece framework_name(line, 0, offset);
StringPiece proto_file_list(line, offset + 1, line.length() - offset - 1);
StringPieceTrimWhitespace(&framework_name);
int start = 0;
while (start < proto_file_list.length()) {
offset = proto_file_list.find(',', start);
if (offset == StringPiece::npos) {
offset = proto_file_list.length();
}
StringPiece proto_file(proto_file_list, start, offset - start);
StringPieceTrimWhitespace(&proto_file);
if (proto_file.size() != 0) {
map<string, string>::iterator existing_entry =
map_->find(proto_file.ToString());
if (existing_entry != map_->end()) {
cerr << "warning: duplicate proto file reference, replacing framework entry for '"
<< proto_file.ToString() << "' with '" << framework_name.ToString()
<< "' (was '" << existing_entry->second << "')." << endl;
cerr.flush();
}
if (proto_file.find(' ') != StringPiece::npos) {
cerr << "note: framework mapping file had a proto file with a space in, hopefully that isn't a missing comma: '"
<< proto_file.ToString() << "'" << endl;
cerr.flush();
}
(*map_)[proto_file.ToString()] = framework_name.ToString();
}
start = offset + 1;
}
return true;
}
} // namespace objectivec
} // namespace compiler

View File

@ -225,6 +225,42 @@ class LIBPROTOC_EXPORT LineConsumer {
bool ParseSimpleFile(
const string& path, LineConsumer* line_consumer, string* out_error);
// Helper class for parsing framework import mappings and generating
// import statements.
class LIBPROTOC_EXPORT ImportWriter {
public:
ImportWriter(const Options& options)
: options_(options),
need_to_parse_mapping_file_(true) {}
void AddFile(const FileDescriptor* file);
void Print(io::Printer *printer) const;
private:
class ProtoFrameworkCollector : public LineConsumer {
public:
ProtoFrameworkCollector(map<string, string>* inout_proto_file_to_framework_name)
: map_(inout_proto_file_to_framework_name) {}
virtual bool ConsumeLine(const StringPiece& line, string* out_error);
private:
map<string, string>* map_;
};
void ParseFrameworkMappings();
const Options options_;
map<string, string> proto_file_to_framework_name_;
bool need_to_parse_mapping_file_;
vector<string> protobuf_framework_imports_;
vector<string> protobuf_non_framework_imports_;
vector<string> other_framework_imports_;
vector<string> other_imports_;
};
} // namespace objectivec
} // namespace compiler
} // namespace protobuf