blob: 66dd8a1679e04a1ec0d1cd2c54c929c4e9828435 [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/code_generator.h"
#include <cstddef>
#include <string>
#include <utility>
#include <vector>
#include "absl/log/absl_log.h"
#include "absl/status/statusor.h"
#include "absl/strings/match.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_split.h"
#include "absl/strings/string_view.h"
#include "absl/strings/strip.h"
#include "google/protobuf/compiler/plugin.pb.h"
#include "google/protobuf/descriptor.h"
#include "google/protobuf/feature_resolver.h"
// Must be included last.
#include "google/protobuf/port_def.inc"
namespace google {
namespace protobuf {
namespace compiler {
CodeGenerator::~CodeGenerator() = default;
bool CodeGenerator::GenerateAll(const std::vector<const FileDescriptor*>& files,
const std::string& parameter,
GeneratorContext* generator_context,
std::string* error) const {
// Default implementation is just to call the per file method, and prefix any
// error string with the file to provide context.
bool succeeded = true;
for (size_t i = 0; i < files.size(); i++) {
const FileDescriptor* file = files[i];
succeeded = Generate(file, parameter, generator_context, error);
if (!succeeded && error && error->empty()) {
*error =
"Code generator returned false but provided no error "
"description.";
}
if (error && !error->empty()) {
*error = absl::StrCat(file->name(), ": ", *error);
break;
}
if (!succeeded) {
break;
}
}
return succeeded;
}
absl::StatusOr<FeatureSetDefaults> CodeGenerator::BuildFeatureSetDefaults()
const {
if ((GetSupportedFeatures() & FEATURE_SUPPORTS_EDITIONS) == 0) {
// For generators that don't fully support editions yet, provide an
// optimistic set of defaults. Protoc will check this condition later
// anyway.
return FeatureResolver::CompileDefaults(
FeatureSet::descriptor(), GetFeatureExtensions(),
PROTOBUF_MINIMUM_EDITION, PROTOBUF_MAXIMUM_EDITION);
}
return FeatureResolver::CompileDefaults(
FeatureSet::descriptor(), GetFeatureExtensions(), GetMinimumEdition(),
GetMaximumEdition());
}
GeneratorContext::~GeneratorContext() = default;
io::ZeroCopyOutputStream* GeneratorContext::OpenForAppend(
const std::string& filename) {
return nullptr;
}
io::ZeroCopyOutputStream* GeneratorContext::OpenForInsert(
const std::string& filename, const std::string& insertion_point) {
ABSL_LOG(FATAL) << "This GeneratorContext does not support insertion.";
return nullptr; // make compiler happy
}
io::ZeroCopyOutputStream* GeneratorContext::OpenForInsertWithGeneratedCodeInfo(
const std::string& filename, const std::string& insertion_point,
const google::protobuf::GeneratedCodeInfo& /*info*/) {
return OpenForInsert(filename, insertion_point);
}
void GeneratorContext::ListParsedFiles(
std::vector<const FileDescriptor*>* output) {
ABSL_LOG(FATAL) << "This GeneratorContext does not support ListParsedFiles";
}
void GeneratorContext::GetCompilerVersion(Version* version) const {
version->set_major(GOOGLE_PROTOBUF_VERSION / 1000000);
version->set_minor(GOOGLE_PROTOBUF_VERSION / 1000 % 1000);
version->set_patch(GOOGLE_PROTOBUF_VERSION % 1000);
version->set_suffix(GOOGLE_PROTOBUF_VERSION_SUFFIX);
}
// Parses a set of comma-delimited name/value pairs.
void ParseGeneratorParameter(
absl::string_view text,
std::vector<std::pair<std::string, std::string> >* output) {
std::vector<absl::string_view> parts =
absl::StrSplit(text, ',', absl::SkipEmpty());
for (absl::string_view part : parts) {
auto equals_pos = part.find_first_of('=');
if (equals_pos == absl::string_view::npos) {
output->emplace_back(part, "");
} else {
output->emplace_back(part.substr(0, equals_pos),
part.substr(equals_pos + 1));
}
}
}
// Strips ".proto" or ".protodevel" from the end of a filename.
std::string StripProto(absl::string_view filename) {
if (absl::EndsWith(filename, ".protodevel")) {
return std::string(absl::StripSuffix(filename, ".protodevel"));
} else {
return std::string(absl::StripSuffix(filename, ".proto"));
}
}
bool IsKnownFeatureProto(absl::string_view filename) {
if (filename == "google/protobuf/cpp_features.proto" ||
filename == "google/protobuf/java_features.proto") {
return true;
}
return false;
}
bool CanSkipEditionCheck(absl::string_view filename) {
return absl::StartsWith(filename, "google/protobuf/") ||
absl::StartsWith(filename, "upb/");
}
} // namespace compiler
} // namespace protobuf
} // namespace google
#include "google/protobuf/port_undef.inc"