diff options
Diffstat (limited to 'NorthstarDedicatedTest/include/protobuf/compiler')
218 files changed, 87190 insertions, 0 deletions
diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/annotation_test_util.cc b/NorthstarDedicatedTest/include/protobuf/compiler/annotation_test_util.cc new file mode 100644 index 00000000..0ffa4c08 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/annotation_test_util.cc @@ -0,0 +1,168 @@ +// 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 <compiler/annotation_test_util.h> + +#include <cstdint> +#include <memory> + +#include <testing/file.h> +#include <testing/file.h> +#include <compiler/code_generator.h> +#include <compiler/command_line_interface.h> +#include <io/printer.h> +#include <io/zero_copy_stream.h> +#include <io/zero_copy_stream_impl_lite.h> +#include <descriptor.pb.h> +#include <testing/googletest.h> +#include <gtest/gtest.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace annotation_test_util { +namespace { + +// A CodeGenerator that captures the FileDescriptor it's passed as a +// FileDescriptorProto. +class DescriptorCapturingGenerator : public CodeGenerator { + public: + // Does not own file; file must outlive the Generator. + explicit DescriptorCapturingGenerator(FileDescriptorProto* file) + : file_(file) {} + + virtual bool Generate(const FileDescriptor* file, + const std::string& parameter, GeneratorContext* context, + std::string* error) const { + file->CopyTo(file_); + return true; + } + + private: + FileDescriptorProto* file_; +}; +} // namespace + +void AddFile(const std::string& filename, const std::string& data) { + GOOGLE_CHECK_OK(File::SetContents(TestTempDir() + "/" + filename, data, + true)); +} + +bool RunProtoCompiler(const std::string& filename, + const std::string& plugin_specific_args, + CommandLineInterface* cli, FileDescriptorProto* file) { + cli->SetInputsAreProtoPathRelative(true); + + DescriptorCapturingGenerator capturing_generator(file); + cli->RegisterGenerator("--capture_out", &capturing_generator, ""); + + std::string proto_path = "-I" + TestTempDir(); + std::string capture_out = "--capture_out=" + TestTempDir(); + + const char* argv[] = {"protoc", proto_path.c_str(), + plugin_specific_args.c_str(), capture_out.c_str(), + filename.c_str()}; + + return cli->Run(5, argv) == 0; +} + +bool DecodeMetadata(const std::string& path, GeneratedCodeInfo* info) { + std::string data; + GOOGLE_CHECK_OK(File::GetContents(path, &data, true)); + io::ArrayInputStream input(data.data(), data.size()); + return info->ParseFromZeroCopyStream(&input); +} + +void FindAnnotationsOnPath( + const GeneratedCodeInfo& info, const std::string& source_file, + const std::vector<int>& path, + std::vector<const GeneratedCodeInfo::Annotation*>* annotations) { + for (int i = 0; i < info.annotation_size(); ++i) { + const GeneratedCodeInfo::Annotation* annotation = &info.annotation(i); + if (annotation->source_file() != source_file || + annotation->path_size() != path.size()) { + continue; + } + int node = 0; + for (; node < path.size(); ++node) { + if (annotation->path(node) != path[node]) { + break; + } + } + if (node == path.size()) { + annotations->push_back(annotation); + } + } +} + +const GeneratedCodeInfo::Annotation* FindAnnotationOnPath( + const GeneratedCodeInfo& info, const std::string& source_file, + const std::vector<int>& path) { + std::vector<const GeneratedCodeInfo::Annotation*> annotations; + FindAnnotationsOnPath(info, source_file, path, &annotations); + if (annotations.empty()) { + return NULL; + } + return annotations[0]; +} + +bool AtLeastOneAnnotationMatchesSubstring( + const std::string& file_content, + const std::vector<const GeneratedCodeInfo::Annotation*>& annotations, + const std::string& expected_text) { + for (std::vector<const GeneratedCodeInfo::Annotation*>::const_iterator + i = annotations.begin(), + e = annotations.end(); + i != e; ++i) { + const GeneratedCodeInfo::Annotation* annotation = *i; + uint32_t begin = annotation->begin(); + uint32_t end = annotation->end(); + if (end < begin || end > file_content.size()) { + return false; + } + if (file_content.substr(begin, end - begin) == expected_text) { + return true; + } + } + return false; +} + +bool AnnotationMatchesSubstring(const std::string& file_content, + const GeneratedCodeInfo::Annotation* annotation, + const std::string& expected_text) { + std::vector<const GeneratedCodeInfo::Annotation*> annotations; + annotations.push_back(annotation); + return AtLeastOneAnnotationMatchesSubstring(file_content, annotations, + expected_text); +} +} // namespace annotation_test_util +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/annotation_test_util.h b/NorthstarDedicatedTest/include/protobuf/compiler/annotation_test_util.h new file mode 100644 index 00000000..2fd179cd --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/annotation_test_util.h @@ -0,0 +1,115 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_ANNOTATION_TEST_UTIL_H__ +#define GOOGLE_PROTOBUF_COMPILER_ANNOTATION_TEST_UTIL_H__ + +#include <descriptor.pb.h> +#include <testing/googletest.h> +#include <gtest/gtest.h> + +// Utilities that assist in writing tests for generator annotations. +// See java/internal/annotation_unittest.cc for an example. +namespace google { +namespace protobuf { +namespace compiler { +namespace annotation_test_util { + +// Struct that contains the file generated from a .proto file and its +// GeneratedCodeInfo. For example, the Java generator will fill this struct +// (for some 'foo.proto') with: +// file_path = "Foo.java" +// file_content = content of Foo.java +// file_info = parsed content of Foo.java.pb.meta +struct ExpectedOutput { + std::string file_path; + std::string file_content; + GeneratedCodeInfo file_info; + explicit ExpectedOutput(const std::string& file_path) + : file_path(file_path) {} +}; + +// Creates a file with name `filename` and content `data` in temp test +// directory. +void AddFile(const std::string& filename, const std::string& data); + +// Runs proto compiler. Captures proto file structure in FileDescriptorProto. +// Files will be generated in TestTempDir() folder. Callers of this +// function must read generated files themselves. +// +// filename: source .proto file used to generate code. +// plugin_specific_args: command line arguments specific to current generator. +// For Java, this value might be "--java_out=annotate_code:test_temp_dir" +// cli: instance of command line interface to run generator. See Java's +// annotation_unittest.cc for an example of how to initialize it. +// file: output parameter, will be set to the descriptor of the proto file +// specified in filename. +bool RunProtoCompiler(const std::string& filename, + const std::string& plugin_specific_args, + CommandLineInterface* cli, FileDescriptorProto* file); + +bool DecodeMetadata(const std::string& path, GeneratedCodeInfo* info); + +// Finds all of the Annotations for a given source file and path. +// See Location.path in https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/descriptor.proto for +// explanation of what path vector is. +void FindAnnotationsOnPath( + const GeneratedCodeInfo& info, const std::string& source_file, + const std::vector<int>& path, + std::vector<const GeneratedCodeInfo::Annotation*>* annotations); + +// Finds the Annotation for a given source file and path (or returns null if it +// couldn't). If there are several annotations for given path, returns the first +// one. See Location.path in +// https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/descriptor.proto for explanation of what path +// vector is. +const GeneratedCodeInfo::Annotation* FindAnnotationOnPath( + const GeneratedCodeInfo& info, const std::string& source_file, + const std::vector<int>& path); + +// Returns true if at least one of the provided annotations covers a given +// substring in file_content. +bool AtLeastOneAnnotationMatchesSubstring( + const std::string& file_content, + const std::vector<const GeneratedCodeInfo::Annotation*>& annotations, + const std::string& expected_text); + +// Returns true if the provided annotation covers a given substring in +// file_content. +bool AnnotationMatchesSubstring(const std::string& file_content, + const GeneratedCodeInfo::Annotation* annotation, + const std::string& expected_text); + +} // namespace annotation_test_util +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_ANNOTATION_TEST_UTIL_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/code_generator.cc b/NorthstarDedicatedTest/include/protobuf/compiler/code_generator.cc new file mode 100644 index 00000000..fd33d895 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/code_generator.cc @@ -0,0 +1,137 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <compiler/code_generator.h> + +#include <stubs/logging.h> +#include <stubs/common.h> +#include <compiler/plugin.pb.h> +#include <descriptor.h> +#include <stubs/strutil.h> + +namespace google { +namespace protobuf { +namespace compiler { + +CodeGenerator::~CodeGenerator() {} + +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 (int 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 = file->name() + ": " + *error; + break; + } + if (!succeeded) { + break; + } + } + return succeeded; +} + +GeneratorContext::~GeneratorContext() {} + +io::ZeroCopyOutputStream* GeneratorContext::OpenForAppend( + const std::string& filename) { + return NULL; +} + +io::ZeroCopyOutputStream* GeneratorContext::OpenForInsert( + const std::string& filename, const std::string& insertion_point) { + GOOGLE_LOG(FATAL) << "This GeneratorContext does not support insertion."; + return NULL; // 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) { + GOOGLE_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( + const std::string& text, + std::vector<std::pair<std::string, std::string> >* output) { + std::vector<std::string> parts = Split(text, ",", true); + + for (int i = 0; i < parts.size(); i++) { + std::string::size_type equals_pos = parts[i].find_first_of('='); + std::pair<std::string, std::string> value; + if (equals_pos == std::string::npos) { + value.first = parts[i]; + value.second = ""; + } else { + value.first = parts[i].substr(0, equals_pos); + value.second = parts[i].substr(equals_pos + 1); + } + output->push_back(value); + } +} + +// Strips ".proto" or ".protodevel" from the end of a filename. +std::string StripProto(const std::string& filename) { + if (HasSuffixString(filename, ".protodevel")) { + return StripSuffixString(filename, ".protodevel"); + } else { + return StripSuffixString(filename, ".proto"); + } +} + +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/code_generator.h b/NorthstarDedicatedTest/include/protobuf/compiler/code_generator.h new file mode 100644 index 00000000..ac2cf004 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/code_generator.h @@ -0,0 +1,206 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// Defines the abstract interface implemented by each of the language-specific +// code generators. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CODE_GENERATOR_H__ +#define GOOGLE_PROTOBUF_COMPILER_CODE_GENERATOR_H__ + +#include <string> +#include <utility> +#include <vector> +#include <stubs/common.h> + +#include <port_def.inc> + +namespace google { +namespace protobuf { + +namespace io { +class ZeroCopyOutputStream; +} +class FileDescriptor; +class GeneratedCodeInfo; + +namespace compiler { +class AccessInfoMap; + +class Version; + +// Defined in this file. +class CodeGenerator; +class GeneratorContext; + +// The abstract interface to a class which generates code implementing a +// particular proto file in a particular language. A number of these may +// be registered with CommandLineInterface to support various languages. +class PROTOC_EXPORT CodeGenerator { + public: + inline CodeGenerator() {} + virtual ~CodeGenerator(); + + // Generates code for the given proto file, generating one or more files in + // the given output directory. + // + // A parameter to be passed to the generator can be specified on the command + // line. This is intended to be used to pass generator specific parameters. + // It is empty if no parameter was given. ParseGeneratorParameter (below), + // can be used to accept multiple parameters within the single parameter + // command line flag. + // + // Returns true if successful. Otherwise, sets *error to a description of + // the problem (e.g. "invalid parameter") and returns false. + virtual bool Generate(const FileDescriptor* file, + const std::string& parameter, + GeneratorContext* generator_context, + std::string* error) const = 0; + + // Generates code for all given proto files. + // + // WARNING: The canonical code generator design produces one or two output + // files per input .proto file, and we do not wish to encourage alternate + // designs. + // + // A parameter is given as passed on the command line, as in |Generate()| + // above. + // + // Returns true if successful. Otherwise, sets *error to a description of + // the problem (e.g. "invalid parameter") and returns false. + virtual bool GenerateAll(const std::vector<const FileDescriptor*>& files, + const std::string& parameter, + GeneratorContext* generator_context, + std::string* error) const; + + // This must be kept in sync with plugin.proto. See that file for + // documentation on each value. + enum Feature { + FEATURE_PROTO3_OPTIONAL = 1, + }; + + // Implement this to indicate what features this code generator supports. + // + // This must be a bitwise OR of values from the Feature enum above (or zero). + virtual uint64_t GetSupportedFeatures() const { return 0; } + + // This is no longer used, but this class is part of the opensource protobuf + // library, so it has to remain to keep vtables the same for the current + // version of the library. When protobufs does a api breaking change, the + // method can be removed. + virtual bool HasGenerateAll() const { return true; } + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CodeGenerator); +}; + +// CodeGenerators generate one or more files in a given directory. This +// abstract interface represents the directory to which the CodeGenerator is +// to write and other information about the context in which the Generator +// runs. +class PROTOC_EXPORT GeneratorContext { + public: + inline GeneratorContext() { + } + virtual ~GeneratorContext(); + + // Opens the given file, truncating it if it exists, and returns a + // ZeroCopyOutputStream that writes to the file. The caller takes ownership + // of the returned object. This method never fails (a dummy stream will be + // returned instead). + // + // The filename given should be relative to the root of the source tree. + // E.g. the C++ generator, when generating code for "foo/bar.proto", will + // generate the files "foo/bar.pb.h" and "foo/bar.pb.cc"; note that + // "foo/" is included in these filenames. The filename is not allowed to + // contain "." or ".." components. + virtual io::ZeroCopyOutputStream* Open(const std::string& filename) = 0; + + // Similar to Open() but the output will be appended to the file if exists + virtual io::ZeroCopyOutputStream* OpenForAppend(const std::string& filename); + + // Creates a ZeroCopyOutputStream which will insert code into the given file + // at the given insertion point. See plugin.proto (plugin.pb.h) for more + // information on insertion points. The default implementation + // assert-fails -- it exists only for backwards-compatibility. + // + // WARNING: This feature is currently EXPERIMENTAL and is subject to change. + virtual io::ZeroCopyOutputStream* OpenForInsert( + const std::string& filename, const std::string& insertion_point); + + // Similar to OpenForInsert, but if `info` is non-empty, will open (or create) + // filename.pb.meta and insert info at the appropriate place with the + // necessary shifts. The default implementation ignores `info`. + // + // WARNING: This feature will be REMOVED in the near future. + virtual io::ZeroCopyOutputStream* OpenForInsertWithGeneratedCodeInfo( + const std::string& filename, const std::string& insertion_point, + const google::protobuf::GeneratedCodeInfo& info); + + // Returns a vector of FileDescriptors for all the files being compiled + // in this run. Useful for languages, such as Go, that treat files + // differently when compiled as a set rather than individually. + virtual void ListParsedFiles(std::vector<const FileDescriptor*>* output); + + // Retrieves the version number of the protocol compiler associated with + // this GeneratorContext. + virtual void GetCompilerVersion(Version* version) const; + + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(GeneratorContext); +}; + +// The type GeneratorContext was once called OutputDirectory. This typedef +// provides backward compatibility. +typedef GeneratorContext OutputDirectory; + +// Several code generators treat the parameter argument as holding a +// list of options separated by commas. This helper function parses +// a set of comma-delimited name/value pairs: e.g., +// "foo=bar,baz,qux=corge" +// parses to the pairs: +// ("foo", "bar"), ("baz", ""), ("qux", "corge") +PROTOC_EXPORT void ParseGeneratorParameter( + const std::string&, std::vector<std::pair<std::string, std::string> >*); + +// Strips ".proto" or ".protodevel" from the end of a filename. +PROTOC_EXPORT std::string StripProto(const std::string& filename); + +} // namespace compiler +} // namespace protobuf +} // namespace google + +#include <port_undef.inc> + +#endif // GOOGLE_PROTOBUF_COMPILER_CODE_GENERATOR_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/command_line_interface.cc b/NorthstarDedicatedTest/include/protobuf/compiler/command_line_interface.cc new file mode 100644 index 00000000..f2209964 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/command_line_interface.cc @@ -0,0 +1,2616 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <compiler/command_line_interface.h> + +#include <cstdint> + +#include <stubs/platform_macros.h> + +#include <stdio.h> +#include <sys/types.h> +#ifdef major +#undef major +#endif +#ifdef minor +#undef minor +#endif +#include <fcntl.h> +#include <sys/stat.h> +#ifndef _MSC_VER +#include <unistd.h> +#endif +#include <ctype.h> +#include <errno.h> +#include <fstream> +#include <iostream> + +#include <limits.h> //For PATH_MAX + +#include <memory> + +#if defined(__APPLE__) +#include <mach-o/dyld.h> +#elif defined(__FreeBSD__) +#include <sys/sysctl.h> +#endif + +#include <stubs/common.h> +#include <stubs/logging.h> +#include <stubs/stringprintf.h> +#include <compiler/subprocess.h> +#include <compiler/zip_writer.h> +#include <compiler/plugin.pb.h> +#include <compiler/code_generator.h> +#include <compiler/importer.h> +#include <io/coded_stream.h> +#include <io/printer.h> +#include <io/zero_copy_stream_impl.h> +#include <descriptor.h> +#include <dynamic_message.h> +#include <text_format.h> +#include <stubs/strutil.h> +#include <stubs/substitute.h> +#include <io/io_win32.h> +#include <stubs/map_util.h> +#include <stubs/stl_util.h> + + +#include <port_def.inc> + +namespace google { +namespace protobuf { +namespace compiler { + +#ifndef O_BINARY +#ifdef _O_BINARY +#define O_BINARY _O_BINARY +#else +#define O_BINARY 0 // If this isn't defined, the platform doesn't need it. +#endif +#endif + +namespace { +#if defined(_WIN32) +// DO NOT include <io.h>, instead create functions in io_win32.{h,cc} and import +// them like we do below. +using google::protobuf::io::win32::access; +using google::protobuf::io::win32::close; +using google::protobuf::io::win32::mkdir; +using google::protobuf::io::win32::open; +using google::protobuf::io::win32::setmode; +using google::protobuf::io::win32::write; +#endif + +static const char* kDefaultDirectDependenciesViolationMsg = + "File is imported but not declared in --direct_dependencies: %s"; + +// Returns true if the text looks like a Windows-style absolute path, starting +// with a drive letter. Example: "C:\foo". TODO(kenton): Share this with +// copy in importer.cc? +static bool IsWindowsAbsolutePath(const std::string& text) { +#if defined(_WIN32) || defined(__CYGWIN__) + return text.size() >= 3 && text[1] == ':' && isalpha(text[0]) && + (text[2] == '/' || text[2] == '\\') && text.find_last_of(':') == 1; +#else + return false; +#endif +} + +void SetFdToTextMode(int fd) { +#ifdef _WIN32 + if (setmode(fd, _O_TEXT) == -1) { + // This should never happen, I think. + GOOGLE_LOG(WARNING) << "setmode(" << fd << ", _O_TEXT): " << strerror(errno); + } +#endif + // (Text and binary are the same on non-Windows platforms.) +} + +void SetFdToBinaryMode(int fd) { +#ifdef _WIN32 + if (setmode(fd, _O_BINARY) == -1) { + // This should never happen, I think. + GOOGLE_LOG(WARNING) << "setmode(" << fd << ", _O_BINARY): " << strerror(errno); + } +#endif + // (Text and binary are the same on non-Windows platforms.) +} + +void AddTrailingSlash(std::string* path) { + if (!path->empty() && path->at(path->size() - 1) != '/') { + path->push_back('/'); + } +} + +bool VerifyDirectoryExists(const std::string& path) { + if (path.empty()) return true; + + if (access(path.c_str(), F_OK) == -1) { + std::cerr << path << ": " << strerror(errno) << std::endl; + return false; + } else { + return true; + } +} + +// Try to create the parent directory of the given file, creating the parent's +// parent if necessary, and so on. The full file name is actually +// (prefix + filename), but we assume |prefix| already exists and only create +// directories listed in |filename|. +bool TryCreateParentDirectory(const std::string& prefix, + const std::string& filename) { + // Recursively create parent directories to the output file. + // On Windows, both '/' and '\' are valid path separators. + std::vector<std::string> parts = + Split(filename, "/\\", true); + std::string path_so_far = prefix; + for (int i = 0; i < parts.size() - 1; i++) { + path_so_far += parts[i]; + if (mkdir(path_so_far.c_str(), 0777) != 0) { + if (errno != EEXIST) { + std::cerr << filename << ": while trying to create directory " + << path_so_far << ": " << strerror(errno) << std::endl; + return false; + } + } + path_so_far += '/'; + } + + return true; +} + +// Get the absolute path of this protoc binary. +bool GetProtocAbsolutePath(std::string* path) { +#ifdef _WIN32 + char buffer[MAX_PATH]; + int len = GetModuleFileNameA(NULL, buffer, MAX_PATH); +#elif defined(__APPLE__) + char buffer[PATH_MAX]; + int len = 0; + + char dirtybuffer[PATH_MAX]; + uint32_t size = sizeof(dirtybuffer); + if (_NSGetExecutablePath(dirtybuffer, &size) == 0) { + realpath(dirtybuffer, buffer); + len = strlen(buffer); + } +#elif defined(__FreeBSD__) + char buffer[PATH_MAX]; + size_t len = PATH_MAX; + int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1}; + if (sysctl(mib, 4, &buffer, &len, NULL, 0) != 0) { + len = 0; + } +#else + char buffer[PATH_MAX]; + int len = readlink("/proc/self/exe", buffer, PATH_MAX); +#endif + if (len > 0) { + path->assign(buffer, len); + return true; + } else { + return false; + } +} + +// Whether a path is where google/protobuf/descriptor.proto and other well-known +// type protos are installed. +bool IsInstalledProtoPath(const std::string& path) { + // Checking the descriptor.proto file should be good enough. + std::string file_path = path + "/google/protobuf/descriptor.proto"; + return access(file_path.c_str(), F_OK) != -1; +} + +// Add the paths where google/protobuf/descriptor.proto and other well-known +// type protos are installed. +void AddDefaultProtoPaths( + std::vector<std::pair<std::string, std::string>>* paths) { + // TODO(xiaofeng): The code currently only checks relative paths of where + // the protoc binary is installed. We probably should make it handle more + // cases than that. + std::string path; + if (!GetProtocAbsolutePath(&path)) { + return; + } + // Strip the binary name. + size_t pos = path.find_last_of("/\\"); + if (pos == std::string::npos || pos == 0) { + return; + } + path = path.substr(0, pos); + // Check the binary's directory. + if (IsInstalledProtoPath(path)) { + paths->push_back(std::pair<std::string, std::string>("", path)); + return; + } + // Check if there is an include subdirectory. + if (IsInstalledProtoPath(path + "/include")) { + paths->push_back( + std::pair<std::string, std::string>("", path + "/include")); + return; + } + // Check if the upper level directory has an "include" subdirectory. + pos = path.find_last_of("/\\"); + if (pos == std::string::npos || pos == 0) { + return; + } + path = path.substr(0, pos); + if (IsInstalledProtoPath(path + "/include")) { + paths->push_back( + std::pair<std::string, std::string>("", path + "/include")); + return; + } +} + +std::string PluginName(const std::string& plugin_prefix, + const std::string& directive) { + // Assuming the directive starts with "--" and ends with "_out" or "_opt", + // strip the "--" and "_out/_opt" and add the plugin prefix. + return plugin_prefix + "gen-" + directive.substr(2, directive.size() - 6); +} + +} // namespace + +// A MultiFileErrorCollector that prints errors to stderr. +class CommandLineInterface::ErrorPrinter + : public MultiFileErrorCollector, + public io::ErrorCollector, + public DescriptorPool::ErrorCollector { + public: + ErrorPrinter(ErrorFormat format, DiskSourceTree* tree = NULL) + : format_(format), + tree_(tree), + found_errors_(false), + found_warnings_(false) {} + ~ErrorPrinter() {} + + // implements MultiFileErrorCollector ------------------------------ + void AddError(const std::string& filename, int line, int column, + const std::string& message) override { + found_errors_ = true; + AddErrorOrWarning(filename, line, column, message, "error", std::cerr); + } + + void AddWarning(const std::string& filename, int line, int column, + const std::string& message) override { + found_warnings_ = true; + AddErrorOrWarning(filename, line, column, message, "warning", std::clog); + } + + // implements io::ErrorCollector ----------------------------------- + void AddError(int line, int column, const std::string& message) override { + AddError("input", line, column, message); + } + + void AddWarning(int line, int column, const std::string& message) override { + AddErrorOrWarning("input", line, column, message, "warning", std::clog); + } + + // implements DescriptorPool::ErrorCollector------------------------- + void AddError(const std::string& filename, const std::string& element_name, + const Message* descriptor, ErrorLocation location, + const std::string& message) override { + AddErrorOrWarning(filename, -1, -1, message, "error", std::cerr); + } + + void AddWarning(const std::string& filename, const std::string& element_name, + const Message* descriptor, ErrorLocation location, + const std::string& message) override { + AddErrorOrWarning(filename, -1, -1, message, "warning", std::clog); + } + + bool FoundErrors() const { return found_errors_; } + + bool FoundWarnings() const { return found_warnings_; } + + private: + void AddErrorOrWarning(const std::string& filename, int line, int column, + const std::string& message, const std::string& type, + std::ostream& out) { + // Print full path when running under MSVS + std::string dfile; + if (format_ == CommandLineInterface::ERROR_FORMAT_MSVS && tree_ != NULL && + tree_->VirtualFileToDiskFile(filename, &dfile)) { + out << dfile; + } else { + out << filename; + } + + // Users typically expect 1-based line/column numbers, so we add 1 + // to each here. + if (line != -1) { + // Allow for both GCC- and Visual-Studio-compatible output. + switch (format_) { + case CommandLineInterface::ERROR_FORMAT_GCC: + out << ":" << (line + 1) << ":" << (column + 1); + break; + case CommandLineInterface::ERROR_FORMAT_MSVS: + out << "(" << (line + 1) << ") : " << type + << " in column=" << (column + 1); + break; + } + } + + if (type == "warning") { + out << ": warning: " << message << std::endl; + } else { + out << ": " << message << std::endl; + } + } + + const ErrorFormat format_; + DiskSourceTree* tree_; + bool found_errors_; + bool found_warnings_; +}; + +// ------------------------------------------------------------------- + +// A GeneratorContext implementation that buffers files in memory, then dumps +// them all to disk on demand. +class CommandLineInterface::GeneratorContextImpl : public GeneratorContext { + public: + GeneratorContextImpl(const std::vector<const FileDescriptor*>& parsed_files); + + // Write all files in the directory to disk at the given output location, + // which must end in a '/'. + bool WriteAllToDisk(const std::string& prefix); + + // Write the contents of this directory to a ZIP-format archive with the + // given name. + bool WriteAllToZip(const std::string& filename); + + // Add a boilerplate META-INF/MANIFEST.MF file as required by the Java JAR + // format, unless one has already been written. + void AddJarManifest(); + + // Get name of all output files. + void GetOutputFilenames(std::vector<std::string>* output_filenames); + + // implements GeneratorContext -------------------------------------- + io::ZeroCopyOutputStream* Open(const std::string& filename) override; + io::ZeroCopyOutputStream* OpenForAppend(const std::string& filename) override; + io::ZeroCopyOutputStream* OpenForInsert( + const std::string& filename, const std::string& insertion_point) override; + io::ZeroCopyOutputStream* OpenForInsertWithGeneratedCodeInfo( + const std::string& filename, const std::string& insertion_point, + const google::protobuf::GeneratedCodeInfo& info) override; + void ListParsedFiles(std::vector<const FileDescriptor*>* output) override { + *output = parsed_files_; + } + + private: + friend class MemoryOutputStream; + + // The files_ field maps from path keys to file content values. It's a map + // instead of an unordered_map so that files are written in order (good when + // writing zips). + std::map<std::string, std::string> files_; + const std::vector<const FileDescriptor*>& parsed_files_; + bool had_error_; +}; + +class CommandLineInterface::MemoryOutputStream + : public io::ZeroCopyOutputStream { + public: + MemoryOutputStream(GeneratorContextImpl* directory, + const std::string& filename, bool append_mode); + MemoryOutputStream(GeneratorContextImpl* directory, + const std::string& filename, + const std::string& insertion_point); + MemoryOutputStream(GeneratorContextImpl* directory, + const std::string& filename, + const std::string& insertion_point, + const google::protobuf::GeneratedCodeInfo& info); + virtual ~MemoryOutputStream(); + + // implements ZeroCopyOutputStream --------------------------------- + bool Next(void** data, int* size) override { + return inner_->Next(data, size); + } + void BackUp(int count) override { inner_->BackUp(count); } + int64_t ByteCount() const override { return inner_->ByteCount(); } + + private: + // Checks to see if "filename_.pb.meta" exists in directory_; if so, fixes the + // offsets in that GeneratedCodeInfo record to reflect bytes inserted in + // filename_ at original offset insertion_offset with length insertion_length. + // Also adds in the data from info_to_insert_ with updated offsets governed by + // insertion_offset and indent_length. We assume that insertions will not + // occur within any given annotated span of text. insertion_content must end + // with an endline. + void UpdateMetadata(const std::string& insertion_content, + size_t insertion_offset, size_t insertion_length, + size_t indent_length); + + // Inserts info_to_insert_ into target_info, assuming that the relevant + // insertion was made at insertion_offset in file_content with the given + // indent_length. insertion_content must end with an endline. + void InsertShiftedInfo(const std::string& insertion_content, + size_t insertion_offset, size_t indent_length, + google::protobuf::GeneratedCodeInfo& target_info); + + // Where to insert the string when it's done. + GeneratorContextImpl* directory_; + std::string filename_; + std::string insertion_point_; + + // The string we're building. + std::string data_; + + // Whether we should append the output stream to the existing file. + bool append_mode_; + + // StringOutputStream writing to data_. + std::unique_ptr<io::StringOutputStream> inner_; + + // The GeneratedCodeInfo to insert at the insertion point. + google::protobuf::GeneratedCodeInfo info_to_insert_; +}; + +// ------------------------------------------------------------------- + +CommandLineInterface::GeneratorContextImpl::GeneratorContextImpl( + const std::vector<const FileDescriptor*>& parsed_files) + : parsed_files_(parsed_files), had_error_(false) {} + +bool CommandLineInterface::GeneratorContextImpl::WriteAllToDisk( + const std::string& prefix) { + if (had_error_) { + return false; + } + + if (!VerifyDirectoryExists(prefix)) { + return false; + } + + for (const auto& pair : files_) { + const std::string& relative_filename = pair.first; + const char* data = pair.second.data(); + int size = pair.second.size(); + + if (!TryCreateParentDirectory(prefix, relative_filename)) { + return false; + } + std::string filename = prefix + relative_filename; + + // Create the output file. + int file_descriptor; + do { + file_descriptor = + open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666); + } while (file_descriptor < 0 && errno == EINTR); + + if (file_descriptor < 0) { + int error = errno; + std::cerr << filename << ": " << strerror(error); + return false; + } + + // Write the file. + while (size > 0) { + int write_result; + do { + write_result = write(file_descriptor, data, size); + } while (write_result < 0 && errno == EINTR); + + if (write_result <= 0) { + // Write error. + + // FIXME(kenton): According to the man page, if write() returns zero, + // there was no error; write() simply did not write anything. It's + // unclear under what circumstances this might happen, but presumably + // errno won't be set in this case. I am confused as to how such an + // event should be handled. For now I'm treating it as an error, + // since retrying seems like it could lead to an infinite loop. I + // suspect this never actually happens anyway. + + if (write_result < 0) { + int error = errno; + std::cerr << filename << ": write: " << strerror(error); + } else { + std::cerr << filename << ": write() returned zero?" << std::endl; + } + return false; + } + + data += write_result; + size -= write_result; + } + + if (close(file_descriptor) != 0) { + int error = errno; + std::cerr << filename << ": close: " << strerror(error); + return false; + } + } + + return true; +} + +bool CommandLineInterface::GeneratorContextImpl::WriteAllToZip( + const std::string& filename) { + if (had_error_) { + return false; + } + + // Create the output file. + int file_descriptor; + do { + file_descriptor = + open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666); + } while (file_descriptor < 0 && errno == EINTR); + + if (file_descriptor < 0) { + int error = errno; + std::cerr << filename << ": " << strerror(error); + return false; + } + + // Create the ZipWriter + io::FileOutputStream stream(file_descriptor); + ZipWriter zip_writer(&stream); + + for (const auto& pair : files_) { + zip_writer.Write(pair.first, pair.second); + } + + zip_writer.WriteDirectory(); + + if (stream.GetErrno() != 0) { + std::cerr << filename << ": " << strerror(stream.GetErrno()) << std::endl; + return false; + } + + if (!stream.Close()) { + std::cerr << filename << ": " << strerror(stream.GetErrno()) << std::endl; + return false; + } + + return true; +} + +void CommandLineInterface::GeneratorContextImpl::AddJarManifest() { + auto pair = files_.insert({"META-INF/MANIFEST.MF", ""}); + if (pair.second) { + pair.first->second = + "Manifest-Version: 1.0\n" + "Created-By: 1.6.0 (protoc)\n" + "\n"; + } +} + +void CommandLineInterface::GeneratorContextImpl::GetOutputFilenames( + std::vector<std::string>* output_filenames) { + for (const auto& pair : files_) { + output_filenames->push_back(pair.first); + } +} + +io::ZeroCopyOutputStream* CommandLineInterface::GeneratorContextImpl::Open( + const std::string& filename) { + return new MemoryOutputStream(this, filename, false); +} + +io::ZeroCopyOutputStream* +CommandLineInterface::GeneratorContextImpl::OpenForAppend( + const std::string& filename) { + return new MemoryOutputStream(this, filename, true); +} + +io::ZeroCopyOutputStream* +CommandLineInterface::GeneratorContextImpl::OpenForInsert( + const std::string& filename, const std::string& insertion_point) { + return new MemoryOutputStream(this, filename, insertion_point); +} + +io::ZeroCopyOutputStream* +CommandLineInterface::GeneratorContextImpl::OpenForInsertWithGeneratedCodeInfo( + const std::string& filename, const std::string& insertion_point, + const google::protobuf::GeneratedCodeInfo& info) { + return new MemoryOutputStream(this, filename, insertion_point, info); +} + +// ------------------------------------------------------------------- + +CommandLineInterface::MemoryOutputStream::MemoryOutputStream( + GeneratorContextImpl* directory, const std::string& filename, + bool append_mode) + : directory_(directory), + filename_(filename), + append_mode_(append_mode), + inner_(new io::StringOutputStream(&data_)) {} + +CommandLineInterface::MemoryOutputStream::MemoryOutputStream( + GeneratorContextImpl* directory, const std::string& filename, + const std::string& insertion_point) + : directory_(directory), + filename_(filename), + insertion_point_(insertion_point), + inner_(new io::StringOutputStream(&data_)) {} + +CommandLineInterface::MemoryOutputStream::MemoryOutputStream( + GeneratorContextImpl* directory, const std::string& filename, + const std::string& insertion_point, const google::protobuf::GeneratedCodeInfo& info) + : directory_(directory), + filename_(filename), + insertion_point_(insertion_point), + inner_(new io::StringOutputStream(&data_)), + info_to_insert_(info) {} + +void CommandLineInterface::MemoryOutputStream::InsertShiftedInfo( + const std::string& insertion_content, size_t insertion_offset, + size_t indent_length, google::protobuf::GeneratedCodeInfo& target_info) { + // Keep track of how much extra data was added for indents before the + // current annotation being inserted. `pos` and `source_annotation.begin()` + // are offsets in `insertion_content`. `insertion_offset` is updated so that + // it can be added to an annotation's `begin` field to reflect that + // annotation's updated location after `insertion_content` was inserted into + // the target file. + size_t pos = 0; + insertion_offset += indent_length; + for (const auto& source_annotation : info_to_insert_.annotation()) { + GeneratedCodeInfo::Annotation* annotation = target_info.add_annotation(); + int inner_indent = 0; + // insertion_content is guaranteed to end in an endline. This last endline + // has no effect on indentation. + for (; pos < source_annotation.end() && pos < insertion_content.size() - 1; + ++pos) { + if (insertion_content[pos] == '\n') { + if (pos >= source_annotation.begin()) { + // The beginning of the annotation is at insertion_offset, but the end + // can still move further in the target file. + inner_indent += indent_length; + } else { + insertion_offset += indent_length; + } + } + } + *annotation = source_annotation; + annotation->set_begin(annotation->begin() + insertion_offset); + insertion_offset += inner_indent; + annotation->set_end(annotation->end() + insertion_offset); + } +} + +void CommandLineInterface::MemoryOutputStream::UpdateMetadata( + const std::string& insertion_content, size_t insertion_offset, + size_t insertion_length, size_t indent_length) { + auto it = directory_->files_.find(filename_ + ".pb.meta"); + if (it == directory_->files_.end() && info_to_insert_.annotation().empty()) { + // No metadata was recorded for this file. + return; + } + GeneratedCodeInfo metadata; + bool is_text_format = false; + std::string* encoded_data = nullptr; + if (it != directory_->files_.end()) { + encoded_data = &it->second; + // Try to decode a GeneratedCodeInfo proto from the .pb.meta file. It may be + // in wire or text format. Keep the same format when the data is written out + // later. + if (!metadata.ParseFromString(*encoded_data)) { + if (!TextFormat::ParseFromString(*encoded_data, &metadata)) { + // The metadata is invalid. + std::cerr + << filename_ + << ".pb.meta: Could not parse metadata as wire or text format." + << std::endl; + return; + } + // Generators that use the public plugin interface emit text-format + // metadata (because in the public plugin protocol, file content must be + // UTF8-encoded strings). + is_text_format = true; + } + } else { + // Create a new file to store the new metadata in info_to_insert_. + encoded_data = + &directory_->files_.insert({filename_ + ".pb.meta", ""}).first->second; + } + GeneratedCodeInfo new_metadata; + bool crossed_offset = false; + size_t to_add = 0; + for (const auto& source_annotation : metadata.annotation()) { + // The first time an annotation at or after the insertion point is found, + // insert the new metadata from info_to_insert_. Shift all annotations + // after the new metadata by the length of the text that was inserted + // (including any additional indent length). + if (source_annotation.begin() >= insertion_offset && !crossed_offset) { + crossed_offset = true; + InsertShiftedInfo(insertion_content, insertion_offset, indent_length, + new_metadata); + to_add += insertion_length; + } + GeneratedCodeInfo::Annotation* annotation = new_metadata.add_annotation(); + *annotation = source_annotation; + annotation->set_begin(annotation->begin() + to_add); + annotation->set_end(annotation->end() + to_add); + } + // If there were never any annotations at or after the insertion point, + // make sure to still insert the new metadata from info_to_insert_. + if (!crossed_offset) { + InsertShiftedInfo(insertion_content, insertion_offset, indent_length, + new_metadata); + } + if (is_text_format) { + TextFormat::PrintToString(new_metadata, encoded_data); + } else { + new_metadata.SerializeToString(encoded_data); + } +} + +CommandLineInterface::MemoryOutputStream::~MemoryOutputStream() { + // Make sure all data has been written. + inner_.reset(); + + // Insert into the directory. + auto pair = directory_->files_.insert({filename_, ""}); + auto it = pair.first; + bool already_present = !pair.second; + + if (insertion_point_.empty()) { + // This was just a regular Open(). + if (already_present) { + if (append_mode_) { + it->second.append(data_); + } else { + std::cerr << filename_ << ": Tried to write the same file twice." + << std::endl; + directory_->had_error_ = true; + } + return; + } + + it->second.swap(data_); + } else { + // This was an OpenForInsert(). + + // If the data doesn't end with a clean line break, add one. + if (!data_.empty() && data_[data_.size() - 1] != '\n') { + data_.push_back('\n'); + } + + // Find the file we are going to insert into. + if (!already_present) { + std::cerr << filename_ + << ": Tried to insert into file that doesn't exist." + << std::endl; + directory_->had_error_ = true; + return; + } + std::string* target = &it->second; + + // Find the insertion point. + std::string magic_string = + strings::Substitute("@@protoc_insertion_point($0)", insertion_point_); + std::string::size_type pos = target->find(magic_string); + + if (pos == std::string::npos) { + std::cerr << filename_ << ": insertion point \"" << insertion_point_ + << "\" not found." << std::endl; + directory_->had_error_ = true; + return; + } + + if ((pos > 3) && (target->substr(pos - 3, 2) == "/*")) { + // Support for inline "/* @@protoc_insertion_point() */" + pos = pos - 3; + } else { + // Seek backwards to the beginning of the line, which is where we will + // insert the data. Note that this has the effect of pushing the + // insertion point down, so the data is inserted before it. This is + // intentional because it means that multiple insertions at the same point + // will end up in the expected order in the final output. + pos = target->find_last_of('\n', pos); + if (pos == std::string::npos) { + // Insertion point is on the first line. + pos = 0; + } else { + // Advance to character after '\n'. + ++pos; + } + } + + // Extract indent. + std::string indent_(*target, pos, + target->find_first_not_of(" \t", pos) - pos); + + if (indent_.empty()) { + // No indent. This makes things easier. + target->insert(pos, data_); + UpdateMetadata(data_, pos, data_.size(), 0); + } else { + // Calculate how much space we need. + int indent_size = 0; + for (int i = 0; i < data_.size(); i++) { + if (data_[i] == '\n') indent_size += indent_.size(); + } + + // Make a hole for it. + target->insert(pos, data_.size() + indent_size, '\0'); + + // Now copy in the data. + std::string::size_type data_pos = 0; + char* target_ptr = ::google::protobuf::string_as_array(target) + pos; + while (data_pos < data_.size()) { + // Copy indent. + memcpy(target_ptr, indent_.data(), indent_.size()); + target_ptr += indent_.size(); + + // Copy line from data_. + // We already guaranteed that data_ ends with a newline (above), so this + // search can't fail. + std::string::size_type line_length = + data_.find_first_of('\n', data_pos) + 1 - data_pos; + memcpy(target_ptr, data_.data() + data_pos, line_length); + target_ptr += line_length; + data_pos += line_length; + } + UpdateMetadata(data_, pos, data_.size() + indent_size, indent_.size()); + + GOOGLE_CHECK_EQ(target_ptr, + ::google::protobuf::string_as_array(target) + pos + data_.size() + indent_size); + } + } +} + +// =================================================================== + +#if defined(_WIN32) && !defined(__CYGWIN__) +const char* const CommandLineInterface::kPathSeparator = ";"; +#else +const char* const CommandLineInterface::kPathSeparator = ":"; +#endif + +CommandLineInterface::CommandLineInterface() + : direct_dependencies_violation_msg_( + kDefaultDirectDependenciesViolationMsg) {} + +CommandLineInterface::~CommandLineInterface() {} + +void CommandLineInterface::RegisterGenerator(const std::string& flag_name, + CodeGenerator* generator, + const std::string& help_text) { + GeneratorInfo info; + info.flag_name = flag_name; + info.generator = generator; + info.help_text = help_text; + generators_by_flag_name_[flag_name] = info; +} + +void CommandLineInterface::RegisterGenerator( + const std::string& flag_name, const std::string& option_flag_name, + CodeGenerator* generator, const std::string& help_text) { + GeneratorInfo info; + info.flag_name = flag_name; + info.option_flag_name = option_flag_name; + info.generator = generator; + info.help_text = help_text; + generators_by_flag_name_[flag_name] = info; + generators_by_option_name_[option_flag_name] = info; +} + +void CommandLineInterface::AllowPlugins(const std::string& exe_name_prefix) { + plugin_prefix_ = exe_name_prefix; +} + +namespace { + +bool ContainsProto3Optional(const Descriptor* desc) { + for (int i = 0; i < desc->field_count(); i++) { + if (desc->field(i)->has_optional_keyword()) { + return true; + } + } + for (int i = 0; i < desc->nested_type_count(); i++) { + if (ContainsProto3Optional(desc->nested_type(i))) { + return true; + } + } + return false; +} + +bool ContainsProto3Optional(const FileDescriptor* file) { + if (file->syntax() == FileDescriptor::SYNTAX_PROTO3) { + for (int i = 0; i < file->message_type_count(); i++) { + if (ContainsProto3Optional(file->message_type(i))) { + return true; + } + } + } + return false; +} + +} // namespace + +namespace { +std::unique_ptr<SimpleDescriptorDatabase> +PopulateSingleSimpleDescriptorDatabase(const std::string& descriptor_set_name); +} + +int CommandLineInterface::Run(int argc, const char* const argv[]) { + Clear(); + switch (ParseArguments(argc, argv)) { + case PARSE_ARGUMENT_DONE_AND_EXIT: + return 0; + case PARSE_ARGUMENT_FAIL: + return 1; + case PARSE_ARGUMENT_DONE_AND_CONTINUE: + break; + } + + std::vector<const FileDescriptor*> parsed_files; + std::unique_ptr<DiskSourceTree> disk_source_tree; + std::unique_ptr<ErrorPrinter> error_collector; + std::unique_ptr<DescriptorPool> descriptor_pool; + + // The SimpleDescriptorDatabases here are the constituents of the + // MergedDescriptorDatabase descriptor_set_in_database, so this vector is for + // managing their lifetimes. Its scope should match descriptor_set_in_database + std::vector<std::unique_ptr<SimpleDescriptorDatabase>> + databases_per_descriptor_set; + std::unique_ptr<MergedDescriptorDatabase> descriptor_set_in_database; + + std::unique_ptr<SourceTreeDescriptorDatabase> source_tree_database; + + // Any --descriptor_set_in FileDescriptorSet objects will be used as a + // fallback to input_files on command line, so create that db first. + if (!descriptor_set_in_names_.empty()) { + for (const std::string& name : descriptor_set_in_names_) { + std::unique_ptr<SimpleDescriptorDatabase> database_for_descriptor_set = + PopulateSingleSimpleDescriptorDatabase(name); + if (!database_for_descriptor_set) { + return EXIT_FAILURE; + } + databases_per_descriptor_set.push_back( + std::move(database_for_descriptor_set)); + } + + std::vector<DescriptorDatabase*> raw_databases_per_descriptor_set; + raw_databases_per_descriptor_set.reserve( + databases_per_descriptor_set.size()); + for (const std::unique_ptr<SimpleDescriptorDatabase>& db : + databases_per_descriptor_set) { + raw_databases_per_descriptor_set.push_back(db.get()); + } + descriptor_set_in_database.reset( + new MergedDescriptorDatabase(raw_databases_per_descriptor_set)); + } + + if (proto_path_.empty()) { + // If there are no --proto_path flags, then just look in the specified + // --descriptor_set_in files. But first, verify that the input files are + // there. + if (!VerifyInputFilesInDescriptors(descriptor_set_in_database.get())) { + return 1; + } + + error_collector.reset(new ErrorPrinter(error_format_)); + descriptor_pool.reset(new DescriptorPool(descriptor_set_in_database.get(), + error_collector.get())); + } else { + disk_source_tree.reset(new DiskSourceTree()); + if (!InitializeDiskSourceTree(disk_source_tree.get(), + descriptor_set_in_database.get())) { + return 1; + } + + error_collector.reset( + new ErrorPrinter(error_format_, disk_source_tree.get())); + + source_tree_database.reset(new SourceTreeDescriptorDatabase( + disk_source_tree.get(), descriptor_set_in_database.get())); + source_tree_database->RecordErrorsTo(error_collector.get()); + + descriptor_pool.reset(new DescriptorPool( + source_tree_database.get(), + source_tree_database->GetValidationErrorCollector())); + } + + descriptor_pool->EnforceWeakDependencies(true); + if (!ParseInputFiles(descriptor_pool.get(), disk_source_tree.get(), + &parsed_files)) { + return 1; + } + + + // We construct a separate GeneratorContext for each output location. Note + // that two code generators may output to the same location, in which case + // they should share a single GeneratorContext so that OpenForInsert() works. + GeneratorContextMap output_directories; + + // Generate output. + if (mode_ == MODE_COMPILE) { + for (int i = 0; i < output_directives_.size(); i++) { + std::string output_location = output_directives_[i].output_location; + if (!HasSuffixString(output_location, ".zip") && + !HasSuffixString(output_location, ".jar") && + !HasSuffixString(output_location, ".srcjar")) { + AddTrailingSlash(&output_location); + } + + auto& generator = output_directories[output_location]; + + if (!generator) { + // First time we've seen this output location. + generator.reset(new GeneratorContextImpl(parsed_files)); + } + + if (!GenerateOutput(parsed_files, output_directives_[i], + generator.get())) { + return 1; + } + } + } + + // Write all output to disk. + for (const auto& pair : output_directories) { + const std::string& location = pair.first; + GeneratorContextImpl* directory = pair.second.get(); + if (HasSuffixString(location, "/")) { + if (!directory->WriteAllToDisk(location)) { + return 1; + } + } else { + if (HasSuffixString(location, ".jar")) { + directory->AddJarManifest(); + } + + if (!directory->WriteAllToZip(location)) { + return 1; + } + } + } + + if (!dependency_out_name_.empty()) { + GOOGLE_DCHECK(disk_source_tree.get()); + if (!GenerateDependencyManifestFile(parsed_files, output_directories, + disk_source_tree.get())) { + return 1; + } + } + + if (!descriptor_set_out_name_.empty()) { + if (!WriteDescriptorSet(parsed_files)) { + return 1; + } + } + + if (mode_ == MODE_ENCODE || mode_ == MODE_DECODE) { + if (codec_type_.empty()) { + // HACK: Define an EmptyMessage type to use for decoding. + DescriptorPool pool; + FileDescriptorProto file; + file.set_name("empty_message.proto"); + file.add_message_type()->set_name("EmptyMessage"); + GOOGLE_CHECK(pool.BuildFile(file) != NULL); + codec_type_ = "EmptyMessage"; + if (!EncodeOrDecode(&pool)) { + return 1; + } + } else { + if (!EncodeOrDecode(descriptor_pool.get())) { + return 1; + } + } + } + + if (error_collector->FoundErrors() || + (fatal_warnings_ && error_collector->FoundWarnings())) { + return 1; + } + + if (mode_ == MODE_PRINT) { + switch (print_mode_) { + case PRINT_FREE_FIELDS: + for (int i = 0; i < parsed_files.size(); ++i) { + const FileDescriptor* fd = parsed_files[i]; + for (int j = 0; j < fd->message_type_count(); ++j) { + PrintFreeFieldNumbers(fd->message_type(j)); + } + } + break; + case PRINT_NONE: + GOOGLE_LOG(ERROR) << "If the code reaches here, it usually means a bug of " + "flag parsing in the CommandLineInterface."; + return 1; + + // Do not add a default case. + } + } + + return 0; +} + +bool CommandLineInterface::InitializeDiskSourceTree( + DiskSourceTree* source_tree, DescriptorDatabase* fallback_database) { + AddDefaultProtoPaths(&proto_path_); + + // Set up the source tree. + for (int i = 0; i < proto_path_.size(); i++) { + source_tree->MapPath(proto_path_[i].first, proto_path_[i].second); + } + + // Map input files to virtual paths if possible. + if (!MakeInputsBeProtoPathRelative(source_tree, fallback_database)) { + return false; + } + + return true; +} + +namespace { +std::unique_ptr<SimpleDescriptorDatabase> +PopulateSingleSimpleDescriptorDatabase(const std::string& descriptor_set_name) { + int fd; + do { + fd = open(descriptor_set_name.c_str(), O_RDONLY | O_BINARY); + } while (fd < 0 && errno == EINTR); + if (fd < 0) { + std::cerr << descriptor_set_name << ": " << strerror(ENOENT) << std::endl; + return nullptr; + } + + FileDescriptorSet file_descriptor_set; + bool parsed = file_descriptor_set.ParseFromFileDescriptor(fd); + if (close(fd) != 0) { + std::cerr << descriptor_set_name << ": close: " << strerror(errno) + << std::endl; + return nullptr; + } + + if (!parsed) { + std::cerr << descriptor_set_name << ": Unable to parse." << std::endl; + return nullptr; + } + + std::unique_ptr<SimpleDescriptorDatabase> database{ + new SimpleDescriptorDatabase()}; + + for (int j = 0; j < file_descriptor_set.file_size(); j++) { + FileDescriptorProto previously_added_file_descriptor_proto; + if (database->FindFileByName(file_descriptor_set.file(j).name(), + &previously_added_file_descriptor_proto)) { + // already present - skip + continue; + } + if (!database->Add(file_descriptor_set.file(j))) { + return nullptr; + } + } + return database; +} + +} // namespace + + +bool CommandLineInterface::VerifyInputFilesInDescriptors( + DescriptorDatabase* database) { + for (const auto& input_file : input_files_) { + FileDescriptorProto file_descriptor; + if (!database->FindFileByName(input_file, &file_descriptor)) { + std::cerr << "Could not find file in descriptor database: " << input_file + << ": " << strerror(ENOENT) << std::endl; + return false; + } + + // Enforce --disallow_services. + if (disallow_services_ && file_descriptor.service_size() > 0) { + std::cerr << file_descriptor.name() + << ": This file contains services, but " + "--disallow_services was used." + << std::endl; + return false; + } + + } + return true; +} + +bool CommandLineInterface::ParseInputFiles( + DescriptorPool* descriptor_pool, DiskSourceTree* source_tree, + std::vector<const FileDescriptor*>* parsed_files) { + + if (!proto_path_.empty()) { + // Track unused imports in all source files that were loaded from the + // filesystem. We do not track unused imports for files loaded from + // descriptor sets as they may be programmatically generated in which case + // exerting this level of rigor is less desirable. We're also making the + // assumption that the initial parse of the proto from the filesystem + // was rigorous in checking unused imports and that the descriptor set + // being parsed was produced then and that it was subsequent mutations + // of that descriptor set that left unused imports. + // + // Note that relying on proto_path exclusively is limited in that we may + // be loading descriptors from both the filesystem and descriptor sets + // depending on the invocation. At least for invocations that are + // exclusively reading from descriptor sets, we can eliminate this failure + // condition. + for (const auto& input_file : input_files_) { + descriptor_pool->AddUnusedImportTrackFile(input_file); + } + } + + bool result = true; + // Parse each file. + for (const auto& input_file : input_files_) { + // Import the file. + const FileDescriptor* parsed_file = + descriptor_pool->FindFileByName(input_file); + if (parsed_file == NULL) { + result = false; + break; + } + parsed_files->push_back(parsed_file); + + // Enforce --disallow_services. + if (disallow_services_ && parsed_file->service_count() > 0) { + std::cerr << parsed_file->name() + << ": This file contains services, but " + "--disallow_services was used." + << std::endl; + result = false; + break; + } + + + // Enforce --direct_dependencies + if (direct_dependencies_explicitly_set_) { + bool indirect_imports = false; + for (int i = 0; i < parsed_file->dependency_count(); i++) { + if (direct_dependencies_.find(parsed_file->dependency(i)->name()) == + direct_dependencies_.end()) { + indirect_imports = true; + std::cerr << parsed_file->name() << ": " + << StringReplace(direct_dependencies_violation_msg_, "%s", + parsed_file->dependency(i)->name(), + true /* replace_all */) + << std::endl; + } + } + if (indirect_imports) { + result = false; + break; + } + } + } + descriptor_pool->ClearUnusedImportTrackFiles(); + return result; +} + +void CommandLineInterface::Clear() { + // Clear all members that are set by Run(). Note that we must not clear + // members which are set by other methods before Run() is called. + executable_name_.clear(); + proto_path_.clear(); + input_files_.clear(); + direct_dependencies_.clear(); + direct_dependencies_violation_msg_ = kDefaultDirectDependenciesViolationMsg; + output_directives_.clear(); + codec_type_.clear(); + descriptor_set_in_names_.clear(); + descriptor_set_out_name_.clear(); + dependency_out_name_.clear(); + + + mode_ = MODE_COMPILE; + print_mode_ = PRINT_NONE; + imports_in_descriptor_set_ = false; + source_info_in_descriptor_set_ = false; + disallow_services_ = false; + direct_dependencies_explicitly_set_ = false; + deterministic_output_ = false; +} + +bool CommandLineInterface::MakeProtoProtoPathRelative( + DiskSourceTree* source_tree, std::string* proto, + DescriptorDatabase* fallback_database) { + // If it's in the fallback db, don't report non-existent file errors. + FileDescriptorProto fallback_file; + bool in_fallback_database = + fallback_database != nullptr && + fallback_database->FindFileByName(*proto, &fallback_file); + + // If the input file path is not a physical file path, it must be a virtual + // path. + if (access(proto->c_str(), F_OK) < 0) { + std::string disk_file; + if (source_tree->VirtualFileToDiskFile(*proto, &disk_file) || + in_fallback_database) { + return true; + } else { + std::cerr << "Could not make proto path relative: " << *proto << ": " + << strerror(ENOENT) << std::endl; + return false; + } + } + + std::string virtual_file, shadowing_disk_file; + switch (source_tree->DiskFileToVirtualFile(*proto, &virtual_file, + &shadowing_disk_file)) { + case DiskSourceTree::SUCCESS: + *proto = virtual_file; + break; + case DiskSourceTree::SHADOWED: + std::cerr << *proto << ": Input is shadowed in the --proto_path by \"" + << shadowing_disk_file + << "\". Either use the latter file as your input or reorder " + "the --proto_path so that the former file's location " + "comes first." + << std::endl; + return false; + case DiskSourceTree::CANNOT_OPEN: { + if (in_fallback_database) { + return true; + } + std::string error_str = source_tree->GetLastErrorMessage().empty() + ? strerror(errno) + : source_tree->GetLastErrorMessage(); + std::cerr << "Could not map to virtual file: " << *proto << ": " + << error_str << std::endl; + return false; + } + case DiskSourceTree::NO_MAPPING: { + // Try to interpret the path as a virtual path. + std::string disk_file; + if (source_tree->VirtualFileToDiskFile(*proto, &disk_file) || + in_fallback_database) { + return true; + } else { + // The input file path can't be mapped to any --proto_path and it also + // can't be interpreted as a virtual path. + std::cerr + << *proto + << ": File does not reside within any path " + "specified using --proto_path (or -I). You must specify a " + "--proto_path which encompasses this file. Note that the " + "proto_path must be an exact prefix of the .proto file " + "names -- protoc is too dumb to figure out when two paths " + "(e.g. absolute and relative) are equivalent (it's harder " + "than you think)." + << std::endl; + return false; + } + } + } + return true; +} + +bool CommandLineInterface::MakeInputsBeProtoPathRelative( + DiskSourceTree* source_tree, DescriptorDatabase* fallback_database) { + for (auto& input_file : input_files_) { + if (!MakeProtoProtoPathRelative(source_tree, &input_file, + fallback_database)) { + return false; + } + } + + return true; +} + + +bool CommandLineInterface::ExpandArgumentFile( + const std::string& file, std::vector<std::string>* arguments) { + // The argument file is searched in the working directory only. We don't + // use the proto import path here. + std::ifstream file_stream(file.c_str()); + if (!file_stream.is_open()) { + return false; + } + std::string argument; + // We don't support any kind of shell expansion right now. + while (std::getline(file_stream, argument)) { + arguments->push_back(argument); + } + return true; +} + +CommandLineInterface::ParseArgumentStatus CommandLineInterface::ParseArguments( + int argc, const char* const argv[]) { + executable_name_ = argv[0]; + + std::vector<std::string> arguments; + for (int i = 1; i < argc; ++i) { + if (argv[i][0] == '@') { + if (!ExpandArgumentFile(argv[i] + 1, &arguments)) { + std::cerr << "Failed to open argument file: " << (argv[i] + 1) + << std::endl; + return PARSE_ARGUMENT_FAIL; + } + continue; + } + arguments.push_back(argv[i]); + } + + // if no arguments are given, show help + if (arguments.empty()) { + PrintHelpText(); + return PARSE_ARGUMENT_DONE_AND_EXIT; // Exit without running compiler. + } + + // Iterate through all arguments and parse them. + for (int i = 0; i < arguments.size(); ++i) { + std::string name, value; + + if (ParseArgument(arguments[i].c_str(), &name, &value)) { + // Returned true => Use the next argument as the flag value. + if (i + 1 == arguments.size() || arguments[i + 1][0] == '-') { + std::cerr << "Missing value for flag: " << name << std::endl; + if (name == "--decode") { + std::cerr << "To decode an unknown message, use --decode_raw." + << std::endl; + } + return PARSE_ARGUMENT_FAIL; + } else { + ++i; + value = arguments[i]; + } + } + + ParseArgumentStatus status = InterpretArgument(name, value); + if (status != PARSE_ARGUMENT_DONE_AND_CONTINUE) return status; + } + + // Make sure each plugin option has a matching plugin output. + bool foundUnknownPluginOption = false; + for (std::map<std::string, std::string>::const_iterator i = + plugin_parameters_.begin(); + i != plugin_parameters_.end(); ++i) { + if (plugins_.find(i->first) != plugins_.end()) { + continue; + } + bool foundImplicitPlugin = false; + for (std::vector<OutputDirective>::const_iterator j = + output_directives_.begin(); + j != output_directives_.end(); ++j) { + if (j->generator == NULL) { + std::string plugin_name = PluginName(plugin_prefix_, j->name); + if (plugin_name == i->first) { + foundImplicitPlugin = true; + break; + } + } + } + if (!foundImplicitPlugin) { + std::cerr << "Unknown flag: " + // strip prefix + "gen-" and add back "_opt" + << "--" + i->first.substr(plugin_prefix_.size() + 4) + "_opt" + << std::endl; + foundUnknownPluginOption = true; + } + } + if (foundUnknownPluginOption) { + return PARSE_ARGUMENT_FAIL; + } + + // The --proto_path & --descriptor_set_in flags both specify places to look + // for proto files. If neither were given, use the current working directory. + if (proto_path_.empty() && descriptor_set_in_names_.empty()) { + // Don't use make_pair as the old/default standard library on Solaris + // doesn't support it without explicit template parameters, which are + // incompatible with C++0x's make_pair. + proto_path_.push_back(std::pair<std::string, std::string>("", ".")); + } + + // Check error cases that span multiple flag values. + bool missing_proto_definitions = false; + switch (mode_) { + case MODE_COMPILE: + missing_proto_definitions = input_files_.empty(); + break; + case MODE_DECODE: + // Handle --decode_raw separately, since it requires that no proto + // definitions are specified. + if (codec_type_.empty()) { + if (!input_files_.empty() || !descriptor_set_in_names_.empty()) { + std::cerr + << "When using --decode_raw, no input files should be given." + << std::endl; + return PARSE_ARGUMENT_FAIL; + } + missing_proto_definitions = false; + break; // only for --decode_raw + } + // --decode (not raw) is handled the same way as the rest of the modes. + PROTOBUF_FALLTHROUGH_INTENDED; + case MODE_ENCODE: + case MODE_PRINT: + missing_proto_definitions = + input_files_.empty() && descriptor_set_in_names_.empty(); + break; + default: + GOOGLE_LOG(FATAL) << "Unexpected mode: " << mode_; + } + if (missing_proto_definitions) { + std::cerr << "Missing input file." << std::endl; + return PARSE_ARGUMENT_FAIL; + } + if (mode_ == MODE_COMPILE && output_directives_.empty() && + descriptor_set_out_name_.empty()) { + std::cerr << "Missing output directives." << std::endl; + return PARSE_ARGUMENT_FAIL; + } + if (mode_ != MODE_COMPILE && !dependency_out_name_.empty()) { + std::cerr << "Can only use --dependency_out=FILE when generating code." + << std::endl; + return PARSE_ARGUMENT_FAIL; + } + if (mode_ != MODE_ENCODE && deterministic_output_) { + std::cerr << "Can only use --deterministic_output with --encode." + << std::endl; + return PARSE_ARGUMENT_FAIL; + } + if (!dependency_out_name_.empty() && input_files_.size() > 1) { + std::cerr + << "Can only process one input file when using --dependency_out=FILE." + << std::endl; + return PARSE_ARGUMENT_FAIL; + } + if (imports_in_descriptor_set_ && descriptor_set_out_name_.empty()) { + std::cerr << "--include_imports only makes sense when combined with " + "--descriptor_set_out." + << std::endl; + } + if (source_info_in_descriptor_set_ && descriptor_set_out_name_.empty()) { + std::cerr << "--include_source_info only makes sense when combined with " + "--descriptor_set_out." + << std::endl; + } + + return PARSE_ARGUMENT_DONE_AND_CONTINUE; +} + +bool CommandLineInterface::ParseArgument(const char* arg, std::string* name, + std::string* value) { + bool parsed_value = false; + + if (arg[0] != '-') { + // Not a flag. + name->clear(); + parsed_value = true; + *value = arg; + } else if (arg[1] == '-') { + // Two dashes: Multi-character name, with '=' separating name and + // value. + const char* equals_pos = strchr(arg, '='); + if (equals_pos != NULL) { + *name = std::string(arg, equals_pos - arg); + *value = equals_pos + 1; + parsed_value = true; + } else { + *name = arg; + } + } else { + // One dash: One-character name, all subsequent characters are the + // value. + if (arg[1] == '\0') { + // arg is just "-". We treat this as an input file, except that at + // present this will just lead to a "file not found" error. + name->clear(); + *value = arg; + parsed_value = true; + } else { + *name = std::string(arg, 2); + *value = arg + 2; + parsed_value = !value->empty(); + } + } + + // Need to return true iff the next arg should be used as the value for this + // one, false otherwise. + + if (parsed_value) { + // We already parsed a value for this flag. + return false; + } + + if (*name == "-h" || *name == "--help" || *name == "--disallow_services" || + *name == "--include_imports" || *name == "--include_source_info" || + *name == "--version" || *name == "--decode_raw" || + *name == "--print_free_field_numbers" || + *name == "--experimental_allow_proto3_optional" || + *name == "--deterministic_output" || *name == "--fatal_warnings") { + // HACK: These are the only flags that don't take a value. + // They probably should not be hard-coded like this but for now it's + // not worth doing better. + return false; + } + + // Next argument is the flag value. + return true; +} + +CommandLineInterface::ParseArgumentStatus +CommandLineInterface::InterpretArgument(const std::string& name, + const std::string& value) { + if (name.empty()) { + // Not a flag. Just a filename. + if (value.empty()) { + std::cerr + << "You seem to have passed an empty string as one of the " + "arguments to " + << executable_name_ + << ". This is actually " + "sort of hard to do. Congrats. Unfortunately it is not valid " + "input so the program is going to die now." + << std::endl; + return PARSE_ARGUMENT_FAIL; + } + +#if defined(_WIN32) + // On Windows, the shell (typically cmd.exe) does not expand wildcards in + // file names (e.g. foo\*.proto), so we do it ourselves. + switch (google::protobuf::io::win32::ExpandWildcards( + value, + [this](const string& path) { this->input_files_.push_back(path); })) { + case google::protobuf::io::win32::ExpandWildcardsResult::kSuccess: + break; + case google::protobuf::io::win32::ExpandWildcardsResult:: + kErrorNoMatchingFile: + // Path does not exist, is not a file, or it's longer than MAX_PATH and + // long path handling is disabled. + std::cerr << "Invalid file name pattern or missing input file \"" + << value << "\"" << std::endl; + return PARSE_ARGUMENT_FAIL; + default: + std::cerr << "Cannot convert path \"" << value + << "\" to or from Windows style" << std::endl; + return PARSE_ARGUMENT_FAIL; + } +#else // not _WIN32 + // On other platforms than Windows (e.g. Linux, Mac OS) the shell (typically + // Bash) expands wildcards. + input_files_.push_back(value); +#endif // _WIN32 + + } else if (name == "-I" || name == "--proto_path") { + // Java's -classpath (and some other languages) delimits path components + // with colons. Let's accept that syntax too just to make things more + // intuitive. + std::vector<std::string> parts = Split( + value, CommandLineInterface::kPathSeparator, + true); + + for (int i = 0; i < parts.size(); i++) { + std::string virtual_path; + std::string disk_path; + + std::string::size_type equals_pos = parts[i].find_first_of('='); + if (equals_pos == std::string::npos) { + virtual_path = ""; + disk_path = parts[i]; + } else { + virtual_path = parts[i].substr(0, equals_pos); + disk_path = parts[i].substr(equals_pos + 1); + } + + if (disk_path.empty()) { + std::cerr + << "--proto_path passed empty directory name. (Use \".\" for " + "current directory.)" + << std::endl; + return PARSE_ARGUMENT_FAIL; + } + + // Make sure disk path exists, warn otherwise. + if (access(disk_path.c_str(), F_OK) < 0) { + // Try the original path; it may have just happened to have a '=' in it. + if (access(parts[i].c_str(), F_OK) < 0) { + std::cerr << disk_path << ": warning: directory does not exist." + << std::endl; + } else { + virtual_path = ""; + disk_path = parts[i]; + } + } + + // Don't use make_pair as the old/default standard library on Solaris + // doesn't support it without explicit template parameters, which are + // incompatible with C++0x's make_pair. + proto_path_.push_back( + std::pair<std::string, std::string>(virtual_path, disk_path)); + } + + } else if (name == "--direct_dependencies") { + if (direct_dependencies_explicitly_set_) { + std::cerr << name + << " may only be passed once. To specify multiple " + "direct dependencies, pass them all as a single " + "parameter separated by ':'." + << std::endl; + return PARSE_ARGUMENT_FAIL; + } + + direct_dependencies_explicitly_set_ = true; + std::vector<std::string> direct = + Split(value, ":", true); + GOOGLE_DCHECK(direct_dependencies_.empty()); + direct_dependencies_.insert(direct.begin(), direct.end()); + + } else if (name == "--direct_dependencies_violation_msg") { + direct_dependencies_violation_msg_ = value; + + } else if (name == "--descriptor_set_in") { + if (!descriptor_set_in_names_.empty()) { + std::cerr << name + << " may only be passed once. To specify multiple " + "descriptor sets, pass them all as a single " + "parameter separated by '" + << CommandLineInterface::kPathSeparator << "'." << std::endl; + return PARSE_ARGUMENT_FAIL; + } + if (value.empty()) { + std::cerr << name << " requires a non-empty value." << std::endl; + return PARSE_ARGUMENT_FAIL; + } + if (!dependency_out_name_.empty()) { + std::cerr << name << " cannot be used with --dependency_out." + << std::endl; + return PARSE_ARGUMENT_FAIL; + } + + descriptor_set_in_names_ = Split( + value, CommandLineInterface::kPathSeparator, + true); + + } else if (name == "-o" || name == "--descriptor_set_out") { + if (!descriptor_set_out_name_.empty()) { + std::cerr << name << " may only be passed once." << std::endl; + return PARSE_ARGUMENT_FAIL; + } + if (value.empty()) { + std::cerr << name << " requires a non-empty value." << std::endl; + return PARSE_ARGUMENT_FAIL; + } + if (mode_ != MODE_COMPILE) { + std::cerr + << "Cannot use --encode or --decode and generate descriptors at the " + "same time." + << std::endl; + return PARSE_ARGUMENT_FAIL; + } + descriptor_set_out_name_ = value; + + } else if (name == "--dependency_out") { + if (!dependency_out_name_.empty()) { + std::cerr << name << " may only be passed once." << std::endl; + return PARSE_ARGUMENT_FAIL; + } + if (value.empty()) { + std::cerr << name << " requires a non-empty value." << std::endl; + return PARSE_ARGUMENT_FAIL; + } + if (!descriptor_set_in_names_.empty()) { + std::cerr << name << " cannot be used with --descriptor_set_in." + << std::endl; + return PARSE_ARGUMENT_FAIL; + } + dependency_out_name_ = value; + + } else if (name == "--include_imports") { + if (imports_in_descriptor_set_) { + std::cerr << name << " may only be passed once." << std::endl; + return PARSE_ARGUMENT_FAIL; + } + imports_in_descriptor_set_ = true; + + } else if (name == "--include_source_info") { + if (source_info_in_descriptor_set_) { + std::cerr << name << " may only be passed once." << std::endl; + return PARSE_ARGUMENT_FAIL; + } + source_info_in_descriptor_set_ = true; + + } else if (name == "-h" || name == "--help") { + PrintHelpText(); + return PARSE_ARGUMENT_DONE_AND_EXIT; // Exit without running compiler. + + } else if (name == "--version") { + if (!version_info_.empty()) { + std::cout << version_info_ << std::endl; + } + std::cout << "libprotoc " << internal::VersionString(PROTOBUF_VERSION) + << PROTOBUF_VERSION_SUFFIX << std::endl; + return PARSE_ARGUMENT_DONE_AND_EXIT; // Exit without running compiler. + + } else if (name == "--disallow_services") { + disallow_services_ = true; + + + } else if (name == "--experimental_allow_proto3_optional") { + // Flag is no longer observed, but we allow it for backward compat. + } else if (name == "--encode" || name == "--decode" || + name == "--decode_raw") { + if (mode_ != MODE_COMPILE) { + std::cerr << "Only one of --encode and --decode can be specified." + << std::endl; + return PARSE_ARGUMENT_FAIL; + } + if (!output_directives_.empty() || !descriptor_set_out_name_.empty()) { + std::cerr << "Cannot use " << name + << " and generate code or descriptors at the same time." + << std::endl; + return PARSE_ARGUMENT_FAIL; + } + + mode_ = (name == "--encode") ? MODE_ENCODE : MODE_DECODE; + + if (value.empty() && name != "--decode_raw") { + std::cerr << "Type name for " << name << " cannot be blank." << std::endl; + if (name == "--decode") { + std::cerr << "To decode an unknown message, use --decode_raw." + << std::endl; + } + return PARSE_ARGUMENT_FAIL; + } else if (!value.empty() && name == "--decode_raw") { + std::cerr << "--decode_raw does not take a parameter." << std::endl; + return PARSE_ARGUMENT_FAIL; + } + + codec_type_ = value; + + } else if (name == "--deterministic_output") { + deterministic_output_ = true; + + } else if (name == "--error_format") { + if (value == "gcc") { + error_format_ = ERROR_FORMAT_GCC; + } else if (value == "msvs") { + error_format_ = ERROR_FORMAT_MSVS; + } else { + std::cerr << "Unknown error format: " << value << std::endl; + return PARSE_ARGUMENT_FAIL; + } + + } else if (name == "--fatal_warnings") { + if (fatal_warnings_) { + std::cerr << name << " may only be passed once." << std::endl; + return PARSE_ARGUMENT_FAIL; + } + fatal_warnings_ = true; + } else if (name == "--plugin") { + if (plugin_prefix_.empty()) { + std::cerr << "This compiler does not support plugins." << std::endl; + return PARSE_ARGUMENT_FAIL; + } + + std::string plugin_name; + std::string path; + + std::string::size_type equals_pos = value.find_first_of('='); + if (equals_pos == std::string::npos) { + // Use the basename of the file. + std::string::size_type slash_pos = value.find_last_of('/'); + if (slash_pos == std::string::npos) { + plugin_name = value; + } else { + plugin_name = value.substr(slash_pos + 1); + } + path = value; + } else { + plugin_name = value.substr(0, equals_pos); + path = value.substr(equals_pos + 1); + } + + plugins_[plugin_name] = path; + + } else if (name == "--print_free_field_numbers") { + if (mode_ != MODE_COMPILE) { + std::cerr << "Cannot use " << name + << " and use --encode, --decode or print " + << "other info at the same time." << std::endl; + return PARSE_ARGUMENT_FAIL; + } + if (!output_directives_.empty() || !descriptor_set_out_name_.empty()) { + std::cerr << "Cannot use " << name + << " and generate code or descriptors at the same time." + << std::endl; + return PARSE_ARGUMENT_FAIL; + } + mode_ = MODE_PRINT; + print_mode_ = PRINT_FREE_FIELDS; + } else { + // Some other flag. Look it up in the generators list. + const GeneratorInfo* generator_info = + FindOrNull(generators_by_flag_name_, name); + if (generator_info == NULL && + (plugin_prefix_.empty() || !HasSuffixString(name, "_out"))) { + // Check if it's a generator option flag. + generator_info = FindOrNull(generators_by_option_name_, name); + if (generator_info != NULL) { + std::string* parameters = + &generator_parameters_[generator_info->flag_name]; + if (!parameters->empty()) { + parameters->append(","); + } + parameters->append(value); + } else if (HasPrefixString(name, "--") && HasSuffixString(name, "_opt")) { + std::string* parameters = + &plugin_parameters_[PluginName(plugin_prefix_, name)]; + if (!parameters->empty()) { + parameters->append(","); + } + parameters->append(value); + } else { + std::cerr << "Unknown flag: " << name << std::endl; + return PARSE_ARGUMENT_FAIL; + } + } else { + // It's an output flag. Add it to the output directives. + if (mode_ != MODE_COMPILE) { + std::cerr << "Cannot use --encode, --decode or print .proto info and " + "generate code at the same time." + << std::endl; + return PARSE_ARGUMENT_FAIL; + } + + OutputDirective directive; + directive.name = name; + if (generator_info == NULL) { + directive.generator = NULL; + } else { + directive.generator = generator_info->generator; + } + + // Split value at ':' to separate the generator parameter from the + // filename. However, avoid doing this if the colon is part of a valid + // Windows-style absolute path. + std::string::size_type colon_pos = value.find_first_of(':'); + if (colon_pos == std::string::npos || IsWindowsAbsolutePath(value)) { + directive.output_location = value; + } else { + directive.parameter = value.substr(0, colon_pos); + directive.output_location = value.substr(colon_pos + 1); + } + + output_directives_.push_back(directive); + } + } + + return PARSE_ARGUMENT_DONE_AND_CONTINUE; +} + +void CommandLineInterface::PrintHelpText() { + // Sorry for indentation here; line wrapping would be uglier. + std::cout << "Usage: " << executable_name_ << " [OPTION] PROTO_FILES"; + std::cout << R"( +Parse PROTO_FILES and generate output based on the options given: + -IPATH, --proto_path=PATH Specify the directory in which to search for + imports. May be specified multiple times; + directories will be searched in order. If not + given, the current working directory is used. + If not found in any of the these directories, + the --descriptor_set_in descriptors will be + checked for required proto file. + --version Show version info and exit. + -h, --help Show this text and exit. + --encode=MESSAGE_TYPE Read a text-format message of the given type + from standard input and write it in binary + to standard output. The message type must + be defined in PROTO_FILES or their imports. + --deterministic_output When using --encode, ensure map fields are + deterministically ordered. Note that this order + is not canonical, and changes across builds or + releases of protoc. + --decode=MESSAGE_TYPE Read a binary message of the given type from + standard input and write it in text format + to standard output. The message type must + be defined in PROTO_FILES or their imports. + --decode_raw Read an arbitrary protocol message from + standard input and write the raw tag/value + pairs in text format to standard output. No + PROTO_FILES should be given when using this + flag. + --descriptor_set_in=FILES Specifies a delimited list of FILES + each containing a FileDescriptorSet (a + protocol buffer defined in descriptor.proto). + The FileDescriptor for each of the PROTO_FILES + provided will be loaded from these + FileDescriptorSets. If a FileDescriptor + appears multiple times, the first occurrence + will be used. + -oFILE, Writes a FileDescriptorSet (a protocol buffer, + --descriptor_set_out=FILE defined in descriptor.proto) containing all of + the input files to FILE. + --include_imports When using --descriptor_set_out, also include + all dependencies of the input files in the + set, so that the set is self-contained. + --include_source_info When using --descriptor_set_out, do not strip + SourceCodeInfo from the FileDescriptorProto. + This results in vastly larger descriptors that + include information about the original + location of each decl in the source file as + well as surrounding comments. + --dependency_out=FILE Write a dependency output file in the format + expected by make. This writes the transitive + set of input file paths to FILE + --error_format=FORMAT Set the format in which to print errors. + FORMAT may be 'gcc' (the default) or 'msvs' + (Microsoft Visual Studio format). + --fatal_warnings Make warnings be fatal (similar to -Werr in + gcc). This flag will make protoc return + with a non-zero exit code if any warnings + are generated. + --print_free_field_numbers Print the free field numbers of the messages + defined in the given proto files. Groups share + the same field number space with the parent + message. Extension ranges are counted as + occupied fields numbers.)"; + if (!plugin_prefix_.empty()) { + std::cout << R"( + --plugin=EXECUTABLE Specifies a plugin executable to use. + Normally, protoc searches the PATH for + plugins, but you may specify additional + executables not in the path using this flag. + Additionally, EXECUTABLE may be of the form + NAME=PATH, in which case the given plugin name + is mapped to the given executable even if + the executable's own name differs.)"; + } + + for (GeneratorMap::iterator iter = generators_by_flag_name_.begin(); + iter != generators_by_flag_name_.end(); ++iter) { + // FIXME(kenton): If the text is long enough it will wrap, which is ugly, + // but fixing this nicely (e.g. splitting on spaces) is probably more + // trouble than it's worth. + std::cout << std::endl + << " " << iter->first << "=OUT_DIR " + << std::string(19 - iter->first.size(), + ' ') // Spaces for alignment. + << iter->second.help_text; + } + std::cout << R"( + @<filename> Read options and filenames from file. If a + relative file path is specified, the file + will be searched in the working directory. + The --proto_path option will not affect how + this argument file is searched. Content of + the file will be expanded in the position of + @<filename> as in the argument list. Note + that shell expansion is not applied to the + content of the file (i.e., you cannot use + quotes, wildcards, escapes, commands, etc.). + Each line corresponds to a single argument, + even if it contains spaces.)"; + std::cout << std::endl; +} + +bool CommandLineInterface::EnforceProto3OptionalSupport( + const std::string& codegen_name, uint64_t supported_features, + const std::vector<const FileDescriptor*>& parsed_files) const { + bool supports_proto3_optional = + supported_features & CodeGenerator::FEATURE_PROTO3_OPTIONAL; + if (!supports_proto3_optional) { + for (const auto fd : parsed_files) { + if (ContainsProto3Optional(fd)) { + std::cerr << fd->name() + << ": is a proto3 file that contains optional fields, but " + "code generator " + << codegen_name + << " hasn't been updated to support optional fields in " + "proto3. Please ask the owner of this code generator to " + "support proto3 optional."; + return false; + } + } + } + return true; +} + +bool CommandLineInterface::GenerateOutput( + const std::vector<const FileDescriptor*>& parsed_files, + const OutputDirective& output_directive, + GeneratorContext* generator_context) { + // Call the generator. + std::string error; + if (output_directive.generator == NULL) { + // This is a plugin. + GOOGLE_CHECK(HasPrefixString(output_directive.name, "--") && + HasSuffixString(output_directive.name, "_out")) + << "Bad name for plugin generator: " << output_directive.name; + + std::string plugin_name = PluginName(plugin_prefix_, output_directive.name); + std::string parameters = output_directive.parameter; + if (!plugin_parameters_[plugin_name].empty()) { + if (!parameters.empty()) { + parameters.append(","); + } + parameters.append(plugin_parameters_[plugin_name]); + } + if (!GeneratePluginOutput(parsed_files, plugin_name, parameters, + generator_context, &error)) { + std::cerr << output_directive.name << ": " << error << std::endl; + return false; + } + } else { + // Regular generator. + std::string parameters = output_directive.parameter; + if (!generator_parameters_[output_directive.name].empty()) { + if (!parameters.empty()) { + parameters.append(","); + } + parameters.append(generator_parameters_[output_directive.name]); + } + if (!EnforceProto3OptionalSupport( + output_directive.name, + output_directive.generator->GetSupportedFeatures(), parsed_files)) { + return false; + } + + if (!output_directive.generator->GenerateAll(parsed_files, parameters, + generator_context, &error)) { + // Generator returned an error. + std::cerr << output_directive.name << ": " << error << std::endl; + return false; + } + } + + return true; +} + +bool CommandLineInterface::GenerateDependencyManifestFile( + const std::vector<const FileDescriptor*>& parsed_files, + const GeneratorContextMap& output_directories, + DiskSourceTree* source_tree) { + FileDescriptorSet file_set; + + std::set<const FileDescriptor*> already_seen; + for (int i = 0; i < parsed_files.size(); i++) { + GetTransitiveDependencies(parsed_files[i], false, false, &already_seen, + file_set.mutable_file()); + } + + std::vector<std::string> output_filenames; + for (const auto& pair : output_directories) { + const std::string& location = pair.first; + GeneratorContextImpl* directory = pair.second.get(); + std::vector<std::string> relative_output_filenames; + directory->GetOutputFilenames(&relative_output_filenames); + for (int i = 0; i < relative_output_filenames.size(); i++) { + std::string output_filename = location + relative_output_filenames[i]; + if (output_filename.compare(0, 2, "./") == 0) { + output_filename = output_filename.substr(2); + } + output_filenames.push_back(output_filename); + } + } + + int fd; + do { + fd = open(dependency_out_name_.c_str(), + O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666); + } while (fd < 0 && errno == EINTR); + + if (fd < 0) { + perror(dependency_out_name_.c_str()); + return false; + } + + io::FileOutputStream out(fd); + io::Printer printer(&out, '$'); + + for (int i = 0; i < output_filenames.size(); i++) { + printer.Print(output_filenames[i].c_str()); + if (i == output_filenames.size() - 1) { + printer.Print(":"); + } else { + printer.Print(" \\\n"); + } + } + + for (int i = 0; i < file_set.file_size(); i++) { + const FileDescriptorProto& file = file_set.file(i); + const std::string& virtual_file = file.name(); + std::string disk_file; + if (source_tree && + source_tree->VirtualFileToDiskFile(virtual_file, &disk_file)) { + printer.Print(" $disk_file$", "disk_file", disk_file); + if (i < file_set.file_size() - 1) printer.Print("\\\n"); + } else { + std::cerr << "Unable to identify path for file " << virtual_file + << std::endl; + return false; + } + } + + return true; +} + +bool CommandLineInterface::GeneratePluginOutput( + const std::vector<const FileDescriptor*>& parsed_files, + const std::string& plugin_name, const std::string& parameter, + GeneratorContext* generator_context, std::string* error) { + CodeGeneratorRequest request; + CodeGeneratorResponse response; + std::string processed_parameter = parameter; + + + // Build the request. + if (!processed_parameter.empty()) { + request.set_parameter(processed_parameter); + } + + + std::set<const FileDescriptor*> already_seen; + for (int i = 0; i < parsed_files.size(); i++) { + request.add_file_to_generate(parsed_files[i]->name()); + GetTransitiveDependencies(parsed_files[i], + true, // Include json_name for plugins. + true, // Include source code info. + &already_seen, request.mutable_proto_file()); + } + + google::protobuf::compiler::Version* version = + request.mutable_compiler_version(); + version->set_major(PROTOBUF_VERSION / 1000000); + version->set_minor(PROTOBUF_VERSION / 1000 % 1000); + version->set_patch(PROTOBUF_VERSION % 1000); + version->set_suffix(PROTOBUF_VERSION_SUFFIX); + + // Invoke the plugin. + Subprocess subprocess; + + if (plugins_.count(plugin_name) > 0) { + subprocess.Start(plugins_[plugin_name], Subprocess::EXACT_NAME); + } else { + subprocess.Start(plugin_name, Subprocess::SEARCH_PATH); + } + + std::string communicate_error; + if (!subprocess.Communicate(request, &response, &communicate_error)) { + *error = strings::Substitute("$0: $1", plugin_name, communicate_error); + return false; + } + + // Write the files. We do this even if there was a generator error in order + // to match the behavior of a compiled-in generator. + std::unique_ptr<io::ZeroCopyOutputStream> current_output; + for (int i = 0; i < response.file_size(); i++) { + const CodeGeneratorResponse::File& output_file = response.file(i); + + if (!output_file.insertion_point().empty()) { + std::string filename = output_file.name(); + // Open a file for insert. + // We reset current_output to NULL first so that the old file is closed + // before the new one is opened. + current_output.reset(); + current_output.reset( + generator_context->OpenForInsertWithGeneratedCodeInfo( + filename, output_file.insertion_point(), + output_file.generated_code_info())); + } else if (!output_file.name().empty()) { + // Starting a new file. Open it. + // We reset current_output to NULL first so that the old file is closed + // before the new one is opened. + current_output.reset(); + current_output.reset(generator_context->Open(output_file.name())); + } else if (current_output == NULL) { + *error = strings::Substitute( + "$0: First file chunk returned by plugin did not specify a file " + "name.", + plugin_name); + return false; + } + + // Use CodedOutputStream for convenience; otherwise we'd need to provide + // our own buffer-copying loop. + io::CodedOutputStream writer(current_output.get()); + writer.WriteString(output_file.content()); + } + + // Check for errors. + if (!response.error().empty()) { + // Generator returned an error. + *error = response.error(); + return false; + } else if (!EnforceProto3OptionalSupport( + plugin_name, response.supported_features(), parsed_files)) { + return false; + } + + return true; +} + +bool CommandLineInterface::EncodeOrDecode(const DescriptorPool* pool) { + // Look up the type. + const Descriptor* type = pool->FindMessageTypeByName(codec_type_); + if (type == NULL) { + std::cerr << "Type not defined: " << codec_type_ << std::endl; + return false; + } + + DynamicMessageFactory dynamic_factory(pool); + std::unique_ptr<Message> message(dynamic_factory.GetPrototype(type)->New()); + + if (mode_ == MODE_ENCODE) { + SetFdToTextMode(STDIN_FILENO); + SetFdToBinaryMode(STDOUT_FILENO); + } else { + SetFdToBinaryMode(STDIN_FILENO); + SetFdToTextMode(STDOUT_FILENO); + } + + io::FileInputStream in(STDIN_FILENO); + io::FileOutputStream out(STDOUT_FILENO); + + if (mode_ == MODE_ENCODE) { + // Input is text. + ErrorPrinter error_collector(error_format_); + TextFormat::Parser parser; + parser.RecordErrorsTo(&error_collector); + parser.AllowPartialMessage(true); + + if (!parser.Parse(&in, message.get())) { + std::cerr << "Failed to parse input." << std::endl; + return false; + } + } else { + // Input is binary. + if (!message->ParsePartialFromZeroCopyStream(&in)) { + std::cerr << "Failed to parse input." << std::endl; + return false; + } + } + + if (!message->IsInitialized()) { + std::cerr << "warning: Input message is missing required fields: " + << message->InitializationErrorString() << std::endl; + } + + if (mode_ == MODE_ENCODE) { + // Output is binary. + io::CodedOutputStream coded_out(&out); + coded_out.SetSerializationDeterministic(deterministic_output_); + if (!message->SerializePartialToCodedStream(&coded_out)) { + std::cerr << "output: I/O error." << std::endl; + return false; + } + } else { + // Output is text. + if (!TextFormat::Print(*message, &out)) { + std::cerr << "output: I/O error." << std::endl; + return false; + } + } + + return true; +} + +bool CommandLineInterface::WriteDescriptorSet( + const std::vector<const FileDescriptor*>& parsed_files) { + FileDescriptorSet file_set; + + std::set<const FileDescriptor*> already_seen; + if (!imports_in_descriptor_set_) { + // Since we don't want to output transitive dependencies, but we do want + // things to be in dependency order, add all dependencies that aren't in + // parsed_files to already_seen. This will short circuit the recursion + // in GetTransitiveDependencies. + std::set<const FileDescriptor*> to_output; + to_output.insert(parsed_files.begin(), parsed_files.end()); + for (int i = 0; i < parsed_files.size(); i++) { + const FileDescriptor* file = parsed_files[i]; + for (int j = 0; j < file->dependency_count(); j++) { + const FileDescriptor* dependency = file->dependency(j); + // if the dependency isn't in parsed files, mark it as already seen + if (to_output.find(dependency) == to_output.end()) { + already_seen.insert(dependency); + } + } + } + } + for (int i = 0; i < parsed_files.size(); i++) { + GetTransitiveDependencies(parsed_files[i], + true, // Include json_name + source_info_in_descriptor_set_, &already_seen, + file_set.mutable_file()); + } + + int fd; + do { + fd = open(descriptor_set_out_name_.c_str(), + O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666); + } while (fd < 0 && errno == EINTR); + + if (fd < 0) { + perror(descriptor_set_out_name_.c_str()); + return false; + } + + io::FileOutputStream out(fd); + + { + io::CodedOutputStream coded_out(&out); + // Determinism is useful here because build outputs are sometimes checked + // into version control. + coded_out.SetSerializationDeterministic(true); + if (!file_set.SerializeToCodedStream(&coded_out)) { + std::cerr << descriptor_set_out_name_ << ": " << strerror(out.GetErrno()) + << std::endl; + out.Close(); + return false; + } + } + + if (!out.Close()) { + std::cerr << descriptor_set_out_name_ << ": " << strerror(out.GetErrno()) + << std::endl; + return false; + } + + return true; +} + +void CommandLineInterface::GetTransitiveDependencies( + const FileDescriptor* file, bool include_json_name, + bool include_source_code_info, + std::set<const FileDescriptor*>* already_seen, + RepeatedPtrField<FileDescriptorProto>* output) { + if (!already_seen->insert(file).second) { + // Already saw this file. Skip. + return; + } + + // Add all dependencies. + for (int i = 0; i < file->dependency_count(); i++) { + GetTransitiveDependencies(file->dependency(i), include_json_name, + include_source_code_info, already_seen, output); + } + + // Add this file. + FileDescriptorProto* new_descriptor = output->Add(); + file->CopyTo(new_descriptor); + if (include_json_name) { + file->CopyJsonNameTo(new_descriptor); + } + if (include_source_code_info) { + file->CopySourceCodeInfoTo(new_descriptor); + } +} + +namespace { + +// Utility function for PrintFreeFieldNumbers. +// Stores occupied ranges into the ranges parameter, and next level of sub +// message types into the nested_messages parameter. The FieldRange is left +// inclusive, right exclusive. i.e. [a, b). +// +// Nested Messages: +// Note that it only stores the nested message type, iff the nested type is +// either a direct child of the given descriptor, or the nested type is a +// descendant of the given descriptor and all the nodes between the +// nested type and the given descriptor are group types. e.g. +// +// message Foo { +// message Bar { +// message NestedBar {} +// } +// group Baz = 1 { +// group NestedBazGroup = 2 { +// message Quz { +// message NestedQuz {} +// } +// } +// message NestedBaz {} +// } +// } +// +// In this case, Bar, Quz and NestedBaz will be added into the nested types. +// Since free field numbers of group types will not be printed, this makes sure +// the nested message types in groups will not be dropped. The nested_messages +// parameter will contain the direct children (when groups are ignored in the +// tree) of the given descriptor for the caller to traverse. The declaration +// order of the nested messages is also preserved. +typedef std::pair<int, int> FieldRange; +void GatherOccupiedFieldRanges( + const Descriptor* descriptor, std::set<FieldRange>* ranges, + std::vector<const Descriptor*>* nested_messages) { + std::set<const Descriptor*> groups; + for (int i = 0; i < descriptor->field_count(); ++i) { + const FieldDescriptor* fd = descriptor->field(i); + ranges->insert(FieldRange(fd->number(), fd->number() + 1)); + if (fd->type() == FieldDescriptor::TYPE_GROUP) { + groups.insert(fd->message_type()); + } + } + for (int i = 0; i < descriptor->extension_range_count(); ++i) { + ranges->insert(FieldRange(descriptor->extension_range(i)->start, + descriptor->extension_range(i)->end)); + } + for (int i = 0; i < descriptor->reserved_range_count(); ++i) { + ranges->insert(FieldRange(descriptor->reserved_range(i)->start, + descriptor->reserved_range(i)->end)); + } + // Handle the nested messages/groups in declaration order to make it + // post-order strict. + for (int i = 0; i < descriptor->nested_type_count(); ++i) { + const Descriptor* nested_desc = descriptor->nested_type(i); + if (groups.find(nested_desc) != groups.end()) { + GatherOccupiedFieldRanges(nested_desc, ranges, nested_messages); + } else { + nested_messages->push_back(nested_desc); + } + } +} + +// Utility function for PrintFreeFieldNumbers. +// Actually prints the formatted free field numbers for given message name and +// occupied ranges. +void FormatFreeFieldNumbers(const std::string& name, + const std::set<FieldRange>& ranges) { + std::string output; + StringAppendF(&output, "%-35s free:", name.c_str()); + int next_free_number = 1; + for (std::set<FieldRange>::const_iterator i = ranges.begin(); + i != ranges.end(); ++i) { + // This happens when groups re-use parent field numbers, in which + // case we skip the FieldRange entirely. + if (next_free_number >= i->second) continue; + + if (next_free_number < i->first) { + if (next_free_number + 1 == i->first) { + // Singleton + StringAppendF(&output, " %d", next_free_number); + } else { + // Range + StringAppendF(&output, " %d-%d", next_free_number, i->first - 1); + } + } + next_free_number = i->second; + } + if (next_free_number <= FieldDescriptor::kMaxNumber) { + StringAppendF(&output, " %d-INF", next_free_number); + } + std::cout << output << std::endl; +} + +} // namespace + +void CommandLineInterface::PrintFreeFieldNumbers(const Descriptor* descriptor) { + std::set<FieldRange> ranges; + std::vector<const Descriptor*> nested_messages; + GatherOccupiedFieldRanges(descriptor, &ranges, &nested_messages); + + for (int i = 0; i < nested_messages.size(); ++i) { + PrintFreeFieldNumbers(nested_messages[i]); + } + FormatFreeFieldNumbers(descriptor->full_name(), ranges); +} + + +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/command_line_interface.h b/NorthstarDedicatedTest/include/protobuf/compiler/command_line_interface.h new file mode 100644 index 00000000..4d37bd6d --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/command_line_interface.h @@ -0,0 +1,462 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// Implements the Protocol Compiler front-end such that it may be reused by +// custom compilers written to support other languages. + +#ifndef GOOGLE_PROTOBUF_COMPILER_COMMAND_LINE_INTERFACE_H__ +#define GOOGLE_PROTOBUF_COMPILER_COMMAND_LINE_INTERFACE_H__ + +#include <cstdint> +#include <map> +#include <memory> +#include <set> +#include <string> +#include <unordered_map> +#include <unordered_set> +#include <utility> +#include <vector> + +#include <stubs/common.h> +#include <port_def.inc> + +namespace google { +namespace protobuf { + +class Descriptor; // descriptor.h +class DescriptorDatabase; // descriptor_database.h +class DescriptorPool; // descriptor.h +class FileDescriptor; // descriptor.h +class FileDescriptorSet; // descriptor.h +class FileDescriptorProto; // descriptor.pb.h +template <typename T> +class RepeatedPtrField; // repeated_field.h +class SimpleDescriptorDatabase; // descriptor_database.h + +namespace compiler { + +class CodeGenerator; // code_generator.h +class GeneratorContext; // code_generator.h +class DiskSourceTree; // importer.h + +// This class implements the command-line interface to the protocol compiler. +// It is designed to make it very easy to create a custom protocol compiler +// supporting the languages of your choice. For example, if you wanted to +// create a custom protocol compiler binary which includes both the regular +// C++ support plus support for your own custom output "Foo", you would +// write a class "FooGenerator" which implements the CodeGenerator interface, +// then write a main() procedure like this: +// +// int main(int argc, char* argv[]) { +// google::protobuf::compiler::CommandLineInterface cli; +// +// // Support generation of C++ source and headers. +// google::protobuf::compiler::cpp::CppGenerator cpp_generator; +// cli.RegisterGenerator("--cpp_out", &cpp_generator, +// "Generate C++ source and header."); +// +// // Support generation of Foo code. +// FooGenerator foo_generator; +// cli.RegisterGenerator("--foo_out", &foo_generator, +// "Generate Foo file."); +// +// return cli.Run(argc, argv); +// } +// +// The compiler is invoked with syntax like: +// protoc --cpp_out=outdir --foo_out=outdir --proto_path=src src/foo.proto +// +// The .proto file to compile can be specified on the command line using either +// its physical file path, or a virtual path relative to a directory specified +// in --proto_path. For example, for src/foo.proto, the following two protoc +// invocations work the same way: +// 1. protoc --proto_path=src src/foo.proto (physical file path) +// 2. protoc --proto_path=src foo.proto (virtual path relative to src) +// +// If a file path can be interpreted both as a physical file path and as a +// relative virtual path, the physical file path takes precedence. +// +// For a full description of the command-line syntax, invoke it with --help. +class PROTOC_EXPORT CommandLineInterface { + public: + static const char* const kPathSeparator; + + CommandLineInterface(); + ~CommandLineInterface(); + + // Register a code generator for a language. + // + // Parameters: + // * flag_name: The command-line flag used to specify an output file of + // this type. The name must start with a '-'. If the name is longer + // than one letter, it must start with two '-'s. + // * generator: The CodeGenerator which will be called to generate files + // of this type. + // * help_text: Text describing this flag in the --help output. + // + // Some generators accept extra parameters. You can specify this parameter + // on the command-line by placing it before the output directory, separated + // by a colon: + // protoc --foo_out=enable_bar:outdir + // The text before the colon is passed to CodeGenerator::Generate() as the + // "parameter". + void RegisterGenerator(const std::string& flag_name, CodeGenerator* generator, + const std::string& help_text); + + // Register a code generator for a language. + // Besides flag_name you can specify another option_flag_name that could be + // used to pass extra parameters to the registered code generator. + // Suppose you have registered a generator by calling: + // command_line_interface.RegisterGenerator("--foo_out", "--foo_opt", ...) + // Then you could invoke the compiler with a command like: + // protoc --foo_out=enable_bar:outdir --foo_opt=enable_baz + // This will pass "enable_bar,enable_baz" as the parameter to the generator. + void RegisterGenerator(const std::string& flag_name, + const std::string& option_flag_name, + CodeGenerator* generator, + const std::string& help_text); + + // Enables "plugins". In this mode, if a command-line flag ends with "_out" + // but does not match any registered generator, the compiler will attempt to + // find a "plugin" to implement the generator. Plugins are just executables. + // They should live somewhere in the PATH. + // + // The compiler determines the executable name to search for by concatenating + // exe_name_prefix with the unrecognized flag name, removing "_out". So, for + // example, if exe_name_prefix is "protoc-" and you pass the flag --foo_out, + // the compiler will try to run the program "protoc-gen-foo". + // + // The plugin program should implement the following usage: + // plugin [--out=OUTDIR] [--parameter=PARAMETER] PROTO_FILES < DESCRIPTORS + // --out indicates the output directory (as passed to the --foo_out + // parameter); if omitted, the current directory should be used. --parameter + // gives the generator parameter, if any was provided (see below). The + // PROTO_FILES list the .proto files which were given on the compiler + // command-line; these are the files for which the plugin is expected to + // generate output code. Finally, DESCRIPTORS is an encoded FileDescriptorSet + // (as defined in descriptor.proto). This is piped to the plugin's stdin. + // The set will include descriptors for all the files listed in PROTO_FILES as + // well as all files that they import. The plugin MUST NOT attempt to read + // the PROTO_FILES directly -- it must use the FileDescriptorSet. + // + // The plugin should generate whatever files are necessary, as code generators + // normally do. It should write the names of all files it generates to + // stdout. The names should be relative to the output directory, NOT absolute + // names or relative to the current directory. If any errors occur, error + // messages should be written to stderr. If an error is fatal, the plugin + // should exit with a non-zero exit code. + // + // Plugins can have generator parameters similar to normal built-in + // generators. Extra generator parameters can be passed in via a matching + // "_opt" parameter. For example: + // protoc --plug_out=enable_bar:outdir --plug_opt=enable_baz + // This will pass "enable_bar,enable_baz" as the parameter to the plugin. + // + void AllowPlugins(const std::string& exe_name_prefix); + + // Run the Protocol Compiler with the given command-line parameters. + // Returns the error code which should be returned by main(). + // + // It may not be safe to call Run() in a multi-threaded environment because + // it calls strerror(). I'm not sure why you'd want to do this anyway. + int Run(int argc, const char* const argv[]); + + // DEPRECATED. Calling this method has no effect. Protocol compiler now + // always try to find the .proto file relative to the current directory + // first and if the file is not found, it will then treat the input path + // as a virtual path. + void SetInputsAreProtoPathRelative(bool /* enable */) {} + + // Provides some text which will be printed when the --version flag is + // used. The version of libprotoc will also be printed on the next line + // after this text. + void SetVersionInfo(const std::string& text) { version_info_ = text; } + + + private: + // ----------------------------------------------------------------- + + class ErrorPrinter; + class GeneratorContextImpl; + class MemoryOutputStream; + typedef std::unordered_map<std::string, std::unique_ptr<GeneratorContextImpl>> + GeneratorContextMap; + + // Clear state from previous Run(). + void Clear(); + + // Remaps the proto file so that it is relative to one of the directories + // in proto_path_. Returns false if an error occurred. + bool MakeProtoProtoPathRelative(DiskSourceTree* source_tree, + std::string* proto, + DescriptorDatabase* fallback_database); + + // Remaps each file in input_files_ so that it is relative to one of the + // directories in proto_path_. Returns false if an error occurred. + bool MakeInputsBeProtoPathRelative(DiskSourceTree* source_tree, + DescriptorDatabase* fallback_database); + + // Fails if these files use proto3 optional and the code generator doesn't + // support it. This is a permanent check. + bool EnforceProto3OptionalSupport( + const std::string& codegen_name, uint64_t supported_features, + const std::vector<const FileDescriptor*>& parsed_files) const; + + + // Return status for ParseArguments() and InterpretArgument(). + enum ParseArgumentStatus { + PARSE_ARGUMENT_DONE_AND_CONTINUE, + PARSE_ARGUMENT_DONE_AND_EXIT, + PARSE_ARGUMENT_FAIL + }; + + // Parse all command-line arguments. + ParseArgumentStatus ParseArguments(int argc, const char* const argv[]); + + // Read an argument file and append the file's content to the list of + // arguments. Return false if the file cannot be read. + bool ExpandArgumentFile(const std::string& file, + std::vector<std::string>* arguments); + + // Parses a command-line argument into a name/value pair. Returns + // true if the next argument in the argv should be used as the value, + // false otherwise. + // + // Examples: + // "-Isrc/protos" -> + // name = "-I", value = "src/protos" + // "--cpp_out=src/foo.pb2.cc" -> + // name = "--cpp_out", value = "src/foo.pb2.cc" + // "foo.proto" -> + // name = "", value = "foo.proto" + bool ParseArgument(const char* arg, std::string* name, std::string* value); + + // Interprets arguments parsed with ParseArgument. + ParseArgumentStatus InterpretArgument(const std::string& name, + const std::string& value); + + // Print the --help text to stderr. + void PrintHelpText(); + + // Loads proto_path_ into the provided source_tree. + bool InitializeDiskSourceTree(DiskSourceTree* source_tree, + DescriptorDatabase* fallback_database); + + // Verify that all the input files exist in the given database. + bool VerifyInputFilesInDescriptors(DescriptorDatabase* fallback_database); + + // Parses input_files_ into parsed_files + bool ParseInputFiles(DescriptorPool* descriptor_pool, + DiskSourceTree* source_tree, + std::vector<const FileDescriptor*>* parsed_files); + + // Generate the given output file from the given input. + struct OutputDirective; // see below + bool GenerateOutput(const std::vector<const FileDescriptor*>& parsed_files, + const OutputDirective& output_directive, + GeneratorContext* generator_context); + bool GeneratePluginOutput( + const std::vector<const FileDescriptor*>& parsed_files, + const std::string& plugin_name, const std::string& parameter, + GeneratorContext* generator_context, std::string* error); + + // Implements --encode and --decode. + bool EncodeOrDecode(const DescriptorPool* pool); + + // Implements the --descriptor_set_out option. + bool WriteDescriptorSet( + const std::vector<const FileDescriptor*>& parsed_files); + + // Implements the --dependency_out option + bool GenerateDependencyManifestFile( + const std::vector<const FileDescriptor*>& parsed_files, + const GeneratorContextMap& output_directories, + DiskSourceTree* source_tree); + + // Get all transitive dependencies of the given file (including the file + // itself), adding them to the given list of FileDescriptorProtos. The + // protos will be ordered such that every file is listed before any file that + // depends on it, so that you can call DescriptorPool::BuildFile() on them + // in order. Any files in *already_seen will not be added, and each file + // added will be inserted into *already_seen. If include_source_code_info is + // true then include the source code information in the FileDescriptorProtos. + // If include_json_name is true, populate the json_name field of + // FieldDescriptorProto for all fields. + static void GetTransitiveDependencies( + const FileDescriptor* file, bool include_json_name, + bool include_source_code_info, + std::set<const FileDescriptor*>* already_seen, + RepeatedPtrField<FileDescriptorProto>* output); + + // Implements the --print_free_field_numbers. This function prints free field + // numbers into stdout for the message and it's nested message types in + // post-order, i.e. nested types first. Printed range are left-right + // inclusive, i.e. [a, b]. + // + // Groups: + // For historical reasons, groups are considered to share the same + // field number space with the parent message, thus it will not print free + // field numbers for groups. The field numbers used in the groups are + // excluded in the free field numbers of the parent message. + // + // Extension Ranges: + // Extension ranges are considered ocuppied field numbers and they will not be + // listed as free numbers in the output. + void PrintFreeFieldNumbers(const Descriptor* descriptor); + + // ----------------------------------------------------------------- + + // The name of the executable as invoked (i.e. argv[0]). + std::string executable_name_; + + // Version info set with SetVersionInfo(). + std::string version_info_; + + // Registered generators. + struct GeneratorInfo { + std::string flag_name; + std::string option_flag_name; + CodeGenerator* generator; + std::string help_text; + }; + typedef std::map<std::string, GeneratorInfo> GeneratorMap; + GeneratorMap generators_by_flag_name_; + GeneratorMap generators_by_option_name_; + // A map from generator names to the parameters specified using the option + // flag. For example, if the user invokes the compiler with: + // protoc --foo_out=outputdir --foo_opt=enable_bar ... + // Then there will be an entry ("--foo_out", "enable_bar") in this map. + std::map<std::string, std::string> generator_parameters_; + // Similar to generator_parameters_, but stores the parameters for plugins. + std::map<std::string, std::string> plugin_parameters_; + + // See AllowPlugins(). If this is empty, plugins aren't allowed. + std::string plugin_prefix_; + + // Maps specific plugin names to files. When executing a plugin, this map + // is searched first to find the plugin executable. If not found here, the + // PATH (or other OS-specific search strategy) is searched. + std::map<std::string, std::string> plugins_; + + // Stuff parsed from command line. + enum Mode { + MODE_COMPILE, // Normal mode: parse .proto files and compile them. + MODE_ENCODE, // --encode: read text from stdin, write binary to stdout. + MODE_DECODE, // --decode: read binary from stdin, write text to stdout. + MODE_PRINT, // Print mode: print info of the given .proto files and exit. + }; + + Mode mode_ = MODE_COMPILE; + + enum PrintMode { + PRINT_NONE, // Not in MODE_PRINT + PRINT_FREE_FIELDS, // --print_free_fields + }; + + PrintMode print_mode_ = PRINT_NONE; + + enum ErrorFormat { + ERROR_FORMAT_GCC, // GCC error output format (default). + ERROR_FORMAT_MSVS // Visual Studio output (--error_format=msvs). + }; + + ErrorFormat error_format_ = ERROR_FORMAT_GCC; + + // True if we should treat warnings as errors that fail the compilation. + bool fatal_warnings_ = false; + + std::vector<std::pair<std::string, std::string> > + proto_path_; // Search path for proto files. + std::vector<std::string> input_files_; // Names of the input proto files. + + // Names of proto files which are allowed to be imported. Used by build + // systems to enforce depend-on-what-you-import. + std::set<std::string> direct_dependencies_; + bool direct_dependencies_explicitly_set_ = false; + + // If there's a violation of depend-on-what-you-import, this string will be + // presented to the user. "%s" will be replaced with the violating import. + std::string direct_dependencies_violation_msg_; + + // output_directives_ lists all the files we are supposed to output and what + // generator to use for each. + struct OutputDirective { + std::string name; // E.g. "--foo_out" + CodeGenerator* generator; // NULL for plugins + std::string parameter; + std::string output_location; + }; + std::vector<OutputDirective> output_directives_; + + // When using --encode or --decode, this names the type we are encoding or + // decoding. (Empty string indicates --decode_raw.) + std::string codec_type_; + + // If --descriptor_set_in was given, these are filenames containing + // parsed FileDescriptorSets to be used for loading protos. Otherwise, empty. + std::vector<std::string> descriptor_set_in_names_; + + // If --descriptor_set_out was given, this is the filename to which the + // FileDescriptorSet should be written. Otherwise, empty. + std::string descriptor_set_out_name_; + + // If --dependency_out was given, this is the path to the file where the + // dependency file will be written. Otherwise, empty. + std::string dependency_out_name_; + + // True if --include_imports was given, meaning that we should + // write all transitive dependencies to the DescriptorSet. Otherwise, only + // the .proto files listed on the command-line are added. + bool imports_in_descriptor_set_; + + // True if --include_source_info was given, meaning that we should not strip + // SourceCodeInfo from the DescriptorSet. + bool source_info_in_descriptor_set_ = false; + + // Was the --disallow_services flag used? + bool disallow_services_ = false; + + // When using --encode, this will be passed to SetSerializationDeterministic. + bool deterministic_output_ = false; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CommandLineInterface); +}; + +} // namespace compiler +} // namespace protobuf +} // namespace google + +#include <port_undef.inc> + +#endif // GOOGLE_PROTOBUF_COMPILER_COMMAND_LINE_INTERFACE_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/command_line_interface_unittest.cc b/NorthstarDedicatedTest/include/protobuf/compiler/command_line_interface_unittest.cc new file mode 100644 index 00000000..78c13f61 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/command_line_interface_unittest.cc @@ -0,0 +1,2760 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <fcntl.h> +#include <sys/stat.h> +#include <sys/types.h> + +#include <cstdint> + +#ifndef _MSC_VER +#include <unistd.h> +#endif +#include <memory> +#include <string> +#include <vector> + +#include <stubs/stringprintf.h> +#include <testing/file.h> +#include <testing/file.h> +#include <testing/file.h> +#include <any.pb.h> +#include <compiler/mock_code_generator.h> +#include <compiler/subprocess.h> +#include <compiler/code_generator.h> +#include <compiler/command_line_interface.h> +#include <test_util2.h> +#include <unittest.pb.h> +#include <unittest_custom_options.pb.h> +#include <io/printer.h> +#include <io/zero_copy_stream.h> +#include <descriptor.pb.h> +#include <descriptor.h> +#include <testing/googletest.h> +#include <gtest/gtest.h> +#include <stubs/strutil.h> +#include <stubs/substitute.h> +#include <io/io_win32.h> + + +namespace google { +namespace protobuf { +namespace compiler { + +#if defined(_WIN32) +// DO NOT include <io.h>, instead create functions in io_win32.{h,cc} and import +// them like we do below. +using google::protobuf::io::win32::access; +using google::protobuf::io::win32::close; +using google::protobuf::io::win32::dup; +using google::protobuf::io::win32::dup2; +using google::protobuf::io::win32::open; +using google::protobuf::io::win32::write; +#endif + +// Disable the whole test when we use tcmalloc for "draconian" heap checks, in +// which case tcmalloc will print warnings that fail the plugin tests. +#if !GOOGLE_PROTOBUF_HEAP_CHECK_DRACONIAN + + +namespace { + +bool FileExists(const std::string& path) { + return File::Exists(path); +} + +class CommandLineInterfaceTest : public testing::Test { + protected: + virtual void SetUp(); + virtual void TearDown(); + + // Runs the CommandLineInterface with the given command line. The + // command is automatically split on spaces, and the string "$tmpdir" + // is replaced with TestTempDir(). + void Run(const std::string& command); + void RunWithArgs(std::vector<std::string> args); + + // ----------------------------------------------------------------- + // Methods to set up the test (called before Run()). + + class NullCodeGenerator; + + // Normally plugins are allowed for all tests. Call this to explicitly + // disable them. + void DisallowPlugins() { disallow_plugins_ = true; } + + // Create a temp file within temp_directory_ with the given name. + // The containing directory is also created if necessary. + void CreateTempFile(const std::string& name, const std::string& contents); + + // Create a subdirectory within temp_directory_. + void CreateTempDir(const std::string& name); + +#ifdef PROTOBUF_OPENSOURCE + // Change working directory to temp directory. + void SwitchToTempDirectory() { + File::ChangeWorkingDirectory(temp_directory_); + } +#else // !PROTOBUF_OPENSOURCE + // TODO(teboring): Figure out how to change and get working directory in + // google3. +#endif // !PROTOBUF_OPENSOURCE + + // ----------------------------------------------------------------- + // Methods to check the test results (called after Run()). + + // Checks that no text was written to stderr during Run(), and Run() + // returned 0. + void ExpectNoErrors(); + + // Checks that Run() returned non-zero and the stderr output is exactly + // the text given. expected_test may contain references to "$tmpdir", + // which will be replaced by the temporary directory path. + void ExpectErrorText(const std::string& expected_text); + + // Checks that Run() returned non-zero and the stderr contains the given + // substring. + void ExpectErrorSubstring(const std::string& expected_substring); + + // Checks that Run() returned zero and the stderr contains the given + // substring. + void ExpectWarningSubstring(const std::string& expected_substring); + + // Checks that the captured stdout is the same as the expected_text. + void ExpectCapturedStdout(const std::string& expected_text); + + // Checks that Run() returned zero and the stdout contains the given + // substring. + void ExpectCapturedStdoutSubstringWithZeroReturnCode( + const std::string& expected_substring); + + // Checks that Run() returned zero and the stderr contains the given + // substring. + void ExpectCapturedStderrSubstringWithZeroReturnCode( + const std::string& expected_substring); + +#if defined(_WIN32) && !defined(__CYGWIN__) + // Returns true if ExpectErrorSubstring(expected_substring) would pass, but + // does not fail otherwise. + bool HasAlternateErrorSubstring(const std::string& expected_substring); +#endif // _WIN32 && !__CYGWIN__ + + // Checks that MockCodeGenerator::Generate() was called in the given + // context (or the generator in test_plugin.cc, which produces the same + // output). That is, this tests if the generator with the given name + // was called with the given parameter and proto file and produced the + // given output file. This is checked by reading the output file and + // checking that it contains the content that MockCodeGenerator would + // generate given these inputs. message_name is the name of the first + // message that appeared in the proto file; this is just to make extra + // sure that the correct file was parsed. + void ExpectGenerated(const std::string& generator_name, + const std::string& parameter, + const std::string& proto_name, + const std::string& message_name); + void ExpectGenerated(const std::string& generator_name, + const std::string& parameter, + const std::string& proto_name, + const std::string& message_name, + const std::string& output_directory); + void ExpectGeneratedWithMultipleInputs(const std::string& generator_name, + const std::string& all_proto_names, + const std::string& proto_name, + const std::string& message_name); + void ExpectGeneratedWithInsertions(const std::string& generator_name, + const std::string& parameter, + const std::string& insertions, + const std::string& proto_name, + const std::string& message_name); + void CheckGeneratedAnnotations(const std::string& name, + const std::string& file); + +#if defined(_WIN32) + void ExpectNullCodeGeneratorCalled(const std::string& parameter); +#endif // _WIN32 + + + void ReadDescriptorSet(const std::string& filename, + FileDescriptorSet* descriptor_set); + + void WriteDescriptorSet(const std::string& filename, + const FileDescriptorSet* descriptor_set); + + void ExpectFileContent(const std::string& filename, + const std::string& content); + + // The default code generators support all features. Use this to create a + // code generator that omits the given feature(s). + void CreateGeneratorWithMissingFeatures(const std::string& name, + const std::string& description, + uint64_t features) { + MockCodeGenerator* generator = new MockCodeGenerator(name); + generator->SuppressFeatures(features); + mock_generators_to_delete_.push_back(generator); + cli_.RegisterGenerator(name, generator, description); + } + + private: + // The object we are testing. + CommandLineInterface cli_; + + // Was DisallowPlugins() called? + bool disallow_plugins_; + + // We create a directory within TestTempDir() in order to add extra + // protection against accidentally deleting user files (since we recursively + // delete this directory during the test). This is the full path of that + // directory. + std::string temp_directory_; + + // The result of Run(). + int return_code_; + + // The captured stderr output. + std::string error_text_; + + // The captured stdout. + std::string captured_stdout_; + + // Pointers which need to be deleted later. + std::vector<CodeGenerator*> mock_generators_to_delete_; + + NullCodeGenerator* null_generator_; +}; + +class CommandLineInterfaceTest::NullCodeGenerator : public CodeGenerator { + public: + NullCodeGenerator() : called_(false) {} + ~NullCodeGenerator() {} + + mutable bool called_; + mutable std::string parameter_; + + // implements CodeGenerator ---------------------------------------- + bool Generate(const FileDescriptor* file, const std::string& parameter, + GeneratorContext* context, std::string* error) const { + called_ = true; + parameter_ = parameter; + return true; + } +}; + +// =================================================================== + +void CommandLineInterfaceTest::SetUp() { + temp_directory_ = TestTempDir() + "/proto2_cli_test_temp"; + + // If the temp directory already exists, it must be left over from a + // previous run. Delete it. + if (FileExists(temp_directory_)) { + File::DeleteRecursively(temp_directory_, NULL, NULL); + } + + // Create the temp directory. + GOOGLE_CHECK_OK(File::CreateDir(temp_directory_, 0777)); + + // Register generators. + CodeGenerator* generator = new MockCodeGenerator("test_generator"); + mock_generators_to_delete_.push_back(generator); + cli_.RegisterGenerator("--test_out", "--test_opt", generator, "Test output."); + cli_.RegisterGenerator("-t", generator, "Test output."); + + generator = new MockCodeGenerator("alt_generator"); + mock_generators_to_delete_.push_back(generator); + cli_.RegisterGenerator("--alt_out", generator, "Alt output."); + + generator = null_generator_ = new NullCodeGenerator(); + mock_generators_to_delete_.push_back(generator); + cli_.RegisterGenerator("--null_out", generator, "Null output."); + + + disallow_plugins_ = false; +} + +void CommandLineInterfaceTest::TearDown() { + // Delete the temp directory. + if (FileExists(temp_directory_)) { + File::DeleteRecursively(temp_directory_, NULL, NULL); + } + + // Delete all the MockCodeGenerators. + for (int i = 0; i < mock_generators_to_delete_.size(); i++) { + delete mock_generators_to_delete_[i]; + } + mock_generators_to_delete_.clear(); +} + +void CommandLineInterfaceTest::Run(const std::string& command) { + RunWithArgs(Split(command, " ", true)); +} + +void CommandLineInterfaceTest::RunWithArgs(std::vector<std::string> args) { + if (!disallow_plugins_) { + cli_.AllowPlugins("prefix-"); + std::string plugin_path; +#ifdef GOOGLE_PROTOBUF_TEST_PLUGIN_PATH + plugin_path = GOOGLE_PROTOBUF_TEST_PLUGIN_PATH; +#else + const char* possible_paths[] = { + // When building with shared libraries, libtool hides the real + // executable + // in .libs and puts a fake wrapper in the current directory. + // Unfortunately, due to an apparent bug on Cygwin/MinGW, if one program + // wrapped in this way (e.g. protobuf-tests.exe) tries to execute + // another + // program wrapped in this way (e.g. test_plugin.exe), the latter fails + // with error code 127 and no explanation message. Presumably the + // problem + // is that the wrapper for protobuf-tests.exe set some environment + // variables that confuse the wrapper for test_plugin.exe. Luckily, it + // turns out that if we simply invoke the wrapped test_plugin.exe + // directly, it works -- I guess the environment variables set by the + // protobuf-tests.exe wrapper happen to be correct for it too. So we do + // that. + ".libs/test_plugin.exe", // Win32 w/autotool (Cygwin / MinGW) + "test_plugin.exe", // Other Win32 (MSVC) + "test_plugin", // Unix + }; + for (int i = 0; i < GOOGLE_ARRAYSIZE(possible_paths); i++) { + if (access(possible_paths[i], F_OK) == 0) { + plugin_path = possible_paths[i]; + break; + } + } +#endif + + if (plugin_path.empty()) { + GOOGLE_LOG(ERROR) + << "Plugin executable not found. Plugin tests are likely to fail."; + } else { + args.push_back("--plugin=prefix-gen-plug=" + plugin_path); + } + } + + std::unique_ptr<const char*[]> argv(new const char*[args.size()]); + + for (int i = 0; i < args.size(); i++) { + args[i] = StringReplace(args[i], "$tmpdir", temp_directory_, true); + argv[i] = args[i].c_str(); + } + + // TODO(jieluo): Cygwin doesn't work well if we try to capture stderr and + // stdout at the same time. Need to figure out why and add this capture back + // for Cygwin. +#if !defined(__CYGWIN__) + CaptureTestStdout(); +#endif + CaptureTestStderr(); + + return_code_ = cli_.Run(args.size(), argv.get()); + + error_text_ = GetCapturedTestStderr(); +#if !defined(__CYGWIN__) + captured_stdout_ = GetCapturedTestStdout(); +#endif +} + +// ------------------------------------------------------------------- + +void CommandLineInterfaceTest::CreateTempFile(const std::string& name, + const std::string& contents) { + // Create parent directory, if necessary. + std::string::size_type slash_pos = name.find_last_of('/'); + if (slash_pos != std::string::npos) { + std::string dir = name.substr(0, slash_pos); + if (!FileExists(temp_directory_ + "/" + dir)) { + GOOGLE_CHECK_OK(File::RecursivelyCreateDir(temp_directory_ + "/" + dir, + 0777)); + } + } + + // Write file. + std::string full_name = temp_directory_ + "/" + name; + GOOGLE_CHECK_OK(File::SetContents( + full_name, StringReplace(contents, "$tmpdir", temp_directory_, true), + true)); +} + +void CommandLineInterfaceTest::CreateTempDir(const std::string& name) { + GOOGLE_CHECK_OK(File::RecursivelyCreateDir(temp_directory_ + "/" + name, + 0777)); +} + +// ------------------------------------------------------------------- + +void CommandLineInterfaceTest::ExpectNoErrors() { + EXPECT_EQ(0, return_code_); + EXPECT_EQ("", error_text_); +} + +void CommandLineInterfaceTest::ExpectErrorText( + const std::string& expected_text) { + EXPECT_NE(0, return_code_); + EXPECT_EQ(StringReplace(expected_text, "$tmpdir", temp_directory_, true), + error_text_); +} + +void CommandLineInterfaceTest::ExpectErrorSubstring( + const std::string& expected_substring) { + EXPECT_NE(0, return_code_); + EXPECT_PRED_FORMAT2(testing::IsSubstring, expected_substring, error_text_); +} + +void CommandLineInterfaceTest::ExpectWarningSubstring( + const std::string& expected_substring) { + EXPECT_PRED_FORMAT2(testing::IsSubstring, expected_substring, error_text_); + EXPECT_EQ(0, return_code_); +} + +#if defined(_WIN32) && !defined(__CYGWIN__) +bool CommandLineInterfaceTest::HasAlternateErrorSubstring( + const std::string& expected_substring) { + EXPECT_NE(0, return_code_); + return error_text_.find(expected_substring) != std::string::npos; +} +#endif // _WIN32 && !__CYGWIN__ + +void CommandLineInterfaceTest::ExpectGenerated( + const std::string& generator_name, const std::string& parameter, + const std::string& proto_name, const std::string& message_name) { + MockCodeGenerator::ExpectGenerated(generator_name, parameter, "", proto_name, + message_name, proto_name, temp_directory_); +} + +void CommandLineInterfaceTest::ExpectGenerated( + const std::string& generator_name, const std::string& parameter, + const std::string& proto_name, const std::string& message_name, + const std::string& output_directory) { + MockCodeGenerator::ExpectGenerated(generator_name, parameter, "", proto_name, + message_name, proto_name, + temp_directory_ + "/" + output_directory); +} + +void CommandLineInterfaceTest::ExpectGeneratedWithMultipleInputs( + const std::string& generator_name, const std::string& all_proto_names, + const std::string& proto_name, const std::string& message_name) { + MockCodeGenerator::ExpectGenerated(generator_name, "", "", proto_name, + message_name, all_proto_names, + temp_directory_); +} + +void CommandLineInterfaceTest::ExpectGeneratedWithInsertions( + const std::string& generator_name, const std::string& parameter, + const std::string& insertions, const std::string& proto_name, + const std::string& message_name) { + MockCodeGenerator::ExpectGenerated(generator_name, parameter, insertions, + proto_name, message_name, proto_name, + temp_directory_); +} + +void CommandLineInterfaceTest::CheckGeneratedAnnotations( + const std::string& name, const std::string& file) { + MockCodeGenerator::CheckGeneratedAnnotations(name, file, temp_directory_); +} + +#if defined(_WIN32) +void CommandLineInterfaceTest::ExpectNullCodeGeneratorCalled( + const std::string& parameter) { + EXPECT_TRUE(null_generator_->called_); + EXPECT_EQ(parameter, null_generator_->parameter_); +} +#endif // _WIN32 + + +void CommandLineInterfaceTest::ReadDescriptorSet( + const std::string& filename, FileDescriptorSet* descriptor_set) { + std::string path = temp_directory_ + "/" + filename; + std::string file_contents; + GOOGLE_CHECK_OK(File::GetContents(path, &file_contents, true)); + + if (!descriptor_set->ParseFromString(file_contents)) { + FAIL() << "Could not parse file contents: " << path; + } +} + +void CommandLineInterfaceTest::WriteDescriptorSet( + const std::string& filename, const FileDescriptorSet* descriptor_set) { + std::string binary_proto; + GOOGLE_CHECK(descriptor_set->SerializeToString(&binary_proto)); + CreateTempFile(filename, binary_proto); +} + +void CommandLineInterfaceTest::ExpectCapturedStdout( + const std::string& expected_text) { + EXPECT_EQ(expected_text, captured_stdout_); +} + +void CommandLineInterfaceTest::ExpectCapturedStdoutSubstringWithZeroReturnCode( + const std::string& expected_substring) { + EXPECT_EQ(0, return_code_); + EXPECT_PRED_FORMAT2(testing::IsSubstring, expected_substring, + captured_stdout_); +} + +void CommandLineInterfaceTest::ExpectCapturedStderrSubstringWithZeroReturnCode( + const std::string& expected_substring) { + EXPECT_EQ(0, return_code_); + EXPECT_PRED_FORMAT2(testing::IsSubstring, expected_substring, error_text_); +} + +void CommandLineInterfaceTest::ExpectFileContent(const std::string& filename, + const std::string& content) { + std::string path = temp_directory_ + "/" + filename; + std::string file_contents; + GOOGLE_CHECK_OK(File::GetContents(path, &file_contents, true)); + + EXPECT_EQ(StringReplace(content, "$tmpdir", temp_directory_, true), + file_contents); +} + +// =================================================================== + +TEST_F(CommandLineInterfaceTest, BasicOutput) { + // Test that the common case works. + + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); + + Run("protocol_compiler --test_out=$tmpdir " + "--proto_path=$tmpdir foo.proto"); + + ExpectNoErrors(); + ExpectGenerated("test_generator", "", "foo.proto", "Foo"); +} + +TEST_F(CommandLineInterfaceTest, BasicOutput_DescriptorSetIn) { + // Test that the common case works. + FileDescriptorSet file_descriptor_set; + FileDescriptorProto* file_descriptor_proto = file_descriptor_set.add_file(); + file_descriptor_proto->set_name("foo.proto"); + file_descriptor_proto->add_message_type()->set_name("Foo"); + + WriteDescriptorSet("foo.bin", &file_descriptor_set); + + Run("protocol_compiler --test_out=$tmpdir " + "--descriptor_set_in=$tmpdir/foo.bin foo.proto"); + + ExpectNoErrors(); + ExpectGenerated("test_generator", "", "foo.proto", "Foo"); +} + +TEST_F(CommandLineInterfaceTest, BasicPlugin) { + // Test that basic plugins work. + + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); + + Run("protocol_compiler --plug_out=$tmpdir " + "--proto_path=$tmpdir foo.proto"); + + ExpectNoErrors(); + ExpectGenerated("test_plugin", "", "foo.proto", "Foo"); +} + +TEST_F(CommandLineInterfaceTest, BasicPlugin_DescriptorSetIn) { + // Test that basic plugins work. + + FileDescriptorSet file_descriptor_set; + FileDescriptorProto* file_descriptor_proto = file_descriptor_set.add_file(); + file_descriptor_proto->set_name("foo.proto"); + file_descriptor_proto->add_message_type()->set_name("Foo"); + + WriteDescriptorSet("foo.bin", &file_descriptor_set); + + Run("protocol_compiler --plug_out=$tmpdir " + "--descriptor_set_in=$tmpdir/foo.bin foo.proto"); + + ExpectNoErrors(); + ExpectGenerated("test_plugin", "", "foo.proto", "Foo"); +} + +TEST_F(CommandLineInterfaceTest, GeneratorAndPlugin) { + // Invoke a generator and a plugin at the same time. + + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); + + Run("protocol_compiler --test_out=$tmpdir --plug_out=$tmpdir " + "--proto_path=$tmpdir foo.proto"); + + ExpectNoErrors(); + ExpectGenerated("test_generator", "", "foo.proto", "Foo"); + ExpectGenerated("test_plugin", "", "foo.proto", "Foo"); +} + +TEST_F(CommandLineInterfaceTest, GeneratorAndPlugin_DescriptorSetIn) { + // Invoke a generator and a plugin at the same time. + + FileDescriptorSet file_descriptor_set; + FileDescriptorProto* file_descriptor_proto = file_descriptor_set.add_file(); + file_descriptor_proto->set_name("foo.proto"); + file_descriptor_proto->add_message_type()->set_name("Foo"); + + WriteDescriptorSet("foo.bin", &file_descriptor_set); + + Run("protocol_compiler --test_out=$tmpdir --plug_out=$tmpdir " + "--descriptor_set_in=$tmpdir/foo.bin foo.proto"); + + ExpectNoErrors(); + ExpectGenerated("test_generator", "", "foo.proto", "Foo"); + ExpectGenerated("test_plugin", "", "foo.proto", "Foo"); +} + +TEST_F(CommandLineInterfaceTest, MultipleInputs) { + // Test parsing multiple input files. + + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); + CreateTempFile("bar.proto", + "syntax = \"proto2\";\n" + "message Bar {}\n"); + + Run("protocol_compiler --test_out=$tmpdir --plug_out=$tmpdir " + "--proto_path=$tmpdir foo.proto bar.proto"); + + ExpectNoErrors(); + ExpectGeneratedWithMultipleInputs("test_generator", "foo.proto,bar.proto", + "foo.proto", "Foo"); + ExpectGeneratedWithMultipleInputs("test_generator", "foo.proto,bar.proto", + "bar.proto", "Bar"); + ExpectGeneratedWithMultipleInputs("test_plugin", "foo.proto,bar.proto", + "foo.proto", "Foo"); + ExpectGeneratedWithMultipleInputs("test_plugin", "foo.proto,bar.proto", + "bar.proto", "Bar"); +} + +TEST_F(CommandLineInterfaceTest, MultipleInputs_DescriptorSetIn) { + // Test parsing multiple input files. + FileDescriptorSet file_descriptor_set; + + FileDescriptorProto* file_descriptor_proto = file_descriptor_set.add_file(); + file_descriptor_proto->set_name("foo.proto"); + file_descriptor_proto->add_message_type()->set_name("Foo"); + + file_descriptor_proto = file_descriptor_set.add_file(); + file_descriptor_proto->set_name("bar.proto"); + file_descriptor_proto->add_message_type()->set_name("Bar"); + + WriteDescriptorSet("foo.bin", &file_descriptor_set); + + Run("protocol_compiler --test_out=$tmpdir --plug_out=$tmpdir " + "--descriptor_set_in=$tmpdir/foo.bin foo.proto bar.proto"); + + ExpectNoErrors(); + ExpectGeneratedWithMultipleInputs("test_generator", "foo.proto,bar.proto", + "foo.proto", "Foo"); + ExpectGeneratedWithMultipleInputs("test_generator", "foo.proto,bar.proto", + "bar.proto", "Bar"); + ExpectGeneratedWithMultipleInputs("test_plugin", "foo.proto,bar.proto", + "foo.proto", "Foo"); + ExpectGeneratedWithMultipleInputs("test_plugin", "foo.proto,bar.proto", + "bar.proto", "Bar"); +} + +TEST_F(CommandLineInterfaceTest, MultipleInputs_UnusedImport_DescriptorSetIn) { + // Test unused import warning is not raised when descriptor_set_in is called + // and custom options are in unknown field instead of uninterpreted_options. + FileDescriptorSet file_descriptor_set; + + const FileDescriptor* descriptor_file = + FileDescriptorProto::descriptor()->file(); + descriptor_file->CopyTo(file_descriptor_set.add_file()); + + FileDescriptorProto& any_proto = *file_descriptor_set.add_file(); + google::protobuf::Any::descriptor()->file()->CopyTo(&any_proto); + + const FileDescriptor* custom_file = + protobuf_unittest::AggregateMessage::descriptor()->file(); + FileDescriptorProto* file_descriptor_proto = file_descriptor_set.add_file(); + custom_file->CopyTo(file_descriptor_proto); + file_descriptor_proto->set_name("custom_options.proto"); + // Add a custom message option. + FieldDescriptorProto* extension_option = + file_descriptor_proto->add_extension(); + extension_option->set_name("unknown_option"); + extension_option->set_extendee(".google.protobuf.MessageOptions"); + extension_option->set_number(1111); + extension_option->set_label(FieldDescriptorProto::LABEL_OPTIONAL); + extension_option->set_type(FieldDescriptorProto::TYPE_INT64); + + file_descriptor_proto = file_descriptor_set.add_file(); + file_descriptor_proto->set_name("import_custom_unknown_options.proto"); + file_descriptor_proto->add_dependency("custom_options.proto"); + // Add custom message option to unknown field. This custom option is + // not known in generated pool, thus option will be in unknown fields. + file_descriptor_proto->add_message_type()->set_name("Bar"); + file_descriptor_proto->mutable_message_type(0) + ->mutable_options() + ->mutable_unknown_fields() + ->AddVarint(1111, 2222); + + WriteDescriptorSet("foo.bin", &file_descriptor_set); + + Run("protocol_compiler --test_out=$tmpdir --plug_out=$tmpdir " + "--descriptor_set_in=$tmpdir/foo.bin " + "import_custom_unknown_options.proto"); + + // TODO(jieluo): Fix this test. This test case only happens when + // CommandLineInterface::Run() is used instead of invoke protoc combined + // with descriptor_set_in, and same custom options are defined in both + // generated pool and descriptor_set_in. There's no such uages for now but + // still need to be fixed. + /* + file_descriptor_proto = file_descriptor_set.add_file(); + file_descriptor_proto->set_name("import_custom_extension_options.proto"); + file_descriptor_proto->add_dependency("custom_options.proto"); + // Add custom message option to unknown field. This custom option is + // also defined in generated pool, thus option will be in extensions. + file_descriptor_proto->add_message_type()->set_name("Foo"); + file_descriptor_proto->mutable_message_type(0) + ->mutable_options() + ->mutable_unknown_fields() + ->AddVarint(protobuf_unittest::message_opt1.number(), 2222); + + WriteDescriptorSet("foo.bin", &file_descriptor_set); + + Run("protocol_compiler --test_out=$tmpdir --plug_out=$tmpdir " + "--descriptor_set_in=$tmpdir/foo.bin import_custom_unknown_options.proto " + "import_custom_extension_options.proto"); + */ + + ExpectNoErrors(); +} + +TEST_F(CommandLineInterfaceTest, MultipleInputsWithImport) { + // Test parsing multiple input files with an import of a separate file. + + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); + CreateTempFile("bar.proto", + "syntax = \"proto2\";\n" + "import \"baz.proto\";\n" + "message Bar {\n" + " optional Baz a = 1;\n" + "}\n"); + CreateTempFile("baz.proto", + "syntax = \"proto2\";\n" + "message Baz {}\n"); + + Run("protocol_compiler --test_out=$tmpdir --plug_out=$tmpdir " + "--proto_path=$tmpdir foo.proto bar.proto"); + + ExpectNoErrors(); + ExpectGeneratedWithMultipleInputs("test_generator", "foo.proto,bar.proto", + "foo.proto", "Foo"); + ExpectGeneratedWithMultipleInputs("test_generator", "foo.proto,bar.proto", + "bar.proto", "Bar"); + ExpectGeneratedWithMultipleInputs("test_plugin", "foo.proto,bar.proto", + "foo.proto", "Foo"); + ExpectGeneratedWithMultipleInputs("test_plugin", "foo.proto,bar.proto", + "bar.proto", "Bar"); +} + +TEST_F(CommandLineInterfaceTest, MultipleInputsWithImport_DescriptorSetIn) { + // Test parsing multiple input files with an import of a separate file. + FileDescriptorSet file_descriptor_set; + + FileDescriptorProto* file_descriptor_proto = file_descriptor_set.add_file(); + file_descriptor_proto->set_name("foo.proto"); + file_descriptor_proto->add_message_type()->set_name("Foo"); + + file_descriptor_proto = file_descriptor_set.add_file(); + file_descriptor_proto->set_name("bar.proto"); + file_descriptor_proto->add_dependency("baz.proto"); + DescriptorProto* message = file_descriptor_proto->add_message_type(); + message->set_name("Bar"); + FieldDescriptorProto* field = message->add_field(); + field->set_type_name("Baz"); + field->set_name("a"); + field->set_number(1); + + WriteDescriptorSet("foo_and_bar.bin", &file_descriptor_set); + + file_descriptor_set.clear_file(); + file_descriptor_proto = file_descriptor_set.add_file(); + file_descriptor_proto->set_name("baz.proto"); + file_descriptor_proto->add_message_type()->set_name("Baz"); + + file_descriptor_proto = file_descriptor_set.add_file(); + file_descriptor_proto->set_name("bat.proto"); + file_descriptor_proto->add_dependency("baz.proto"); + message = file_descriptor_proto->add_message_type(); + message->set_name("Bat"); + field = message->add_field(); + field->set_type_name("Baz"); + field->set_name("a"); + field->set_number(1); + + WriteDescriptorSet("baz_and_bat.bin", &file_descriptor_set); + Run(strings::Substitute( + "protocol_compiler --test_out=$$tmpdir --plug_out=$$tmpdir " + "--descriptor_set_in=$0 foo.proto bar.proto", + std::string("$tmpdir/foo_and_bar.bin") + + CommandLineInterface::kPathSeparator + "$tmpdir/baz_and_bat.bin")); + + ExpectNoErrors(); + ExpectGeneratedWithMultipleInputs("test_generator", "foo.proto,bar.proto", + "foo.proto", "Foo"); + ExpectGeneratedWithMultipleInputs("test_generator", "foo.proto,bar.proto", + "bar.proto", "Bar"); + ExpectGeneratedWithMultipleInputs("test_plugin", "foo.proto,bar.proto", + "foo.proto", "Foo"); + ExpectGeneratedWithMultipleInputs("test_plugin", "foo.proto,bar.proto", + "bar.proto", "Bar"); + + Run(strings::Substitute( + "protocol_compiler --test_out=$$tmpdir --plug_out=$$tmpdir " + "--descriptor_set_in=$0 baz.proto bat.proto", + std::string("$tmpdir/foo_and_bar.bin") + + CommandLineInterface::kPathSeparator + "$tmpdir/baz_and_bat.bin")); + + ExpectNoErrors(); + ExpectGeneratedWithMultipleInputs("test_generator", "baz.proto,bat.proto", + "baz.proto", "Baz"); + ExpectGeneratedWithMultipleInputs("test_generator", "baz.proto,bat.proto", + "bat.proto", "Bat"); + ExpectGeneratedWithMultipleInputs("test_plugin", "baz.proto,bat.proto", + "baz.proto", "Baz"); + ExpectGeneratedWithMultipleInputs("test_plugin", "baz.proto,bat.proto", + "bat.proto", "Bat"); +} + +TEST_F(CommandLineInterfaceTest, + MultipleInputsWithImport_DescriptorSetIn_DuplicateFileDescriptor) { + // Test parsing multiple input files with an import of a separate file. + FileDescriptorSet file_descriptor_set; + + FileDescriptorProto foo_file_descriptor_proto; + foo_file_descriptor_proto.set_name("foo.proto"); + foo_file_descriptor_proto.add_message_type()->set_name("Foo"); + + file_descriptor_set.add_file()->CopyFrom(foo_file_descriptor_proto); + + FileDescriptorProto* file_descriptor_proto = file_descriptor_set.add_file(); + file_descriptor_proto->set_name("bar.proto"); + file_descriptor_proto->add_dependency("baz.proto"); + file_descriptor_proto->add_dependency("foo.proto"); + DescriptorProto* message = file_descriptor_proto->add_message_type(); + message->set_name("Bar"); + FieldDescriptorProto* field = message->add_field(); + field->set_type_name("Baz"); + field->set_name("a"); + field->set_number(1); + field = message->add_field(); + field->set_type_name("Foo"); + field->set_name("f"); + field->set_number(2); + WriteDescriptorSet("foo_and_bar.bin", &file_descriptor_set); + + file_descriptor_set.clear_file(); + file_descriptor_set.add_file()->CopyFrom(foo_file_descriptor_proto); + + file_descriptor_proto = file_descriptor_set.add_file(); + file_descriptor_proto->set_name("baz.proto"); + file_descriptor_proto->add_dependency("foo.proto"); + message = file_descriptor_proto->add_message_type(); + message->set_name("Baz"); + field = message->add_field(); + field->set_type_name("Foo"); + field->set_name("f"); + field->set_number(1); + WriteDescriptorSet("foo_and_baz.bin", &file_descriptor_set); + + Run(strings::Substitute( + "protocol_compiler --test_out=$$tmpdir --plug_out=$$tmpdir " + "--descriptor_set_in=$0 bar.proto", + std::string("$tmpdir/foo_and_bar.bin") + + CommandLineInterface::kPathSeparator + "$tmpdir/foo_and_baz.bin")); + + ExpectNoErrors(); + ExpectGenerated("test_generator", "", "bar.proto", "Bar"); + ExpectGenerated("test_plugin", "", "bar.proto", "Bar"); +} + +TEST_F(CommandLineInterfaceTest, + MultipleInputsWithImport_DescriptorSetIn_MissingImport) { + // Test parsing multiple input files with an import of a separate file. + FileDescriptorSet file_descriptor_set; + + FileDescriptorProto* file_descriptor_proto = file_descriptor_set.add_file(); + file_descriptor_proto->set_name("foo.proto"); + file_descriptor_proto->add_message_type()->set_name("Foo"); + + file_descriptor_proto = file_descriptor_set.add_file(); + file_descriptor_proto->set_name("bar.proto"); + file_descriptor_proto->add_dependency("baz.proto"); + DescriptorProto* message = file_descriptor_proto->add_message_type(); + message->set_name("Bar"); + FieldDescriptorProto* field = message->add_field(); + field->set_type_name("Baz"); + field->set_name("a"); + field->set_number(1); + + WriteDescriptorSet("foo_and_bar.bin", &file_descriptor_set); + + file_descriptor_set.clear_file(); + file_descriptor_proto = file_descriptor_set.add_file(); + file_descriptor_proto->set_name("baz.proto"); + file_descriptor_proto->add_message_type()->set_name("Baz"); + + WriteDescriptorSet("baz.bin", &file_descriptor_set); + Run("protocol_compiler --test_out=$tmpdir --plug_out=$tmpdir " + "--descriptor_set_in=$tmpdir/foo_and_bar.bin " + "foo.proto bar.proto"); + ExpectErrorSubstring( + "bar.proto: Import \"baz.proto\" was not found or had errors."); + ExpectErrorSubstring("bar.proto: \"Baz\" is not defined."); +} + +TEST_F(CommandLineInterfaceTest, + InputsOnlyFromDescriptorSetIn_UnusedImportIsNotReported) { + FileDescriptorSet file_descriptor_set; + + FileDescriptorProto* file_descriptor_proto = file_descriptor_set.add_file(); + file_descriptor_proto->set_name("unused.proto"); + file_descriptor_proto->add_message_type()->set_name("Unused"); + + file_descriptor_proto = file_descriptor_set.add_file(); + file_descriptor_proto->set_name("bar.proto"); + file_descriptor_proto->add_dependency("unused.proto"); + file_descriptor_proto->add_message_type()->set_name("Bar"); + + WriteDescriptorSet("unused_and_bar.bin", &file_descriptor_set); + + Run("protocol_compiler --test_out=$tmpdir --plug_out=$tmpdir " + "--descriptor_set_in=$tmpdir/unused_and_bar.bin unused.proto bar.proto"); + ExpectNoErrors(); +} + +TEST_F(CommandLineInterfaceTest, + InputsFromDescriptorSetInAndFileSystem_UnusedImportIsReported) { + FileDescriptorSet file_descriptor_set; + + FileDescriptorProto* file_descriptor_proto = file_descriptor_set.add_file(); + file_descriptor_proto->set_name("unused.proto"); + file_descriptor_proto->add_message_type()->set_name("Unused"); + + file_descriptor_proto = file_descriptor_set.add_file(); + file_descriptor_proto->set_name("bar.proto"); + file_descriptor_proto->add_dependency("unused.proto"); + file_descriptor_proto->add_message_type()->set_name("Bar"); + + WriteDescriptorSet("unused_and_bar.bin", &file_descriptor_set); + + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "import \"bar.proto\";\n" + "message Foo {\n" + " optional Bar bar = 1;\n" + "}\n"); + + Run("protocol_compiler --test_out=$tmpdir --plug_out=$tmpdir " + "--descriptor_set_in=$tmpdir/unused_and_bar.bin " + "--proto_path=$tmpdir unused.proto bar.proto foo.proto"); + // Reporting unused imports here is unfair, since it's unactionable. Notice + // the lack of a line number. + // TODO(b/144853061): If the file with unused import is from the descriptor + // set and not from the file system, suppress the warning. + ExpectWarningSubstring("bar.proto: warning: Import unused.proto is unused."); +} + +TEST_F(CommandLineInterfaceTest, + OnlyReportsUnusedImportsForFilesBeingGenerated) { + CreateTempFile("unused.proto", + "syntax = \"proto2\";\n" + "message Unused {}\n"); + CreateTempFile("bar.proto", + "syntax = \"proto2\";\n" + "import \"unused.proto\";\n" + "message Bar {}\n"); + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "import \"bar.proto\";\n" + "message Foo {\n" + " optional Bar bar = 1;\n" + "}\n"); + + Run("protocol_compiler --test_out=$tmpdir " + "--proto_path=$tmpdir foo.proto"); + ExpectNoErrors(); +} + +TEST_F(CommandLineInterfaceTest, ReportsTransitiveMisingImports_LeafFirst) { + CreateTempFile("unused.proto", + "syntax = \"proto2\";\n" + "message Unused {}\n"); + CreateTempFile("bar.proto", + "syntax = \"proto2\";\n" + "import \"unused.proto\";\n" + "message Bar {}\n"); + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "import \"bar.proto\";\n" + "message Foo {\n" + " optional Bar bar = 1;\n" + "}\n"); + + Run("protocol_compiler --test_out=$tmpdir " + "--proto_path=$tmpdir bar.proto foo.proto"); + ExpectWarningSubstring( + "bar.proto:2:1: warning: Import unused.proto is unused."); +} + +TEST_F(CommandLineInterfaceTest, ReportsTransitiveMisingImports_LeafLast) { + CreateTempFile("unused.proto", + "syntax = \"proto2\";\n" + "message Unused {}\n"); + CreateTempFile("bar.proto", + "syntax = \"proto2\";\n" + "import \"unused.proto\";\n" + "message Bar {}\n"); + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "import \"bar.proto\";\n" + "message Foo {\n" + " optional Bar bar = 1;\n" + "}\n"); + + Run("protocol_compiler --test_out=$tmpdir " + "--proto_path=$tmpdir foo.proto bar.proto"); + ExpectWarningSubstring( + "bar.proto:2:1: warning: Import unused.proto is unused."); +} +TEST_F(CommandLineInterfaceTest, CreateDirectory) { + // Test that when we output to a sub-directory, it is created. + + CreateTempFile("bar/baz/foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); + CreateTempDir("out"); + CreateTempDir("plugout"); + + Run("protocol_compiler --test_out=$tmpdir/out --plug_out=$tmpdir/plugout " + "--proto_path=$tmpdir bar/baz/foo.proto"); + + ExpectNoErrors(); + ExpectGenerated("test_generator", "", "bar/baz/foo.proto", "Foo", "out"); + ExpectGenerated("test_plugin", "", "bar/baz/foo.proto", "Foo", "plugout"); +} + +TEST_F(CommandLineInterfaceTest, GeneratorParameters) { + // Test that generator parameters are correctly parsed from the command line. + + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); + + Run("protocol_compiler --test_out=TestParameter:$tmpdir " + "--plug_out=TestPluginParameter:$tmpdir " + "--proto_path=$tmpdir foo.proto"); + + ExpectNoErrors(); + ExpectGenerated("test_generator", "TestParameter", "foo.proto", "Foo"); + ExpectGenerated("test_plugin", "TestPluginParameter", "foo.proto", "Foo"); +} + +TEST_F(CommandLineInterfaceTest, ExtraGeneratorParameters) { + // Test that generator parameters specified with the option flag are + // correctly passed to the code generator. + + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); + // Create the "a" and "b" sub-directories. + CreateTempDir("a"); + CreateTempDir("b"); + + Run("protocol_compiler " + "--test_opt=foo1 " + "--test_out=bar:$tmpdir/a " + "--test_opt=foo2 " + "--test_out=baz:$tmpdir/b " + "--test_opt=foo3 " + "--proto_path=$tmpdir foo.proto"); + + ExpectNoErrors(); + ExpectGenerated("test_generator", "bar,foo1,foo2,foo3", "foo.proto", "Foo", + "a"); + ExpectGenerated("test_generator", "baz,foo1,foo2,foo3", "foo.proto", "Foo", + "b"); +} + +TEST_F(CommandLineInterfaceTest, ExtraPluginParameters) { + // Test that generator parameters specified with the option flag are + // correctly passed to the code generator. + + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); + // Create the "a" and "b" sub-directories. + CreateTempDir("a"); + CreateTempDir("b"); + + Run("protocol_compiler " + "--plug_opt=foo1 " + "--plug_out=bar:$tmpdir/a " + "--plug_opt=foo2 " + "--plug_out=baz:$tmpdir/b " + "--plug_opt=foo3 " + "--proto_path=$tmpdir foo.proto"); + + ExpectNoErrors(); + ExpectGenerated("test_plugin", "bar,foo1,foo2,foo3", "foo.proto", "Foo", "a"); + ExpectGenerated("test_plugin", "baz,foo1,foo2,foo3", "foo.proto", "Foo", "b"); +} + +TEST_F(CommandLineInterfaceTest, UnrecognizedExtraParameters) { + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); + + Run("protocol_compiler --plug_out=TestParameter:$tmpdir " + "--unknown_plug_a_opt=Foo " + "--unknown_plug_b_opt=Bar " + "--proto_path=$tmpdir foo.proto"); + + ExpectErrorSubstring("Unknown flag: --unknown_plug_a_opt"); + ExpectErrorSubstring("Unknown flag: --unknown_plug_b_opt"); +} + +TEST_F(CommandLineInterfaceTest, ExtraPluginParametersForOutParameters) { + // This doesn't rely on the plugin having been registered and instead that + // the existence of --[name]_out is enough to make the --[name]_opt valid. + // However, running out of process plugins found via the search path (i.e. - + // not pre registered with --plugin) isn't support in this test suite, so we + // list the options pre/post the _out directive, and then include _opt that + // will be unknown, and confirm the failure output is about the expected + // unknown directive, which means the other were accepted. + // NOTE: UnrecognizedExtraParameters confirms that if two unknown _opt + // directives appear, they both are reported. + + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); + + Run("protocol_compiler --plug_out=TestParameter:$tmpdir " + "--xyz_opt=foo=bar --xyz_out=$tmpdir " + "--abc_out=$tmpdir --abc_opt=foo=bar " + "--unknown_plug_opt=Foo " + "--proto_path=$tmpdir foo.proto"); + + ExpectErrorText("Unknown flag: --unknown_plug_opt\n"); +} + +TEST_F(CommandLineInterfaceTest, Insert) { + // Test running a generator that inserts code into another's output. + + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); + + Run("protocol_compiler " + "--test_out=TestParameter:$tmpdir " + "--plug_out=TestPluginParameter:$tmpdir " + "--test_out=insert=test_generator,test_plugin:$tmpdir " + "--plug_out=insert=test_generator,test_plugin:$tmpdir " + "--proto_path=$tmpdir foo.proto"); + + ExpectNoErrors(); + ExpectGeneratedWithInsertions("test_generator", "TestParameter", + "test_generator,test_plugin", "foo.proto", + "Foo"); + ExpectGeneratedWithInsertions("test_plugin", "TestPluginParameter", + "test_generator,test_plugin", "foo.proto", + "Foo"); +} + +TEST_F(CommandLineInterfaceTest, InsertWithAnnotationFixup) { + // Check that annotation spans are updated after insertions. + + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message MockCodeGenerator_Annotate {}\n"); + + Run("protocol_compiler " + "--test_out=TestParameter:$tmpdir " + "--plug_out=TestPluginParameter:$tmpdir " + "--test_out=insert_endlines=test_generator,test_plugin:$tmpdir " + "--plug_out=insert_endlines=test_generator,test_plugin:$tmpdir " + "--proto_path=$tmpdir foo.proto"); + + ExpectNoErrors(); + CheckGeneratedAnnotations("test_generator", "foo.proto"); + CheckGeneratedAnnotations("test_plugin", "foo.proto"); +} + +#if defined(_WIN32) + +TEST_F(CommandLineInterfaceTest, WindowsOutputPath) { + // Test that the output path can be a Windows-style path. + + CreateTempFile("foo.proto", "syntax = \"proto2\";\n"); + + Run("protocol_compiler --null_out=C:\\ " + "--proto_path=$tmpdir foo.proto"); + + ExpectNoErrors(); + ExpectNullCodeGeneratorCalled(""); +} + +TEST_F(CommandLineInterfaceTest, WindowsOutputPathAndParameter) { + // Test that we can have a windows-style output path and a parameter. + + CreateTempFile("foo.proto", "syntax = \"proto2\";\n"); + + Run("protocol_compiler --null_out=bar:C:\\ " + "--proto_path=$tmpdir foo.proto"); + + ExpectNoErrors(); + ExpectNullCodeGeneratorCalled("bar"); +} + +TEST_F(CommandLineInterfaceTest, TrailingBackslash) { + // Test that the directories can end in backslashes. Some users claim this + // doesn't work on their system. + + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); + + Run("protocol_compiler --test_out=$tmpdir\\ " + "--proto_path=$tmpdir\\ foo.proto"); + + ExpectNoErrors(); + ExpectGenerated("test_generator", "", "foo.proto", "Foo"); +} + +TEST_F(CommandLineInterfaceTest, Win32ErrorMessage) { + EXPECT_EQ("The system cannot find the file specified.\r\n", + Subprocess::Win32ErrorMessage(ERROR_FILE_NOT_FOUND)); +} + +#endif // defined(_WIN32) || defined(__CYGWIN__) + +TEST_F(CommandLineInterfaceTest, PathLookup) { + // Test that specifying multiple directories in the proto search path works. + + CreateTempFile("b/bar.proto", + "syntax = \"proto2\";\n" + "message Bar {}\n"); + CreateTempFile("a/foo.proto", + "syntax = \"proto2\";\n" + "import \"bar.proto\";\n" + "message Foo {\n" + " optional Bar a = 1;\n" + "}\n"); + CreateTempFile("b/foo.proto", "this should not be parsed\n"); + + Run("protocol_compiler --test_out=$tmpdir " + "--proto_path=$tmpdir/a --proto_path=$tmpdir/b foo.proto"); + + ExpectNoErrors(); + ExpectGenerated("test_generator", "", "foo.proto", "Foo"); +} + +TEST_F(CommandLineInterfaceTest, ColonDelimitedPath) { + // Same as PathLookup, but we provide the proto_path in a single flag. + + CreateTempFile("b/bar.proto", + "syntax = \"proto2\";\n" + "message Bar {}\n"); + CreateTempFile("a/foo.proto", + "syntax = \"proto2\";\n" + "import \"bar.proto\";\n" + "message Foo {\n" + " optional Bar a = 1;\n" + "}\n"); + CreateTempFile("b/foo.proto", "this should not be parsed\n"); + + Run(strings::Substitute( + "protocol_compiler --test_out=$$tmpdir --proto_path=$0 foo.proto", + std::string("$tmpdir/a") + CommandLineInterface::kPathSeparator + + "$tmpdir/b")); + + ExpectNoErrors(); + ExpectGenerated("test_generator", "", "foo.proto", "Foo"); +} + +TEST_F(CommandLineInterfaceTest, NonRootMapping) { + // Test setting up a search path mapping a directory to a non-root location. + + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); + + Run("protocol_compiler --test_out=$tmpdir " + "--proto_path=bar=$tmpdir bar/foo.proto"); + + ExpectNoErrors(); + ExpectGenerated("test_generator", "", "bar/foo.proto", "Foo"); +} + +TEST_F(CommandLineInterfaceTest, PathWithEqualsSign) { + // Test setting up a search path which happens to have '=' in it. + + CreateTempDir("with=sign"); + CreateTempFile("with=sign/foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); + + Run("protocol_compiler --test_out=$tmpdir " + "--proto_path=$tmpdir/with=sign foo.proto"); + + ExpectNoErrors(); + ExpectGenerated("test_generator", "", "foo.proto", "Foo"); +} + +TEST_F(CommandLineInterfaceTest, MultipleGenerators) { + // Test that we can have multiple generators and use both in one invocation, + // each with a different output directory. + + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); + // Create the "a" and "b" sub-directories. + CreateTempDir("a"); + CreateTempDir("b"); + + Run("protocol_compiler " + "--test_out=$tmpdir/a " + "--alt_out=$tmpdir/b " + "--proto_path=$tmpdir foo.proto"); + + ExpectNoErrors(); + ExpectGenerated("test_generator", "", "foo.proto", "Foo", "a"); + ExpectGenerated("alt_generator", "", "foo.proto", "Foo", "b"); +} + +TEST_F(CommandLineInterfaceTest, DisallowServicesNoServices) { + // Test that --disallow_services doesn't cause a problem when there are no + // services. + + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); + + Run("protocol_compiler --disallow_services --test_out=$tmpdir " + "--proto_path=$tmpdir foo.proto"); + + ExpectNoErrors(); + ExpectGenerated("test_generator", "", "foo.proto", "Foo"); +} + +TEST_F(CommandLineInterfaceTest, DisallowServicesHasService) { + // Test that --disallow_services produces an error when there are services. + + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n" + "service Bar {}\n"); + + Run("protocol_compiler --disallow_services --test_out=$tmpdir " + "--proto_path=$tmpdir foo.proto"); + + ExpectErrorSubstring("foo.proto: This file contains services"); +} + +TEST_F(CommandLineInterfaceTest, AllowServicesHasService) { + // Test that services work fine as long as --disallow_services is not used. + + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n" + "service Bar {}\n"); + + Run("protocol_compiler --test_out=$tmpdir " + "--proto_path=$tmpdir foo.proto"); + + ExpectNoErrors(); + ExpectGenerated("test_generator", "", "foo.proto", "Foo"); +} + + +TEST_F(CommandLineInterfaceTest, DirectDependencies_Missing_EmptyList) { + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "import \"bar.proto\";\n" + "message Foo { optional Bar bar = 1; }"); + CreateTempFile("bar.proto", + "syntax = \"proto2\";\n" + "message Bar { optional string text = 1; }"); + + Run("protocol_compiler --test_out=$tmpdir --proto_path=$tmpdir " + "--direct_dependencies= foo.proto"); + + ExpectErrorText( + "foo.proto: File is imported but not declared in --direct_dependencies: " + "bar.proto\n"); +} + +TEST_F(CommandLineInterfaceTest, DirectDependencies_Missing) { + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "import \"bar.proto\";\n" + "import \"bla.proto\";\n" + "message Foo { optional Bar bar = 1; optional Bla bla = 2; }"); + CreateTempFile("bar.proto", + "syntax = \"proto2\";\n" + "message Bar { optional string text = 1; }"); + CreateTempFile("bla.proto", + "syntax = \"proto2\";\n" + "message Bla { optional int64 number = 1; }"); + + Run("protocol_compiler --test_out=$tmpdir --proto_path=$tmpdir " + "--direct_dependencies=bla.proto foo.proto"); + + ExpectErrorText( + "foo.proto: File is imported but not declared in --direct_dependencies: " + "bar.proto\n"); +} + +TEST_F(CommandLineInterfaceTest, DirectDependencies_NoViolation) { + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "import \"bar.proto\";\n" + "message Foo { optional Bar bar = 1; }"); + CreateTempFile("bar.proto", + "syntax = \"proto2\";\n" + "message Bar { optional string text = 1; }"); + + Run("protocol_compiler --test_out=$tmpdir --proto_path=$tmpdir " + "--direct_dependencies=bar.proto foo.proto"); + + ExpectNoErrors(); +} + +TEST_F(CommandLineInterfaceTest, DirectDependencies_NoViolation_MultiImports) { + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "import \"bar.proto\";\n" + "import \"bla.proto\";\n" + "message Foo { optional Bar bar = 1; optional Bla bla = 2; }"); + CreateTempFile("bar.proto", + "syntax = \"proto2\";\n" + "message Bar { optional string text = 1; }"); + CreateTempFile("bla.proto", + "syntax = \"proto2\";\n" + "message Bla { optional int64 number = 1; }"); + + Run("protocol_compiler --test_out=$tmpdir --proto_path=$tmpdir " + "--direct_dependencies=bar.proto:bla.proto foo.proto"); + + ExpectNoErrors(); +} + +TEST_F(CommandLineInterfaceTest, DirectDependencies_ProvidedMultipleTimes) { + CreateTempFile("foo.proto", "syntax = \"proto2\";\n"); + + Run("protocol_compiler --test_out=$tmpdir --proto_path=$tmpdir " + "--direct_dependencies=bar.proto --direct_dependencies=bla.proto " + "foo.proto"); + + ExpectErrorText( + "--direct_dependencies may only be passed once. To specify multiple " + "direct dependencies, pass them all as a single parameter separated by " + "':'.\n"); +} + +TEST_F(CommandLineInterfaceTest, DirectDependencies_CustomErrorMessage) { + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "import \"bar.proto\";\n" + "message Foo { optional Bar bar = 1; }"); + CreateTempFile("bar.proto", + "syntax = \"proto2\";\n" + "message Bar { optional string text = 1; }"); + + std::vector<std::string> commands; + commands.push_back("protocol_compiler"); + commands.push_back("--test_out=$tmpdir"); + commands.push_back("--proto_path=$tmpdir"); + commands.push_back("--direct_dependencies="); + commands.push_back("--direct_dependencies_violation_msg=Bla \"%s\" Bla"); + commands.push_back("foo.proto"); + RunWithArgs(commands); + + ExpectErrorText("foo.proto: Bla \"bar.proto\" Bla\n"); +} + +TEST_F(CommandLineInterfaceTest, CwdRelativeInputs) { + // Test that we can accept working-directory-relative input files. + + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); + + Run("protocol_compiler --test_out=$tmpdir " + "--proto_path=$tmpdir $tmpdir/foo.proto"); + + ExpectNoErrors(); + ExpectGenerated("test_generator", "", "foo.proto", "Foo"); +} + +TEST_F(CommandLineInterfaceTest, WriteDescriptorSet) { + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); + CreateTempFile("bar.proto", + "syntax = \"proto2\";\n" + "import \"foo.proto\";\n" + "message Bar {\n" + " optional Foo foo = 1;\n" + "}\n"); + + Run("protocol_compiler --descriptor_set_out=$tmpdir/descriptor_set " + "--proto_path=$tmpdir bar.proto"); + + ExpectNoErrors(); + + FileDescriptorSet descriptor_set; + ReadDescriptorSet("descriptor_set", &descriptor_set); + if (HasFatalFailure()) return; + EXPECT_EQ(1, descriptor_set.file_size()); + EXPECT_EQ("bar.proto", descriptor_set.file(0).name()); + // Descriptor set should not have source code info. + EXPECT_FALSE(descriptor_set.file(0).has_source_code_info()); + // Descriptor set should have json_name. + EXPECT_EQ("Bar", descriptor_set.file(0).message_type(0).name()); + EXPECT_EQ("foo", descriptor_set.file(0).message_type(0).field(0).name()); + EXPECT_TRUE(descriptor_set.file(0).message_type(0).field(0).has_json_name()); +} + +TEST_F(CommandLineInterfaceTest, WriteDescriptorSetWithDuplicates) { + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); + CreateTempFile("bar.proto", + "syntax = \"proto2\";\n" + "import \"foo.proto\";\n" + "message Bar {\n" + " optional Foo foo = 1;\n" + "}\n"); + CreateTempFile("baz.proto", + "syntax = \"proto2\";\n" + "import \"foo.proto\";\n" + "message Baz {\n" + " optional Foo foo = 1;\n" + "}\n"); + + Run("protocol_compiler --descriptor_set_out=$tmpdir/descriptor_set " + "--proto_path=$tmpdir bar.proto foo.proto bar.proto baz.proto"); + + ExpectNoErrors(); + + FileDescriptorSet descriptor_set; + ReadDescriptorSet("descriptor_set", &descriptor_set); + if (HasFatalFailure()) return; + EXPECT_EQ(3, descriptor_set.file_size()); + // foo should come first since the output is in dependency order. + // since bar and baz are unordered, they should be in command line order. + EXPECT_EQ("foo.proto", descriptor_set.file(0).name()); + EXPECT_EQ("bar.proto", descriptor_set.file(1).name()); + EXPECT_EQ("baz.proto", descriptor_set.file(2).name()); + // Descriptor set should not have source code info. + EXPECT_FALSE(descriptor_set.file(0).has_source_code_info()); + // Descriptor set should have json_name. + EXPECT_EQ("Bar", descriptor_set.file(1).message_type(0).name()); + EXPECT_EQ("foo", descriptor_set.file(1).message_type(0).field(0).name()); + EXPECT_TRUE(descriptor_set.file(1).message_type(0).field(0).has_json_name()); +} + +TEST_F(CommandLineInterfaceTest, WriteDescriptorSetWithSourceInfo) { + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); + CreateTempFile("bar.proto", + "syntax = \"proto2\";\n" + "import \"foo.proto\";\n" + "message Bar {\n" + " optional Foo foo = 1;\n" + "}\n"); + + Run("protocol_compiler --descriptor_set_out=$tmpdir/descriptor_set " + "--include_source_info --proto_path=$tmpdir bar.proto"); + + ExpectNoErrors(); + + FileDescriptorSet descriptor_set; + ReadDescriptorSet("descriptor_set", &descriptor_set); + if (HasFatalFailure()) return; + EXPECT_EQ(1, descriptor_set.file_size()); + EXPECT_EQ("bar.proto", descriptor_set.file(0).name()); + // Source code info included. + EXPECT_TRUE(descriptor_set.file(0).has_source_code_info()); +} + +TEST_F(CommandLineInterfaceTest, WriteTransitiveDescriptorSet) { + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); + CreateTempFile("bar.proto", + "syntax = \"proto2\";\n" + "import \"foo.proto\";\n" + "message Bar {\n" + " optional Foo foo = 1;\n" + "}\n"); + + Run("protocol_compiler --descriptor_set_out=$tmpdir/descriptor_set " + "--include_imports --proto_path=$tmpdir bar.proto"); + + ExpectNoErrors(); + + FileDescriptorSet descriptor_set; + ReadDescriptorSet("descriptor_set", &descriptor_set); + if (HasFatalFailure()) return; + EXPECT_EQ(2, descriptor_set.file_size()); + if (descriptor_set.file(0).name() == "bar.proto") { + std::swap(descriptor_set.mutable_file()->mutable_data()[0], + descriptor_set.mutable_file()->mutable_data()[1]); + } + EXPECT_EQ("foo.proto", descriptor_set.file(0).name()); + EXPECT_EQ("bar.proto", descriptor_set.file(1).name()); + // Descriptor set should not have source code info. + EXPECT_FALSE(descriptor_set.file(0).has_source_code_info()); + EXPECT_FALSE(descriptor_set.file(1).has_source_code_info()); +} + +TEST_F(CommandLineInterfaceTest, WriteTransitiveDescriptorSetWithSourceInfo) { + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); + CreateTempFile("bar.proto", + "syntax = \"proto2\";\n" + "import \"foo.proto\";\n" + "message Bar {\n" + " optional Foo foo = 1;\n" + "}\n"); + + Run("protocol_compiler --descriptor_set_out=$tmpdir/descriptor_set " + "--include_imports --include_source_info --proto_path=$tmpdir bar.proto"); + + ExpectNoErrors(); + + FileDescriptorSet descriptor_set; + ReadDescriptorSet("descriptor_set", &descriptor_set); + if (HasFatalFailure()) return; + EXPECT_EQ(2, descriptor_set.file_size()); + if (descriptor_set.file(0).name() == "bar.proto") { + std::swap(descriptor_set.mutable_file()->mutable_data()[0], + descriptor_set.mutable_file()->mutable_data()[1]); + } + EXPECT_EQ("foo.proto", descriptor_set.file(0).name()); + EXPECT_EQ("bar.proto", descriptor_set.file(1).name()); + // Source code info included. + EXPECT_TRUE(descriptor_set.file(0).has_source_code_info()); + EXPECT_TRUE(descriptor_set.file(1).has_source_code_info()); +} + +#ifdef _WIN32 +// TODO(teboring): Figure out how to write test on windows. +#else +TEST_F(CommandLineInterfaceTest, WriteDependencyManifestFileGivenTwoInputs) { + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); + CreateTempFile("bar.proto", + "syntax = \"proto2\";\n" + "import \"foo.proto\";\n" + "message Bar {\n" + " optional Foo foo = 1;\n" + "}\n"); + + Run("protocol_compiler --dependency_out=$tmpdir/manifest " + "--test_out=$tmpdir --proto_path=$tmpdir bar.proto foo.proto"); + + ExpectErrorText( + "Can only process one input file when using --dependency_out=FILE.\n"); +} + +#ifdef PROTOBUF_OPENSOURCE +TEST_F(CommandLineInterfaceTest, WriteDependencyManifestFile) { + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); + CreateTempFile("bar.proto", + "syntax = \"proto2\";\n" + "import \"foo.proto\";\n" + "message Bar {\n" + " optional Foo foo = 1;\n" + "}\n"); + + std::string current_working_directory = getcwd(NULL, 0); + SwitchToTempDirectory(); + + Run("protocol_compiler --dependency_out=manifest --test_out=. " + "bar.proto"); + + ExpectNoErrors(); + + ExpectFileContent("manifest", + "bar.proto.MockCodeGenerator.test_generator: " + "foo.proto\\\n bar.proto"); + + File::ChangeWorkingDirectory(current_working_directory); +} +#else // !PROTOBUF_OPENSOURCE +// TODO(teboring): Figure out how to change and get working directory in +// google3. +#endif // !PROTOBUF_OPENSOURCE + +TEST_F(CommandLineInterfaceTest, WriteDependencyManifestFileForAbsolutePath) { + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); + CreateTempFile("bar.proto", + "syntax = \"proto2\";\n" + "import \"foo.proto\";\n" + "message Bar {\n" + " optional Foo foo = 1;\n" + "}\n"); + + Run("protocol_compiler --dependency_out=$tmpdir/manifest " + "--test_out=$tmpdir --proto_path=$tmpdir bar.proto"); + + ExpectNoErrors(); + + ExpectFileContent("manifest", + "$tmpdir/bar.proto.MockCodeGenerator.test_generator: " + "$tmpdir/foo.proto\\\n $tmpdir/bar.proto"); +} +#endif // !_WIN32 + +TEST_F(CommandLineInterfaceTest, TestArgumentFile) { + // Test parsing multiple input files using an argument file. + + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); + CreateTempFile("bar.proto", + "syntax = \"proto2\";\n" + "message Bar {}\n"); + CreateTempFile("arguments.txt", + "--test_out=$tmpdir\n" + "--plug_out=$tmpdir\n" + "--proto_path=$tmpdir\n" + "--direct_dependencies_violation_msg=%s is not imported\n" + "foo.proto\n" + "bar.proto"); + + Run("protocol_compiler @$tmpdir/arguments.txt"); + + ExpectNoErrors(); + ExpectGeneratedWithMultipleInputs("test_generator", "foo.proto,bar.proto", + "foo.proto", "Foo"); + ExpectGeneratedWithMultipleInputs("test_generator", "foo.proto,bar.proto", + "bar.proto", "Bar"); + ExpectGeneratedWithMultipleInputs("test_plugin", "foo.proto,bar.proto", + "foo.proto", "Foo"); + ExpectGeneratedWithMultipleInputs("test_plugin", "foo.proto,bar.proto", + "bar.proto", "Bar"); +} + + +// ------------------------------------------------------------------- + +TEST_F(CommandLineInterfaceTest, ParseErrors) { + // Test that parse errors are reported. + + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "badsyntax\n"); + + Run("protocol_compiler --test_out=$tmpdir " + "--proto_path=$tmpdir foo.proto"); + + ExpectErrorText( + "foo.proto:2:1: Expected top-level statement (e.g. \"message\").\n"); +} + +TEST_F(CommandLineInterfaceTest, ParseErrors_DescriptorSetIn) { + // Test that parse errors are reported. + CreateTempFile("foo.bin", "not a FileDescriptorSet"); + + Run("protocol_compiler --test_out=$tmpdir " + "--descriptor_set_in=$tmpdir/foo.bin foo.proto"); + + ExpectErrorText("$tmpdir/foo.bin: Unable to parse.\n"); +} + +TEST_F(CommandLineInterfaceTest, ParseErrorsMultipleFiles) { + // Test that parse errors are reported from multiple files. + + // We set up files such that foo.proto actually depends on bar.proto in + // two ways: Directly and through baz.proto. bar.proto's errors should + // only be reported once. + CreateTempFile("bar.proto", + "syntax = \"proto2\";\n" + "badsyntax\n"); + CreateTempFile("baz.proto", + "syntax = \"proto2\";\n" + "import \"bar.proto\";\n"); + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "import \"bar.proto\";\n" + "import \"baz.proto\";\n"); + + Run("protocol_compiler --test_out=$tmpdir " + "--proto_path=$tmpdir foo.proto"); + + ExpectErrorText( + "bar.proto:2:1: Expected top-level statement (e.g. \"message\").\n" + "baz.proto:2:1: Import \"bar.proto\" was not found or had errors.\n" + "foo.proto:2:1: Import \"bar.proto\" was not found or had errors.\n" + "foo.proto:3:1: Import \"baz.proto\" was not found or had errors.\n"); +} + +TEST_F(CommandLineInterfaceTest, RecursiveImportFails) { + // Create a proto file that imports itself. + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "import \"foo.proto\";\n"); + + Run("protocol_compiler --test_out=$tmpdir " + "--proto_path=$tmpdir foo.proto"); + + ExpectErrorSubstring( + "foo.proto:2:1: File recursively imports itself: " + "foo.proto -> foo.proto\n"); +} + +TEST_F(CommandLineInterfaceTest, InputNotFoundError) { + // Test what happens if the input file is not found. + + Run("protocol_compiler --test_out=$tmpdir " + "--proto_path=$tmpdir foo.proto"); + + ExpectErrorText( + "Could not make proto path relative: foo.proto: No such file or " + "directory\n"); +} + +TEST_F(CommandLineInterfaceTest, InputNotFoundError_DescriptorSetIn) { + // Test what happens if the input file is not found. + + Run("protocol_compiler --test_out=$tmpdir " + "--descriptor_set_in=$tmpdir/foo.bin foo.proto"); + + ExpectErrorText("$tmpdir/foo.bin: No such file or directory\n"); +} + +TEST_F(CommandLineInterfaceTest, CwdRelativeInputNotFoundError) { + // Test what happens when a working-directory-relative input file is not + // found. + + Run("protocol_compiler --test_out=$tmpdir " + "--proto_path=$tmpdir $tmpdir/foo.proto"); + + ExpectErrorText( + "Could not make proto path relative: $tmpdir/foo.proto: No such file or " + "directory\n"); +} + +TEST_F(CommandLineInterfaceTest, CwdRelativeInputNotMappedError) { + // Test what happens when a working-directory-relative input file is not + // mapped to a virtual path. + + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); + + // Create a directory called "bar" so that we can point --proto_path at it. + CreateTempFile("bar/dummy", ""); + + Run("protocol_compiler --test_out=$tmpdir " + "--proto_path=$tmpdir/bar $tmpdir/foo.proto"); + + ExpectErrorText( + "$tmpdir/foo.proto: File does not reside within any path " + "specified using --proto_path (or -I). You must specify a " + "--proto_path which encompasses this file. Note that the " + "proto_path must be an exact prefix of the .proto file " + "names -- protoc is too dumb to figure out when two paths " + "(e.g. absolute and relative) are equivalent (it's harder " + "than you think).\n"); +} + +TEST_F(CommandLineInterfaceTest, CwdRelativeInputNotFoundAndNotMappedError) { + // Check what happens if the input file is not found *and* is not mapped + // in the proto_path. + + // Create a directory called "bar" so that we can point --proto_path at it. + CreateTempFile("bar/dummy", ""); + + Run("protocol_compiler --test_out=$tmpdir " + "--proto_path=$tmpdir/bar $tmpdir/foo.proto"); + + ExpectErrorText( + "Could not make proto path relative: $tmpdir/foo.proto: No such file or " + "directory\n"); +} + +TEST_F(CommandLineInterfaceTest, CwdRelativeInputShadowedError) { + // Test what happens when a working-directory-relative input file is shadowed + // by another file in the virtual path. + + CreateTempFile("foo/foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); + CreateTempFile("bar/foo.proto", + "syntax = \"proto2\";\n" + "message Bar {}\n"); + + Run("protocol_compiler --test_out=$tmpdir " + "--proto_path=$tmpdir/foo --proto_path=$tmpdir/bar " + "$tmpdir/bar/foo.proto"); + + ExpectErrorText( + "$tmpdir/bar/foo.proto: Input is shadowed in the --proto_path " + "by \"$tmpdir/foo/foo.proto\". Either use the latter " + "file as your input or reorder the --proto_path so that the " + "former file's location comes first.\n"); +} + +TEST_F(CommandLineInterfaceTest, ProtoPathNotFoundError) { + // Test what happens if the input file is not found. + + Run("protocol_compiler --test_out=$tmpdir " + "--proto_path=$tmpdir/foo foo.proto"); + + ExpectErrorText( + "$tmpdir/foo: warning: directory does not exist.\n" + "Could not make proto path relative: foo.proto: No such file or " + "directory\n"); +} + +TEST_F(CommandLineInterfaceTest, ProtoPathAndDescriptorSetIn) { + Run("protocol_compiler --test_out=$tmpdir " + "--proto_path=$tmpdir --descriptor_set_in=$tmpdir/foo.bin foo.proto"); + ExpectErrorText("$tmpdir/foo.bin: No such file or directory\n"); + + Run("protocol_compiler --test_out=$tmpdir " + "--descriptor_set_in=$tmpdir/foo.bin --proto_path=$tmpdir foo.proto"); + ExpectErrorText("$tmpdir/foo.bin: No such file or directory\n"); +} + +TEST_F(CommandLineInterfaceTest, ProtoPathAndDescriptorSetIn_CompileFiles) { + // Test what happens if a proto is in a --descriptor_set_in and also exists + // on disk. + FileDescriptorSet file_descriptor_set; + + // NOTE: This file desc SHOULD be different from the one created as a temp + // to make it easier to test that the file was output instead of the + // contents of the --descriptor_set_in file. + FileDescriptorProto* file_descriptor_proto = file_descriptor_set.add_file(); + file_descriptor_proto->set_name("foo.proto"); + file_descriptor_proto->add_message_type()->set_name("Foo"); + + WriteDescriptorSet("foo.bin", &file_descriptor_set); + + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message FooBar { required string foo_message = 1; }\n"); + + Run("protocol_compiler --descriptor_set_out=$tmpdir/descriptor_set " + "--descriptor_set_in=$tmpdir/foo.bin " + "--include_source_info " + "--proto_path=$tmpdir foo.proto"); + + ExpectNoErrors(); + + FileDescriptorSet descriptor_set; + ReadDescriptorSet("descriptor_set", &descriptor_set); + + EXPECT_EQ(1, descriptor_set.file_size()); + EXPECT_EQ("foo.proto", descriptor_set.file(0).name()); + // Descriptor set SHOULD have source code info. + EXPECT_TRUE(descriptor_set.file(0).has_source_code_info()); + + EXPECT_EQ("FooBar", descriptor_set.file(0).message_type(0).name()); + EXPECT_EQ("foo_message", + descriptor_set.file(0).message_type(0).field(0).name()); +} + +TEST_F(CommandLineInterfaceTest, ProtoPathAndDependencyOut) { + Run("protocol_compiler --test_out=$tmpdir " + "--dependency_out=$tmpdir/manifest " + "--descriptor_set_in=$tmpdir/foo.bin foo.proto"); + ExpectErrorText( + "--descriptor_set_in cannot be used with --dependency_out.\n"); + + Run("protocol_compiler --test_out=$tmpdir " + "--descriptor_set_in=$tmpdir/foo.bin " + "--dependency_out=$tmpdir/manifest foo.proto"); + ExpectErrorText( + "--dependency_out cannot be used with --descriptor_set_in.\n"); +} + +TEST_F(CommandLineInterfaceTest, MissingInputError) { + // Test that we get an error if no inputs are given. + + Run("protocol_compiler --test_out=$tmpdir " + "--proto_path=$tmpdir"); + + ExpectErrorText("Missing input file.\n"); +} + +TEST_F(CommandLineInterfaceTest, MissingOutputError) { + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); + + Run("protocol_compiler --proto_path=$tmpdir foo.proto"); + + ExpectErrorText("Missing output directives.\n"); +} + +TEST_F(CommandLineInterfaceTest, OutputWriteError) { + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); + + std::string output_file = + MockCodeGenerator::GetOutputFileName("test_generator", "foo.proto"); + + // Create a directory blocking our output location. + CreateTempDir(output_file); + + Run("protocol_compiler --test_out=$tmpdir " + "--proto_path=$tmpdir foo.proto"); + + // MockCodeGenerator no longer detects an error because we actually write to + // an in-memory location first, then dump to disk at the end. This is no + // big deal. + // ExpectErrorSubstring("MockCodeGenerator detected write error."); + +#if defined(_WIN32) && !defined(__CYGWIN__) + // Windows with MSVCRT.dll produces EPERM instead of EISDIR. + if (HasAlternateErrorSubstring(output_file + ": Permission denied")) { + return; + } +#endif + + ExpectErrorSubstring(output_file + ": Is a directory"); +} + +TEST_F(CommandLineInterfaceTest, PluginOutputWriteError) { + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); + + std::string output_file = + MockCodeGenerator::GetOutputFileName("test_plugin", "foo.proto"); + + // Create a directory blocking our output location. + CreateTempDir(output_file); + + Run("protocol_compiler --plug_out=$tmpdir " + "--proto_path=$tmpdir foo.proto"); + +#if defined(_WIN32) && !defined(__CYGWIN__) + // Windows with MSVCRT.dll produces EPERM instead of EISDIR. + if (HasAlternateErrorSubstring(output_file + ": Permission denied")) { + return; + } +#endif + + ExpectErrorSubstring(output_file + ": Is a directory"); +} + +TEST_F(CommandLineInterfaceTest, OutputDirectoryNotFoundError) { + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); + + Run("protocol_compiler --test_out=$tmpdir/nosuchdir " + "--proto_path=$tmpdir foo.proto"); + + ExpectErrorSubstring("nosuchdir/: No such file or directory"); +} + +TEST_F(CommandLineInterfaceTest, PluginOutputDirectoryNotFoundError) { + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); + + Run("protocol_compiler --plug_out=$tmpdir/nosuchdir " + "--proto_path=$tmpdir foo.proto"); + + ExpectErrorSubstring("nosuchdir/: No such file or directory"); +} + +TEST_F(CommandLineInterfaceTest, OutputDirectoryIsFileError) { + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); + + Run("protocol_compiler --test_out=$tmpdir/foo.proto " + "--proto_path=$tmpdir foo.proto"); + +#if defined(_WIN32) && !defined(__CYGWIN__) + // Windows with MSVCRT.dll produces EINVAL instead of ENOTDIR. + if (HasAlternateErrorSubstring("foo.proto/: Invalid argument")) { + return; + } +#endif + + ExpectErrorSubstring("foo.proto/: Not a directory"); +} + +TEST_F(CommandLineInterfaceTest, GeneratorError) { + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message MockCodeGenerator_Error {}\n"); + + Run("protocol_compiler --test_out=$tmpdir " + "--proto_path=$tmpdir foo.proto"); + + ExpectErrorSubstring( + "--test_out: foo.proto: Saw message type MockCodeGenerator_Error."); +} + +TEST_F(CommandLineInterfaceTest, GeneratorPluginError) { + // Test a generator plugin that returns an error. + + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message MockCodeGenerator_Error {}\n"); + + Run("protocol_compiler --plug_out=TestParameter:$tmpdir " + "--proto_path=$tmpdir foo.proto"); + + ExpectErrorSubstring( + "--plug_out: foo.proto: Saw message type MockCodeGenerator_Error."); +} + +TEST_F(CommandLineInterfaceTest, GeneratorPluginFail) { + // Test a generator plugin that exits with an error code. + + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message MockCodeGenerator_Exit {}\n"); + + Run("protocol_compiler --plug_out=TestParameter:$tmpdir " + "--proto_path=$tmpdir foo.proto"); + + ExpectErrorSubstring("Saw message type MockCodeGenerator_Exit."); + ExpectErrorSubstring( + "--plug_out: prefix-gen-plug: Plugin failed with status code 123."); +} + +TEST_F(CommandLineInterfaceTest, GeneratorPluginCrash) { + // Test a generator plugin that crashes. + + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message MockCodeGenerator_Abort {}\n"); + + Run("protocol_compiler --plug_out=TestParameter:$tmpdir " + "--proto_path=$tmpdir foo.proto"); + + ExpectErrorSubstring("Saw message type MockCodeGenerator_Abort."); + +#ifdef _WIN32 + // Windows doesn't have signals. It looks like abort()ing causes the process + // to exit with status code 3, but let's not depend on the exact number here. + ExpectErrorSubstring( + "--plug_out: prefix-gen-plug: Plugin failed with status code"); +#else + // Don't depend on the exact signal number. + ExpectErrorSubstring("--plug_out: prefix-gen-plug: Plugin killed by signal"); +#endif +} + +TEST_F(CommandLineInterfaceTest, PluginReceivesSourceCodeInfo) { + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message MockCodeGenerator_HasSourceCodeInfo {}\n"); + + Run("protocol_compiler --plug_out=$tmpdir --proto_path=$tmpdir foo.proto"); + + ExpectErrorSubstring( + "Saw message type MockCodeGenerator_HasSourceCodeInfo: 1."); +} + +TEST_F(CommandLineInterfaceTest, PluginReceivesJsonName) { + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message MockCodeGenerator_HasJsonName {\n" + " optional int32 value = 1;\n" + "}\n"); + + Run("protocol_compiler --plug_out=$tmpdir --proto_path=$tmpdir foo.proto"); + + ExpectErrorSubstring("Saw json_name: 1"); +} + +TEST_F(CommandLineInterfaceTest, PluginReceivesCompilerVersion) { + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message MockCodeGenerator_ShowVersionNumber {\n" + " optional int32 value = 1;\n" + "}\n"); + + Run("protocol_compiler --plug_out=$tmpdir --proto_path=$tmpdir foo.proto"); + + ExpectErrorSubstring(StringPrintf("Saw compiler_version: %d %s", + GOOGLE_PROTOBUF_VERSION, + GOOGLE_PROTOBUF_VERSION_SUFFIX)); +} + +TEST_F(CommandLineInterfaceTest, GeneratorPluginNotFound) { + // Test what happens if the plugin isn't found. + + CreateTempFile("error.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); + + Run("protocol_compiler --badplug_out=TestParameter:$tmpdir " + "--plugin=prefix-gen-badplug=no_such_file " + "--proto_path=$tmpdir error.proto"); + +#ifdef _WIN32 + ExpectErrorSubstring("--badplug_out: prefix-gen-badplug: " + + Subprocess::Win32ErrorMessage(ERROR_FILE_NOT_FOUND)); +#else + // Error written to stdout by child process after exec() fails. + ExpectErrorSubstring("no_such_file: program not found or is not executable"); + + ExpectErrorSubstring( + "Please specify a program using absolute path or make sure " + "the program is available in your PATH system variable"); + + // Error written by parent process when child fails. + ExpectErrorSubstring( + "--badplug_out: prefix-gen-badplug: Plugin failed with status code 1."); +#endif +} + +TEST_F(CommandLineInterfaceTest, GeneratorPluginNotAllowed) { + // Test what happens if plugins aren't allowed. + + CreateTempFile("error.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); + + DisallowPlugins(); + Run("protocol_compiler --plug_out=TestParameter:$tmpdir " + "--proto_path=$tmpdir error.proto"); + + ExpectErrorSubstring("Unknown flag: --plug_out"); +} + +TEST_F(CommandLineInterfaceTest, HelpText) { + Run("test_exec_name --help"); + + ExpectCapturedStdoutSubstringWithZeroReturnCode("Usage: test_exec_name "); + ExpectCapturedStdoutSubstringWithZeroReturnCode("--test_out=OUT_DIR"); + ExpectCapturedStdoutSubstringWithZeroReturnCode("Test output."); + ExpectCapturedStdoutSubstringWithZeroReturnCode("--alt_out=OUT_DIR"); + ExpectCapturedStdoutSubstringWithZeroReturnCode("Alt output."); +} + +TEST_F(CommandLineInterfaceTest, GccFormatErrors) { + // Test --error_format=gcc (which is the default, but we want to verify + // that it can be set explicitly). + + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "badsyntax\n"); + + Run("protocol_compiler --test_out=$tmpdir " + "--proto_path=$tmpdir --error_format=gcc foo.proto"); + + ExpectErrorText( + "foo.proto:2:1: Expected top-level statement (e.g. \"message\").\n"); +} + +TEST_F(CommandLineInterfaceTest, MsvsFormatErrors) { + // Test --error_format=msvs + + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "badsyntax\n"); + + Run("protocol_compiler --test_out=$tmpdir " + "--proto_path=$tmpdir --error_format=msvs foo.proto"); + + ExpectErrorText( + "$tmpdir/foo.proto(2) : error in column=1: Expected top-level statement " + "(e.g. \"message\").\n"); +} + +TEST_F(CommandLineInterfaceTest, InvalidErrorFormat) { + // Test invalid --error_format + + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "badsyntax\n"); + + Run("protocol_compiler --test_out=$tmpdir " + "--proto_path=$tmpdir --error_format=invalid foo.proto"); + + ExpectErrorText("Unknown error format: invalid\n"); +} + +TEST_F(CommandLineInterfaceTest, Warnings) { + // Test --fatal_warnings. + + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "import \"bar.proto\";\n"); + CreateTempFile("bar.proto", "syntax = \"proto2\";\n"); + + Run("protocol_compiler --test_out=$tmpdir " + "--proto_path=$tmpdir foo.proto"); + ExpectCapturedStderrSubstringWithZeroReturnCode( + "foo.proto:2:1: warning: Import bar.proto is unused."); + + Run("protocol_compiler --test_out=$tmpdir --fatal_warnings " + "--proto_path=$tmpdir foo.proto"); + ExpectErrorSubstring("foo.proto:2:1: warning: Import bar.proto is unused."); +} + +// ------------------------------------------------------------------- +// Flag parsing tests + +TEST_F(CommandLineInterfaceTest, ParseSingleCharacterFlag) { + // Test that a single-character flag works. + + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); + + Run("protocol_compiler -t$tmpdir " + "--proto_path=$tmpdir foo.proto"); + + ExpectNoErrors(); + ExpectGenerated("test_generator", "", "foo.proto", "Foo"); +} + +TEST_F(CommandLineInterfaceTest, ParseSpaceDelimitedValue) { + // Test that separating the flag value with a space works. + + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); + + Run("protocol_compiler --test_out $tmpdir " + "--proto_path=$tmpdir foo.proto"); + + ExpectNoErrors(); + ExpectGenerated("test_generator", "", "foo.proto", "Foo"); +} + +TEST_F(CommandLineInterfaceTest, ParseSingleCharacterSpaceDelimitedValue) { + // Test that separating the flag value with a space works for + // single-character flags. + + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); + + Run("protocol_compiler -t $tmpdir " + "--proto_path=$tmpdir foo.proto"); + + ExpectNoErrors(); + ExpectGenerated("test_generator", "", "foo.proto", "Foo"); +} + +TEST_F(CommandLineInterfaceTest, MissingValueError) { + // Test that we get an error if a flag is missing its value. + + Run("protocol_compiler --test_out --proto_path=$tmpdir foo.proto"); + + ExpectErrorText("Missing value for flag: --test_out\n"); +} + +TEST_F(CommandLineInterfaceTest, MissingValueAtEndError) { + // Test that we get an error if the last argument is a flag requiring a + // value. + + Run("protocol_compiler --test_out"); + + ExpectErrorText("Missing value for flag: --test_out\n"); +} + +TEST_F(CommandLineInterfaceTest, Proto3OptionalDisallowedNoCodegenSupport) { + CreateTempFile("google/foo.proto", + "syntax = \"proto3\";\n" + "message Foo {\n" + " optional int32 i = 1;\n" + "}\n"); + + CreateGeneratorWithMissingFeatures("--no_proto3_optional_out", + "Doesn't support proto3 optional", + CodeGenerator::FEATURE_PROTO3_OPTIONAL); + + Run("protocol_compiler --experimental_allow_proto3_optional " + "--proto_path=$tmpdir google/foo.proto --no_proto3_optional_out=$tmpdir"); + + ExpectErrorSubstring( + "code generator --no_proto3_optional_out hasn't been updated to support " + "optional fields in proto3"); +} + +TEST_F(CommandLineInterfaceTest, Proto3OptionalAllowWithFlag) { + CreateTempFile("google/foo.proto", + "syntax = \"proto3\";\n" + "message Foo {\n" + " optional int32 i = 1;\n" + "}\n"); + + Run("protocol_compiler --experimental_allow_proto3_optional " + "--proto_path=$tmpdir google/foo.proto --test_out=$tmpdir"); + ExpectNoErrors(); +} + +TEST_F(CommandLineInterfaceTest, PrintFreeFieldNumbers) { + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "package foo;\n" + "message Foo {\n" + " optional int32 a = 2;\n" + " optional string b = 4;\n" + " optional string c = 5;\n" + " optional int64 d = 8;\n" + " optional double e = 10;\n" + "}\n"); + CreateTempFile("bar.proto", + "syntax = \"proto2\";\n" + "message Bar {\n" + " optional int32 a = 2;\n" + " extensions 4 to 5;\n" + " optional int64 d = 8;\n" + " extensions 10;\n" + "}\n"); + CreateTempFile("baz.proto", + "syntax = \"proto2\";\n" + "message Baz {\n" + " optional int32 a = 2;\n" + " optional int64 d = 8;\n" + " extensions 15 to max;\n" // unordered. + " extensions 13;\n" + " extensions 10 to 12;\n" + " extensions 5;\n" + " extensions 4;\n" + "}\n"); + CreateTempFile( + "quz.proto", + "syntax = \"proto2\";\n" + "message Quz {\n" + " message Foo {}\n" // nested message + " optional int32 a = 2;\n" + " optional group C = 4 {\n" + " optional int32 d = 5;\n" + " }\n" + " extensions 8 to 10;\n" + " optional group E = 11 {\n" + " optional int32 f = 9;\n" // explicitly reuse extension range 8-10 + " optional group G = 15 {\n" // nested group + " message Foo {}\n" // nested message inside nested group + " }\n" + " }\n" + "}\n"); + + Run("protocol_compiler --print_free_field_numbers --proto_path=$tmpdir " + "foo.proto bar.proto baz.proto quz.proto"); + + ExpectNoErrors(); + + // TODO(jieluo): Cygwin doesn't work well if we try to capture stderr and + // stdout at the same time. Need to figure out why and add this test back + // for Cygwin. +#if !defined(__CYGWIN__) + ExpectCapturedStdout( + "foo.Foo free: 1 3 6-7 9 11-INF\n" + "Bar free: 1 3 6-7 9 11-INF\n" + "Baz free: 1 3 6-7 9 14\n" + "Quz.Foo free: 1-INF\n" + "Quz.E.G.Foo free: 1-INF\n" + "Quz free: 1 3 6-7 12-14 16-INF\n"); +#endif +} + +// =================================================================== + +// Test for --encode and --decode. Note that it would be easier to do this +// test as a shell script, but we'd like to be able to run the test on +// platforms that don't have a Bourne-compatible shell available (especially +// Windows/MSVC). + +enum EncodeDecodeTestMode { PROTO_PATH, DESCRIPTOR_SET_IN }; + +class EncodeDecodeTest : public testing::TestWithParam<EncodeDecodeTestMode> { + protected: + virtual void SetUp() { + WriteUnittestProtoDescriptorSet(); + duped_stdin_ = dup(STDIN_FILENO); + } + + virtual void TearDown() { + dup2(duped_stdin_, STDIN_FILENO); + close(duped_stdin_); + } + + void RedirectStdinFromText(const std::string& input) { + std::string filename = TestTempDir() + "/test_stdin"; + GOOGLE_CHECK_OK(File::SetContents(filename, input, true)); + GOOGLE_CHECK(RedirectStdinFromFile(filename)); + } + + bool RedirectStdinFromFile(const std::string& filename) { + int fd = open(filename.c_str(), O_RDONLY); + if (fd < 0) return false; + dup2(fd, STDIN_FILENO); + close(fd); + return true; + } + + // Remove '\r' characters from text. + std::string StripCR(const std::string& text) { + std::string result; + + for (int i = 0; i < text.size(); i++) { + if (text[i] != '\r') { + result.push_back(text[i]); + } + } + + return result; + } + + enum Type { TEXT, BINARY }; + enum ReturnCode { SUCCESS, ERROR }; + + bool Run(const std::string& command, bool specify_proto_files = true) { + std::vector<std::string> args; + args.push_back("protoc"); + for (StringPiece split_piece : + Split(command, " ", true)) { + args.push_back(std::string(split_piece)); + } + if (specify_proto_files) { + switch (GetParam()) { + case PROTO_PATH: + args.push_back("--proto_path=" + TestUtil::TestSourceDir()); + break; + case DESCRIPTOR_SET_IN: + args.push_back(StrCat("--descriptor_set_in=", + unittest_proto_descriptor_set_filename_)); + break; + default: + ADD_FAILURE() << "unexpected EncodeDecodeTestMode: " << GetParam(); + } + } + + std::unique_ptr<const char*[]> argv(new const char*[args.size()]); + for (int i = 0; i < args.size(); i++) { + argv[i] = args[i].c_str(); + } + + CommandLineInterface cli; + + CaptureTestStdout(); + CaptureTestStderr(); + + int result = cli.Run(args.size(), argv.get()); + + captured_stdout_ = GetCapturedTestStdout(); + captured_stderr_ = GetCapturedTestStderr(); + + return result == 0; + } + + void ExpectStdoutMatchesBinaryFile(const std::string& filename) { + std::string expected_output; + GOOGLE_CHECK_OK(File::GetContents(filename, &expected_output, true)); + + // Don't use EXPECT_EQ because we don't want to print raw binary data to + // stdout on failure. + EXPECT_TRUE(captured_stdout_ == expected_output); + } + + void ExpectStdoutMatchesTextFile(const std::string& filename) { + std::string expected_output; + GOOGLE_CHECK_OK(File::GetContents(filename, &expected_output, true)); + + ExpectStdoutMatchesText(expected_output); + } + + void ExpectStdoutMatchesText(const std::string& expected_text) { + EXPECT_EQ(StripCR(expected_text), StripCR(captured_stdout_)); + } + + void ExpectStderrMatchesText(const std::string& expected_text) { + EXPECT_EQ(StripCR(expected_text), StripCR(captured_stderr_)); + } + + void ExpectStderrContainsText(const std::string& expected_text) { + EXPECT_NE(StripCR(captured_stderr_).find(StripCR(expected_text)), + std::string::npos); + } + + private: + void WriteUnittestProtoDescriptorSet() { + unittest_proto_descriptor_set_filename_ = + TestTempDir() + "/unittest_proto_descriptor_set.bin"; + FileDescriptorSet file_descriptor_set; + protobuf_unittest::TestAllTypes test_all_types; + test_all_types.descriptor()->file()->CopyTo(file_descriptor_set.add_file()); + + protobuf_unittest_import::ImportMessage import_message; + import_message.descriptor()->file()->CopyTo(file_descriptor_set.add_file()); + + protobuf_unittest_import::PublicImportMessage public_import_message; + public_import_message.descriptor()->file()->CopyTo( + file_descriptor_set.add_file()); + GOOGLE_DCHECK(file_descriptor_set.IsInitialized()); + + std::string binary_proto; + GOOGLE_CHECK(file_descriptor_set.SerializeToString(&binary_proto)); + GOOGLE_CHECK_OK(File::SetContents(unittest_proto_descriptor_set_filename_, + binary_proto, true)); + } + + int duped_stdin_; + std::string captured_stdout_; + std::string captured_stderr_; + std::string unittest_proto_descriptor_set_filename_; +}; + +TEST_P(EncodeDecodeTest, Encode) { + RedirectStdinFromFile(TestUtil::GetTestDataPath( + "net/proto2/internal/" + "testdata/text_format_unittest_data_oneof_implemented.txt")); + std::string args; + if (GetParam() != DESCRIPTOR_SET_IN) { + args.append( + TestUtil::MaybeTranslatePath("net/proto2/internal/unittest.proto")); + } + EXPECT_TRUE(Run(args + " --encode=protobuf_unittest.TestAllTypes")); + ExpectStdoutMatchesBinaryFile(TestUtil::GetTestDataPath( + "net/proto2/internal/testdata/golden_message_oneof_implemented")); + ExpectStderrMatchesText(""); +} + +TEST_P(EncodeDecodeTest, Decode) { + RedirectStdinFromFile(TestUtil::GetTestDataPath( + "net/proto2/internal/testdata/golden_message_oneof_implemented")); + EXPECT_TRUE( + Run(TestUtil::MaybeTranslatePath("net/proto2/internal/unittest.proto") + + " --decode=protobuf_unittest.TestAllTypes")); + ExpectStdoutMatchesTextFile(TestUtil::GetTestDataPath( + "net/proto2/internal/" + "testdata/text_format_unittest_data_oneof_implemented.txt")); + ExpectStderrMatchesText(""); +} + +TEST_P(EncodeDecodeTest, Partial) { + RedirectStdinFromText(""); + EXPECT_TRUE( + Run(TestUtil::MaybeTranslatePath("net/proto2/internal/unittest.proto") + + " --encode=protobuf_unittest.TestRequired")); + ExpectStdoutMatchesText(""); + ExpectStderrMatchesText( + "warning: Input message is missing required fields: a, b, c\n"); +} + +TEST_P(EncodeDecodeTest, DecodeRaw) { + protobuf_unittest::TestAllTypes message; + message.set_optional_int32(123); + message.set_optional_string("foo"); + std::string data; + message.SerializeToString(&data); + + RedirectStdinFromText(data); + EXPECT_TRUE(Run("--decode_raw", /*specify_proto_files=*/false)); + ExpectStdoutMatchesText( + "1: 123\n" + "14: \"foo\"\n"); + ExpectStderrMatchesText(""); +} + +TEST_P(EncodeDecodeTest, UnknownType) { + EXPECT_FALSE( + Run(TestUtil::MaybeTranslatePath("net/proto2/internal/unittest.proto") + + " --encode=NoSuchType")); + ExpectStdoutMatchesText(""); + ExpectStderrMatchesText("Type not defined: NoSuchType\n"); +} + +TEST_P(EncodeDecodeTest, ProtoParseError) { + EXPECT_FALSE( + Run("net/proto2/internal/no_such_file.proto " + "--encode=NoSuchType")); + ExpectStdoutMatchesText(""); + ExpectStderrContainsText( + "net/proto2/internal/no_such_file.proto: No such file or directory\n"); +} + +TEST_P(EncodeDecodeTest, EncodeDeterministicOutput) { + RedirectStdinFromFile(TestUtil::GetTestDataPath( + "net/proto2/internal/" + "testdata/text_format_unittest_data_oneof_implemented.txt")); + std::string args; + if (GetParam() != DESCRIPTOR_SET_IN) { + args.append( + TestUtil::MaybeTranslatePath("net/proto2/internal/unittest.proto")); + } + EXPECT_TRUE(Run( + args + " --encode=protobuf_unittest.TestAllTypes --deterministic_output")); + ExpectStdoutMatchesBinaryFile(TestUtil::GetTestDataPath( + "net/proto2/internal/testdata/golden_message_oneof_implemented")); + ExpectStderrMatchesText(""); +} + +TEST_P(EncodeDecodeTest, DecodeDeterministicOutput) { + RedirectStdinFromFile(TestUtil::GetTestDataPath( + "net/proto2/internal/testdata/golden_message_oneof_implemented")); + EXPECT_FALSE( + Run(TestUtil::MaybeTranslatePath("net/proto2/internal/unittest.proto") + + " --decode=protobuf_unittest.TestAllTypes --deterministic_output")); + ExpectStderrMatchesText( + "Can only use --deterministic_output with --encode.\n"); +} + +INSTANTIATE_TEST_SUITE_P(FileDescriptorSetSource, EncodeDecodeTest, + testing::Values(PROTO_PATH, DESCRIPTOR_SET_IN)); +} // anonymous namespace + +#endif // !GOOGLE_PROTOBUF_HEAP_CHECK_DRACONIAN + +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc new file mode 100644 index 00000000..e13b29f9 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc @@ -0,0 +1,195 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// This test insures that net/proto2/proto/descriptor.pb.{h,cc} match exactly +// what would be generated by the protocol compiler. These files are not +// generated automatically at build time because they are compiled into the +// protocol compiler itself. So, if they were auto-generated, you'd have a +// chicken-and-egg problem. +// +// If this test fails, run the script +// "generate_descriptor_proto.sh" and add +// descriptor.pb.{h,cc} to your changelist. + +#include <map> + +#include <testing/file.h> +#include <testing/file.h> +#include <compiler/cpp/cpp_helpers.h> +#include <compiler/cpp/cpp_generator.h> +#include <compiler/importer.h> +#include <test_util2.h> +#include <io/zero_copy_stream_impl.h> +#include <descriptor.h> +#include <stubs/strutil.h> +#include <testing/googletest.h> +#include <gtest/gtest.h> +#include <stubs/substitute.h> +#include <stubs/map_util.h> +#include <stubs/stl_util.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { + +namespace { + +class MockErrorCollector : public MultiFileErrorCollector { + public: + MockErrorCollector() {} + ~MockErrorCollector() {} + + std::string text_; + + // implements ErrorCollector --------------------------------------- + void AddError(const std::string& filename, int line, int column, + const std::string& message) { + strings::SubstituteAndAppend(&text_, "$0:$1:$2: $3\n", filename, line, column, + message); + } +}; + +class MockGeneratorContext : public GeneratorContext { + public: + void ExpectFileMatches(const std::string& virtual_filename, + const std::string& physical_filename) { + auto it = files_.find(virtual_filename); + ASSERT_TRUE(it != files_.end()) + << "Generator failed to generate file: " << virtual_filename; + + std::string expected_contents = *it->second; + std::string actual_contents; + GOOGLE_CHECK_OK( + File::GetContents(TestUtil::TestSourceDir() + "/" + physical_filename, + &actual_contents, true)) + << physical_filename; + CleanStringLineEndings(&actual_contents, false); + +#ifdef WRITE_FILES // Define to debug mismatched files. + GOOGLE_CHECK_OK(File::SetContents("/tmp/expected.cc", expected_contents, + true)); + GOOGLE_CHECK_OK( + File::SetContents("/tmp/actual.cc", actual_contents, true)); +#endif + + ASSERT_EQ(expected_contents, actual_contents) + << physical_filename + << " needs to be regenerated. Please run " + "generate_descriptor_proto.sh. " + "Then add this file to your CL."; + } + + // implements GeneratorContext -------------------------------------- + + virtual io::ZeroCopyOutputStream* Open(const std::string& filename) { + auto& map_slot = files_[filename]; + map_slot.reset(new std::string); + return new io::StringOutputStream(map_slot.get()); + } + + private: + std::map<std::string, std::unique_ptr<std::string>> files_; +}; + +const char kDescriptorParameter[] = "dllexport_decl=PROTOBUF_EXPORT"; +const char kPluginParameter[] = "dllexport_decl=PROTOC_EXPORT"; + + +const char* test_protos[][2] = { + {"google/protobuf/descriptor", kDescriptorParameter}, + {"google/protobuf/compiler/plugin", kPluginParameter}, +}; + +TEST(BootstrapTest, GeneratedFilesMatch) { + // We need a mapping from the actual file to virtual and actual path + // of the data to compare to. + std::map<std::string, std::string> vpath_map; + std::map<std::string, std::string> rpath_map; + rpath_map["third_party/protobuf/src/google/protobuf/test_messages_proto2"] = + "net/proto2/z_generated_example/test_messages_proto2"; + rpath_map["third_party/protobuf/src/google/protobuf/test_messages_proto3"] = + "net/proto2/z_generated_example/test_messages_proto3"; + rpath_map["net/proto2/internal/proto2_weak"] = + "net/proto2/z_generated_example/proto2_weak"; + + DiskSourceTree source_tree; + source_tree.MapPath("", TestUtil::TestSourceDir()); + + for (auto file_parameter : test_protos) { + MockErrorCollector error_collector; + Importer importer(&source_tree, &error_collector); + const FileDescriptor* file = + importer.Import(file_parameter[0] + std::string(".proto")); + ASSERT_TRUE(file != nullptr) + << "Can't import file " << file_parameter[0] + std::string(".proto") + << "\n"; + EXPECT_EQ("", error_collector.text_); + CppGenerator generator; + MockGeneratorContext context; +#ifdef GOOGLE_PROTOBUF_RUNTIME_INCLUDE_BASE + generator.set_opensource_runtime(true); + generator.set_runtime_include_base(GOOGLE_PROTOBUF_RUNTIME_INCLUDE_BASE); +#endif + std::string error; + ASSERT_TRUE(generator.Generate(file, file_parameter[1], &context, &error)); + + std::string vpath = + FindWithDefault(vpath_map, file_parameter[0], file_parameter[0]); + std::string rpath = + FindWithDefault(rpath_map, file_parameter[0], file_parameter[0]); + context.ExpectFileMatches(vpath + ".pb.cc", rpath + ".pb.cc"); + context.ExpectFileMatches(vpath + ".pb.h", rpath + ".pb.h"); + } +} + +// test Generate in cpp_generator.cc +TEST(BootstrapTest, OptionNotExist) { + cpp::CppGenerator generator; + DescriptorPool pool; + GeneratorContext* generator_context = nullptr; + std::string parameter = "aaa"; + std::string error; + ASSERT_FALSE(generator.Generate( + pool.FindFileByName("google/protobuf/descriptor.proto"), parameter, + generator_context, &error)); + EXPECT_EQ(error, "Unknown generator option: " + parameter); +} + +} // namespace + +} // namespace cpp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_enum.cc b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_enum.cc new file mode 100644 index 00000000..e2bf2e6f --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_enum.cc @@ -0,0 +1,438 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <compiler/cpp/cpp_enum.h> + +#include <cstdint> +#include <limits> +#include <map> + +#include <compiler/cpp/cpp_helpers.h> +#include <compiler/cpp/cpp_names.h> +#include <io/printer.h> +#include <stubs/strutil.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { + +namespace { +// The GOOGLE_ARRAYSIZE constant is the max enum value plus 1. If the max enum value +// is kint32max, GOOGLE_ARRAYSIZE will overflow. In such cases we should omit the +// generation of the GOOGLE_ARRAYSIZE constant. +bool ShouldGenerateArraySize(const EnumDescriptor* descriptor) { + int32_t max_value = descriptor->value(0)->number(); + for (int i = 0; i < descriptor->value_count(); i++) { + if (descriptor->value(i)->number() > max_value) { + max_value = descriptor->value(i)->number(); + } + } + return max_value != std::numeric_limits<int32_t>::max(); +} + +// Returns the number of unique numeric enum values. This is less than +// descriptor->value_count() when there are aliased values. +int CountUniqueValues(const EnumDescriptor* descriptor) { + std::set<int> values; + for (int i = 0; i < descriptor->value_count(); ++i) { + values.insert(descriptor->value(i)->number()); + } + return values.size(); +} + +} // namespace + +EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor, + const std::map<std::string, std::string>& vars, + const Options& options) + : descriptor_(descriptor), + classname_(ClassName(descriptor, false)), + options_(options), + generate_array_size_(ShouldGenerateArraySize(descriptor)), + variables_(vars) { + variables_["classname"] = classname_; + variables_["classtype"] = QualifiedClassName(descriptor_, options); + variables_["short_name"] = descriptor_->name(); + variables_["nested_name"] = descriptor_->name(); + variables_["resolved_name"] = ResolveKeyword(descriptor_->name()); + variables_["prefix"] = + (descriptor_->containing_type() == NULL) ? "" : classname_ + "_"; +} + +EnumGenerator::~EnumGenerator() {} + +void EnumGenerator::GenerateDefinition(io::Printer* printer) { + Formatter format(printer, variables_); + format("enum ${1$$classname$$}$ : int {\n", descriptor_); + format.Indent(); + + const EnumValueDescriptor* min_value = descriptor_->value(0); + const EnumValueDescriptor* max_value = descriptor_->value(0); + + for (int i = 0; i < descriptor_->value_count(); i++) { + auto format_value = format; + format_value.Set("name", EnumValueName(descriptor_->value(i))); + // In C++, an value of -2147483648 gets interpreted as the negative of + // 2147483648, and since 2147483648 can't fit in an integer, this produces a + // compiler warning. This works around that issue. + format_value.Set("number", Int32ToString(descriptor_->value(i)->number())); + format_value.Set("deprecation", + DeprecatedAttribute(options_, descriptor_->value(i))); + + if (i > 0) format_value(",\n"); + format_value("${1$$prefix$$name$$}$ $deprecation$= $number$", + descriptor_->value(i)); + + if (descriptor_->value(i)->number() < min_value->number()) { + min_value = descriptor_->value(i); + } + if (descriptor_->value(i)->number() > max_value->number()) { + max_value = descriptor_->value(i); + } + } + + if (descriptor_->file()->syntax() == FileDescriptor::SYNTAX_PROTO3) { + // For new enum semantics: generate min and max sentinel values equal to + // INT32_MIN and INT32_MAX + if (descriptor_->value_count() > 0) format(",\n"); + format( + "$classname$_$prefix$INT_MIN_SENTINEL_DO_NOT_USE_ = " + "std::numeric_limits<$int32$>::min(),\n" + "$classname$_$prefix$INT_MAX_SENTINEL_DO_NOT_USE_ = " + "std::numeric_limits<$int32$>::max()"); + } + + format.Outdent(); + format("\n};\n"); + + format( + "$dllexport_decl $bool $classname$_IsValid(int value);\n" + "constexpr $classname$ ${1$$prefix$$short_name$_MIN$}$ = " + "$prefix$$2$;\n" + "constexpr $classname$ ${1$$prefix$$short_name$_MAX$}$ = " + "$prefix$$3$;\n", + descriptor_, EnumValueName(min_value), EnumValueName(max_value)); + + if (generate_array_size_) { + format( + "constexpr int ${1$$prefix$$short_name$_ARRAYSIZE$}$ = " + "$prefix$$short_name$_MAX + 1;\n\n", + descriptor_); + } + + if (HasDescriptorMethods(descriptor_->file(), options_)) { + format( + "$dllexport_decl $const ::$proto_ns$::EnumDescriptor* " + "$classname$_descriptor();\n"); + } + + // The _Name and _Parse functions. The lite implementation is table-based, so + // we make sure to keep the tables hidden in the .cc file. + if (!HasDescriptorMethods(descriptor_->file(), options_)) { + format("const std::string& $classname$_Name($classname$ value);\n"); + } + // The _Name() function accepts the enum type itself but also any integral + // type. + format( + "template<typename T>\n" + "inline const std::string& $classname$_Name(T enum_t_value) {\n" + " static_assert(::std::is_same<T, $classname$>::value ||\n" + " ::std::is_integral<T>::value,\n" + " \"Incorrect type passed to function $classname$_Name.\");\n"); + if (HasDescriptorMethods(descriptor_->file(), options_)) { + format( + " return ::$proto_ns$::internal::NameOfEnum(\n" + " $classname$_descriptor(), enum_t_value);\n"); + } else { + format( + " return $classname$_Name(static_cast<$classname$>(enum_t_value));\n"); + } + format("}\n"); + + if (HasDescriptorMethods(descriptor_->file(), options_)) { + format( + "inline bool $classname$_Parse(\n" + " ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, $classname$* " + "value) " + "{\n" + " return ::$proto_ns$::internal::ParseNamedEnum<$classname$>(\n" + " $classname$_descriptor(), name, value);\n" + "}\n"); + } else { + format( + "bool $classname$_Parse(\n" + " ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, $classname$* " + "value);\n"); + } +} + +void EnumGenerator::GenerateGetEnumDescriptorSpecializations( + io::Printer* printer) { + Formatter format(printer, variables_); + format( + "template <> struct is_proto_enum< $classtype$> : ::std::true_type " + "{};\n"); + if (HasDescriptorMethods(descriptor_->file(), options_)) { + format( + "template <>\n" + "inline const EnumDescriptor* GetEnumDescriptor< $classtype$>() {\n" + " return $classtype$_descriptor();\n" + "}\n"); + } +} + +void EnumGenerator::GenerateSymbolImports(io::Printer* printer) const { + Formatter format(printer, variables_); + format("typedef $classname$ $resolved_name$;\n"); + + for (int j = 0; j < descriptor_->value_count(); j++) { + std::string deprecated_attr = + DeprecatedAttribute(options_, descriptor_->value(j)); + format( + "$1$static constexpr $resolved_name$ ${2$$3$$}$ =\n" + " $classname$_$3$;\n", + deprecated_attr, descriptor_->value(j), + EnumValueName(descriptor_->value(j))); + } + + format( + "static inline bool $nested_name$_IsValid(int value) {\n" + " return $classname$_IsValid(value);\n" + "}\n" + "static constexpr $resolved_name$ ${1$$nested_name$_MIN$}$ =\n" + " $classname$_$nested_name$_MIN;\n" + "static constexpr $resolved_name$ ${1$$nested_name$_MAX$}$ =\n" + " $classname$_$nested_name$_MAX;\n", + descriptor_); + if (generate_array_size_) { + format( + "static constexpr int ${1$$nested_name$_ARRAYSIZE$}$ =\n" + " $classname$_$nested_name$_ARRAYSIZE;\n", + descriptor_); + } + + if (HasDescriptorMethods(descriptor_->file(), options_)) { + format( + "static inline const ::$proto_ns$::EnumDescriptor*\n" + "$nested_name$_descriptor() {\n" + " return $classname$_descriptor();\n" + "}\n"); + } + + format( + "template<typename T>\n" + "static inline const std::string& $nested_name$_Name(T enum_t_value) {\n" + " static_assert(::std::is_same<T, $resolved_name$>::value ||\n" + " ::std::is_integral<T>::value,\n" + " \"Incorrect type passed to function $nested_name$_Name.\");\n" + " return $classname$_Name(enum_t_value);\n" + "}\n"); + format( + "static inline bool " + "$nested_name$_Parse(::PROTOBUF_NAMESPACE_ID::ConstStringParam name,\n" + " $resolved_name$* value) {\n" + " return $classname$_Parse(name, value);\n" + "}\n"); +} + +void EnumGenerator::GenerateMethods(int idx, io::Printer* printer) { + Formatter format(printer, variables_); + if (HasDescriptorMethods(descriptor_->file(), options_)) { + format( + "const ::$proto_ns$::EnumDescriptor* $classname$_descriptor() {\n" + " ::$proto_ns$::internal::AssignDescriptors(&$desc_table$);\n" + " return $file_level_enum_descriptors$[$1$];\n" + "}\n", + idx); + } + + format( + "bool $classname$_IsValid(int value) {\n" + " switch (value) {\n"); + + // Multiple values may have the same number. Make sure we only cover + // each number once by first constructing a set containing all valid + // numbers, then printing a case statement for each element. + + std::set<int> numbers; + for (int j = 0; j < descriptor_->value_count(); j++) { + const EnumValueDescriptor* value = descriptor_->value(j); + numbers.insert(value->number()); + } + + for (std::set<int>::iterator iter = numbers.begin(); iter != numbers.end(); + ++iter) { + format(" case $1$:\n", Int32ToString(*iter)); + } + + format( + " return true;\n" + " default:\n" + " return false;\n" + " }\n" + "}\n" + "\n"); + + if (!HasDescriptorMethods(descriptor_->file(), options_)) { + // In lite mode (where descriptors are unavailable), we generate separate + // tables for mapping between enum names and numbers. The _entries table + // contains the bulk of the data and is sorted by name, while + // _entries_by_number is sorted by number and just contains pointers into + // _entries. The two tables allow mapping from name to number and number to + // name, both in time logarithmic in the number of enum entries. This could + // probably be made faster, but for now the tables are intended to be simple + // and compact. + // + // Enums with allow_alias = true support multiple entries with the same + // numerical value. In cases where there are multiple names for the same + // number, we treat the first name appearing in the .proto file as the + // canonical one. + std::map<std::string, int> name_to_number; + std::map<int, std::string> number_to_canonical_name; + for (int i = 0; i < descriptor_->value_count(); i++) { + const EnumValueDescriptor* value = descriptor_->value(i); + name_to_number.emplace(value->name(), value->number()); + // The same number may appear with multiple names, so we use emplace() to + // let the first name win. + number_to_canonical_name.emplace(value->number(), value->name()); + } + + format( + "static ::$proto_ns$::internal::ExplicitlyConstructed<std::string> " + "$classname$_strings[$1$] = {};\n\n", + CountUniqueValues(descriptor_)); + + // We concatenate all the names for a given enum into one big string + // literal. If instead we store an array of string literals, the linker + // seems to put all enum strings for a given .proto file in the same + // section, which hinders its ability to strip out unused strings. + format("static const char $classname$_names[] ="); + for (const auto& p : name_to_number) { + format("\n \"$1$\"", p.first); + } + format(";\n\n"); + + format( + "static const ::$proto_ns$::internal::EnumEntry $classname$_entries[] " + "= {\n"); + int i = 0; + std::map<int, int> number_to_index; + int data_index = 0; + for (const auto& p : name_to_number) { + format(" { {$classname$_names + $1$, $2$}, $3$ },\n", data_index, + p.first.size(), p.second); + if (number_to_canonical_name[p.second] == p.first) { + number_to_index.emplace(p.second, i); + } + ++i; + data_index += p.first.size(); + } + + format( + "};\n" + "\n" + "static const int $classname$_entries_by_number[] = {\n"); + for (const auto& p : number_to_index) { + format(" $1$, // $2$ -> $3$\n", p.second, p.first, + number_to_canonical_name[p.first]); + } + format( + "};\n" + "\n"); + + format( + "const std::string& $classname$_Name(\n" + " $classname$ value) {\n" + " static const bool dummy =\n" + " ::$proto_ns$::internal::InitializeEnumStrings(\n" + " $classname$_entries,\n" + " $classname$_entries_by_number,\n" + " $1$, $classname$_strings);\n" + " (void) dummy;\n" + " int idx = ::$proto_ns$::internal::LookUpEnumName(\n" + " $classname$_entries,\n" + " $classname$_entries_by_number,\n" + " $1$, value);\n" + " return idx == -1 ? ::$proto_ns$::internal::GetEmptyString() :\n" + " $classname$_strings[idx].get();\n" + "}\n", + CountUniqueValues(descriptor_)); + format( + "bool $classname$_Parse(\n" + " ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, $classname$* " + "value) " + "{\n" + " int int_value;\n" + " bool success = ::$proto_ns$::internal::LookUpEnumValue(\n" + " $classname$_entries, $1$, name, &int_value);\n" + " if (success) {\n" + " *value = static_cast<$classname$>(int_value);\n" + " }\n" + " return success;\n" + "}\n", + descriptor_->value_count()); + } + + if (descriptor_->containing_type() != NULL) { + std::string parent = ClassName(descriptor_->containing_type(), false); + // Before C++17, we must define the static constants which were + // declared in the header, to give the linker a place to put them. + // But MSVC++ pre-2015 and post-2017 (version 15.5+) insists that we not. + format( + "#if (__cplusplus < 201703) && " + "(!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))\n"); + + for (int i = 0; i < descriptor_->value_count(); i++) { + format("constexpr $classname$ $1$::$2$;\n", parent, + EnumValueName(descriptor_->value(i))); + } + format( + "constexpr $classname$ $1$::$nested_name$_MIN;\n" + "constexpr $classname$ $1$::$nested_name$_MAX;\n", + parent); + if (generate_array_size_) { + format("constexpr int $1$::$nested_name$_ARRAYSIZE;\n", parent); + } + + format( + "#endif // (__cplusplus < 201703) && " + "(!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))\n"); + } +} + +} // namespace cpp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_enum.h b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_enum.h new file mode 100644 index 00000000..19a2cbe5 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_enum.h @@ -0,0 +1,105 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_H__ +#define GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_H__ + +#include <map> +#include <set> +#include <string> +#include <compiler/cpp/cpp_options.h> +#include <descriptor.h> + +namespace google { +namespace protobuf { +namespace io { +class Printer; // printer.h +} +} // namespace protobuf +} // namespace google + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { + +class EnumGenerator { + public: + // See generator.cc for the meaning of dllexport_decl. + EnumGenerator(const EnumDescriptor* descriptor, + const std::map<std::string, std::string>& vars, + const Options& options); + ~EnumGenerator(); + + // Generate header code defining the enum. This code should be placed + // within the enum's package namespace, but NOT within any class, even for + // nested enums. + void GenerateDefinition(io::Printer* printer); + + // Generate specialization of GetEnumDescriptor<MyEnum>(). + // Precondition: in ::google::protobuf namespace. + void GenerateGetEnumDescriptorSpecializations(io::Printer* printer); + + // For enums nested within a message, generate code to import all the enum's + // symbols (e.g. the enum type name, all its values, etc.) into the class's + // namespace. This should be placed inside the class definition in the + // header. + void GenerateSymbolImports(io::Printer* printer) const; + + // Source file stuff. + + // Generate non-inline methods related to the enum, such as IsValidValue(). + // Goes in the .cc file. EnumDescriptors are stored in an array, idx is + // the index in this array that corresponds with this enum. + void GenerateMethods(int idx, io::Printer* printer); + + private: + const EnumDescriptor* descriptor_; + const std::string classname_; + const Options& options_; + // whether to generate the *_ARRAYSIZE constant. + const bool generate_array_size_; + + std::map<std::string, std::string> variables_; + + friend class FileGenerator; + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumGenerator); +}; + +} // namespace cpp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_enum_field.cc b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_enum_field.cc new file mode 100644 index 00000000..e0b3f9e5 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_enum_field.cc @@ -0,0 +1,406 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <compiler/cpp/cpp_enum_field.h> +#include <compiler/cpp/cpp_helpers.h> +#include <io/printer.h> +#include <wire_format.h> +#include <stubs/strutil.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { + +namespace { + +void SetEnumVariables(const FieldDescriptor* descriptor, + std::map<std::string, std::string>* variables, + const Options& options) { + SetCommonFieldVariables(descriptor, variables, options); + const EnumValueDescriptor* default_value = descriptor->default_value_enum(); + (*variables)["type"] = QualifiedClassName(descriptor->enum_type(), options); + (*variables)["default"] = Int32ToString(default_value->number()); + (*variables)["full_name"] = descriptor->full_name(); +} + +} // namespace + +// =================================================================== + +EnumFieldGenerator::EnumFieldGenerator(const FieldDescriptor* descriptor, + const Options& options) + : FieldGenerator(descriptor, options) { + SetEnumVariables(descriptor, &variables_, options); +} + +EnumFieldGenerator::~EnumFieldGenerator() {} + +void EnumFieldGenerator::GeneratePrivateMembers(io::Printer* printer) const { + Formatter format(printer, variables_); + format("int $name$_;\n"); +} + +void EnumFieldGenerator::GenerateAccessorDeclarations( + io::Printer* printer) const { + Formatter format(printer, variables_); + format( + "$deprecated_attr$$type$ ${1$$name$$}$() const;\n" + "$deprecated_attr$void ${1$set_$name$$}$($type$ value);\n" + "private:\n" + "$type$ ${1$_internal_$name$$}$() const;\n" + "void ${1$_internal_set_$name$$}$($type$ value);\n" + "public:\n", + descriptor_); +} + +void EnumFieldGenerator::GenerateInlineAccessorDefinitions( + io::Printer* printer) const { + Formatter format(printer, variables_); + format( + "inline $type$ $classname$::_internal_$name$() const {\n" + " return static_cast< $type$ >($name$_);\n" + "}\n" + "inline $type$ $classname$::$name$() const {\n" + "$annotate_get$" + " // @@protoc_insertion_point(field_get:$full_name$)\n" + " return _internal_$name$();\n" + "}\n" + "inline void $classname$::_internal_set_$name$($type$ value) {\n"); + if (!HasPreservingUnknownEnumSemantics(descriptor_)) { + format(" assert($type$_IsValid(value));\n"); + } + format( + " $set_hasbit$\n" + " $name$_ = value;\n" + "}\n" + "inline void $classname$::set_$name$($type$ value) {\n" + " _internal_set_$name$(value);\n" + "$annotate_set$" + " // @@protoc_insertion_point(field_set:$full_name$)\n" + "}\n"); +} + +void EnumFieldGenerator::GenerateClearingCode(io::Printer* printer) const { + Formatter format(printer, variables_); + format("$name$_ = $default$;\n"); +} + +void EnumFieldGenerator::GenerateMergingCode(io::Printer* printer) const { + Formatter format(printer, variables_); + format("_internal_set_$name$(from._internal_$name$());\n"); +} + +void EnumFieldGenerator::GenerateSwappingCode(io::Printer* printer) const { + Formatter format(printer, variables_); + format("swap($name$_, other->$name$_);\n"); +} + +void EnumFieldGenerator::GenerateConstructorCode(io::Printer* printer) const { + Formatter format(printer, variables_); + format("$name$_ = $default$;\n"); +} + +void EnumFieldGenerator::GenerateCopyConstructorCode( + io::Printer* printer) const { + Formatter format(printer, variables_); + format("$name$_ = from.$name$_;\n"); +} + +void EnumFieldGenerator::GenerateSerializeWithCachedSizesToArray( + io::Printer* printer) const { + Formatter format(printer, variables_); + format( + "target = stream->EnsureSpace(target);\n" + "target = ::$proto_ns$::internal::WireFormatLite::WriteEnumToArray(\n" + " $number$, this->_internal_$name$(), target);\n"); +} + +void EnumFieldGenerator::GenerateByteSize(io::Printer* printer) const { + Formatter format(printer, variables_); + format( + "total_size += $tag_size$ +\n" + " " + "::$proto_ns$::internal::WireFormatLite::EnumSize(this->_internal_$name$(" + "));\n"); +} + +void EnumFieldGenerator::GenerateConstinitInitializer( + io::Printer* printer) const { + Formatter format(printer, variables_); + format("$name$_($default$)\n"); +} + +// =================================================================== + +EnumOneofFieldGenerator::EnumOneofFieldGenerator( + const FieldDescriptor* descriptor, const Options& options) + : EnumFieldGenerator(descriptor, options) { + SetCommonOneofFieldVariables(descriptor, &variables_); +} + +EnumOneofFieldGenerator::~EnumOneofFieldGenerator() {} + +void EnumOneofFieldGenerator::GenerateInlineAccessorDefinitions( + io::Printer* printer) const { + Formatter format(printer, variables_); + format( + "inline $type$ $classname$::_internal_$name$() const {\n" + " if (_internal_has_$name$()) {\n" + " return static_cast< $type$ >($field_member$);\n" + " }\n" + " return static_cast< $type$ >($default$);\n" + "}\n" + "inline $type$ $classname$::$name$() const {\n" + "$annotate_get$" + " // @@protoc_insertion_point(field_get:$full_name$)\n" + " return _internal_$name$();\n" + "}\n" + "inline void $classname$::_internal_set_$name$($type$ value) {\n"); + if (!HasPreservingUnknownEnumSemantics(descriptor_)) { + format(" assert($type$_IsValid(value));\n"); + } + format( + " if (!_internal_has_$name$()) {\n" + " clear_$oneof_name$();\n" + " set_has_$name$();\n" + " }\n" + " $field_member$ = value;\n" + "}\n" + "inline void $classname$::set_$name$($type$ value) {\n" + " _internal_set_$name$(value);\n" + "$annotate_set$" + " // @@protoc_insertion_point(field_set:$full_name$)\n" + "}\n"); +} + +void EnumOneofFieldGenerator::GenerateClearingCode(io::Printer* printer) const { + Formatter format(printer, variables_); + format("$field_member$ = $default$;\n"); +} + +void EnumOneofFieldGenerator::GenerateSwappingCode(io::Printer* printer) const { + // Don't print any swapping code. Swapping the union will swap this field. +} + +void EnumOneofFieldGenerator::GenerateConstructorCode( + io::Printer* printer) const { + Formatter format(printer, variables_); + format("$ns$::_$classname$_default_instance_.$name$_ = $default$;\n"); +} + +// =================================================================== + +RepeatedEnumFieldGenerator::RepeatedEnumFieldGenerator( + const FieldDescriptor* descriptor, const Options& options) + : FieldGenerator(descriptor, options) { + SetEnumVariables(descriptor, &variables_, options); +} + +RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() {} + +void RepeatedEnumFieldGenerator::GeneratePrivateMembers( + io::Printer* printer) const { + Formatter format(printer, variables_); + format("::$proto_ns$::RepeatedField<int> $name$_;\n"); + if (descriptor_->is_packed() && + HasGeneratedMethods(descriptor_->file(), options_)) { + format("mutable std::atomic<int> _$name$_cached_byte_size_;\n"); + } +} + +void RepeatedEnumFieldGenerator::GenerateAccessorDeclarations( + io::Printer* printer) const { + Formatter format(printer, variables_); + format( + "private:\n" + "$type$ ${1$_internal_$name$$}$(int index) const;\n" + "void ${1$_internal_add_$name$$}$($type$ value);\n" + "::$proto_ns$::RepeatedField<int>* " + "${1$_internal_mutable_$name$$}$();\n" + "public:\n" + "$deprecated_attr$$type$ ${1$$name$$}$(int index) const;\n" + "$deprecated_attr$void ${1$set_$name$$}$(int index, $type$ value);\n" + "$deprecated_attr$void ${1$add_$name$$}$($type$ value);\n" + "$deprecated_attr$const ::$proto_ns$::RepeatedField<int>& " + "${1$$name$$}$() const;\n" + "$deprecated_attr$::$proto_ns$::RepeatedField<int>* " + "${1$mutable_$name$$}$();\n", + descriptor_); +} + +void RepeatedEnumFieldGenerator::GenerateInlineAccessorDefinitions( + io::Printer* printer) const { + Formatter format(printer, variables_); + format( + "inline $type$ $classname$::_internal_$name$(int index) const {\n" + " return static_cast< $type$ >($name$_.Get(index));\n" + "}\n" + "inline $type$ $classname$::$name$(int index) const {\n" + "$annotate_get$" + " // @@protoc_insertion_point(field_get:$full_name$)\n" + " return _internal_$name$(index);\n" + "}\n" + "inline void $classname$::set_$name$(int index, $type$ value) {\n"); + if (!HasPreservingUnknownEnumSemantics(descriptor_)) { + format(" assert($type$_IsValid(value));\n"); + } + format( + " $name$_.Set(index, value);\n" + "$annotate_set$" + " // @@protoc_insertion_point(field_set:$full_name$)\n" + "}\n" + "inline void $classname$::_internal_add_$name$($type$ value) {\n"); + if (!HasPreservingUnknownEnumSemantics(descriptor_)) { + format(" assert($type$_IsValid(value));\n"); + } + format( + " $name$_.Add(value);\n" + "}\n" + "inline void $classname$::add_$name$($type$ value) {\n" + " _internal_add_$name$(value);\n" + "$annotate_add$" + " // @@protoc_insertion_point(field_add:$full_name$)\n" + "}\n" + "inline const ::$proto_ns$::RepeatedField<int>&\n" + "$classname$::$name$() const {\n" + "$annotate_list$" + " // @@protoc_insertion_point(field_list:$full_name$)\n" + " return $name$_;\n" + "}\n" + "inline ::$proto_ns$::RepeatedField<int>*\n" + "$classname$::_internal_mutable_$name$() {\n" + " return &$name$_;\n" + "}\n" + "inline ::$proto_ns$::RepeatedField<int>*\n" + "$classname$::mutable_$name$() {\n" + "$annotate_mutable_list$" + " // @@protoc_insertion_point(field_mutable_list:$full_name$)\n" + " return _internal_mutable_$name$();\n" + "}\n"); +} + +void RepeatedEnumFieldGenerator::GenerateClearingCode( + io::Printer* printer) const { + Formatter format(printer, variables_); + format("$name$_.Clear();\n"); +} + +void RepeatedEnumFieldGenerator::GenerateMergingCode( + io::Printer* printer) const { + Formatter format(printer, variables_); + format("$name$_.MergeFrom(from.$name$_);\n"); +} + +void RepeatedEnumFieldGenerator::GenerateSwappingCode( + io::Printer* printer) const { + Formatter format(printer, variables_); + format("$name$_.InternalSwap(&other->$name$_);\n"); +} + +void RepeatedEnumFieldGenerator::GenerateConstructorCode( + io::Printer* printer) const { + // Not needed for repeated fields. +} + +void RepeatedEnumFieldGenerator::GenerateSerializeWithCachedSizesToArray( + io::Printer* printer) const { + Formatter format(printer, variables_); + if (descriptor_->is_packed()) { + // Write the tag and the size. + format( + "{\n" + " int byte_size = " + "_$name$_cached_byte_size_.load(std::memory_order_relaxed);\n" + " if (byte_size > 0) {\n" + " target = stream->WriteEnumPacked(\n" + " $number$, $name$_, byte_size, target);\n" + " }\n" + "}\n"); + } else { + format( + "for (int i = 0, n = this->_internal_$name$_size(); i < n; i++) {\n" + " target = stream->EnsureSpace(target);\n" + " target = ::$proto_ns$::internal::WireFormatLite::WriteEnumToArray(\n" + " $number$, this->_internal_$name$(i), target);\n" + "}\n"); + } +} + +void RepeatedEnumFieldGenerator::GenerateByteSize(io::Printer* printer) const { + Formatter format(printer, variables_); + format( + "{\n" + " size_t data_size = 0;\n" + " unsigned int count = static_cast<unsigned " + "int>(this->_internal_$name$_size());"); + format.Indent(); + format( + "for (unsigned int i = 0; i < count; i++) {\n" + " data_size += ::$proto_ns$::internal::WireFormatLite::EnumSize(\n" + " this->_internal_$name$(static_cast<int>(i)));\n" + "}\n"); + + if (descriptor_->is_packed()) { + format( + "if (data_size > 0) {\n" + " total_size += $tag_size$ +\n" + " ::$proto_ns$::internal::WireFormatLite::Int32Size(\n" + " static_cast<$int32$>(data_size));\n" + "}\n" + "int cached_size = ::$proto_ns$::internal::ToCachedSize(data_size);\n" + "_$name$_cached_byte_size_.store(cached_size,\n" + " std::memory_order_relaxed);\n" + "total_size += data_size;\n"); + } else { + format("total_size += ($tag_size$UL * count) + data_size;\n"); + } + format.Outdent(); + format("}\n"); +} + +void RepeatedEnumFieldGenerator::GenerateConstinitInitializer( + io::Printer* printer) const { + Formatter format(printer, variables_); + format("$name$_()"); + if (descriptor_->is_packed() && + HasGeneratedMethods(descriptor_->file(), options_)) { + format("\n, _$name$_cached_byte_size_(0)"); + } +} + +} // namespace cpp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_enum_field.h b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_enum_field.h new file mode 100644 index 00000000..3be207bf --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_enum_field.h @@ -0,0 +1,115 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_FIELD_H__ +#define GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_FIELD_H__ + +#include <map> +#include <string> +#include <compiler/cpp/cpp_field.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { + +class EnumFieldGenerator : public FieldGenerator { + public: + EnumFieldGenerator(const FieldDescriptor* descriptor, const Options& options); + ~EnumFieldGenerator(); + + // implements FieldGenerator --------------------------------------- + void GeneratePrivateMembers(io::Printer* printer) const override; + void GenerateAccessorDeclarations(io::Printer* printer) const override; + void GenerateInlineAccessorDefinitions(io::Printer* printer) const override; + void GenerateClearingCode(io::Printer* printer) const override; + void GenerateMergingCode(io::Printer* printer) const override; + void GenerateSwappingCode(io::Printer* printer) const override; + void GenerateConstructorCode(io::Printer* printer) const override; + void GenerateCopyConstructorCode(io::Printer* printer) const override; + void GenerateSerializeWithCachedSizesToArray( + io::Printer* printer) const override; + void GenerateByteSize(io::Printer* printer) const override; + void GenerateConstinitInitializer(io::Printer* printer) const override; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumFieldGenerator); +}; + +class EnumOneofFieldGenerator : public EnumFieldGenerator { + public: + EnumOneofFieldGenerator(const FieldDescriptor* descriptor, + const Options& options); + ~EnumOneofFieldGenerator(); + + // implements FieldGenerator --------------------------------------- + void GenerateInlineAccessorDefinitions(io::Printer* printer) const override; + void GenerateClearingCode(io::Printer* printer) const override; + void GenerateSwappingCode(io::Printer* printer) const override; + void GenerateConstructorCode(io::Printer* printer) const override; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumOneofFieldGenerator); +}; + +class RepeatedEnumFieldGenerator : public FieldGenerator { + public: + RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor, + const Options& options); + ~RepeatedEnumFieldGenerator(); + + // implements FieldGenerator --------------------------------------- + void GeneratePrivateMembers(io::Printer* printer) const override; + void GenerateAccessorDeclarations(io::Printer* printer) const override; + void GenerateInlineAccessorDefinitions(io::Printer* printer) const override; + void GenerateClearingCode(io::Printer* printer) const override; + void GenerateMergingCode(io::Printer* printer) const override; + void GenerateSwappingCode(io::Printer* printer) const override; + void GenerateConstructorCode(io::Printer* printer) const override; + void GenerateCopyConstructorCode(io::Printer* printer) const override {} + void GenerateSerializeWithCachedSizesToArray( + io::Printer* printer) const override; + void GenerateByteSize(io::Printer* printer) const override; + void GenerateConstinitInitializer(io::Printer* printer) const override; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedEnumFieldGenerator); +}; + +} // namespace cpp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_FIELD_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_extension.cc b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_extension.cc new file mode 100644 index 00000000..f0dae72d --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_extension.cc @@ -0,0 +1,189 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <compiler/cpp/cpp_extension.h> +#include <map> +#include <compiler/cpp/cpp_helpers.h> +#include <descriptor.pb.h> +#include <io/printer.h> +#include <stubs/strutil.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { + +ExtensionGenerator::ExtensionGenerator(const FieldDescriptor* descriptor, + const Options& options, + MessageSCCAnalyzer* scc_analyzer) + : descriptor_(descriptor), options_(options), scc_analyzer_(scc_analyzer) { + // Construct type_traits_. + if (descriptor_->is_repeated()) { + type_traits_ = "Repeated"; + } + + switch (descriptor_->cpp_type()) { + case FieldDescriptor::CPPTYPE_ENUM: + type_traits_.append("EnumTypeTraits< "); + type_traits_.append(ClassName(descriptor_->enum_type(), true)); + type_traits_.append(", "); + type_traits_.append(ClassName(descriptor_->enum_type(), true)); + type_traits_.append("_IsValid>"); + break; + case FieldDescriptor::CPPTYPE_STRING: + type_traits_.append("StringTypeTraits"); + break; + case FieldDescriptor::CPPTYPE_MESSAGE: + type_traits_.append("MessageTypeTraits< "); + type_traits_.append(ClassName(descriptor_->message_type(), true)); + type_traits_.append(" >"); + break; + default: + type_traits_.append("PrimitiveTypeTraits< "); + type_traits_.append(PrimitiveTypeName(options_, descriptor_->cpp_type())); + type_traits_.append(" >"); + break; + } + SetCommonVars(options, &variables_); + variables_["extendee"] = + QualifiedClassName(descriptor_->containing_type(), options_); + variables_["type_traits"] = type_traits_; + std::string name = descriptor_->name(); + variables_["name"] = ResolveKeyword(name); + variables_["constant_name"] = FieldConstantName(descriptor_); + variables_["field_type"] = + StrCat(static_cast<int>(descriptor_->type())); + variables_["packed"] = descriptor_->is_packed() ? "true" : "false"; + + std::string scope = + IsScoped() ? ClassName(descriptor_->extension_scope(), false) + "::" : ""; + variables_["scope"] = scope; + variables_["scoped_name"] = ExtensionName(descriptor_); + variables_["number"] = StrCat(descriptor_->number()); +} + +ExtensionGenerator::~ExtensionGenerator() {} + +bool ExtensionGenerator::IsScoped() const { + return descriptor_->extension_scope() != nullptr; +} + +void ExtensionGenerator::GenerateDeclaration(io::Printer* printer) const { + Formatter format(printer, variables_); + + // If this is a class member, it needs to be declared "static". Otherwise, + // it needs to be "extern". In the latter case, it also needs the DLL + // export/import specifier. + std::string qualifier; + if (!IsScoped()) { + qualifier = "extern"; + if (!options_.dllexport_decl.empty()) { + qualifier = options_.dllexport_decl + " " + qualifier; + } + } else { + qualifier = "static"; + } + + format( + "static const int $constant_name$ = $number$;\n" + "$1$ ::$proto_ns$::internal::ExtensionIdentifier< $extendee$,\n" + " ::$proto_ns$::internal::$type_traits$, $field_type$, $packed$ >\n" + " ${2$$name$$}$;\n", + qualifier, descriptor_); +} + +void ExtensionGenerator::GenerateDefinition(io::Printer* printer) { + // If we are building for lite with implicit weak fields, we want to skip over + // any custom options (i.e. extensions of messages from descriptor.proto). + // This prevents the creation of any unnecessary linker references to the + // descriptor messages. + if (options_.lite_implicit_weak_fields && + descriptor_->containing_type()->file()->name() == + "net/proto2/proto/descriptor.proto") { + return; + } + + Formatter format(printer, variables_); + std::string default_str; + // If this is a class member, it needs to be declared in its class scope. + if (descriptor_->cpp_type() == FieldDescriptor::CPPTYPE_STRING) { + // We need to declare a global string which will contain the default value. + // We cannot declare it at class scope because that would require exposing + // it in the header which would be annoying for other reasons. So we + // replace :: with _ in the name and declare it as a global. + default_str = + StringReplace(variables_["scoped_name"], "::", "_", true) + "_default"; + format("const std::string $1$($2$);\n", default_str, + DefaultValue(options_, descriptor_)); + } else if (descriptor_->message_type()) { + // We have to initialize the default instance for extensions at registration + // time. + default_str = + FieldMessageTypeName(descriptor_, options_) + "::default_instance()"; + } else { + default_str = DefaultValue(options_, descriptor_); + } + + // Likewise, class members need to declare the field constant variable. + if (IsScoped()) { + format( + "#if !defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912)\n" + "const int $scope$$constant_name$;\n" + "#endif\n"); + } + + format( + "PROTOBUF_ATTRIBUTE_INIT_PRIORITY " + "::$proto_ns$::internal::ExtensionIdentifier< $extendee$,\n" + " ::$proto_ns$::internal::$type_traits$, $field_type$, $packed$ >\n" + " $scoped_name$($constant_name$, $1$);\n", + default_str); + + // Register extension verify function if needed. + if (descriptor_->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && + ShouldVerify(descriptor_->message_type(), options_, scc_analyzer_) && + ShouldVerify(descriptor_->containing_type(), options_, scc_analyzer_)) { + format( + "PROTOBUF_ATTRIBUTE_INIT_PRIORITY " + "::$proto_ns$::internal::RegisterExtensionVerify< $extendee$,\n" + " $1$, $number$> $2$_$name$_register;\n", + ClassName(descriptor_->message_type(), true), + IsScoped() ? ClassName(descriptor_->extension_scope(), false) : ""); + } +} + +} // namespace cpp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_extension.h b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_extension.h new file mode 100644 index 00000000..76c0e3db --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_extension.h @@ -0,0 +1,95 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_EXTENSION_H__ +#define GOOGLE_PROTOBUF_COMPILER_CPP_EXTENSION_H__ + +#include <map> +#include <string> + +#include <stubs/common.h> +#include <compiler/cpp/cpp_options.h> + +namespace google { +namespace protobuf { +class FieldDescriptor; // descriptor.h +namespace io { +class Printer; // printer.h +} +} // namespace protobuf +} // namespace google + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { + +class MessageSCCAnalyzer; + +// Generates code for an extension, which may be within the scope of some +// message or may be at file scope. This is much simpler than FieldGenerator +// since extensions are just simple identifiers with interesting types. +class ExtensionGenerator { + public: + // See generator.cc for the meaning of dllexport_decl. + explicit ExtensionGenerator(const FieldDescriptor* descriptor, + const Options& options, + MessageSCCAnalyzer* scc_analyzer); + ~ExtensionGenerator(); + + // Header stuff. + void GenerateDeclaration(io::Printer* printer) const; + + // Source file stuff. + void GenerateDefinition(io::Printer* printer); + + bool IsScoped() const; + + private: + const FieldDescriptor* descriptor_; + std::string type_traits_; + Options options_; + MessageSCCAnalyzer* scc_analyzer_; + + std::map<std::string, std::string> variables_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ExtensionGenerator); +}; + +} // namespace cpp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_field.cc b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_field.cc new file mode 100644 index 00000000..8edda0c7 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_field.cc @@ -0,0 +1,391 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <compiler/cpp/cpp_field.h> + +#include <cstdint> +#include <memory> +#include <string> + +#include <compiler/cpp/cpp_helpers.h> +#include <compiler/cpp/cpp_primitive_field.h> +#include <compiler/cpp/cpp_string_field.h> +#include <stubs/strutil.h> +#include <stubs/substitute.h> +#include <stubs/logging.h> +#include <stubs/common.h> +#include <compiler/cpp/cpp_enum_field.h> +#include <compiler/cpp/cpp_map_field.h> +#include <compiler/cpp/cpp_message_field.h> +#include <descriptor.pb.h> +#include <io/printer.h> +#include <wire_format.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { + +using internal::WireFormat; + +namespace { + +void MaySetAnnotationVariable(const Options& options, + StringPiece annotation_name, + StringPiece substitute_template_prefix, + StringPiece prepared_template, + int field_index, StringPiece access_type, + std::map<std::string, std::string>* variables) { + if (options.field_listener_options.forbidden_field_listener_events.count( + std::string(annotation_name))) + return; + (*variables)[StrCat("annotate_", annotation_name)] = strings::Substitute( + StrCat(substitute_template_prefix, prepared_template, ");\n"), + field_index, access_type); +} + +std::string GenerateTemplateForOneofString(const FieldDescriptor* descriptor, + StringPiece proto_ns, + StringPiece field_member) { + std::string field_name = google::protobuf::compiler::cpp::FieldName(descriptor); + std::string field_pointer = + descriptor->options().ctype() == google::protobuf::FieldOptions::STRING + ? "$0.GetPointer()" + : "$0"; + + if (descriptor->default_value_string().empty()) { + return strings::Substitute(StrCat("_internal_has_", field_name, "() ? ", + field_pointer, ": nullptr"), + field_member); + } + + if (descriptor->options().ctype() == google::protobuf::FieldOptions::STRING_PIECE) { + return strings::Substitute(StrCat("_internal_has_", field_name, "() ? ", + field_pointer, ": nullptr"), + field_member); + } + + std::string default_value_pointer = + descriptor->options().ctype() == google::protobuf::FieldOptions::STRING + ? "&$1.get()" + : "&$1"; + return strings::Substitute( + StrCat("_internal_has_", field_name, "() ? ", field_pointer, " : ", + default_value_pointer), + field_member, MakeDefaultName(descriptor)); +} + +std::string GenerateTemplateForSingleString(const FieldDescriptor* descriptor, + StringPiece field_member) { + if (descriptor->default_value_string().empty()) { + return StrCat("&", field_member); + } + + if (descriptor->options().ctype() == google::protobuf::FieldOptions::STRING) { + return strings::Substitute( + "$0.IsDefault(nullptr) ? &$1.get() : $0.GetPointer()", field_member, + MakeDefaultName(descriptor)); + } + + return StrCat("&", field_member); +} + +} // namespace + +void AddAccessorAnnotations(const FieldDescriptor* descriptor, + const Options& options, + std::map<std::string, std::string>* variables) { + // Can be expanded to include more specific calls, for example, for arena or + // clear calls. + static constexpr const char* kAccessorsAnnotations[] = { + "annotate_add", "annotate_get", "annotate_has", + "annotate_list", "annotate_mutable", "annotate_mutable_list", + "annotate_release", "annotate_set", "annotate_size", + "annotate_clear", "annotate_add_mutable", + }; + for (size_t i = 0; i < GOOGLE_ARRAYSIZE(kAccessorsAnnotations); ++i) { + (*variables)[kAccessorsAnnotations[i]] = ""; + } + if (options.annotate_accessor) { + for (size_t i = 0; i < GOOGLE_ARRAYSIZE(kAccessorsAnnotations); ++i) { + (*variables)[kAccessorsAnnotations[i]] = StrCat( + " ", FieldName(descriptor), "_AccessedNoStrip = true;\n"); + } + } + if (!options.field_listener_options.inject_field_listener_events) { + return; + } + if (descriptor->file()->options().optimize_for() == + google::protobuf::FileOptions::LITE_RUNTIME) { + return; + } + std::string field_member = (*variables)["field_member"]; + const google::protobuf::OneofDescriptor* oneof_member = + descriptor->real_containing_oneof(); + if (oneof_member) { + field_member = StrCat(oneof_member->name(), "_.", field_member); + } + const std::string proto_ns = (*variables)["proto_ns"]; + const std::string substitute_template_prefix = " _tracker_.$1<$0>(this, "; + std::string prepared_template; + + // Flat template is needed if the prepared one is introspecting the values + // inside the returned values, for example, for repeated fields and maps. + std::string prepared_flat_template; + std::string prepared_add_template; + // TODO(b/190614678): Support fields with type Message or Map. + if (descriptor->is_repeated() && !descriptor->is_map()) { + if (descriptor->type() != FieldDescriptor::TYPE_MESSAGE && + descriptor->type() != FieldDescriptor::TYPE_GROUP) { + prepared_template = strings::Substitute("&$0.Get(index)", field_member); + prepared_add_template = + strings::Substitute("&$0.Get($0.size() - 1)", field_member); + } else { + prepared_template = "nullptr"; + prepared_add_template = "nullptr"; + } + } else if (descriptor->is_map()) { + prepared_template = "nullptr"; + } else if (descriptor->type() == FieldDescriptor::TYPE_MESSAGE && + !descriptor->options().lazy()) { + prepared_template = "nullptr"; + } else if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_STRING) { + if (oneof_member) { + prepared_template = GenerateTemplateForOneofString( + descriptor, (*variables)["proto_ns"], field_member); + } else { + prepared_template = + GenerateTemplateForSingleString(descriptor, field_member); + } + } else { + prepared_template = StrCat("&", field_member); + } + if (descriptor->is_repeated() && !descriptor->is_map() && + descriptor->type() != FieldDescriptor::TYPE_MESSAGE && + descriptor->type() != FieldDescriptor::TYPE_GROUP) { + prepared_flat_template = StrCat("&", field_member); + } else { + prepared_flat_template = prepared_template; + } + + MaySetAnnotationVariable(options, "get", substitute_template_prefix, + prepared_template, descriptor->index(), "OnGet", + variables); + MaySetAnnotationVariable(options, "set", substitute_template_prefix, + prepared_template, descriptor->index(), "OnSet", + variables); + MaySetAnnotationVariable(options, "has", substitute_template_prefix, + prepared_template, descriptor->index(), "OnHas", + variables); + MaySetAnnotationVariable(options, "mutable", substitute_template_prefix, + prepared_template, descriptor->index(), "OnMutable", + variables); + MaySetAnnotationVariable(options, "release", substitute_template_prefix, + prepared_template, descriptor->index(), "OnRelease", + variables); + MaySetAnnotationVariable(options, "clear", substitute_template_prefix, + prepared_flat_template, descriptor->index(), + "OnClear", variables); + MaySetAnnotationVariable(options, "size", substitute_template_prefix, + prepared_flat_template, descriptor->index(), + "OnSize", variables); + MaySetAnnotationVariable(options, "list", substitute_template_prefix, + prepared_flat_template, descriptor->index(), + "OnList", variables); + MaySetAnnotationVariable(options, "mutable_list", substitute_template_prefix, + prepared_flat_template, descriptor->index(), + "OnMutableList", variables); + MaySetAnnotationVariable(options, "add", substitute_template_prefix, + prepared_add_template, descriptor->index(), "OnAdd", + variables); + MaySetAnnotationVariable(options, "add_mutable", substitute_template_prefix, + prepared_add_template, descriptor->index(), + "OnAddMutable", variables); +} + +void SetCommonFieldVariables(const FieldDescriptor* descriptor, + std::map<std::string, std::string>* variables, + const Options& options) { + SetCommonVars(options, variables); + (*variables)["ns"] = Namespace(descriptor, options); + (*variables)["name"] = FieldName(descriptor); + (*variables)["index"] = StrCat(descriptor->index()); + (*variables)["number"] = StrCat(descriptor->number()); + (*variables)["classname"] = ClassName(FieldScope(descriptor), false); + (*variables)["declared_type"] = DeclaredTypeMethodName(descriptor->type()); + (*variables)["field_member"] = FieldName(descriptor) + "_"; + + (*variables)["tag_size"] = StrCat( + WireFormat::TagSize(descriptor->number(), descriptor->type())); + (*variables)["deprecated_attr"] = DeprecatedAttribute(options, descriptor); + + (*variables)["set_hasbit"] = ""; + (*variables)["clear_hasbit"] = ""; + if (HasHasbit(descriptor)) { + (*variables)["set_hasbit_io"] = + "_Internal::set_has_" + FieldName(descriptor) + "(&_has_bits_);"; + } else { + (*variables)["set_hasbit_io"] = ""; + } + + AddAccessorAnnotations(descriptor, options, variables); + + // These variables are placeholders to pick out the beginning and ends of + // identifiers for annotations (when doing so with existing variables would + // be ambiguous or impossible). They should never be set to anything but the + // empty string. + (*variables)["{"] = ""; + (*variables)["}"] = ""; +} + +void FieldGenerator::SetHasBitIndex(int32_t has_bit_index) { + if (!HasHasbit(descriptor_)) { + GOOGLE_CHECK_EQ(has_bit_index, -1); + return; + } + variables_["set_hasbit"] = StrCat( + "_has_bits_[", has_bit_index / 32, "] |= 0x", + strings::Hex(1u << (has_bit_index % 32), strings::ZERO_PAD_8), "u;"); + variables_["clear_hasbit"] = StrCat( + "_has_bits_[", has_bit_index / 32, "] &= ~0x", + strings::Hex(1u << (has_bit_index % 32), strings::ZERO_PAD_8), "u;"); +} + +void FieldGenerator::SetInlinedStringIndex(int32_t inlined_string_index) { + if (!IsStringInlined(descriptor_, options_)) { + GOOGLE_CHECK_EQ(inlined_string_index, -1); + return; + } + variables_["inlined_string_donated"] = StrCat( + "(_inlined_string_donated_[", inlined_string_index / 32, "] & 0x", + strings::Hex(1u << (inlined_string_index % 32), strings::ZERO_PAD_8), + "u) != 0;"); + variables_["donating_states_word"] = + StrCat("_inlined_string_donated_[", inlined_string_index / 32, "]"); + variables_["mask_for_undonate"] = StrCat( + "~0x", strings::Hex(1u << (inlined_string_index % 32), strings::ZERO_PAD_8), + "u"); +} + +void SetCommonOneofFieldVariables( + const FieldDescriptor* descriptor, + std::map<std::string, std::string>* variables) { + const std::string prefix = descriptor->containing_oneof()->name() + "_."; + (*variables)["oneof_name"] = descriptor->containing_oneof()->name(); + (*variables)["field_member"] = + StrCat(prefix, (*variables)["name"], "_"); +} + +FieldGenerator::~FieldGenerator() {} + +FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor, + const Options& options, + MessageSCCAnalyzer* scc_analyzer) + : descriptor_(descriptor), field_generators_(descriptor->field_count()) { + // Construct all the FieldGenerators. + for (int i = 0; i < descriptor->field_count(); i++) { + field_generators_[i].reset( + MakeGenerator(descriptor->field(i), options, scc_analyzer)); + } +} + +FieldGenerator* FieldGeneratorMap::MakeGoogleInternalGenerator( + const FieldDescriptor* field, const Options& options, + MessageSCCAnalyzer* scc_analyzer) { + + return nullptr; +} + +FieldGenerator* FieldGeneratorMap::MakeGenerator( + const FieldDescriptor* field, const Options& options, + MessageSCCAnalyzer* scc_analyzer) { + FieldGenerator* generator = + MakeGoogleInternalGenerator(field, options, scc_analyzer); + if (generator) { + return generator; + } + + if (field->is_repeated()) { + switch (field->cpp_type()) { + case FieldDescriptor::CPPTYPE_MESSAGE: + if (field->is_map()) { + return new MapFieldGenerator(field, options, scc_analyzer); + } else { + return new RepeatedMessageFieldGenerator(field, options, + scc_analyzer); + } + case FieldDescriptor::CPPTYPE_STRING: + return new RepeatedStringFieldGenerator(field, options); + case FieldDescriptor::CPPTYPE_ENUM: + return new RepeatedEnumFieldGenerator(field, options); + default: + return new RepeatedPrimitiveFieldGenerator(field, options); + } + } else if (field->real_containing_oneof()) { + switch (field->cpp_type()) { + case FieldDescriptor::CPPTYPE_MESSAGE: + return new MessageOneofFieldGenerator(field, options, scc_analyzer); + case FieldDescriptor::CPPTYPE_STRING: + return new StringOneofFieldGenerator(field, options); + case FieldDescriptor::CPPTYPE_ENUM: + return new EnumOneofFieldGenerator(field, options); + default: + return new PrimitiveOneofFieldGenerator(field, options); + } + } else { + switch (field->cpp_type()) { + case FieldDescriptor::CPPTYPE_MESSAGE: + return new MessageFieldGenerator(field, options, scc_analyzer); + case FieldDescriptor::CPPTYPE_STRING: + return new StringFieldGenerator(field, options); + case FieldDescriptor::CPPTYPE_ENUM: + return new EnumFieldGenerator(field, options); + default: + return new PrimitiveFieldGenerator(field, options); + } + } +} + +FieldGeneratorMap::~FieldGeneratorMap() {} + +const FieldGenerator& FieldGeneratorMap::get( + const FieldDescriptor* field) const { + GOOGLE_CHECK_EQ(field->containing_type(), descriptor_); + return *field_generators_[field->index()]; +} + +} // namespace cpp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_field.h b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_field.h new file mode 100644 index 00000000..d0ead8c6 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_field.h @@ -0,0 +1,242 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_FIELD_H__ +#define GOOGLE_PROTOBUF_COMPILER_CPP_FIELD_H__ + +#include <cstdint> +#include <map> +#include <memory> +#include <string> + +#include <compiler/cpp/cpp_helpers.h> +#include <compiler/cpp/cpp_options.h> +#include <descriptor.h> + +namespace google { +namespace protobuf { +namespace io { +class Printer; // printer.h +} +} // namespace protobuf +} // namespace google + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { + +// Helper function: set variables in the map that are the same for all +// field code generators. +// ['name', 'index', 'number', 'classname', 'declared_type', 'tag_size', +// 'deprecation']. +void SetCommonFieldVariables(const FieldDescriptor* descriptor, + std::map<std::string, std::string>* variables, + const Options& options); + +void SetCommonOneofFieldVariables( + const FieldDescriptor* descriptor, + std::map<std::string, std::string>* variables); + +class FieldGenerator { + public: + explicit FieldGenerator(const FieldDescriptor* descriptor, + const Options& options) + : descriptor_(descriptor), options_(options) {} + virtual ~FieldGenerator(); + virtual void GenerateSerializeWithCachedSizes( + io::Printer* printer) const final{}; + // Generate lines of code declaring members fields of the message class + // needed to represent this field. These are placed inside the message + // class. + virtual void GeneratePrivateMembers(io::Printer* printer) const = 0; + + // Generate static default variable for this field. These are placed inside + // the message class. Most field types don't need this, so the default + // implementation is empty. + virtual void GenerateStaticMembers(io::Printer* /*printer*/) const {} + + // Generate prototypes for all of the accessor functions related to this + // field. These are placed inside the class definition. + virtual void GenerateAccessorDeclarations(io::Printer* printer) const = 0; + + // Generate inline definitions of accessor functions for this field. + // These are placed inside the header after all class definitions. + virtual void GenerateInlineAccessorDefinitions( + io::Printer* printer) const = 0; + + // Generate definitions of accessors that aren't inlined. These are + // placed somewhere in the .cc file. + // Most field types don't need this, so the default implementation is empty. + virtual void GenerateNonInlineAccessorDefinitions( + io::Printer* /*printer*/) const {} + + // Generate declarations of accessors that are for internal purposes only. + // Most field types don't need this, so the default implementation is empty. + virtual void GenerateInternalAccessorDefinitions( + io::Printer* /*printer*/) const {} + + // Generate definitions of accessors that are for internal purposes only. + // Most field types don't need this, so the default implementation is empty. + virtual void GenerateInternalAccessorDeclarations( + io::Printer* /*printer*/) const {} + + // Generate lines of code (statements, not declarations) which clear the + // field. This is used to define the clear_$name$() method + virtual void GenerateClearingCode(io::Printer* printer) const = 0; + + // Generate lines of code (statements, not declarations) which clear the + // field as part of the Clear() method for the whole message. For message + // types which have field presence bits, MessageGenerator::GenerateClear + // will have already checked the presence bits. + // + // Since most field types can re-use GenerateClearingCode, this method is + // not pure virtual. + virtual void GenerateMessageClearingCode(io::Printer* printer) const { + GenerateClearingCode(printer); + } + + // Generate lines of code (statements, not declarations) which merges the + // contents of the field from the current message to the target message, + // which is stored in the generated code variable "from". + // This is used to fill in the MergeFrom method for the whole message. + // Details of this usage can be found in message.cc under the + // GenerateMergeFrom method. + virtual void GenerateMergingCode(io::Printer* printer) const = 0; + + // Generates a copy constructor + virtual void GenerateCopyConstructorCode(io::Printer* printer) const = 0; + + // Generate lines of code (statements, not declarations) which swaps + // this field and the corresponding field of another message, which + // is stored in the generated code variable "other". This is used to + // define the Swap method. Details of usage can be found in + // message.cc under the GenerateSwap method. + virtual void GenerateSwappingCode(io::Printer* printer) const = 0; + + // Generate initialization code for private members declared by + // GeneratePrivateMembers(). These go into the message class's SharedCtor() + // method, invoked by each of the generated constructors. + virtual void GenerateConstructorCode(io::Printer* printer) const = 0; + + // Generate any code that needs to go in the class's SharedDtor() method, + // invoked by the destructor. + // Most field types don't need this, so the default implementation is empty. + virtual void GenerateDestructorCode(io::Printer* /*printer*/) const {} + + // Generate a manual destructor invocation for use when the message is on an + // arena. The code that this method generates will be executed inside a + // shared-for-the-whole-message-class method registered with + // OwnDestructor(). The method should return |true| if it generated any code + // that requires a call; this allows the message generator to eliminate the + // OwnDestructor() registration if no fields require it. + virtual bool GenerateArenaDestructorCode(io::Printer* printer) const { + return false; + } + + // Generate initialization code for private members declared by + // GeneratePrivateMembers(), specifically for the constexpr constructor. + // These go into the constructor's initializer list and must follow that + // syntax (eg `field_(args)`). Does not include `:` or `,` separators. + virtual void GenerateConstinitInitializer(io::Printer* printer) const {} + + // Generate lines to serialize this field directly to the array "target", + // which are placed within the message's SerializeWithCachedSizesToArray() + // method. This must also advance "target" past the written bytes. + virtual void GenerateSerializeWithCachedSizesToArray( + io::Printer* printer) const = 0; + + // Generate lines to compute the serialized size of this field, which + // are placed in the message's ByteSize() method. + virtual void GenerateByteSize(io::Printer* printer) const = 0; + + // Generates lines to call IsInitialized() for eligible message fields. Non + // message fields won't need to override this function. + virtual void GenerateIsInitialized(io::Printer* printer) const {} + + virtual bool IsInlined() const { return false; } + + void SetHasBitIndex(int32_t has_bit_index); + void SetInlinedStringIndex(int32_t inlined_string_index); + + protected: + const FieldDescriptor* descriptor_; + const Options& options_; + std::map<std::string, std::string> variables_; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGenerator); +}; + +// Convenience class which constructs FieldGenerators for a Descriptor. +class FieldGeneratorMap { + public: + FieldGeneratorMap(const Descriptor* descriptor, const Options& options, + MessageSCCAnalyzer* scc_analyzer); + ~FieldGeneratorMap(); + + const FieldGenerator& get(const FieldDescriptor* field) const; + + void SetHasBitIndices(const std::vector<int>& has_bit_indices_) { + for (int i = 0; i < descriptor_->field_count(); ++i) { + field_generators_[i]->SetHasBitIndex(has_bit_indices_[i]); + } + } + + void SetInlinedStringIndices(const std::vector<int>& inlined_string_indices) { + for (int i = 0; i < descriptor_->field_count(); ++i) { + field_generators_[i]->SetInlinedStringIndex(inlined_string_indices[i]); + } + } + + private: + const Descriptor* descriptor_; + std::vector<std::unique_ptr<FieldGenerator>> field_generators_; + + static FieldGenerator* MakeGoogleInternalGenerator( + const FieldDescriptor* field, const Options& options, + MessageSCCAnalyzer* scc_analyzer); + static FieldGenerator* MakeGenerator(const FieldDescriptor* field, + const Options& options, + MessageSCCAnalyzer* scc_analyzer); + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGeneratorMap); +}; + +} // namespace cpp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_CPP_FIELD_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_file.cc b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_file.cc new file mode 100644 index 00000000..51758b9e --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_file.cc @@ -0,0 +1,1419 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <compiler/cpp/cpp_file.h> + +#include <iostream> +#include <map> +#include <memory> +#include <set> +#include <unordered_map> +#include <unordered_set> +#include <vector> + +#include <compiler/cpp/cpp_enum.h> +#include <compiler/cpp/cpp_extension.h> +#include <compiler/cpp/cpp_field.h> +#include <compiler/cpp/cpp_helpers.h> +#include <compiler/cpp/cpp_message.h> +#include <compiler/cpp/cpp_service.h> +#include <compiler/scc.h> +#include <descriptor.pb.h> +#include <io/printer.h> +#include <stubs/strutil.h> + +// Must be last. +#include <port_def.inc> + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { + +namespace { + +// When we forward-declare things, we want to create a sorted order so our +// output is deterministic and minimizes namespace changes. +template <class T> +std::string GetSortKey(const T& val) { + return val.full_name(); +} + +template <> +std::string GetSortKey<FileDescriptor>(const FileDescriptor& val) { + return val.name(); +} + +template <class T> +bool CompareSortKeys(const T* a, const T* b) { + return GetSortKey(*a) < GetSortKey(*b); +} + +template <class T> +std::vector<const T*> Sorted(const std::unordered_set<const T*>& vals) { + std::vector<const T*> sorted(vals.begin(), vals.end()); + std::sort(sorted.begin(), sorted.end(), CompareSortKeys<T>); + return sorted; +} + +} // namespace + +FileGenerator::FileGenerator(const FileDescriptor* file, const Options& options) + : file_(file), options_(options), scc_analyzer_(options) { + // These variables are the same on a file level + SetCommonVars(options, &variables_); + variables_["dllexport_decl"] = options.dllexport_decl; + variables_["tablename"] = UniqueName("TableStruct", file_, options_); + variables_["file_level_metadata"] = + UniqueName("file_level_metadata", file_, options_); + variables_["desc_table"] = DescriptorTableName(file_, options_); + variables_["file_level_enum_descriptors"] = + UniqueName("file_level_enum_descriptors", file_, options_); + variables_["file_level_service_descriptors"] = + UniqueName("file_level_service_descriptors", file_, options_); + variables_["filename"] = file_->name(); + variables_["package_ns"] = Namespace(file_, options); + + std::vector<const Descriptor*> msgs = FlattenMessagesInFile(file); + for (int i = 0; i < msgs.size(); i++) { + // Deleted in destructor + MessageGenerator* msg_gen = + new MessageGenerator(msgs[i], variables_, i, options, &scc_analyzer_); + message_generators_.emplace_back(msg_gen); + msg_gen->AddGenerators(&enum_generators_, &extension_generators_); + } + + for (int i = 0; i < file->enum_type_count(); i++) { + enum_generators_.emplace_back( + new EnumGenerator(file->enum_type(i), variables_, options)); + } + + for (int i = 0; i < file->service_count(); i++) { + service_generators_.emplace_back( + new ServiceGenerator(file->service(i), variables_, options)); + } + if (HasGenericServices(file_, options_)) { + for (int i = 0; i < service_generators_.size(); i++) { + service_generators_[i]->index_in_metadata_ = i; + } + } + for (int i = 0; i < file->extension_count(); i++) { + extension_generators_.emplace_back( + new ExtensionGenerator(file->extension(i), options, &scc_analyzer_)); + } + for (int i = 0; i < file->weak_dependency_count(); ++i) { + weak_deps_.insert(file->weak_dependency(i)); + } +} + +FileGenerator::~FileGenerator() = default; + +void FileGenerator::GenerateMacroUndefs(io::Printer* printer) { + Formatter format(printer, variables_); + // Only do this for protobuf's own types. There are some google3 protos using + // macros as field names and the generated code compiles after the macro + // expansion. Undefing these macros actually breaks such code. + if (file_->name() != "net/proto2/compiler/proto/plugin.proto" && + file_->name() != "google/protobuf/compiler/plugin.proto") { + return; + } + std::vector<std::string> names_to_undef; + std::vector<const FieldDescriptor*> fields; + ListAllFields(file_, &fields); + for (int i = 0; i < fields.size(); i++) { + const std::string& name = fields[i]->name(); + static const char* kMacroNames[] = {"major", "minor"}; + for (int j = 0; j < GOOGLE_ARRAYSIZE(kMacroNames); ++j) { + if (name == kMacroNames[j]) { + names_to_undef.push_back(name); + break; + } + } + } + for (int i = 0; i < names_to_undef.size(); ++i) { + format( + "#ifdef $1$\n" + "#undef $1$\n" + "#endif\n", + names_to_undef[i]); + } +} + +void FileGenerator::GenerateHeader(io::Printer* printer) { + Formatter format(printer, variables_); + + // port_def.inc must be included after all other includes. + IncludeFile("net/proto2/public/port_def.inc", printer); + format("#define $1$$ dllexport_decl$\n", FileDllExport(file_, options_)); + GenerateMacroUndefs(printer); + + // For Any support with lite protos, we need to friend AnyMetadata, so we + // forward-declare it here. + format( + "PROTOBUF_NAMESPACE_OPEN\n" + "namespace internal {\n" + "class AnyMetadata;\n" + "} // namespace internal\n" + "PROTOBUF_NAMESPACE_CLOSE\n"); + + GenerateGlobalStateFunctionDeclarations(printer); + + GenerateForwardDeclarations(printer); + + { + NamespaceOpener ns(Namespace(file_, options_), format); + + format("\n"); + + GenerateEnumDefinitions(printer); + + format(kThickSeparator); + format("\n"); + + GenerateMessageDefinitions(printer); + + format("\n"); + format(kThickSeparator); + format("\n"); + + GenerateServiceDefinitions(printer); + + GenerateExtensionIdentifiers(printer); + + format("\n"); + format(kThickSeparator); + format("\n"); + + GenerateInlineFunctionDefinitions(printer); + + format( + "\n" + "// @@protoc_insertion_point(namespace_scope)\n" + "\n"); + } + + // We need to specialize some templates in the ::google::protobuf namespace: + GenerateProto2NamespaceEnumSpecializations(printer); + + format( + "\n" + "// @@protoc_insertion_point(global_scope)\n" + "\n"); + IncludeFile("net/proto2/public/port_undef.inc", printer); +} + +void FileGenerator::GenerateProtoHeader(io::Printer* printer, + const std::string& info_path) { + Formatter format(printer, variables_); + if (!options_.proto_h) { + return; + } + + GenerateTopHeaderGuard(printer, false); + + if (!options_.opensource_runtime) { + format( + "#ifdef SWIG\n" + "#error \"Do not SWIG-wrap protobufs.\"\n" + "#endif // SWIG\n" + "\n"); + } + + if (IsBootstrapProto(options_, file_)) { + format("// IWYU pragma: private, include \"$1$.proto.h\"\n\n", + StripProto(file_->name())); + } + + GenerateLibraryIncludes(printer); + + for (int i = 0; i < file_->public_dependency_count(); i++) { + const FileDescriptor* dep = file_->public_dependency(i); + format("#include \"$1$.proto.h\"\n", StripProto(dep->name())); + } + + format("// @@protoc_insertion_point(includes)\n"); + + GenerateMetadataPragma(printer, info_path); + + GenerateHeader(printer); + + GenerateBottomHeaderGuard(printer, false); +} + +void FileGenerator::GeneratePBHeader(io::Printer* printer, + const std::string& info_path) { + Formatter format(printer, variables_); + GenerateTopHeaderGuard(printer, true); + + if (options_.proto_h) { + std::string target_basename = StripProto(file_->name()); + if (!options_.opensource_runtime) { + GetBootstrapBasename(options_, target_basename, &target_basename); + } + format("#include \"$1$.proto.h\" // IWYU pragma: export\n", + target_basename); + } else { + GenerateLibraryIncludes(printer); + } + + if (options_.transitive_pb_h) { + GenerateDependencyIncludes(printer); + } + + // This is unfortunately necessary for some plugins. I don't see why we + // need two of the same insertion points. + // TODO(gerbens) remove this. + format("// @@protoc_insertion_point(includes)\n"); + + GenerateMetadataPragma(printer, info_path); + + if (!options_.proto_h) { + GenerateHeader(printer); + } else { + { + NamespaceOpener ns(Namespace(file_, options_), format); + format( + "\n" + "// @@protoc_insertion_point(namespace_scope)\n"); + } + format( + "\n" + "// @@protoc_insertion_point(global_scope)\n" + "\n"); + } + + GenerateBottomHeaderGuard(printer, true); +} + +void FileGenerator::DoIncludeFile(const std::string& google3_name, + bool do_export, io::Printer* printer) { + Formatter format(printer, variables_); + const std::string prefix = "net/proto2/"; + GOOGLE_CHECK(google3_name.find(prefix) == 0) << google3_name; + + if (options_.opensource_runtime) { + std::string path = google3_name.substr(prefix.size()); + + path = StringReplace(path, "internal/", "", false); + path = StringReplace(path, "proto/", "", false); + path = StringReplace(path, "public/", "", false); + if (options_.runtime_include_base.empty()) { + format("#include <$1$>", path); + } else { + format("#include \"$1$google/protobuf/$2$\"", + options_.runtime_include_base, path); + } + } else { + format("#include \"$1$\"", google3_name); + } + + if (do_export) { + format(" // IWYU pragma: export"); + } + + format("\n"); +} + +std::string FileGenerator::CreateHeaderInclude(const std::string& basename, + const FileDescriptor* file) { + bool use_system_include = false; + std::string name = basename; + + if (options_.opensource_runtime) { + if (IsWellKnownMessage(file)) { + if (options_.runtime_include_base.empty()) { + use_system_include = true; + } else { + name = options_.runtime_include_base + basename; + } + } + } + + std::string left = "\""; + std::string right = "\""; + if (use_system_include) { + left = "<"; + right = ">"; + } + return left + name + right; +} + +void FileGenerator::GenerateSourceIncludes(io::Printer* printer) { + Formatter format(printer, variables_); + std::string target_basename = StripProto(file_->name()); + if (!options_.opensource_runtime) { + GetBootstrapBasename(options_, target_basename, &target_basename); + } + target_basename += options_.proto_h ? ".proto.h" : ".pb.h"; + format( + "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" + "// source: $filename$\n" + "\n" + "#include $1$\n" + "\n" + "#include <algorithm>\n" // for swap() + "\n", + CreateHeaderInclude(target_basename, file_)); + + IncludeFile("net/proto2/io/public/coded_stream.h", printer); + // TODO(gerbens) This is to include parse_context.h, we need a better way + IncludeFile("net/proto2/public/extension_set.h", printer); + IncludeFile("net/proto2/public/wire_format_lite.h", printer); + + // Unknown fields implementation in lite mode uses StringOutputStream + if (!UseUnknownFieldSet(file_, options_) && !message_generators_.empty()) { + IncludeFile("net/proto2/io/public/zero_copy_stream_impl_lite.h", printer); + } + + if (HasDescriptorMethods(file_, options_)) { + IncludeFile("net/proto2/public/descriptor.h", printer); + IncludeFile("net/proto2/public/generated_message_reflection.h", printer); + IncludeFile("net/proto2/public/reflection_ops.h", printer); + IncludeFile("net/proto2/public/wire_format.h", printer); + } + + if (HasGeneratedMethods(file_, options_) && + options_.tctable_mode != Options::kTCTableNever) { + IncludeFile("net/proto2/public/generated_message_tctable_impl.h", printer); + } + + if (options_.proto_h) { + // Use the smaller .proto.h files. + for (int i = 0; i < file_->dependency_count(); i++) { + const FileDescriptor* dep = file_->dependency(i); + // Do not import weak deps. + if (!options_.opensource_runtime && IsDepWeak(dep)) continue; + std::string basename = StripProto(dep->name()); + if (IsBootstrapProto(options_, file_)) { + GetBootstrapBasename(options_, basename, &basename); + } + format("#include \"$1$.proto.h\"\n", basename); + } + } + if (HasCordFields(file_, options_)) { + format( + "#include \"third_party/absl/strings/internal/string_constant.h\"\n"); + } + + format("// @@protoc_insertion_point(includes)\n"); + IncludeFile("net/proto2/public/port_def.inc", printer); + + // For MSVC builds, we use #pragma init_seg to move the initialization of our + // libraries to happen before the user code. + // This worksaround the fact that MSVC does not do constant initializers when + // required by the standard. + format("\nPROTOBUF_PRAGMA_INIT_SEG\n"); +} + +void FileGenerator::GenerateSourceDefaultInstance(int idx, + io::Printer* printer) { + Formatter format(printer, variables_); + MessageGenerator* generator = message_generators_[idx].get(); + generator->GenerateConstexprConstructor(printer); + // Use a union to disable the destructor of the _instance member. + // We can constant initialize, but the object will still have a non-trivial + // destructor that we need to elide. + format( + "struct $1$ {\n" + " constexpr $1$()\n" + " : _instance(::$proto_ns$::internal::ConstantInitialized{}) {}\n" + " ~$1$() {}\n" + " union {\n" + " $2$ _instance;\n" + " };\n" + "};\n", + DefaultInstanceType(generator->descriptor_, options_), + generator->classname_); + // NO_DESTROY is not necessary for correctness. The empty destructor is + // enough. However, the empty destructor fails to be elided in some + // configurations (like non-opt or with certain sanitizers). NO_DESTROY is + // there just to improve performance and binary size in these builds. + format("PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT $1$ $2$;\n", + DefaultInstanceType(generator->descriptor_, options_), + DefaultInstanceName(generator->descriptor_, options_)); + + for (int i = 0; i < generator->descriptor_->field_count(); i++) { + const FieldDescriptor* field = generator->descriptor_->field(i); + if (IsStringInlined(field, options_)) { + // Force the initialization of the inlined string in the default instance. + format( + "PROTOBUF_ATTRIBUTE_INIT_PRIORITY std::true_type " + "$1$::_init_inline_$2$_ = " + "($3$._instance.$2$_.Init(), std::true_type{});\n", + ClassName(generator->descriptor_), FieldName(field), + DefaultInstanceName(generator->descriptor_, options_)); + } + } + + if (options_.lite_implicit_weak_fields) { + format("$1$* $2$ = &$3$;\n", + DefaultInstanceType(generator->descriptor_, options_), + DefaultInstancePtr(generator->descriptor_, options_), + DefaultInstanceName(generator->descriptor_, options_)); + } +} + +// A list of things defined in one .pb.cc file that we need to reference from +// another .pb.cc file. +struct FileGenerator::CrossFileReferences { + // Populated if we are referencing from messages or files. + std::unordered_set<const Descriptor*> weak_default_instances; + + // Only if we are referencing from files. + std::unordered_set<const FileDescriptor*> strong_reflection_files; + std::unordered_set<const FileDescriptor*> weak_reflection_files; +}; + +void FileGenerator::GetCrossFileReferencesForField(const FieldDescriptor* field, + CrossFileReferences* refs) { + const Descriptor* msg = field->message_type(); + if (msg == nullptr) return; + + if (IsImplicitWeakField(field, options_, &scc_analyzer_) || + IsWeak(field, options_)) { + refs->weak_default_instances.insert(msg); + } +} + +void FileGenerator::GetCrossFileReferencesForFile(const FileDescriptor* file, + CrossFileReferences* refs) { + ForEachField(file, [this, refs](const FieldDescriptor* field) { + GetCrossFileReferencesForField(field, refs); + }); + + if (!HasDescriptorMethods(file, options_)) return; + + for (int i = 0; i < file->dependency_count(); i++) { + const FileDescriptor* dep = file->dependency(i); + if (IsDepWeak(dep)) { + refs->weak_reflection_files.insert(dep); + } else { + refs->strong_reflection_files.insert(dep); + } + } +} + +// Generates references to variables defined in other files. +void FileGenerator::GenerateInternalForwardDeclarations( + const CrossFileReferences& refs, io::Printer* printer) { + Formatter format(printer, variables_); + + { + NamespaceOpener ns(format); + for (auto instance : Sorted(refs.weak_default_instances)) { + ns.ChangeTo(Namespace(instance, options_)); + if (options_.lite_implicit_weak_fields) { + format("extern $1$ $2$;\n", DefaultInstanceType(instance, options_), + DefaultInstanceName(instance, options_)); + format("__attribute__((weak)) $1$* $2$ = nullptr;\n", + DefaultInstanceType(instance, options_), + DefaultInstancePtr(instance, options_)); + } else { + format("extern __attribute__((weak)) $1$ $2$;\n", + DefaultInstanceType(instance, options_), + DefaultInstanceName(instance, options_)); + } + } + } + + for (auto file : Sorted(refs.weak_reflection_files)) { + format( + "extern __attribute__((weak)) const " + "::$proto_ns$::internal::DescriptorTable $1$;\n", + DescriptorTableName(file, options_)); + } +} + +void FileGenerator::GenerateSourceForMessage(int idx, io::Printer* printer) { + Formatter format(printer, variables_); + GenerateSourceIncludes(printer); + + CrossFileReferences refs; + ForEachField(message_generators_[idx]->descriptor_, + [this, &refs](const FieldDescriptor* field) { + GetCrossFileReferencesForField(field, &refs); + }); + GenerateInternalForwardDeclarations(refs, printer); + + { // package namespace + NamespaceOpener ns(Namespace(file_, options_), format); + + // Define default instances + GenerateSourceDefaultInstance(idx, printer); + + // Generate classes. + format("\n"); + message_generators_[idx]->GenerateClassMethods(printer); + + format( + "\n" + "// @@protoc_insertion_point(namespace_scope)\n"); + } // end package namespace + + { + NamespaceOpener proto_ns(ProtobufNamespace(options_), format); + message_generators_[idx]->GenerateSourceInProto2Namespace(printer); + } + + format( + "\n" + "// @@protoc_insertion_point(global_scope)\n"); +} + +void FileGenerator::GenerateSourceForExtension(int idx, io::Printer* printer) { + Formatter format(printer, variables_); + GenerateSourceIncludes(printer); + NamespaceOpener ns(Namespace(file_, options_), format); + extension_generators_[idx]->GenerateDefinition(printer); +} + +void FileGenerator::GenerateGlobalSource(io::Printer* printer) { + Formatter format(printer, variables_); + GenerateSourceIncludes(printer); + + { + GenerateTables(printer); + + // Define the code to initialize reflection. This code uses a global + // constructor to register reflection data with the runtime pre-main. + if (HasDescriptorMethods(file_, options_)) { + GenerateReflectionInitializationCode(printer); + } + } + + NamespaceOpener ns(Namespace(file_, options_), format); + + // Generate enums. + for (int i = 0; i < enum_generators_.size(); i++) { + enum_generators_[i]->GenerateMethods(i, printer); + } +} + +void FileGenerator::GenerateSource(io::Printer* printer) { + Formatter format(printer, variables_); + GenerateSourceIncludes(printer); + CrossFileReferences refs; + GetCrossFileReferencesForFile(file_, &refs); + GenerateInternalForwardDeclarations(refs, printer); + + { + NamespaceOpener ns(Namespace(file_, options_), format); + + // Define default instances + for (int i = 0; i < message_generators_.size(); i++) { + GenerateSourceDefaultInstance(i, printer); + } + } + + { + GenerateTables(printer); + + if (HasDescriptorMethods(file_, options_)) { + // Define the code to initialize reflection. This code uses a global + // constructor to register reflection data with the runtime pre-main. + GenerateReflectionInitializationCode(printer); + } + } + + { + NamespaceOpener ns(Namespace(file_, options_), format); + + // Actually implement the protos + + // Generate enums. + for (int i = 0; i < enum_generators_.size(); i++) { + enum_generators_[i]->GenerateMethods(i, printer); + } + + // Generate classes. + for (int i = 0; i < message_generators_.size(); i++) { + format("\n"); + format(kThickSeparator); + format("\n"); + message_generators_[i]->GenerateClassMethods(printer); + } + + if (HasGenericServices(file_, options_)) { + // Generate services. + for (int i = 0; i < service_generators_.size(); i++) { + if (i == 0) format("\n"); + format(kThickSeparator); + format("\n"); + service_generators_[i]->GenerateImplementation(printer); + } + } + + // Define extensions. + for (int i = 0; i < extension_generators_.size(); i++) { + extension_generators_[i]->GenerateDefinition(printer); + } + + format( + "\n" + "// @@protoc_insertion_point(namespace_scope)\n"); + } + + { + NamespaceOpener proto_ns(ProtobufNamespace(options_), format); + for (int i = 0; i < message_generators_.size(); i++) { + message_generators_[i]->GenerateSourceInProto2Namespace(printer); + } + } + + format( + "\n" + "// @@protoc_insertion_point(global_scope)\n"); + + IncludeFile("net/proto2/public/port_undef.inc", printer); +} + +void FileGenerator::GenerateReflectionInitializationCode(io::Printer* printer) { + Formatter format(printer, variables_); + + if (!message_generators_.empty()) { + format("static ::$proto_ns$::Metadata $file_level_metadata$[$1$];\n", + message_generators_.size()); + } + if (!enum_generators_.empty()) { + format( + "static " + "const ::$proto_ns$::EnumDescriptor* " + "$file_level_enum_descriptors$[$1$];\n", + enum_generators_.size()); + } else { + format( + "static " + "constexpr ::$proto_ns$::EnumDescriptor const** " + "$file_level_enum_descriptors$ = nullptr;\n"); + } + if (HasGenericServices(file_, options_) && file_->service_count() > 0) { + format( + "static " + "const ::$proto_ns$::ServiceDescriptor* " + "$file_level_service_descriptors$[$1$];\n", + file_->service_count()); + } else { + format( + "static " + "constexpr ::$proto_ns$::ServiceDescriptor const** " + "$file_level_service_descriptors$ = nullptr;\n"); + } + + if (!message_generators_.empty()) { + format( + "\n" + "const $uint32$ $tablename$::offsets[] " + "PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {\n"); + format.Indent(); + std::vector<std::pair<size_t, size_t> > pairs; + pairs.reserve(message_generators_.size()); + for (int i = 0; i < message_generators_.size(); i++) { + pairs.push_back(message_generators_[i]->GenerateOffsets(printer)); + } + format.Outdent(); + format( + "};\n" + "static const ::$proto_ns$::internal::MigrationSchema schemas[] " + "PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {\n"); + format.Indent(); + { + int offset = 0; + for (int i = 0; i < message_generators_.size(); i++) { + message_generators_[i]->GenerateSchema(printer, offset, + pairs[i].second); + offset += pairs[i].first; + } + } + format.Outdent(); + format( + "};\n" + "\nstatic " + "::$proto_ns$::Message const * const file_default_instances[] = {\n"); + format.Indent(); + for (int i = 0; i < message_generators_.size(); i++) { + const Descriptor* descriptor = message_generators_[i]->descriptor_; + format( + "reinterpret_cast<const " + "::$proto_ns$::Message*>(&$1$::_$2$_default_instance_),\n", + Namespace(descriptor, options_), // 1 + ClassName(descriptor)); // 2 + } + format.Outdent(); + format( + "};\n" + "\n"); + } else { + // we still need these symbols to exist + format( + // MSVC doesn't like empty arrays, so we add a dummy. + "const $uint32$ $tablename$::offsets[1] = {};\n" + "static constexpr ::$proto_ns$::internal::MigrationSchema* schemas = " + "nullptr;" + "\n" + "static constexpr ::$proto_ns$::Message* const* " + "file_default_instances = nullptr;\n" + "\n"); + } + + // --------------------------------------------------------------- + + // Embed the descriptor. We simply serialize the entire + // FileDescriptorProto/ and embed it as a string literal, which is parsed and + // built into real descriptors at initialization time. + const std::string protodef_name = + UniqueName("descriptor_table_protodef", file_, options_); + format("const char $1$[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) =\n", + protodef_name); + format.Indent(); + FileDescriptorProto file_proto; + file_->CopyTo(&file_proto); + std::string file_data; + file_proto.SerializeToString(&file_data); + + { + if (file_data.size() > 65535) { + // Workaround for MSVC: "Error C1091: compiler limit: string exceeds + // 65535 bytes in length". Declare a static array of chars rather than + // use a string literal. Only write 25 bytes per line. + static const int kBytesPerLine = 25; + format("{ "); + for (int i = 0; i < file_data.size();) { + for (int j = 0; j < kBytesPerLine && i < file_data.size(); ++i, ++j) { + format("'$1$', ", CEscape(file_data.substr(i, 1))); + } + format("\n"); + } + format("'\\0' }"); // null-terminate + } else { + // Only write 40 bytes per line. + static const int kBytesPerLine = 40; + for (int i = 0; i < file_data.size(); i += kBytesPerLine) { + format( + "\"$1$\"\n", + EscapeTrigraphs(CEscape(file_data.substr(i, kBytesPerLine)))); + } + } + format(";\n"); + } + format.Outdent(); + + CrossFileReferences refs; + GetCrossFileReferencesForFile(file_, &refs); + int num_deps = + refs.strong_reflection_files.size() + refs.weak_reflection_files.size(); + + // Build array of DescriptorTable deps. + if (num_deps > 0) { + format( + "static const ::$proto_ns$::internal::DescriptorTable*const " + "$desc_table$_deps[$1$] = {\n", + num_deps); + + for (auto dep : Sorted(refs.strong_reflection_files)) { + format(" &::$1$,\n", DescriptorTableName(dep, options_)); + } + for (auto dep : Sorted(refs.weak_reflection_files)) { + format(" &::$1$,\n", DescriptorTableName(dep, options_)); + } + + format("};\n"); + } + + // The DescriptorTable itself. + // Should be "bool eager = NeedsEagerDescriptorAssignment(file_, options_);" + // however this might cause a tsan failure in superroot b/148382879, + // so disable for now. + bool eager = false; + format( + "static ::$proto_ns$::internal::once_flag $desc_table$_once;\n" + "const ::$proto_ns$::internal::DescriptorTable $desc_table$ = {\n" + " false, $1$, $2$, $3$, \"$filename$\", \n" + " &$desc_table$_once, $4$, $5$, $6$,\n" + " schemas, file_default_instances, $tablename$::offsets,\n" + " $7$, $file_level_enum_descriptors$, " + "$file_level_service_descriptors$,\n" + "};\n" + // This function exists to be marked as weak. + // It can significantly speed up compilation by breaking up LLVM's SCC in + // the .pb.cc translation units. Large translation units see a reduction + // of more than 35% of walltime for optimized builds. + // Without the weak attribute all the messages in the file, including all + // the vtables and everything they use become part of the same SCC through + // a cycle like: + // GetMetadata -> descriptor table -> default instances -> + // vtables -> GetMetadata + // By adding a weak function here we break the connection from the + // individual vtables back into the descriptor table. + "PROTOBUF_ATTRIBUTE_WEAK const ::$proto_ns$::internal::DescriptorTable* " + "$desc_table$_getter() {\n" + " return &$desc_table$;\n" + "}\n" + "\n", + eager ? "true" : "false", file_data.size(), protodef_name, + num_deps == 0 ? "nullptr" : variables_["desc_table"] + "_deps", num_deps, + message_generators_.size(), + message_generators_.empty() ? "nullptr" + : variables_["file_level_metadata"]); + + // For descriptor.proto we want to avoid doing any dynamic initialization, + // because in some situations that would otherwise pull in a lot of + // unnecessary code that can't be stripped by --gc-sections. Descriptor + // initialization will still be performed lazily when it's needed. + if (file_->name() != "net/proto2/proto/descriptor.proto") { + format( + "// Force running AddDescriptors() at dynamic initialization time.\n" + "PROTOBUF_ATTRIBUTE_INIT_PRIORITY " + "static ::$proto_ns$::internal::AddDescriptorsRunner " + "$1$(&$desc_table$);\n", + UniqueName("dynamic_init_dummy", file_, options_)); + } +} + +void FileGenerator::GenerateTables(io::Printer* printer) { + Formatter format(printer, variables_); + if (options_.table_driven_parsing) { + // TODO(ckennelly): Gate this with the same options flag to enable + // table-driven parsing. + format( + "PROTOBUF_CONSTEXPR_VAR ::$proto_ns$::internal::ParseTableField\n" + " const $tablename$::entries[] " + "PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {\n"); + format.Indent(); + + std::vector<size_t> entries; + size_t count = 0; + for (int i = 0; i < message_generators_.size(); i++) { + size_t value = message_generators_[i]->GenerateParseOffsets(printer); + entries.push_back(value); + count += value; + } + + // We need these arrays to exist, and MSVC does not like empty arrays. + if (count == 0) { + format("{0, 0, 0, ::$proto_ns$::internal::kInvalidMask, 0, 0},\n"); + } + + format.Outdent(); + format( + "};\n" + "\n" + "PROTOBUF_CONSTEXPR_VAR " + "::$proto_ns$::internal::AuxiliaryParseTableField\n" + " const $tablename$::aux[] " + "PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {\n"); + format.Indent(); + + std::vector<size_t> aux_entries; + count = 0; + for (int i = 0; i < message_generators_.size(); i++) { + size_t value = message_generators_[i]->GenerateParseAuxTable(printer); + aux_entries.push_back(value); + count += value; + } + + if (count == 0) { + format("::$proto_ns$::internal::AuxiliaryParseTableField(),\n"); + } + + format.Outdent(); + format( + "};\n" + "PROTOBUF_CONSTEXPR_VAR ::$proto_ns$::internal::ParseTable const\n" + " $tablename$::schema[] " + "PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {\n"); + format.Indent(); + + size_t offset = 0; + size_t aux_offset = 0; + for (int i = 0; i < message_generators_.size(); i++) { + message_generators_[i]->GenerateParseTable(printer, offset, aux_offset); + offset += entries[i]; + aux_offset += aux_entries[i]; + } + + if (message_generators_.empty()) { + format("{ nullptr, nullptr, 0, -1, -1, false },\n"); + } + + format.Outdent(); + format( + "};\n" + "\n"); + } + + if (!message_generators_.empty() && options_.table_driven_serialization) { + format( + "const ::$proto_ns$::internal::FieldMetadata " + "$tablename$::field_metadata[] " + "= {\n"); + format.Indent(); + std::vector<int> field_metadata_offsets; + int idx = 0; + for (int i = 0; i < message_generators_.size(); i++) { + field_metadata_offsets.push_back(idx); + idx += message_generators_[i]->GenerateFieldMetadata(printer); + } + field_metadata_offsets.push_back(idx); + format.Outdent(); + format( + "};\n" + "const ::$proto_ns$::internal::SerializationTable " + "$tablename$::serialization_table[] = {\n"); + format.Indent(); + // We rely on the order we layout the tables to match the order we + // calculate them with FlattenMessagesInFile, so we check here that + // these match exactly. + std::vector<const Descriptor*> calculated_order = + FlattenMessagesInFile(file_); + GOOGLE_CHECK_EQ(calculated_order.size(), message_generators_.size()); + for (int i = 0; i < message_generators_.size(); i++) { + GOOGLE_CHECK_EQ(calculated_order[i], message_generators_[i]->descriptor_); + format("{$1$, $tablename$::field_metadata + $2$},\n", + field_metadata_offsets[i + 1] - field_metadata_offsets[i], // 1 + field_metadata_offsets[i]); // 2 + } + format.Outdent(); + format( + "};\n" + "\n"); + } +} + +class FileGenerator::ForwardDeclarations { + public: + void AddMessage(const Descriptor* d) { classes_[ClassName(d)] = d; } + void AddEnum(const EnumDescriptor* d) { enums_[ClassName(d)] = d; } + + void Print(const Formatter& format, const Options& options) const { + for (const auto& p : enums_) { + const std::string& enumname = p.first; + const EnumDescriptor* enum_desc = p.second; + format( + "enum ${1$$2$$}$ : int;\n" + "bool $2$_IsValid(int value);\n", + enum_desc, enumname); + } + for (const auto& p : classes_) { + const std::string& classname = p.first; + const Descriptor* class_desc = p.second; + format( + "class ${1$$2$$}$;\n" + "struct $3$;\n" + "$dllexport_decl $extern $3$ $4$;\n", + class_desc, classname, DefaultInstanceType(class_desc, options), + DefaultInstanceName(class_desc, options)); + } + } + + void PrintTopLevelDecl(const Formatter& format, + const Options& options) const { + for (const auto& pair : classes_) { + format( + "template<> $dllexport_decl $" + "$1$* Arena::CreateMaybeMessage<$1$>(Arena*);\n", + QualifiedClassName(pair.second, options)); + } + } + + private: + std::map<std::string, const Descriptor*> classes_; + std::map<std::string, const EnumDescriptor*> enums_; +}; + +static void PublicImportDFS(const FileDescriptor* fd, + std::unordered_set<const FileDescriptor*>* fd_set) { + for (int i = 0; i < fd->public_dependency_count(); i++) { + const FileDescriptor* dep = fd->public_dependency(i); + if (fd_set->insert(dep).second) PublicImportDFS(dep, fd_set); + } +} + +void FileGenerator::GenerateForwardDeclarations(io::Printer* printer) { + Formatter format(printer, variables_); + std::vector<const Descriptor*> classes; + std::vector<const EnumDescriptor*> enums; + + FlattenMessagesInFile(file_, &classes); // All messages need forward decls. + + if (options_.proto_h) { // proto.h needs extra forward declarations. + // All classes / enums referred to as field members + std::vector<const FieldDescriptor*> fields; + ListAllFields(file_, &fields); + for (int i = 0; i < fields.size(); i++) { + classes.push_back(fields[i]->containing_type()); + classes.push_back(fields[i]->message_type()); + enums.push_back(fields[i]->enum_type()); + } + ListAllTypesForServices(file_, &classes); + } + + // Calculate the set of files whose definitions we get through include. + // No need to forward declare types that are defined in these. + std::unordered_set<const FileDescriptor*> public_set; + PublicImportDFS(file_, &public_set); + + std::map<std::string, ForwardDeclarations> decls; + for (int i = 0; i < classes.size(); i++) { + const Descriptor* d = classes[i]; + if (d && !public_set.count(d->file())) + decls[Namespace(d, options_)].AddMessage(d); + } + for (int i = 0; i < enums.size(); i++) { + const EnumDescriptor* d = enums[i]; + if (d && !public_set.count(d->file())) + decls[Namespace(d, options_)].AddEnum(d); + } + + { + NamespaceOpener ns(format); + for (const auto& pair : decls) { + ns.ChangeTo(pair.first); + pair.second.Print(format, options_); + } + } + format("PROTOBUF_NAMESPACE_OPEN\n"); + for (const auto& pair : decls) { + pair.second.PrintTopLevelDecl(format, options_); + } + format("PROTOBUF_NAMESPACE_CLOSE\n"); +} + +void FileGenerator::GenerateTopHeaderGuard(io::Printer* printer, bool pb_h) { + Formatter format(printer, variables_); + // Generate top of header. + format( + "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" + "// source: $filename$\n" + "\n" + "#ifndef $1$\n" + "#define $1$\n" + "\n" + "#include <limits>\n" + "#include <string>\n", + IncludeGuard(file_, pb_h, options_)); + if (!options_.opensource_runtime && !enum_generators_.empty()) { + // Add header to provide std::is_integral for safe Enum_Name() function. + format("#include <type_traits>\n"); + } + format("\n"); +} + +void FileGenerator::GenerateBottomHeaderGuard(io::Printer* printer, bool pb_h) { + Formatter format(printer, variables_); + format("#endif // $GOOGLE_PROTOBUF$_INCLUDED_$1$\n", + IncludeGuard(file_, pb_h, options_)); +} + +void FileGenerator::GenerateLibraryIncludes(io::Printer* printer) { + Formatter format(printer, variables_); + if (UsingImplicitWeakFields(file_, options_)) { + IncludeFile("net/proto2/public/implicit_weak_message.h", printer); + } + if (HasWeakFields(file_, options_)) { + GOOGLE_CHECK(!options_.opensource_runtime); + IncludeFile("net/proto2/public/weak_field_map.h", printer); + } + if (HasLazyFields(file_, options_, &scc_analyzer_)) { + GOOGLE_CHECK(!options_.opensource_runtime); + IncludeFile("net/proto2/public/lazy_field.h", printer); + } + if (ShouldVerify(file_, options_, &scc_analyzer_)) { + IncludeFile("net/proto2/public/wire_format_verify.h", printer); + } + + if (options_.opensource_runtime) { + // Verify the protobuf library header version is compatible with the protoc + // version before going any further. + IncludeFile("net/proto2/public/port_def.inc", printer); + format( + "#if PROTOBUF_VERSION < $1$\n" + "#error This file was generated by a newer version of protoc which is\n" + "#error incompatible with your Protocol Buffer headers. Please update\n" + "#error your headers.\n" + "#endif\n" + "#if $2$ < PROTOBUF_MIN_PROTOC_VERSION\n" + "#error This file was generated by an older version of protoc which " + "is\n" + "#error incompatible with your Protocol Buffer headers. Please\n" + "#error regenerate this file with a newer version of protoc.\n" + "#endif\n" + "\n", + PROTOBUF_MIN_HEADER_VERSION_FOR_PROTOC, // 1 + PROTOBUF_VERSION); // 2 + IncludeFile("net/proto2/public/port_undef.inc", printer); + } + + // OK, it's now safe to #include other files. + IncludeFile("net/proto2/io/public/coded_stream.h", printer); + IncludeFile("net/proto2/public/arena.h", printer); + IncludeFile("net/proto2/public/arenastring.h", printer); + if ((options_.force_inline_string || options_.profile_driven_inline_string) && + !options_.opensource_runtime) { + IncludeFile("net/proto2/public/inlined_string_field.h", printer); + } + if (HasSimpleBaseClasses(file_, options_)) { + IncludeFile("net/proto2/public/generated_message_bases.h", printer); + } + IncludeFile("net/proto2/public/generated_message_table_driven.h", printer); + if (HasGeneratedMethods(file_, options_) && + options_.tctable_mode != Options::kTCTableNever) { + IncludeFile("net/proto2/public/generated_message_tctable_decl.h", printer); + } + IncludeFile("net/proto2/public/generated_message_util.h", printer); + IncludeFile("net/proto2/public/metadata_lite.h", printer); + + if (HasDescriptorMethods(file_, options_)) { + IncludeFile("net/proto2/public/generated_message_reflection.h", printer); + } + + if (!message_generators_.empty()) { + if (HasDescriptorMethods(file_, options_)) { + IncludeFile("net/proto2/public/message.h", printer); + } else { + IncludeFile("net/proto2/public/message_lite.h", printer); + } + } + if (options_.opensource_runtime) { + // Open-source relies on unconditional includes of these. + IncludeFileAndExport("net/proto2/public/repeated_field.h", printer); + IncludeFileAndExport("net/proto2/public/extension_set.h", printer); + } else { + // Google3 includes these files only when they are necessary. + if (HasExtensionsOrExtendableMessage(file_)) { + IncludeFileAndExport("net/proto2/public/extension_set.h", printer); + } + if (HasRepeatedFields(file_)) { + IncludeFileAndExport("net/proto2/public/repeated_field.h", printer); + } + if (HasStringPieceFields(file_, options_)) { + IncludeFile("net/proto2/public/string_piece_field_support.h", printer); + } + if (HasCordFields(file_, options_)) { + format("#include \"third_party/absl/strings/cord.h\"\n"); + } + } + if (HasMapFields(file_)) { + IncludeFileAndExport("net/proto2/public/map.h", printer); + if (HasDescriptorMethods(file_, options_)) { + IncludeFile("net/proto2/public/map_entry.h", printer); + IncludeFile("net/proto2/public/map_field_inl.h", printer); + } else { + IncludeFile("net/proto2/public/map_entry_lite.h", printer); + IncludeFile("net/proto2/public/map_field_lite.h", printer); + } + } + + if (HasEnumDefinitions(file_)) { + if (HasDescriptorMethods(file_, options_)) { + IncludeFile("net/proto2/public/generated_enum_reflection.h", printer); + } else { + IncludeFile("net/proto2/public/generated_enum_util.h", printer); + } + } + + if (HasGenericServices(file_, options_)) { + IncludeFile("net/proto2/public/service.h", printer); + } + + if (UseUnknownFieldSet(file_, options_) && !message_generators_.empty()) { + IncludeFile("net/proto2/public/unknown_field_set.h", printer); + } +} + +void FileGenerator::GenerateMetadataPragma(io::Printer* printer, + const std::string& info_path) { + Formatter format(printer, variables_); + if (!info_path.empty() && !options_.annotation_pragma_name.empty() && + !options_.annotation_guard_name.empty()) { + format.Set("guard", options_.annotation_guard_name); + format.Set("pragma", options_.annotation_pragma_name); + format.Set("info_path", info_path); + format( + "#ifdef $guard$\n" + "#pragma $pragma$ \"$info_path$\"\n" + "#endif // $guard$\n"); + } +} + +void FileGenerator::GenerateDependencyIncludes(io::Printer* printer) { + Formatter format(printer, variables_); + for (int i = 0; i < file_->dependency_count(); i++) { + std::string basename = StripProto(file_->dependency(i)->name()); + + // Do not import weak deps. + if (IsDepWeak(file_->dependency(i))) continue; + + if (IsBootstrapProto(options_, file_)) { + GetBootstrapBasename(options_, basename, &basename); + } + + format("#include $1$\n", + CreateHeaderInclude(basename + ".pb.h", file_->dependency(i))); + } +} + +void FileGenerator::GenerateGlobalStateFunctionDeclarations( + io::Printer* printer) { + Formatter format(printer, variables_); + // Forward-declare the DescriptorTable because this is referenced by .pb.cc + // files depending on this file. + // + // The TableStruct is also outputted in weak_message_field.cc, because the + // weak fields must refer to table struct but cannot include the header. + // Also it annotates extra weak attributes. + // TODO(gerbens) make sure this situation is handled better. + format( + "\n" + "// Internal implementation detail -- do not use these members.\n" + "struct $dllexport_decl $$tablename$ {\n" + // These tables describe how to serialize and parse messages. Used + // for table driven code. + " static const ::$proto_ns$::internal::ParseTableField entries[]\n" + " PROTOBUF_SECTION_VARIABLE(protodesc_cold);\n" + " static const ::$proto_ns$::internal::AuxiliaryParseTableField aux[]\n" + " PROTOBUF_SECTION_VARIABLE(protodesc_cold);\n" + " static const ::$proto_ns$::internal::ParseTable schema[$1$]\n" + " PROTOBUF_SECTION_VARIABLE(protodesc_cold);\n" + " static const ::$proto_ns$::internal::FieldMetadata field_metadata[];\n" + " static const ::$proto_ns$::internal::SerializationTable " + "serialization_table[];\n" + " static const $uint32$ offsets[];\n" + "};\n", + std::max(size_t(1), message_generators_.size())); + if (HasDescriptorMethods(file_, options_)) { + format( + "$dllexport_decl $extern const ::$proto_ns$::internal::DescriptorTable " + "$desc_table$;\n"); + } +} + +void FileGenerator::GenerateMessageDefinitions(io::Printer* printer) { + Formatter format(printer, variables_); + // Generate class definitions. + for (int i = 0; i < message_generators_.size(); i++) { + if (i > 0) { + format("\n"); + format(kThinSeparator); + format("\n"); + } + message_generators_[i]->GenerateClassDefinition(printer); + } +} + +void FileGenerator::GenerateEnumDefinitions(io::Printer* printer) { + // Generate enum definitions. + for (int i = 0; i < enum_generators_.size(); i++) { + enum_generators_[i]->GenerateDefinition(printer); + } +} + +void FileGenerator::GenerateServiceDefinitions(io::Printer* printer) { + Formatter format(printer, variables_); + if (HasGenericServices(file_, options_)) { + // Generate service definitions. + for (int i = 0; i < service_generators_.size(); i++) { + if (i > 0) { + format("\n"); + format(kThinSeparator); + format("\n"); + } + service_generators_[i]->GenerateDeclarations(printer); + } + + format("\n"); + format(kThickSeparator); + format("\n"); + } +} + +void FileGenerator::GenerateExtensionIdentifiers(io::Printer* printer) { + // Declare extension identifiers. These are in global scope and so only + // the global scope extensions. + for (auto& extension_generator : extension_generators_) { + if (extension_generator->IsScoped()) continue; + extension_generator->GenerateDeclaration(printer); + } +} + +void FileGenerator::GenerateInlineFunctionDefinitions(io::Printer* printer) { + Formatter format(printer, variables_); + // TODO(gerbens) remove pragmas when gcc is no longer used. Current version + // of gcc fires a bogus error when compiled with strict-aliasing. + format( + "#ifdef __GNUC__\n" + " #pragma GCC diagnostic push\n" + " #pragma GCC diagnostic ignored \"-Wstrict-aliasing\"\n" + "#endif // __GNUC__\n"); + // Generate class inline methods. + for (int i = 0; i < message_generators_.size(); i++) { + if (i > 0) { + format(kThinSeparator); + format("\n"); + } + message_generators_[i]->GenerateInlineMethods(printer); + } + format( + "#ifdef __GNUC__\n" + " #pragma GCC diagnostic pop\n" + "#endif // __GNUC__\n"); + + for (int i = 0; i < message_generators_.size(); i++) { + if (i > 0) { + format(kThinSeparator); + format("\n"); + } + } +} + +void FileGenerator::GenerateProto2NamespaceEnumSpecializations( + io::Printer* printer) { + Formatter format(printer, variables_); + // Emit GetEnumDescriptor specializations into google::protobuf namespace: + if (HasEnumDefinitions(file_)) { + format("\n"); + { + NamespaceOpener proto_ns(ProtobufNamespace(options_), format); + format("\n"); + for (int i = 0; i < enum_generators_.size(); i++) { + enum_generators_[i]->GenerateGetEnumDescriptorSpecializations(printer); + } + format("\n"); + } + } +} + +} // namespace cpp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_file.h b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_file.h new file mode 100644 index 00000000..a5e751aa --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_file.h @@ -0,0 +1,208 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_FILE_H__ +#define GOOGLE_PROTOBUF_COMPILER_CPP_FILE_H__ + +#include <algorithm> +#include <memory> +#include <set> +#include <string> +#include <vector> +#include <stubs/common.h> +#include <compiler/cpp/cpp_field.h> +#include <compiler/cpp/cpp_helpers.h> +#include <compiler/cpp/cpp_options.h> +#include <compiler/scc.h> + +namespace google { +namespace protobuf { +class FileDescriptor; // descriptor.h +namespace io { +class Printer; // printer.h +} +} // namespace protobuf +} // namespace google + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { + +class EnumGenerator; // enum.h +class MessageGenerator; // message.h +class ServiceGenerator; // service.h +class ExtensionGenerator; // extension.h + +class FileGenerator { + public: + // See generator.cc for the meaning of dllexport_decl. + FileGenerator(const FileDescriptor* file, const Options& options); + ~FileGenerator(); + + // Shared code between the two header generators below. + void GenerateHeader(io::Printer* printer); + + // info_path, if non-empty, should be the path (relative to printer's + // output) to the metadata file describing this proto header. + void GenerateProtoHeader(io::Printer* printer, const std::string& info_path); + // info_path, if non-empty, should be the path (relative to printer's + // output) to the metadata file describing this PB header. + void GeneratePBHeader(io::Printer* printer, const std::string& info_path); + void GenerateSource(io::Printer* printer); + + // The following member functions are used when the lite_implicit_weak_fields + // option is set. In this mode the code is organized a bit differently to + // promote better linker stripping of unused code. In particular, we generate + // one .cc file per message, one .cc file per extension, and a main pb.cc file + // containing everything else. + + int NumMessages() const { return message_generators_.size(); } + int NumExtensions() const { return extension_generators_.size(); } + // Generates the source file for one message. + void GenerateSourceForMessage(int idx, io::Printer* printer); + // Generates the source file for one extension. + void GenerateSourceForExtension(int idx, io::Printer* printer); + // Generates a source file containing everything except messages and + // extensions. + void GenerateGlobalSource(io::Printer* printer); + + private: + // Internal type used by GenerateForwardDeclarations (defined in file.cc). + class ForwardDeclarations; + struct CrossFileReferences; + + void IncludeFile(const std::string& google3_name, io::Printer* printer) { + DoIncludeFile(google3_name, false, printer); + } + void IncludeFileAndExport(const std::string& google3_name, + io::Printer* printer) { + DoIncludeFile(google3_name, true, printer); + } + void DoIncludeFile(const std::string& google3_name, bool do_export, + io::Printer* printer); + + std::string CreateHeaderInclude(const std::string& basename, + const FileDescriptor* file); + void GetCrossFileReferencesForField(const FieldDescriptor* field, + CrossFileReferences* refs); + void GetCrossFileReferencesForFile(const FileDescriptor* file, + CrossFileReferences* refs); + void GenerateInternalForwardDeclarations(const CrossFileReferences& refs, + io::Printer* printer); + void GenerateSourceIncludes(io::Printer* printer); + void GenerateSourceDefaultInstance(int idx, io::Printer* printer); + + void GenerateInitForSCC(const SCC* scc, const CrossFileReferences& refs, + io::Printer* printer); + void GenerateTables(io::Printer* printer); + void GenerateReflectionInitializationCode(io::Printer* printer); + + // For other imports, generates their forward-declarations. + void GenerateForwardDeclarations(io::Printer* printer); + + // Generates top or bottom of a header file. + void GenerateTopHeaderGuard(io::Printer* printer, bool pb_h); + void GenerateBottomHeaderGuard(io::Printer* printer, bool pb_h); + + // Generates #include directives. + void GenerateLibraryIncludes(io::Printer* printer); + void GenerateDependencyIncludes(io::Printer* printer); + + // Generate a pragma to pull in metadata using the given info_path (if + // non-empty). info_path should be relative to printer's output. + void GenerateMetadataPragma(io::Printer* printer, + const std::string& info_path); + + // Generates a couple of different pieces before definitions: + void GenerateGlobalStateFunctionDeclarations(io::Printer* printer); + + // Generates types for classes. + void GenerateMessageDefinitions(io::Printer* printer); + + void GenerateEnumDefinitions(io::Printer* printer); + + // Generates generic service definitions. + void GenerateServiceDefinitions(io::Printer* printer); + + // Generates extension identifiers. + void GenerateExtensionIdentifiers(io::Printer* printer); + + // Generates inline function definitions. + void GenerateInlineFunctionDefinitions(io::Printer* printer); + + void GenerateProto2NamespaceEnumSpecializations(io::Printer* printer); + + // Sometimes the names we use in a .proto file happen to be defined as + // macros on some platforms (e.g., macro/minor used in plugin.proto are + // defined as macros in sys/types.h on FreeBSD and a few other platforms). + // To make the generated code compile on these platforms, we either have to + // undef the macro for these few platforms, or rename the field name for all + // platforms. Since these names are part of protobuf public API, renaming is + // generally a breaking change so we prefer the #undef approach. + void GenerateMacroUndefs(io::Printer* printer); + + bool IsDepWeak(const FileDescriptor* dep) const { + if (weak_deps_.count(dep) != 0) { + GOOGLE_CHECK(!options_.opensource_runtime); + return true; + } + return false; + } + + std::set<const FileDescriptor*> weak_deps_; + + const FileDescriptor* file_; + const Options options_; + + MessageSCCAnalyzer scc_analyzer_; + + std::map<std::string, std::string> variables_; + + // Contains the post-order walk of all the messages (and child messages) in + // this file. If you need a pre-order walk just reverse iterate. + std::vector<std::unique_ptr<MessageGenerator>> message_generators_; + std::vector<std::unique_ptr<EnumGenerator>> enum_generators_; + std::vector<std::unique_ptr<ServiceGenerator>> service_generators_; + std::vector<std::unique_ptr<ExtensionGenerator>> extension_generators_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileGenerator); +}; + +} // namespace cpp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_CPP_FILE_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_generator.cc b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_generator.cc new file mode 100644 index 00000000..88caa897 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_generator.cc @@ -0,0 +1,271 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <compiler/cpp/cpp_generator.h> + +#include <memory> +#include <string> +#include <utility> +#include <vector> + +#include <stubs/strutil.h> +#include <compiler/cpp/cpp_file.h> +#include <compiler/cpp/cpp_helpers.h> +#include <descriptor.pb.h> +#include <io/printer.h> +#include <io/zero_copy_stream.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { + +CppGenerator::CppGenerator() {} +CppGenerator::~CppGenerator() {} + +namespace { +std::string NumberedCcFileName(const std::string& basename, int number) { + return StrCat(basename, ".out/", number, ".cc"); +} +} // namespace + +bool CppGenerator::Generate(const FileDescriptor* file, + const std::string& parameter, + GeneratorContext* generator_context, + std::string* error) const { + std::vector<std::pair<std::string, std::string> > options; + ParseGeneratorParameter(parameter, &options); + + // ----------------------------------------------------------------- + // parse generator options + + // If the dllexport_decl option is passed to the compiler, we need to write + // it in front of every symbol that should be exported if this .proto is + // compiled into a Windows DLL. E.g., if the user invokes the protocol + // compiler as: + // protoc --cpp_out=dllexport_decl=FOO_EXPORT:outdir foo.proto + // then we'll define classes like this: + // class FOO_EXPORT Foo { + // ... + // } + // FOO_EXPORT is a macro which should expand to __declspec(dllexport) or + // __declspec(dllimport) depending on what is being compiled. + // + Options file_options; + + file_options.opensource_runtime = opensource_runtime_; + file_options.runtime_include_base = runtime_include_base_; + + for (int i = 0; i < options.size(); i++) { + if (options[i].first == "dllexport_decl") { + file_options.dllexport_decl = options[i].second; + } else if (options[i].first == "safe_boundary_check") { + file_options.safe_boundary_check = true; + } else if (options[i].first == "annotate_headers") { + file_options.annotate_headers = true; + } else if (options[i].first == "annotation_pragma_name") { + file_options.annotation_pragma_name = options[i].second; + } else if (options[i].first == "annotation_guard_name") { + file_options.annotation_guard_name = options[i].second; + } else if (options[i].first == "speed") { + file_options.enforce_mode = EnforceOptimizeMode::kSpeed; + } else if (options[i].first == "code_size") { + file_options.enforce_mode = EnforceOptimizeMode::kCodeSize; + } else if (options[i].first == "lite") { + file_options.enforce_mode = EnforceOptimizeMode::kLiteRuntime; + } else if (options[i].first == "lite_implicit_weak_fields") { + file_options.enforce_mode = EnforceOptimizeMode::kLiteRuntime; + file_options.lite_implicit_weak_fields = true; + if (!options[i].second.empty()) { + file_options.num_cc_files = + strto32(options[i].second.c_str(), NULL, 10); + } + } else if (options[i].first == "annotate_accessor") { + file_options.annotate_accessor = true; + } else if (options[i].first == "inject_field_listener_events") { + file_options.field_listener_options.inject_field_listener_events = true; + } else if (options[i].first == "forbidden_field_listener_events") { + std::size_t pos = 0; + do { + std::size_t next_pos = options[i].second.find_first_of("+", pos); + if (next_pos == std::string::npos) { + next_pos = options[i].second.size(); + } + if (next_pos > pos) + file_options.field_listener_options.forbidden_field_listener_events + .insert(options[i].second.substr(pos, next_pos - pos)); + pos = next_pos + 1; + } while (pos < options[i].second.size()); + } else if (options[i].first == "eagerly_verified_lazy") { + file_options.eagerly_verified_lazy = true; + } else if (options[i].first == "force_eagerly_verified_lazy") { + file_options.force_eagerly_verified_lazy = true; + } else if (options[i].first == "table_driven_parsing") { + file_options.table_driven_parsing = true; + } else if (options[i].first == "table_driven_serialization") { + file_options.table_driven_serialization = true; + } else if (options[i].first == "experimental_tail_call_table_mode") { + if (options[i].second == "never") { + file_options.tctable_mode = Options::kTCTableNever; + } else if (options[i].second == "guarded") { + file_options.tctable_mode = Options::kTCTableGuarded; + } else if (options[i].second == "always") { + file_options.tctable_mode = Options::kTCTableAlways; + } else { + *error = "Unknown value for experimental_tail_call_table_mode: " + + options[i].second; + return false; + } + } else { + *error = "Unknown generator option: " + options[i].first; + return false; + } + } + + // The safe_boundary_check option controls behavior for Google-internal + // protobuf APIs. + if (file_options.safe_boundary_check && file_options.opensource_runtime) { + *error = + "The safe_boundary_check option is not supported outside of Google."; + return false; + } + + // ----------------------------------------------------------------- + + + std::string basename = StripProto(file->name()); + + if (MaybeBootstrap(file_options, generator_context, file_options.bootstrap, + &basename)) { + return true; + } + + FileGenerator file_generator(file, file_options); + + // Generate header(s). + if (file_options.proto_h) { + std::unique_ptr<io::ZeroCopyOutputStream> output( + generator_context->Open(basename + ".proto.h")); + GeneratedCodeInfo annotations; + io::AnnotationProtoCollector<GeneratedCodeInfo> annotation_collector( + &annotations); + std::string info_path = basename + ".proto.h.meta"; + io::Printer printer( + output.get(), '$', + file_options.annotate_headers ? &annotation_collector : NULL); + file_generator.GenerateProtoHeader( + &printer, file_options.annotate_headers ? info_path : ""); + if (file_options.annotate_headers) { + std::unique_ptr<io::ZeroCopyOutputStream> info_output( + generator_context->Open(info_path)); + annotations.SerializeToZeroCopyStream(info_output.get()); + } + } + + { + std::unique_ptr<io::ZeroCopyOutputStream> output( + generator_context->Open(basename + ".pb.h")); + GeneratedCodeInfo annotations; + io::AnnotationProtoCollector<GeneratedCodeInfo> annotation_collector( + &annotations); + std::string info_path = basename + ".pb.h.meta"; + io::Printer printer( + output.get(), '$', + file_options.annotate_headers ? &annotation_collector : NULL); + file_generator.GeneratePBHeader( + &printer, file_options.annotate_headers ? info_path : ""); + if (file_options.annotate_headers) { + std::unique_ptr<io::ZeroCopyOutputStream> info_output( + generator_context->Open(info_path)); + annotations.SerializeToZeroCopyStream(info_output.get()); + } + } + + // Generate cc file(s). + if (UsingImplicitWeakFields(file, file_options)) { + { + // This is the global .cc file, containing + // enum/services/tables/reflection + std::unique_ptr<io::ZeroCopyOutputStream> output( + generator_context->Open(basename + ".pb.cc")); + io::Printer printer(output.get(), '$'); + file_generator.GenerateGlobalSource(&printer); + } + + int num_cc_files = + file_generator.NumMessages() + file_generator.NumExtensions(); + + // If we're using implicit weak fields then we allow the user to + // optionally specify how many files to generate, not counting the global + // pb.cc file. If we have more files than messages, then some files will + // be generated as empty placeholders. + if (file_options.num_cc_files > 0) { + GOOGLE_CHECK_LE(num_cc_files, file_options.num_cc_files) + << "There must be at least as many numbered .cc files as messages " + "and extensions."; + num_cc_files = file_options.num_cc_files; + } + int cc_file_number = 0; + for (int i = 0; i < file_generator.NumMessages(); i++) { + std::unique_ptr<io::ZeroCopyOutputStream> output(generator_context->Open( + NumberedCcFileName(basename, cc_file_number++))); + io::Printer printer(output.get(), '$'); + file_generator.GenerateSourceForMessage(i, &printer); + } + for (int i = 0; i < file_generator.NumExtensions(); i++) { + std::unique_ptr<io::ZeroCopyOutputStream> output(generator_context->Open( + NumberedCcFileName(basename, cc_file_number++))); + io::Printer printer(output.get(), '$'); + file_generator.GenerateSourceForExtension(i, &printer); + } + // Create empty placeholder files if necessary to match the expected number + // of files. + for (; cc_file_number < num_cc_files; ++cc_file_number) { + std::unique_ptr<io::ZeroCopyOutputStream> output(generator_context->Open( + NumberedCcFileName(basename, cc_file_number))); + } + } else { + std::unique_ptr<io::ZeroCopyOutputStream> output( + generator_context->Open(basename + ".pb.cc")); + io::Printer printer(output.get(), '$'); + file_generator.GenerateSource(&printer); + } + + return true; +} + +} // namespace cpp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_generator.h b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_generator.h new file mode 100644 index 00000000..14c7672a --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_generator.h @@ -0,0 +1,106 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// Generates C++ code for a given .proto file. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_GENERATOR_H__ +#define GOOGLE_PROTOBUF_COMPILER_CPP_GENERATOR_H__ + +#include <string> +#include <compiler/code_generator.h> + +#include <port_def.inc> + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { + +// CodeGenerator implementation which generates a C++ source file and +// header. If you create your own protocol compiler binary and you want +// it to support C++ output, you can do so by registering an instance of this +// CodeGenerator with the CommandLineInterface in your main() function. +class PROTOC_EXPORT CppGenerator : public CodeGenerator { + public: + CppGenerator(); + ~CppGenerator(); + + enum class Runtime { + kGoogle3, // Use the internal google3 runtime. + kOpensource, // Use the open-source runtime. + + // Use the open-source runtime with google3 #include paths. We make these + // absolute to avoid ambiguity, so the runtime will be #included like: + // #include "third_party/protobuf/.../google/protobuf/message.h" + kOpensourceGoogle3 + }; + + void set_opensource_runtime(bool opensource) { + opensource_runtime_ = opensource; + } + + // If set to a non-empty string, generated code will do: + // #include "<BASE>/google/protobuf/message.h" + // instead of: + // #include <message.h> + // This has no effect if opensource_runtime = false. + void set_runtime_include_base(const std::string& base) { + runtime_include_base_ = base; + } + + // implements CodeGenerator ---------------------------------------- + bool Generate(const FileDescriptor* file, const std::string& parameter, + GeneratorContext* generator_context, + std::string* error) const override; + + uint64_t GetSupportedFeatures() const override { + // We don't fully support this yet, but this is needed to unblock the tests, + // and we will have full support before the experimental flag is removed. + return FEATURE_PROTO3_OPTIONAL; + } + + private: + bool opensource_runtime_ = true; + std::string runtime_include_base_; + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CppGenerator); +}; + +} // namespace cpp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#include <port_undef.inc> + +#endif // GOOGLE_PROTOBUF_COMPILER_CPP_GENERATOR_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_helpers.cc b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_helpers.cc new file mode 100644 index 00000000..9f133247 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_helpers.cc @@ -0,0 +1,1497 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <compiler/cpp/cpp_helpers.h> + +#include <cstdint> +#include <functional> +#include <limits> +#include <map> +#include <queue> +#include <unordered_set> +#include <vector> + +#include <stubs/common.h> +#include <stubs/logging.h> +#include <compiler/cpp/cpp_options.h> +#include <compiler/cpp/cpp_names.h> +#include <descriptor.pb.h> +#include <descriptor.h> +#include <compiler/scc.h> +#include <io/printer.h> +#include <io/zero_copy_stream.h> +#include <dynamic_message.h> +#include <wire_format.h> +#include <wire_format_lite.h> +#include <stubs/strutil.h> +#include <stubs/substitute.h> +#include <stubs/hash.h> + +// Must be last. +#include <port_def.inc> + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { + +namespace { + +static const char kAnyMessageName[] = "Any"; +static const char kAnyProtoFile[] = "google/protobuf/any.proto"; + +std::string DotsToColons(const std::string& name) { + return StringReplace(name, ".", "::", true); +} + +static const char* const kKeywordList[] = { // + "NULL", + "alignas", + "alignof", + "and", + "and_eq", + "asm", + "auto", + "bitand", + "bitor", + "bool", + "break", + "case", + "catch", + "char", + "class", + "compl", + "const", + "constexpr", + "const_cast", + "continue", + "decltype", + "default", + "delete", + "do", + "double", + "dynamic_cast", + "else", + "enum", + "explicit", + "export", + "extern", + "false", + "float", + "for", + "friend", + "goto", + "if", + "inline", + "int", + "long", + "mutable", + "namespace", + "new", + "noexcept", + "not", + "not_eq", + "nullptr", + "operator", + "or", + "or_eq", + "private", + "protected", + "public", + "register", + "reinterpret_cast", + "return", + "short", + "signed", + "sizeof", + "static", + "static_assert", + "static_cast", + "struct", + "switch", + "template", + "this", + "thread_local", + "throw", + "true", + "try", + "typedef", + "typeid", + "typename", + "union", + "unsigned", + "using", + "virtual", + "void", + "volatile", + "wchar_t", + "while", + "xor", + "xor_eq"}; + +static std::unordered_set<std::string>* MakeKeywordsMap() { + auto* result = new std::unordered_set<std::string>(); + for (const auto keyword : kKeywordList) { + result->emplace(keyword); + } + return result; +} + +static std::unordered_set<std::string>& kKeywords = *MakeKeywordsMap(); + +std::string IntTypeName(const Options& options, const std::string& type) { + return type + "_t"; +} + +void SetIntVar(const Options& options, const std::string& type, + std::map<std::string, std::string>* variables) { + (*variables)[type] = IntTypeName(options, type); +} +bool IsEagerlyVerifiedLazyImpl(const FieldDescriptor* field, + const Options& options, + MessageSCCAnalyzer* scc_analyzer) { + return false; +} + +} // namespace + +bool IsLazy(const FieldDescriptor* field, const Options& options, + MessageSCCAnalyzer* scc_analyzer) { + return IsLazilyVerifiedLazy(field, options) || + IsEagerlyVerifiedLazyImpl(field, options, scc_analyzer); +} + +void SetCommonVars(const Options& options, + std::map<std::string, std::string>* variables) { + (*variables)["proto_ns"] = ProtobufNamespace(options); + + // Warning: there is some clever naming/splitting here to avoid extract script + // rewrites. The names of these variables must not be things that the extract + // script will rewrite. That's why we use "CHK" (for example) instead of + // "GOOGLE_CHECK". + if (options.opensource_runtime) { + (*variables)["GOOGLE_PROTOBUF"] = "GOOGLE_PROTOBUF"; + (*variables)["CHK"] = "GOOGLE_CHECK"; + (*variables)["DCHK"] = "GOOGLE_DCHECK"; + } else { + // These values are things the extract script would rewrite if we did not + // split them. It might not strictly matter since we don't generate google3 + // code in open-source. But it's good to prevent surprising things from + // happening. + (*variables)["GOOGLE_PROTOBUF"] = + "GOOGLE3" + "_PROTOBUF"; + (*variables)["CHK"] = + "CH" + "ECK"; + (*variables)["DCHK"] = + "DCH" + "ECK"; + } + + SetIntVar(options, "int8", variables); + SetIntVar(options, "uint8", variables); + SetIntVar(options, "uint32", variables); + SetIntVar(options, "uint64", variables); + SetIntVar(options, "int32", variables); + SetIntVar(options, "int64", variables); + (*variables)["string"] = "std::string"; +} + +void SetUnknownFieldsVariable(const Descriptor* descriptor, + const Options& options, + std::map<std::string, std::string>* variables) { + std::string proto_ns = ProtobufNamespace(options); + std::string unknown_fields_type; + if (UseUnknownFieldSet(descriptor->file(), options)) { + unknown_fields_type = "::" + proto_ns + "::UnknownFieldSet"; + (*variables)["unknown_fields"] = + "_internal_metadata_.unknown_fields<" + unknown_fields_type + ">(" + + unknown_fields_type + "::default_instance)"; + } else { + unknown_fields_type = + PrimitiveTypeName(options, FieldDescriptor::CPPTYPE_STRING); + (*variables)["unknown_fields"] = "_internal_metadata_.unknown_fields<" + + unknown_fields_type + ">(::" + proto_ns + + "::internal::GetEmptyString)"; + } + (*variables)["unknown_fields_type"] = unknown_fields_type; + (*variables)["have_unknown_fields"] = + "_internal_metadata_.have_unknown_fields()"; + (*variables)["mutable_unknown_fields"] = + "_internal_metadata_.mutable_unknown_fields<" + unknown_fields_type + + ">()"; +} + +std::string UnderscoresToCamelCase(const std::string& input, + bool cap_next_letter) { + 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') { + // Capital letters 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; + } + } + return result; +} + +const char kThickSeparator[] = + "// ===================================================================\n"; +const char kThinSeparator[] = + "// -------------------------------------------------------------------\n"; + +bool CanInitializeByZeroing(const FieldDescriptor* field) { + if (field->is_repeated() || field->is_extension()) return false; + switch (field->cpp_type()) { + case FieldDescriptor::CPPTYPE_ENUM: + return field->default_value_enum()->number() == 0; + case FieldDescriptor::CPPTYPE_INT32: + return field->default_value_int32() == 0; + case FieldDescriptor::CPPTYPE_INT64: + return field->default_value_int64() == 0; + case FieldDescriptor::CPPTYPE_UINT32: + return field->default_value_uint32() == 0; + case FieldDescriptor::CPPTYPE_UINT64: + return field->default_value_uint64() == 0; + case FieldDescriptor::CPPTYPE_FLOAT: + return field->default_value_float() == 0; + case FieldDescriptor::CPPTYPE_DOUBLE: + return field->default_value_double() == 0; + case FieldDescriptor::CPPTYPE_BOOL: + return field->default_value_bool() == false; + default: + return false; + } +} + +std::string ClassName(const Descriptor* descriptor) { + const Descriptor* parent = descriptor->containing_type(); + std::string res; + if (parent) res += ClassName(parent) + "_"; + res += descriptor->name(); + if (IsMapEntryMessage(descriptor)) res += "_DoNotUse"; + return ResolveKeyword(res); +} + +std::string ClassName(const EnumDescriptor* enum_descriptor) { + if (enum_descriptor->containing_type() == nullptr) { + return ResolveKeyword(enum_descriptor->name()); + } else { + return ClassName(enum_descriptor->containing_type()) + "_" + + enum_descriptor->name(); + } +} + +std::string QualifiedClassName(const Descriptor* d, const Options& options) { + return QualifiedFileLevelSymbol(d->file(), ClassName(d), options); +} + +std::string QualifiedClassName(const EnumDescriptor* d, + const Options& options) { + return QualifiedFileLevelSymbol(d->file(), ClassName(d), options); +} + +std::string QualifiedClassName(const Descriptor* d) { + return QualifiedClassName(d, Options()); +} + +std::string QualifiedClassName(const EnumDescriptor* d) { + return QualifiedClassName(d, Options()); +} + +std::string ExtensionName(const FieldDescriptor* d) { + if (const Descriptor* scope = d->extension_scope()) + return StrCat(ClassName(scope), "::", ResolveKeyword(d->name())); + return ResolveKeyword(d->name()); +} + +std::string QualifiedExtensionName(const FieldDescriptor* d, + const Options& options) { + GOOGLE_DCHECK(d->is_extension()); + return QualifiedFileLevelSymbol(d->file(), ExtensionName(d), options); +} + +std::string QualifiedExtensionName(const FieldDescriptor* d) { + return QualifiedExtensionName(d, Options()); +} + +std::string Namespace(const std::string& package) { + if (package.empty()) return ""; + return "::" + DotsToColons(package); +} + +std::string Namespace(const FileDescriptor* d, const Options& options) { + std::string ret = Namespace(d->package()); + if (IsWellKnownMessage(d) && options.opensource_runtime) { + // Written with string concatenation to prevent rewriting of + // ::google::protobuf. + ret = StringReplace(ret, + "::google::" + "protobuf", + "::PROTOBUF_NAMESPACE_ID", false); + } + return ret; +} + +std::string Namespace(const Descriptor* d, const Options& options) { + return Namespace(d->file(), options); +} + +std::string Namespace(const FieldDescriptor* d, const Options& options) { + return Namespace(d->file(), options); +} + +std::string Namespace(const EnumDescriptor* d, const Options& options) { + return Namespace(d->file(), options); +} + +std::string DefaultInstanceType(const Descriptor* descriptor, + const Options& options) { + return ClassName(descriptor) + "DefaultTypeInternal"; +} + +std::string DefaultInstanceName(const Descriptor* descriptor, + const Options& options) { + return "_" + ClassName(descriptor, false) + "_default_instance_"; +} + +std::string DefaultInstancePtr(const Descriptor* descriptor, + const Options& options) { + return DefaultInstanceName(descriptor, options) + "ptr_"; +} + +std::string QualifiedDefaultInstanceName(const Descriptor* descriptor, + const Options& options) { + return QualifiedFileLevelSymbol( + descriptor->file(), DefaultInstanceName(descriptor, options), options); +} + +std::string QualifiedDefaultInstancePtr(const Descriptor* descriptor, + const Options& options) { + return QualifiedDefaultInstanceName(descriptor, options) + "ptr_"; +} + +std::string DescriptorTableName(const FileDescriptor* file, + const Options& options) { + return UniqueName("descriptor_table", file, options); +} + +std::string FileDllExport(const FileDescriptor* file, const Options& options) { + return UniqueName("PROTOBUF_INTERNAL_EXPORT", file, options); +} + +std::string SuperClassName(const Descriptor* descriptor, + const Options& options) { + if (!HasDescriptorMethods(descriptor->file(), options)) { + return "::" + ProtobufNamespace(options) + "::MessageLite"; + } + auto simple_base = SimpleBaseClass(descriptor, options); + if (simple_base.empty()) { + return "::" + ProtobufNamespace(options) + "::Message"; + } + return "::" + ProtobufNamespace(options) + "::internal::" + simple_base; +} + +std::string ResolveKeyword(const std::string& name) { + if (kKeywords.count(name) > 0) { + return name + "_"; + } + return name; +} + +std::string FieldName(const FieldDescriptor* field) { + std::string result = field->name(); + LowerString(&result); + if (kKeywords.count(result) > 0) { + result.append("_"); + } + return result; +} + +std::string OneofCaseConstantName(const FieldDescriptor* field) { + GOOGLE_DCHECK(field->containing_oneof()); + std::string field_name = UnderscoresToCamelCase(field->name(), true); + return "k" + field_name; +} + +std::string QualifiedOneofCaseConstantName(const FieldDescriptor* field) { + GOOGLE_DCHECK(field->containing_oneof()); + const std::string qualification = + QualifiedClassName(field->containing_type()); + return StrCat(qualification, "::", OneofCaseConstantName(field)); +} + +std::string EnumValueName(const EnumValueDescriptor* enum_value) { + std::string result = enum_value->name(); + if (kKeywords.count(result) > 0) { + result.append("_"); + } + return result; +} + +int EstimateAlignmentSize(const FieldDescriptor* field) { + if (field == nullptr) return 0; + if (field->is_repeated()) return 8; + switch (field->cpp_type()) { + case FieldDescriptor::CPPTYPE_BOOL: + return 1; + + case FieldDescriptor::CPPTYPE_INT32: + case FieldDescriptor::CPPTYPE_UINT32: + case FieldDescriptor::CPPTYPE_ENUM: + case FieldDescriptor::CPPTYPE_FLOAT: + return 4; + + case FieldDescriptor::CPPTYPE_INT64: + case FieldDescriptor::CPPTYPE_UINT64: + case FieldDescriptor::CPPTYPE_DOUBLE: + case FieldDescriptor::CPPTYPE_STRING: + case FieldDescriptor::CPPTYPE_MESSAGE: + return 8; + } + GOOGLE_LOG(FATAL) << "Can't get here."; + return -1; // Make compiler happy. +} + +std::string FieldConstantName(const FieldDescriptor* field) { + std::string field_name = UnderscoresToCamelCase(field->name(), true); + std::string result = "k" + field_name + "FieldNumber"; + + if (!field->is_extension() && + field->containing_type()->FindFieldByCamelcaseName( + field->camelcase_name()) != field) { + // This field's camelcase name is not unique. As a hack, add the field + // number to the constant name. This makes the constant rather useless, + // but what can we do? + result += "_" + StrCat(field->number()); + } + + return result; +} + +std::string FieldMessageTypeName(const FieldDescriptor* field, + const Options& options) { + // Note: The Google-internal version of Protocol Buffers uses this function + // as a hook point for hacks to support legacy code. + return QualifiedClassName(field->message_type(), options); +} + +std::string StripProto(const std::string& filename) { + /* + * TODO(github/georgthegreat) remove this proxy method + * once Google's internal codebase will become ready + */ + return compiler::StripProto(filename); +} + +const char* PrimitiveTypeName(FieldDescriptor::CppType type) { + switch (type) { + case FieldDescriptor::CPPTYPE_INT32: + return "int32_t"; + case FieldDescriptor::CPPTYPE_INT64: + return "int64_t"; + case FieldDescriptor::CPPTYPE_UINT32: + return "uint32_t"; + case FieldDescriptor::CPPTYPE_UINT64: + return "uint64_t"; + case FieldDescriptor::CPPTYPE_DOUBLE: + return "double"; + case FieldDescriptor::CPPTYPE_FLOAT: + return "float"; + case FieldDescriptor::CPPTYPE_BOOL: + return "bool"; + case FieldDescriptor::CPPTYPE_ENUM: + return "int"; + case FieldDescriptor::CPPTYPE_STRING: + return "std::string"; + case FieldDescriptor::CPPTYPE_MESSAGE: + return nullptr; + + // No default because we want the compiler to complain if any new + // CppTypes are added. + } + + GOOGLE_LOG(FATAL) << "Can't get here."; + return nullptr; +} + +std::string PrimitiveTypeName(const Options& options, + FieldDescriptor::CppType type) { + switch (type) { + case FieldDescriptor::CPPTYPE_INT32: + return IntTypeName(options, "int32"); + case FieldDescriptor::CPPTYPE_INT64: + return IntTypeName(options, "int64"); + case FieldDescriptor::CPPTYPE_UINT32: + return IntTypeName(options, "uint32"); + case FieldDescriptor::CPPTYPE_UINT64: + return IntTypeName(options, "uint64"); + case FieldDescriptor::CPPTYPE_DOUBLE: + return "double"; + case FieldDescriptor::CPPTYPE_FLOAT: + return "float"; + case FieldDescriptor::CPPTYPE_BOOL: + return "bool"; + case FieldDescriptor::CPPTYPE_ENUM: + return "int"; + case FieldDescriptor::CPPTYPE_STRING: + return "std::string"; + case FieldDescriptor::CPPTYPE_MESSAGE: + return ""; + + // No default because we want the compiler to complain if any new + // CppTypes are added. + } + + GOOGLE_LOG(FATAL) << "Can't get here."; + return ""; +} + +const char* DeclaredTypeMethodName(FieldDescriptor::Type type) { + switch (type) { + case FieldDescriptor::TYPE_INT32: + return "Int32"; + case FieldDescriptor::TYPE_INT64: + return "Int64"; + case FieldDescriptor::TYPE_UINT32: + return "UInt32"; + case FieldDescriptor::TYPE_UINT64: + return "UInt64"; + case FieldDescriptor::TYPE_SINT32: + return "SInt32"; + case FieldDescriptor::TYPE_SINT64: + return "SInt64"; + case FieldDescriptor::TYPE_FIXED32: + return "Fixed32"; + case FieldDescriptor::TYPE_FIXED64: + return "Fixed64"; + case FieldDescriptor::TYPE_SFIXED32: + return "SFixed32"; + 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_ENUM: + return "Enum"; + + case FieldDescriptor::TYPE_STRING: + return "String"; + case FieldDescriptor::TYPE_BYTES: + return "Bytes"; + 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. + } + GOOGLE_LOG(FATAL) << "Can't get here."; + return ""; +} + +std::string Int32ToString(int number) { + if (number == std::numeric_limits<int32_t>::min()) { + // This needs to be special-cased, see explanation here: + // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=52661 + return StrCat(number + 1, " - 1"); + } else { + return StrCat(number); + } +} + +static std::string Int64ToString(int64_t number) { + if (number == std::numeric_limits<int64_t>::min()) { + // This needs to be special-cased, see explanation here: + // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=52661 + return StrCat("int64_t{", number + 1, "} - 1"); + } + return StrCat("int64_t{", number, "}"); +} + +static std::string UInt64ToString(uint64_t number) { + return StrCat("uint64_t{", number, "u}"); +} + +std::string DefaultValue(const FieldDescriptor* field) { + return DefaultValue(Options(), field); +} + +std::string DefaultValue(const Options& options, const FieldDescriptor* field) { + switch (field->cpp_type()) { + case FieldDescriptor::CPPTYPE_INT32: + return Int32ToString(field->default_value_int32()); + case FieldDescriptor::CPPTYPE_UINT32: + return StrCat(field->default_value_uint32()) + "u"; + case FieldDescriptor::CPPTYPE_INT64: + return Int64ToString(field->default_value_int64()); + case FieldDescriptor::CPPTYPE_UINT64: + return UInt64ToString(field->default_value_uint64()); + case FieldDescriptor::CPPTYPE_DOUBLE: { + double value = field->default_value_double(); + if (value == std::numeric_limits<double>::infinity()) { + return "std::numeric_limits<double>::infinity()"; + } else if (value == -std::numeric_limits<double>::infinity()) { + return "-std::numeric_limits<double>::infinity()"; + } else if (value != value) { + return "std::numeric_limits<double>::quiet_NaN()"; + } else { + return SimpleDtoa(value); + } + } + case FieldDescriptor::CPPTYPE_FLOAT: { + float value = field->default_value_float(); + if (value == std::numeric_limits<float>::infinity()) { + return "std::numeric_limits<float>::infinity()"; + } else if (value == -std::numeric_limits<float>::infinity()) { + return "-std::numeric_limits<float>::infinity()"; + } else if (value != value) { + return "std::numeric_limits<float>::quiet_NaN()"; + } else { + std::string float_value = SimpleFtoa(value); + // If floating point value contains a period (.) or an exponent + // (either E or e), then append suffix 'f' to make it a float + // literal. + if (float_value.find_first_of(".eE") != std::string::npos) { + float_value.push_back('f'); + } + return float_value; + } + } + case FieldDescriptor::CPPTYPE_BOOL: + return field->default_value_bool() ? "true" : "false"; + case FieldDescriptor::CPPTYPE_ENUM: + // Lazy: Generate a static_cast because we don't have a helper function + // that constructs the full name of an enum value. + return strings::Substitute( + "static_cast< $0 >($1)", ClassName(field->enum_type(), true), + Int32ToString(field->default_value_enum()->number())); + case FieldDescriptor::CPPTYPE_STRING: + return "\"" + + EscapeTrigraphs(CEscape(field->default_value_string())) + + "\""; + case FieldDescriptor::CPPTYPE_MESSAGE: + return "*" + FieldMessageTypeName(field, options) + + "::internal_default_instance()"; + } + // Can't actually get here; make compiler happy. (We could add a default + // case above but then we wouldn't get the nice compiler warning when a + // new type is added.) + GOOGLE_LOG(FATAL) << "Can't get here."; + return ""; +} + +// Convert a file name into a valid identifier. +std::string FilenameIdentifier(const std::string& filename) { + std::string result; + for (int i = 0; i < filename.size(); i++) { + if (ascii_isalnum(filename[i])) { + result.push_back(filename[i]); + } else { + // Not alphanumeric. To avoid any possibility of name conflicts we + // use the hex code for the character. + StrAppend(&result, "_", + strings::Hex(static_cast<uint8_t>(filename[i]))); + } + } + return result; +} + +std::string UniqueName(const std::string& name, const std::string& filename, + const Options& options) { + return name + "_" + FilenameIdentifier(filename); +} + +// Return the qualified C++ name for a file level symbol. +std::string QualifiedFileLevelSymbol(const FileDescriptor* file, + const std::string& name, + const Options& options) { + if (file->package().empty()) { + return StrCat("::", name); + } + return StrCat(Namespace(file, options), "::", name); +} + +// Escape C++ trigraphs by escaping question marks to \? +std::string EscapeTrigraphs(const std::string& to_escape) { + return StringReplace(to_escape, "?", "\\?", true); +} + +// Escaped function name to eliminate naming conflict. +std::string SafeFunctionName(const Descriptor* descriptor, + const FieldDescriptor* field, + const std::string& prefix) { + // Do not use FieldName() since it will escape keywords. + std::string name = field->name(); + LowerString(&name); + std::string function_name = prefix + name; + if (descriptor->FindFieldByName(function_name)) { + // Single underscore will also make it conflicting with the private data + // member. We use double underscore to escape function names. + function_name.append("__"); + } else if (kKeywords.count(name) > 0) { + // If the field name is a keyword, we append the underscore back to keep it + // consistent with other function names. + function_name.append("_"); + } + return function_name; +} + +bool IsStringInlined(const FieldDescriptor* descriptor, + const Options& options) { + (void)descriptor; + (void)options; + return false; +} + +static bool HasLazyFields(const Descriptor* descriptor, const Options& options, + MessageSCCAnalyzer* scc_analyzer) { + for (int field_idx = 0; field_idx < descriptor->field_count(); field_idx++) { + if (IsLazy(descriptor->field(field_idx), options, scc_analyzer)) { + return true; + } + } + for (int idx = 0; idx < descriptor->extension_count(); idx++) { + if (IsLazy(descriptor->extension(idx), options, scc_analyzer)) { + return true; + } + } + for (int idx = 0; idx < descriptor->nested_type_count(); idx++) { + if (HasLazyFields(descriptor->nested_type(idx), options, scc_analyzer)) { + return true; + } + } + return false; +} + +// Does the given FileDescriptor use lazy fields? +bool HasLazyFields(const FileDescriptor* file, const Options& options, + MessageSCCAnalyzer* scc_analyzer) { + for (int i = 0; i < file->message_type_count(); i++) { + const Descriptor* descriptor(file->message_type(i)); + if (HasLazyFields(descriptor, options, scc_analyzer)) { + return true; + } + } + for (int field_idx = 0; field_idx < file->extension_count(); field_idx++) { + if (IsLazy(file->extension(field_idx), options, scc_analyzer)) { + return true; + } + } + return false; +} + +static bool HasRepeatedFields(const Descriptor* descriptor) { + for (int i = 0; i < descriptor->field_count(); ++i) { + if (descriptor->field(i)->label() == FieldDescriptor::LABEL_REPEATED) { + return true; + } + } + for (int i = 0; i < descriptor->nested_type_count(); ++i) { + if (HasRepeatedFields(descriptor->nested_type(i))) return true; + } + return false; +} + +bool HasRepeatedFields(const FileDescriptor* file) { + for (int i = 0; i < file->message_type_count(); ++i) { + if (HasRepeatedFields(file->message_type(i))) return true; + } + return false; +} + +static bool IsStringPieceField(const FieldDescriptor* field, + const Options& options) { + return field->cpp_type() == FieldDescriptor::CPPTYPE_STRING && + EffectiveStringCType(field, options) == FieldOptions::STRING_PIECE; +} + +static bool HasStringPieceFields(const Descriptor* descriptor, + const Options& options) { + for (int i = 0; i < descriptor->field_count(); ++i) { + if (IsStringPieceField(descriptor->field(i), options)) return true; + } + for (int i = 0; i < descriptor->nested_type_count(); ++i) { + if (HasStringPieceFields(descriptor->nested_type(i), options)) return true; + } + return false; +} + +bool HasStringPieceFields(const FileDescriptor* file, const Options& options) { + for (int i = 0; i < file->message_type_count(); ++i) { + if (HasStringPieceFields(file->message_type(i), options)) return true; + } + return false; +} + +static bool IsCordField(const FieldDescriptor* field, const Options& options) { + return field->cpp_type() == FieldDescriptor::CPPTYPE_STRING && + EffectiveStringCType(field, options) == FieldOptions::CORD; +} + +static bool HasCordFields(const Descriptor* descriptor, + const Options& options) { + for (int i = 0; i < descriptor->field_count(); ++i) { + if (IsCordField(descriptor->field(i), options)) return true; + } + for (int i = 0; i < descriptor->nested_type_count(); ++i) { + if (HasCordFields(descriptor->nested_type(i), options)) return true; + } + return false; +} + +bool HasCordFields(const FileDescriptor* file, const Options& options) { + for (int i = 0; i < file->message_type_count(); ++i) { + if (HasCordFields(file->message_type(i), options)) return true; + } + return false; +} + +static bool HasExtensionsOrExtendableMessage(const Descriptor* descriptor) { + if (descriptor->extension_range_count() > 0) return true; + if (descriptor->extension_count() > 0) return true; + for (int i = 0; i < descriptor->nested_type_count(); ++i) { + if (HasExtensionsOrExtendableMessage(descriptor->nested_type(i))) { + return true; + } + } + return false; +} + +bool HasExtensionsOrExtendableMessage(const FileDescriptor* file) { + if (file->extension_count() > 0) return true; + for (int i = 0; i < file->message_type_count(); ++i) { + if (HasExtensionsOrExtendableMessage(file->message_type(i))) return true; + } + return false; +} + +static bool HasMapFields(const Descriptor* descriptor) { + for (int i = 0; i < descriptor->field_count(); ++i) { + if (descriptor->field(i)->is_map()) { + return true; + } + } + for (int i = 0; i < descriptor->nested_type_count(); ++i) { + if (HasMapFields(descriptor->nested_type(i))) return true; + } + return false; +} + +bool HasMapFields(const FileDescriptor* file) { + for (int i = 0; i < file->message_type_count(); ++i) { + if (HasMapFields(file->message_type(i))) return true; + } + return false; +} + +static bool HasEnumDefinitions(const Descriptor* message_type) { + if (message_type->enum_type_count() > 0) return true; + for (int i = 0; i < message_type->nested_type_count(); ++i) { + if (HasEnumDefinitions(message_type->nested_type(i))) return true; + } + return false; +} + +bool HasEnumDefinitions(const FileDescriptor* file) { + if (file->enum_type_count() > 0) return true; + for (int i = 0; i < file->message_type_count(); ++i) { + if (HasEnumDefinitions(file->message_type(i))) return true; + } + return false; +} + +bool ShouldVerify(const Descriptor* descriptor, const Options& options, + MessageSCCAnalyzer* scc_analyzer) { + (void)descriptor; + (void)options; + (void)scc_analyzer; + return false; +} + +bool ShouldVerify(const FileDescriptor* file, const Options& options, + MessageSCCAnalyzer* scc_analyzer) { + (void)file; + (void)options; + (void)scc_analyzer; + return false; +} + +bool IsStringOrMessage(const FieldDescriptor* field) { + switch (field->cpp_type()) { + case FieldDescriptor::CPPTYPE_INT32: + case FieldDescriptor::CPPTYPE_INT64: + case FieldDescriptor::CPPTYPE_UINT32: + case FieldDescriptor::CPPTYPE_UINT64: + case FieldDescriptor::CPPTYPE_DOUBLE: + case FieldDescriptor::CPPTYPE_FLOAT: + case FieldDescriptor::CPPTYPE_BOOL: + case FieldDescriptor::CPPTYPE_ENUM: + return false; + case FieldDescriptor::CPPTYPE_STRING: + case FieldDescriptor::CPPTYPE_MESSAGE: + return true; + } + + GOOGLE_LOG(FATAL) << "Can't get here."; + return false; +} + +FieldOptions::CType EffectiveStringCType(const FieldDescriptor* field, + const Options& options) { + GOOGLE_DCHECK(field->cpp_type() == FieldDescriptor::CPPTYPE_STRING); + if (options.opensource_runtime) { + // Open-source protobuf release only supports STRING ctype. + return FieldOptions::STRING; + } else { + // Google-internal supports all ctypes. + return field->options().ctype(); + } +} + +bool IsAnyMessage(const FileDescriptor* descriptor, const Options& options) { + return descriptor->name() == kAnyProtoFile; +} + +bool IsAnyMessage(const Descriptor* descriptor, const Options& options) { + return descriptor->name() == kAnyMessageName && + IsAnyMessage(descriptor->file(), options); +} + +bool IsWellKnownMessage(const FileDescriptor* file) { + static const std::unordered_set<std::string> well_known_files{ + "google/protobuf/any.proto", + "google/protobuf/api.proto", + "google/protobuf/compiler/plugin.proto", + "google/protobuf/descriptor.proto", + "google/protobuf/duration.proto", + "google/protobuf/empty.proto", + "google/protobuf/field_mask.proto", + "google/protobuf/source_context.proto", + "google/protobuf/struct.proto", + "google/protobuf/timestamp.proto", + "google/protobuf/type.proto", + "google/protobuf/wrappers.proto", + }; + return well_known_files.find(file->name()) != well_known_files.end(); +} + +static bool FieldEnforceUtf8(const FieldDescriptor* field, + const Options& options) { + return true; +} + +static bool FileUtf8Verification(const FileDescriptor* file, + const Options& options) { + return true; +} + +// Which level of UTF-8 enforcemant is placed on this file. +Utf8CheckMode GetUtf8CheckMode(const FieldDescriptor* field, + const Options& options) { + if (field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3 && + FieldEnforceUtf8(field, options)) { + return Utf8CheckMode::kStrict; + } else if (GetOptimizeFor(field->file(), options) != + FileOptions::LITE_RUNTIME && + FileUtf8Verification(field->file(), options)) { + return Utf8CheckMode::kVerify; + } else { + return Utf8CheckMode::kNone; + } +} + +static void GenerateUtf8CheckCode(const FieldDescriptor* field, + const Options& options, bool for_parse, + const char* parameters, + const char* strict_function, + const char* verify_function, + const Formatter& format) { + switch (GetUtf8CheckMode(field, options)) { + case Utf8CheckMode::kStrict: { + if (for_parse) { + format("DO_("); + } + format("::$proto_ns$::internal::WireFormatLite::$1$(\n", strict_function); + format.Indent(); + format(parameters); + if (for_parse) { + format("::$proto_ns$::internal::WireFormatLite::PARSE,\n"); + } else { + format("::$proto_ns$::internal::WireFormatLite::SERIALIZE,\n"); + } + format("\"$1$\")", field->full_name()); + if (for_parse) { + format(")"); + } + format(";\n"); + format.Outdent(); + break; + } + case Utf8CheckMode::kVerify: { + format("::$proto_ns$::internal::WireFormat::$1$(\n", verify_function); + format.Indent(); + format(parameters); + if (for_parse) { + format("::$proto_ns$::internal::WireFormat::PARSE,\n"); + } else { + format("::$proto_ns$::internal::WireFormat::SERIALIZE,\n"); + } + format("\"$1$\");\n", field->full_name()); + format.Outdent(); + break; + } + case Utf8CheckMode::kNone: + break; + } +} + +void GenerateUtf8CheckCodeForString(const FieldDescriptor* field, + const Options& options, bool for_parse, + const char* parameters, + const Formatter& format) { + GenerateUtf8CheckCode(field, options, for_parse, parameters, + "VerifyUtf8String", "VerifyUTF8StringNamedField", + format); +} + +void GenerateUtf8CheckCodeForCord(const FieldDescriptor* field, + const Options& options, bool for_parse, + const char* parameters, + const Formatter& format) { + GenerateUtf8CheckCode(field, options, for_parse, parameters, "VerifyUtf8Cord", + "VerifyUTF8CordNamedField", format); +} + +void FlattenMessagesInFile(const FileDescriptor* file, + std::vector<const Descriptor*>* result) { + for (int i = 0; i < file->message_type_count(); i++) { + ForEachMessage(file->message_type(i), [&](const Descriptor* descriptor) { + result->push_back(descriptor); + }); + } +} + +bool HasWeakFields(const Descriptor* descriptor, const Options& options) { + for (int i = 0; i < descriptor->field_count(); i++) { + if (IsWeak(descriptor->field(i), options)) return true; + } + return false; +} + +bool HasWeakFields(const FileDescriptor* file, const Options& options) { + for (int i = 0; i < file->message_type_count(); ++i) { + if (HasWeakFields(file->message_type(i), options)) return true; + } + return false; +} + +bool UsingImplicitWeakFields(const FileDescriptor* file, + const Options& options) { + return options.lite_implicit_weak_fields && + GetOptimizeFor(file, options) == FileOptions::LITE_RUNTIME; +} + +bool IsImplicitWeakField(const FieldDescriptor* field, const Options& options, + MessageSCCAnalyzer* scc_analyzer) { + return UsingImplicitWeakFields(field->file(), options) && + field->type() == FieldDescriptor::TYPE_MESSAGE && + !field->is_required() && !field->is_map() && !field->is_extension() && + !field->real_containing_oneof() && + !IsWellKnownMessage(field->message_type()->file()) && + field->message_type()->file()->name() != + "net/proto2/proto/descriptor.proto" && + // We do not support implicit weak fields between messages in the same + // strongly-connected component. + scc_analyzer->GetSCC(field->containing_type()) != + scc_analyzer->GetSCC(field->message_type()); +} + +MessageAnalysis MessageSCCAnalyzer::GetSCCAnalysis(const SCC* scc) { + if (analysis_cache_.count(scc)) return analysis_cache_[scc]; + MessageAnalysis result; + if (UsingImplicitWeakFields(scc->GetFile(), options_)) { + result.contains_weak = true; + } + for (int i = 0; i < scc->descriptors.size(); i++) { + const Descriptor* descriptor = scc->descriptors[i]; + if (descriptor->extension_range_count() > 0) { + result.contains_extension = true; + } + for (int j = 0; j < descriptor->field_count(); j++) { + const FieldDescriptor* field = descriptor->field(j); + if (field->is_required()) { + result.contains_required = true; + } + if (field->options().weak()) { + result.contains_weak = true; + } + switch (field->type()) { + case FieldDescriptor::TYPE_STRING: + case FieldDescriptor::TYPE_BYTES: { + if (field->options().ctype() == FieldOptions::CORD) { + result.contains_cord = true; + } + break; + } + case FieldDescriptor::TYPE_GROUP: + case FieldDescriptor::TYPE_MESSAGE: { + const SCC* child = analyzer_.GetSCC(field->message_type()); + if (child != scc) { + MessageAnalysis analysis = GetSCCAnalysis(child); + result.contains_cord |= analysis.contains_cord; + result.contains_extension |= analysis.contains_extension; + if (!ShouldIgnoreRequiredFieldCheck(field, options_)) { + result.contains_required |= analysis.contains_required; + } + result.contains_weak |= analysis.contains_weak; + } else { + // This field points back into the same SCC hence the messages + // in the SCC are recursive. Note if SCC contains more than two + // nodes it has to be recursive, however this test also works for + // a single node that is recursive. + result.is_recursive = true; + } + break; + } + default: + break; + } + } + } + // We deliberately only insert the result here. After we contracted the SCC + // in the graph, the graph should be a DAG. Hence we shouldn't need to mark + // nodes visited as we can never return to them. By inserting them here + // we will go in an infinite loop if the SCC is not correct. + return analysis_cache_[scc] = result; +} + +void ListAllFields(const Descriptor* d, + std::vector<const FieldDescriptor*>* fields) { + // Collect sub messages + for (int i = 0; i < d->nested_type_count(); i++) { + ListAllFields(d->nested_type(i), fields); + } + // Collect message level extensions. + for (int i = 0; i < d->extension_count(); i++) { + fields->push_back(d->extension(i)); + } + // Add types of fields necessary + for (int i = 0; i < d->field_count(); i++) { + fields->push_back(d->field(i)); + } +} + +void ListAllFields(const FileDescriptor* d, + std::vector<const FieldDescriptor*>* fields) { + // Collect file level message. + for (int i = 0; i < d->message_type_count(); i++) { + ListAllFields(d->message_type(i), fields); + } + // Collect message level extensions. + for (int i = 0; i < d->extension_count(); i++) { + fields->push_back(d->extension(i)); + } +} + +void ListAllTypesForServices(const FileDescriptor* fd, + std::vector<const Descriptor*>* types) { + for (int i = 0; i < fd->service_count(); i++) { + const ServiceDescriptor* sd = fd->service(i); + for (int j = 0; j < sd->method_count(); j++) { + const MethodDescriptor* method = sd->method(j); + types->push_back(method->input_type()); + types->push_back(method->output_type()); + } + } +} + +bool GetBootstrapBasename(const Options& options, const std::string& basename, + std::string* bootstrap_basename) { + if (options.opensource_runtime) { + return false; + } + + std::unordered_map<std::string, std::string> bootstrap_mapping{ + {"net/proto2/proto/descriptor", + "net/proto2/internal/descriptor"}, + {"net/proto2/compiler/proto/plugin", + "net/proto2/compiler/proto/plugin"}, + {"net/proto2/compiler/proto/profile", + "net/proto2/compiler/proto/profile_bootstrap"}, + }; + auto iter = bootstrap_mapping.find(basename); + if (iter == bootstrap_mapping.end()) { + *bootstrap_basename = basename; + return false; + } else { + *bootstrap_basename = iter->second; + return true; + } +} + +bool IsBootstrapProto(const Options& options, const FileDescriptor* file) { + std::string my_name = StripProto(file->name()); + return GetBootstrapBasename(options, my_name, &my_name); +} + +bool MaybeBootstrap(const Options& options, GeneratorContext* generator_context, + bool bootstrap_flag, std::string* basename) { + std::string bootstrap_basename; + if (!GetBootstrapBasename(options, *basename, &bootstrap_basename)) { + return false; + } + + if (bootstrap_flag) { + // Adjust basename, but don't abort code generation. + *basename = bootstrap_basename; + return false; + } else { + std::string forward_to_basename = bootstrap_basename; + + // Generate forwarding headers and empty .pb.cc. + { + std::unique_ptr<io::ZeroCopyOutputStream> output( + generator_context->Open(*basename + ".pb.h")); + io::Printer printer(output.get(), '$', nullptr); + printer.Print( + "#ifndef PROTOBUF_INCLUDED_$filename_identifier$_FORWARD_PB_H\n" + "#define PROTOBUF_INCLUDED_$filename_identifier$_FORWARD_PB_H\n" + "#include \"$forward_to_basename$.pb.h\" // IWYU pragma: export\n" + "#endif // PROTOBUF_INCLUDED_$filename_identifier$_FORWARD_PB_H\n", + "forward_to_basename", forward_to_basename, "filename_identifier", + FilenameIdentifier(*basename)); + + if (!options.opensource_runtime) { + // HACK HACK HACK, tech debt from the deeps of proto1 and SWIG + // protocoltype is SWIG'ed and we need to forward + if (*basename == "net/proto/protocoltype") { + printer.Print( + "#ifdef SWIG\n" + "%include \"$forward_to_basename$.pb.h\"\n" + "#endif // SWIG\n", + "forward_to_basename", forward_to_basename); + } + } + } + + { + std::unique_ptr<io::ZeroCopyOutputStream> output( + generator_context->Open(*basename + ".proto.h")); + io::Printer printer(output.get(), '$', nullptr); + printer.Print( + "#ifndef PROTOBUF_INCLUDED_$filename_identifier$_FORWARD_PROTO_H\n" + "#define PROTOBUF_INCLUDED_$filename_identifier$_FORWARD_PROTO_H\n" + "#include \"$forward_to_basename$.proto.h\" // IWYU pragma: " + "export\n" + "#endif // " + "PROTOBUF_INCLUDED_$filename_identifier$_FORWARD_PROTO_H\n", + "forward_to_basename", forward_to_basename, "filename_identifier", + FilenameIdentifier(*basename)); + } + + { + std::unique_ptr<io::ZeroCopyOutputStream> output( + generator_context->Open(*basename + ".pb.cc")); + io::Printer printer(output.get(), '$', nullptr); + printer.Print("\n"); + } + + { + std::unique_ptr<io::ZeroCopyOutputStream> output( + generator_context->Open(*basename + ".pb.h.meta")); + } + + { + std::unique_ptr<io::ZeroCopyOutputStream> output( + generator_context->Open(*basename + ".proto.h.meta")); + } + + // Abort code generation. + return true; + } +} + +static bool HasExtensionFromFile(const Message& msg, const FileDescriptor* file, + const Options& options, + bool* has_opt_codesize_extension) { + std::vector<const FieldDescriptor*> fields; + auto reflection = msg.GetReflection(); + reflection->ListFields(msg, &fields); + for (auto field : fields) { + const auto* field_msg = field->message_type(); + if (field_msg == nullptr) { + // It so happens that enums Is_Valid are still generated so enums work. + // Only messages have potential problems. + continue; + } + // If this option has an extension set AND that extension is defined in the + // same file we have bootstrap problem. + if (field->is_extension()) { + const auto* msg_extension_file = field->message_type()->file(); + if (msg_extension_file == file) return true; + if (has_opt_codesize_extension && + GetOptimizeFor(msg_extension_file, options) == + FileOptions::CODE_SIZE) { + *has_opt_codesize_extension = true; + } + } + // Recurse in this field to see if there is a problem in there + if (field->is_repeated()) { + for (int i = 0; i < reflection->FieldSize(msg, field); i++) { + if (HasExtensionFromFile(reflection->GetRepeatedMessage(msg, field, i), + file, options, has_opt_codesize_extension)) { + return true; + } + } + } else { + if (HasExtensionFromFile(reflection->GetMessage(msg, field), file, + options, has_opt_codesize_extension)) { + return true; + } + } + } + return false; +} + +static bool HasBootstrapProblem(const FileDescriptor* file, + const Options& options, + bool* has_opt_codesize_extension) { + static auto& cache = *new std::unordered_map<const FileDescriptor*, bool>; + auto it = cache.find(file); + if (it != cache.end()) return it->second; + // In order to build the data structures for the reflective parse, it needs + // to parse the serialized descriptor describing all the messages defined in + // this file. Obviously this presents a bootstrap problem for descriptor + // messages. + if (file->name() == "net/proto2/proto/descriptor.proto" || + file->name() == "google/protobuf/descriptor.proto") { + return true; + } + // Unfortunately we're not done yet. The descriptor option messages allow + // for extensions. So we need to be able to parse these extensions in order + // to parse the file descriptor for a file that has custom options. This is a + // problem when these custom options extensions are defined in the same file. + FileDescriptorProto linkedin_fd_proto; + const DescriptorPool* pool = file->pool(); + const Descriptor* fd_proto_descriptor = + pool->FindMessageTypeByName(linkedin_fd_proto.GetTypeName()); + // Not all pools have descriptor.proto in them. In these cases there for sure + // are no custom options. + if (fd_proto_descriptor == nullptr) return false; + + // It's easier to inspect file as a proto, because we can use reflection on + // the proto to iterate over all content. + file->CopyTo(&linkedin_fd_proto); + + // linkedin_fd_proto is a generated proto linked in the proto compiler. As + // such it doesn't know the extensions that are potentially present in the + // descriptor pool constructed from the protos that are being compiled. These + // custom options are therefore in the unknown fields. + // By building the corresponding FileDescriptorProto in the pool constructed + // by the protos that are being compiled, ie. file's pool, the unknown fields + // are converted to extensions. + DynamicMessageFactory factory(pool); + Message* fd_proto = factory.GetPrototype(fd_proto_descriptor)->New(); + fd_proto->ParseFromString(linkedin_fd_proto.SerializeAsString()); + + bool& res = cache[file]; + res = HasExtensionFromFile(*fd_proto, file, options, + has_opt_codesize_extension); + delete fd_proto; + return res; +} + +FileOptions_OptimizeMode GetOptimizeFor(const FileDescriptor* file, + const Options& options, + bool* has_opt_codesize_extension) { + if (has_opt_codesize_extension) *has_opt_codesize_extension = false; + switch (options.enforce_mode) { + case EnforceOptimizeMode::kSpeed: + return FileOptions::SPEED; + case EnforceOptimizeMode::kLiteRuntime: + return FileOptions::LITE_RUNTIME; + case EnforceOptimizeMode::kCodeSize: + if (file->options().optimize_for() == FileOptions::LITE_RUNTIME) { + return FileOptions::LITE_RUNTIME; + } + if (HasBootstrapProblem(file, options, has_opt_codesize_extension)) { + return FileOptions::SPEED; + } + return FileOptions::CODE_SIZE; + case EnforceOptimizeMode::kNoEnforcement: + if (file->options().optimize_for() == FileOptions::CODE_SIZE) { + if (HasBootstrapProblem(file, options, has_opt_codesize_extension)) { + GOOGLE_LOG(WARNING) << "Proto states optimize_for = CODE_SIZE, but we " + "cannot honor that because it contains custom option " + "extensions defined in the same proto."; + return FileOptions::SPEED; + } + } + return file->options().optimize_for(); + } + + GOOGLE_LOG(FATAL) << "Unknown optimization enforcement requested."; + // The phony return below serves to silence a warning from GCC 8. + return FileOptions::SPEED; +} + +bool EnableMessageOwnedArena(const Descriptor* desc) { + (void)desc; + return false; +} + +} // namespace cpp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_helpers.h b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_helpers.h new file mode 100644 index 00000000..dd380c7e --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_helpers.h @@ -0,0 +1,971 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_HELPERS_H__ +#define GOOGLE_PROTOBUF_COMPILER_CPP_HELPERS_H__ + +#include <algorithm> +#include <cstdint> +#include <iterator> +#include <map> +#include <string> + +#include <compiler/cpp/cpp_options.h> +#include <compiler/cpp/cpp_names.h> +#include <compiler/scc.h> +#include <compiler/code_generator.h> +#include <descriptor.pb.h> +#include <io/printer.h> +#include <descriptor.h> +#include <port.h> +#include <stubs/strutil.h> + +// Must be included last. +#include <port_def.inc> + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { + +inline std::string ProtobufNamespace(const Options& /* options */) { + return "PROTOBUF_NAMESPACE_ID"; +} + +inline std::string MacroPrefix(const Options& /* options */) { + return "GOOGLE_PROTOBUF"; +} + +inline std::string DeprecatedAttribute(const Options& /* options */, + const FieldDescriptor* d) { + return d->options().deprecated() ? "PROTOBUF_DEPRECATED " : ""; +} + +inline std::string DeprecatedAttribute(const Options& /* options */, + const EnumValueDescriptor* d) { + return d->options().deprecated() ? "PROTOBUF_DEPRECATED_ENUM " : ""; +} + +// Commonly-used separator comments. Thick is a line of '=', thin is a line +// of '-'. +extern const char kThickSeparator[]; +extern const char kThinSeparator[]; + +void SetCommonVars(const Options& options, + std::map<std::string, std::string>* variables); + +void SetUnknownFieldsVariable(const Descriptor* descriptor, + const Options& options, + std::map<std::string, std::string>* variables); + +bool GetBootstrapBasename(const Options& options, const std::string& basename, + std::string* bootstrap_basename); +bool MaybeBootstrap(const Options& options, GeneratorContext* generator_context, + bool bootstrap_flag, std::string* basename); +bool IsBootstrapProto(const Options& options, const FileDescriptor* file); + +// Name space of the proto file. This namespace is such that the string +// "<namespace>::some_name" is the correct fully qualified namespace. +// This means if the package is empty the namespace is "", and otherwise +// the namespace is "::foo::bar::...::baz" without trailing semi-colons. +std::string Namespace(const FileDescriptor* d, const Options& options); +std::string Namespace(const Descriptor* d, const Options& options); +std::string Namespace(const FieldDescriptor* d, const Options& options); +std::string Namespace(const EnumDescriptor* d, const Options& options); + +// Returns true if it's safe to reset "field" to zero. +bool CanInitializeByZeroing(const FieldDescriptor* field); + +std::string ClassName(const Descriptor* descriptor); +std::string ClassName(const EnumDescriptor* enum_descriptor); + +std::string QualifiedClassName(const Descriptor* d, const Options& options); +std::string QualifiedClassName(const EnumDescriptor* d, const Options& options); + +std::string QualifiedClassName(const Descriptor* d); +std::string QualifiedClassName(const EnumDescriptor* d); + +// DEPRECATED just use ClassName or QualifiedClassName, a boolean is very +// unreadable at the callsite. +// Returns the non-nested type name for the given type. If "qualified" is +// true, prefix the type with the full namespace. For example, if you had: +// package foo.bar; +// message Baz { message Qux {} } +// Then the qualified ClassName for Qux would be: +// ::foo::bar::Baz_Qux +// While the non-qualified version would be: +// Baz_Qux +inline std::string ClassName(const Descriptor* descriptor, bool qualified) { + return qualified ? QualifiedClassName(descriptor, Options()) + : ClassName(descriptor); +} + +inline std::string ClassName(const EnumDescriptor* descriptor, bool qualified) { + return qualified ? QualifiedClassName(descriptor, Options()) + : ClassName(descriptor); +} + +// Returns the extension name prefixed with the class name if nested but without +// the package name. +std::string ExtensionName(const FieldDescriptor* d); + +std::string QualifiedExtensionName(const FieldDescriptor* d, + const Options& options); +std::string QualifiedExtensionName(const FieldDescriptor* d); + +// Type name of default instance. +std::string DefaultInstanceType(const Descriptor* descriptor, + const Options& options); + +// Non-qualified name of the default_instance of this message. +std::string DefaultInstanceName(const Descriptor* descriptor, + const Options& options); + +// Non-qualified name of the default instance pointer. This is used only for +// implicit weak fields, where we need an extra indirection. +std::string DefaultInstancePtr(const Descriptor* descriptor, + const Options& options); + +// Fully qualified name of the default_instance of this message. +std::string QualifiedDefaultInstanceName(const Descriptor* descriptor, + const Options& options); + +// Fully qualified name of the default instance pointer. +std::string QualifiedDefaultInstancePtr(const Descriptor* descriptor, + const Options& options); + +// DescriptorTable variable name. +std::string DescriptorTableName(const FileDescriptor* file, + const Options& options); + +// When declaring symbol externs from another file, this macro will supply the +// dllexport needed for the target file, if any. +std::string FileDllExport(const FileDescriptor* file, const Options& options); + +// Name of the base class: google::protobuf::Message or google::protobuf::MessageLite. +std::string SuperClassName(const Descriptor* descriptor, + const Options& options); + +// Adds an underscore if necessary to prevent conflicting with a keyword. +std::string ResolveKeyword(const std::string& name); + +// Get the (unqualified) name that should be used for this field in C++ code. +// The name is coerced to lower-case to emulate proto1 behavior. People +// should be using lowercase-with-underscores style for proto field names +// anyway, so normally this just returns field->name(). +std::string FieldName(const FieldDescriptor* field); + +// Returns an estimate of the compiler's alignment for the field. This +// can't guarantee to be correct because the generated code could be compiled on +// different systems with different alignment rules. The estimates below assume +// 64-bit pointers. +int EstimateAlignmentSize(const FieldDescriptor* field); + +// Get the unqualified name that should be used for a field's field +// number constant. +std::string FieldConstantName(const FieldDescriptor* field); + +// Returns the scope where the field was defined (for extensions, this is +// different from the message type to which the field applies). +inline const Descriptor* FieldScope(const FieldDescriptor* field) { + return field->is_extension() ? field->extension_scope() + : field->containing_type(); +} + +// Returns the fully-qualified type name field->message_type(). Usually this +// is just ClassName(field->message_type(), true); +std::string FieldMessageTypeName(const FieldDescriptor* field, + const Options& options); + +// Get the C++ type name for a primitive type (e.g. "double", "::google::protobuf::int32", etc.). +const char* PrimitiveTypeName(FieldDescriptor::CppType type); +std::string PrimitiveTypeName(const Options& options, + FieldDescriptor::CppType type); + +// Get the declared type name in CamelCase format, as is used e.g. for the +// methods of WireFormat. For example, TYPE_INT32 becomes "Int32". +const char* DeclaredTypeMethodName(FieldDescriptor::Type type); + +// Return the code that evaluates to the number when compiled. +std::string Int32ToString(int number); + +// Get code that evaluates to the field's default value. +std::string DefaultValue(const Options& options, const FieldDescriptor* field); + +// Compatibility function for callers outside proto2. +std::string DefaultValue(const FieldDescriptor* field); + +// Convert a file name into a valid identifier. +std::string FilenameIdentifier(const std::string& filename); + +// For each .proto file generates a unique name. To prevent collisions of +// symbols in the global namespace +std::string UniqueName(const std::string& name, const std::string& filename, + const Options& options); +inline std::string UniqueName(const std::string& name, const FileDescriptor* d, + const Options& options) { + return UniqueName(name, d->name(), options); +} +inline std::string UniqueName(const std::string& name, const Descriptor* d, + const Options& options) { + return UniqueName(name, d->file(), options); +} +inline std::string UniqueName(const std::string& name, const EnumDescriptor* d, + const Options& options) { + return UniqueName(name, d->file(), options); +} +inline std::string UniqueName(const std::string& name, + const ServiceDescriptor* d, + const Options& options) { + return UniqueName(name, d->file(), options); +} + +// Versions for call sites that only support the internal runtime (like proto1 +// support). +inline Options InternalRuntimeOptions() { + Options options; + options.opensource_runtime = false; + return options; +} +inline std::string UniqueName(const std::string& name, + const std::string& filename) { + return UniqueName(name, filename, InternalRuntimeOptions()); +} +inline std::string UniqueName(const std::string& name, + const FileDescriptor* d) { + return UniqueName(name, d->name(), InternalRuntimeOptions()); +} +inline std::string UniqueName(const std::string& name, const Descriptor* d) { + return UniqueName(name, d->file(), InternalRuntimeOptions()); +} +inline std::string UniqueName(const std::string& name, + const EnumDescriptor* d) { + return UniqueName(name, d->file(), InternalRuntimeOptions()); +} +inline std::string UniqueName(const std::string& name, + const ServiceDescriptor* d) { + return UniqueName(name, d->file(), InternalRuntimeOptions()); +} + +// Return the qualified C++ name for a file level symbol. +std::string QualifiedFileLevelSymbol(const FileDescriptor* file, + const std::string& name, + const Options& options); + +// Escape C++ trigraphs by escaping question marks to \? +std::string EscapeTrigraphs(const std::string& to_escape); + +// Escaped function name to eliminate naming conflict. +std::string SafeFunctionName(const Descriptor* descriptor, + const FieldDescriptor* field, + const std::string& prefix); + +// Returns true if generated messages have public unknown fields accessors +inline bool PublicUnknownFieldsAccessors(const Descriptor* message) { + return message->file()->syntax() != FileDescriptor::SYNTAX_PROTO3; +} + +// Returns the optimize mode for <file>, respecting <options.enforce_lite>. +FileOptions_OptimizeMode GetOptimizeFor(const FileDescriptor* file, + const Options& options); + +// Determines whether unknown fields will be stored in an UnknownFieldSet or +// a string. +inline bool UseUnknownFieldSet(const FileDescriptor* file, + const Options& options) { + return GetOptimizeFor(file, options) != FileOptions::LITE_RUNTIME; +} + +inline bool IsWeak(const FieldDescriptor* field, const Options& options) { + if (field->options().weak()) { + GOOGLE_CHECK(!options.opensource_runtime); + return true; + } + return false; +} + +bool IsStringInlined(const FieldDescriptor* descriptor, const Options& options); + +// For a string field, returns the effective ctype. If the actual ctype is +// not supported, returns the default of STRING. +FieldOptions::CType EffectiveStringCType(const FieldDescriptor* field, + const Options& options); + +inline bool IsCord(const FieldDescriptor* field, const Options& options) { + return field->cpp_type() == FieldDescriptor::CPPTYPE_STRING && + EffectiveStringCType(field, options) == FieldOptions::CORD; +} + +inline bool IsString(const FieldDescriptor* field, const Options& options) { + return field->cpp_type() == FieldDescriptor::CPPTYPE_STRING && + EffectiveStringCType(field, options) == FieldOptions::STRING; +} + +inline bool IsStringPiece(const FieldDescriptor* field, + const Options& options) { + return field->cpp_type() == FieldDescriptor::CPPTYPE_STRING && + EffectiveStringCType(field, options) == FieldOptions::STRING_PIECE; +} + +class MessageSCCAnalyzer; + +// Does the given FileDescriptor use lazy fields? +bool HasLazyFields(const FileDescriptor* file, const Options& options, + MessageSCCAnalyzer* scc_analyzer); + +// Is the given field a supported lazy field? +bool IsLazy(const FieldDescriptor* field, const Options& options, + MessageSCCAnalyzer* scc_analyzer); + +inline bool IsLazilyVerifiedLazy(const FieldDescriptor* field, + const Options& options) { + return field->options().lazy() && !field->is_repeated() && + field->type() == FieldDescriptor::TYPE_MESSAGE && + GetOptimizeFor(field->file(), options) != FileOptions::LITE_RUNTIME && + !options.opensource_runtime; +} + +inline bool IsEagerlyVerifiedLazy(const FieldDescriptor* field, + const Options& options, + MessageSCCAnalyzer* scc_analyzer) { + return IsLazy(field, options, scc_analyzer) && !field->options().lazy(); +} + +inline bool IsFieldUsed(const FieldDescriptor* /* field */, + const Options& /* options */) { + return true; +} + +// Returns true if "field" is stripped. +inline bool IsFieldStripped(const FieldDescriptor* /*field*/, + const Options& /*options*/) { + return false; +} + +// Does the file contain any definitions that need extension_set.h? +bool HasExtensionsOrExtendableMessage(const FileDescriptor* file); + +// Does the file have any repeated fields, necessitating the file to include +// repeated_field.h? This does not include repeated extensions, since those are +// all stored internally in an ExtensionSet, not a separate RepeatedField*. +bool HasRepeatedFields(const FileDescriptor* file); + +// Does the file have any string/bytes fields with ctype=STRING_PIECE? This +// does not include extensions, since ctype is ignored for extensions. +bool HasStringPieceFields(const FileDescriptor* file, const Options& options); + +// Does the file have any string/bytes fields with ctype=CORD? This does not +// include extensions, since ctype is ignored for extensions. +bool HasCordFields(const FileDescriptor* file, const Options& options); + +// Does the file have any map fields, necessitating the file to include +// map_field_inl.h and map.h. +bool HasMapFields(const FileDescriptor* file); + +// Does this file have any enum type definitions? +bool HasEnumDefinitions(const FileDescriptor* file); + +// Does this file have generated parsing, serialization, and other +// standard methods for which reflection-based fallback implementations exist? +inline bool HasGeneratedMethods(const FileDescriptor* file, + const Options& options) { + return GetOptimizeFor(file, options) != FileOptions::CODE_SIZE; +} + +// Do message classes in this file have descriptor and reflection methods? +inline bool HasDescriptorMethods(const FileDescriptor* file, + const Options& options) { + return GetOptimizeFor(file, options) != FileOptions::LITE_RUNTIME; +} + +// Should we generate generic services for this file? +inline bool HasGenericServices(const FileDescriptor* file, + const Options& options) { + return file->service_count() > 0 && + GetOptimizeFor(file, options) != FileOptions::LITE_RUNTIME && + file->options().cc_generic_services(); +} + +inline bool IsProto2MessageSet(const Descriptor* descriptor, + const Options& options) { + return !options.opensource_runtime && + options.enforce_mode != EnforceOptimizeMode::kLiteRuntime && + !options.lite_implicit_weak_fields && + descriptor->options().message_set_wire_format() && + descriptor->full_name() == "google.protobuf.bridge.MessageSet"; +} + +inline bool IsMapEntryMessage(const Descriptor* descriptor) { + return descriptor->options().map_entry(); +} + +// Returns true if the field's CPPTYPE is string or message. +bool IsStringOrMessage(const FieldDescriptor* field); + +std::string UnderscoresToCamelCase(const std::string& input, + bool cap_next_letter); + +inline bool IsProto3(const FileDescriptor* file) { + return file->syntax() == FileDescriptor::SYNTAX_PROTO3; +} + +inline bool HasHasbit(const FieldDescriptor* field) { + // This predicate includes proto3 message fields only if they have "optional". + // Foo submsg1 = 1; // HasHasbit() == false + // optional Foo submsg2 = 2; // HasHasbit() == true + // This is slightly odd, as adding "optional" to a singular proto3 field does + // not change the semantics or API. However whenever any field in a message + // has a hasbit, it forces reflection to include hasbit offsets for *all* + // fields, even if almost all of them are set to -1 (no hasbit). So to avoid + // causing a sudden size regression for ~all proto3 messages, we give proto3 + // message fields a hasbit only if "optional" is present. If the user is + // explicitly writing "optional", it is likely they are writing it on + // primitive fields also. + return (field->has_optional_keyword() || field->is_required()) && + !field->options().weak(); +} + +// Returns true if 'enum' semantics are such that unknown values are preserved +// in the enum field itself, rather than going to the UnknownFieldSet. +inline bool HasPreservingUnknownEnumSemantics(const FieldDescriptor* field) { + return field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3; +} + +inline bool IsCrossFileMessage(const FieldDescriptor* field) { + return field->type() == FieldDescriptor::TYPE_MESSAGE && + field->message_type()->file() != field->file(); +} + +inline std::string MakeDefaultName(const FieldDescriptor* field) { + return "_i_give_permission_to_break_this_code_default_" + FieldName(field) + + "_"; +} + +bool IsAnyMessage(const FileDescriptor* descriptor, const Options& options); +bool IsAnyMessage(const Descriptor* descriptor, const Options& options); + +bool IsWellKnownMessage(const FileDescriptor* descriptor); + +inline std::string IncludeGuard(const FileDescriptor* file, bool pb_h, + const Options& options) { + // If we are generating a .pb.h file and the proto_h option is enabled, then + // the .pb.h gets an extra suffix. + std::string filename_identifier = FilenameIdentifier( + file->name() + (pb_h && options.proto_h ? ".pb.h" : "")); + + if (IsWellKnownMessage(file)) { + // For well-known messages we need third_party/protobuf and net/proto2 to + // have distinct include guards, because some source files include both and + // both need to be defined (the third_party copies will be in the + // google::protobuf_opensource namespace). + return MacroPrefix(options) + "_INCLUDED_" + filename_identifier; + } else { + // Ideally this case would use distinct include guards for opensource and + // google3 protos also. (The behavior of "first #included wins" is not + // ideal). But unfortunately some legacy code includes both and depends on + // the identical include guards to avoid compile errors. + // + // We should clean this up so that this case can be removed. + return "GOOGLE_PROTOBUF_INCLUDED_" + filename_identifier; + } +} + +// Returns the OptimizeMode for this file, furthermore it updates a status +// bool if has_opt_codesize_extension is non-null. If this status bool is true +// it means this file contains an extension that itself is defined as +// optimized_for = CODE_SIZE. +FileOptions_OptimizeMode GetOptimizeFor(const FileDescriptor* file, + const Options& options, + bool* has_opt_codesize_extension); +inline FileOptions_OptimizeMode GetOptimizeFor(const FileDescriptor* file, + const Options& options) { + return GetOptimizeFor(file, options, nullptr); +} +inline bool NeedsEagerDescriptorAssignment(const FileDescriptor* file, + const Options& options) { + bool has_opt_codesize_extension; + if (GetOptimizeFor(file, options, &has_opt_codesize_extension) == + FileOptions::CODE_SIZE && + has_opt_codesize_extension) { + // If this filedescriptor contains an extension from another file which + // is optimized_for = CODE_SIZE. We need to be careful in the ordering so + // we eagerly build the descriptors in the dependencies before building + // the descriptors of this file. + return true; + } else { + // If we have a generated code based parser we never need eager + // initialization of descriptors of our deps. + return false; + } +} + +// This orders the messages in a .pb.cc as it's outputted by file.cc +void FlattenMessagesInFile(const FileDescriptor* file, + std::vector<const Descriptor*>* result); +inline std::vector<const Descriptor*> FlattenMessagesInFile( + const FileDescriptor* file) { + std::vector<const Descriptor*> result; + FlattenMessagesInFile(file, &result); + return result; +} + +template <typename F> +void ForEachMessage(const Descriptor* descriptor, F&& func) { + for (int i = 0; i < descriptor->nested_type_count(); i++) + ForEachMessage(descriptor->nested_type(i), std::forward<F&&>(func)); + func(descriptor); +} + +template <typename F> +void ForEachMessage(const FileDescriptor* descriptor, F&& func) { + for (int i = 0; i < descriptor->message_type_count(); i++) + ForEachMessage(descriptor->message_type(i), std::forward<F&&>(func)); +} + +bool HasWeakFields(const Descriptor* desc, const Options& options); +bool HasWeakFields(const FileDescriptor* desc, const Options& options); + +// Returns true if the "required" restriction check should be ignored for the +// given field. +inline static bool ShouldIgnoreRequiredFieldCheck(const FieldDescriptor* field, + const Options& options) { + // Do not check "required" for lazily verified lazy fields. + return IsLazilyVerifiedLazy(field, options); +} + +struct MessageAnalysis { + bool is_recursive = false; + bool contains_cord = false; + bool contains_extension = false; + bool contains_required = false; + bool contains_weak = false; // Implicit weak as well. +}; + +// This class is used in FileGenerator, to ensure linear instead of +// quadratic performance, if we do this per message we would get O(V*(V+E)). +// Logically this is just only used in message.cc, but in the header for +// FileGenerator to help share it. +class PROTOC_EXPORT MessageSCCAnalyzer { + public: + explicit MessageSCCAnalyzer(const Options& options) : options_(options) {} + + MessageAnalysis GetSCCAnalysis(const SCC* scc); + + bool HasRequiredFields(const Descriptor* descriptor) { + MessageAnalysis result = GetSCCAnalysis(GetSCC(descriptor)); + return result.contains_required || result.contains_extension; + } + bool HasWeakField(const Descriptor* descriptor) { + MessageAnalysis result = GetSCCAnalysis(GetSCC(descriptor)); + return result.contains_weak; + } + const SCC* GetSCC(const Descriptor* descriptor) { + return analyzer_.GetSCC(descriptor); + } + + private: + struct DepsGenerator { + std::vector<const Descriptor*> operator()(const Descriptor* desc) const { + std::vector<const Descriptor*> deps; + for (int i = 0; i < desc->field_count(); i++) { + if (desc->field(i)->message_type()) { + deps.push_back(desc->field(i)->message_type()); + } + } + return deps; + } + }; + SCCAnalyzer<DepsGenerator> analyzer_; + Options options_; + std::map<const SCC*, MessageAnalysis> analysis_cache_; +}; + +void ListAllFields(const Descriptor* d, + std::vector<const FieldDescriptor*>* fields); +void ListAllFields(const FileDescriptor* d, + std::vector<const FieldDescriptor*>* fields); + +template <class T> +void ForEachField(const Descriptor* d, T&& func) { + for (int i = 0; i < d->nested_type_count(); i++) { + ForEachField(d->nested_type(i), std::forward<T&&>(func)); + } + for (int i = 0; i < d->extension_count(); i++) { + func(d->extension(i)); + } + for (int i = 0; i < d->field_count(); i++) { + func(d->field(i)); + } +} + +template <class T> +void ForEachField(const FileDescriptor* d, T&& func) { + for (int i = 0; i < d->message_type_count(); i++) { + ForEachField(d->message_type(i), std::forward<T&&>(func)); + } + for (int i = 0; i < d->extension_count(); i++) { + func(d->extension(i)); + } +} + +void ListAllTypesForServices(const FileDescriptor* fd, + std::vector<const Descriptor*>* types); + +// Indicates whether we should use implicit weak fields for this file. +bool UsingImplicitWeakFields(const FileDescriptor* file, + const Options& options); + +// Indicates whether to treat this field as implicitly weak. +bool IsImplicitWeakField(const FieldDescriptor* field, const Options& options, + MessageSCCAnalyzer* scc_analyzer); + +inline bool HasSimpleBaseClass(const Descriptor* desc, const Options& options) { + if (!HasDescriptorMethods(desc->file(), options)) return false; + if (desc->extension_range_count() != 0) return false; + if (desc->field_count() == 0) return true; + // TODO(jorg): Support additional common message types with only one + // or two fields + return false; +} + +inline bool HasSimpleBaseClasses(const FileDescriptor* file, + const Options& options) { + bool v = false; + ForEachMessage(file, [&v, &options](const Descriptor* desc) { + v |= HasSimpleBaseClass(desc, options); + }); + return v; +} + +inline std::string SimpleBaseClass(const Descriptor* desc, + const Options& options) { + if (!HasDescriptorMethods(desc->file(), options)) return ""; + if (desc->extension_range_count() != 0) return ""; + if (desc->field_count() == 0) { + return "ZeroFieldsBase"; + } + // TODO(jorg): Support additional common message types with only one + // or two fields + return ""; +} + +// Formatter is a functor class which acts as a closure around printer and +// the variable map. It's much like printer->Print except it supports both named +// variables that are substituted using a key value map and direct arguments. In +// the format string $1$, $2$, etc... are substituted for the first, second, ... +// direct argument respectively in the format call, it accepts both strings and +// integers. The implementation verifies all arguments are used and are "first" +// used in order of appearance in the argument list. For example, +// +// Format("return array[$1$];", 3) -> "return array[3];" +// Format("array[$2$] = $1$;", "Bla", 3) -> FATAL error (wrong order) +// Format("array[$1$] = $2$;", 3, "Bla") -> "array[3] = Bla;" +// +// The arguments can be used more than once like +// +// Format("array[$1$] = $2$; // Index = $1$", 3, "Bla") -> +// "array[3] = Bla; // Index = 3" +// +// If you use more arguments use the following style to help the reader, +// +// Format("int $1$() {\n" +// " array[$2$] = $3$;\n" +// " return $4$;" +// "}\n", +// funname, // 1 +// idx, // 2 +// varname, // 3 +// retval); // 4 +// +// but consider using named variables. Named variables like $foo$, with some +// identifier foo, are looked up in the map. One additional feature is that +// spaces are accepted between the '$' delimiters, $ foo$ will +// substiture to " bar" if foo stands for "bar", but in case it's empty +// will substitute to "". Hence, for example, +// +// Format(vars, "$dllexport $void fun();") -> "void fun();" +// "__declspec(export) void fun();" +// +// which is convenient to prevent double, leading or trailing spaces. +class PROTOC_EXPORT Formatter { + public: + explicit Formatter(io::Printer* printer) : printer_(printer) {} + Formatter(io::Printer* printer, + const std::map<std::string, std::string>& vars) + : printer_(printer), vars_(vars) {} + + template <typename T> + void Set(const std::string& key, const T& value) { + vars_[key] = ToString(value); + } + + void AddMap(const std::map<std::string, std::string>& vars) { + for (const auto& keyval : vars) vars_[keyval.first] = keyval.second; + } + + template <typename... Args> + void operator()(const char* format, const Args&... args) const { + printer_->FormatInternal({ToString(args)...}, vars_, format); + } + + void Indent() const { printer_->Indent(); } + void Outdent() const { printer_->Outdent(); } + io::Printer* printer() const { return printer_; } + + class PROTOC_EXPORT ScopedIndenter { + public: + explicit ScopedIndenter(Formatter* format) : format_(format) { + format_->Indent(); + } + ~ScopedIndenter() { format_->Outdent(); } + + private: + Formatter* format_; + }; + + PROTOBUF_NODISCARD ScopedIndenter ScopedIndent() { + return ScopedIndenter(this); + } + template <typename... Args> + PROTOBUF_NODISCARD ScopedIndenter ScopedIndent(const char* format, + const Args&&... args) { + (*this)(format, static_cast<Args&&>(args)...); + return ScopedIndenter(this); + } + + class PROTOC_EXPORT SaveState { + public: + explicit SaveState(Formatter* format) + : format_(format), vars_(format->vars_) {} + ~SaveState() { format_->vars_.swap(vars_); } + + private: + Formatter* format_; + std::map<std::string, std::string> vars_; + }; + + private: + io::Printer* printer_; + std::map<std::string, std::string> vars_; + + // Convenience overloads to accept different types as arguments. + static std::string ToString(const std::string& s) { return s; } + template <typename I, typename = typename std::enable_if< + std::is_integral<I>::value>::type> + static std::string ToString(I x) { + return StrCat(x); + } + static std::string ToString(strings::Hex x) { return StrCat(x); } + static std::string ToString(const FieldDescriptor* d) { return Payload(d); } + static std::string ToString(const Descriptor* d) { return Payload(d); } + static std::string ToString(const EnumDescriptor* d) { return Payload(d); } + static std::string ToString(const EnumValueDescriptor* d) { + return Payload(d); + } + static std::string ToString(const OneofDescriptor* d) { return Payload(d); } + + template <typename Descriptor> + static std::string Payload(const Descriptor* descriptor) { + std::vector<int> path; + descriptor->GetLocationPath(&path); + GeneratedCodeInfo::Annotation annotation; + for (int index : path) { + annotation.add_path(index); + } + annotation.set_source_file(descriptor->file()->name()); + return annotation.SerializeAsString(); + } +}; + +template <class T> +void PrintFieldComment(const Formatter& format, const T* field) { + // Print the field's (or oneof's) proto-syntax definition as a comment. + // We don't want to print group bodies so we cut off after the first + // line. + DebugStringOptions options; + options.elide_group_body = true; + options.elide_oneof_body = true; + std::string def = field->DebugStringWithOptions(options); + format("// $1$\n", def.substr(0, def.find_first_of('\n'))); +} + +class PROTOC_EXPORT NamespaceOpener { + public: + explicit NamespaceOpener(const Formatter& format) + : printer_(format.printer()) {} + NamespaceOpener(const std::string& name, const Formatter& format) + : NamespaceOpener(format) { + ChangeTo(name); + } + ~NamespaceOpener() { ChangeTo(""); } + + void ChangeTo(const std::string& name) { + std::vector<std::string> new_stack_ = + Split(name, "::", true); + size_t len = std::min(name_stack_.size(), new_stack_.size()); + size_t common_idx = 0; + while (common_idx < len) { + if (name_stack_[common_idx] != new_stack_[common_idx]) break; + common_idx++; + } + for (auto it = name_stack_.crbegin(); + it != name_stack_.crend() - common_idx; ++it) { + if (*it == "PROTOBUF_NAMESPACE_ID") { + printer_->Print("PROTOBUF_NAMESPACE_CLOSE\n"); + } else { + printer_->Print("} // namespace $ns$\n", "ns", *it); + } + } + name_stack_.swap(new_stack_); + for (size_t i = common_idx; i < name_stack_.size(); ++i) { + if (name_stack_[i] == "PROTOBUF_NAMESPACE_ID") { + printer_->Print("PROTOBUF_NAMESPACE_OPEN\n"); + } else { + printer_->Print("namespace $ns$ {\n", "ns", name_stack_[i]); + } + } + } + + private: + io::Printer* printer_; + std::vector<std::string> name_stack_; +}; + +enum class Utf8CheckMode { + kStrict = 0, // Parsing will fail if non UTF-8 data is in string fields. + kVerify = 1, // Only log an error but parsing will succeed. + kNone = 2, // No UTF-8 check. +}; + +Utf8CheckMode GetUtf8CheckMode(const FieldDescriptor* field, + const Options& options); + +void GenerateUtf8CheckCodeForString(const FieldDescriptor* field, + const Options& options, bool for_parse, + const char* parameters, + const Formatter& format); + +void GenerateUtf8CheckCodeForCord(const FieldDescriptor* field, + const Options& options, bool for_parse, + const char* parameters, + const Formatter& format); + +template <typename T> +struct FieldRangeImpl { + struct Iterator { + using iterator_category = std::forward_iterator_tag; + using value_type = const FieldDescriptor*; + using difference_type = int; + + value_type operator*() { return descriptor->field(idx); } + + friend bool operator==(const Iterator& a, const Iterator& b) { + GOOGLE_DCHECK(a.descriptor == b.descriptor); + return a.idx == b.idx; + } + friend bool operator!=(const Iterator& a, const Iterator& b) { + return !(a == b); + } + + Iterator& operator++() { + idx++; + return *this; + } + + int idx; + const T* descriptor; + }; + + Iterator begin() const { return {0, descriptor}; } + Iterator end() const { return {descriptor->field_count(), descriptor}; } + + const T* descriptor; +}; + +template <typename T> +FieldRangeImpl<T> FieldRange(const T* desc) { + return {desc}; +} + +struct OneOfRangeImpl { + struct Iterator { + using iterator_category = std::forward_iterator_tag; + using value_type = const OneofDescriptor*; + using difference_type = int; + + value_type operator*() { return descriptor->oneof_decl(idx); } + + friend bool operator==(const Iterator& a, const Iterator& b) { + GOOGLE_DCHECK(a.descriptor == b.descriptor); + return a.idx == b.idx; + } + friend bool operator!=(const Iterator& a, const Iterator& b) { + return !(a == b); + } + + Iterator& operator++() { + idx++; + return *this; + } + + int idx; + const Descriptor* descriptor; + }; + + Iterator begin() const { return {0, descriptor}; } + Iterator end() const { + return {descriptor->real_oneof_decl_count(), descriptor}; + } + + const Descriptor* descriptor; +}; + +inline OneOfRangeImpl OneOfRange(const Descriptor* desc) { return {desc}; } + +PROTOC_EXPORT std::string StripProto(const std::string& filename); + +bool EnableMessageOwnedArena(const Descriptor* desc); + +bool ShouldVerify(const Descriptor* descriptor, const Options& options, + MessageSCCAnalyzer* scc_analyzer); +bool ShouldVerify(const FileDescriptor* file, const Options& options, + MessageSCCAnalyzer* scc_analyzer); +} // namespace cpp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#include <port_undef.inc> + +#endif // GOOGLE_PROTOBUF_COMPILER_CPP_HELPERS_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_map_field.cc b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_map_field.cc new file mode 100644 index 00000000..3626a360 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_map_field.cc @@ -0,0 +1,334 @@ +// 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 <compiler/cpp/cpp_map_field.h> + +#include <compiler/cpp/cpp_helpers.h> +#include <io/printer.h> +#include <wire_format.h> +#include <stubs/strutil.h> + + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { + +bool IsProto3Field(const FieldDescriptor* field_descriptor) { + const FileDescriptor* file_descriptor = field_descriptor->file(); + return file_descriptor->syntax() == FileDescriptor::SYNTAX_PROTO3; +} + +void SetMessageVariables(const FieldDescriptor* descriptor, + std::map<std::string, std::string>* variables, + const Options& options) { + SetCommonFieldVariables(descriptor, variables, options); + (*variables)["type"] = ClassName(descriptor->message_type(), false); + (*variables)["full_name"] = descriptor->full_name(); + + const FieldDescriptor* key = + descriptor->message_type()->FindFieldByName("key"); + const FieldDescriptor* val = + descriptor->message_type()->FindFieldByName("value"); + (*variables)["key_cpp"] = PrimitiveTypeName(options, key->cpp_type()); + switch (val->cpp_type()) { + case FieldDescriptor::CPPTYPE_MESSAGE: + (*variables)["val_cpp"] = FieldMessageTypeName(val, options); + break; + case FieldDescriptor::CPPTYPE_ENUM: + (*variables)["val_cpp"] = ClassName(val->enum_type(), true); + break; + default: + (*variables)["val_cpp"] = PrimitiveTypeName(options, val->cpp_type()); + } + (*variables)["key_wire_type"] = + "TYPE_" + ToUpper(DeclaredTypeMethodName(key->type())); + (*variables)["val_wire_type"] = + "TYPE_" + ToUpper(DeclaredTypeMethodName(val->type())); + (*variables)["map_classname"] = ClassName(descriptor->message_type(), false); + (*variables)["number"] = StrCat(descriptor->number()); + (*variables)["tag"] = StrCat(internal::WireFormat::MakeTag(descriptor)); + + if (HasDescriptorMethods(descriptor->file(), options)) { + (*variables)["lite"] = ""; + } else { + (*variables)["lite"] = "Lite"; + } +} + +MapFieldGenerator::MapFieldGenerator(const FieldDescriptor* descriptor, + const Options& options, + MessageSCCAnalyzer* scc_analyzer) + : FieldGenerator(descriptor, options), + has_required_fields_( + scc_analyzer->HasRequiredFields(descriptor->message_type())) { + SetMessageVariables(descriptor, &variables_, options); +} + +MapFieldGenerator::~MapFieldGenerator() {} + +void MapFieldGenerator::GeneratePrivateMembers(io::Printer* printer) const { + Formatter format(printer, variables_); + format( + "::$proto_ns$::internal::MapField$lite$<\n" + " $map_classname$,\n" + " $key_cpp$, $val_cpp$,\n" + " ::$proto_ns$::internal::WireFormatLite::$key_wire_type$,\n" + " ::$proto_ns$::internal::WireFormatLite::$val_wire_type$> " + "$name$_;\n"); +} + +void MapFieldGenerator::GenerateAccessorDeclarations( + io::Printer* printer) const { + Formatter format(printer, variables_); + format( + "private:\n" + "const ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >&\n" + " ${1$_internal_$name$$}$() const;\n" + "::$proto_ns$::Map< $key_cpp$, $val_cpp$ >*\n" + " ${1$_internal_mutable_$name$$}$();\n" + "public:\n" + "$deprecated_attr$const ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >&\n" + " ${1$$name$$}$() const;\n" + "$deprecated_attr$::$proto_ns$::Map< $key_cpp$, $val_cpp$ >*\n" + " ${1$mutable_$name$$}$();\n", + descriptor_); +} + +void MapFieldGenerator::GenerateInlineAccessorDefinitions( + io::Printer* printer) const { + Formatter format(printer, variables_); + format( + "inline const ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >&\n" + "$classname$::_internal_$name$() const {\n" + " return $name$_.GetMap();\n" + "}\n" + "inline const ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >&\n" + "$classname$::$name$() const {\n" + "$annotate_get$" + " // @@protoc_insertion_point(field_map:$full_name$)\n" + " return _internal_$name$();\n" + "}\n" + "inline ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >*\n" + "$classname$::_internal_mutable_$name$() {\n" + " return $name$_.MutableMap();\n" + "}\n" + "inline ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >*\n" + "$classname$::mutable_$name$() {\n" + "$annotate_mutable$" + " // @@protoc_insertion_point(field_mutable_map:$full_name$)\n" + " return _internal_mutable_$name$();\n" + "}\n"); +} + +void MapFieldGenerator::GenerateClearingCode(io::Printer* printer) const { + Formatter format(printer, variables_); + format("$name$_.Clear();\n"); +} + +void MapFieldGenerator::GenerateMergingCode(io::Printer* printer) const { + Formatter format(printer, variables_); + format("$name$_.MergeFrom(from.$name$_);\n"); +} + +void MapFieldGenerator::GenerateSwappingCode(io::Printer* printer) const { + Formatter format(printer, variables_); + format("$name$_.InternalSwap(&other->$name$_);\n"); +} + +void MapFieldGenerator::GenerateCopyConstructorCode( + io::Printer* printer) const { + GenerateConstructorCode(printer); + GenerateMergingCode(printer); +} + +static void GenerateSerializationLoop(const Formatter& format, bool string_key, + bool string_value, + bool is_deterministic) { + std::string ptr; + if (is_deterministic) { + format("for (size_type i = 0; i < n; i++) {\n"); + ptr = string_key ? "items[static_cast<ptrdiff_t>(i)]" + : "items[static_cast<ptrdiff_t>(i)].second"; + } else { + format( + "for (::$proto_ns$::Map< $key_cpp$, $val_cpp$ >::const_iterator\n" + " it = this->_internal_$name$().begin();\n" + " it != this->_internal_$name$().end(); ++it) {\n"); + ptr = "it"; + } + format.Indent(); + + format( + "target = $map_classname$::Funcs::InternalSerialize($number$, " + "$1$->first, $1$->second, target, stream);\n", + ptr); + + if (string_key || string_value) { + // ptr is either an actual pointer or an iterator, either way we can + // create a pointer by taking the address after de-referencing it. + format("Utf8Check::Check(&(*$1$));\n", ptr); + } + + format.Outdent(); + format("}\n"); +} + +void MapFieldGenerator::GenerateSerializeWithCachedSizesToArray( + io::Printer* printer) const { + Formatter format(printer, variables_); + format("if (!this->_internal_$name$().empty()) {\n"); + format.Indent(); + const FieldDescriptor* key_field = + descriptor_->message_type()->FindFieldByName("key"); + const FieldDescriptor* value_field = + descriptor_->message_type()->FindFieldByName("value"); + const bool string_key = key_field->type() == FieldDescriptor::TYPE_STRING; + const bool string_value = value_field->type() == FieldDescriptor::TYPE_STRING; + + format( + "typedef ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >::const_pointer\n" + " ConstPtr;\n"); + if (string_key) { + format( + "typedef ConstPtr SortItem;\n" + "typedef ::$proto_ns$::internal::" + "CompareByDerefFirst<SortItem> Less;\n"); + } else { + format( + "typedef ::$proto_ns$::internal::SortItem< $key_cpp$, ConstPtr > " + "SortItem;\n" + "typedef ::$proto_ns$::internal::CompareByFirstField<SortItem> " + "Less;\n"); + } + bool utf8_check = string_key || string_value; + if (utf8_check) { + format( + "struct Utf8Check {\n" + " static void Check(ConstPtr p) {\n" + // p may be unused when GetUtf8CheckMode evaluates to kNone, + // thus disabling the validation. + " (void)p;\n"); + format.Indent(); + format.Indent(); + if (string_key) { + GenerateUtf8CheckCodeForString( + key_field, options_, false, + "p->first.data(), static_cast<int>(p->first.length()),\n", format); + } + if (string_value) { + GenerateUtf8CheckCodeForString( + value_field, options_, false, + "p->second.data(), static_cast<int>(p->second.length()),\n", format); + } + format.Outdent(); + format.Outdent(); + format( + " }\n" + "};\n"); + } + + format( + "\n" + "if (stream->IsSerializationDeterministic() &&\n" + " this->_internal_$name$().size() > 1) {\n" + " ::std::unique_ptr<SortItem[]> items(\n" + " new SortItem[this->_internal_$name$().size()]);\n" + " typedef ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >::size_type " + "size_type;\n" + " size_type n = 0;\n" + " for (::$proto_ns$::Map< $key_cpp$, $val_cpp$ >::const_iterator\n" + " it = this->_internal_$name$().begin();\n" + " it != this->_internal_$name$().end(); ++it, ++n) {\n" + " items[static_cast<ptrdiff_t>(n)] = SortItem(&*it);\n" + " }\n" + " ::std::sort(&items[0], &items[static_cast<ptrdiff_t>(n)], Less());\n"); + format.Indent(); + GenerateSerializationLoop(format, string_key, string_value, true); + format.Outdent(); + format("} else {\n"); + format.Indent(); + GenerateSerializationLoop(format, string_key, string_value, false); + format.Outdent(); + format("}\n"); + format.Outdent(); + format("}\n"); +} + +void MapFieldGenerator::GenerateByteSize(io::Printer* printer) const { + Formatter format(printer, variables_); + format( + "total_size += $tag_size$ *\n" + " " + "::$proto_ns$::internal::FromIntSize(this->_internal_$name$_size());\n" + "for (::$proto_ns$::Map< $key_cpp$, $val_cpp$ >::const_iterator\n" + " it = this->_internal_$name$().begin();\n" + " it != this->_internal_$name$().end(); ++it) {\n" + " total_size += $map_classname$::Funcs::ByteSizeLong(it->first, " + "it->second);\n" + "}\n"); +} + +void MapFieldGenerator::GenerateIsInitialized(io::Printer* printer) const { + if (!has_required_fields_) return; + + Formatter format(printer, variables_); + format( + "if (!::$proto_ns$::internal::AllAreInitialized($name$_)) return " + "false;\n"); +} + +void MapFieldGenerator::GenerateConstinitInitializer( + io::Printer* printer) const { + Formatter format(printer, variables_); + if (HasDescriptorMethods(descriptor_->file(), options_)) { + format("$name$_(::$proto_ns$::internal::ConstantInitialized{})"); + } else { + format("$name$_()"); + } +} + +bool MapFieldGenerator::GenerateArenaDestructorCode( + io::Printer* printer) const { + Formatter format(printer, variables_); + if (HasDescriptorMethods(descriptor_->file(), options_)) { + // _this is the object being destructed (we are inside a static method + // here). + format("_this->$name$_. ~MapField();\n"); + return true; + } else { + return false; + } +} + +} // namespace cpp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_map_field.h b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_map_field.h new file mode 100644 index 00000000..8287e536 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_map_field.h @@ -0,0 +1,78 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_MAP_FIELD_H__ +#define GOOGLE_PROTOBUF_COMPILER_CPP_MAP_FIELD_H__ + +#include <map> +#include <string> + +#include <compiler/cpp/cpp_helpers.h> +#include <compiler/cpp/cpp_message_field.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { + +class MapFieldGenerator : public FieldGenerator { + public: + MapFieldGenerator(const FieldDescriptor* descriptor, const Options& options, + MessageSCCAnalyzer* scc_analyzer); + ~MapFieldGenerator() override; + + // implements FieldGenerator --------------------------------------- + void GeneratePrivateMembers(io::Printer* printer) const override; + void GenerateAccessorDeclarations(io::Printer* printer) const override; + void GenerateInlineAccessorDefinitions(io::Printer* printer) const override; + void GenerateClearingCode(io::Printer* printer) const override; + void GenerateMergingCode(io::Printer* printer) const override; + void GenerateSwappingCode(io::Printer* printer) const override; + void GenerateConstructorCode(io::Printer* printer) const override {} + void GenerateCopyConstructorCode(io::Printer* printer) const override; + void GenerateSerializeWithCachedSizesToArray( + io::Printer* printer) const override; + void GenerateByteSize(io::Printer* printer) const override; + void GenerateIsInitialized(io::Printer* printer) const override; + void GenerateConstinitInitializer(io::Printer* printer) const override; + bool GenerateArenaDestructorCode(io::Printer* printer) const override; + + private: + const bool has_required_fields_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapFieldGenerator); +}; + +} // namespace cpp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_CPP_MAP_FIELD_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_message.cc b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_message.cc new file mode 100644 index 00000000..b541017f --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_message.cc @@ -0,0 +1,4584 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <compiler/cpp/cpp_message.h> + +#include <algorithm> +#include <cstdint> +#include <functional> +#include <map> +#include <memory> +#include <unordered_map> +#include <utility> +#include <vector> + +#include <stubs/common.h> +#include <compiler/cpp/cpp_enum.h> +#include <compiler/cpp/cpp_extension.h> +#include <compiler/cpp/cpp_field.h> +#include <compiler/cpp/cpp_helpers.h> +#include <compiler/cpp/cpp_padding_optimizer.h> +#include <compiler/cpp/cpp_parse_function_generator.h> +#include <descriptor.pb.h> +#include <io/coded_stream.h> +#include <io/printer.h> +#include <descriptor.h> +#include <generated_message_table_driven.h> +#include <generated_message_util.h> +#include <map_entry_lite.h> +#include <wire_format.h> +#include <stubs/strutil.h> +#include <stubs/substitute.h> +#include <stubs/hash.h> + + +// Must be included last. +#include <port_def.inc> + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { + +using internal::WireFormat; +using internal::WireFormatLite; + +namespace { + +static constexpr int kNoHasbit = -1; + +// Create an expression that evaluates to +// "for all i, (_has_bits_[i] & masks[i]) == masks[i]" +// masks is allowed to be shorter than _has_bits_, but at least one element of +// masks must be non-zero. +std::string ConditionalToCheckBitmasks( + const std::vector<uint32_t>& masks, bool return_success = true, + StringPiece has_bits_var = "_has_bits_") { + std::vector<std::string> parts; + for (int i = 0; i < masks.size(); i++) { + if (masks[i] == 0) continue; + std::string m = StrCat("0x", strings::Hex(masks[i], strings::ZERO_PAD_8)); + // Each xor evaluates to 0 if the expected bits are present. + parts.push_back( + StrCat("((", has_bits_var, "[", i, "] & ", m, ") ^ ", m, ")")); + } + GOOGLE_CHECK(!parts.empty()); + // If we have multiple parts, each expected to be 0, then bitwise-or them. + std::string result = + parts.size() == 1 + ? parts[0] + : StrCat("(", Join(parts, "\n | "), ")"); + return result + (return_success ? " == 0" : " != 0"); +} + +void PrintPresenceCheck(const Formatter& format, const FieldDescriptor* field, + const std::vector<int>& has_bit_indices, + io::Printer* printer, int* cached_has_word_index) { + if (!field->options().weak()) { + int has_bit_index = has_bit_indices[field->index()]; + if (*cached_has_word_index != (has_bit_index / 32)) { + *cached_has_word_index = (has_bit_index / 32); + format("cached_has_bits = _has_bits_[$1$];\n", *cached_has_word_index); + } + const std::string mask = + StrCat(strings::Hex(1u << (has_bit_index % 32), strings::ZERO_PAD_8)); + format("if (cached_has_bits & 0x$1$u) {\n", mask); + } else { + format("if (has_$1$()) {\n", FieldName(field)); + } + format.Indent(); +} + +struct FieldOrderingByNumber { + inline bool operator()(const FieldDescriptor* a, + const FieldDescriptor* b) const { + return a->number() < b->number(); + } +}; + +// Sort the fields of the given Descriptor by number into a new[]'d array +// and return it. +std::vector<const FieldDescriptor*> SortFieldsByNumber( + const Descriptor* descriptor) { + std::vector<const FieldDescriptor*> fields(descriptor->field_count()); + for (int i = 0; i < descriptor->field_count(); i++) { + fields[i] = descriptor->field(i); + } + std::sort(fields.begin(), fields.end(), FieldOrderingByNumber()); + return fields; +} + +// Functor for sorting extension ranges by their "start" field number. +struct ExtensionRangeSorter { + bool operator()(const Descriptor::ExtensionRange* left, + const Descriptor::ExtensionRange* right) const { + return left->start < right->start; + } +}; + +bool IsPOD(const FieldDescriptor* field) { + if (field->is_repeated() || field->is_extension()) return false; + switch (field->cpp_type()) { + case FieldDescriptor::CPPTYPE_ENUM: + case FieldDescriptor::CPPTYPE_INT32: + case FieldDescriptor::CPPTYPE_INT64: + case FieldDescriptor::CPPTYPE_UINT32: + case FieldDescriptor::CPPTYPE_UINT64: + case FieldDescriptor::CPPTYPE_FLOAT: + case FieldDescriptor::CPPTYPE_DOUBLE: + case FieldDescriptor::CPPTYPE_BOOL: + return true; + case FieldDescriptor::CPPTYPE_STRING: + return false; + default: + return false; + } +} + +// Helper for the code that emits the SharedCtor() and InternalSwap() methods. +// Anything that is a POD or a "normal" message (represented by a pointer) can +// be manipulated as raw bytes. +bool CanBeManipulatedAsRawBytes(const FieldDescriptor* field, + const Options& options, + MessageSCCAnalyzer* scc_analyzer) { + bool ret = CanInitializeByZeroing(field); + + // Non-repeated, non-lazy message fields are simply raw pointers, so we can + // swap them or use memset to initialize these in SharedCtor. We cannot use + // this in Clear, as we need to potentially delete the existing value. + ret = + ret || (!field->is_repeated() && !IsLazy(field, options, scc_analyzer) && + field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE); + return ret; +} + +bool StrContains(const std::string& haystack, const std::string& needle) { + return haystack.find(needle) != std::string::npos; +} + +// Finds runs of fields for which `predicate` is true. +// RunMap maps from fields that start each run to the number of fields in that +// run. This is optimized for the common case that there are very few runs in +// a message and that most of the eligible fields appear together. +using RunMap = std::unordered_map<const FieldDescriptor*, size_t>; +RunMap FindRuns(const std::vector<const FieldDescriptor*>& fields, + const std::function<bool(const FieldDescriptor*)>& predicate) { + RunMap runs; + const FieldDescriptor* last_start = nullptr; + + for (auto field : fields) { + if (predicate(field)) { + if (last_start == nullptr) { + last_start = field; + } + + runs[last_start]++; + } else { + last_start = nullptr; + } + } + return runs; +} + +// Emits an if-statement with a condition that evaluates to true if |field| is +// considered non-default (will be sent over the wire), for message types +// without true field presence. Should only be called if +// !HasHasbit(field). +bool EmitFieldNonDefaultCondition(io::Printer* printer, + const std::string& prefix, + const FieldDescriptor* field) { + GOOGLE_CHECK(!HasHasbit(field)); + Formatter format(printer); + format.Set("prefix", prefix); + format.Set("name", FieldName(field)); + // Merge and serialize semantics: primitive fields are merged/serialized only + // if non-zero (numeric) or non-empty (string). + if (!field->is_repeated() && !field->containing_oneof()) { + if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) { + format("if (!$prefix$_internal_$name$().empty()) {\n"); + } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + // Message fields still have has_$name$() methods. + format("if ($prefix$_internal_has_$name$()) {\n"); + } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_FLOAT) { + format( + "static_assert(sizeof(uint32_t) == sizeof(float), \"Code assumes " + "uint32_t and float are the same size.\");\n" + "float tmp_$name$ = $prefix$_internal_$name$();\n" + "uint32_t raw_$name$;\n" + "memcpy(&raw_$name$, &tmp_$name$, sizeof(tmp_$name$));\n" + "if (raw_$name$ != 0) {\n"); + } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_DOUBLE) { + format( + "static_assert(sizeof(uint64_t) == sizeof(double), \"Code assumes " + "uint64_t and double are the same size.\");\n" + "double tmp_$name$ = $prefix$_internal_$name$();\n" + "uint64_t raw_$name$;\n" + "memcpy(&raw_$name$, &tmp_$name$, sizeof(tmp_$name$));\n" + "if (raw_$name$ != 0) {\n"); + } else { + format("if ($prefix$_internal_$name$() != 0) {\n"); + } + format.Indent(); + return true; + } else if (field->real_containing_oneof()) { + format("if (_internal_has_$name$()) {\n"); + format.Indent(); + return true; + } + return false; +} + +// Does the given field have a has_$name$() method? +bool HasHasMethod(const FieldDescriptor* field) { + if (!IsProto3(field->file())) { + // In proto1/proto2, every field has a has_$name$() method. + return true; + } + // For message types without true field presence, only fields with a message + // type or inside an one-of have a has_$name$() method. + return field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE || + field->has_optional_keyword() || field->real_containing_oneof(); +} + +// Collects map entry message type information. +void CollectMapInfo(const Options& options, const Descriptor* descriptor, + std::map<std::string, std::string>* variables) { + GOOGLE_CHECK(IsMapEntryMessage(descriptor)); + std::map<std::string, std::string>& vars = *variables; + const FieldDescriptor* key = descriptor->FindFieldByName("key"); + const FieldDescriptor* val = descriptor->FindFieldByName("value"); + vars["key_cpp"] = PrimitiveTypeName(options, key->cpp_type()); + switch (val->cpp_type()) { + case FieldDescriptor::CPPTYPE_MESSAGE: + vars["val_cpp"] = FieldMessageTypeName(val, options); + break; + case FieldDescriptor::CPPTYPE_ENUM: + vars["val_cpp"] = ClassName(val->enum_type(), true); + break; + default: + vars["val_cpp"] = PrimitiveTypeName(options, val->cpp_type()); + } + vars["key_wire_type"] = + "TYPE_" + ToUpper(DeclaredTypeMethodName(key->type())); + vars["val_wire_type"] = + "TYPE_" + ToUpper(DeclaredTypeMethodName(val->type())); +} + +// Does the given field have a private (internal helper only) has_$name$() +// method? +bool HasPrivateHasMethod(const FieldDescriptor* field) { + // Only for oneofs in message types with no field presence. has_$name$(), + // based on the oneof case, is still useful internally for generated code. + return IsProto3(field->file()) && field->real_containing_oneof(); +} + +// TODO(ckennelly): Cull these exclusions if/when these protos do not have +// their methods overridden by subclasses. + +bool ShouldMarkClassAsFinal(const Descriptor* descriptor, + const Options& options) { + return true; +} + + +// Returns true to make the message serialize in order, decided by the following +// factors in the order of precedence. +// --options().message_set_wire_format() == true +// --the message is in the allowlist (true) +// --GOOGLE_PROTOBUF_SHUFFLE_SERIALIZE is defined (false) +// --a ranage of message names that are allowed to stay in order (true) +bool ShouldSerializeInOrder(const Descriptor* descriptor, + const Options& options) { + return true; +} + +bool TableDrivenParsingEnabled(const Descriptor* descriptor, + const Options& options, + MessageSCCAnalyzer* scc_analyzer) { + if (!options.table_driven_parsing) { + return false; + } + + // Consider table-driven parsing. We only do this if: + // - We have has_bits for fields. This avoids a check on every field we set + // when are present (the common case). + bool has_hasbit = false; + for (int i = 0; i < descriptor->field_count(); i++) { + if (HasHasbit(descriptor->field(i))) { + has_hasbit = true; + break; + } + } + + if (!has_hasbit) return false; + + const double table_sparseness = 0.5; + int max_field_number = 0; + for (auto field : FieldRange(descriptor)) { + if (max_field_number < field->number()) { + max_field_number = field->number(); + } + + // - There are no weak fields. + if (IsWeak(field, options)) { + return false; + } + + // - There are no lazy fields (they require the non-lite library). + if (IsLazy(field, options, scc_analyzer)) { + return false; + } + } + + // - There range of field numbers is "small" + if (max_field_number >= (2 << 14)) { + return false; + } + + // - Field numbers are relatively dense within the actual number of fields. + // We check for strictly greater than in the case where there are no fields + // (only extensions) so max_field_number == descriptor->field_count() == 0. + if (max_field_number * table_sparseness > descriptor->field_count()) { + return false; + } + + // - This is not a MapEntryMessage. + if (IsMapEntryMessage(descriptor)) { + return false; + } + + return true; +} + +bool IsCrossFileMapField(const FieldDescriptor* field) { + if (!field->is_map()) { + return false; + } + + const Descriptor* d = field->message_type(); + const FieldDescriptor* value = d->FindFieldByNumber(2); + + return IsCrossFileMessage(value); +} + +bool IsCrossFileMaybeMap(const FieldDescriptor* field) { + if (IsCrossFileMapField(field)) { + return true; + } + + return IsCrossFileMessage(field); +} + +bool IsRequired(const std::vector<const FieldDescriptor*>& v) { + return v.front()->is_required(); +} + +bool HasSingularString(const Descriptor* desc, const Options& options) { + for (const auto* field : FieldRange(desc)) { + if (IsString(field, options) && !IsStringInlined(field, options) && + !field->is_repeated() && !field->real_containing_oneof()) { + return true; + } + } + return false; +} + +// Collects neighboring fields based on a given criteria (equivalent predicate). +template <typename Predicate> +std::vector<std::vector<const FieldDescriptor*>> CollectFields( + const std::vector<const FieldDescriptor*>& fields, + const Predicate& equivalent) { + std::vector<std::vector<const FieldDescriptor*>> chunks; + for (auto field : fields) { + if (chunks.empty() || !equivalent(chunks.back().back(), field)) { + chunks.emplace_back(); + } + chunks.back().push_back(field); + } + return chunks; +} + +// Returns a bit mask based on has_bit index of "fields" that are typically on +// the same chunk. It is used in a group presence check where _has_bits_ is +// masked to tell if any thing in "fields" is present. +uint32_t GenChunkMask(const std::vector<const FieldDescriptor*>& fields, + const std::vector<int>& has_bit_indices) { + GOOGLE_CHECK(!fields.empty()); + int first_index_offset = has_bit_indices[fields.front()->index()] / 32; + uint32_t chunk_mask = 0; + for (auto field : fields) { + // "index" defines where in the _has_bits_ the field appears. + int index = has_bit_indices[field->index()]; + GOOGLE_CHECK_EQ(first_index_offset, index / 32); + chunk_mask |= static_cast<uint32_t>(1) << (index % 32); + } + GOOGLE_CHECK_NE(0, chunk_mask); + return chunk_mask; +} + +// Return the number of bits set in n, a non-negative integer. +static int popcnt(uint32_t n) { + int result = 0; + while (n != 0) { + result += (n & 1); + n = n / 2; + } + return result; +} + +// For a run of cold chunks, opens and closes an external if statement that +// checks multiple has_bits words to skip bulk of cold fields. +class ColdChunkSkipper { + public: + ColdChunkSkipper( + const Options& options, + const std::vector<std::vector<const FieldDescriptor*>>& chunks, + const std::vector<int>& has_bit_indices, const double cold_threshold) + : chunks_(chunks), + has_bit_indices_(has_bit_indices), + access_info_map_(options.access_info_map), + cold_threshold_(cold_threshold) { + SetCommonVars(options, &variables_); + } + + // May open an external if check for a batch of cold fields. "from" is the + // prefix to _has_bits_ to allow MergeFrom to use "from._has_bits_". + // Otherwise, it should be "". + void OnStartChunk(int chunk, int cached_has_word_index, + const std::string& from, io::Printer* printer); + bool OnEndChunk(int chunk, io::Printer* printer); + + private: + bool IsColdChunk(int chunk); + + int HasbitWord(int chunk, int offset) { + return has_bit_indices_[chunks_[chunk][offset]->index()] / 32; + } + + const std::vector<std::vector<const FieldDescriptor*>>& chunks_; + const std::vector<int>& has_bit_indices_; + const AccessInfoMap* access_info_map_; + const double cold_threshold_; + std::map<std::string, std::string> variables_; + int limit_chunk_ = -1; +}; + +// Tuning parameters for ColdChunkSkipper. +const double kColdRatio = 0.005; + +bool ColdChunkSkipper::IsColdChunk(int chunk) { + // Mark this variable as used until it is actually used + (void)cold_threshold_; + return false; +} + + +void ColdChunkSkipper::OnStartChunk(int chunk, int cached_has_word_index, + const std::string& from, + io::Printer* printer) { + Formatter format(printer, variables_); + if (!access_info_map_) { + return; + } else if (chunk < limit_chunk_) { + // We are already inside a run of cold chunks. + return; + } else if (!IsColdChunk(chunk)) { + // We can't start a run of cold chunks. + return; + } + + // Find the end of consecutive cold chunks. + limit_chunk_ = chunk; + while (limit_chunk_ < chunks_.size() && IsColdChunk(limit_chunk_)) { + limit_chunk_++; + } + + if (limit_chunk_ <= chunk + 1) { + // Require at least two chunks to emit external has_bit checks. + limit_chunk_ = -1; + return; + } + + // Emit has_bit check for each has_bit_dword index. + format("if (PROTOBUF_PREDICT_FALSE("); + int first_word = HasbitWord(chunk, 0); + while (chunk < limit_chunk_) { + uint32_t mask = 0; + int this_word = HasbitWord(chunk, 0); + // Generate mask for chunks on the same word. + for (; chunk < limit_chunk_ && HasbitWord(chunk, 0) == this_word; chunk++) { + for (auto field : chunks_[chunk]) { + int hasbit_index = has_bit_indices_[field->index()]; + // Fields on a chunk must be in the same word. + GOOGLE_CHECK_EQ(this_word, hasbit_index / 32); + mask |= 1 << (hasbit_index % 32); + } + } + + if (this_word != first_word) { + format(" ||\n "); + } + format.Set("mask", strings::Hex(mask, strings::ZERO_PAD_8)); + if (this_word == cached_has_word_index) { + format("(cached_has_bits & 0x$mask$u) != 0"); + } else { + format("($1$_has_bits_[$2$] & 0x$mask$u) != 0", from, this_word); + } + } + format(")) {\n"); + format.Indent(); +} + +bool ColdChunkSkipper::OnEndChunk(int chunk, io::Printer* printer) { + Formatter format(printer, variables_); + if (chunk != limit_chunk_ - 1) { + return false; + } + format.Outdent(); + format("}\n"); + return true; +} + +void MaySetAnnotationVariable(const Options& options, + StringPiece annotation_name, + StringPiece injector_template_prefix, + StringPiece injector_template_suffix, + std::map<std::string, std::string>* variables) { + if (options.field_listener_options.forbidden_field_listener_events.count( + std::string(annotation_name))) + return; + (*variables)[StrCat("annotate_", annotation_name)] = strings::Substitute( + StrCat(injector_template_prefix, injector_template_suffix), + (*variables)["classtype"]); +} + +void GenerateExtensionAnnotations( + const Descriptor* descriptor, const Options& options, + std::map<std::string, std::string>* variables) { + const std::map<std::string, std::string> accessor_annotations_to_hooks = { + {"annotate_extension_has", "OnHasExtension"}, + {"annotate_extension_clear", "OnClearExtension"}, + {"annotate_extension_repeated_size", "OnExtensionSize"}, + {"annotate_extension_get", "OnGetExtension"}, + {"annotate_extension_mutable", "OnMutableExtension"}, + {"annotate_extension_set", "OnSetExtension"}, + {"annotate_extension_release", "OnReleaseExtension"}, + {"annotate_repeated_extension_get", "OnGetExtension"}, + {"annotate_repeated_extension_mutable", "OnMutableExtension"}, + {"annotate_repeated_extension_set", "OnSetExtension"}, + {"annotate_repeated_extension_add", "OnAddExtension"}, + {"annotate_repeated_extension_add_mutable", "OnAddMutableExtension"}, + {"annotate_repeated_extension_list", "OnListExtension"}, + {"annotate_repeated_extension_list_mutable", "OnMutableListExtension"}, + }; + for (const auto& annotation : accessor_annotations_to_hooks) { + (*variables)[annotation.first] = ""; + } + if (!options.field_listener_options.inject_field_listener_events || + descriptor->file()->options().optimize_for() == + google::protobuf::FileOptions::LITE_RUNTIME) { + return; + } + for (const auto& annotation : accessor_annotations_to_hooks) { + const std::string& annotation_name = annotation.first; + const std::string& listener_call = annotation.second; + if (!StrContains(annotation_name, "repeated") && + !StrContains(annotation_name, "size") && + !StrContains(annotation_name, "clear")) { + // Primitive fields accessors. + // "Has" is here as users calling "has" on a repeated field is a mistake. + (*variables)[annotation_name] = StrCat( + " _tracker_.", listener_call, + "(this, id.number(), _proto_TypeTraits::GetPtr(id.number(), " + "_extensions_, id.default_value_ref()));"); + } else if (StrContains(annotation_name, "repeated") && + !StrContains(annotation_name, "list") && + !StrContains(annotation_name, "size")) { + // Repeated index accessors. + std::string str_index = "index"; + if (StrContains(annotation_name, "add")) { + str_index = "_extensions_.ExtensionSize(id.number()) - 1"; + } + (*variables)[annotation_name] = + StrCat(" _tracker_.", listener_call, + "(this, id.number(), " + "_proto_TypeTraits::GetPtr(id.number(), _extensions_, ", + str_index, "));"); + } else if (StrContains(annotation_name, "list") || + StrContains(annotation_name, "size")) { + // Repeated full accessors. + (*variables)[annotation_name] = StrCat( + " _tracker_.", listener_call, + "(this, id.number(), _proto_TypeTraits::GetRepeatedPtr(id.number(), " + "_extensions_));"); + } else { + // Generic accessors such as "clear". + // TODO(b/190614678): Generalize clear from both repeated and non repeated + // calls, currently their underlying memory interfaces are very different. + // Or think of removing clear callback as no usages are needed and no + // memory exist after calling clear(). + } + } +} + +} // anonymous namespace + +// =================================================================== + +MessageGenerator::MessageGenerator( + const Descriptor* descriptor, + const std::map<std::string, std::string>& vars, int index_in_file_messages, + const Options& options, MessageSCCAnalyzer* scc_analyzer) + : descriptor_(descriptor), + index_in_file_messages_(index_in_file_messages), + classname_(ClassName(descriptor, false)), + options_(options), + field_generators_(descriptor, options, scc_analyzer), + max_has_bit_index_(0), + max_inlined_string_index_(0), + num_weak_fields_(0), + scc_analyzer_(scc_analyzer), + variables_(vars) { + if (!message_layout_helper_) { + message_layout_helper_.reset(new PaddingOptimizer()); + } + + // Variables that apply to this class + variables_["classname"] = classname_; + variables_["classtype"] = QualifiedClassName(descriptor_, options); + variables_["full_name"] = descriptor_->full_name(); + variables_["superclass"] = SuperClassName(descriptor_, options_); + variables_["annotate_serialize"] = ""; + variables_["annotate_deserialize"] = ""; + variables_["annotate_reflection"] = ""; + variables_["annotate_bytesize"] = ""; + variables_["annotate_mergefrom"] = ""; + + if (options.field_listener_options.inject_field_listener_events && + descriptor->file()->options().optimize_for() != + google::protobuf::FileOptions::LITE_RUNTIME) { + const std::string injector_template = " _tracker_."; + + MaySetAnnotationVariable(options, "serialize", injector_template, + "OnSerialize(this);\n", &variables_); + MaySetAnnotationVariable(options, "deserialize", injector_template, + "OnDeserialize(this);\n", &variables_); + // TODO(danilak): Ideally annotate_reflection should not exist and we need + // to annotate all reflective calls on our own, however, as this is a cause + // for side effects, i.e. reading values dynamically, we want the users know + // that dynamic access can happen. + MaySetAnnotationVariable(options, "reflection", injector_template, + "OnGetMetadata();\n", &variables_); + MaySetAnnotationVariable(options, "bytesize", injector_template, + "OnByteSize(this);\n", &variables_); + MaySetAnnotationVariable(options, "mergefrom", injector_template, + "OnMergeFrom(this, &from);\n", &variables_); + } + + GenerateExtensionAnnotations(descriptor_, options_, &variables_); + + SetUnknownFieldsVariable(descriptor_, options_, &variables_); + + // Compute optimized field order to be used for layout and initialization + // purposes. + for (auto field : FieldRange(descriptor_)) { + if (IsFieldStripped(field, options_)) { + continue; + } + + if (IsWeak(field, options_)) { + num_weak_fields_++; + } else if (!field->real_containing_oneof()) { + optimized_order_.push_back(field); + } + } + + message_layout_helper_->OptimizeLayout(&optimized_order_, options_, + scc_analyzer_); + + // This message has hasbits iff one or more fields need one. + for (auto field : optimized_order_) { + if (HasHasbit(field)) { + if (has_bit_indices_.empty()) { + has_bit_indices_.resize(descriptor_->field_count(), kNoHasbit); + } + has_bit_indices_[field->index()] = max_has_bit_index_++; + } + if (IsStringInlined(field, options_)) { + if (inlined_string_indices_.empty()) { + inlined_string_indices_.resize(descriptor_->field_count(), kNoHasbit); + } + inlined_string_indices_[field->index()] = max_inlined_string_index_++; + } + } + + if (!has_bit_indices_.empty()) { + field_generators_.SetHasBitIndices(has_bit_indices_); + } + + if (!inlined_string_indices_.empty()) { + field_generators_.SetInlinedStringIndices(inlined_string_indices_); + } + + num_required_fields_ = 0; + for (int i = 0; i < descriptor->field_count(); i++) { + if (descriptor->field(i)->is_required()) { + ++num_required_fields_; + } + } + + table_driven_ = + TableDrivenParsingEnabled(descriptor_, options_, scc_analyzer_); + parse_function_generator_.reset(new ParseFunctionGenerator( + descriptor_, max_has_bit_index_, has_bit_indices_, + inlined_string_indices_, options_, scc_analyzer_, variables_)); +} + +MessageGenerator::~MessageGenerator() = default; + +size_t MessageGenerator::HasBitsSize() const { + return (max_has_bit_index_ + 31) / 32; +} + +size_t MessageGenerator::InlinedStringDonatedSize() const { + return (max_inlined_string_index_ + 31) / 32; +} + +int MessageGenerator::HasBitIndex(const FieldDescriptor* field) const { + return has_bit_indices_.empty() ? kNoHasbit + : has_bit_indices_[field->index()]; +} + +int MessageGenerator::HasByteIndex(const FieldDescriptor* field) const { + int hasbit = HasBitIndex(field); + return hasbit == kNoHasbit ? kNoHasbit : hasbit / 8; +} + +int MessageGenerator::HasWordIndex(const FieldDescriptor* field) const { + int hasbit = HasBitIndex(field); + return hasbit == kNoHasbit ? kNoHasbit : hasbit / 32; +} + +void MessageGenerator::AddGenerators( + std::vector<std::unique_ptr<EnumGenerator>>* enum_generators, + std::vector<std::unique_ptr<ExtensionGenerator>>* extension_generators) { + for (int i = 0; i < descriptor_->enum_type_count(); i++) { + enum_generators->emplace_back( + new EnumGenerator(descriptor_->enum_type(i), variables_, options_)); + enum_generators_.push_back(enum_generators->back().get()); + } + for (int i = 0; i < descriptor_->extension_count(); i++) { + extension_generators->emplace_back(new ExtensionGenerator( + descriptor_->extension(i), options_, scc_analyzer_)); + extension_generators_.push_back(extension_generators->back().get()); + } +} + +void MessageGenerator::GenerateFieldAccessorDeclarations(io::Printer* printer) { + Formatter format(printer, variables_); + // optimized_fields_ does not contain fields where + // field->real_containing_oneof() + // so we need to iterate over those as well. + // + // We place the non-oneof fields in optimized_order_, as that controls the + // order of the _has_bits_ entries and we want GDB's pretty printers to be + // able to infer these indices from the k[FIELDNAME]FieldNumber order. + std::vector<const FieldDescriptor*> ordered_fields; + ordered_fields.reserve(descriptor_->field_count()); + + ordered_fields.insert(ordered_fields.begin(), optimized_order_.begin(), + optimized_order_.end()); + for (auto field : FieldRange(descriptor_)) { + if (!field->real_containing_oneof() && !field->options().weak() && + !IsFieldStripped(field, options_)) { + continue; + } + ordered_fields.push_back(field); + } + + if (!ordered_fields.empty()) { + format("enum : int {\n"); + for (auto field : ordered_fields) { + Formatter::SaveState save(&format); + + std::map<std::string, std::string> vars; + SetCommonFieldVariables(field, &vars, options_); + format.AddMap(vars); + format(" ${1$$2$$}$ = $number$,\n", field, FieldConstantName(field)); + } + format("};\n"); + } + for (auto field : ordered_fields) { + PrintFieldComment(format, field); + + Formatter::SaveState save(&format); + + std::map<std::string, std::string> vars; + SetCommonFieldVariables(field, &vars, options_); + format.AddMap(vars); + + if (field->is_repeated()) { + format("$deprecated_attr$int ${1$$name$_size$}$() const$2$\n", field, + !IsFieldStripped(field, options_) ? ";" : " {__builtin_trap();}"); + if (!IsFieldStripped(field, options_)) { + format( + "private:\n" + "int ${1$_internal_$name$_size$}$() const;\n" + "public:\n", + field); + } + } else if (HasHasMethod(field)) { + format("$deprecated_attr$bool ${1$has_$name$$}$() const$2$\n", field, + !IsFieldStripped(field, options_) ? ";" : " {__builtin_trap();}"); + if (!IsFieldStripped(field, options_)) { + format( + "private:\n" + "bool _internal_has_$name$() const;\n" + "public:\n"); + } + } else if (HasPrivateHasMethod(field)) { + if (!IsFieldStripped(field, options_)) { + format( + "private:\n" + "bool ${1$_internal_has_$name$$}$() const;\n" + "public:\n", + field); + } + } + format("$deprecated_attr$void ${1$clear_$name$$}$()$2$\n", field, + !IsFieldStripped(field, options_) ? ";" : "{__builtin_trap();}"); + + // Generate type-specific accessor declarations. + field_generators_.get(field).GenerateAccessorDeclarations(printer); + + format("\n"); + } + + if (descriptor_->extension_range_count() > 0) { + // Generate accessors for extensions. + // We use "_proto_TypeTraits" as a type name below because "TypeTraits" + // causes problems if the class has a nested message or enum type with that + // name and "_TypeTraits" is technically reserved for the C++ library since + // it starts with an underscore followed by a capital letter. + // + // For similar reason, we use "_field_type" and "_is_packed" as parameter + // names below, so that "field_type" and "is_packed" can be used as field + // names. + format(R"( +template <typename _proto_TypeTraits, + ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, + bool _is_packed> +inline bool HasExtension( + const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< + $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) const { +$annotate_extension_has$ + return _extensions_.Has(id.number()); +} + +template <typename _proto_TypeTraits, + ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, + bool _is_packed> +inline void ClearExtension( + const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< + $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) { + _extensions_.ClearExtension(id.number()); +$annotate_extension_clear$ +} + +template <typename _proto_TypeTraits, + ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, + bool _is_packed> +inline int ExtensionSize( + const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< + $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) const { +$annotate_extension_repeated_size$ + return _extensions_.ExtensionSize(id.number()); +} + +template <typename _proto_TypeTraits, + ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, + bool _is_packed> +inline typename _proto_TypeTraits::Singular::ConstType GetExtension( + const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< + $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) const { +$annotate_extension_get$ + return _proto_TypeTraits::Get(id.number(), _extensions_, + id.default_value()); +} + +template <typename _proto_TypeTraits, + ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, + bool _is_packed> +inline typename _proto_TypeTraits::Singular::MutableType MutableExtension( + const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< + $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) { +$annotate_extension_mutable$ + return _proto_TypeTraits::Mutable(id.number(), _field_type, + &_extensions_); +} + +template <typename _proto_TypeTraits, + ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, + bool _is_packed> +inline void SetExtension( + const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< + $classname$, _proto_TypeTraits, _field_type, _is_packed>& id, + typename _proto_TypeTraits::Singular::ConstType value) { + _proto_TypeTraits::Set(id.number(), _field_type, value, &_extensions_); +$annotate_extension_set$ +} + +template <typename _proto_TypeTraits, + ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, + bool _is_packed> +inline void SetAllocatedExtension( + const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< + $classname$, _proto_TypeTraits, _field_type, _is_packed>& id, + typename _proto_TypeTraits::Singular::MutableType value) { + _proto_TypeTraits::SetAllocated(id.number(), _field_type, value, + &_extensions_); +$annotate_extension_set$ +} +template <typename _proto_TypeTraits, + ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, + bool _is_packed> +inline void UnsafeArenaSetAllocatedExtension( + const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< + $classname$, _proto_TypeTraits, _field_type, _is_packed>& id, + typename _proto_TypeTraits::Singular::MutableType value) { + _proto_TypeTraits::UnsafeArenaSetAllocated(id.number(), _field_type, + value, &_extensions_); +$annotate_extension_set$ +} +template <typename _proto_TypeTraits, + ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, + bool _is_packed> +PROTOBUF_NODISCARD inline + typename _proto_TypeTraits::Singular::MutableType + ReleaseExtension( + const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< + $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) { +$annotate_extension_release$ + return _proto_TypeTraits::Release(id.number(), _field_type, + &_extensions_); +} +template <typename _proto_TypeTraits, + ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, + bool _is_packed> +inline typename _proto_TypeTraits::Singular::MutableType +UnsafeArenaReleaseExtension( + const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< + $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) { +$annotate_extension_release$ + return _proto_TypeTraits::UnsafeArenaRelease(id.number(), _field_type, + &_extensions_); +} + +template <typename _proto_TypeTraits, + ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, + bool _is_packed> +inline typename _proto_TypeTraits::Repeated::ConstType GetExtension( + const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< + $classname$, _proto_TypeTraits, _field_type, _is_packed>& id, + int index) const { +$annotate_repeated_extension_get$ + return _proto_TypeTraits::Get(id.number(), _extensions_, index); +} + +template <typename _proto_TypeTraits, + ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, + bool _is_packed> +inline typename _proto_TypeTraits::Repeated::MutableType MutableExtension( + const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< + $classname$, _proto_TypeTraits, _field_type, _is_packed>& id, + int index) { +$annotate_repeated_extension_mutable$ + return _proto_TypeTraits::Mutable(id.number(), index, &_extensions_); +} + +template <typename _proto_TypeTraits, + ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, + bool _is_packed> +inline void SetExtension( + const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< + $classname$, _proto_TypeTraits, _field_type, _is_packed>& id, + int index, typename _proto_TypeTraits::Repeated::ConstType value) { + _proto_TypeTraits::Set(id.number(), index, value, &_extensions_); +$annotate_repeated_extension_set$ +} + +template <typename _proto_TypeTraits, + ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, + bool _is_packed> +inline typename _proto_TypeTraits::Repeated::MutableType AddExtension( + const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< + $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) { + typename _proto_TypeTraits::Repeated::MutableType to_add = + _proto_TypeTraits::Add(id.number(), _field_type, &_extensions_); +$annotate_repeated_extension_add_mutable$ + return to_add; +} + +template <typename _proto_TypeTraits, + ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, + bool _is_packed> +inline void AddExtension( + const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< + $classname$, _proto_TypeTraits, _field_type, _is_packed>& id, + typename _proto_TypeTraits::Repeated::ConstType value) { + _proto_TypeTraits::Add(id.number(), _field_type, _is_packed, value, + &_extensions_); +$annotate_repeated_extension_add$ +} + +template <typename _proto_TypeTraits, + ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, + bool _is_packed> +inline const typename _proto_TypeTraits::Repeated::RepeatedFieldType& +GetRepeatedExtension( + const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< + $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) const { +$annotate_repeated_extension_list$ + return _proto_TypeTraits::GetRepeated(id.number(), _extensions_); +} + +template <typename _proto_TypeTraits, + ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, + bool _is_packed> +inline typename _proto_TypeTraits::Repeated::RepeatedFieldType* +MutableRepeatedExtension( + const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< + $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) { +$annotate_repeated_extension_list_mutable$ + return _proto_TypeTraits::MutableRepeated(id.number(), _field_type, + _is_packed, &_extensions_); +} + +)"); + // Generate MessageSet specific APIs for proto2 MessageSet. + // For testing purposes we don't check for bridge.MessageSet, so + // we don't use IsProto2MessageSet + if (descriptor_->options().message_set_wire_format() && + !options_.opensource_runtime && !options_.lite_implicit_weak_fields) { + // Special-case MessageSet + format("GOOGLE_PROTOBUF_EXTENSION_MESSAGE_SET_ACCESSORS($classname$)\n"); + } + } + + for (auto oneof : OneOfRange(descriptor_)) { + Formatter::SaveState saver(&format); + format.Set("oneof_name", oneof->name()); + format.Set("camel_oneof_name", UnderscoresToCamelCase(oneof->name(), true)); + format( + "void ${1$clear_$oneof_name$$}$();\n" + "$camel_oneof_name$Case $oneof_name$_case() const;\n", + oneof); + } +} + +void MessageGenerator::GenerateSingularFieldHasBits( + const FieldDescriptor* field, Formatter format) { + if (IsFieldStripped(field, options_)) { + format( + "inline bool $classname$::has_$name$() const { " + "__builtin_trap(); }\n"); + return; + } + if (field->options().weak()) { + format( + "inline bool $classname$::has_$name$() const {\n" + "$annotate_has$" + " return _weak_field_map_.Has($number$);\n" + "}\n"); + return; + } + if (HasHasbit(field)) { + int has_bit_index = HasBitIndex(field); + GOOGLE_CHECK_NE(has_bit_index, kNoHasbit); + + format.Set("has_array_index", has_bit_index / 32); + format.Set("has_mask", + strings::Hex(1u << (has_bit_index % 32), strings::ZERO_PAD_8)); + format( + "inline bool $classname$::_internal_has_$name$() const {\n" + " bool value = " + "(_has_bits_[$has_array_index$] & 0x$has_mask$u) != 0;\n"); + + if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && + !IsLazy(field, options_, scc_analyzer_)) { + // We maintain the invariant that for a submessage x, has_x() returning + // true implies that x_ is not null. By giving this information to the + // compiler, we allow it to eliminate unnecessary null checks later on. + format(" PROTOBUF_ASSUME(!value || $name$_ != nullptr);\n"); + } + + format( + " return value;\n" + "}\n" + "inline bool $classname$::has_$name$() const {\n" + "$annotate_has$" + " return _internal_has_$name$();\n" + "}\n"); + } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + // Message fields have a has_$name$() method. + if (IsLazy(field, options_, scc_analyzer_)) { + format( + "inline bool $classname$::_internal_has_$name$() const {\n" + " return !$name$_.IsCleared();\n" + "}\n"); + } else { + format( + "inline bool $classname$::_internal_has_$name$() const {\n" + " return this != internal_default_instance() " + "&& $name$_ != nullptr;\n" + "}\n"); + } + format( + "inline bool $classname$::has_$name$() const {\n" + "$annotate_has$" + " return _internal_has_$name$();\n" + "}\n"); + } +} + +void MessageGenerator::GenerateOneofHasBits(io::Printer* printer) { + Formatter format(printer, variables_); + for (auto oneof : OneOfRange(descriptor_)) { + format.Set("oneof_name", oneof->name()); + format.Set("oneof_index", oneof->index()); + format.Set("cap_oneof_name", ToUpper(oneof->name())); + format( + "inline bool $classname$::has_$oneof_name$() const {\n" + " return $oneof_name$_case() != $cap_oneof_name$_NOT_SET;\n" + "}\n" + "inline void $classname$::clear_has_$oneof_name$() {\n" + " _oneof_case_[$oneof_index$] = $cap_oneof_name$_NOT_SET;\n" + "}\n"); + } +} + +void MessageGenerator::GenerateOneofMemberHasBits(const FieldDescriptor* field, + const Formatter& format) { + if (IsFieldStripped(field, options_)) { + if (HasHasMethod(field)) { + format( + "inline bool $classname$::has_$name$() const { " + "__builtin_trap(); }\n"); + } + format( + "inline void $classname$::set_has_$name$() { __builtin_trap(); " + "}\n"); + return; + } + // Singular field in a oneof + // N.B.: Without field presence, we do not use has-bits or generate + // has_$name$() methods, but oneofs still have set_has_$name$(). + // Oneofs also have has_$name$() but only as a private helper + // method, so that generated code is slightly cleaner (vs. comparing + // _oneof_case_[index] against a constant everywhere). + // + // If has_$name$() is private, there is no need to add an internal accessor. + // Only annotate public accessors. + if (HasHasMethod(field)) { + format( + "inline bool $classname$::_internal_has_$name$() const {\n" + " return $oneof_name$_case() == k$field_name$;\n" + "}\n" + "inline bool $classname$::has_$name$() const {\n" + "$annotate_has$" + " return _internal_has_$name$();\n" + "}\n"); + } else if (HasPrivateHasMethod(field)) { + format( + "inline bool $classname$::_internal_has_$name$() const {\n" + " return $oneof_name$_case() == k$field_name$;\n" + "}\n"); + } + // set_has_$name$() for oneof fields is always private; hence should not be + // annotated. + format( + "inline void $classname$::set_has_$name$() {\n" + " _oneof_case_[$oneof_index$] = k$field_name$;\n" + "}\n"); +} + +void MessageGenerator::GenerateFieldClear(const FieldDescriptor* field, + bool is_inline, Formatter format) { + if (IsFieldStripped(field, options_)) { + format("void $classname$::clear_$name$() { __builtin_trap(); }\n"); + return; + } + + // Generate clear_$name$(). + if (is_inline) { + format("inline "); + } + format("void $classname$::clear_$name$() {\n"); + + format.Indent(); + + if (field->real_containing_oneof()) { + // Clear this field only if it is the active field in this oneof, + // otherwise ignore + format("if (_internal_has_$name$()) {\n"); + format.Indent(); + field_generators_.get(field).GenerateClearingCode(format.printer()); + format("clear_has_$oneof_name$();\n"); + format.Outdent(); + format("}\n"); + } else { + field_generators_.get(field).GenerateClearingCode(format.printer()); + if (HasHasbit(field)) { + int has_bit_index = HasBitIndex(field); + format.Set("has_array_index", has_bit_index / 32); + format.Set("has_mask", + strings::Hex(1u << (has_bit_index % 32), strings::ZERO_PAD_8)); + format("_has_bits_[$has_array_index$] &= ~0x$has_mask$u;\n"); + } + } + format("$annotate_clear$"); + format.Outdent(); + format("}\n"); +} + +void MessageGenerator::GenerateFieldAccessorDefinitions(io::Printer* printer) { + Formatter format(printer, variables_); + format("// $classname$\n\n"); + + for (auto field : FieldRange(descriptor_)) { + PrintFieldComment(format, field); + + if (IsFieldStripped(field, options_)) { + continue; + } + + std::map<std::string, std::string> vars; + SetCommonFieldVariables(field, &vars, options_); + + Formatter::SaveState saver(&format); + format.AddMap(vars); + + // Generate has_$name$() or $name$_size(). + if (field->is_repeated()) { + if (IsFieldStripped(field, options_)) { + format( + "inline int $classname$::$name$_size() const { " + "__builtin_trap(); }\n"); + } else { + format( + "inline int $classname$::_internal_$name$_size() const {\n" + " return $name$_$1$.size();\n" + "}\n" + "inline int $classname$::$name$_size() const {\n" + "$annotate_size$" + " return _internal_$name$_size();\n" + "}\n", + IsImplicitWeakField(field, options_, scc_analyzer_) && + field->message_type() + ? ".weak" + : ""); + } + } else if (field->real_containing_oneof()) { + format.Set("field_name", UnderscoresToCamelCase(field->name(), true)); + format.Set("oneof_name", field->containing_oneof()->name()); + format.Set("oneof_index", + StrCat(field->containing_oneof()->index())); + GenerateOneofMemberHasBits(field, format); + } else { + // Singular field. + GenerateSingularFieldHasBits(field, format); + } + + if (!IsCrossFileMaybeMap(field)) { + GenerateFieldClear(field, true, format); + } + + // Generate type-specific accessors. + if (!IsFieldStripped(field, options_)) { + field_generators_.get(field).GenerateInlineAccessorDefinitions(printer); + } + + format("\n"); + } + + // Generate has_$name$() and clear_has_$name$() functions for oneofs. + GenerateOneofHasBits(printer); +} + +void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { + Formatter format(printer, variables_); + format.Set("class_final", + ShouldMarkClassAsFinal(descriptor_, options_) ? "final" : ""); + + if (IsMapEntryMessage(descriptor_)) { + std::map<std::string, std::string> vars; + CollectMapInfo(options_, descriptor_, &vars); + vars["lite"] = + HasDescriptorMethods(descriptor_->file(), options_) ? "" : "Lite"; + format.AddMap(vars); + format( + "class $classname$ : public " + "::$proto_ns$::internal::MapEntry$lite$<$classname$, \n" + " $key_cpp$, $val_cpp$,\n" + " ::$proto_ns$::internal::WireFormatLite::$key_wire_type$,\n" + " ::$proto_ns$::internal::WireFormatLite::$val_wire_type$> {\n" + "public:\n" + " typedef ::$proto_ns$::internal::MapEntry$lite$<$classname$, \n" + " $key_cpp$, $val_cpp$,\n" + " ::$proto_ns$::internal::WireFormatLite::$key_wire_type$,\n" + " ::$proto_ns$::internal::WireFormatLite::$val_wire_type$> " + "SuperType;\n" + " $classname$();\n" + " explicit constexpr $classname$(\n" + " ::$proto_ns$::internal::ConstantInitialized);\n" + " explicit $classname$(::$proto_ns$::Arena* arena);\n" + " void MergeFrom(const $classname$& other);\n" + " static const $classname$* internal_default_instance() { return " + "reinterpret_cast<const " + "$classname$*>(&_$classname$_default_instance_); }\n"); + auto utf8_check = GetUtf8CheckMode(descriptor_->field(0), options_); + if (descriptor_->field(0)->type() == FieldDescriptor::TYPE_STRING && + utf8_check != Utf8CheckMode::kNone) { + if (utf8_check == Utf8CheckMode::kStrict) { + format( + " static bool ValidateKey(std::string* s) {\n" + " return ::$proto_ns$::internal::WireFormatLite::" + "VerifyUtf8String(s->data(), static_cast<int>(s->size()), " + "::$proto_ns$::internal::WireFormatLite::PARSE, \"$1$\");\n" + " }\n", + descriptor_->field(0)->full_name()); + } else { + GOOGLE_CHECK(utf8_check == Utf8CheckMode::kVerify); + format( + " static bool ValidateKey(std::string* s) {\n" + "#ifndef NDEBUG\n" + " ::$proto_ns$::internal::WireFormatLite::VerifyUtf8String(\n" + " s->data(), static_cast<int>(s->size()), " + "::$proto_ns$::internal::" + "WireFormatLite::PARSE, \"$1$\");\n" + "#else\n" + " (void) s;\n" + "#endif\n" + " return true;\n" + " }\n", + descriptor_->field(0)->full_name()); + } + } else { + format(" static bool ValidateKey(void*) { return true; }\n"); + } + if (descriptor_->field(1)->type() == FieldDescriptor::TYPE_STRING && + utf8_check != Utf8CheckMode::kNone) { + if (utf8_check == Utf8CheckMode::kStrict) { + format( + " static bool ValidateValue(std::string* s) {\n" + " return ::$proto_ns$::internal::WireFormatLite::" + "VerifyUtf8String(s->data(), static_cast<int>(s->size()), " + "::$proto_ns$::internal::WireFormatLite::PARSE, \"$1$\");\n" + " }\n", + descriptor_->field(1)->full_name()); + } else { + GOOGLE_CHECK(utf8_check == Utf8CheckMode::kVerify); + format( + " static bool ValidateValue(std::string* s) {\n" + "#ifndef NDEBUG\n" + " ::$proto_ns$::internal::WireFormatLite::VerifyUtf8String(\n" + " s->data(), static_cast<int>(s->size()), " + "::$proto_ns$::internal::" + "WireFormatLite::PARSE, \"$1$\");\n" + "#else\n" + " (void) s;\n" + "#endif\n" + " return true;\n" + " }\n", + descriptor_->field(1)->full_name()); + } + } else { + format(" static bool ValidateValue(void*) { return true; }\n"); + } + if (HasDescriptorMethods(descriptor_->file(), options_)) { + format( + " using ::$proto_ns$::Message::MergeFrom;\n" + "" + " ::$proto_ns$::Metadata GetMetadata() const final;\n"); + } + format("};\n"); + return; + } + + format( + "class $dllexport_decl $${1$$classname$$}$$ class_final$ :\n" + " public $superclass$ /* @@protoc_insertion_point(" + "class_definition:$full_name$) */ {\n", + descriptor_); + format(" public:\n"); + format.Indent(); + + if (EnableMessageOwnedArena(descriptor_)) { + format( + "inline $classname$() : $classname$(" + "::$proto_ns$::Arena::InternalHelper<$classname$>::\n" + " CreateMessageOwnedArena(), true) {}\n"); + } else { + format("inline $classname$() : $classname$(nullptr) {}\n"); + } + if (!HasSimpleBaseClass(descriptor_, options_)) { + format("~$classname$() override;\n"); + } + format( + "explicit constexpr " + "$classname$(::$proto_ns$::internal::ConstantInitialized);\n" + "\n" + "$classname$(const $classname$& from);\n" + "$classname$($classname$&& from) noexcept\n" + " : $classname$() {\n" + " *this = ::std::move(from);\n" + "}\n" + "\n" + "inline $classname$& operator=(const $classname$& from) {\n" + " CopyFrom(from);\n" + " return *this;\n" + "}\n" + "inline $classname$& operator=($classname$&& from) noexcept {\n" + " if (this == &from) return *this;\n" + " if (GetOwningArena() == from.GetOwningArena()\n" + "#ifdef PROTOBUF_FORCE_COPY_IN_MOVE\n" + " && GetOwningArena() != nullptr\n" + "#endif // !PROTOBUF_FORCE_COPY_IN_MOVE\n" + " ) {\n" + " InternalSwap(&from);\n" + " } else {\n" + " CopyFrom(from);\n" + " }\n" + " return *this;\n" + "}\n" + "\n"); + + if (options_.table_driven_serialization) { + format( + "private:\n" + "const void* InternalGetTable() const override;\n" + "public:\n" + "\n"); + } + + if (PublicUnknownFieldsAccessors(descriptor_)) { + format( + "inline const $unknown_fields_type$& unknown_fields() const {\n" + " return $unknown_fields$;\n" + "}\n" + "inline $unknown_fields_type$* mutable_unknown_fields() {\n" + " return $mutable_unknown_fields$;\n" + "}\n" + "\n"); + } + + // Only generate this member if it's not disabled. + if (HasDescriptorMethods(descriptor_->file(), options_) && + !descriptor_->options().no_standard_descriptor_accessor()) { + format( + "static const ::$proto_ns$::Descriptor* descriptor() {\n" + " return GetDescriptor();\n" + "}\n"); + } + + if (HasDescriptorMethods(descriptor_->file(), options_)) { + // These shadow non-static methods of the same names in Message. We + // redefine them here because calls directly on the generated class can be + // statically analyzed -- we know what descriptor types are being requested. + // It also avoids a vtable dispatch. + // + // We would eventually like to eliminate the methods in Message, and having + // this separate also lets us track calls to the base class methods + // separately. + format( + "static const ::$proto_ns$::Descriptor* GetDescriptor() {\n" + " return default_instance().GetMetadata().descriptor;\n" + "}\n" + "static const ::$proto_ns$::Reflection* GetReflection() {\n" + " return default_instance().GetMetadata().reflection;\n" + "}\n"); + } + + format( + "static const $classname$& default_instance() {\n" + " return *internal_default_instance();\n" + "}\n"); + + // Generate enum values for every field in oneofs. One list is generated for + // each oneof with an additional *_NOT_SET value. + for (auto oneof : OneOfRange(descriptor_)) { + format("enum $1$Case {\n", UnderscoresToCamelCase(oneof->name(), true)); + format.Indent(); + for (auto field : FieldRange(oneof)) { + format("$1$ = $2$,\n", OneofCaseConstantName(field), // 1 + field->number()); // 2 + } + format("$1$_NOT_SET = 0,\n", ToUpper(oneof->name())); + format.Outdent(); + format( + "};\n" + "\n"); + } + + // TODO(gerbens) make this private, while still granting other protos access. + format( + "static inline const $classname$* internal_default_instance() {\n" + " return reinterpret_cast<const $classname$*>(\n" + " &_$classname$_default_instance_);\n" + "}\n" + "static constexpr int kIndexInFileMessages =\n" + " $1$;\n" + "\n", + index_in_file_messages_); + + if (IsAnyMessage(descriptor_, options_)) { + format( + "// implements Any -----------------------------------------------\n" + "\n"); + if (HasDescriptorMethods(descriptor_->file(), options_)) { + format( + "bool PackFrom(const ::$proto_ns$::Message& message) {\n" + " return _any_metadata_.PackFrom(GetArena(), message);\n" + "}\n" + "bool PackFrom(const ::$proto_ns$::Message& message,\n" + " ::PROTOBUF_NAMESPACE_ID::ConstStringParam " + "type_url_prefix) {\n" + " return _any_metadata_.PackFrom(GetArena(), message, " + "type_url_prefix);\n" + "}\n" + "bool UnpackTo(::$proto_ns$::Message* message) const {\n" + " return _any_metadata_.UnpackTo(message);\n" + "}\n" + "static bool GetAnyFieldDescriptors(\n" + " const ::$proto_ns$::Message& message,\n" + " const ::$proto_ns$::FieldDescriptor** type_url_field,\n" + " const ::$proto_ns$::FieldDescriptor** value_field);\n" + "template <typename T, class = typename std::enable_if<" + "!std::is_convertible<T, const ::$proto_ns$::Message&>" + "::value>::type>\n" + "bool PackFrom(const T& message) {\n" + " return _any_metadata_.PackFrom<T>(GetArena(), message);\n" + "}\n" + "template <typename T, class = typename std::enable_if<" + "!std::is_convertible<T, const ::$proto_ns$::Message&>" + "::value>::type>\n" + "bool PackFrom(const T& message,\n" + " ::PROTOBUF_NAMESPACE_ID::ConstStringParam " + "type_url_prefix) {\n" + " return _any_metadata_.PackFrom<T>(GetArena(), message, " + "type_url_prefix);" + "}\n" + "template <typename T, class = typename std::enable_if<" + "!std::is_convertible<T, const ::$proto_ns$::Message&>" + "::value>::type>\n" + "bool UnpackTo(T* message) const {\n" + " return _any_metadata_.UnpackTo<T>(message);\n" + "}\n"); + } else { + format( + "template <typename T>\n" + "bool PackFrom(const T& message) {\n" + " return _any_metadata_.PackFrom(GetArena(), message);\n" + "}\n" + "template <typename T>\n" + "bool PackFrom(const T& message,\n" + " ::PROTOBUF_NAMESPACE_ID::ConstStringParam " + "type_url_prefix) {\n" + " return _any_metadata_.PackFrom(GetArena(), message, " + "type_url_prefix);\n" + "}\n" + "template <typename T>\n" + "bool UnpackTo(T* message) const {\n" + " return _any_metadata_.UnpackTo(message);\n" + "}\n"); + } + format( + "template<typename T> bool Is() const {\n" + " return _any_metadata_.Is<T>();\n" + "}\n" + "static bool ParseAnyTypeUrl(::PROTOBUF_NAMESPACE_ID::ConstStringParam " + "type_url,\n" + " std::string* full_type_name);\n"); + } + + format( + "friend void swap($classname$& a, $classname$& b) {\n" + " a.Swap(&b);\n" + "}\n" + "inline void Swap($classname$* other) {\n" + " if (other == this) return;\n" + "#ifdef PROTOBUF_FORCE_COPY_IN_SWAP\n" + " if (GetOwningArena() != nullptr &&\n" + " GetOwningArena() == other->GetOwningArena()) {\n " + "#else // PROTOBUF_FORCE_COPY_IN_SWAP\n" + " if (GetOwningArena() == other->GetOwningArena()) {\n" + "#endif // !PROTOBUF_FORCE_COPY_IN_SWAP\n" + " InternalSwap(other);\n" + " } else {\n" + " ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);\n" + " }\n" + "}\n" + "void UnsafeArenaSwap($classname$* other) {\n" + " if (other == this) return;\n" + " $DCHK$(GetOwningArena() == other->GetOwningArena());\n" + " InternalSwap(other);\n" + "}\n"); + + format( + "\n" + "// implements Message ----------------------------------------------\n" + "\n" + "$classname$* New(::$proto_ns$::Arena* arena = nullptr) const final {\n" + " return CreateMaybeMessage<$classname$>(arena);\n" + "}\n"); + + // For instances that derive from Message (rather than MessageLite), some + // methods are virtual and should be marked as final. + format.Set("full_final", HasDescriptorMethods(descriptor_->file(), options_) + ? "final" + : ""); + + if (HasGeneratedMethods(descriptor_->file(), options_)) { + if (HasDescriptorMethods(descriptor_->file(), options_)) { + if (!HasSimpleBaseClass(descriptor_, options_)) { + format( + // Use Message's built-in MergeFrom and CopyFrom when the passed-in + // argument is a generic Message instance, and only define the + // custom MergeFrom and CopyFrom instances when the source of the + // merge/copy is known to be the same class as the destination. + // TODO(jorg): Define MergeFrom in terms of MergeImpl, rather than + // the other way around, to save even more code size. + "using $superclass$::CopyFrom;\n" + "void CopyFrom(const $classname$& from);\n" + "" + "using $superclass$::MergeFrom;\n" + "void MergeFrom(const $classname$& from);\n" + "private:\n" + "static void MergeImpl(::$proto_ns$::Message* to, const " + "::$proto_ns$::Message& from);\n" + "public:\n"); + } else { + format( + "using $superclass$::CopyFrom;\n" + "inline void CopyFrom(const $classname$& from) {\n" + " $superclass$::CopyImpl(this, from);\n" + "}\n" + "" + "using $superclass$::MergeFrom;\n" + "void MergeFrom(const $classname$& from) {\n" + " $superclass$::MergeImpl(this, from);\n" + "}\n" + "public:\n"); + } + } else { + format( + "void CheckTypeAndMergeFrom(const ::$proto_ns$::MessageLite& from)" + " final;\n" + "void CopyFrom(const $classname$& from);\n" + "void MergeFrom(const $classname$& from);\n"); + } + + if (!HasSimpleBaseClass(descriptor_, options_)) { + format( + "PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;\n" + "bool IsInitialized() const final;\n" + "\n" + "size_t ByteSizeLong() const final;\n"); + + parse_function_generator_->GenerateMethodDecls(printer); + + format( + "$uint8$* _InternalSerialize(\n" + " $uint8$* target, ::$proto_ns$::io::EpsCopyOutputStream* stream) " + "const final;\n"); + } + } + + if (options_.field_listener_options.inject_field_listener_events) { + format("static constexpr int _kInternalFieldNumber = $1$;\n", + descriptor_->field_count()); + } + + if (!HasSimpleBaseClass(descriptor_, options_)) { + format( + "int GetCachedSize() const final { return _cached_size_.Get(); }" + "\n\nprivate:\n" + "void SharedCtor();\n" + "void SharedDtor();\n" + "void SetCachedSize(int size) const$ full_final$;\n" + "void InternalSwap($classname$* other);\n"); + } + + format( + // Friend AnyMetadata so that it can call this FullMessageName() method. + "\nprivate:\n" + "friend class ::$proto_ns$::internal::AnyMetadata;\n" + "static $1$ FullMessageName() {\n" + " return \"$full_name$\";\n" + "}\n", + options_.opensource_runtime ? "::PROTOBUF_NAMESPACE_ID::StringPiece" + : "::StringPiece"); + + format( + // TODO(gerbens) Make this private! Currently people are deriving from + // protos to give access to this constructor, breaking the invariants + // we rely on. + "protected:\n" + "explicit $classname$(::$proto_ns$::Arena* arena,\n" + " bool is_message_owned = false);\n" + "private:\n"); + + if (!HasSimpleBaseClass(descriptor_, options_)) { + format( + "static void ArenaDtor(void* object);\n" + "inline void RegisterArenaDtor(::$proto_ns$::Arena* arena);\n"); + } + + format( + "public:\n" + "\n"); + + if (HasDescriptorMethods(descriptor_->file(), options_)) { + if (HasGeneratedMethods(descriptor_->file(), options_)) { + format( + "static const ClassData _class_data_;\n" + "const ::$proto_ns$::Message::ClassData*" + "GetClassData() const final;\n" + "\n"); + } + format( + "::$proto_ns$::Metadata GetMetadata() const final;\n" + "\n"); + } else { + format( + "std::string GetTypeName() const final;\n" + "\n"); + } + + format( + "// nested types ----------------------------------------------------\n" + "\n"); + + // Import all nested message classes into this class's scope with typedefs. + for (int i = 0; i < descriptor_->nested_type_count(); i++) { + const Descriptor* nested_type = descriptor_->nested_type(i); + if (!IsMapEntryMessage(nested_type)) { + format.Set("nested_full_name", ClassName(nested_type, false)); + format.Set("nested_name", ResolveKeyword(nested_type->name())); + format("typedef ${1$$nested_full_name$$}$ ${1$$nested_name$$}$;\n", + nested_type); + } + } + + if (descriptor_->nested_type_count() > 0) { + format("\n"); + } + + // Import all nested enums and their values into this class's scope with + // typedefs and constants. + for (int i = 0; i < descriptor_->enum_type_count(); i++) { + enum_generators_[i]->GenerateSymbolImports(printer); + format("\n"); + } + + format( + "// accessors -------------------------------------------------------\n" + "\n"); + + // Generate accessor methods for all fields. + GenerateFieldAccessorDeclarations(printer); + + // Declare extension identifiers. + for (int i = 0; i < descriptor_->extension_count(); i++) { + extension_generators_[i]->GenerateDeclaration(printer); + } + + + format("// @@protoc_insertion_point(class_scope:$full_name$)\n"); + + // Generate private members. + format.Outdent(); + format(" private:\n"); + format.Indent(); + // TODO(seongkim): Remove hack to track field access and remove this class. + format("class _Internal;\n"); + + for (auto field : FieldRange(descriptor_)) { + // set_has_***() generated in all oneofs. + if (!field->is_repeated() && !field->options().weak() && + field->real_containing_oneof()) { + format("void set_has_$1$();\n", FieldName(field)); + } + } + format("\n"); + + // Generate oneof function declarations + for (auto oneof : OneOfRange(descriptor_)) { + format( + "inline bool has_$1$() const;\n" + "inline void clear_has_$1$();\n\n", + oneof->name()); + } + + if (HasGeneratedMethods(descriptor_->file(), options_) && + !descriptor_->options().message_set_wire_format() && + num_required_fields_ > 1) { + format( + "// helper for ByteSizeLong()\n" + "size_t RequiredFieldsByteSizeFallback() const;\n\n"); + } + + if (HasGeneratedMethods(descriptor_->file(), options_)) { + parse_function_generator_->GenerateDataDecls(printer); + } + + // Prepare decls for _cached_size_ and _has_bits_. Their position in the + // output will be determined later. + + bool need_to_emit_cached_size = true; + const std::string cached_size_decl = + "mutable ::$proto_ns$::internal::CachedSize _cached_size_;\n"; + + const size_t sizeof_has_bits = HasBitsSize(); + const std::string has_bits_decl = + sizeof_has_bits == 0 ? "" + : StrCat("::$proto_ns$::internal::HasBits<", + sizeof_has_bits, "> _has_bits_;\n"); + + // To minimize padding, data members are divided into three sections: + // (1) members assumed to align to 8 bytes + // (2) members corresponding to message fields, re-ordered to optimize + // alignment. + // (3) members assumed to align to 4 bytes. + + // Members assumed to align to 8 bytes: + + if (descriptor_->extension_range_count() > 0) { + format( + "::$proto_ns$::internal::ExtensionSet _extensions_;\n" + "\n"); + } + + if (options_.field_listener_options.inject_field_listener_events && + descriptor_->file()->options().optimize_for() != + google::protobuf::FileOptions::LITE_RUNTIME) { + format("static ::$proto_ns$::AccessListener<$1$> _tracker_;\n", + ClassName(descriptor_)); + } + + // Generate _inlined_string_donated_ for inlined string type. + // TODO(congliu): To avoid affecting the locality of `_has_bits_`, should this + // be below or above `_has_bits_`? + if (!inlined_string_indices_.empty()) { + format("::$proto_ns$::internal::HasBits<$1$> _inlined_string_donated_;\n", + InlinedStringDonatedSize()); + } + + format( + "template <typename T> friend class " + "::$proto_ns$::Arena::InternalHelper;\n" + "typedef void InternalArenaConstructable_;\n" + "typedef void DestructorSkippable_;\n"); + + if (!has_bit_indices_.empty()) { + // _has_bits_ is frequently accessed, so to reduce code size and improve + // speed, it should be close to the start of the object. Placing + // _cached_size_ together with _has_bits_ improves cache locality despite + // potential alignment padding. + format(has_bits_decl.c_str()); + format(cached_size_decl.c_str()); + need_to_emit_cached_size = false; + } + + // Field members: + + // Emit some private and static members + for (auto field : optimized_order_) { + const FieldGenerator& generator = field_generators_.get(field); + generator.GenerateStaticMembers(printer); + generator.GeneratePrivateMembers(printer); + } + + // For each oneof generate a union + for (auto oneof : OneOfRange(descriptor_)) { + std::string camel_oneof_name = UnderscoresToCamelCase(oneof->name(), true); + format("union $1$Union {\n", camel_oneof_name); + format.Indent(); + format( + // explicit empty constructor is needed when union contains + // ArenaStringPtr members for string fields. + "constexpr $1$Union() : _constinit_{} {}\n" + " ::$proto_ns$::internal::ConstantInitialized _constinit_;\n", + camel_oneof_name); + for (auto field : FieldRange(oneof)) { + if (!IsFieldStripped(field, options_)) { + field_generators_.get(field).GeneratePrivateMembers(printer); + } + } + format.Outdent(); + format("} $1$_;\n", oneof->name()); + for (auto field : FieldRange(oneof)) { + if (!IsFieldStripped(field, options_)) { + field_generators_.get(field).GenerateStaticMembers(printer); + } + } + } + + // Members assumed to align to 4 bytes: + + if (need_to_emit_cached_size) { + format(cached_size_decl.c_str()); + need_to_emit_cached_size = false; + } + + // Generate _oneof_case_. + if (descriptor_->real_oneof_decl_count() > 0) { + format( + "$uint32$ _oneof_case_[$1$];\n" + "\n", + descriptor_->real_oneof_decl_count()); + } + + if (num_weak_fields_) { + format("::$proto_ns$::internal::WeakFieldMap _weak_field_map_;\n"); + } + // Generate _any_metadata_ for the Any type. + if (IsAnyMessage(descriptor_, options_)) { + format("::$proto_ns$::internal::AnyMetadata _any_metadata_;\n"); + } + + // The TableStruct struct needs access to the private parts, in order to + // construct the offsets of all members. + format("friend struct ::$tablename$;\n"); + + format.Outdent(); + format("};"); + GOOGLE_DCHECK(!need_to_emit_cached_size); +} // NOLINT(readability/fn_size) + +void MessageGenerator::GenerateInlineMethods(io::Printer* printer) { + if (IsMapEntryMessage(descriptor_)) return; + GenerateFieldAccessorDefinitions(printer); + + // Generate oneof_case() functions. + for (auto oneof : OneOfRange(descriptor_)) { + Formatter format(printer, variables_); + format.Set("camel_oneof_name", UnderscoresToCamelCase(oneof->name(), true)); + format.Set("oneof_name", oneof->name()); + format.Set("oneof_index", oneof->index()); + format( + "inline $classname$::$camel_oneof_name$Case $classname$::" + "${1$$oneof_name$_case$}$() const {\n" + " return $classname$::$camel_oneof_name$Case(" + "_oneof_case_[$oneof_index$]);\n" + "}\n", + oneof); + } +} + +bool MessageGenerator::GenerateParseTable(io::Printer* printer, size_t offset, + size_t aux_offset) { + Formatter format(printer, variables_); + + if (!table_driven_) { + format("{ nullptr, nullptr, 0, -1, -1, -1, -1, nullptr, false },\n"); + return false; + } + + int max_field_number = 0; + for (auto field : FieldRange(descriptor_)) { + if (max_field_number < field->number()) { + max_field_number = field->number(); + } + } + + format("{\n"); + format.Indent(); + + format( + "$tablename$::entries + $1$,\n" + "$tablename$::aux + $2$,\n" + "$3$,\n", + offset, aux_offset, max_field_number); + + if (has_bit_indices_.empty()) { + // If no fields have hasbits, then _has_bits_ does not exist. + format("-1,\n"); + } else { + format("PROTOBUF_FIELD_OFFSET($classtype$, _has_bits_),\n"); + } + + if (descriptor_->real_oneof_decl_count() > 0) { + format("PROTOBUF_FIELD_OFFSET($classtype$, _oneof_case_),\n"); + } else { + format("-1, // no _oneof_case_\n"); + } + + if (descriptor_->extension_range_count() > 0) { + format("PROTOBUF_FIELD_OFFSET($classtype$, _extensions_),\n"); + } else { + format("-1, // no _extensions_\n"); + } + + // TODO(ckennelly): Consolidate this with the calculation for + // AuxiliaryParseTableField. + format( + "PROTOBUF_FIELD_OFFSET($classtype$, _internal_metadata_),\n" + "&$package_ns$::_$classname$_default_instance_,\n"); + + if (UseUnknownFieldSet(descriptor_->file(), options_)) { + format("true,\n"); + } else { + format("false,\n"); + } + + format.Outdent(); + format("},\n"); + return true; +} + +void MessageGenerator::GenerateSchema(io::Printer* printer, int offset, + int has_offset) { + Formatter format(printer, variables_); + has_offset = !has_bit_indices_.empty() || IsMapEntryMessage(descriptor_) + ? offset + has_offset + : -1; + int inlined_string_indices_offset; + if (inlined_string_indices_.empty()) { + inlined_string_indices_offset = -1; + } else { + GOOGLE_DCHECK_NE(has_offset, -1); + GOOGLE_DCHECK(!IsMapEntryMessage(descriptor_)); + inlined_string_indices_offset = has_offset + has_bit_indices_.size(); + } + + format("{ $1$, $2$, $3$, sizeof($classtype$)},\n", offset, has_offset, + inlined_string_indices_offset); +} + +namespace { + +// We need to calculate for each field what function the table driven code +// should use to serialize it. This returns the index in a lookup table. +uint32_t CalcFieldNum(const FieldGenerator& generator, + const FieldDescriptor* field, const Options& options) { + bool is_a_map = IsMapEntryMessage(field->containing_type()); + int type = field->type(); + if (type == FieldDescriptor::TYPE_STRING || + type == FieldDescriptor::TYPE_BYTES) { + // string field + if (generator.IsInlined()) { + type = internal::FieldMetadata::kInlinedType; + } else if (IsCord(field, options)) { + type = internal::FieldMetadata::kCordType; + } else if (IsStringPiece(field, options)) { + type = internal::FieldMetadata::kStringPieceType; + } + } + + if (field->real_containing_oneof()) { + return internal::FieldMetadata::CalculateType( + type, internal::FieldMetadata::kOneOf); + } else if (field->is_packed()) { + return internal::FieldMetadata::CalculateType( + type, internal::FieldMetadata::kPacked); + } else if (field->is_repeated()) { + return internal::FieldMetadata::CalculateType( + type, internal::FieldMetadata::kRepeated); + } else if (HasHasbit(field) || field->real_containing_oneof() || is_a_map) { + return internal::FieldMetadata::CalculateType( + type, internal::FieldMetadata::kPresence); + } else { + return internal::FieldMetadata::CalculateType( + type, internal::FieldMetadata::kNoPresence); + } +} + +int FindMessageIndexInFile(const Descriptor* descriptor) { + std::vector<const Descriptor*> flatten = + FlattenMessagesInFile(descriptor->file()); + return std::find(flatten.begin(), flatten.end(), descriptor) - + flatten.begin(); +} + +} // namespace + +int MessageGenerator::GenerateFieldMetadata(io::Printer* printer) { + Formatter format(printer, variables_); + if (!options_.table_driven_serialization) { + return 0; + } + + std::vector<const FieldDescriptor*> sorted = SortFieldsByNumber(descriptor_); + if (IsMapEntryMessage(descriptor_)) { + for (int i = 0; i < 2; i++) { + const FieldDescriptor* field = sorted[i]; + const FieldGenerator& generator = field_generators_.get(field); + + uint32_t tag = internal::WireFormatLite::MakeTag( + field->number(), WireFormat::WireTypeForFieldType(field->type())); + + std::map<std::string, std::string> vars; + vars["classtype"] = QualifiedClassName(descriptor_, options_); + vars["field_name"] = FieldName(field); + vars["tag"] = StrCat(tag); + vars["hasbit"] = StrCat(i); + vars["type"] = StrCat(CalcFieldNum(generator, field, options_)); + vars["ptr"] = "nullptr"; + if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + GOOGLE_CHECK(!IsMapEntryMessage(field->message_type())); + vars["ptr"] = + "::" + UniqueName("TableStruct", field->message_type(), options_) + + "::serialization_table + " + + StrCat(FindMessageIndexInFile(field->message_type())); + } + Formatter::SaveState saver(&format); + format.AddMap(vars); + format( + "{PROTOBUF_FIELD_OFFSET(" + "::$proto_ns$::internal::MapEntryHelper<$classtype$::" + "SuperType>, $field_name$_), $tag$," + "PROTOBUF_FIELD_OFFSET(" + "::$proto_ns$::internal::MapEntryHelper<$classtype$::" + "SuperType>, _has_bits_) * 8 + $hasbit$, $type$, " + "$ptr$},\n"); + } + return 2; + } + format( + "{PROTOBUF_FIELD_OFFSET($classtype$, _cached_size_)," + " 0, 0, 0, nullptr},\n"); + std::vector<const Descriptor::ExtensionRange*> sorted_extensions; + sorted_extensions.reserve(descriptor_->extension_range_count()); + for (int i = 0; i < descriptor_->extension_range_count(); ++i) { + sorted_extensions.push_back(descriptor_->extension_range(i)); + } + std::sort(sorted_extensions.begin(), sorted_extensions.end(), + ExtensionRangeSorter()); + for (int i = 0, extension_idx = 0; /* no range */; i++) { + for (; extension_idx < sorted_extensions.size() && + (i == sorted.size() || + sorted_extensions[extension_idx]->start < sorted[i]->number()); + extension_idx++) { + const Descriptor::ExtensionRange* range = + sorted_extensions[extension_idx]; + format( + "{PROTOBUF_FIELD_OFFSET($classtype$, _extensions_), " + "$1$, $2$, ::$proto_ns$::internal::FieldMetadata::kSpecial, " + "reinterpret_cast<const " + "void*>(::$proto_ns$::internal::ExtensionSerializer)},\n", + range->start, range->end); + } + if (i == sorted.size()) break; + const FieldDescriptor* field = sorted[i]; + + uint32_t tag = internal::WireFormatLite::MakeTag( + field->number(), WireFormat::WireTypeForFieldType(field->type())); + if (field->is_packed()) { + tag = internal::WireFormatLite::MakeTag( + field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED); + } + + std::string classfieldname = FieldName(field); + if (field->real_containing_oneof()) { + classfieldname = field->containing_oneof()->name(); + } + format.Set("field_name", classfieldname); + std::string ptr = "nullptr"; + if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + if (IsMapEntryMessage(field->message_type())) { + format( + "{PROTOBUF_FIELD_OFFSET($classtype$, $field_name$_), $1$, $2$, " + "::$proto_ns$::internal::FieldMetadata::kSpecial, " + "reinterpret_cast<const void*>(static_cast< " + "::$proto_ns$::internal::SpecialSerializer>(" + "::$proto_ns$::internal::MapFieldSerializer< " + "::$proto_ns$::internal::MapEntryToMapField<" + "$3$>::MapFieldType, " + "$tablename$::serialization_table>))},\n", + tag, FindMessageIndexInFile(field->message_type()), + QualifiedClassName(field->message_type(), options_)); + continue; + } else if (!field->message_type()->options().message_set_wire_format()) { + // message_set doesn't have the usual table and we need to + // dispatch to generated serializer, hence ptr stays zero. + ptr = + "::" + UniqueName("TableStruct", field->message_type(), options_) + + "::serialization_table + " + + StrCat(FindMessageIndexInFile(field->message_type())); + } + } + + const FieldGenerator& generator = field_generators_.get(field); + int type = CalcFieldNum(generator, field, options_); + + if (IsLazy(field, options_, scc_analyzer_)) { + type = internal::FieldMetadata::kSpecial; + ptr = "reinterpret_cast<const void*>(::" + variables_["proto_ns"] + + "::internal::LazyFieldSerializer"; + if (field->real_containing_oneof()) { + ptr += "OneOf"; + } else if (!HasHasbit(field)) { + ptr += "NoPresence"; + } + ptr += ")"; + } + + if (field->options().weak()) { + // TODO(gerbens) merge weak fields into ranges + format( + "{PROTOBUF_FIELD_OFFSET(" + "$classtype$, _weak_field_map_), $1$, $1$, " + "::$proto_ns$::internal::FieldMetadata::kSpecial, " + "reinterpret_cast<const " + "void*>(::$proto_ns$::internal::WeakFieldSerializer)},\n", + tag); + } else if (field->real_containing_oneof()) { + format.Set("oneofoffset", + sizeof(uint32_t) * field->containing_oneof()->index()); + format( + "{PROTOBUF_FIELD_OFFSET($classtype$, $field_name$_), $1$," + " PROTOBUF_FIELD_OFFSET($classtype$, _oneof_case_) + " + "$oneofoffset$, $2$, $3$},\n", + tag, type, ptr); + } else if (HasHasbit(field)) { + format.Set("hasbitsoffset", has_bit_indices_[field->index()]); + format( + "{PROTOBUF_FIELD_OFFSET($classtype$, $field_name$_), " + "$1$, PROTOBUF_FIELD_OFFSET($classtype$, _has_bits_) * 8 + " + "$hasbitsoffset$, $2$, $3$},\n", + tag, type, ptr); + } else { + format( + "{PROTOBUF_FIELD_OFFSET($classtype$, $field_name$_), " + "$1$, ~0u, $2$, $3$},\n", + tag, type, ptr); + } + } + int num_field_metadata = 1 + sorted.size() + sorted_extensions.size(); + num_field_metadata++; + std::string serializer = UseUnknownFieldSet(descriptor_->file(), options_) + ? "UnknownFieldSetSerializer" + : "UnknownFieldSerializerLite"; + format( + "{PROTOBUF_FIELD_OFFSET($classtype$, _internal_metadata_), 0, ~0u, " + "::$proto_ns$::internal::FieldMetadata::kSpecial, reinterpret_cast<const " + "void*>(::$proto_ns$::internal::$1$)},\n", + serializer); + return num_field_metadata; +} + +void MessageGenerator::GenerateClassMethods(io::Printer* printer) { + Formatter format(printer, variables_); + if (IsMapEntryMessage(descriptor_)) { + format( + "$classname$::$classname$() {}\n" + "$classname$::$classname$(::$proto_ns$::Arena* arena)\n" + " : SuperType(arena) {}\n" + "void $classname$::MergeFrom(const $classname$& other) {\n" + " MergeFromInternal(other);\n" + "}\n"); + if (HasDescriptorMethods(descriptor_->file(), options_)) { + if (!descriptor_->options().map_entry()) { + format( + "::$proto_ns$::Metadata $classname$::GetMetadata() const {\n" + "$annotate_reflection$" + " return ::$proto_ns$::internal::AssignDescriptors(\n" + " &$desc_table$_getter, &$desc_table$_once,\n" + " $file_level_metadata$[$1$]);\n" + "}\n", + index_in_file_messages_); + } else { + format( + "::$proto_ns$::Metadata $classname$::GetMetadata() const {\n" + " return ::$proto_ns$::internal::AssignDescriptors(\n" + " &$desc_table$_getter, &$desc_table$_once,\n" + " $file_level_metadata$[$1$]);\n" + "}\n", + index_in_file_messages_); + } + } + return; + } + + if (IsAnyMessage(descriptor_, options_)) { + if (HasDescriptorMethods(descriptor_->file(), options_)) { + format( + "bool $classname$::GetAnyFieldDescriptors(\n" + " const ::$proto_ns$::Message& message,\n" + " const ::$proto_ns$::FieldDescriptor** type_url_field,\n" + " const ::$proto_ns$::FieldDescriptor** value_field) {\n" + " return ::$proto_ns$::internal::GetAnyFieldDescriptors(\n" + " message, type_url_field, value_field);\n" + "}\n"); + } + format( + "bool $classname$::ParseAnyTypeUrl(\n" + " ::PROTOBUF_NAMESPACE_ID::ConstStringParam type_url,\n" + " std::string* full_type_name) {\n" + " return ::$proto_ns$::internal::ParseAnyTypeUrl(type_url,\n" + " full_type_name);\n" + "}\n" + "\n"); + } + + format( + "class $classname$::_Internal {\n" + " public:\n"); + format.Indent(); + if (!has_bit_indices_.empty()) { + format( + "using HasBits = decltype(std::declval<$classname$>()._has_bits_);\n"); + } + for (auto field : FieldRange(descriptor_)) { + field_generators_.get(field).GenerateInternalAccessorDeclarations(printer); + if (IsFieldStripped(field, options_)) { + continue; + } + if (HasHasbit(field)) { + int has_bit_index = HasBitIndex(field); + GOOGLE_CHECK_NE(has_bit_index, kNoHasbit) << field->full_name(); + format( + "static void set_has_$1$(HasBits* has_bits) {\n" + " (*has_bits)[$2$] |= $3$u;\n" + "}\n", + FieldName(field), has_bit_index / 32, (1u << (has_bit_index % 32))); + } + } + if (num_required_fields_ > 0) { + const std::vector<uint32_t> masks_for_has_bits = RequiredFieldsBitMask(); + format( + "static bool MissingRequiredFields(const HasBits& has_bits) " + "{\n" + " return $1$;\n" + "}\n", + ConditionalToCheckBitmasks(masks_for_has_bits, false, "has_bits")); + } + + format.Outdent(); + format("};\n\n"); + for (auto field : FieldRange(descriptor_)) { + if (!IsFieldStripped(field, options_)) { + field_generators_.get(field).GenerateInternalAccessorDefinitions(printer); + } + } + + // Generate non-inline field definitions. + for (auto field : FieldRange(descriptor_)) { + if (IsFieldStripped(field, options_)) { + continue; + } + field_generators_.get(field).GenerateNonInlineAccessorDefinitions(printer); + if (IsCrossFileMaybeMap(field)) { + Formatter::SaveState saver(&format); + std::map<std::string, std::string> vars; + SetCommonFieldVariables(field, &vars, options_); + if (field->real_containing_oneof()) { + SetCommonOneofFieldVariables(field, &vars); + } + format.AddMap(vars); + GenerateFieldClear(field, false, format); + } + } + + GenerateStructors(printer); + format("\n"); + + if (descriptor_->real_oneof_decl_count() > 0) { + GenerateOneofClear(printer); + format("\n"); + } + + if (HasGeneratedMethods(descriptor_->file(), options_)) { + GenerateClear(printer); + format("\n"); + + if (!HasSimpleBaseClass(descriptor_, options_)) { + parse_function_generator_->GenerateMethodImpls(printer); + format("\n"); + + parse_function_generator_->GenerateDataDefinitions(printer); + } + + GenerateSerializeWithCachedSizesToArray(printer); + format("\n"); + + GenerateByteSize(printer); + format("\n"); + + GenerateMergeFrom(printer); + format("\n"); + + GenerateClassSpecificMergeFrom(printer); + format("\n"); + + GenerateCopyFrom(printer); + format("\n"); + + GenerateIsInitialized(printer); + format("\n"); + } + + GenerateVerify(printer); + + GenerateSwap(printer); + format("\n"); + + if (options_.table_driven_serialization) { + format( + "const void* $classname$::InternalGetTable() const {\n" + " return ::$tablename$::serialization_table + $1$;\n" + "}\n" + "\n", + index_in_file_messages_); + } + if (HasDescriptorMethods(descriptor_->file(), options_)) { + if (!descriptor_->options().map_entry()) { + format( + "::$proto_ns$::Metadata $classname$::GetMetadata() const {\n" + "$annotate_reflection$" + " return ::$proto_ns$::internal::AssignDescriptors(\n" + " &$desc_table$_getter, &$desc_table$_once,\n" + " $file_level_metadata$[$1$]);\n" + "}\n", + index_in_file_messages_); + } else { + format( + "::$proto_ns$::Metadata $classname$::GetMetadata() const {\n" + " return ::$proto_ns$::internal::AssignDescriptors(\n" + " &$desc_table$_getter, &$desc_table$_once,\n" + " $file_level_metadata$[$1$]);\n" + "}\n", + index_in_file_messages_); + } + } else { + format( + "std::string $classname$::GetTypeName() const {\n" + " return \"$full_name$\";\n" + "}\n" + "\n"); + } + + if (options_.field_listener_options.inject_field_listener_events && + descriptor_->file()->options().optimize_for() != + google::protobuf::FileOptions::LITE_RUNTIME) { + format( + "::$proto_ns$::AccessListener<$classtype$> " + "$1$::_tracker_(&FullMessageName);\n", + ClassName(descriptor_)); + } +} + +size_t MessageGenerator::GenerateParseOffsets(io::Printer* printer) { + Formatter format(printer, variables_); + + if (!table_driven_) { + return 0; + } + + // Field "0" is special: We use it in our switch statement of processing + // types to handle the successful end tag case. + format("{0, 0, 0, ::$proto_ns$::internal::kInvalidMask, 0, 0},\n"); + int last_field_number = 1; + + std::vector<const FieldDescriptor*> ordered_fields = + SortFieldsByNumber(descriptor_); + + for (auto field : ordered_fields) { + Formatter::SaveState saver(&format); + GOOGLE_CHECK_GE(field->number(), last_field_number); + + for (; last_field_number < field->number(); last_field_number++) { + format( + "{ 0, 0, ::$proto_ns$::internal::kInvalidMask,\n" + " ::$proto_ns$::internal::kInvalidMask, 0, 0 },\n"); + } + last_field_number++; + + unsigned char normal_wiretype, packed_wiretype, processing_type; + normal_wiretype = WireFormat::WireTypeForFieldType(field->type()); + + if (field->is_packable()) { + packed_wiretype = WireFormatLite::WIRETYPE_LENGTH_DELIMITED; + } else { + packed_wiretype = internal::kNotPackedMask; + } + + processing_type = static_cast<unsigned>(field->type()); + const FieldGenerator& generator = field_generators_.get(field); + if (field->type() == FieldDescriptor::TYPE_STRING) { + switch (EffectiveStringCType(field, options_)) { + case FieldOptions::STRING: + if (generator.IsInlined()) { + processing_type = internal::TYPE_STRING_INLINED; + } + break; + case FieldOptions::CORD: + processing_type = internal::TYPE_STRING_CORD; + break; + case FieldOptions::STRING_PIECE: + processing_type = internal::TYPE_STRING_STRING_PIECE; + break; + } + } else if (field->type() == FieldDescriptor::TYPE_BYTES) { + switch (EffectiveStringCType(field, options_)) { + case FieldOptions::STRING: + if (generator.IsInlined()) { + processing_type = internal::TYPE_BYTES_INLINED; + } + break; + case FieldOptions::CORD: + processing_type = internal::TYPE_BYTES_CORD; + break; + case FieldOptions::STRING_PIECE: + processing_type = internal::TYPE_BYTES_STRING_PIECE; + break; + } + } + + processing_type |= static_cast<unsigned>( + field->is_repeated() ? internal::kRepeatedMask : 0); + processing_type |= static_cast<unsigned>( + field->real_containing_oneof() ? internal::kOneofMask : 0); + + if (field->is_map()) { + processing_type = internal::TYPE_MAP; + } + + const unsigned char tag_size = + WireFormat::TagSize(field->number(), field->type()); + + std::map<std::string, std::string> vars; + if (field->real_containing_oneof()) { + vars["name"] = field->containing_oneof()->name(); + vars["presence"] = StrCat(field->containing_oneof()->index()); + } else { + vars["name"] = FieldName(field); + vars["presence"] = StrCat(has_bit_indices_[field->index()]); + } + vars["nwtype"] = StrCat(normal_wiretype); + vars["pwtype"] = StrCat(packed_wiretype); + vars["ptype"] = StrCat(processing_type); + vars["tag_size"] = StrCat(tag_size); + + format.AddMap(vars); + + format( + "{\n" + " PROTOBUF_FIELD_OFFSET($classtype$, $name$_),\n" + " static_cast<$uint32$>($presence$),\n" + " $nwtype$, $pwtype$, $ptype$, $tag_size$\n" + "},\n"); + } + + return last_field_number; +} + +size_t MessageGenerator::GenerateParseAuxTable(io::Printer* printer) { + Formatter format(printer, variables_); + + if (!table_driven_) { + return 0; + } + + std::vector<const FieldDescriptor*> ordered_fields = + SortFieldsByNumber(descriptor_); + + format("::$proto_ns$::internal::AuxiliaryParseTableField(),\n"); + int last_field_number = 1; + for (auto field : ordered_fields) { + Formatter::SaveState saver(&format); + + GOOGLE_CHECK_GE(field->number(), last_field_number); + for (; last_field_number < field->number(); last_field_number++) { + format("::$proto_ns$::internal::AuxiliaryParseTableField(),\n"); + } + + std::map<std::string, std::string> vars; + SetCommonFieldVariables(field, &vars, options_); + format.AddMap(vars); + + switch (field->cpp_type()) { + case FieldDescriptor::CPPTYPE_ENUM: + if (HasPreservingUnknownEnumSemantics(field)) { + format( + "{::$proto_ns$::internal::AuxiliaryParseTableField::enum_aux{" + "nullptr}},\n"); + } else { + format( + "{::$proto_ns$::internal::AuxiliaryParseTableField::enum_aux{" + "$1$_IsValid}},\n", + ClassName(field->enum_type(), true)); + } + last_field_number++; + break; + case FieldDescriptor::CPPTYPE_MESSAGE: { + if (field->is_map()) { + format( + "{::$proto_ns$::internal::AuxiliaryParseTableField::map_" + "aux{&::$proto_ns$::internal::ParseMap<$1$>}},\n", + QualifiedClassName(field->message_type(), options_)); + last_field_number++; + break; + } + format.Set("field_classname", ClassName(field->message_type(), false)); + format.Set("default_instance", QualifiedDefaultInstanceName( + field->message_type(), options_)); + + format( + "{::$proto_ns$::internal::AuxiliaryParseTableField::message_aux{\n" + " &$default_instance$}},\n"); + last_field_number++; + break; + } + case FieldDescriptor::CPPTYPE_STRING: { + std::string default_val; + switch (EffectiveStringCType(field, options_)) { + case FieldOptions::STRING: + default_val = field->default_value_string().empty() + ? "&::" + variables_["proto_ns"] + + "::internal::fixed_address_empty_string" + : "&" + + QualifiedClassName(descriptor_, options_) + + "::" + MakeDefaultName(field); + break; + case FieldOptions::CORD: + case FieldOptions::STRING_PIECE: + default_val = + "\"" + CEscape(field->default_value_string()) + "\""; + break; + } + format( + "{::$proto_ns$::internal::AuxiliaryParseTableField::string_aux{\n" + " $1$,\n" + " \"$2$\"\n" + "}},\n", + default_val, field->full_name()); + last_field_number++; + break; + } + default: + break; + } + } + + return last_field_number; +} + +std::pair<size_t, size_t> MessageGenerator::GenerateOffsets( + io::Printer* printer) { + Formatter format(printer, variables_); + + if (!has_bit_indices_.empty() || IsMapEntryMessage(descriptor_)) { + format("PROTOBUF_FIELD_OFFSET($classtype$, _has_bits_),\n"); + } else { + format("~0u, // no _has_bits_\n"); + } + format("PROTOBUF_FIELD_OFFSET($classtype$, _internal_metadata_),\n"); + if (descriptor_->extension_range_count() > 0) { + format("PROTOBUF_FIELD_OFFSET($classtype$, _extensions_),\n"); + } else { + format("~0u, // no _extensions_\n"); + } + if (descriptor_->real_oneof_decl_count() > 0) { + format("PROTOBUF_FIELD_OFFSET($classtype$, _oneof_case_[0]),\n"); + } else { + format("~0u, // no _oneof_case_\n"); + } + if (num_weak_fields_ > 0) { + format("PROTOBUF_FIELD_OFFSET($classtype$, _weak_field_map_),\n"); + } else { + format("~0u, // no _weak_field_map_\n"); + } + if (!inlined_string_indices_.empty()) { + format("PROTOBUF_FIELD_OFFSET($classtype$, _inlined_string_donated_),\n"); + } else { + format("~0u, // no _inlined_string_donated_\n"); + } + const int kNumGenericOffsets = 6; // the number of fixed offsets above + const size_t offsets = kNumGenericOffsets + descriptor_->field_count() + + descriptor_->real_oneof_decl_count(); + size_t entries = offsets; + for (auto field : FieldRange(descriptor_)) { + if (IsFieldStripped(field, options_)) { + format("~0u, // stripped\n"); + continue; + } + // TODO(sbenza): We should not have an entry in the offset table for fields + // that do not use them. + if (field->options().weak() || field->real_containing_oneof()) { + // Mark the field to prevent unintentional access through reflection. + // Don't use the top bit because that is for unused fields. + format("::$proto_ns$::internal::kInvalidFieldOffsetTag"); + } else { + format("PROTOBUF_FIELD_OFFSET($classtype$, $1$_)", FieldName(field)); + } + + // Some information about a field is in the pdproto profile. The profile is + // only available at compile time. So we embed such information in the + // offset of the field, so that the information is available when + // reflectively accessing the field at run time. + // + // Embed whether the field is used to the MSB of the offset. + if (!IsFieldUsed(field, options_)) { + format(" | 0x80000000u // unused\n"); + } + + // Embed whether the field is eagerly verified lazy or inlined string to the + // LSB of the offset. + if (IsEagerlyVerifiedLazy(field, options_, scc_analyzer_)) { + format(" | 0x1u // eagerly verified lazy\n"); + } else if (IsStringInlined(field, options_)) { + format(" | 0x1u // inlined\n"); + } + format(",\n"); + } + + int count = 0; + for (auto oneof : OneOfRange(descriptor_)) { + format("PROTOBUF_FIELD_OFFSET($classtype$, $1$_),\n", oneof->name()); + count++; + } + GOOGLE_CHECK_EQ(count, descriptor_->real_oneof_decl_count()); + + if (IsMapEntryMessage(descriptor_)) { + entries += 2; + format( + "0,\n" + "1,\n"); + } else if (!has_bit_indices_.empty()) { + entries += has_bit_indices_.size(); + for (int i = 0; i < has_bit_indices_.size(); i++) { + const std::string index = + has_bit_indices_[i] >= 0 ? StrCat(has_bit_indices_[i]) : "~0u"; + format("$1$,\n", index); + } + } + if (!inlined_string_indices_.empty()) { + entries += inlined_string_indices_.size(); + for (int inlined_string_indice : inlined_string_indices_) { + const std::string index = inlined_string_indice >= 0 + ? StrCat(inlined_string_indice) + : "~0u"; + format("$1$,\n", index); + } + } + + return std::make_pair(entries, offsets); +} + +void MessageGenerator::GenerateSharedConstructorCode(io::Printer* printer) { + if (HasSimpleBaseClass(descriptor_, options_)) return; + Formatter format(printer, variables_); + + format("inline void $classname$::SharedCtor() {\n"); + + std::vector<bool> processed(optimized_order_.size(), false); + GenerateConstructorBody(printer, processed, false); + + for (auto oneof : OneOfRange(descriptor_)) { + format("clear_has_$1$();\n", oneof->name()); + } + + format("}\n\n"); +} + +void MessageGenerator::GenerateSharedDestructorCode(io::Printer* printer) { + if (HasSimpleBaseClass(descriptor_, options_)) return; + Formatter format(printer, variables_); + + format("inline void $classname$::SharedDtor() {\n"); + format.Indent(); + format("$DCHK$(GetArenaForAllocation() == nullptr);\n"); + // Write the destructors for each field except oneof members. + // optimized_order_ does not contain oneof fields. + for (auto field : optimized_order_) { + field_generators_.get(field).GenerateDestructorCode(printer); + } + + // Generate code to destruct oneofs. Clearing should do the work. + for (auto oneof : OneOfRange(descriptor_)) { + format( + "if (has_$1$()) {\n" + " clear_$1$();\n" + "}\n", + oneof->name()); + } + + if (num_weak_fields_) { + format("_weak_field_map_.ClearAll();\n"); + } + format.Outdent(); + format( + "}\n" + "\n"); +} + +void MessageGenerator::GenerateArenaDestructorCode(io::Printer* printer) { + if (HasSimpleBaseClass(descriptor_, options_)) return; + Formatter format(printer, variables_); + + // Generate the ArenaDtor() method. Track whether any fields actually produced + // code that needs to be called. + format("void $classname$::ArenaDtor(void* object) {\n"); + format.Indent(); + + // This code is placed inside a static method, rather than an ordinary one, + // since that simplifies Arena's destructor list (ordinary function pointers + // rather than member function pointers). _this is the object being + // destructed. + format( + "$classname$* _this = reinterpret_cast< $classname$* >(object);\n" + // avoid an "unused variable" warning in case no fields have dtor code. + "(void)_this;\n"); + + bool need_registration = false; + // Process non-oneof fields first. + for (auto field : optimized_order_) { + if (field_generators_.get(field).GenerateArenaDestructorCode(printer)) { + need_registration = true; + } + } + + // Process oneof fields. + // + // Note: As of 10/5/2016, GenerateArenaDestructorCode does not emit anything + // and returns false for oneof fields. + for (auto oneof : OneOfRange(descriptor_)) { + for (auto field : FieldRange(oneof)) { + if (!IsFieldStripped(field, options_) && + field_generators_.get(field).GenerateArenaDestructorCode(printer)) { + need_registration = true; + } + } + } + + format.Outdent(); + format("}\n"); + + if (need_registration) { + format( + "inline void $classname$::RegisterArenaDtor(::$proto_ns$::Arena* " + "arena) {\n" + " if (arena != nullptr) {\n" + " arena->OwnCustomDestructor(this, &$classname$::ArenaDtor);\n" + " }\n" + "}\n"); + } else { + format( + "void $classname$::RegisterArenaDtor(::$proto_ns$::Arena*) {\n" + "}\n"); + } +} + +void MessageGenerator::GenerateConstexprConstructor(io::Printer* printer) { + Formatter format(printer, variables_); + + format( + "constexpr $classname$::$classname$(\n" + " ::$proto_ns$::internal::ConstantInitialized)"); + format.Indent(); + const char* field_sep = ":"; + const auto put_sep = [&] { + format("\n$1$ ", field_sep); + field_sep = ","; + }; + + if (!IsMapEntryMessage(descriptor_)) { + // Process non-oneof fields first. + for (auto field : optimized_order_) { + auto& gen = field_generators_.get(field); + put_sep(); + gen.GenerateConstinitInitializer(printer); + } + + if (IsAnyMessage(descriptor_, options_)) { + put_sep(); + format("_any_metadata_(&type_url_, &value_)"); + } + + if (descriptor_->real_oneof_decl_count() != 0) { + put_sep(); + format("_oneof_case_{}"); + } + } + + format.Outdent(); + format("{}\n"); +} + +void MessageGenerator::GenerateConstructorBody(io::Printer* printer, + std::vector<bool> processed, + bool copy_constructor) const { + Formatter format(printer, variables_); + + const RunMap runs = FindRuns( + optimized_order_, [copy_constructor, this](const FieldDescriptor* field) { + return (copy_constructor && IsPOD(field)) || + (!copy_constructor && + CanBeManipulatedAsRawBytes(field, options_, scc_analyzer_)); + }); + + std::string pod_template; + if (copy_constructor) { + pod_template = + "::memcpy(&$first$_, &from.$first$_,\n" + " static_cast<size_t>(reinterpret_cast<char*>(&$last$_) -\n" + " reinterpret_cast<char*>(&$first$_)) + sizeof($last$_));\n"; + } else { + pod_template = + "::memset(reinterpret_cast<char*>(this) + static_cast<size_t>(\n" + " reinterpret_cast<char*>(&$first$_) - " + "reinterpret_cast<char*>(this)),\n" + " 0, static_cast<size_t>(reinterpret_cast<char*>(&$last$_) -\n" + " reinterpret_cast<char*>(&$first$_)) + sizeof($last$_));\n"; + } + + for (int i = 0; i < optimized_order_.size(); ++i) { + if (processed[i]) { + continue; + } + + const FieldDescriptor* field = optimized_order_[i]; + const auto it = runs.find(field); + + // We only apply the memset technique to runs of more than one field, as + // assignment is better than memset for generated code clarity. + if (it != runs.end() && it->second > 1) { + // Use a memset, then skip run_length fields. + const size_t run_length = it->second; + const std::string first_field_name = FieldName(field); + const std::string last_field_name = + FieldName(optimized_order_[i + run_length - 1]); + + format.Set("first", first_field_name); + format.Set("last", last_field_name); + + format(pod_template.c_str()); + + i += run_length - 1; + // ++i at the top of the loop. + } else { + if (copy_constructor) { + field_generators_.get(field).GenerateCopyConstructorCode(printer); + } else { + field_generators_.get(field).GenerateConstructorCode(printer); + } + } + } +} + +void MessageGenerator::GenerateStructors(io::Printer* printer) { + Formatter format(printer, variables_); + + std::string superclass; + superclass = SuperClassName(descriptor_, options_); + std::string initializer_with_arena = superclass + "(arena, is_message_owned)"; + + if (descriptor_->extension_range_count() > 0) { + initializer_with_arena += ",\n _extensions_(arena)"; + } + + // Initialize member variables with arena constructor. + for (auto field : optimized_order_) { + GOOGLE_DCHECK(!IsFieldStripped(field, options_)); + bool has_arena_constructor = field->is_repeated(); + if (!field->real_containing_oneof() && + (IsLazy(field, options_, scc_analyzer_) || + IsStringPiece(field, options_) || + (IsString(field, options_) && IsStringInlined(field, options_)))) { + has_arena_constructor = true; + } + if (has_arena_constructor) { + initializer_with_arena += + std::string(",\n ") + FieldName(field) + std::string("_(arena)"); + } + } + + if (IsAnyMessage(descriptor_, options_)) { + initializer_with_arena += ",\n _any_metadata_(&type_url_, &value_)"; + } + if (num_weak_fields_ > 0) { + initializer_with_arena += ", _weak_field_map_(arena)"; + } + + std::string initializer_null = superclass + "()"; + if (IsAnyMessage(descriptor_, options_)) { + initializer_null += ", _any_metadata_(&type_url_, &value_)"; + } + if (num_weak_fields_ > 0) { + initializer_null += ", _weak_field_map_(nullptr)"; + } + + format( + "$classname$::$classname$(::$proto_ns$::Arena* arena,\n" + " bool is_message_owned)\n" + " : $1$ {\n", + initializer_with_arena); + + if (!inlined_string_indices_.empty()) { + // Donate inline string fields. + format(" if (arena != nullptr) {\n"); + for (size_t i = 0; i < InlinedStringDonatedSize(); ++i) { + format(" _inlined_string_donated_[$1$] = ~0u;\n", i); + } + format(" }\n"); + } + + if (!HasSimpleBaseClass(descriptor_, options_)) { + format( + " SharedCtor();\n" + " if (!is_message_owned) {\n" + " RegisterArenaDtor(arena);\n" + " }\n"); + } + format( + " // @@protoc_insertion_point(arena_constructor:$full_name$)\n" + "}\n"); + + std::map<std::string, std::string> vars; + SetUnknownFieldsVariable(descriptor_, options_, &vars); + format.AddMap(vars); + + // Generate the copy constructor. + if (UsingImplicitWeakFields(descriptor_->file(), options_)) { + // If we are in lite mode and using implicit weak fields, we generate a + // one-liner copy constructor that delegates to MergeFrom. This saves some + // code size and also cuts down on the complexity of implicit weak fields. + // We might eventually want to do this for all lite protos. + format( + "$classname$::$classname$(const $classname$& from)\n" + " : $classname$() {\n" + " MergeFrom(from);\n" + "}\n"); + } else { + format( + "$classname$::$classname$(const $classname$& from)\n" + " : $superclass$()"); + format.Indent(); + format.Indent(); + format.Indent(); + + // Do not copy inlined_string_donated_, because this is not an arena + // constructor. + + if (!has_bit_indices_.empty()) { + format(",\n_has_bits_(from._has_bits_)"); + } + + std::vector<bool> processed(optimized_order_.size(), false); + for (int i = 0; i < optimized_order_.size(); i++) { + auto field = optimized_order_[i]; + if (!(field->is_repeated() && !(field->is_map())) && + !IsCord(field, options_)) { + continue; + } + + processed[i] = true; + format(",\n$1$_(from.$1$_)", FieldName(field)); + } + + if (IsAnyMessage(descriptor_, options_)) { + format(",\n_any_metadata_(&type_url_, &value_)"); + } + if (num_weak_fields_ > 0) { + format(",\n_weak_field_map_(from._weak_field_map_)"); + } + + format.Outdent(); + format.Outdent(); + format(" {\n"); + + format( + "_internal_metadata_.MergeFrom<$unknown_fields_type$>(from._internal_" + "metadata_);\n"); + + if (descriptor_->extension_range_count() > 0) { + format( + "_extensions_.MergeFrom(internal_default_instance(), " + "from._extensions_);\n"); + } + + GenerateConstructorBody(printer, processed, true); + + // Copy oneof fields. Oneof field requires oneof case check. + for (auto oneof : OneOfRange(descriptor_)) { + format( + "clear_has_$1$();\n" + "switch (from.$1$_case()) {\n", + oneof->name()); + format.Indent(); + for (auto field : FieldRange(oneof)) { + format("case k$1$: {\n", UnderscoresToCamelCase(field->name(), true)); + format.Indent(); + if (!IsFieldStripped(field, options_)) { + field_generators_.get(field).GenerateMergingCode(printer); + } + format("break;\n"); + format.Outdent(); + format("}\n"); + } + format( + "case $1$_NOT_SET: {\n" + " break;\n" + "}\n", + ToUpper(oneof->name())); + format.Outdent(); + format("}\n"); + } + + format.Outdent(); + format( + " // @@protoc_insertion_point(copy_constructor:$full_name$)\n" + "}\n" + "\n"); + } + + // Generate the shared constructor code. + GenerateSharedConstructorCode(printer); + + // Generate the destructor. + if (!HasSimpleBaseClass(descriptor_, options_)) { + format( + "$classname$::~$classname$() {\n" + " // @@protoc_insertion_point(destructor:$full_name$)\n" + " if (GetArenaForAllocation() != nullptr) return;\n" + " SharedDtor();\n" + " _internal_metadata_.Delete<$unknown_fields_type$>();\n" + "}\n" + "\n"); + } else { + // For messages using simple base classes, having no destructor + // allows our vtable to share the same destructor as every other + // message with a simple base class. This works only as long as + // we have no fields needing destruction, of course. (No strings + // or extensions) + } + + // Generate the shared destructor code. + GenerateSharedDestructorCode(printer); + + // Generate the arena-specific destructor code. + GenerateArenaDestructorCode(printer); + + if (!HasSimpleBaseClass(descriptor_, options_)) { + // Generate SetCachedSize. + format( + "void $classname$::SetCachedSize(int size) const {\n" + " _cached_size_.Set(size);\n" + "}\n"); + } +} + +void MessageGenerator::GenerateSourceInProto2Namespace(io::Printer* printer) { + Formatter format(printer, variables_); + format( + "template<> " + "PROTOBUF_NOINLINE " + "$classtype$* Arena::CreateMaybeMessage< $classtype$ >(Arena* arena) {\n" + " return Arena::CreateMessageInternal< $classtype$ >(arena);\n" + "}\n"); +} + +void MessageGenerator::GenerateClear(io::Printer* printer) { + if (HasSimpleBaseClass(descriptor_, options_)) return; + Formatter format(printer, variables_); + + // The maximum number of bytes we will memset to zero without checking their + // hasbit to see if a zero-init is necessary. + const int kMaxUnconditionalPrimitiveBytesClear = 4; + + format( + "void $classname$::Clear() {\n" + "// @@protoc_insertion_point(message_clear_start:$full_name$)\n"); + format.Indent(); + + format( + // TODO(jwb): It would be better to avoid emitting this if it is not used, + // rather than emitting a workaround for the resulting warning. + "$uint32$ cached_has_bits = 0;\n" + "// Prevent compiler warnings about cached_has_bits being unused\n" + "(void) cached_has_bits;\n\n"); + + if (descriptor_->extension_range_count() > 0) { + format("_extensions_.Clear();\n"); + } + + // Collect fields into chunks. Each chunk may have an if() condition that + // checks all hasbits in the chunk and skips it if none are set. + int zero_init_bytes = 0; + for (const auto& field : optimized_order_) { + if (CanInitializeByZeroing(field)) { + zero_init_bytes += EstimateAlignmentSize(field); + } + } + bool merge_zero_init = zero_init_bytes > kMaxUnconditionalPrimitiveBytesClear; + int chunk_count = 0; + + std::vector<std::vector<const FieldDescriptor*>> chunks = CollectFields( + optimized_order_, + [&](const FieldDescriptor* a, const FieldDescriptor* b) -> bool { + chunk_count++; + // This predicate guarantees that there is only a single zero-init + // (memset) per chunk, and if present it will be at the beginning. + bool same = HasByteIndex(a) == HasByteIndex(b) && + a->is_repeated() == b->is_repeated() && + (CanInitializeByZeroing(a) == CanInitializeByZeroing(b) || + (CanInitializeByZeroing(a) && + (chunk_count == 1 || merge_zero_init))); + if (!same) chunk_count = 0; + return same; + }); + + ColdChunkSkipper cold_skipper(options_, chunks, has_bit_indices_, kColdRatio); + int cached_has_word_index = -1; + + for (int chunk_index = 0; chunk_index < chunks.size(); chunk_index++) { + std::vector<const FieldDescriptor*>& chunk = chunks[chunk_index]; + cold_skipper.OnStartChunk(chunk_index, cached_has_word_index, "", printer); + + const FieldDescriptor* memset_start = nullptr; + const FieldDescriptor* memset_end = nullptr; + bool saw_non_zero_init = false; + + for (const auto& field : chunk) { + if (CanInitializeByZeroing(field)) { + GOOGLE_CHECK(!saw_non_zero_init); + if (!memset_start) memset_start = field; + memset_end = field; + } else { + saw_non_zero_init = true; + } + } + + // Whether we wrap this chunk in: + // if (cached_has_bits & <chunk hasbits) { /* chunk. */ } + // We can omit the if() for chunk size 1, or if our fields do not have + // hasbits. I don't understand the rationale for the last part of the + // condition, but it matches the old logic. + const bool have_outer_if = HasBitIndex(chunk.front()) != kNoHasbit && + chunk.size() > 1 && + (memset_end != chunk.back() || merge_zero_init); + + if (have_outer_if) { + // Emit an if() that will let us skip the whole chunk if none are set. + uint32_t chunk_mask = GenChunkMask(chunk, has_bit_indices_); + std::string chunk_mask_str = + StrCat(strings::Hex(chunk_mask, strings::ZERO_PAD_8)); + + // Check (up to) 8 has_bits at a time if we have more than one field in + // this chunk. Due to field layout ordering, we may check + // _has_bits_[last_chunk * 8 / 32] multiple times. + GOOGLE_DCHECK_LE(2, popcnt(chunk_mask)); + GOOGLE_DCHECK_GE(8, popcnt(chunk_mask)); + + if (cached_has_word_index != HasWordIndex(chunk.front())) { + cached_has_word_index = HasWordIndex(chunk.front()); + format("cached_has_bits = _has_bits_[$1$];\n", cached_has_word_index); + } + format("if (cached_has_bits & 0x$1$u) {\n", chunk_mask_str); + format.Indent(); + } + + if (memset_start) { + if (memset_start == memset_end) { + // For clarity, do not memset a single field. + field_generators_.get(memset_start) + .GenerateMessageClearingCode(printer); + } else { + format( + "::memset(&$1$_, 0, static_cast<size_t>(\n" + " reinterpret_cast<char*>(&$2$_) -\n" + " reinterpret_cast<char*>(&$1$_)) + sizeof($2$_));\n", + FieldName(memset_start), FieldName(memset_end)); + } + } + + // Clear all non-zero-initializable fields in the chunk. + for (const auto& field : chunk) { + if (CanInitializeByZeroing(field)) continue; + // It's faster to just overwrite primitive types, but we should only + // clear strings and messages if they were set. + // + // TODO(kenton): Let the CppFieldGenerator decide this somehow. + bool have_enclosing_if = + HasBitIndex(field) != kNoHasbit && + (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE || + field->cpp_type() == FieldDescriptor::CPPTYPE_STRING); + + if (have_enclosing_if) { + PrintPresenceCheck(format, field, has_bit_indices_, printer, + &cached_has_word_index); + } + + field_generators_.get(field).GenerateMessageClearingCode(printer); + + if (have_enclosing_if) { + format.Outdent(); + format("}\n"); + } + } + + if (have_outer_if) { + format.Outdent(); + format("}\n"); + } + + if (cold_skipper.OnEndChunk(chunk_index, printer)) { + // Reset here as it may have been updated in just closed if statement. + cached_has_word_index = -1; + } + } + + // Step 4: Unions. + for (auto oneof : OneOfRange(descriptor_)) { + format("clear_$1$();\n", oneof->name()); + } + + if (num_weak_fields_) { + format("_weak_field_map_.ClearAll();\n"); + } + + // We don't clear donated status. + + if (!has_bit_indices_.empty()) { + // Step 5: Everything else. + format("_has_bits_.Clear();\n"); + } + + std::map<std::string, std::string> vars; + SetUnknownFieldsVariable(descriptor_, options_, &vars); + format.AddMap(vars); + format("_internal_metadata_.Clear<$unknown_fields_type$>();\n"); + + format.Outdent(); + format("}\n"); +} + +void MessageGenerator::GenerateOneofClear(io::Printer* printer) { + // Generated function clears the active field and union case (e.g. foo_case_). + int i = 0; + for (auto oneof : OneOfRange(descriptor_)) { + Formatter format(printer, variables_); + format.Set("oneofname", oneof->name()); + + format( + "void $classname$::clear_$oneofname$() {\n" + "// @@protoc_insertion_point(one_of_clear_start:$full_name$)\n"); + format.Indent(); + format("switch ($oneofname$_case()) {\n"); + format.Indent(); + for (auto field : FieldRange(oneof)) { + format("case k$1$: {\n", UnderscoresToCamelCase(field->name(), true)); + format.Indent(); + // We clear only allocated objects in oneofs + if (!IsStringOrMessage(field) || IsFieldStripped(field, options_)) { + format("// No need to clear\n"); + } else { + field_generators_.get(field).GenerateClearingCode(printer); + } + format("break;\n"); + format.Outdent(); + format("}\n"); + } + format( + "case $1$_NOT_SET: {\n" + " break;\n" + "}\n", + ToUpper(oneof->name())); + format.Outdent(); + format( + "}\n" + "_oneof_case_[$1$] = $2$_NOT_SET;\n", + i, ToUpper(oneof->name())); + format.Outdent(); + format( + "}\n" + "\n"); + i++; + } +} + +void MessageGenerator::GenerateSwap(io::Printer* printer) { + if (HasSimpleBaseClass(descriptor_, options_)) return; + Formatter format(printer, variables_); + + format("void $classname$::InternalSwap($classname$* other) {\n"); + format.Indent(); + format("using std::swap;\n"); + + if (HasGeneratedMethods(descriptor_->file(), options_)) { + if (descriptor_->extension_range_count() > 0) { + format("_extensions_.InternalSwap(&other->_extensions_);\n"); + } + + std::map<std::string, std::string> vars; + SetUnknownFieldsVariable(descriptor_, options_, &vars); + format.AddMap(vars); + if (HasSingularString(descriptor_, options_)) { + format( + "auto* lhs_arena = GetArenaForAllocation();\n" + "auto* rhs_arena = other->GetArenaForAllocation();\n"); + } + format("_internal_metadata_.InternalSwap(&other->_internal_metadata_);\n"); + + if (!has_bit_indices_.empty()) { + for (int i = 0; i < HasBitsSize(); ++i) { + format("swap(_has_bits_[$1$], other->_has_bits_[$1$]);\n", i); + } + } + + // If possible, we swap several fields at once, including padding. + const RunMap runs = + FindRuns(optimized_order_, [this](const FieldDescriptor* field) { + return CanBeManipulatedAsRawBytes(field, options_, scc_analyzer_); + }); + + for (int i = 0; i < optimized_order_.size(); ++i) { + const FieldDescriptor* field = optimized_order_[i]; + const auto it = runs.find(field); + + // We only apply the memswap technique to runs of more than one field, as + // `swap(field_, other.field_)` is better than + // `memswap<...>(&field_, &other.field_)` for generated code readability. + if (it != runs.end() && it->second > 1) { + // Use a memswap, then skip run_length fields. + const size_t run_length = it->second; + const std::string first_field_name = FieldName(field); + const std::string last_field_name = + FieldName(optimized_order_[i + run_length - 1]); + + format.Set("first", first_field_name); + format.Set("last", last_field_name); + + format( + "::PROTOBUF_NAMESPACE_ID::internal::memswap<\n" + " PROTOBUF_FIELD_OFFSET($classname$, $last$_)\n" + " + sizeof($classname$::$last$_)\n" + " - PROTOBUF_FIELD_OFFSET($classname$, $first$_)>(\n" + " reinterpret_cast<char*>(&$first$_),\n" + " reinterpret_cast<char*>(&other->$first$_));\n"); + + i += run_length - 1; + // ++i at the top of the loop. + } else { + field_generators_.get(field).GenerateSwappingCode(printer); + } + } + + for (auto oneof : OneOfRange(descriptor_)) { + format("swap($1$_, other->$1$_);\n", oneof->name()); + } + + for (int i = 0; i < descriptor_->real_oneof_decl_count(); i++) { + format("swap(_oneof_case_[$1$], other->_oneof_case_[$1$]);\n", i); + } + + if (num_weak_fields_) { + format("_weak_field_map_.UnsafeArenaSwap(&other->_weak_field_map_);\n"); + } + } else { + format("GetReflection()->Swap(this, other);"); + } + + format.Outdent(); + format("}\n"); +} + +void MessageGenerator::GenerateMergeFrom(io::Printer* printer) { + Formatter format(printer, variables_); + if (!HasSimpleBaseClass(descriptor_, options_)) { + if (HasDescriptorMethods(descriptor_->file(), options_)) { + // We don't override the generalized MergeFrom (aka that which + // takes in the Message base class as a parameter); instead we just + // let the base Message::MergeFrom take care of it. The base MergeFrom + // knows how to quickly confirm the types exactly match, and if so, will + // use GetClassData() to retrieve the address of MergeImpl, which calls + // the fast MergeFrom overload. Most callers avoid all this by passing + // a "from" message that is the same type as the message being merged + // into, rather than a generic Message. + + format( + "const ::$proto_ns$::Message::ClassData " + "$classname$::_class_data_ = {\n" + " ::$proto_ns$::Message::CopyWithSizeCheck,\n" + " $classname$::MergeImpl\n" + "};\n" + "const ::$proto_ns$::Message::ClassData*" + "$classname$::GetClassData() const { return &_class_data_; }\n" + "\n" + "void $classname$::MergeImpl(::$proto_ns$::Message* to,\n" + " const ::$proto_ns$::Message& from) {\n" + " static_cast<$classname$ *>(to)->MergeFrom(\n" + " static_cast<const $classname$ &>(from));\n" + "}\n" + "\n"); + } else { + // Generate CheckTypeAndMergeFrom(). + format( + "void $classname$::CheckTypeAndMergeFrom(\n" + " const ::$proto_ns$::MessageLite& from) {\n" + " MergeFrom(*::$proto_ns$::internal::DownCast<const $classname$*>(\n" + " &from));\n" + "}\n"); + } + } else { + // In the simple case, we just define ClassData that vectors back to the + // simple implementation of Copy and Merge. + format( + "const ::$proto_ns$::Message::ClassData " + "$classname$::_class_data_ = {\n" + " $superclass$::CopyImpl,\n" + " $superclass$::MergeImpl,\n" + "};\n" + "const ::$proto_ns$::Message::ClassData*" + "$classname$::GetClassData() const { return &_class_data_; }\n" + "\n" + "\n"); + } +} + +void MessageGenerator::GenerateClassSpecificMergeFrom(io::Printer* printer) { + if (HasSimpleBaseClass(descriptor_, options_)) return; + // Generate the class-specific MergeFrom, which avoids the GOOGLE_CHECK and cast. + Formatter format(printer, variables_); + format( + "void $classname$::MergeFrom(const $classname$& from) {\n" + "$annotate_mergefrom$" + "// @@protoc_insertion_point(class_specific_merge_from_start:" + "$full_name$)\n" + " $DCHK$_NE(&from, this);\n"); + format.Indent(); + + format( + "$uint32$ cached_has_bits = 0;\n" + "(void) cached_has_bits;\n\n"); + + std::vector<std::vector<const FieldDescriptor*>> chunks = CollectFields( + optimized_order_, + [&](const FieldDescriptor* a, const FieldDescriptor* b) -> bool { + return HasByteIndex(a) == HasByteIndex(b); + }); + + ColdChunkSkipper cold_skipper(options_, chunks, has_bit_indices_, kColdRatio); + + // cached_has_word_index maintains that: + // cached_has_bits = from._has_bits_[cached_has_word_index] + // for cached_has_word_index >= 0 + int cached_has_word_index = -1; + + for (int chunk_index = 0; chunk_index < chunks.size(); chunk_index++) { + const std::vector<const FieldDescriptor*>& chunk = chunks[chunk_index]; + bool have_outer_if = + chunk.size() > 1 && HasByteIndex(chunk.front()) != kNoHasbit; + cold_skipper.OnStartChunk(chunk_index, cached_has_word_index, "from.", + printer); + + if (have_outer_if) { + // Emit an if() that will let us skip the whole chunk if none are set. + uint32_t chunk_mask = GenChunkMask(chunk, has_bit_indices_); + std::string chunk_mask_str = + StrCat(strings::Hex(chunk_mask, strings::ZERO_PAD_8)); + + // Check (up to) 8 has_bits at a time if we have more than one field in + // this chunk. Due to field layout ordering, we may check + // _has_bits_[last_chunk * 8 / 32] multiple times. + GOOGLE_DCHECK_LE(2, popcnt(chunk_mask)); + GOOGLE_DCHECK_GE(8, popcnt(chunk_mask)); + + if (cached_has_word_index != HasWordIndex(chunk.front())) { + cached_has_word_index = HasWordIndex(chunk.front()); + format("cached_has_bits = from._has_bits_[$1$];\n", + cached_has_word_index); + } + + format("if (cached_has_bits & 0x$1$u) {\n", chunk_mask_str); + format.Indent(); + } + + // Go back and emit merging code for each of the fields we processed. + bool deferred_has_bit_changes = false; + for (const auto field : chunk) { + const FieldGenerator& generator = field_generators_.get(field); + + if (field->is_repeated()) { + generator.GenerateMergingCode(printer); + } else if (field->is_optional() && !HasHasbit(field)) { + // Merge semantics without true field presence: primitive fields are + // merged only if non-zero (numeric) or non-empty (string). + bool have_enclosing_if = + EmitFieldNonDefaultCondition(printer, "from.", field); + generator.GenerateMergingCode(printer); + if (have_enclosing_if) { + format.Outdent(); + format("}\n"); + } + } else if (field->options().weak() || + cached_has_word_index != HasWordIndex(field)) { + // Check hasbit, not using cached bits. + GOOGLE_CHECK(HasHasbit(field)); + format("if (from._internal_has_$1$()) {\n", FieldName(field)); + format.Indent(); + generator.GenerateMergingCode(printer); + format.Outdent(); + format("}\n"); + } else { + // Check hasbit, using cached bits. + GOOGLE_CHECK(HasHasbit(field)); + int has_bit_index = has_bit_indices_[field->index()]; + const std::string mask = StrCat( + strings::Hex(1u << (has_bit_index % 32), strings::ZERO_PAD_8)); + format("if (cached_has_bits & 0x$1$u) {\n", mask); + format.Indent(); + + if (have_outer_if && IsPOD(field)) { + // Defer hasbit modification until the end of chunk. + // This can reduce the number of loads/stores by up to 7 per 8 fields. + deferred_has_bit_changes = true; + generator.GenerateCopyConstructorCode(printer); + } else { + generator.GenerateMergingCode(printer); + } + + format.Outdent(); + format("}\n"); + } + } + + if (have_outer_if) { + if (deferred_has_bit_changes) { + // Flush the has bits for the primitives we deferred. + GOOGLE_CHECK_LE(0, cached_has_word_index); + format("_has_bits_[$1$] |= cached_has_bits;\n", cached_has_word_index); + } + + format.Outdent(); + format("}\n"); + } + + if (cold_skipper.OnEndChunk(chunk_index, printer)) { + // Reset here as it may have been updated in just closed if statement. + cached_has_word_index = -1; + } + } + + // Merge oneof fields. Oneof field requires oneof case check. + for (auto oneof : OneOfRange(descriptor_)) { + format("switch (from.$1$_case()) {\n", oneof->name()); + format.Indent(); + for (auto field : FieldRange(oneof)) { + format("case k$1$: {\n", UnderscoresToCamelCase(field->name(), true)); + format.Indent(); + if (!IsFieldStripped(field, options_)) { + field_generators_.get(field).GenerateMergingCode(printer); + } + format("break;\n"); + format.Outdent(); + format("}\n"); + } + format( + "case $1$_NOT_SET: {\n" + " break;\n" + "}\n", + ToUpper(oneof->name())); + format.Outdent(); + format("}\n"); + } + if (num_weak_fields_) { + format("_weak_field_map_.MergeFrom(from._weak_field_map_);\n"); + } + + // Merging of extensions and unknown fields is done last, to maximize + // the opportunity for tail calls. + if (descriptor_->extension_range_count() > 0) { + format( + "_extensions_.MergeFrom(internal_default_instance(), " + "from._extensions_);\n"); + } + + format( + "_internal_metadata_.MergeFrom<$unknown_fields_type$>(from._internal_" + "metadata_);\n"); + + format.Outdent(); + format("}\n"); +} + +void MessageGenerator::GenerateCopyFrom(io::Printer* printer) { + if (HasSimpleBaseClass(descriptor_, options_)) return; + Formatter format(printer, variables_); + if (HasDescriptorMethods(descriptor_->file(), options_)) { + // We don't override the generalized CopyFrom (aka that which + // takes in the Message base class as a parameter); instead we just + // let the base Message::CopyFrom take care of it. The base MergeFrom + // knows how to quickly confirm the types exactly match, and if so, will + // use GetClassData() to get the address of Message::CopyWithSizeCheck, + // which calls Clear() and then MergeFrom(), as well as making sure that + // clearing the destination message doesn't alter the size of the source, + // when in debug builds. + // Most callers avoid this by passing a "from" message that is the same + // type as the message being merged into, rather than a generic Message. + } + + // Generate the class-specific CopyFrom. + format( + "void $classname$::CopyFrom(const $classname$& from) {\n" + "// @@protoc_insertion_point(class_specific_copy_from_start:" + "$full_name$)\n"); + format.Indent(); + + format("if (&from == this) return;\n"); + + if (!options_.opensource_runtime) { + // This check is disabled in the opensource release because we're + // concerned that many users do not define NDEBUG in their release builds. + format( + "#ifndef NDEBUG\n" + "size_t from_size = from.ByteSizeLong();\n" + "#endif\n" + "Clear();\n" + "#ifndef NDEBUG\n" + "$CHK$_EQ(from_size, from.ByteSizeLong())\n" + " << \"Source of CopyFrom changed when clearing target. Either \"\n" + " \"source is a nested message in target (not allowed), or \"\n" + " \"another thread is modifying the source.\";\n" + "#endif\n"); + } else { + format("Clear();\n"); + } + format("MergeFrom(from);\n"); + + format.Outdent(); + format("}\n"); +} + +void MessageGenerator::GenerateVerify(io::Printer* printer) { +} + +void MessageGenerator::GenerateSerializeOneofFields( + io::Printer* printer, const std::vector<const FieldDescriptor*>& fields) { + Formatter format(printer, variables_); + GOOGLE_CHECK(!fields.empty()); + if (fields.size() == 1) { + GenerateSerializeOneField(printer, fields[0], -1); + return; + } + // We have multiple mutually exclusive choices. Emit a switch statement. + const OneofDescriptor* oneof = fields[0]->containing_oneof(); + format("switch ($1$_case()) {\n", oneof->name()); + format.Indent(); + for (auto field : fields) { + format("case k$1$: {\n", UnderscoresToCamelCase(field->name(), true)); + format.Indent(); + field_generators_.get(field).GenerateSerializeWithCachedSizesToArray( + printer); + format("break;\n"); + format.Outdent(); + format("}\n"); + } + format.Outdent(); + // Doing nothing is an option. + format( + " default: ;\n" + "}\n"); +} + +void MessageGenerator::GenerateSerializeOneField(io::Printer* printer, + const FieldDescriptor* field, + int cached_has_bits_index) { + Formatter format(printer, variables_); + if (!field->options().weak()) { + // For weakfields, PrintFieldComment is called during iteration. + PrintFieldComment(format, field); + } + + bool have_enclosing_if = false; + if (field->options().weak()) { + } else if (HasHasbit(field)) { + // Attempt to use the state of cached_has_bits, if possible. + int has_bit_index = HasBitIndex(field); + if (cached_has_bits_index == has_bit_index / 32) { + const std::string mask = + StrCat(strings::Hex(1u << (has_bit_index % 32), strings::ZERO_PAD_8)); + + format("if (cached_has_bits & 0x$1$u) {\n", mask); + } else { + format("if (_internal_has_$1$()) {\n", FieldName(field)); + } + + format.Indent(); + have_enclosing_if = true; + } else if (field->is_optional() && !HasHasbit(field)) { + have_enclosing_if = EmitFieldNonDefaultCondition(printer, "this->", field); + } + + field_generators_.get(field).GenerateSerializeWithCachedSizesToArray(printer); + + if (have_enclosing_if) { + format.Outdent(); + format("}\n"); + } + format("\n"); +} + +void MessageGenerator::GenerateSerializeOneExtensionRange( + io::Printer* printer, const Descriptor::ExtensionRange* range) { + std::map<std::string, std::string> vars = variables_; + vars["start"] = StrCat(range->start); + vars["end"] = StrCat(range->end); + Formatter format(printer, vars); + format("// Extension range [$start$, $end$)\n"); + format( + "target = _extensions_._InternalSerialize(\n" + "internal_default_instance(), $start$, $end$, target, stream);\n\n"); +} + +void MessageGenerator::GenerateSerializeWithCachedSizesToArray( + io::Printer* printer) { + if (HasSimpleBaseClass(descriptor_, options_)) return; + Formatter format(printer, variables_); + if (descriptor_->options().message_set_wire_format()) { + // Special-case MessageSet. + format( + "$uint8$* $classname$::_InternalSerialize(\n" + " $uint8$* target, ::$proto_ns$::io::EpsCopyOutputStream* stream) " + "const {\n" + "$annotate_serialize$" + " target = _extensions_." + "InternalSerializeMessageSetWithCachedSizesToArray(\n" // + "internal_default_instance(), target, stream);\n"); + std::map<std::string, std::string> vars; + SetUnknownFieldsVariable(descriptor_, options_, &vars); + format.AddMap(vars); + format( + " target = ::$proto_ns$::internal::" + "InternalSerializeUnknownMessageSetItemsToArray(\n" + " $unknown_fields$, target, stream);\n"); + format( + " return target;\n" + "}\n"); + return; + } + + format( + "$uint8$* $classname$::_InternalSerialize(\n" + " $uint8$* target, ::$proto_ns$::io::EpsCopyOutputStream* stream) " + "const {\n" + "$annotate_serialize$"); + format.Indent(); + + format("// @@protoc_insertion_point(serialize_to_array_start:$full_name$)\n"); + + if (!ShouldSerializeInOrder(descriptor_, options_)) { + format.Outdent(); + format("#ifdef NDEBUG\n"); + format.Indent(); + } + + GenerateSerializeWithCachedSizesBody(printer); + + if (!ShouldSerializeInOrder(descriptor_, options_)) { + format.Outdent(); + format("#else // NDEBUG\n"); + format.Indent(); + + GenerateSerializeWithCachedSizesBodyShuffled(printer); + + format.Outdent(); + format("#endif // !NDEBUG\n"); + format.Indent(); + } + + format("// @@protoc_insertion_point(serialize_to_array_end:$full_name$)\n"); + + format.Outdent(); + format( + " return target;\n" + "}\n"); +} + +void MessageGenerator::GenerateSerializeWithCachedSizesBody( + io::Printer* printer) { + if (HasSimpleBaseClass(descriptor_, options_)) return; + Formatter format(printer, variables_); + // If there are multiple fields in a row from the same oneof then we + // coalesce them and emit a switch statement. This is more efficient + // because it lets the C++ compiler know this is a "at most one can happen" + // situation. If we emitted "if (has_x()) ...; if (has_y()) ..." the C++ + // compiler's emitted code might check has_y() even when has_x() is true. + class LazySerializerEmitter { + public: + LazySerializerEmitter(MessageGenerator* mg, io::Printer* printer) + : mg_(mg), + format_(printer), + eager_(IsProto3(mg->descriptor_->file())), + cached_has_bit_index_(kNoHasbit) {} + + ~LazySerializerEmitter() { Flush(); } + + // If conditions allow, try to accumulate a run of fields from the same + // oneof, and handle them at the next Flush(). + void Emit(const FieldDescriptor* field) { + if (eager_ || MustFlush(field)) { + Flush(); + } + if (!field->real_containing_oneof()) { + // TODO(ckennelly): Defer non-oneof fields similarly to oneof fields. + + if (!field->options().weak() && !field->is_repeated() && !eager_) { + // We speculatively load the entire _has_bits_[index] contents, even + // if it is for only one field. Deferring non-oneof emitting would + // allow us to determine whether this is going to be useful. + int has_bit_index = mg_->has_bit_indices_[field->index()]; + if (cached_has_bit_index_ != has_bit_index / 32) { + // Reload. + int new_index = has_bit_index / 32; + + format_("cached_has_bits = _has_bits_[$1$];\n", new_index); + + cached_has_bit_index_ = new_index; + } + } + + mg_->GenerateSerializeOneField(format_.printer(), field, + cached_has_bit_index_); + } else { + v_.push_back(field); + } + } + + void EmitIfNotNull(const FieldDescriptor* field) { + if (field != nullptr) { + Emit(field); + } + } + + void Flush() { + if (!v_.empty()) { + mg_->GenerateSerializeOneofFields(format_.printer(), v_); + v_.clear(); + } + } + + private: + // If we have multiple fields in v_ then they all must be from the same + // oneof. Would adding field to v_ break that invariant? + bool MustFlush(const FieldDescriptor* field) { + return !v_.empty() && + v_[0]->containing_oneof() != field->containing_oneof(); + } + + MessageGenerator* mg_; + Formatter format_; + const bool eager_; + std::vector<const FieldDescriptor*> v_; + + // cached_has_bit_index_ maintains that: + // cached_has_bits = from._has_bits_[cached_has_bit_index_] + // for cached_has_bit_index_ >= 0 + int cached_has_bit_index_; + }; + + class LazyExtensionRangeEmitter { + public: + LazyExtensionRangeEmitter(MessageGenerator* mg, io::Printer* printer) + : mg_(mg), format_(printer) {} + + void AddToRange(const Descriptor::ExtensionRange* range) { + if (!has_current_range_) { + current_combined_range_ = *range; + has_current_range_ = true; + } else { + current_combined_range_.start = + std::min(current_combined_range_.start, range->start); + current_combined_range_.end = + std::max(current_combined_range_.end, range->end); + } + } + + void Flush() { + if (has_current_range_) { + mg_->GenerateSerializeOneExtensionRange(format_.printer(), + ¤t_combined_range_); + } + has_current_range_ = false; + } + + private: + MessageGenerator* mg_; + Formatter format_; + bool has_current_range_ = false; + Descriptor::ExtensionRange current_combined_range_; + }; + + // We need to track the largest weak field, because weak fields are serialized + // differently than normal fields. The WeakFieldMap::FieldWriter will + // serialize all weak fields that are ordinally between the last serialized + // weak field and the current field. In order to guarantee that all weak + // fields are serialized, we need to make sure to emit the code to serialize + // the largest weak field present at some point. + class LargestWeakFieldHolder { + public: + const FieldDescriptor* Release() { + const FieldDescriptor* result = field_; + field_ = nullptr; + return result; + } + void ReplaceIfLarger(const FieldDescriptor* field) { + if (field_ == nullptr || field_->number() < field->number()) { + field_ = field; + } + } + + private: + const FieldDescriptor* field_ = nullptr; + }; + + std::vector<const FieldDescriptor*> ordered_fields = + SortFieldsByNumber(descriptor_); + + std::vector<const Descriptor::ExtensionRange*> sorted_extensions; + sorted_extensions.reserve(descriptor_->extension_range_count()); + for (int i = 0; i < descriptor_->extension_range_count(); ++i) { + sorted_extensions.push_back(descriptor_->extension_range(i)); + } + std::sort(sorted_extensions.begin(), sorted_extensions.end(), + ExtensionRangeSorter()); + if (num_weak_fields_) { + format( + "::$proto_ns$::internal::WeakFieldMap::FieldWriter field_writer(" + "_weak_field_map_);\n"); + } + + format( + "$uint32$ cached_has_bits = 0;\n" + "(void) cached_has_bits;\n\n"); + + // Merge the fields and the extension ranges, both sorted by field number. + { + LazySerializerEmitter e(this, printer); + LazyExtensionRangeEmitter re(this, printer); + LargestWeakFieldHolder largest_weak_field; + int i, j; + for (i = 0, j = 0; + i < ordered_fields.size() || j < sorted_extensions.size();) { + if ((j == sorted_extensions.size()) || + (i < descriptor_->field_count() && + ordered_fields[i]->number() < sorted_extensions[j]->start)) { + const FieldDescriptor* field = ordered_fields[i++]; + if (IsFieldStripped(field, options_)) { + continue; + } + re.Flush(); + if (field->options().weak()) { + largest_weak_field.ReplaceIfLarger(field); + PrintFieldComment(format, field); + } else { + e.EmitIfNotNull(largest_weak_field.Release()); + e.Emit(field); + } + } else { + e.EmitIfNotNull(largest_weak_field.Release()); + e.Flush(); + re.AddToRange(sorted_extensions[j++]); + } + } + re.Flush(); + e.EmitIfNotNull(largest_weak_field.Release()); + } + + std::map<std::string, std::string> vars; + SetUnknownFieldsVariable(descriptor_, options_, &vars); + format.AddMap(vars); + format("if (PROTOBUF_PREDICT_FALSE($have_unknown_fields$)) {\n"); + format.Indent(); + if (UseUnknownFieldSet(descriptor_->file(), options_)) { + format( + "target = " + "::$proto_ns$::internal::WireFormat::" + "InternalSerializeUnknownFieldsToArray(\n" + " $unknown_fields$, target, stream);\n"); + } else { + format( + "target = stream->WriteRaw($unknown_fields$.data(),\n" + " static_cast<int>($unknown_fields$.size()), target);\n"); + } + format.Outdent(); + format("}\n"); +} + +void MessageGenerator::GenerateSerializeWithCachedSizesBodyShuffled( + io::Printer* printer) { + Formatter format(printer, variables_); + + std::vector<const FieldDescriptor*> ordered_fields = + SortFieldsByNumber(descriptor_); + ordered_fields.erase( + std::remove_if(ordered_fields.begin(), ordered_fields.end(), + [this](const FieldDescriptor* f) { + return !IsFieldUsed(f, options_); + }), + ordered_fields.end()); + + std::vector<const Descriptor::ExtensionRange*> sorted_extensions; + sorted_extensions.reserve(descriptor_->extension_range_count()); + for (int i = 0; i < descriptor_->extension_range_count(); ++i) { + sorted_extensions.push_back(descriptor_->extension_range(i)); + } + std::sort(sorted_extensions.begin(), sorted_extensions.end(), + ExtensionRangeSorter()); + + int num_fields = ordered_fields.size() + sorted_extensions.size(); + constexpr int kLargePrime = 1000003; + GOOGLE_CHECK_LT(num_fields, kLargePrime) + << "Prime offset must be greater than the number of fields to ensure " + "those are coprime."; + + if (num_weak_fields_) { + format( + "::$proto_ns$::internal::WeakFieldMap::FieldWriter field_writer(" + "_weak_field_map_);\n"); + } + + format("for (int i = $1$; i >= 0; i-- ) {\n", num_fields - 1); + + format.Indent(); + format("switch(i) {\n"); + format.Indent(); + + int index = 0; + for (const auto* f : ordered_fields) { + format("case $1$: {\n", index++); + format.Indent(); + + GenerateSerializeOneField(printer, f, -1); + + format("break;\n"); + format.Outdent(); + format("}\n"); + } + + for (const auto* r : sorted_extensions) { + format("case $1$: {\n", index++); + format.Indent(); + + GenerateSerializeOneExtensionRange(printer, r); + + format("break;\n"); + format.Outdent(); + format("}\n"); + } + + format( + "default: {\n" + " $DCHK$(false) << \"Unexpected index: \" << i;\n" + "}\n"); + format.Outdent(); + format("}\n"); + + format.Outdent(); + format("}\n"); + + std::map<std::string, std::string> vars; + SetUnknownFieldsVariable(descriptor_, options_, &vars); + format.AddMap(vars); + format("if (PROTOBUF_PREDICT_FALSE($have_unknown_fields$)) {\n"); + format.Indent(); + if (UseUnknownFieldSet(descriptor_->file(), options_)) { + format( + "target = " + "::$proto_ns$::internal::WireFormat::" + "InternalSerializeUnknownFieldsToArray(\n" + " $unknown_fields$, target, stream);\n"); + } else { + format( + "target = stream->WriteRaw($unknown_fields$.data(),\n" + " static_cast<int>($unknown_fields$.size()), target);\n"); + } + format.Outdent(); + format("}\n"); +} + +std::vector<uint32_t> MessageGenerator::RequiredFieldsBitMask() const { + const int array_size = HasBitsSize(); + std::vector<uint32_t> masks(array_size, 0); + + for (auto field : FieldRange(descriptor_)) { + if (!field->is_required()) { + continue; + } + + const int has_bit_index = has_bit_indices_[field->index()]; + masks[has_bit_index / 32] |= static_cast<uint32_t>(1) + << (has_bit_index % 32); + } + return masks; +} + +void MessageGenerator::GenerateByteSize(io::Printer* printer) { + if (HasSimpleBaseClass(descriptor_, options_)) return; + Formatter format(printer, variables_); + + if (descriptor_->options().message_set_wire_format()) { + // Special-case MessageSet. + std::map<std::string, std::string> vars; + SetUnknownFieldsVariable(descriptor_, options_, &vars); + format.AddMap(vars); + format( + "size_t $classname$::ByteSizeLong() const {\n" + "$annotate_bytesize$" + "// @@protoc_insertion_point(message_set_byte_size_start:$full_name$)\n" + " size_t total_size = _extensions_.MessageSetByteSize();\n" + " if ($have_unknown_fields$) {\n" + " total_size += ::$proto_ns$::internal::\n" + " ComputeUnknownMessageSetItemsSize($unknown_fields$);\n" + " }\n" + " int cached_size = " + "::$proto_ns$::internal::ToCachedSize(total_size);\n" + " SetCachedSize(cached_size);\n" + " return total_size;\n" + "}\n"); + return; + } + + if (num_required_fields_ > 1) { + // Emit a function (rarely used, we hope) that handles the required fields + // by checking for each one individually. + format( + "size_t $classname$::RequiredFieldsByteSizeFallback() const {\n" + "// @@protoc_insertion_point(required_fields_byte_size_fallback_start:" + "$full_name$)\n"); + format.Indent(); + format("size_t total_size = 0;\n"); + for (auto field : optimized_order_) { + if (field->is_required()) { + format( + "\n" + "if (_internal_has_$1$()) {\n", + FieldName(field)); + format.Indent(); + PrintFieldComment(format, field); + field_generators_.get(field).GenerateByteSize(printer); + format.Outdent(); + format("}\n"); + } + } + format( + "\n" + "return total_size;\n"); + format.Outdent(); + format("}\n"); + } + + format( + "size_t $classname$::ByteSizeLong() const {\n" + "$annotate_bytesize$" + "// @@protoc_insertion_point(message_byte_size_start:$full_name$)\n"); + format.Indent(); + format( + "size_t total_size = 0;\n" + "\n"); + + if (descriptor_->extension_range_count() > 0) { + format( + "total_size += _extensions_.ByteSize();\n" + "\n"); + } + + std::map<std::string, std::string> vars; + SetUnknownFieldsVariable(descriptor_, options_, &vars); + format.AddMap(vars); + + // Handle required fields (if any). We expect all of them to be + // present, so emit one conditional that checks for that. If they are all + // present then the fast path executes; otherwise the slow path executes. + if (num_required_fields_ > 1) { + // The fast path works if all required fields are present. + const std::vector<uint32_t> masks_for_has_bits = RequiredFieldsBitMask(); + format("if ($1$) { // All required fields are present.\n", + ConditionalToCheckBitmasks(masks_for_has_bits)); + format.Indent(); + // Oneof fields cannot be required, so optimized_order_ contains all of the + // fields that we need to potentially emit. + for (auto field : optimized_order_) { + if (!field->is_required()) continue; + PrintFieldComment(format, field); + field_generators_.get(field).GenerateByteSize(printer); + format("\n"); + } + format.Outdent(); + format( + "} else {\n" // the slow path + " total_size += RequiredFieldsByteSizeFallback();\n" + "}\n"); + } else { + // num_required_fields_ <= 1: no need to be tricky + for (auto field : optimized_order_) { + if (!field->is_required()) continue; + PrintFieldComment(format, field); + format("if (_internal_has_$1$()) {\n", FieldName(field)); + format.Indent(); + field_generators_.get(field).GenerateByteSize(printer); + format.Outdent(); + format("}\n"); + } + } + + std::vector<std::vector<const FieldDescriptor*>> chunks = CollectFields( + optimized_order_, + [&](const FieldDescriptor* a, const FieldDescriptor* b) -> bool { + return a->label() == b->label() && HasByteIndex(a) == HasByteIndex(b); + }); + + // Remove chunks with required fields. + chunks.erase(std::remove_if(chunks.begin(), chunks.end(), IsRequired), + chunks.end()); + + ColdChunkSkipper cold_skipper(options_, chunks, has_bit_indices_, kColdRatio); + int cached_has_word_index = -1; + + format( + "$uint32$ cached_has_bits = 0;\n" + "// Prevent compiler warnings about cached_has_bits being unused\n" + "(void) cached_has_bits;\n\n"); + + for (int chunk_index = 0; chunk_index < chunks.size(); chunk_index++) { + const std::vector<const FieldDescriptor*>& chunk = chunks[chunk_index]; + const bool have_outer_if = + chunk.size() > 1 && HasWordIndex(chunk[0]) != kNoHasbit; + cold_skipper.OnStartChunk(chunk_index, cached_has_word_index, "", printer); + + if (have_outer_if) { + // Emit an if() that will let us skip the whole chunk if none are set. + uint32_t chunk_mask = GenChunkMask(chunk, has_bit_indices_); + std::string chunk_mask_str = + StrCat(strings::Hex(chunk_mask, strings::ZERO_PAD_8)); + + // Check (up to) 8 has_bits at a time if we have more than one field in + // this chunk. Due to field layout ordering, we may check + // _has_bits_[last_chunk * 8 / 32] multiple times. + GOOGLE_DCHECK_LE(2, popcnt(chunk_mask)); + GOOGLE_DCHECK_GE(8, popcnt(chunk_mask)); + + if (cached_has_word_index != HasWordIndex(chunk.front())) { + cached_has_word_index = HasWordIndex(chunk.front()); + format("cached_has_bits = _has_bits_[$1$];\n", cached_has_word_index); + } + format("if (cached_has_bits & 0x$1$u) {\n", chunk_mask_str); + format.Indent(); + } + + // Go back and emit checks for each of the fields we processed. + for (int j = 0; j < chunk.size(); j++) { + const FieldDescriptor* field = chunk[j]; + const FieldGenerator& generator = field_generators_.get(field); + bool have_enclosing_if = false; + bool need_extra_newline = false; + + PrintFieldComment(format, field); + + if (field->is_repeated()) { + // No presence check is required. + need_extra_newline = true; + } else if (HasHasbit(field)) { + PrintPresenceCheck(format, field, has_bit_indices_, printer, + &cached_has_word_index); + have_enclosing_if = true; + } else { + // Without field presence: field is serialized only if it has a + // non-default value. + have_enclosing_if = + EmitFieldNonDefaultCondition(printer, "this->", field); + } + + generator.GenerateByteSize(printer); + + if (have_enclosing_if) { + format.Outdent(); + format( + "}\n" + "\n"); + } + if (need_extra_newline) { + format("\n"); + } + } + + if (have_outer_if) { + format.Outdent(); + format("}\n"); + } + + if (cold_skipper.OnEndChunk(chunk_index, printer)) { + // Reset here as it may have been updated in just closed if statement. + cached_has_word_index = -1; + } + } + + // Fields inside a oneof don't use _has_bits_ so we count them in a separate + // pass. + for (auto oneof : OneOfRange(descriptor_)) { + format("switch ($1$_case()) {\n", oneof->name()); + format.Indent(); + for (auto field : FieldRange(oneof)) { + PrintFieldComment(format, field); + format("case k$1$: {\n", UnderscoresToCamelCase(field->name(), true)); + format.Indent(); + if (!IsFieldStripped(field, options_)) { + field_generators_.get(field).GenerateByteSize(printer); + } + format("break;\n"); + format.Outdent(); + format("}\n"); + } + format( + "case $1$_NOT_SET: {\n" + " break;\n" + "}\n", + ToUpper(oneof->name())); + format.Outdent(); + format("}\n"); + } + + if (num_weak_fields_) { + // TagSize + MessageSize + format("total_size += _weak_field_map_.ByteSizeLong();\n"); + } + + if (UseUnknownFieldSet(descriptor_->file(), options_)) { + // We go out of our way to put the computation of the uncommon path of + // unknown fields in tail position. This allows for better code generation + // of this function for simple protos. + format( + "return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);\n"); + } else { + format("if (PROTOBUF_PREDICT_FALSE($have_unknown_fields$)) {\n"); + format(" total_size += $unknown_fields$.size();\n"); + format("}\n"); + + // We update _cached_size_ even though this is a const method. Because + // const methods might be called concurrently this needs to be atomic + // operations or the program is undefined. In practice, since any + // concurrent writes will be writing the exact same value, normal writes + // will work on all common processors. We use a dedicated wrapper class to + // abstract away the underlying atomic. This makes it easier on platforms + // where even relaxed memory order might have perf impact to replace it with + // ordinary loads and stores. + format( + "int cached_size = ::$proto_ns$::internal::ToCachedSize(total_size);\n" + "SetCachedSize(cached_size);\n" + "return total_size;\n"); + } + + format.Outdent(); + format("}\n"); +} + +void MessageGenerator::GenerateIsInitialized(io::Printer* printer) { + if (HasSimpleBaseClass(descriptor_, options_)) return; + Formatter format(printer, variables_); + format("bool $classname$::IsInitialized() const {\n"); + format.Indent(); + + if (descriptor_->extension_range_count() > 0) { + format( + "if (!_extensions_.IsInitialized()) {\n" + " return false;\n" + "}\n\n"); + } + + if (num_required_fields_ > 0) { + format( + "if (_Internal::MissingRequiredFields(_has_bits_))" + " return false;\n"); + } + + // Now check that all non-oneof embedded messages are initialized. + for (auto field : optimized_order_) { + field_generators_.get(field).GenerateIsInitialized(printer); + } + if (num_weak_fields_) { + // For Weak fields. + format("if (!_weak_field_map_.IsInitialized()) return false;\n"); + } + // Go through the oneof fields, emitting a switch if any might have required + // fields. + for (auto oneof : OneOfRange(descriptor_)) { + bool has_required_fields = false; + for (auto field : FieldRange(oneof)) { + if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && + !ShouldIgnoreRequiredFieldCheck(field, options_) && + scc_analyzer_->HasRequiredFields(field->message_type())) { + has_required_fields = true; + break; + } + } + + if (!has_required_fields) { + continue; + } + + format("switch ($1$_case()) {\n", oneof->name()); + format.Indent(); + for (auto field : FieldRange(oneof)) { + format("case k$1$: {\n", UnderscoresToCamelCase(field->name(), true)); + format.Indent(); + if (!IsFieldStripped(field, options_)) { + field_generators_.get(field).GenerateIsInitialized(printer); + } + format("break;\n"); + format.Outdent(); + format("}\n"); + } + format( + "case $1$_NOT_SET: {\n" + " break;\n" + "}\n", + ToUpper(oneof->name())); + format.Outdent(); + format("}\n"); + } + + format.Outdent(); + format( + " return true;\n" + "}\n"); +} + +} // namespace cpp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#include <port_undef.inc> diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_message.h b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_message.h new file mode 100644 index 00000000..592af570 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_message.h @@ -0,0 +1,231 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_H__ +#define GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_H__ + +#include <cstdint> +#include <memory> +#include <set> +#include <string> + +#include <compiler/cpp/cpp_field.h> +#include <compiler/cpp/cpp_helpers.h> +#include <compiler/cpp/cpp_message_layout_helper.h> +#include <compiler/cpp/cpp_options.h> +#include <compiler/cpp/cpp_parse_function_generator.h> + +namespace google { +namespace protobuf { +namespace io { +class Printer; // printer.h +} +} // namespace protobuf +} // namespace google + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { + +class EnumGenerator; // enum.h +class ExtensionGenerator; // extension.h + +class MessageGenerator { + public: + // See generator.cc for the meaning of dllexport_decl. + MessageGenerator(const Descriptor* descriptor, + const std::map<std::string, std::string>& vars, + int index_in_file_messages, const Options& options, + MessageSCCAnalyzer* scc_analyzer); + ~MessageGenerator(); + + // Append the two types of nested generators to the corresponding vector. + void AddGenerators( + std::vector<std::unique_ptr<EnumGenerator>>* enum_generators, + std::vector<std::unique_ptr<ExtensionGenerator>>* extension_generators); + + // Generate definitions for this class and all its nested types. + void GenerateClassDefinition(io::Printer* printer); + + // Generate definitions of inline methods (placed at the end of the header + // file). + void GenerateInlineMethods(io::Printer* printer); + + // Source file stuff. + + // Generate all non-inline methods for this class. + void GenerateClassMethods(io::Printer* printer); + + // Generate source file code that should go outside any namespace. + void GenerateSourceInProto2Namespace(io::Printer* printer); + + private: + // Generate declarations and definitions of accessors for fields. + void GenerateFieldAccessorDeclarations(io::Printer* printer); + void GenerateFieldAccessorDefinitions(io::Printer* printer); + + // Generate the table-driven parsing array. Returns the number of entries + // generated. + size_t GenerateParseOffsets(io::Printer* printer); + size_t GenerateParseAuxTable(io::Printer* printer); + // Generates a ParseTable entry. Returns whether the proto uses + // table-driven parsing. + bool GenerateParseTable(io::Printer* printer, size_t offset, + size_t aux_offset); + + // Generate the field offsets array. Returns the a pair of the total number + // of entries generated and the index of the first has_bit entry. + std::pair<size_t, size_t> GenerateOffsets(io::Printer* printer); + void GenerateSchema(io::Printer* printer, int offset, int has_offset); + // For each field generates a table entry describing the field for the + // table driven serializer. + int GenerateFieldMetadata(io::Printer* printer); + + // Generate constructors and destructor. + void GenerateStructors(io::Printer* printer); + + // The compiler typically generates multiple copies of each constructor and + // destructor: http://gcc.gnu.org/bugs.html#nonbugs_cxx + // Placing common code in a separate method reduces the generated code size. + // + // Generate the shared constructor code. + void GenerateSharedConstructorCode(io::Printer* printer); + // Generate the shared destructor code. + void GenerateSharedDestructorCode(io::Printer* printer); + // Generate the arena-specific destructor code. + void GenerateArenaDestructorCode(io::Printer* printer); + + // Generate the constexpr constructor for constant initialization of the + // default instance. + void GenerateConstexprConstructor(io::Printer* printer); + + // Generate standard Message methods. + void GenerateClear(io::Printer* printer); + void GenerateOneofClear(io::Printer* printer); + void GenerateVerify(io::Printer* printer); + void GenerateSerializeWithCachedSizes(io::Printer* printer); + void GenerateSerializeWithCachedSizesToArray(io::Printer* printer); + void GenerateSerializeWithCachedSizesBody(io::Printer* printer); + void GenerateSerializeWithCachedSizesBodyShuffled(io::Printer* printer); + void GenerateByteSize(io::Printer* printer); + void GenerateMergeFrom(io::Printer* printer); + void GenerateClassSpecificMergeFrom(io::Printer* printer); + void GenerateCopyFrom(io::Printer* printer); + void GenerateSwap(io::Printer* printer); + void GenerateIsInitialized(io::Printer* printer); + + // Helpers for GenerateSerializeWithCachedSizes(). + // + // cached_has_bit_index maintains that: + // cached_has_bits = _has_bits_[cached_has_bit_index] + // for cached_has_bit_index >= 0 + void GenerateSerializeOneField(io::Printer* printer, + const FieldDescriptor* field, + int cached_has_bits_index); + // Generate a switch statement to serialize 2+ fields from the same oneof. + // Or, if fields.size() == 1, just call GenerateSerializeOneField(). + void GenerateSerializeOneofFields( + io::Printer* printer, const std::vector<const FieldDescriptor*>& fields); + void GenerateSerializeOneExtensionRange( + io::Printer* printer, const Descriptor::ExtensionRange* range); + + // Generates has_foo() functions and variables for singular field has-bits. + void GenerateSingularFieldHasBits(const FieldDescriptor* field, + Formatter format); + // Generates has_foo() functions and variables for oneof field has-bits. + void GenerateOneofHasBits(io::Printer* printer); + // Generates has_foo_bar() functions for oneof members. + void GenerateOneofMemberHasBits(const FieldDescriptor* field, + const Formatter& format); + // Generates the clear_foo() method for a field. + void GenerateFieldClear(const FieldDescriptor* field, bool is_inline, + Formatter format); + + void GenerateConstructorBody(io::Printer* printer, + std::vector<bool> already_processed, + bool copy_constructor) const; + + size_t HasBitsSize() const; + size_t InlinedStringDonatedSize() const; + int HasBitIndex(const FieldDescriptor* a) const; + int HasByteIndex(const FieldDescriptor* a) const; + int HasWordIndex(const FieldDescriptor* a) const; + bool SameHasByte(const FieldDescriptor* a, const FieldDescriptor* b) const; + std::vector<uint32_t> RequiredFieldsBitMask() const; + + const Descriptor* descriptor_; + int index_in_file_messages_; + std::string classname_; + Options options_; + FieldGeneratorMap field_generators_; + // optimized_order_ is the order we layout the message's fields in the + // class. This is reused to initialize the fields in-order for cache + // efficiency. + // + // optimized_order_ excludes oneof fields and weak fields. + std::vector<const FieldDescriptor*> optimized_order_; + std::vector<int> has_bit_indices_; + int max_has_bit_index_; + + // A map from field index to inlined_string index. For non-inlined-string + // fields, the element is -1. + std::vector<int> inlined_string_indices_; + // The count of inlined_string fields in the message. + int max_inlined_string_index_; + + std::vector<const EnumGenerator*> enum_generators_; + std::vector<const ExtensionGenerator*> extension_generators_; + int num_required_fields_; + int num_weak_fields_; + // table_driven_ indicates the generated message uses table-driven parsing. + bool table_driven_; + + std::unique_ptr<MessageLayoutHelper> message_layout_helper_; + std::unique_ptr<ParseFunctionGenerator> parse_function_generator_; + + MessageSCCAnalyzer* scc_analyzer_; + + std::map<std::string, std::string> variables_; + + friend class FileGenerator; + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageGenerator); +}; + +} // namespace cpp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_message_field.cc b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_message_field.cc new file mode 100644 index 00000000..a0b80bd0 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_message_field.cc @@ -0,0 +1,892 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <compiler/cpp/cpp_message_field.h> +#include <compiler/cpp/cpp_helpers.h> +#include <io/printer.h> + +#include <stubs/strutil.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { + +namespace { +std::string ReinterpretCast(const std::string& type, + const std::string& expression, + bool implicit_weak_field) { + if (implicit_weak_field) { + return "reinterpret_cast< " + type + " >(" + expression + ")"; + } else { + return expression; + } +} + +void SetMessageVariables(const FieldDescriptor* descriptor, + const Options& options, bool implicit_weak, + std::map<std::string, std::string>* variables) { + SetCommonFieldVariables(descriptor, variables, options); + (*variables)["type"] = FieldMessageTypeName(descriptor, options); + (*variables)["casted_member"] = ReinterpretCast( + (*variables)["type"] + "*", (*variables)["name"] + "_", implicit_weak); + (*variables)["type_default_instance"] = + QualifiedDefaultInstanceName(descriptor->message_type(), options); + (*variables)["type_default_instance_ptr"] = + QualifiedDefaultInstancePtr(descriptor->message_type(), options); + (*variables)["type_reference_function"] = + implicit_weak ? (" ::" + (*variables)["proto_ns"] + + "::internal::StrongReference(reinterpret_cast<const " + + (*variables)["type"] + "&>(\n" + + (*variables)["type_default_instance"] + "));\n") + : ""; + // NOTE: Escaped here to unblock proto1->proto2 migration. + // TODO(liujisi): Extend this to apply for other conflicting methods. + (*variables)["release_name"] = + SafeFunctionName(descriptor->containing_type(), descriptor, "release_"); + (*variables)["full_name"] = descriptor->full_name(); +} + +} // namespace + +// =================================================================== + +MessageFieldGenerator::MessageFieldGenerator(const FieldDescriptor* descriptor, + const Options& options, + MessageSCCAnalyzer* scc_analyzer) + : FieldGenerator(descriptor, options), + implicit_weak_field_( + IsImplicitWeakField(descriptor, options, scc_analyzer)), + has_required_fields_( + scc_analyzer->HasRequiredFields(descriptor->message_type())) { + SetMessageVariables(descriptor, options, implicit_weak_field_, &variables_); +} + +MessageFieldGenerator::~MessageFieldGenerator() {} + +void MessageFieldGenerator::GeneratePrivateMembers(io::Printer* printer) const { + Formatter format(printer, variables_); + if (implicit_weak_field_) { + format("::$proto_ns$::MessageLite* $name$_;\n"); + } else { + format("$type$* $name$_;\n"); + } +} + +void MessageFieldGenerator::GenerateAccessorDeclarations( + io::Printer* printer) const { + Formatter format(printer, variables_); + if (IsFieldStripped(descriptor_, options_)) { + format( + "$deprecated_attr$const $type$& ${1$$name$$}$() const { " + "__builtin_trap(); }\n" + "PROTOBUF_NODISCARD $deprecated_attr$$type$* " + "${1$$release_name$$}$() { " + "__builtin_trap(); }\n" + "$deprecated_attr$$type$* ${1$mutable_$name$$}$() { " + "__builtin_trap(); }\n" + "$deprecated_attr$void ${1$set_allocated_$name$$}$" + "($type$* $name$) { __builtin_trap(); }\n" + "$deprecated_attr$void " + "${1$unsafe_arena_set_allocated_$name$$}$(\n" + " $type$* $name$) { __builtin_trap(); }\n" + "$deprecated_attr$$type$* ${1$unsafe_arena_release_$name$$}$() { " + "__builtin_trap(); }\n", + descriptor_); + return; + } + format( + "$deprecated_attr$const $type$& ${1$$name$$}$() const;\n" + "PROTOBUF_NODISCARD $deprecated_attr$$type$* " + "${1$$release_name$$}$();\n" + "$deprecated_attr$$type$* ${1$mutable_$name$$}$();\n" + "$deprecated_attr$void ${1$set_allocated_$name$$}$" + "($type$* $name$);\n", + descriptor_); + if (!IsFieldStripped(descriptor_, options_)) { + format( + "private:\n" + "const $type$& ${1$_internal_$name$$}$() const;\n" + "$type$* ${1$_internal_mutable_$name$$}$();\n" + "public:\n", + descriptor_); + } + format( + "$deprecated_attr$void " + "${1$unsafe_arena_set_allocated_$name$$}$(\n" + " $type$* $name$);\n" + "$deprecated_attr$$type$* ${1$unsafe_arena_release_$name$$}$();\n", + descriptor_); +} + +void MessageFieldGenerator::GenerateNonInlineAccessorDefinitions( + io::Printer* printer) const { +} + +void MessageFieldGenerator::GenerateInlineAccessorDefinitions( + io::Printer* printer) const { + Formatter format(printer, variables_); + format( + "inline const $type$& $classname$::_internal_$name$() const {\n" + "$type_reference_function$" + " const $type$* p = $casted_member$;\n" + " return p != nullptr ? *p : reinterpret_cast<const $type$&>(\n" + " $type_default_instance$);\n" + "}\n" + "inline const $type$& $classname$::$name$() const {\n" + "$annotate_get$" + " // @@protoc_insertion_point(field_get:$full_name$)\n" + " return _internal_$name$();\n" + "}\n"); + + format( + "inline void $classname$::unsafe_arena_set_allocated_$name$(\n" + " $type$* $name$) {\n" + // If we're not on an arena, free whatever we were holding before. + // (If we are on arena, we can just forget the earlier pointer.) + " if (GetArenaForAllocation() == nullptr) {\n" + " delete reinterpret_cast<::$proto_ns$::MessageLite*>($name$_);\n" + " }\n"); + if (implicit_weak_field_) { + format( + " $name$_ = " + "reinterpret_cast<::$proto_ns$::MessageLite*>($name$);\n"); + } else { + format(" $name$_ = $name$;\n"); + } + format( + " if ($name$) {\n" + " $set_hasbit$\n" + " } else {\n" + " $clear_hasbit$\n" + " }\n" + "$annotate_set$" + " // @@protoc_insertion_point(field_unsafe_arena_set_allocated" + ":$full_name$)\n" + "}\n"); + format( + "inline $type$* $classname$::$release_name$() {\n" + "$type_reference_function$" + "$annotate_release$" + " $clear_hasbit$\n" + " $type$* temp = $casted_member$;\n" + " $name$_ = nullptr;\n" + "#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE\n" + " auto* old = reinterpret_cast<::$proto_ns$::MessageLite*>(temp);\n" + " temp = ::$proto_ns$::internal::DuplicateIfNonNull(temp);\n" + " if (GetArenaForAllocation() == nullptr) { delete old; }\n" + "#else // PROTOBUF_FORCE_COPY_IN_RELEASE\n" + " if (GetArenaForAllocation() != nullptr) {\n" + " temp = ::$proto_ns$::internal::DuplicateIfNonNull(temp);\n" + " }\n" + "#endif // !PROTOBUF_FORCE_COPY_IN_RELEASE\n" + " return temp;\n" + "}\n" + "inline $type$* $classname$::unsafe_arena_release_$name$() {\n" + "$annotate_release$" + " // @@protoc_insertion_point(field_release:$full_name$)\n" + "$type_reference_function$" + " $clear_hasbit$\n" + " $type$* temp = $casted_member$;\n" + " $name$_ = nullptr;\n" + " return temp;\n" + "}\n"); + + format( + "inline $type$* $classname$::_internal_mutable_$name$() {\n" + "$type_reference_function$" + " $set_hasbit$\n" + " if ($name$_ == nullptr) {\n" + " auto* p = CreateMaybeMessage<$type$>(GetArenaForAllocation());\n"); + if (implicit_weak_field_) { + format(" $name$_ = reinterpret_cast<::$proto_ns$::MessageLite*>(p);\n"); + } else { + format(" $name$_ = p;\n"); + } + format( + " }\n" + " return $casted_member$;\n" + "}\n" + "inline $type$* $classname$::mutable_$name$() {\n" + " $type$* _msg = _internal_mutable_$name$();\n" + "$annotate_mutable$" + " // @@protoc_insertion_point(field_mutable:$full_name$)\n" + " return _msg;\n" + "}\n"); + + // We handle the most common case inline, and delegate less common cases to + // the slow fallback function. + format( + "inline void $classname$::set_allocated_$name$($type$* $name$) {\n" + " ::$proto_ns$::Arena* message_arena = GetArenaForAllocation();\n"); + format(" if (message_arena == nullptr) {\n"); + if (IsCrossFileMessage(descriptor_)) { + format( + " delete reinterpret_cast< ::$proto_ns$::MessageLite*>($name$_);\n"); + } else { + format(" delete $name$_;\n"); + } + format( + " }\n" + " if ($name$) {\n"); + if (IsCrossFileMessage(descriptor_)) { + // We have to read the arena through the virtual method, because the type + // isn't defined in this file. + format( + " ::$proto_ns$::Arena* submessage_arena =\n" + " ::$proto_ns$::Arena::InternalHelper<\n" + " ::$proto_ns$::MessageLite>::GetOwningArena(\n" + " reinterpret_cast<::$proto_ns$::MessageLite*>(" + "$name$));\n"); + } else { + format( + " ::$proto_ns$::Arena* submessage_arena =\n" + " ::$proto_ns$::Arena::InternalHelper<$type$>::GetOwningArena(" + "$name$);\n"); + } + format( + " if (message_arena != submessage_arena) {\n" + " $name$ = ::$proto_ns$::internal::GetOwnedMessage(\n" + " message_arena, $name$, submessage_arena);\n" + " }\n" + " $set_hasbit$\n" + " } else {\n" + " $clear_hasbit$\n" + " }\n"); + if (implicit_weak_field_) { + format(" $name$_ = reinterpret_cast<MessageLite*>($name$);\n"); + } else { + format(" $name$_ = $name$;\n"); + } + format( + "$annotate_set$" + " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" + "}\n"); +} + +void MessageFieldGenerator::GenerateInternalAccessorDeclarations( + io::Printer* printer) const { + Formatter format(printer, variables_); + if (implicit_weak_field_) { + format( + "static const ::$proto_ns$::MessageLite& $name$(" + "const $classname$* msg);\n" + "static ::$proto_ns$::MessageLite* mutable_$name$(" + "$classname$* msg);\n"); + } else { + format("static const $type$& $name$(const $classname$* msg);\n"); + } +} + +void MessageFieldGenerator::GenerateInternalAccessorDefinitions( + io::Printer* printer) const { + // In theory, these accessors could be inline in _Internal. However, in + // practice, the linker is then not able to throw them out making implicit + // weak dependencies not work at all. + Formatter format(printer, variables_); + if (implicit_weak_field_) { + // These private accessors are used by MergeFrom and + // MergePartialFromCodedStream, and their purpose is to provide access to + // the field without creating a strong dependency on the message type. + format( + "const ::$proto_ns$::MessageLite& $classname$::_Internal::$name$(\n" + " const $classname$* msg) {\n" + " if (msg->$name$_ != nullptr) {\n" + " return *msg->$name$_;\n" + " } else if ($type_default_instance_ptr$ != nullptr) {\n" + " return *reinterpret_cast<const ::$proto_ns$::MessageLite*>(\n" + " $type_default_instance_ptr$);\n" + " } else {\n" + " return " + "*::$proto_ns$::internal::ImplicitWeakMessage::default_instance();\n" + " }\n" + "}\n"); + format( + "::$proto_ns$::MessageLite*\n" + "$classname$::_Internal::mutable_$name$($classname$* msg) {\n"); + if (HasHasbit(descriptor_)) { + format(" msg->$set_hasbit$\n"); + } + format( + " if (msg->$name$_ == nullptr) {\n" + " if ($type_default_instance_ptr$ == nullptr) {\n" + " msg->$name$_ = ::$proto_ns$::Arena::CreateMessage<\n" + " ::$proto_ns$::internal::ImplicitWeakMessage>(\n" + " msg->GetArenaForAllocation());\n" + " } else {\n" + " msg->$name$_ = \n" + " reinterpret_cast<const ::$proto_ns$::MessageLite*>(\n" + " $type_default_instance_ptr$)->New(\n" + " msg->GetArenaForAllocation());\n" + " }\n" + " }\n" + " return msg->$name$_;\n" + "}\n"); + } else { + // This inline accessor directly returns member field and is used in + // Serialize such that AFDO profile correctly captures access information to + // message fields under serialize. + format( + "const $type$&\n" + "$classname$::_Internal::$name$(const $classname$* msg) {\n" + " return *msg->$field_member$;\n" + "}\n"); + } +} + +void MessageFieldGenerator::GenerateClearingCode(io::Printer* printer) const { + GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_)); + + Formatter format(printer, variables_); + if (!HasHasbit(descriptor_)) { + // If we don't have has-bits, message presence is indicated only by ptr != + // NULL. Thus on clear, we need to delete the object. + format( + "if (GetArenaForAllocation() == nullptr && $name$_ != nullptr) {\n" + " delete $name$_;\n" + "}\n" + "$name$_ = nullptr;\n"); + } else { + format("if ($name$_ != nullptr) $name$_->Clear();\n"); + } +} + +void MessageFieldGenerator::GenerateMessageClearingCode( + io::Printer* printer) const { + GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_)); + + Formatter format(printer, variables_); + if (!HasHasbit(descriptor_)) { + // If we don't have has-bits, message presence is indicated only by ptr != + // NULL. Thus on clear, we need to delete the object. + format( + "if (GetArenaForAllocation() == nullptr && $name$_ != nullptr) {\n" + " delete $name$_;\n" + "}\n" + "$name$_ = nullptr;\n"); + } else { + format( + "$DCHK$($name$_ != nullptr);\n" + "$name$_->Clear();\n"); + } +} + +void MessageFieldGenerator::GenerateMergingCode(io::Printer* printer) const { + GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_)); + + Formatter format(printer, variables_); + if (implicit_weak_field_) { + format( + "_Internal::mutable_$name$(this)->CheckTypeAndMergeFrom(\n" + " _Internal::$name$(&from));\n"); + } else { + format( + "_internal_mutable_$name$()->$type$::MergeFrom(from._internal_$name$())" + ";\n"); + } +} + +void MessageFieldGenerator::GenerateSwappingCode(io::Printer* printer) const { + GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_)); + + Formatter format(printer, variables_); + format("swap($name$_, other->$name$_);\n"); +} + +void MessageFieldGenerator::GenerateDestructorCode(io::Printer* printer) const { + GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_)); + + Formatter format(printer, variables_); + if (options_.opensource_runtime) { + // TODO(gerbens) Remove this when we don't need to destruct default + // instances. In google3 a default instance will never get deleted so we + // don't need to worry about that but in opensource protobuf default + // instances are deleted in shutdown process and we need to take special + // care when handling them. + format("if (this != internal_default_instance()) "); + } + format("delete $name$_;\n"); +} + +void MessageFieldGenerator::GenerateConstructorCode( + io::Printer* printer) const { + GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_)); + + Formatter format(printer, variables_); + format("$name$_ = nullptr;\n"); +} + +void MessageFieldGenerator::GenerateCopyConstructorCode( + io::Printer* printer) const { + GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_)); + + Formatter format(printer, variables_); + format( + "if (from._internal_has_$name$()) {\n" + " $name$_ = new $type$(*from.$name$_);\n" + "} else {\n" + " $name$_ = nullptr;\n" + "}\n"); +} + +void MessageFieldGenerator::GenerateSerializeWithCachedSizesToArray( + io::Printer* printer) const { + GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_)); + + Formatter format(printer, variables_); + format( + "target = stream->EnsureSpace(target);\n" + "target = ::$proto_ns$::internal::WireFormatLite::\n" + " InternalWrite$declared_type$(\n" + " $number$, _Internal::$name$(this), target, stream);\n"); +} + +void MessageFieldGenerator::GenerateByteSize(io::Printer* printer) const { + GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_)); + + Formatter format(printer, variables_); + format( + "total_size += $tag_size$ +\n" + " ::$proto_ns$::internal::WireFormatLite::$declared_type$Size(\n" + " *$field_member$);\n"); +} + +void MessageFieldGenerator::GenerateIsInitialized(io::Printer* printer) const { + GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_)); + + if (!has_required_fields_) return; + + Formatter format(printer, variables_); + format( + "if (_internal_has_$name$()) {\n" + " if (!$name$_->IsInitialized()) return false;\n" + "}\n"); +} + +void MessageFieldGenerator::GenerateConstinitInitializer( + io::Printer* printer) const { + Formatter format(printer, variables_); + format("$name$_(nullptr)"); +} + +// =================================================================== + +MessageOneofFieldGenerator::MessageOneofFieldGenerator( + const FieldDescriptor* descriptor, const Options& options, + MessageSCCAnalyzer* scc_analyzer) + : MessageFieldGenerator(descriptor, options, scc_analyzer) { + SetCommonOneofFieldVariables(descriptor, &variables_); +} + +MessageOneofFieldGenerator::~MessageOneofFieldGenerator() {} + +void MessageOneofFieldGenerator::GenerateNonInlineAccessorDefinitions( + io::Printer* printer) const { + Formatter format(printer, variables_); + format( + "void $classname$::set_allocated_$name$($type$* $name$) {\n" + " ::$proto_ns$::Arena* message_arena = GetArenaForAllocation();\n" + " clear_$oneof_name$();\n" + " if ($name$) {\n"); + if (descriptor_->file() != descriptor_->message_type()->file()) { + // We have to read the arena through the virtual method, because the type + // isn't defined in this file. + format( + " ::$proto_ns$::Arena* submessage_arena =\n" + " ::$proto_ns$::Arena::InternalHelper<\n" + " ::$proto_ns$::MessageLite>::GetOwningArena(\n" + " reinterpret_cast<::$proto_ns$::MessageLite*>(" + "$name$));\n"); + } else { + format( + " ::$proto_ns$::Arena* submessage_arena =\n" + " ::$proto_ns$::Arena::InternalHelper<" + "$type$>::GetOwningArena($name$);\n"); + } + format( + " if (message_arena != submessage_arena) {\n" + " $name$ = ::$proto_ns$::internal::GetOwnedMessage(\n" + " message_arena, $name$, submessage_arena);\n" + " }\n" + " set_has_$name$();\n" + " $field_member$ = $name$;\n" + " }\n" + "$annotate_set$" + " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" + "}\n"); +} + +void MessageOneofFieldGenerator::GenerateInlineAccessorDefinitions( + io::Printer* printer) const { + Formatter format(printer, variables_); + format( + "inline $type$* $classname$::$release_name$() {\n" + "$annotate_release$" + " // @@protoc_insertion_point(field_release:$full_name$)\n" + " if (_internal_has_$name$()) {\n" + " clear_has_$oneof_name$();\n" + " $type$* temp = $field_member$;\n" + " if (GetArenaForAllocation() != nullptr) {\n" + " temp = ::$proto_ns$::internal::DuplicateIfNonNull(temp);\n" + " }\n" + " $field_member$ = nullptr;\n" + " return temp;\n" + " } else {\n" + " return nullptr;\n" + " }\n" + "}\n"); + + format( + "inline const $type$& $classname$::_internal_$name$() const {\n" + " return _internal_has_$name$()\n" + " ? *$field_member$\n" + " : reinterpret_cast< $type$&>($type_default_instance$);\n" + "}\n" + "inline const $type$& $classname$::$name$() const {\n" + "$annotate_get$" + " // @@protoc_insertion_point(field_get:$full_name$)\n" + " return _internal_$name$();\n" + "}\n" + "inline $type$* $classname$::unsafe_arena_release_$name$() {\n" + "$annotate_release$" + " // @@protoc_insertion_point(field_unsafe_arena_release" + ":$full_name$)\n" + " if (_internal_has_$name$()) {\n" + " clear_has_$oneof_name$();\n" + " $type$* temp = $field_member$;\n" + " $field_member$ = nullptr;\n" + " return temp;\n" + " } else {\n" + " return nullptr;\n" + " }\n" + "}\n" + "inline void $classname$::unsafe_arena_set_allocated_$name$" + "($type$* $name$) {\n" + // We rely on the oneof clear method to free the earlier contents of + // this oneof. We can directly use the pointer we're given to set the + // new value. + " clear_$oneof_name$();\n" + " if ($name$) {\n" + " set_has_$name$();\n" + " $field_member$ = $name$;\n" + " }\n" + "$annotate_set$" + " // @@protoc_insertion_point(field_unsafe_arena_set_allocated:" + "$full_name$)\n" + "}\n" + "inline $type$* $classname$::_internal_mutable_$name$() {\n" + " if (!_internal_has_$name$()) {\n" + " clear_$oneof_name$();\n" + " set_has_$name$();\n" + " $field_member$ = CreateMaybeMessage< $type$ " + ">(GetArenaForAllocation());\n" + " }\n" + " return $field_member$;\n" + "}\n" + "inline $type$* $classname$::mutable_$name$() {\n" + " $type$* _msg = _internal_mutable_$name$();\n" + "$annotate_mutable$" + " // @@protoc_insertion_point(field_mutable:$full_name$)\n" + " return _msg;\n" + "}\n"); +} + +void MessageOneofFieldGenerator::GenerateClearingCode( + io::Printer* printer) const { + GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_)); + + Formatter format(printer, variables_); + format( + "if (GetArenaForAllocation() == nullptr) {\n" + " delete $field_member$;\n" + "}\n"); +} + +void MessageOneofFieldGenerator::GenerateMessageClearingCode( + io::Printer* printer) const { + GenerateClearingCode(printer); +} + +void MessageOneofFieldGenerator::GenerateSwappingCode( + io::Printer* printer) const { + // Don't print any swapping code. Swapping the union will swap this field. +} + +void MessageOneofFieldGenerator::GenerateDestructorCode( + io::Printer* printer) const { + // We inherit from MessageFieldGenerator, so we need to override the default + // behavior. +} + +void MessageOneofFieldGenerator::GenerateConstructorCode( + io::Printer* printer) const { + // Don't print any constructor code. The field is in a union. We allocate + // space only when this field is used. +} + +void MessageOneofFieldGenerator::GenerateIsInitialized( + io::Printer* printer) const { + if (!has_required_fields_) return; + + Formatter format(printer, variables_); + format( + "if (_internal_has_$name$()) {\n" + " if (!$field_member$->IsInitialized()) return false;\n" + "}\n"); +} + +// =================================================================== + +RepeatedMessageFieldGenerator::RepeatedMessageFieldGenerator( + const FieldDescriptor* descriptor, const Options& options, + MessageSCCAnalyzer* scc_analyzer) + : FieldGenerator(descriptor, options), + implicit_weak_field_( + IsImplicitWeakField(descriptor, options, scc_analyzer)), + has_required_fields_( + scc_analyzer->HasRequiredFields(descriptor->message_type())) { + SetMessageVariables(descriptor, options, implicit_weak_field_, &variables_); +} + +RepeatedMessageFieldGenerator::~RepeatedMessageFieldGenerator() {} + +void RepeatedMessageFieldGenerator::GeneratePrivateMembers( + io::Printer* printer) const { + Formatter format(printer, variables_); + if (implicit_weak_field_) { + format("::$proto_ns$::WeakRepeatedPtrField< $type$ > $name$_;\n"); + } else { + format("::$proto_ns$::RepeatedPtrField< $type$ > $name$_;\n"); + } +} + +void RepeatedMessageFieldGenerator::GenerateAccessorDeclarations( + io::Printer* printer) const { + Formatter format(printer, variables_); + if (IsFieldStripped(descriptor_, options_)) { + format( + "$deprecated_attr$$type$* ${1$mutable_$name$$}$(int index) { " + "__builtin_trap(); }\n" + "$deprecated_attr$::$proto_ns$::RepeatedPtrField< $type$ >*\n" + " ${1$mutable_$name$$}$() { __builtin_trap(); }\n" + "$deprecated_attr$const $type$& ${1$$name$$}$(int index) const { " + "__builtin_trap(); }\n" + "$deprecated_attr$$type$* ${1$add_$name$$}$() { " + "__builtin_trap(); }\n" + "$deprecated_attr$const ::$proto_ns$::RepeatedPtrField< $type$ >&\n" + " ${1$$name$$}$() const { __builtin_trap(); }\n", + descriptor_); + return; + } + format( + "$deprecated_attr$$type$* ${1$mutable_$name$$}$(int index);\n" + "$deprecated_attr$::$proto_ns$::RepeatedPtrField< $type$ >*\n" + " ${1$mutable_$name$$}$();\n", + descriptor_); + if (!IsFieldStripped(descriptor_, options_)) { + format( + "private:\n" + "const $type$& ${1$_internal_$name$$}$(int index) const;\n" + "$type$* ${1$_internal_add_$name$$}$();\n" + "public:\n", + descriptor_); + } + format( + "$deprecated_attr$const $type$& ${1$$name$$}$(int index) const;\n" + "$deprecated_attr$$type$* ${1$add_$name$$}$();\n" + "$deprecated_attr$const ::$proto_ns$::RepeatedPtrField< $type$ >&\n" + " ${1$$name$$}$() const;\n", + descriptor_); +} + +void RepeatedMessageFieldGenerator::GenerateInlineAccessorDefinitions( + io::Printer* printer) const { + Formatter format(printer, variables_); + format.Set("weak", implicit_weak_field_ ? ".weak" : ""); + + format( + "inline $type$* $classname$::mutable_$name$(int index) {\n" + "$annotate_mutable$" + // TODO(dlj): move insertion points + " // @@protoc_insertion_point(field_mutable:$full_name$)\n" + "$type_reference_function$" + " return $name$_$weak$.Mutable(index);\n" + "}\n" + "inline ::$proto_ns$::RepeatedPtrField< $type$ >*\n" + "$classname$::mutable_$name$() {\n" + "$annotate_mutable_list$" + " // @@protoc_insertion_point(field_mutable_list:$full_name$)\n" + "$type_reference_function$" + " return &$name$_$weak$;\n" + "}\n"); + + if (options_.safe_boundary_check) { + format( + "inline const $type$& $classname$::_internal_$name$(int index) const " + "{\n" + " return $name$_$weak$.InternalCheckedGet(index,\n" + " reinterpret_cast<const $type$&>($type_default_instance$));\n" + "}\n"); + } else { + format( + "inline const $type$& $classname$::_internal_$name$(int index) const " + "{\n" + "$type_reference_function$" + " return $name$_$weak$.Get(index);\n" + "}\n"); + } + + format( + "inline const $type$& $classname$::$name$(int index) const {\n" + "$annotate_get$" + " // @@protoc_insertion_point(field_get:$full_name$)\n" + " return _internal_$name$(index);\n" + "}\n" + "inline $type$* $classname$::_internal_add_$name$() {\n" + " return $name$_$weak$.Add();\n" + "}\n" + "inline $type$* $classname$::add_$name$() {\n" + " $type$* _add = _internal_add_$name$();\n" + "$annotate_add_mutable$" + " // @@protoc_insertion_point(field_add:$full_name$)\n" + " return _add;\n" + "}\n"); + + format( + "inline const ::$proto_ns$::RepeatedPtrField< $type$ >&\n" + "$classname$::$name$() const {\n" + "$annotate_list$" + " // @@protoc_insertion_point(field_list:$full_name$)\n" + "$type_reference_function$" + " return $name$_$weak$;\n" + "}\n"); +} + +void RepeatedMessageFieldGenerator::GenerateClearingCode( + io::Printer* printer) const { + GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_)); + + Formatter format(printer, variables_); + format("$name$_.Clear();\n"); +} + +void RepeatedMessageFieldGenerator::GenerateMergingCode( + io::Printer* printer) const { + GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_)); + + Formatter format(printer, variables_); + format("$name$_.MergeFrom(from.$name$_);\n"); +} + +void RepeatedMessageFieldGenerator::GenerateSwappingCode( + io::Printer* printer) const { + GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_)); + + Formatter format(printer, variables_); + format("$name$_.InternalSwap(&other->$name$_);\n"); +} + +void RepeatedMessageFieldGenerator::GenerateConstructorCode( + io::Printer* printer) const { + // Not needed for repeated fields. +} + +void RepeatedMessageFieldGenerator::GenerateSerializeWithCachedSizesToArray( + io::Printer* printer) const { + GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_)); + + Formatter format(printer, variables_); + if (implicit_weak_field_) { + format( + "for (auto it = this->$name$_.pointer_begin(),\n" + " end = this->$name$_.pointer_end(); it < end; ++it) {\n" + " target = stream->EnsureSpace(target);\n" + " target = ::$proto_ns$::internal::WireFormatLite::\n" + " InternalWrite$declared_type$($number$, **it, target, stream);\n" + "}\n"); + } else { + format( + "for (unsigned int i = 0,\n" + " n = static_cast<unsigned int>(this->_internal_$name$_size()); i < " + "n; i++) " + "{\n" + " target = stream->EnsureSpace(target);\n" + " target = ::$proto_ns$::internal::WireFormatLite::\n" + " InternalWrite$declared_type$($number$, " + "this->_internal_$name$(i), target, stream);\n" + "}\n"); + } +} + +void RepeatedMessageFieldGenerator::GenerateByteSize( + io::Printer* printer) const { + GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_)); + + Formatter format(printer, variables_); + format( + "total_size += $tag_size$UL * this->_internal_$name$_size();\n" + "for (const auto& msg : this->$name$_) {\n" + " total_size +=\n" + " ::$proto_ns$::internal::WireFormatLite::$declared_type$Size(msg);\n" + "}\n"); +} + +void RepeatedMessageFieldGenerator::GenerateIsInitialized( + io::Printer* printer) const { + GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_)); + + if (!has_required_fields_) return; + + Formatter format(printer, variables_); + if (implicit_weak_field_) { + format( + "if (!::$proto_ns$::internal::AllAreInitializedWeak($name$_.weak))\n" + " return false;\n"); + } else { + format( + "if (!::$proto_ns$::internal::AllAreInitialized($name$_))\n" + " return false;\n"); + } +} + +void RepeatedMessageFieldGenerator::GenerateConstinitInitializer( + io::Printer* printer) const { + Formatter format(printer, variables_); + format("$name$_()"); +} + +} // namespace cpp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_message_field.h b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_message_field.h new file mode 100644 index 00000000..88744299 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_message_field.h @@ -0,0 +1,144 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_FIELD_H__ +#define GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_FIELD_H__ + +#include <map> +#include <string> +#include <compiler/cpp/cpp_field.h> +#include <compiler/cpp/cpp_helpers.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { + +class MessageFieldGenerator : public FieldGenerator { + public: + MessageFieldGenerator(const FieldDescriptor* descriptor, + const Options& options, + MessageSCCAnalyzer* scc_analyzer); + ~MessageFieldGenerator() override; + + // implements FieldGenerator --------------------------------------- + void GeneratePrivateMembers(io::Printer* printer) const override; + void GenerateAccessorDeclarations(io::Printer* printer) const override; + void GenerateInlineAccessorDefinitions(io::Printer* printer) const override; + void GenerateNonInlineAccessorDefinitions( + io::Printer* printer) const override; + void GenerateInternalAccessorDeclarations( + io::Printer* printer) const override; + void GenerateInternalAccessorDefinitions(io::Printer* printer) const override; + void GenerateClearingCode(io::Printer* printer) const override; + void GenerateMessageClearingCode(io::Printer* printer) const override; + void GenerateMergingCode(io::Printer* printer) const override; + void GenerateSwappingCode(io::Printer* printer) const override; + void GenerateDestructorCode(io::Printer* printer) const override; + void GenerateConstructorCode(io::Printer* printer) const override; + void GenerateCopyConstructorCode(io::Printer* printer) const override; + void GenerateSerializeWithCachedSizesToArray( + io::Printer* printer) const override; + void GenerateByteSize(io::Printer* printer) const override; + void GenerateIsInitialized(io::Printer* printer) const override; + void GenerateConstinitInitializer(io::Printer* printer) const override; + + protected: + const bool implicit_weak_field_; + const bool has_required_fields_; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageFieldGenerator); +}; + +class MessageOneofFieldGenerator : public MessageFieldGenerator { + public: + MessageOneofFieldGenerator(const FieldDescriptor* descriptor, + const Options& options, + MessageSCCAnalyzer* scc_analyzer); + ~MessageOneofFieldGenerator() override; + + // implements FieldGenerator --------------------------------------- + void GenerateInlineAccessorDefinitions(io::Printer* printer) const override; + void GenerateNonInlineAccessorDefinitions( + io::Printer* printer) const override; + void GenerateClearingCode(io::Printer* printer) const override; + + // MessageFieldGenerator, from which we inherit, overrides this so we need to + // override it as well. + void GenerateMessageClearingCode(io::Printer* printer) const override; + void GenerateSwappingCode(io::Printer* printer) const override; + void GenerateDestructorCode(io::Printer* printer) const override; + void GenerateConstructorCode(io::Printer* printer) const override; + void GenerateIsInitialized(io::Printer* printer) const override; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageOneofFieldGenerator); +}; + +class RepeatedMessageFieldGenerator : public FieldGenerator { + public: + RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor, + const Options& options, + MessageSCCAnalyzer* scc_analyzer); + ~RepeatedMessageFieldGenerator() override; + + // implements FieldGenerator --------------------------------------- + void GeneratePrivateMembers(io::Printer* printer) const override; + void GenerateAccessorDeclarations(io::Printer* printer) const override; + void GenerateInlineAccessorDefinitions(io::Printer* printer) const override; + void GenerateClearingCode(io::Printer* printer) const override; + void GenerateMergingCode(io::Printer* printer) const override; + void GenerateSwappingCode(io::Printer* printer) const override; + void GenerateConstructorCode(io::Printer* printer) const override; + void GenerateCopyConstructorCode(io::Printer* printer) const override {} + void GenerateSerializeWithCachedSizesToArray( + io::Printer* printer) const override; + void GenerateByteSize(io::Printer* printer) const override; + void GenerateIsInitialized(io::Printer* printer) const override; + void GenerateConstinitInitializer(io::Printer* printer) const override; + + private: + const bool implicit_weak_field_; + const bool has_required_fields_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedMessageFieldGenerator); +}; + +} // namespace cpp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_FIELD_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_message_layout_helper.h b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_message_layout_helper.h new file mode 100644 index 00000000..aa088a2a --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_message_layout_helper.h @@ -0,0 +1,64 @@ +// 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. + +// Author: seongkim@google.com (Seong Beom Kim) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_LAYOUT_HELPER_H__ +#define GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_LAYOUT_HELPER_H__ + +#include <compiler/cpp/cpp_options.h> +#include <descriptor.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { + +class MessageSCCAnalyzer; + +// Provides an abstract interface to optimize message layout +// by rearranging the fields of a message. +class MessageLayoutHelper { + public: + virtual ~MessageLayoutHelper() {} + + virtual void OptimizeLayout(std::vector<const FieldDescriptor*>* fields, + const Options& options, + MessageSCCAnalyzer* scc_analyzer) = 0; +}; + +} // namespace cpp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_LAYOUT_HELPER_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_move_unittest.cc b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_move_unittest.cc new file mode 100644 index 00000000..ccb83acf --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_move_unittest.cc @@ -0,0 +1,169 @@ +// 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 <stubs/common.h> +#include <test_util.h> +#include <unittest.pb.h> +#include <gtest/gtest.h> + +#if LANG_CXX11 +#include <type_traits> +#endif + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { + +// Can't use an anonymous namespace here due to brokenness of Tru64 compiler. +namespace cpp_unittest { + +// Moves are enabled only when compiling with a C++11 compiler or newer. +#if LANG_CXX11 + +TEST(MovableMessageTest, MoveConstructor) { + protobuf_unittest::TestAllTypes message1; + TestUtil::SetAllFields(&message1); + const auto* nested = &message1.optional_nested_message(); + + protobuf_unittest::TestAllTypes message2(std::move(message1)); + TestUtil::ExpectAllFieldsSet(message2); + + // Check if the optional_nested_message was actually moved (and not just + // copied). + EXPECT_EQ(nested, &message2.optional_nested_message()); + EXPECT_NE(nested, &message1.optional_nested_message()); +} + +TEST(MovableMessageTest, MoveAssignmentOperator) { + protobuf_unittest::TestAllTypes message1; + TestUtil::SetAllFields(&message1); + const auto* nested = &message1.optional_nested_message(); + + protobuf_unittest::TestAllTypes message2; + message2 = std::move(message1); + TestUtil::ExpectAllFieldsSet(message2); + + // Check if the optional_nested_message was actually moved (and not just + // copied). + EXPECT_EQ(nested, &message2.optional_nested_message()); + EXPECT_NE(nested, &message1.optional_nested_message()); +} + +TEST(MovableMessageTest, SelfMoveAssignment) { + // The `self` reference is necessary to defeat -Wself-move. + protobuf_unittest::TestAllTypes message, &self = message; + TestUtil::SetAllFields(&message); + message = std::move(self); + TestUtil::ExpectAllFieldsSet(message); +} + +TEST(MovableMessageTest, MoveSameArena) { + Arena arena; + + auto* message1_on_arena = + Arena::CreateMessage<protobuf_unittest::TestAllTypes>(&arena); + TestUtil::SetAllFields(message1_on_arena); + const auto* nested = &message1_on_arena->optional_nested_message(); + + auto* message2_on_arena = + Arena::CreateMessage<protobuf_unittest::TestAllTypes>(&arena); + + // Moving messages on the same arena should lead to swapped pointers. + *message2_on_arena = std::move(*message1_on_arena); + EXPECT_EQ(nested, &message2_on_arena->optional_nested_message()); +} + +TEST(MovableMessageTest, MoveDifferentArenas) { + Arena arena1, arena2; + + auto* message1_on_arena = + Arena::CreateMessage<protobuf_unittest::TestAllTypes>(&arena1); + TestUtil::SetAllFields(message1_on_arena); + const auto* nested = &message1_on_arena->optional_nested_message(); + + auto* message2_on_arena = + Arena::CreateMessage<protobuf_unittest::TestAllTypes>(&arena2); + + // Moving messages on two different arenas should lead to a copy. + *message2_on_arena = std::move(*message1_on_arena); + EXPECT_NE(nested, &message2_on_arena->optional_nested_message()); + TestUtil::ExpectAllFieldsSet(*message1_on_arena); + TestUtil::ExpectAllFieldsSet(*message2_on_arena); +} + +TEST(MovableMessageTest, MoveFromArena) { + Arena arena; + + auto* message1_on_arena = + Arena::CreateMessage<protobuf_unittest::TestAllTypes>(&arena); + TestUtil::SetAllFields(message1_on_arena); + const auto* nested = &message1_on_arena->optional_nested_message(); + + protobuf_unittest::TestAllTypes message2; + + // Moving from a message on the arena should lead to a copy. + message2 = std::move(*message1_on_arena); + EXPECT_NE(nested, &message2.optional_nested_message()); + TestUtil::ExpectAllFieldsSet(*message1_on_arena); + TestUtil::ExpectAllFieldsSet(message2); +} + +TEST(MovableMessageTest, MoveToArena) { + Arena arena; + + protobuf_unittest::TestAllTypes message1; + TestUtil::SetAllFields(&message1); + const auto* nested = &message1.optional_nested_message(); + + auto* message2_on_arena = + Arena::CreateMessage<protobuf_unittest::TestAllTypes>(&arena); + + // Moving to a message on the arena should lead to a copy. + *message2_on_arena = std::move(message1); + EXPECT_NE(nested, &message2_on_arena->optional_nested_message()); + TestUtil::ExpectAllFieldsSet(message1); + TestUtil::ExpectAllFieldsSet(*message2_on_arena); +} + +TEST(MovableMessageTest, Noexcept) { + EXPECT_TRUE( + std::is_nothrow_move_constructible<protobuf_unittest::TestAllTypes>()); + EXPECT_TRUE(std::is_nothrow_move_assignable<protobuf_unittest::TestAllTypes>()); +} + +#endif // LANG_CXX11 + +} // namespace cpp_unittest + +} // namespace cpp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_names.h b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_names.h new file mode 100644 index 00000000..81090017 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_names.h @@ -0,0 +1,96 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_NAMES_H__ +#define GOOGLE_PROTOBUF_COMPILER_CPP_NAMES_H__ + +#include <string> + +#include <port_def.inc> + +namespace google { +namespace protobuf { + +class Descriptor; +class EnumDescriptor; +class EnumValueDescriptor; +class FieldDescriptor; + +namespace compiler { +namespace cpp { + +// Returns the unqualified C++ name. +// +// For example, if you had: +// package foo.bar; +// message Baz { message Qux {} } +// Then the non-qualified version would be: +// Baz_Qux +std::string ClassName(const Descriptor* descriptor); +std::string ClassName(const EnumDescriptor* enum_descriptor); + +// Returns the fully qualified C++ name. +// +// For example, if you had: +// package foo.bar; +// message Baz { message Qux {} } +// Then the qualified ClassName for Qux would be: +// ::foo::bar::Baz_Qux +std::string QualifiedClassName(const Descriptor* d); +std::string QualifiedClassName(const EnumDescriptor* d); +std::string QualifiedExtensionName(const FieldDescriptor* d); + +// Get the (unqualified) name that should be used for this field in C++ code. +// The name is coerced to lower-case to emulate proto1 behavior. People +// should be using lowercase-with-underscores style for proto field names +// anyway, so normally this just returns field->name(). +std::string FieldName(const FieldDescriptor* field); + +// Requires that this field is in a oneof. Returns the (unqualified) case +// constant for this field. +std::string OneofCaseConstantName(const FieldDescriptor* field); +// Returns the quafilied case constant for this field. +std::string QualifiedOneofCaseConstantName(const FieldDescriptor* field); + +// Get the (unqualified) name that should be used for this enum value in C++ +// code. +std::string EnumValueName(const EnumValueDescriptor* enum_value); + +// Strips ".proto" or ".protodevel" from the end of a filename. +PROTOC_EXPORT std::string StripProto(const std::string& filename); + +} // namespace cpp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#include <port_undef.inc> + +#endif // GOOGLE_PROTOBUF_COMPILER_CPP_NAMES_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_options.h b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_options.h new file mode 100644 index 00000000..d0f16d03 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_options.h @@ -0,0 +1,95 @@ +// 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. + +// Author: rennie@google.com (Jeffrey Rennie) + +#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_OPTIONS_H__ +#define GOOGLE_PROTOBUF_COMPILER_CPP_OPTIONS_H__ + +#include <set> +#include <string> + +namespace google { +namespace protobuf { +namespace compiler { +class AccessInfoMap; + +namespace cpp { + +enum class EnforceOptimizeMode { + kNoEnforcement, // Use the runtime specified by the file specific options. + kSpeed, // Full runtime with a generated code implementation. + kCodeSize, // Full runtime with a reflective implementation. + kLiteRuntime, +}; + +struct FieldListenerOptions { + bool inject_field_listener_events = false; + std::set<std::string> forbidden_field_listener_events; +}; + +// Generator options (see generator.cc for a description of each): +struct Options { + std::string dllexport_decl; + bool safe_boundary_check = false; + bool proto_h = false; + bool transitive_pb_h = true; + bool annotate_headers = false; + EnforceOptimizeMode enforce_mode = EnforceOptimizeMode::kNoEnforcement; + bool table_driven_parsing = false; + bool table_driven_serialization = false; + bool lite_implicit_weak_fields = false; + bool bootstrap = false; + bool opensource_runtime = false; + bool annotate_accessor = false; + bool unused_field_stripping = false; + bool profile_driven_inline_string = true; + bool force_inline_string = false; + std::string runtime_include_base; + int num_cc_files = 0; + std::string annotation_pragma_name; + std::string annotation_guard_name; + const AccessInfoMap* access_info_map = nullptr; + enum { + kTCTableNever, + kTCTableGuarded, + kTCTableAlways + } tctable_mode = kTCTableNever; + FieldListenerOptions field_listener_options; + bool eagerly_verified_lazy = false; + bool force_eagerly_verified_lazy = false; +}; + +} // namespace cpp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_CPP_OPTIONS_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_padding_optimizer.cc b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_padding_optimizer.cc new file mode 100644 index 00000000..a6384a7f --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_padding_optimizer.cc @@ -0,0 +1,228 @@ +// 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 <compiler/cpp/cpp_padding_optimizer.h> + +#include <compiler/cpp/cpp_helpers.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { + +namespace { + +// FieldGroup is just a helper for PaddingOptimizer below. It holds a vector of +// fields that are grouped together because they have compatible alignment, and +// a preferred location in the final field ordering. +class FieldGroup { + public: + FieldGroup() : preferred_location_(0) {} + + // A group with a single field. + FieldGroup(float preferred_location, const FieldDescriptor* field) + : preferred_location_(preferred_location), fields_(1, field) {} + + // Append the fields in 'other' to this group. + void Append(const FieldGroup& other) { + if (other.fields_.empty()) { + return; + } + // Preferred location is the average among all the fields, so we weight by + // the number of fields on each FieldGroup object. + preferred_location_ = (preferred_location_ * fields_.size() + + (other.preferred_location_ * other.fields_.size())) / + (fields_.size() + other.fields_.size()); + fields_.insert(fields_.end(), other.fields_.begin(), other.fields_.end()); + } + + void SetPreferredLocation(float location) { preferred_location_ = location; } + const std::vector<const FieldDescriptor*>& fields() const { return fields_; } + + // FieldGroup objects sort by their preferred location. + bool operator<(const FieldGroup& other) const { + return preferred_location_ < other.preferred_location_; + } + + private: + // "preferred_location_" is an estimate of where this group should go in the + // final list of fields. We compute this by taking the average index of each + // field in this group in the original ordering of fields. This is very + // approximate, but should put this group close to where its member fields + // originally went. + float preferred_location_; + std::vector<const FieldDescriptor*> fields_; + // We rely on the default copy constructor and operator= so this type can be + // used in a vector. +}; + +} // namespace + +// Reorder 'fields' so that if the fields are output into a c++ class in the new +// order, fields of similar family (see below) are together and within each +// family, alignment padding is minimized. +// +// We try to do this while keeping each field as close as possible to its field +// number order so that we don't reduce cache locality much for function that +// access each field in order. Originally, OptimizePadding used declaration +// order for its decisions, but generated code minus the serializer/parsers uses +// the output of OptimizePadding as well (stored in +// MessageGenerator::optimized_order_). Since the serializers use field number +// order, we use that as a tie-breaker. +// +// We classify each field into a particular "family" of fields, that we perform +// the same operation on in our generated functions. +// +// REPEATED is placed first, as the C++ compiler automatically initializes +// these fields in layout order. +// +// STRING is grouped next, as our Clear/SharedCtor/SharedDtor walks it and +// calls ArenaStringPtr::Destroy on each. +// +// LAZY_MESSAGE is grouped next, as it interferes with the ability to memset +// non-repeated fields otherwise. +// +// MESSAGE is grouped next, as our Clear/SharedDtor code walks it and calls +// delete on each. We initialize these fields with a NULL pointer (see +// MessageFieldGenerator::GenerateConstructorCode), which allows them to be +// memset. +// +// ZERO_INITIALIZABLE is memset in Clear/SharedCtor +// +// OTHER these fields are initialized one-by-one. +void PaddingOptimizer::OptimizeLayout( + std::vector<const FieldDescriptor*>* fields, const Options& options, + MessageSCCAnalyzer* scc_analyzer) { + // The sorted numeric order of Family determines the declaration order in the + // memory layout. + enum Family { + REPEATED = 0, + STRING = 1, + // Laying out LAZY_MESSAGE before MESSAGE allows a single memset to zero + // MESSAGE and ZERO_INITIALIZABLE fields together. + LAZY_MESSAGE = 2, + MESSAGE = 3, + ZERO_INITIALIZABLE = 4, + OTHER = 5, + kMaxFamily + }; + + // First divide fields into those that align to 1 byte, 4 bytes or 8 bytes. + std::vector<FieldGroup> aligned_to_1[kMaxFamily]; + std::vector<FieldGroup> aligned_to_4[kMaxFamily]; + std::vector<FieldGroup> aligned_to_8[kMaxFamily]; + for (int i = 0; i < fields->size(); ++i) { + const FieldDescriptor* field = (*fields)[i]; + + Family f = OTHER; + if (field->is_repeated()) { + f = REPEATED; + } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) { + f = STRING; + } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + f = MESSAGE; + if (IsLazy(field, options, scc_analyzer)) { + f = LAZY_MESSAGE; + } + } else if (CanInitializeByZeroing(field)) { + f = ZERO_INITIALIZABLE; + } + + const int j = field->number(); + switch (EstimateAlignmentSize(field)) { + case 1: + aligned_to_1[f].push_back(FieldGroup(j, field)); + break; + case 4: + aligned_to_4[f].push_back(FieldGroup(j, field)); + break; + case 8: + aligned_to_8[f].push_back(FieldGroup(j, field)); + break; + default: + GOOGLE_LOG(FATAL) << "Unknown alignment size " << EstimateAlignmentSize(field) + << "for a field " << field->full_name() << "."; + } + } + + // For each family, group fields to optimize padding. + for (int f = 0; f < kMaxFamily; f++) { + // Now group fields aligned to 1 byte into sets of 4, and treat those like a + // single field aligned to 4 bytes. + for (int i = 0; i < aligned_to_1[f].size(); i += 4) { + FieldGroup field_group; + for (int j = i; j < aligned_to_1[f].size() && j < i + 4; ++j) { + field_group.Append(aligned_to_1[f][j]); + } + aligned_to_4[f].push_back(field_group); + } + // Sort by preferred location to keep fields as close to their field number + // order as possible. Using stable_sort ensures that the output is + // consistent across runs. + std::stable_sort(aligned_to_4[f].begin(), aligned_to_4[f].end()); + + // Now group fields aligned to 4 bytes (or the 4-field groups created above) + // into pairs, and treat those like a single field aligned to 8 bytes. + for (int i = 0; i < aligned_to_4[f].size(); i += 2) { + FieldGroup field_group; + for (int j = i; j < aligned_to_4[f].size() && j < i + 2; ++j) { + field_group.Append(aligned_to_4[f][j]); + } + if (i == aligned_to_4[f].size() - 1) { + if (f == OTHER) { + // Move incomplete 4-byte block to the beginning. This is done to + // pair with the (possible) leftover blocks from the + // ZERO_INITIALIZABLE family. + field_group.SetPreferredLocation(-1); + } else { + // Move incomplete 4-byte block to the end. + field_group.SetPreferredLocation(fields->size() + 1); + } + } + aligned_to_8[f].push_back(field_group); + } + // Sort by preferred location. + std::stable_sort(aligned_to_8[f].begin(), aligned_to_8[f].end()); + } + + // Now pull out all the FieldDescriptors in order. + fields->clear(); + for (int f = 0; f < kMaxFamily; ++f) { + for (int i = 0; i < aligned_to_8[f].size(); ++i) { + fields->insert(fields->end(), aligned_to_8[f][i].fields().begin(), + aligned_to_8[f][i].fields().end()); + } + } +} + +} // namespace cpp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_padding_optimizer.h b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_padding_optimizer.h new file mode 100644 index 00000000..c08fa8dc --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_padding_optimizer.h @@ -0,0 +1,65 @@ +// 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. + +// Author: seongkim@google.com (Seong Beom Kim) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_PADDING_OPTIMIZER_H__ +#define GOOGLE_PROTOBUF_COMPILER_CPP_PADDING_OPTIMIZER_H__ + +#include <compiler/cpp/cpp_message_layout_helper.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { + +// Rearranges the fields of a message to minimize padding. +// Fields are grouped by the type and the size. +// For example, grouping four boolean fields and one int32 +// field results in zero padding overhead. See OptimizeLayout's +// comment for details. +class PaddingOptimizer : public MessageLayoutHelper { + public: + PaddingOptimizer() {} + ~PaddingOptimizer() override {} + + void OptimizeLayout(std::vector<const FieldDescriptor*>* fields, + const Options& options, + MessageSCCAnalyzer* scc_analyzer) override; +}; + +} // namespace cpp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_CPP_PADDING_OPTIMIZER_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_parse_function_generator.cc b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_parse_function_generator.cc new file mode 100644 index 00000000..8eed2224 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_parse_function_generator.cc @@ -0,0 +1,1303 @@ +// 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 <compiler/cpp/cpp_parse_function_generator.h> + +#include <algorithm> +#include <limits> +#include <string> + +#include <compiler/cpp/cpp_helpers.h> +#include <wire_format.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { + +namespace { +using google::protobuf::internal::TcFieldData; +using google::protobuf::internal::WireFormat; +using google::protobuf::internal::WireFormatLite; + +std::vector<const FieldDescriptor*> GetOrderedFields( + const Descriptor* descriptor, const Options& options) { + std::vector<const FieldDescriptor*> ordered_fields; + for (auto field : FieldRange(descriptor)) { + if (!IsFieldStripped(field, options)) { + ordered_fields.push_back(field); + } + } + std::sort(ordered_fields.begin(), ordered_fields.end(), + [](const FieldDescriptor* a, const FieldDescriptor* b) { + return a->number() < b->number(); + }); + return ordered_fields; +} + +bool HasInternalAccessors(const FieldOptions::CType ctype) { + return ctype == FieldOptions::STRING || ctype == FieldOptions::CORD; +} + +int TagSize(uint32_t field_number) { + if (field_number < 16) return 1; + GOOGLE_CHECK_LT(field_number, (1 << 14)) + << "coded tag for " << field_number << " too big for uint16_t"; + return 2; +} + +const char* CodedTagType(int tag_size) { + return tag_size == 1 ? "uint8_t" : "uint16_t"; +} + +const char* TagType(const FieldDescriptor* field) { + return CodedTagType(TagSize(field->number())); +} + +std::string TcParserName(const Options& options) { + return StrCat("::", ProtobufNamespace(options), + "::internal::TcParser::"); +} + +std::string MessageTcParseFunctionName(const FieldDescriptor* field, + const Options& options) { + if (field->message_type()->field_count() == 0 || + !HasGeneratedMethods(field->message_type()->file(), options)) { + // For files with `option optimize_for = CODE_SIZE`, or which derive from + // `ZeroFieldsBase`, we need to call the `_InternalParse` function, because + // there is no generated tailcall function. For tailcall parsing, this is + // done by helpers in TcParser. + return StrCat(TcParserName(options), + (field->is_repeated() ? "Repeated" : "Singular"), + "ParseMessage<", + QualifiedClassName(field->message_type()), // + ", ", TagType(field), ">"); + } + // This matches macros in generated_message_tctable_impl.h: + return StrCat("PROTOBUF_TC_PARSE_", + (field->is_repeated() ? "REPEATED" : "SINGULAR"), + TagSize(field->number()), "(", + QualifiedClassName(field->message_type()), ")"); +} + +std::string FieldParseFunctionName(const FieldDescriptor* field, + const Options& options); + +} // namespace + +TailCallTableInfo::TailCallTableInfo(const Descriptor* descriptor, + const Options& options, + const std::vector<int>& has_bit_indices, + MessageSCCAnalyzer* scc_analyzer) { + std::vector<const FieldDescriptor*> ordered_fields = + GetOrderedFields(descriptor, options); + + // The table size is rounded up to the nearest power of 2, clamping at 2^5. + // Note that this is a naive approach: a better approach should only consider + // table-eligible fields. We may also want to push rarely-encountered fields + // into the fallback, to make the table smaller. + table_size_log2 = ordered_fields.size() >= 16 ? 5 + : ordered_fields.size() >= 8 ? 4 + : ordered_fields.size() >= 4 ? 3 + : ordered_fields.size() >= 2 ? 2 + : 1; + const unsigned table_size = 1 << table_size_log2; + + // Construct info for each possible entry. Fields that do not use table-driven + // parsing will still have an entry that nominates the fallback function. + fast_path_fields.resize(table_size); + + for (const auto* field : ordered_fields) { + // Eagerly assume slow path. If we can handle this field on the fast path, + // we will pop its entry from `fallback_fields`. + fallback_fields.push_back(field); + + // Anything difficult slow path: + if (field->is_map()) continue; + if (field->real_containing_oneof()) continue; + if (field->options().weak()) continue; + if (IsImplicitWeakField(field, options, scc_analyzer)) continue; + if (IsLazy(field, options, scc_analyzer)) continue; + + // The largest tag that can be read by the tailcall parser is two bytes + // when varint-coded. This allows 14 bits for the numeric tag value: + // byte 0 byte 1 + // 1nnnnttt 0nnnnnnn + // ^^^^^^^ ^^^^^^^ + uint32_t tag = WireFormat::MakeTag(field); + if (tag >= 1 << 14) { + continue; + } else if (tag >= 1 << 7) { + tag = ((tag << 1) & 0x7F00) | 0x80 | (tag & 0x7F); + } + // The field index is determined by the low bits of the field number, where + // the table size determines the width of the mask. The largest table + // supported is 32 entries. The parse loop uses these bits directly, so that + // the dispatch does not require arithmetic: + // byte 0 byte 1 + // 1nnnnttt 0nnnnnnn + // ^^^^^ + // This means that any field number that does not fit in the lower 4 bits + // will always have the top bit of its table index asserted: + uint32_t idx = (tag >> 3) & (table_size - 1); + // If this entry in the table is already used, then this field will be + // handled by the generated fallback function. + if (!fast_path_fields[idx].func_name.empty()) continue; + + // Determine the hasbit mask for this field, if needed. (Note that fields + // without hasbits use different parse functions.) + int hasbit_idx; + if (HasHasbit(field)) { + hasbit_idx = has_bit_indices[field->index()]; + GOOGLE_CHECK_NE(-1, hasbit_idx) << field->DebugString(); + // The tailcall parser can only update the first 32 hasbits. If this + // field's has-bit is beyond that, then it will need to be handled by the + // fallback parse function. + if (hasbit_idx >= 32) continue; + } else { + // The tailcall parser only ever syncs 32 has-bits, so if there is no + // presence, set a bit that will not be used. + hasbit_idx = 63; + } + + // Determine the name of the fastpath parse function to use for this field. + std::string name; + + switch (field->type()) { + case FieldDescriptor::TYPE_MESSAGE: + name = MessageTcParseFunctionName(field, options); + break; + + case FieldDescriptor::TYPE_FIXED64: + case FieldDescriptor::TYPE_FIXED32: + case FieldDescriptor::TYPE_SFIXED64: + case FieldDescriptor::TYPE_SFIXED32: + case FieldDescriptor::TYPE_DOUBLE: + case FieldDescriptor::TYPE_FLOAT: + case FieldDescriptor::TYPE_INT64: + case FieldDescriptor::TYPE_INT32: + case FieldDescriptor::TYPE_UINT64: + case FieldDescriptor::TYPE_UINT32: + case FieldDescriptor::TYPE_SINT64: + case FieldDescriptor::TYPE_SINT32: + case FieldDescriptor::TYPE_BOOL: + name = FieldParseFunctionName(field, options); + break; + + case FieldDescriptor::TYPE_BYTES: + if (field->options().ctype() == FieldOptions::STRING && + field->default_value_string().empty() && + !IsStringInlined(field, options)) { + name = FieldParseFunctionName(field, options); + } + break; + + default: + break; + } + + if (name.empty()) { + continue; + } + // This field made it into the fast path, so remove it from the fallback + // fields and fill in the table entry. + fallback_fields.pop_back(); + fast_path_fields[idx].func_name = name; + fast_path_fields[idx].bits = TcFieldData(tag, hasbit_idx, 0); + fast_path_fields[idx].field = field; + } + + // If there are no fallback fields, and at most one extension range, the + // parser can use a generic fallback function. Otherwise, a message-specific + // fallback routine is needed. + use_generated_fallback = + !fallback_fields.empty() || descriptor->extension_range_count() > 1; +} + +ParseFunctionGenerator::ParseFunctionGenerator( + const Descriptor* descriptor, int max_has_bit_index, + const std::vector<int>& has_bit_indices, + const std::vector<int>& inlined_string_indices, const Options& options, + MessageSCCAnalyzer* scc_analyzer, + const std::map<std::string, std::string>& vars) + : descriptor_(descriptor), + scc_analyzer_(scc_analyzer), + options_(options), + variables_(vars), + inlined_string_indices_(inlined_string_indices), + num_hasbits_(max_has_bit_index) { + if (should_generate_tctable()) { + tc_table_info_.reset(new TailCallTableInfo(descriptor_, options_, + has_bit_indices, scc_analyzer)); + } + SetCommonVars(options_, &variables_); + SetUnknownFieldsVariable(descriptor_, options_, &variables_); + variables_["classname"] = ClassName(descriptor, false); +} + +void ParseFunctionGenerator::GenerateMethodDecls(io::Printer* printer) { + Formatter format(printer, variables_); + if (should_generate_tctable()) { + auto declare_function = [&format](const char* name, + const std::string& guard) { + if (!guard.empty()) { + format.Outdent(); + format("#if $1$\n", guard); + format.Indent(); + } + format("static const char* $1$(PROTOBUF_TC_PARAM_DECL);\n", name); + if (!guard.empty()) { + format.Outdent(); + format("#endif // $1$\n", guard); + format.Indent(); + } + }; + if (should_generate_guarded_tctable()) { + format.Outdent(); + format("#ifdef PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED\n"); + format.Indent(); + } + format("// The Tct_* functions are internal to the protobuf runtime:\n"); + // These guards are defined in port_def.inc: + declare_function("Tct_ParseS1", "PROTOBUF_TC_STATIC_PARSE_SINGULAR1"); + declare_function("Tct_ParseS2", "PROTOBUF_TC_STATIC_PARSE_SINGULAR2"); + declare_function("Tct_ParseR1", "PROTOBUF_TC_STATIC_PARSE_REPEATED1"); + declare_function("Tct_ParseR2", "PROTOBUF_TC_STATIC_PARSE_REPEATED2"); + if (tc_table_info_->use_generated_fallback) { + format.Outdent(); + format( + " private:\n" + " "); + declare_function("Tct_ParseFallback", ""); + format(" public:\n"); + format.Indent(); + } + if (should_generate_guarded_tctable()) { + format.Outdent(); + format("#endif\n"); + format.Indent(); + } + } + format( + "const char* _InternalParse(const char* ptr, " + "::$proto_ns$::internal::ParseContext* ctx) final;\n"); +} + +void ParseFunctionGenerator::GenerateMethodImpls(io::Printer* printer) { + Formatter format(printer, variables_); + bool need_parse_function = true; + if (descriptor_->options().message_set_wire_format()) { + // Special-case MessageSet. + need_parse_function = false; + format( + "const char* $classname$::_InternalParse(const char* ptr,\n" + " ::$proto_ns$::internal::ParseContext* ctx) {\n" + "$annotate_deserialize$" + " return _extensions_.ParseMessageSet(ptr, \n" + " internal_default_instance(), &_internal_metadata_, ctx);\n" + "}\n"); + } + if (!should_generate_tctable()) { + if (need_parse_function) { + GenerateLoopingParseFunction(format); + } + return; + } + if (should_generate_guarded_tctable()) { + format("#ifdef PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED\n\n"); + } + if (need_parse_function) { + GenerateTailcallParseFunction(format); + } + if (tc_table_info_->use_generated_fallback) { + GenerateTailcallFallbackFunction(format); + } + GenerateTailcallFieldParseFunctions(format); + if (should_generate_guarded_tctable()) { + if (need_parse_function) { + format("\n#else // PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED\n\n"); + GenerateLoopingParseFunction(format); + } + format("\n#endif // PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED\n"); + } +} + +bool ParseFunctionGenerator::should_generate_tctable() const { + if (options_.tctable_mode == Options::kTCTableNever) { + return false; + } + return true; +} + +void ParseFunctionGenerator::GenerateTailcallParseFunction(Formatter& format) { + GOOGLE_CHECK(should_generate_tctable()); + + // Generate an `_InternalParse` that starts the tail-calling loop. + format( + "const char* $classname$::_InternalParse(\n" + " const char* ptr, ::$proto_ns$::internal::ParseContext* ctx) {\n" + "$annotate_deserialize$" + " ptr = ::$proto_ns$::internal::TcParser::ParseLoop(\n" + " this, ptr, ctx, &_table_.header);\n"); + format( + " return ptr;\n" + "}\n\n"); +} + +void ParseFunctionGenerator::GenerateTailcallFallbackFunction( + Formatter& format) { + GOOGLE_CHECK(should_generate_tctable()); + format( + "const char* $classname$::Tct_ParseFallback(PROTOBUF_TC_PARAM_DECL) {\n" + "#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) return nullptr\n"); + format.Indent(); + format("auto* typed_msg = static_cast<$classname$*>(msg);\n"); + + if (num_hasbits_ > 0) { + // Sync hasbits + format("typed_msg->_has_bits_[0] = hasbits;\n"); + } + + format.Set("msg", "typed_msg->"); + format.Set("this", "typed_msg"); + format.Set("has_bits", "typed_msg->_has_bits_"); + format.Set("next_tag", "goto next_tag"); + GenerateParseIterationBody(format, descriptor_, + tc_table_info_->fallback_fields); + + format.Outdent(); + format( + "next_tag:\n" + "message_done:\n" + " return ptr;\n" + "#undef CHK_\n" + "}\n"); +} + +void ParseFunctionGenerator::GenerateTailcallFieldParseFunctions( + Formatter& format) { + GOOGLE_CHECK(should_generate_tctable()); + // There are four cases where a tailcall target are needed for messages: + // {singular, repeated} x {1, 2}-byte tag + struct { + const char* type; + int size; + } const kTagLayouts[] = { + {"uint8_t", 1}, + {"uint16_t", 2}, + }; + // Singular: + for (const auto& layout : kTagLayouts) { + // Guard macros are defined in port_def.inc. + format( + "#if PROTOBUF_TC_STATIC_PARSE_SINGULAR$1$\n" + "const char* $classname$::Tct_ParseS$1$(PROTOBUF_TC_PARAM_DECL) {\n" + " if (PROTOBUF_PREDICT_FALSE(data.coded_tag<$2$>() != 0))\n" + " PROTOBUF_MUSTTAIL " + "return table->fallback(PROTOBUF_TC_PARAM_PASS);\n" + " ptr += $1$;\n" + " hasbits |= (uint64_t{1} << data.hasbit_idx());\n" + " ::$proto_ns$::internal::TcParser::SyncHasbits" + "(msg, hasbits, table);\n" + " auto& field = ::$proto_ns$::internal::TcParser::" + "RefAt<$classtype$*>(msg, data.offset());\n" + " if (field == nullptr)\n" + " field = CreateMaybeMessage<$classtype$>(ctx->data().arena);\n" + " return ctx->ParseMessage(field, ptr);\n" + "}\n" + "#endif // PROTOBUF_TC_STATIC_PARSE_SINGULAR$1$\n", + layout.size, layout.type); + } + // Repeated: + for (const auto& layout : kTagLayouts) { + // Guard macros are defined in port_def.inc. + format( + "#if PROTOBUF_TC_STATIC_PARSE_REPEATED$1$\n" + "const char* $classname$::Tct_ParseR$1$(PROTOBUF_TC_PARAM_DECL) {\n" + " if (PROTOBUF_PREDICT_FALSE(data.coded_tag<$2$>() != 0)) {\n" + " PROTOBUF_MUSTTAIL " + "return table->fallback(PROTOBUF_TC_PARAM_PASS);\n" + " }\n" + " ptr += $1$;\n" + " auto& field = ::$proto_ns$::internal::TcParser::RefAt<" + "::$proto_ns$::RepeatedPtrField<$classname$>>(msg, data.offset());\n" + " ::$proto_ns$::internal::TcParser::SyncHasbits" + "(msg, hasbits, table);\n" + " ptr = ctx->ParseMessage(field.Add(), ptr);\n" + " return ptr;\n" + "}\n" + "#endif // PROTOBUF_TC_STATIC_PARSE_REPEATED$1$\n", + layout.size, layout.type); + } +} + +void ParseFunctionGenerator::GenerateDataDecls(io::Printer* printer) { + if (!should_generate_tctable()) { + return; + } + Formatter format(printer, variables_); + if (should_generate_guarded_tctable()) { + format.Outdent(); + format("#ifdef PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED\n"); + format.Indent(); + } + format( + "static const ::$proto_ns$::internal::TcParseTable<$1$>\n" + " _table_;\n", + tc_table_info_->table_size_log2); + if (should_generate_guarded_tctable()) { + format.Outdent(); + format("#endif // PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED\n"); + format.Indent(); + } +} + +void ParseFunctionGenerator::GenerateDataDefinitions(io::Printer* printer) { + if (!should_generate_tctable()) { + return; + } + Formatter format(printer, variables_); + if (should_generate_guarded_tctable()) { + format("#ifdef PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED\n"); + } + GenerateTailCallTable(format); + if (should_generate_guarded_tctable()) { + format("#endif // PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED\n"); + } +} + +void ParseFunctionGenerator::GenerateLoopingParseFunction(Formatter& format) { + format( + "const char* $classname$::_InternalParse(const char* ptr, " + "::$proto_ns$::internal::ParseContext* ctx) {\n" + "$annotate_deserialize$" + "#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure\n"); + format.Indent(); + format.Set("msg", ""); + format.Set("this", "this"); + int hasbits_size = 0; + if (num_hasbits_ > 0) { + hasbits_size = (num_hasbits_ + 31) / 32; + } + // For now only optimize small hasbits. + if (hasbits_size != 1) hasbits_size = 0; + if (hasbits_size) { + format("_Internal::HasBits has_bits{};\n"); + format.Set("has_bits", "has_bits"); + } else { + format.Set("has_bits", "_has_bits_"); + } + format.Set("next_tag", "continue"); + format("while (!ctx->Done(&ptr)) {\n"); + format.Indent(); + + GenerateParseIterationBody(format, descriptor_, + GetOrderedFields(descriptor_, options_)); + + format.Outdent(); + format("} // while\n"); + + format.Outdent(); + format("message_done:\n"); + if (hasbits_size) format(" _has_bits_.Or(has_bits);\n"); + + format( + " return ptr;\n" + "failure:\n" + " ptr = nullptr;\n" + " goto message_done;\n" + "#undef CHK_\n" + "}\n"); +} + +void ParseFunctionGenerator::GenerateTailCallTable(Formatter& format) { + GOOGLE_CHECK(should_generate_tctable()); + // All entries without a fast-path parsing function need a fallback. + std::string fallback; + if (tc_table_info_->use_generated_fallback) { + fallback = ClassName(descriptor_) + "::Tct_ParseFallback"; + } else { + fallback = TcParserName(options_) + "GenericFallback"; + if (GetOptimizeFor(descriptor_->file(), options_) == + FileOptions::LITE_RUNTIME) { + fallback += "Lite"; + } + } + + // For simplicity and speed, the table is not covering all proto + // configurations. This model uses a fallback to cover all situations that + // the table can't accommodate, together with unknown fields or extensions. + // These are number of fields over 32, fields with 3 or more tag bytes, + // maps, weak fields, lazy, more than 1 extension range. In the cases + // the table is sufficient we can use a generic routine, that just handles + // unknown fields and potentially an extension range. + format( + "const ::$proto_ns$::internal::TcParseTable<$1$>\n" + " $classname$::_table_ = {\n", + tc_table_info_->table_size_log2); + { + auto table_scope = format.ScopedIndent(); + format("{\n"); + { + auto header_scope = format.ScopedIndent(); + if (num_hasbits_ > 0 || IsMapEntryMessage(descriptor_)) { + format("PROTOBUF_FIELD_OFFSET($classname$, _has_bits_),\n"); + } else { + format("0, // no _has_bits_\n"); + } + if (descriptor_->extension_range_count() == 1) { + format( + "PROTOBUF_FIELD_OFFSET($classname$, _extensions_),\n" + "$1$, $2$, // extension_range_{low,high}\n", + descriptor_->extension_range(0)->start, + descriptor_->extension_range(0)->end); + } else { + format("0, 0, 0, // no _extensions_\n"); + } + format( + "$1$, 0, $2$, // fast_idx_mask, reserved, num_fields\n" + "&$3$._instance,\n" + "$4$ // fallback\n", + (((1 << tc_table_info_->table_size_log2) - 1) << 3), + descriptor_->field_count(), + DefaultInstanceName(descriptor_, options_), fallback); + } + format("}, {\n"); + { + auto fast_scope = format.ScopedIndent(); + GenerateFastFieldEntries(format, fallback); + } + format("},\n"); // entries[] + } + format("};\n\n"); // _table_ +} + +void ParseFunctionGenerator::GenerateFastFieldEntries( + Formatter& format, const std::string& fallback) { + for (const auto& info : tc_table_info_->fast_path_fields) { + if (info.field != nullptr) { + PrintFieldComment(format, info.field); + } + format("{$1$, ", info.func_name.empty() ? fallback : info.func_name); + if (info.bits.data) { + GOOGLE_DCHECK_NE(nullptr, info.field); + format( + "{$1$, $2$, " + "static_cast<uint16_t>(PROTOBUF_FIELD_OFFSET($classname$, $3$_))}", + info.bits.coded_tag(), info.bits.hasbit_idx(), FieldName(info.field)); + } else { + format("{}"); + } + format("},\n"); + } +} + +void ParseFunctionGenerator::GenerateArenaString(Formatter& format, + const FieldDescriptor* field) { + if (HasHasbit(field)) { + format("_Internal::set_has_$1$(&$has_bits$);\n", FieldName(field)); + } + std::string default_string = + field->default_value_string().empty() + ? "::" + ProtobufNamespace(options_) + + "::internal::GetEmptyStringAlreadyInited()" + : QualifiedClassName(field->containing_type(), options_) + + "::" + MakeDefaultName(field) + ".get()"; + format( + "if (arena != nullptr) {\n" + " ptr = ctx->ReadArenaString(ptr, &$msg$$name$_, arena"); + if (IsStringInlined(field, options_)) { + GOOGLE_DCHECK(!inlined_string_indices_.empty()); + int inlined_string_index = inlined_string_indices_[field->index()]; + GOOGLE_DCHECK_GE(inlined_string_index, 0); + format( + ", $msg$_internal_$name$_donated()" + ", &$msg$_inlined_string_donated_[$1$]" + ", ~0x$2$u", + inlined_string_index / 32, + strings::Hex(1u << (inlined_string_index % 32), strings::ZERO_PAD_8)); + } else { + GOOGLE_DCHECK(field->default_value_string().empty()); + } + format( + ");\n" + "} else {\n" + " ptr = ::$proto_ns$::internal::InlineGreedyStringParser(" + "$msg$$name$_.MutableNoArenaNoDefault(&$1$), ptr, ctx);\n" + "}\n" + "const std::string* str = &$msg$$name$_.Get(); (void)str;\n", + default_string); +} + +void ParseFunctionGenerator::GenerateStrings(Formatter& format, + const FieldDescriptor* field, + bool check_utf8) { + FieldOptions::CType ctype = FieldOptions::STRING; + if (!options_.opensource_runtime) { + // Open source doesn't support other ctypes; + ctype = field->options().ctype(); + } + if (!field->is_repeated() && !options_.opensource_runtime && + GetOptimizeFor(field->file(), options_) != FileOptions::LITE_RUNTIME && + // For now only use arena string for strings with empty defaults. + field->default_value_string().empty() && + !field->real_containing_oneof() && ctype == FieldOptions::STRING) { + GenerateArenaString(format, field); + } else { + std::string parser_name; + switch (ctype) { + case FieldOptions::STRING: + parser_name = "GreedyStringParser"; + break; + case FieldOptions::CORD: + parser_name = "CordParser"; + break; + case FieldOptions::STRING_PIECE: + parser_name = "StringPieceParser"; + break; + } + format( + "auto str = $msg$$1$$2$_$name$();\n" + "ptr = ::$proto_ns$::internal::Inline$3$(str, ptr, ctx);\n", + HasInternalAccessors(ctype) ? "_internal_" : "", + field->is_repeated() && !field->is_packable() ? "add" : "mutable", + parser_name); + } + if (!check_utf8) return; // return if this is a bytes field + auto level = GetUtf8CheckMode(field, options_); + switch (level) { + case Utf8CheckMode::kNone: + return; + case Utf8CheckMode::kVerify: + format("#ifndef NDEBUG\n"); + break; + case Utf8CheckMode::kStrict: + format("CHK_("); + break; + } + std::string field_name; + field_name = "nullptr"; + if (HasDescriptorMethods(field->file(), options_)) { + field_name = StrCat("\"", field->full_name(), "\""); + } + format("::$proto_ns$::internal::VerifyUTF8(str, $1$)", field_name); + switch (level) { + case Utf8CheckMode::kNone: + return; + case Utf8CheckMode::kVerify: + format( + ";\n" + "#endif // !NDEBUG\n"); + break; + case Utf8CheckMode::kStrict: + format(");\n"); + break; + } +} + +void ParseFunctionGenerator::GenerateLengthDelim(Formatter& format, + const FieldDescriptor* field) { + if (field->is_packable()) { + if (field->type() == FieldDescriptor::TYPE_ENUM && + !HasPreservingUnknownEnumSemantics(field)) { + std::string enum_type = QualifiedClassName(field->enum_type(), options_); + format( + "ptr = " + "::$proto_ns$::internal::Packed$1$Parser<$unknown_fields_type$>(" + "$msg$_internal_mutable_$name$(), ptr, ctx, $2$_IsValid, " + "&$msg$_internal_metadata_, $3$);\n", + DeclaredTypeMethodName(field->type()), enum_type, field->number()); + } else { + format( + "ptr = ::$proto_ns$::internal::Packed$1$Parser(" + "$msg$_internal_mutable_$name$(), ptr, ctx);\n", + DeclaredTypeMethodName(field->type())); + } + } else { + auto field_type = field->type(); + switch (field_type) { + case FieldDescriptor::TYPE_STRING: + GenerateStrings(format, field, true /* utf8 */); + break; + case FieldDescriptor::TYPE_BYTES: + GenerateStrings(format, field, false /* utf8 */); + break; + case FieldDescriptor::TYPE_MESSAGE: { + if (field->is_map()) { + const FieldDescriptor* val = + field->message_type()->FindFieldByName("value"); + GOOGLE_CHECK(val); + if (val->type() == FieldDescriptor::TYPE_ENUM && + !HasPreservingUnknownEnumSemantics(field)) { + format( + "auto object = " + "::$proto_ns$::internal::InitEnumParseWrapper<" + "$unknown_fields_type$>(&$msg$$name$_, $1$_IsValid, " + "$2$, &$msg$_internal_metadata_);\n" + "ptr = ctx->ParseMessage(&object, ptr);\n", + QualifiedClassName(val->enum_type(), options_), + field->number()); + } else { + format("ptr = ctx->ParseMessage(&$msg$$name$_, ptr);\n"); + } + } else if (IsLazy(field, options_, scc_analyzer_)) { + if (field->real_containing_oneof()) { + format( + "if (!$msg$_internal_has_$name$()) {\n" + " $msg$clear_$1$();\n" + " $msg$$1$_.$name$_ = ::$proto_ns$::Arena::CreateMessage<\n" + " ::$proto_ns$::internal::LazyField>(" + "$msg$GetArenaForAllocation());\n" + " $msg$set_has_$name$();\n" + "}\n" + "auto* lazy_field = $msg$$1$_.$name$_;\n", + field->containing_oneof()->name()); + } else if (HasHasbit(field)) { + format( + "_Internal::set_has_$name$(&$has_bits$);\n" + "auto* lazy_field = &$msg$$name$_;\n"); + } else { + format("auto* lazy_field = &$msg$$name$_;\n"); + } + format( + "::$proto_ns$::internal::LazyFieldParseHelper<\n" + " ::$proto_ns$::internal::LazyField> parse_helper(\n" + " $1$::default_instance(),\n" + " $msg$GetArenaForAllocation(), lazy_field);\n" + "ptr = ctx->ParseMessage(&parse_helper, ptr);\n", + FieldMessageTypeName(field, options_)); + } else if (IsImplicitWeakField(field, options_, scc_analyzer_)) { + if (!field->is_repeated()) { + format( + "ptr = ctx->ParseMessage(_Internal::mutable_$name$($this$), " + "ptr);\n"); + } else { + format( + "ptr = ctx->ParseMessage($msg$$name$_.AddWeak(" + "reinterpret_cast<const ::$proto_ns$::MessageLite*>($1$ptr_)" + "), ptr);\n", + QualifiedDefaultInstanceName(field->message_type(), options_)); + } + } else if (IsWeak(field, options_)) { + format( + "{\n" + " auto* default_ = &reinterpret_cast<const Message&>($1$);\n" + " ptr = ctx->ParseMessage($msg$_weak_field_map_.MutableMessage(" + "$2$, default_), ptr);\n" + "}\n", + QualifiedDefaultInstanceName(field->message_type(), options_), + field->number()); + } else { + format( + "ptr = ctx->ParseMessage($msg$_internal_$mutable_field$(), " + "ptr);\n"); + } + break; + } + default: + GOOGLE_LOG(FATAL) << "Illegal combination for length delimited wiretype " + << " filed type is " << field->type(); + } + } +} + +static bool ShouldRepeat(const FieldDescriptor* descriptor, + WireFormatLite::WireType wiretype) { + constexpr int kMaxTwoByteFieldNumber = 16 * 128; + return descriptor->number() < kMaxTwoByteFieldNumber && + descriptor->is_repeated() && + (!descriptor->is_packable() || + wiretype != WireFormatLite::WIRETYPE_LENGTH_DELIMITED); +} + +void ParseFunctionGenerator::GenerateFieldBody( + Formatter& format, WireFormatLite::WireType wiretype, + const FieldDescriptor* field) { + Formatter::SaveState formatter_state(&format); + format.AddMap( + {{"name", FieldName(field)}, + {"primitive_type", PrimitiveTypeName(options_, field->cpp_type())}}); + if (field->is_repeated()) { + format.AddMap({{"put_field", StrCat("add_", FieldName(field))}, + {"mutable_field", StrCat("add_", FieldName(field))}}); + } else { + format.AddMap( + {{"put_field", StrCat("set_", FieldName(field))}, + {"mutable_field", StrCat("mutable_", FieldName(field))}}); + } + uint32_t tag = WireFormatLite::MakeTag(field->number(), wiretype); + switch (wiretype) { + case WireFormatLite::WIRETYPE_VARINT: { + std::string type = PrimitiveTypeName(options_, field->cpp_type()); + if (field->type() == FieldDescriptor::TYPE_ENUM) { + format.Set("enum_type", + QualifiedClassName(field->enum_type(), options_)); + format( + "$uint64$ val = ::$proto_ns$::internal::ReadVarint64(&ptr);\n" + "CHK_(ptr);\n"); + if (!HasPreservingUnknownEnumSemantics(field)) { + format("if (PROTOBUF_PREDICT_TRUE($enum_type$_IsValid(val))) {\n"); + format.Indent(); + } + format("$msg$_internal_$put_field$(static_cast<$enum_type$>(val));\n"); + if (!HasPreservingUnknownEnumSemantics(field)) { + format.Outdent(); + format( + "} else {\n" + " ::$proto_ns$::internal::WriteVarint(" + "$1$, val, $msg$mutable_unknown_fields());\n" + "}\n", + field->number()); + } + } else { + std::string size = (field->type() == FieldDescriptor::TYPE_INT32 || + field->type() == FieldDescriptor::TYPE_SINT32 || + field->type() == FieldDescriptor::TYPE_UINT32) + ? "32" + : "64"; + std::string zigzag; + if ((field->type() == FieldDescriptor::TYPE_SINT32 || + field->type() == FieldDescriptor::TYPE_SINT64)) { + zigzag = "ZigZag"; + } + if (field->is_repeated() || field->real_containing_oneof()) { + format( + "$msg$_internal_$put_field$(" + "::$proto_ns$::internal::ReadVarint$1$$2$(&ptr));\n" + "CHK_(ptr);\n", + zigzag, size); + } else { + if (HasHasbit(field)) { + format("_Internal::set_has_$name$(&$has_bits$);\n"); + } + format( + "$msg$$name$_ = ::$proto_ns$::internal::ReadVarint$1$$2$(&ptr);\n" + "CHK_(ptr);\n", + zigzag, size); + } + } + break; + } + case WireFormatLite::WIRETYPE_FIXED32: + case WireFormatLite::WIRETYPE_FIXED64: { + if (field->is_repeated() || field->real_containing_oneof()) { + format( + "$msg$_internal_$put_field$(" + "::$proto_ns$::internal::UnalignedLoad<$primitive_type$>(ptr));\n" + "ptr += sizeof($primitive_type$);\n"); + } else { + if (HasHasbit(field)) { + format("_Internal::set_has_$name$(&$has_bits$);\n"); + } + format( + "$msg$$name$_ = " + "::$proto_ns$::internal::UnalignedLoad<$primitive_type$>(ptr);\n" + "ptr += sizeof($primitive_type$);\n"); + } + break; + } + case WireFormatLite::WIRETYPE_LENGTH_DELIMITED: { + GenerateLengthDelim(format, field); + format("CHK_(ptr);\n"); + break; + } + case WireFormatLite::WIRETYPE_START_GROUP: { + format( + "ptr = ctx->ParseGroup($msg$_internal_$mutable_field$(), ptr, $1$);\n" + "CHK_(ptr);\n", + tag); + break; + } + case WireFormatLite::WIRETYPE_END_GROUP: { + GOOGLE_LOG(FATAL) << "Can't have end group field\n"; + break; + } + } // switch (wire_type) +} + +// Returns the tag for this field and in case of repeated packable fields, +// sets a fallback tag in fallback_tag_ptr. +static uint32_t ExpectedTag(const FieldDescriptor* field, + uint32_t* fallback_tag_ptr) { + uint32_t expected_tag; + if (field->is_packable()) { + auto expected_wiretype = WireFormat::WireTypeForFieldType(field->type()); + expected_tag = WireFormatLite::MakeTag(field->number(), expected_wiretype); + GOOGLE_CHECK(expected_wiretype != WireFormatLite::WIRETYPE_LENGTH_DELIMITED); + auto fallback_wiretype = WireFormatLite::WIRETYPE_LENGTH_DELIMITED; + uint32_t fallback_tag = + WireFormatLite::MakeTag(field->number(), fallback_wiretype); + + if (field->is_packed()) std::swap(expected_tag, fallback_tag); + *fallback_tag_ptr = fallback_tag; + } else { + auto expected_wiretype = WireFormat::WireTypeForField(field); + expected_tag = WireFormatLite::MakeTag(field->number(), expected_wiretype); + } + return expected_tag; +} + +// These variables are used by the generated parse iteration, and must already +// be defined in the generated code: +// - `const char* ptr`: the input buffer. +// - `ParseContext* ctx`: the associated context for `ptr`. +// - implicit `this`: i.e., we must be in a non-static member function. +// +// The macro `CHK_(x)` must be defined. It should return an error condition if +// the macro parameter is false. +// +// Whenever an END_GROUP tag was read, or tag 0 was read, the generated code +// branches to the label `message_done`. +// +// These formatter variables are used: +// - `next_tag`: a single statement to begin parsing the next tag. +// +// At the end of the generated code, the enclosing function should proceed to +// parse the next tag in the stream. +void ParseFunctionGenerator::GenerateParseIterationBody( + Formatter& format, const Descriptor* descriptor, + const std::vector<const FieldDescriptor*>& ordered_fields) { + format( + "$uint32$ tag;\n" + "ptr = ::$proto_ns$::internal::ReadTag(ptr, &tag);\n"); + + if (!ordered_fields.empty()) { + GenerateFieldSwitch(format, ordered_fields); + // Each field `case` only considers field number. Field numbers that are + // not defined in the message, or tags with an incompatible wire type, are + // considered "unusual" cases. They will be handled by the logic below. + format.Outdent(); + format("handle_unusual:\n"); + format.Indent(); + } + + // Unusual/extension/unknown case: + format( + "if ((tag == 0) || ((tag & 7) == 4)) {\n" + " CHK_(ptr);\n" + " ctx->SetLastTag(tag);\n" + " goto message_done;\n" + "}\n"); + if (IsMapEntryMessage(descriptor)) { + format("$next_tag$;\n"); + } else { + if (descriptor->extension_range_count() > 0) { + format("if ("); + for (int i = 0; i < descriptor->extension_range_count(); i++) { + const Descriptor::ExtensionRange* range = + descriptor->extension_range(i); + if (i > 0) format(" ||\n "); + + uint32_t start_tag = WireFormatLite::MakeTag( + range->start, static_cast<WireFormatLite::WireType>(0)); + uint32_t end_tag = WireFormatLite::MakeTag( + range->end, static_cast<WireFormatLite::WireType>(0)); + + if (range->end > FieldDescriptor::kMaxNumber) { + format("($1$u <= tag)", start_tag); + } else { + format("($1$u <= tag && tag < $2$u)", start_tag, end_tag); + } + } + format( + ") {\n" + " ptr = $msg$_extensions_.ParseField(tag, ptr, " + "internal_default_instance(), &$msg$_internal_metadata_, ctx);\n" + " CHK_(ptr != nullptr);\n" + " $next_tag$;\n" + "}\n"); + } + format( + "ptr = UnknownFieldParse(\n" + " tag,\n" + " $msg$_internal_metadata_.mutable_unknown_fields<" + "$unknown_fields_type$>(),\n" + " ptr, ctx);\n" + "CHK_(ptr != nullptr);\n"); + } +} + +void ParseFunctionGenerator::GenerateFieldSwitch( + Formatter& format, + const std::vector<const FieldDescriptor*>& ordered_fields) { + format("switch (tag >> 3) {\n"); + format.Indent(); + + for (const auto* field : ordered_fields) { + PrintFieldComment(format, field); + format("case $1$:\n", field->number()); + format.Indent(); + uint32_t fallback_tag = 0; + uint32_t expected_tag = ExpectedTag(field, &fallback_tag); + format("if (PROTOBUF_PREDICT_TRUE(static_cast<$uint8$>(tag) == $1$)) {\n", + expected_tag & 0xFF); + format.Indent(); + auto wiretype = WireFormatLite::GetTagWireType(expected_tag); + uint32_t tag = WireFormatLite::MakeTag(field->number(), wiretype); + int tag_size = io::CodedOutputStream::VarintSize32(tag); + bool is_repeat = ShouldRepeat(field, wiretype); + if (is_repeat) { + format( + "ptr -= $1$;\n" + "do {\n" + " ptr += $1$;\n", + tag_size); + format.Indent(); + } + GenerateFieldBody(format, wiretype, field); + if (is_repeat) { + format.Outdent(); + format( + " if (!ctx->DataAvailable(ptr)) break;\n" + "} while (::$proto_ns$::internal::ExpectTag<$1$>(ptr));\n", + tag); + } + format.Outdent(); + if (fallback_tag) { + format("} else if (static_cast<$uint8$>(tag) == $1$) {\n", + fallback_tag & 0xFF); + format.Indent(); + GenerateFieldBody(format, WireFormatLite::GetTagWireType(fallback_tag), + field); + format.Outdent(); + } + format( + "} else\n" + " goto handle_unusual;\n" + "$next_tag$;\n"); + format.Outdent(); + } // for loop over ordered fields + + format( + "default:\n" + " goto handle_unusual;\n"); + format.Outdent(); + format("} // switch\n"); +} + +namespace { + +std::string FieldParseFunctionName(const FieldDescriptor* field, + const Options& options) { + ParseCardinality card = // + field->is_packed() ? ParseCardinality::kPacked + : field->is_repeated() ? ParseCardinality::kRepeated + : field->real_containing_oneof() ? ParseCardinality::kOneof + : ParseCardinality::kSingular; + + TypeFormat type_format; + switch (field->type()) { + case FieldDescriptor::TYPE_FIXED64: + case FieldDescriptor::TYPE_SFIXED64: + case FieldDescriptor::TYPE_DOUBLE: + type_format = TypeFormat::kFixed64; + break; + + case FieldDescriptor::TYPE_FIXED32: + case FieldDescriptor::TYPE_SFIXED32: + case FieldDescriptor::TYPE_FLOAT: + type_format = TypeFormat::kFixed32; + break; + + case FieldDescriptor::TYPE_INT64: + case FieldDescriptor::TYPE_UINT64: + type_format = TypeFormat::kVar64; + break; + + case FieldDescriptor::TYPE_INT32: + case FieldDescriptor::TYPE_UINT32: + type_format = TypeFormat::kVar32; + break; + + case FieldDescriptor::TYPE_SINT64: + type_format = TypeFormat::kSInt64; + break; + + case FieldDescriptor::TYPE_SINT32: + type_format = TypeFormat::kSInt32; + break; + + case FieldDescriptor::TYPE_BOOL: + type_format = TypeFormat::kBool; + break; + + case FieldDescriptor::TYPE_BYTES: + type_format = TypeFormat::kBytes; + break; + + case FieldDescriptor::TYPE_STRING: + switch (GetUtf8CheckMode(field, options)) { + case Utf8CheckMode::kNone: + type_format = TypeFormat::kBytes; + break; + case Utf8CheckMode::kStrict: + type_format = TypeFormat::kString; + break; + case Utf8CheckMode::kVerify: + type_format = TypeFormat::kStringValidateOnly; + break; + default: + GOOGLE_LOG(DFATAL) << "Mode not handled: " + << static_cast<int>(GetUtf8CheckMode(field, options)); + return ""; + } + break; + + default: + GOOGLE_LOG(DFATAL) << "Type not handled: " << field->DebugString(); + return ""; + } + + return "::" + ProtobufNamespace(options) + "::internal::TcParser::" + + GetTailCallFieldHandlerName(card, type_format, + TagSize(field->number()), options); +} + +} // namespace + +std::string GetTailCallFieldHandlerName(ParseCardinality card, + TypeFormat type_format, + int tag_length_bytes, + const Options& options) { + std::string name; + + // The field implementation functions are prefixed by cardinality: + // `Singular` for optional or implicit fields. + // `Repeated` for non-packed repeated. + // `Packed` for packed repeated. + switch (card) { + case ParseCardinality::kSingular: + name.append("Singular"); + break; + case ParseCardinality::kOneof: + name.append("Oneof"); + break; + case ParseCardinality::kRepeated: + name.append("Repeated"); + break; + case ParseCardinality::kPacked: + name.append("Packed"); + break; + } + + // Next in the function name is the TypeFormat-specific name. + switch (type_format) { + case TypeFormat::kFixed64: + case TypeFormat::kFixed32: + name.append("Fixed"); + break; + + case TypeFormat::kVar64: + case TypeFormat::kVar32: + case TypeFormat::kSInt64: + case TypeFormat::kSInt32: + case TypeFormat::kBool: + name.append("Varint"); + break; + + case TypeFormat::kBytes: + case TypeFormat::kString: + case TypeFormat::kStringValidateOnly: + name.append("String"); + break; + + default: + break; + } + + name.append("<"); + + // Determine the numeric layout type for the parser to use, independent of + // the specific parsing logic used. + switch (type_format) { + case TypeFormat::kVar64: + case TypeFormat::kFixed64: + name.append("uint64_t, "); + break; + + case TypeFormat::kSInt64: + name.append("int64_t, "); + break; + + case TypeFormat::kVar32: + case TypeFormat::kFixed32: + name.append("uint32_t, "); + break; + + case TypeFormat::kSInt32: + name.append("int32_t, "); + break; + + case TypeFormat::kBool: + name.append("bool, "); + break; + + default: + break; + } + + name.append(CodedTagType(tag_length_bytes)); + + switch (type_format) { + case TypeFormat::kVar64: + case TypeFormat::kVar32: + case TypeFormat::kBool: + StrAppend(&name, ", ", TcParserName(options), "kNoConversion"); + break; + + case TypeFormat::kSInt64: + case TypeFormat::kSInt32: + StrAppend(&name, ", ", TcParserName(options), "kZigZag"); + break; + + case TypeFormat::kBytes: + StrAppend(&name, ", ", TcParserName(options), "kNoUtf8"); + break; + + case TypeFormat::kString: + StrAppend(&name, ", ", TcParserName(options), "kUtf8"); + break; + + case TypeFormat::kStringValidateOnly: + StrAppend(&name, ", ", TcParserName(options), "kUtf8ValidateOnly"); + break; + + default: + break; + } + + name.append(">"); + return name; +} + +} // namespace cpp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_parse_function_generator.h b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_parse_function_generator.h new file mode 100644 index 00000000..54c0a36d --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_parse_function_generator.h @@ -0,0 +1,199 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_PARSE_FUNCTION_GENERATOR_H__ +#define GOOGLE_PROTOBUF_COMPILER_CPP_PARSE_FUNCTION_GENERATOR_H__ + +#include <map> +#include <string> +#include <vector> + +#include <compiler/cpp/cpp_helpers.h> +#include <compiler/cpp/cpp_options.h> +#include <io/printer.h> +#include <descriptor.h> +#include <generated_message_tctable_decl.h> +#include <wire_format_lite.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { + +// Helper class for generating tailcall parsing functions. +struct TailCallTableInfo { + TailCallTableInfo(const Descriptor* descriptor, const Options& options, + const std::vector<int>& has_bit_indices, + MessageSCCAnalyzer* scc_analyzer); + // Information to generate field entries. + struct FieldInfo { + const FieldDescriptor* field; + google::protobuf::internal::TcFieldData bits; + std::string func_name; + }; + // Fields parsed by the table fast-path. + std::vector<FieldInfo> fast_path_fields; + // Fields parsed by slow-path fallback. + std::vector<const FieldDescriptor*> fallback_fields; + // Table size. + int table_size_log2; + // Mask for has-bits of required fields. + uint32_t has_hasbits_required_mask; + // True if a generated fallback function is required instead of generic. + bool use_generated_fallback; +}; + +// ParseFunctionGenerator generates the _InternalParse function for a message +// (and any associated supporting members). +class ParseFunctionGenerator { + public: + ParseFunctionGenerator(const Descriptor* descriptor, int max_has_bit_index, + const std::vector<int>& has_bit_indices, + const std::vector<int>& inlined_string_indices, + const Options& options, + MessageSCCAnalyzer* scc_analyzer, + const std::map<std::string, std::string>& vars); + + // Emits class-level method declarations to `printer`: + void GenerateMethodDecls(io::Printer* printer); + + // Emits out-of-class method implementation definitions to `printer`: + void GenerateMethodImpls(io::Printer* printer); + + // Emits class-level data member declarations to `printer`: + void GenerateDataDecls(io::Printer* printer); + + // Emits out-of-class data member definitions to `printer`: + void GenerateDataDefinitions(io::Printer* printer); + + private: + // Returns true if tailcall table code should be generated. + bool should_generate_tctable() const; + + // Returns true if tailcall table code should be generated, but inside an + // #ifdef guard. + bool should_generate_guarded_tctable() const { + return should_generate_tctable() && + options_.tctable_mode == Options::kTCTableGuarded; + } + + // Generates a tail-calling `_InternalParse` function. + void GenerateTailcallParseFunction(Formatter& format); + + // Generates a fallback function for tailcall table-based parsing. + void GenerateTailcallFallbackFunction(Formatter& format); + + // Generates functions for parsing this message as a field. + void GenerateTailcallFieldParseFunctions(Formatter& format); + + // Generates a looping `_InternalParse` function. + void GenerateLoopingParseFunction(Formatter& format); + + // Generates the tail-call table definition. + void GenerateTailCallTable(Formatter& format); + void GenerateFastFieldEntries(Formatter& format, const std::string& fallback); + + // Generates parsing code for an `ArenaString` field. + void GenerateArenaString(Formatter& format, const FieldDescriptor* field); + + // Generates parsing code for a string-typed field. + void GenerateStrings(Formatter& format, const FieldDescriptor* field, + bool check_utf8); + + // Generates parsing code for a length-delimited field (strings, messages, + // etc.). + void GenerateLengthDelim(Formatter& format, const FieldDescriptor* field); + + // Generates the parsing code for a known field. + void GenerateFieldBody(Formatter& format, + google::protobuf::internal::WireFormatLite::WireType wiretype, + const FieldDescriptor* field); + + // Generates code to parse the next field from the input stream. + void GenerateParseIterationBody( + Formatter& format, const Descriptor* descriptor, + const std::vector<const FieldDescriptor*>& ordered_fields); + + // Generates a `switch` statement to parse each of `ordered_fields`. + void GenerateFieldSwitch( + Formatter& format, + const std::vector<const FieldDescriptor*>& ordered_fields); + + const Descriptor* descriptor_; + MessageSCCAnalyzer* scc_analyzer_; + const Options& options_; + std::map<std::string, std::string> variables_; + std::unique_ptr<TailCallTableInfo> tc_table_info_; + std::vector<int> inlined_string_indices_; + int num_hasbits_; +}; + +enum class ParseCardinality { + kSingular, + kOneof, + kRepeated, + kPacked, +}; + +// TypeFormat defines parsing types, which encapsulates the expected wire +// format, conversion or validation, and the in-memory layout. +enum class TypeFormat { + // Fixed types: + kFixed64, // fixed64, sfixed64, double + kFixed32, // fixed32, sfixed32, float + + // Varint types: + kVar64, // int64, uint64 + kVar32, // int32, uint32 + kSInt64, // sint64 + kSInt32, // sint32 + kBool, // bool + + // Length-delimited types: + kBytes, // bytes + kString, // string (proto3/UTF-8 strict) + kStringValidateOnly, // string (proto2/UTF-8 validate only) +}; + +// Returns the name of a field parser function. +// +// These are out-of-line functions generated by +// parse_function_inc_generator_main. +std::string GetTailCallFieldHandlerName(ParseCardinality card, + TypeFormat type_format, + int tag_length_bytes, + const Options& options); + +} // namespace cpp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_CPP_PARSE_FUNCTION_GENERATOR_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_plugin_unittest.cc b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_plugin_unittest.cc new file mode 100644 index 00000000..3e7bebf7 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_plugin_unittest.cc @@ -0,0 +1,236 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// +// TODO(kenton): Share code with the versions of this test in other languages? +// It seemed like parameterizing it would add more complexity than it is +// worth. + +#include <memory> + +#include <testing/file.h> +#include <testing/file.h> +#include <compiler/cpp/cpp_generator.h> +#include <compiler/command_line_interface.h> +#include <io/printer.h> +#include <io/zero_copy_stream.h> +#include <testing/googletest.h> +#include <gtest/gtest.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { +namespace { + +class TestGenerator : public CodeGenerator { + public: + TestGenerator() {} + ~TestGenerator() {} + + virtual bool Generate(const FileDescriptor* file, + const std::string& parameter, GeneratorContext* context, + std::string* error) const { + TryInsert("test.pb.h", "includes", context); + TryInsert("test.pb.h", "namespace_scope", context); + TryInsert("test.pb.h", "global_scope", context); + TryInsert("test.pb.h", "class_scope:foo.Bar", context); + TryInsert("test.pb.h", "class_scope:foo.Bar.Baz", context); + + TryInsert("test.pb.cc", "includes", context); + TryInsert("test.pb.cc", "namespace_scope", context); + TryInsert("test.pb.cc", "global_scope", context); + + // Check field accessors for an optional int32: + TryInsert("test.pb.h", "field_get:foo.Bar.optInt", context); + TryInsert("test.pb.h", "field_set:foo.Bar.optInt", context); + + // Check field accessors for a repeated int32: + TryInsert("test.pb.h", "field_get:foo.Bar.repeatedInt", context); + TryInsert("test.pb.h", "field_set:foo.Bar.repeatedInt", context); + + // Check field accessors for a required string: + TryInsert("test.pb.h", "field_get:foo.Bar.requiredString", context); + TryInsert("test.pb.h", "field_set:foo.Bar.requiredString", context); + TryInsert("test.pb.h", "field_mutable:foo.Bar.requiredString", context); + TryInsert("test.pb.h", "field_set_allocated:foo.Bar.requiredString", + context); + + // Check field accessors for a repeated string: + TryInsert("test.pb.h", "field_get:foo.Bar.repeatedString", context); + TryInsert("test.pb.h", "field_set:foo.Bar.repeatedString", context); + TryInsert("test.pb.h", "field_set_char:foo.Bar.repeatedString", context); + TryInsert("test.pb.h", "field_set_pointer:foo.Bar.repeatedString", context); + TryInsert("test.pb.h", "field_mutable:foo.Bar.repeatedString", context); + TryInsert("test.pb.h", "field_set_char:foo.Bar.repeatedString", context); + TryInsert("test.pb.h", "field_set_pointer:foo.Bar.repeatedString", context); + + // Check field accessors for an int inside oneof{}: + TryInsert("test.pb.h", "field_get:foo.Bar.oneOfInt", context); + TryInsert("test.pb.h", "field_set:foo.Bar.oneOfInt", context); + + // Check field accessors for a string inside oneof{}: + TryInsert("test.pb.h", "field_get:foo.Bar.oneOfString", context); + TryInsert("test.pb.h", "field_set:foo.Bar.oneOfString", context); + TryInsert("test.pb.h", "field_mutable:foo.Bar.oneOfString", context); + TryInsert("test.pb.h", "field_set_allocated:foo.Bar.oneOfString", context); + + // Check field accessors for an optional message: + TryInsert("test.pb.h", "field_get:foo.Bar.optMessage", context); + TryInsert("test.pb.h", "field_mutable:foo.Bar.optMessage", context); + TryInsert("test.pb.h", "field_set_allocated:foo.Bar.optMessage", context); + + // Check field accessors for a repeated message: + TryInsert("test.pb.h", "field_add:foo.Bar.repeatedMessage", context); + TryInsert("test.pb.h", "field_get:foo.Bar.repeatedMessage", context); + TryInsert("test.pb.h", "field_list:foo.Bar.repeatedMessage", context); + TryInsert("test.pb.h", "field_mutable:foo.Bar.repeatedMessage", context); + TryInsert("test.pb.h", "field_mutable_list:foo.Bar.repeatedMessage", + context); + + // Check field accessors for a message inside oneof{}: + TryInsert("test.pb.h", "field_get:foo.Bar.oneOfMessage", context); + TryInsert("test.pb.h", "field_mutable:foo.Bar.oneOfMessage", context); + TryInsert("test.pb.cc", "field_set_allocated:foo.Bar.oneOfMessage", + context); + + // Check field accessors for an optional enum: + TryInsert("test.pb.h", "field_get:foo.Bar.optEnum", context); + TryInsert("test.pb.h", "field_set:foo.Bar.optEnum", context); + + // Check field accessors for a repeated enum: + TryInsert("test.pb.h", "field_get:foo.Bar.repeatedEnum", context); + TryInsert("test.pb.h", "field_set:foo.Bar.repeatedEnum", context); + TryInsert("test.pb.h", "field_add:foo.Bar.repeatedEnum", context); + TryInsert("test.pb.h", "field_list:foo.Bar.repeatedEnum", context); + TryInsert("test.pb.h", "field_mutable_list:foo.Bar.repeatedEnum", context); + + // Check field accessors for an enum inside oneof{}: + TryInsert("test.pb.h", "field_get:foo.Bar.oneOfEnum", context); + TryInsert("test.pb.h", "field_set:foo.Bar.oneOfEnum", context); + + // Check field accessors for a required cord: + TryInsert("test.pb.h", "field_get:foo.Bar.requiredCord", context); + TryInsert("test.pb.h", "field_set:foo.Bar.requiredCord", context); + TryInsert("test.pb.h", "field_mutable:foo.Bar.requiredCord", context); + + // Check field accessors for a repeated cord: + TryInsert("test.pb.h", "field_get:foo.Bar.repeatedCord", context); + TryInsert("test.pb.h", "field_set:foo.Bar.repeatedCord", context); + TryInsert("test.pb.h", "field_add:foo.Bar.repeatedCord", context); + TryInsert("test.pb.h", "field_list:foo.Bar.repeatedCord", context); + TryInsert("test.pb.h", "field_mutable:foo.Bar.repeatedCord", context); + TryInsert("test.pb.h", "field_mutable_list:foo.Bar.repeatedCord", context); + + // Check field accessors for a cord inside oneof{}: + TryInsert("test.pb.h", "field_get:foo.Bar.oneOfCord", context); + TryInsert("test.pb.h", "field_set:foo.Bar.oneOfCord", context); + TryInsert("test.pb.h", "field_mutable:foo.Bar.oneOfCord", context); + + return true; + } + + void TryInsert(const std::string& filename, + const std::string& insertion_point, + GeneratorContext* context) const { + std::unique_ptr<io::ZeroCopyOutputStream> output( + context->OpenForInsert(filename, insertion_point)); + io::Printer printer(output.get(), '$'); + printer.Print("// inserted $name$\n", "name", insertion_point); + } +}; + +// This test verifies that all the expected insertion points exist. It does +// not verify that they are correctly-placed; that would require actually +// compiling the output which is a bit more than I care to do for this test. +TEST(CppPluginTest, PluginTest) { + GOOGLE_CHECK_OK(File::SetContents(TestTempDir() + "/test.proto", + "syntax = \"proto2\";\n" + "package foo;\n" + "\n" + "enum Thud { VALUE = 0; }\n" + "\n" + "message Bar {\n" + " message Baz {}\n" + " optional int32 optInt = 1;\n" + " repeated int32 repeatedInt = 2;\n" + "\n" + " required string requiredString = 3;\n" + " repeated string repeatedString = 4;\n" + "\n" + " optional Baz optMessage = 6;\n" + " repeated Baz repeatedMessage = 7;\n" + "\n" + " optional Thud optEnum = 8;\n" + " repeated Thud repeatedEnum = 9;\n" + "\n" + " required string requiredCord = 10 [\n" + " ctype = CORD\n" + " ];\n" + " repeated string repeatedCord = 11 [\n" + " ctype = CORD\n" + " ];\n" + "\n" + " oneof Qux {\n" + " int64 oneOfInt = 20;\n" + " string oneOfString = 21;\n" + " Baz oneOfMessage = 22;\n" + " Thud oneOfEnum = 23;" + " string oneOfCord = 24 [\n" + " ctype = CORD\n" + " ];\n" + " }\n" + "}\n", + true)); + + CommandLineInterface cli; + cli.SetInputsAreProtoPathRelative(true); + + CppGenerator cpp_generator; + TestGenerator test_generator; + cli.RegisterGenerator("--cpp_out", &cpp_generator, ""); + cli.RegisterGenerator("--test_out", &test_generator, ""); + + std::string proto_path = "-I" + TestTempDir(); + std::string cpp_out = "--cpp_out=" + TestTempDir(); + std::string test_out = "--test_out=" + TestTempDir(); + + const char* argv[] = {"protoc", proto_path.c_str(), cpp_out.c_str(), + test_out.c_str(), "test.proto"}; + + EXPECT_EQ(0, cli.Run(5, argv)); +} + +} // namespace +} // namespace cpp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_primitive_field.cc b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_primitive_field.cc new file mode 100644 index 00000000..06037b95 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_primitive_field.cc @@ -0,0 +1,505 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <compiler/cpp/cpp_primitive_field.h> + +#include <compiler/cpp/cpp_helpers.h> +#include <io/printer.h> +#include <wire_format.h> +#include <stubs/strutil.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { + +using internal::WireFormatLite; + +namespace { + +// 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. + } + GOOGLE_LOG(FATAL) << "Can't get here."; + return -1; +} + +void SetPrimitiveVariables(const FieldDescriptor* descriptor, + std::map<std::string, std::string>* variables, + const Options& options) { + SetCommonFieldVariables(descriptor, variables, options); + (*variables)["type"] = PrimitiveTypeName(options, descriptor->cpp_type()); + (*variables)["default"] = DefaultValue(options, descriptor); + (*variables)["tag"] = StrCat(internal::WireFormat::MakeTag(descriptor)); + int fixed_size = FixedSize(descriptor->type()); + if (fixed_size != -1) { + (*variables)["fixed_size"] = StrCat(fixed_size); + } + (*variables)["wire_format_field_type"] = FieldDescriptorProto_Type_Name( + static_cast<FieldDescriptorProto_Type>(descriptor->type())); + (*variables)["full_name"] = descriptor->full_name(); +} + +} // namespace + +// =================================================================== + +PrimitiveFieldGenerator::PrimitiveFieldGenerator( + const FieldDescriptor* descriptor, const Options& options) + : FieldGenerator(descriptor, options) { + SetPrimitiveVariables(descriptor, &variables_, options); +} + +PrimitiveFieldGenerator::~PrimitiveFieldGenerator() {} + +void PrimitiveFieldGenerator::GeneratePrivateMembers( + io::Printer* printer) const { + Formatter format(printer, variables_); + format("$type$ $name$_;\n"); +} + +void PrimitiveFieldGenerator::GenerateAccessorDeclarations( + io::Printer* printer) const { + Formatter format(printer, variables_); + format( + "$deprecated_attr$$type$ ${1$$name$$}$() const;\n" + "$deprecated_attr$void ${1$set_$name$$}$($type$ value);\n" + "private:\n" + "$type$ ${1$_internal_$name$$}$() const;\n" + "void ${1$_internal_set_$name$$}$($type$ value);\n" + "public:\n", + descriptor_); +} + +void PrimitiveFieldGenerator::GenerateInlineAccessorDefinitions( + io::Printer* printer) const { + Formatter format(printer, variables_); + format( + "inline $type$ $classname$::_internal_$name$() const {\n" + " return $name$_;\n" + "}\n" + "inline $type$ $classname$::$name$() const {\n" + "$annotate_get$" + " // @@protoc_insertion_point(field_get:$full_name$)\n" + " return _internal_$name$();\n" + "}\n" + "inline void $classname$::_internal_set_$name$($type$ value) {\n" + " $set_hasbit$\n" + " $name$_ = value;\n" + "}\n" + "inline void $classname$::set_$name$($type$ value) {\n" + " _internal_set_$name$(value);\n" + "$annotate_set$" + " // @@protoc_insertion_point(field_set:$full_name$)\n" + "}\n"); +} + +void PrimitiveFieldGenerator::GenerateClearingCode(io::Printer* printer) const { + Formatter format(printer, variables_); + format("$name$_ = $default$;\n"); +} + +void PrimitiveFieldGenerator::GenerateMergingCode(io::Printer* printer) const { + Formatter format(printer, variables_); + format("_internal_set_$name$(from._internal_$name$());\n"); +} + +void PrimitiveFieldGenerator::GenerateSwappingCode(io::Printer* printer) const { + Formatter format(printer, variables_); + format("swap($name$_, other->$name$_);\n"); +} + +void PrimitiveFieldGenerator::GenerateConstructorCode( + io::Printer* printer) const { + Formatter format(printer, variables_); + format("$name$_ = $default$;\n"); +} + +void PrimitiveFieldGenerator::GenerateCopyConstructorCode( + io::Printer* printer) const { + Formatter format(printer, variables_); + format("$name$_ = from.$name$_;\n"); +} + +void PrimitiveFieldGenerator::GenerateSerializeWithCachedSizesToArray( + io::Printer* printer) const { + Formatter format(printer, variables_); + format( + "target = stream->EnsureSpace(target);\n" + "target = " + "::$proto_ns$::internal::WireFormatLite::Write$declared_type$ToArray(" + "$number$, this->_internal_$name$(), target);\n"); +} + +void PrimitiveFieldGenerator::GenerateByteSize(io::Printer* printer) const { + Formatter format(printer, variables_); + int fixed_size = FixedSize(descriptor_->type()); + if (fixed_size == -1) { + if (internal::WireFormat::TagSize(descriptor_->number(), + descriptor_->type()) == 1) { + // Adding one is very common and it turns out it can be done for + // free inside of WireFormatLite, so we can save an instruction here. + format( + "total_size += ::$proto_ns$::internal::WireFormatLite::" + "$declared_type$SizePlusOne(this->_internal_$name$());\n"); + } else { + format( + "total_size += $tag_size$ +\n" + " ::$proto_ns$::internal::WireFormatLite::$declared_type$Size(\n" + " this->_internal_$name$());\n"); + } + } else { + format("total_size += $tag_size$ + $fixed_size$;\n"); + } +} + +void PrimitiveFieldGenerator::GenerateConstinitInitializer( + io::Printer* printer) const { + Formatter format(printer, variables_); + format("$name$_($default$)"); +} + +// =================================================================== + +PrimitiveOneofFieldGenerator::PrimitiveOneofFieldGenerator( + const FieldDescriptor* descriptor, const Options& options) + : PrimitiveFieldGenerator(descriptor, options) { + SetCommonOneofFieldVariables(descriptor, &variables_); +} + +PrimitiveOneofFieldGenerator::~PrimitiveOneofFieldGenerator() {} + +void PrimitiveOneofFieldGenerator::GenerateInlineAccessorDefinitions( + io::Printer* printer) const { + Formatter format(printer, variables_); + format( + "inline $type$ $classname$::_internal_$name$() const {\n" + " if (_internal_has_$name$()) {\n" + " return $field_member$;\n" + " }\n" + " return $default$;\n" + "}\n" + "inline void $classname$::_internal_set_$name$($type$ value) {\n" + " if (!_internal_has_$name$()) {\n" + " clear_$oneof_name$();\n" + " set_has_$name$();\n" + " }\n" + " $field_member$ = value;\n" + "}\n" + "inline $type$ $classname$::$name$() const {\n" + "$annotate_get$" + " // @@protoc_insertion_point(field_get:$full_name$)\n" + " return _internal_$name$();\n" + "}\n" + "inline void $classname$::set_$name$($type$ value) {\n" + " _internal_set_$name$(value);\n" + "$annotate_set$" + " // @@protoc_insertion_point(field_set:$full_name$)\n" + "}\n"); +} + +void PrimitiveOneofFieldGenerator::GenerateClearingCode( + io::Printer* printer) const { + Formatter format(printer, variables_); + format("$field_member$ = $default$;\n"); +} + +void PrimitiveOneofFieldGenerator::GenerateSwappingCode( + io::Printer* printer) const { + // Don't print any swapping code. Swapping the union will swap this field. +} + +void PrimitiveOneofFieldGenerator::GenerateConstructorCode( + io::Printer* printer) const { + Formatter format(printer, variables_); + format("$ns$::_$classname$_default_instance_.$name$_ = $default$;\n"); +} + +// =================================================================== + +RepeatedPrimitiveFieldGenerator::RepeatedPrimitiveFieldGenerator( + const FieldDescriptor* descriptor, const Options& options) + : FieldGenerator(descriptor, options) { + SetPrimitiveVariables(descriptor, &variables_, options); + + if (descriptor->is_packed()) { + variables_["packed_reader"] = "ReadPackedPrimitive"; + variables_["repeated_reader"] = "ReadRepeatedPrimitiveNoInline"; + } else { + variables_["packed_reader"] = "ReadPackedPrimitiveNoInline"; + variables_["repeated_reader"] = "ReadRepeatedPrimitive"; + } +} + +RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() {} + +void RepeatedPrimitiveFieldGenerator::GeneratePrivateMembers( + io::Printer* printer) const { + Formatter format(printer, variables_); + format("::$proto_ns$::RepeatedField< $type$ > $name$_;\n"); + if (descriptor_->is_packed() && FixedSize(descriptor_->type()) == -1 && + HasGeneratedMethods(descriptor_->file(), options_)) { + format("mutable std::atomic<int> _$name$_cached_byte_size_;\n"); + } +} + +void RepeatedPrimitiveFieldGenerator::GenerateAccessorDeclarations( + io::Printer* printer) const { + Formatter format(printer, variables_); + format( + "private:\n" + "$type$ ${1$_internal_$name$$}$(int index) const;\n" + "const ::$proto_ns$::RepeatedField< $type$ >&\n" + " ${1$_internal_$name$$}$() const;\n" + "void ${1$_internal_add_$name$$}$($type$ value);\n" + "::$proto_ns$::RepeatedField< $type$ >*\n" + " ${1$_internal_mutable_$name$$}$();\n" + "public:\n" + "$deprecated_attr$$type$ ${1$$name$$}$(int index) const;\n" + "$deprecated_attr$void ${1$set_$name$$}$(int index, $type$ value);\n" + "$deprecated_attr$void ${1$add_$name$$}$($type$ value);\n" + "$deprecated_attr$const ::$proto_ns$::RepeatedField< $type$ >&\n" + " ${1$$name$$}$() const;\n" + "$deprecated_attr$::$proto_ns$::RepeatedField< $type$ >*\n" + " ${1$mutable_$name$$}$();\n", + descriptor_); +} + +void RepeatedPrimitiveFieldGenerator::GenerateInlineAccessorDefinitions( + io::Printer* printer) const { + Formatter format(printer, variables_); + format( + "inline $type$ $classname$::_internal_$name$(int index) const {\n" + " return $name$_.Get(index);\n" + "}\n" + "inline $type$ $classname$::$name$(int index) const {\n" + "$annotate_get$" + " // @@protoc_insertion_point(field_get:$full_name$)\n" + " return _internal_$name$(index);\n" + "}\n" + "inline void $classname$::set_$name$(int index, $type$ value) {\n" + "$annotate_set$" + " $name$_.Set(index, value);\n" + " // @@protoc_insertion_point(field_set:$full_name$)\n" + "}\n" + "inline void $classname$::_internal_add_$name$($type$ value) {\n" + " $name$_.Add(value);\n" + "}\n" + "inline void $classname$::add_$name$($type$ value) {\n" + " _internal_add_$name$(value);\n" + "$annotate_add$" + " // @@protoc_insertion_point(field_add:$full_name$)\n" + "}\n" + "inline const ::$proto_ns$::RepeatedField< $type$ >&\n" + "$classname$::_internal_$name$() const {\n" + " return $name$_;\n" + "}\n" + "inline const ::$proto_ns$::RepeatedField< $type$ >&\n" + "$classname$::$name$() const {\n" + "$annotate_list$" + " // @@protoc_insertion_point(field_list:$full_name$)\n" + " return _internal_$name$();\n" + "}\n" + "inline ::$proto_ns$::RepeatedField< $type$ >*\n" + "$classname$::_internal_mutable_$name$() {\n" + " return &$name$_;\n" + "}\n" + "inline ::$proto_ns$::RepeatedField< $type$ >*\n" + "$classname$::mutable_$name$() {\n" + "$annotate_mutable_list$" + " // @@protoc_insertion_point(field_mutable_list:$full_name$)\n" + " return _internal_mutable_$name$();\n" + "}\n"); +} + +void RepeatedPrimitiveFieldGenerator::GenerateClearingCode( + io::Printer* printer) const { + Formatter format(printer, variables_); + format("$name$_.Clear();\n"); +} + +void RepeatedPrimitiveFieldGenerator::GenerateMergingCode( + io::Printer* printer) const { + Formatter format(printer, variables_); + format("$name$_.MergeFrom(from.$name$_);\n"); +} + +void RepeatedPrimitiveFieldGenerator::GenerateSwappingCode( + io::Printer* printer) const { + Formatter format(printer, variables_); + format("$name$_.InternalSwap(&other->$name$_);\n"); +} + +void RepeatedPrimitiveFieldGenerator::GenerateConstructorCode( + io::Printer* printer) const { + // Not needed for repeated fields. +} + +void RepeatedPrimitiveFieldGenerator::GenerateCopyConstructorCode( + io::Printer* printer) const { + Formatter format(printer, variables_); + format("$name$_.CopyFrom(from.$name$_);\n"); +} + +void RepeatedPrimitiveFieldGenerator::GenerateSerializeWithCachedSizesToArray( + io::Printer* printer) const { + Formatter format(printer, variables_); + if (descriptor_->is_packed()) { + if (FixedSize(descriptor_->type()) == -1) { + format( + "{\n" + " int byte_size = " + "_$name$_cached_byte_size_.load(std::memory_order_relaxed);\n" + " if (byte_size > 0) {\n" + " target = stream->Write$declared_type$Packed(\n" + " $number$, _internal_$name$(), byte_size, target);\n" + " }\n" + "}\n"); + } else { + format( + "if (this->_internal_$name$_size() > 0) {\n" + " target = stream->WriteFixedPacked($number$, _internal_$name$(), " + "target);\n" + "}\n"); + } + } else { + format( + "for (int i = 0, n = this->_internal_$name$_size(); i < n; i++) {\n" + " target = stream->EnsureSpace(target);\n" + " target = ::$proto_ns$::internal::WireFormatLite::" + "Write$declared_type$ToArray($number$, this->_internal_$name$(i), " + "target);\n" + "}\n"); + } +} + +void RepeatedPrimitiveFieldGenerator::GenerateByteSize( + io::Printer* printer) const { + Formatter format(printer, variables_); + format("{\n"); + format.Indent(); + int fixed_size = FixedSize(descriptor_->type()); + if (fixed_size == -1) { + format( + "size_t data_size = ::$proto_ns$::internal::WireFormatLite::\n" + " $declared_type$Size(this->$name$_);\n"); + } else { + format( + "unsigned int count = static_cast<unsigned " + "int>(this->_internal_$name$_size());\n" + "size_t data_size = $fixed_size$UL * count;\n"); + } + + if (descriptor_->is_packed()) { + format( + "if (data_size > 0) {\n" + " total_size += $tag_size$ +\n" + " ::$proto_ns$::internal::WireFormatLite::Int32Size(\n" + " static_cast<$int32$>(data_size));\n" + "}\n"); + if (FixedSize(descriptor_->type()) == -1) { + format( + "int cached_size = ::$proto_ns$::internal::ToCachedSize(data_size);\n" + "_$name$_cached_byte_size_.store(cached_size,\n" + " std::memory_order_relaxed);\n"); + } + format("total_size += data_size;\n"); + } else { + format( + "total_size += $tag_size$ *\n" + " " + "::$proto_ns$::internal::FromIntSize(this->_internal_$name$_size());\n" + "total_size += data_size;\n"); + } + format.Outdent(); + format("}\n"); +} + +void RepeatedPrimitiveFieldGenerator::GenerateConstinitInitializer( + io::Printer* printer) const { + Formatter format(printer, variables_); + format("$name$_()"); + if (descriptor_->is_packed() && FixedSize(descriptor_->type()) == -1 && + HasGeneratedMethods(descriptor_->file(), options_)) { + format("\n, _$name$_cached_byte_size_(0)"); + } +} + +} // namespace cpp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_primitive_field.h b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_primitive_field.h new file mode 100644 index 00000000..28f18ce0 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_primitive_field.h @@ -0,0 +1,116 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_PRIMITIVE_FIELD_H__ +#define GOOGLE_PROTOBUF_COMPILER_CPP_PRIMITIVE_FIELD_H__ + +#include <map> +#include <string> +#include <compiler/cpp/cpp_field.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { + +class PrimitiveFieldGenerator : public FieldGenerator { + public: + PrimitiveFieldGenerator(const FieldDescriptor* descriptor, + const Options& options); + ~PrimitiveFieldGenerator(); + + // implements FieldGenerator --------------------------------------- + void GeneratePrivateMembers(io::Printer* printer) const override; + void GenerateAccessorDeclarations(io::Printer* printer) const override; + void GenerateInlineAccessorDefinitions(io::Printer* printer) const override; + void GenerateClearingCode(io::Printer* printer) const override; + void GenerateMergingCode(io::Printer* printer) const override; + void GenerateSwappingCode(io::Printer* printer) const override; + void GenerateConstructorCode(io::Printer* printer) const override; + void GenerateCopyConstructorCode(io::Printer* printer) const override; + void GenerateSerializeWithCachedSizesToArray( + io::Printer* printer) const override; + void GenerateByteSize(io::Printer* printer) const override; + void GenerateConstinitInitializer(io::Printer* printer) const override; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PrimitiveFieldGenerator); +}; + +class PrimitiveOneofFieldGenerator : public PrimitiveFieldGenerator { + public: + PrimitiveOneofFieldGenerator(const FieldDescriptor* descriptor, + const Options& options); + ~PrimitiveOneofFieldGenerator(); + + // implements FieldGenerator --------------------------------------- + void GenerateInlineAccessorDefinitions(io::Printer* printer) const override; + void GenerateClearingCode(io::Printer* printer) const override; + void GenerateSwappingCode(io::Printer* printer) const override; + void GenerateConstructorCode(io::Printer* printer) const override; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PrimitiveOneofFieldGenerator); +}; + +class RepeatedPrimitiveFieldGenerator : public FieldGenerator { + public: + RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor, + const Options& options); + ~RepeatedPrimitiveFieldGenerator(); + + // implements FieldGenerator --------------------------------------- + void GeneratePrivateMembers(io::Printer* printer) const override; + void GenerateAccessorDeclarations(io::Printer* printer) const override; + void GenerateInlineAccessorDefinitions(io::Printer* printer) const override; + void GenerateClearingCode(io::Printer* printer) const override; + void GenerateMergingCode(io::Printer* printer) const override; + void GenerateSwappingCode(io::Printer* printer) const override; + void GenerateConstructorCode(io::Printer* printer) const override; + void GenerateCopyConstructorCode(io::Printer* printer) const override; + void GenerateSerializeWithCachedSizesToArray( + io::Printer* printer) const override; + void GenerateByteSize(io::Printer* printer) const override; + void GenerateConstinitInitializer(io::Printer* printer) const override; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedPrimitiveFieldGenerator); +}; + +} // namespace cpp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_CPP_PRIMITIVE_FIELD_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_service.cc b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_service.cc new file mode 100644 index 00000000..807a4cd9 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_service.cc @@ -0,0 +1,327 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <compiler/cpp/cpp_service.h> +#include <compiler/cpp/cpp_helpers.h> +#include <io/printer.h> +#include <stubs/strutil.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { + +namespace { + +void InitMethodVariables(const MethodDescriptor* method, const Options& options, + Formatter* format) { + format->Set("name", method->name()); + format->Set("input_type", QualifiedClassName(method->input_type(), options)); + format->Set("output_type", + QualifiedClassName(method->output_type(), options)); +} + +} // namespace + +ServiceGenerator::ServiceGenerator( + const ServiceDescriptor* descriptor, + const std::map<std::string, std::string>& vars, const Options& options) + : descriptor_(descriptor), vars_(vars), options_(options) { + vars_["classname"] = descriptor_->name(); + vars_["full_name"] = descriptor_->full_name(); +} + +ServiceGenerator::~ServiceGenerator() {} + +void ServiceGenerator::GenerateDeclarations(io::Printer* printer) { + Formatter format(printer, vars_); + // Forward-declare the stub type. + format( + "class $classname$_Stub;\n" + "\n"); + + GenerateInterface(printer); + GenerateStubDefinition(printer); +} + +void ServiceGenerator::GenerateInterface(io::Printer* printer) { + Formatter format(printer, vars_); + format( + "class $dllexport_decl $$classname$ : public ::$proto_ns$::Service {\n" + " protected:\n" + " // This class should be treated as an abstract interface.\n" + " inline $classname$() {};\n" + " public:\n" + " virtual ~$classname$();\n"); + printer->Indent(); + + format( + "\n" + "typedef $classname$_Stub Stub;\n" + "\n" + "static const ::$proto_ns$::ServiceDescriptor* descriptor();\n" + "\n"); + + GenerateMethodSignatures(VIRTUAL, printer); + + format( + "\n" + "// implements Service ----------------------------------------------\n" + "\n" + "const ::$proto_ns$::ServiceDescriptor* GetDescriptor();\n" + "void CallMethod(const ::$proto_ns$::MethodDescriptor* method,\n" + " ::$proto_ns$::RpcController* controller,\n" + " const ::$proto_ns$::Message* request,\n" + " ::$proto_ns$::Message* response,\n" + " ::google::protobuf::Closure* done);\n" + "const ::$proto_ns$::Message& GetRequestPrototype(\n" + " const ::$proto_ns$::MethodDescriptor* method) const;\n" + "const ::$proto_ns$::Message& GetResponsePrototype(\n" + " const ::$proto_ns$::MethodDescriptor* method) const;\n"); + + printer->Outdent(); + format( + "\n" + " private:\n" + " GOOGLE_DISALLOW_EVIL_CONSTRUCTORS($classname$);\n" + "};\n" + "\n"); +} + +void ServiceGenerator::GenerateStubDefinition(io::Printer* printer) { + Formatter format(printer, vars_); + format( + "class $dllexport_decl $$classname$_Stub : public $classname$ {\n" + " public:\n"); + + printer->Indent(); + + format( + "$classname$_Stub(::$proto_ns$::RpcChannel* channel);\n" + "$classname$_Stub(::$proto_ns$::RpcChannel* channel,\n" + " ::$proto_ns$::Service::ChannelOwnership ownership);\n" + "~$classname$_Stub();\n" + "\n" + "inline ::$proto_ns$::RpcChannel* channel() { return channel_; }\n" + "\n" + "// implements $classname$ ------------------------------------------\n" + "\n"); + + GenerateMethodSignatures(NON_VIRTUAL, printer); + + printer->Outdent(); + format( + " private:\n" + " ::$proto_ns$::RpcChannel* channel_;\n" + " bool owns_channel_;\n" + " GOOGLE_DISALLOW_EVIL_CONSTRUCTORS($classname$_Stub);\n" + "};\n" + "\n"); +} + +void ServiceGenerator::GenerateMethodSignatures(VirtualOrNon virtual_or_non, + io::Printer* printer) { + for (int i = 0; i < descriptor_->method_count(); i++) { + const MethodDescriptor* method = descriptor_->method(i); + Formatter format(printer, vars_); + InitMethodVariables(method, options_, &format); + format.Set("virtual", virtual_or_non == VIRTUAL ? "virtual " : ""); + format( + "$virtual$void $name$(::$proto_ns$::RpcController* controller,\n" + " const $input_type$* request,\n" + " $output_type$* response,\n" + " ::google::protobuf::Closure* done);\n"); + } +} + +// =================================================================== + +void ServiceGenerator::GenerateImplementation(io::Printer* printer) { + Formatter format(printer, vars_); + format( + "$classname$::~$classname$() {}\n" + "\n" + "const ::$proto_ns$::ServiceDescriptor* $classname$::descriptor() {\n" + " " + "::$proto_ns$::internal::AssignDescriptors(&$desc_table$);\n" + " return $file_level_service_descriptors$[$1$];\n" + "}\n" + "\n" + "const ::$proto_ns$::ServiceDescriptor* $classname$::GetDescriptor() {\n" + " return descriptor();\n" + "}\n" + "\n", + index_in_metadata_); + + // Generate methods of the interface. + GenerateNotImplementedMethods(printer); + GenerateCallMethod(printer); + GenerateGetPrototype(REQUEST, printer); + GenerateGetPrototype(RESPONSE, printer); + + // Generate stub implementation. + format( + "$classname$_Stub::$classname$_Stub(::$proto_ns$::RpcChannel* channel)\n" + " : channel_(channel), owns_channel_(false) {}\n" + "$classname$_Stub::$classname$_Stub(\n" + " ::$proto_ns$::RpcChannel* channel,\n" + " ::$proto_ns$::Service::ChannelOwnership ownership)\n" + " : channel_(channel),\n" + " owns_channel_(ownership == " + "::$proto_ns$::Service::STUB_OWNS_CHANNEL) " + "{}\n" + "$classname$_Stub::~$classname$_Stub() {\n" + " if (owns_channel_) delete channel_;\n" + "}\n" + "\n"); + + GenerateStubMethods(printer); +} + +void ServiceGenerator::GenerateNotImplementedMethods(io::Printer* printer) { + for (int i = 0; i < descriptor_->method_count(); i++) { + const MethodDescriptor* method = descriptor_->method(i); + Formatter format(printer, vars_); + InitMethodVariables(method, options_, &format); + format( + "void $classname$::$name$(::$proto_ns$::RpcController* controller,\n" + " const $input_type$*,\n" + " $output_type$*,\n" + " ::google::protobuf::Closure* done) {\n" + " controller->SetFailed(\"Method $name$() not implemented.\");\n" + " done->Run();\n" + "}\n" + "\n"); + } +} + +void ServiceGenerator::GenerateCallMethod(io::Printer* printer) { + Formatter format(printer, vars_); + format( + "void $classname$::CallMethod(const ::$proto_ns$::MethodDescriptor* " + "method,\n" + " ::$proto_ns$::RpcController* controller,\n" + " const ::$proto_ns$::Message* request,\n" + " ::$proto_ns$::Message* response,\n" + " ::google::protobuf::Closure* done) {\n" + " GOOGLE_DCHECK_EQ(method->service(), $file_level_service_descriptors$[$1$]);\n" + " switch(method->index()) {\n", + index_in_metadata_); + + for (int i = 0; i < descriptor_->method_count(); i++) { + const MethodDescriptor* method = descriptor_->method(i); + Formatter format_method(printer, vars_); + InitMethodVariables(method, options_, &format_method); + + // Note: down_cast does not work here because it only works on pointers, + // not references. + format_method( + " case $1$:\n" + " $name$(controller,\n" + " ::$proto_ns$::internal::DownCast<const $input_type$*>(\n" + " request),\n" + " ::$proto_ns$::internal::DownCast<$output_type$*>(\n" + " response),\n" + " done);\n" + " break;\n", + i); + } + + format( + " default:\n" + " GOOGLE_LOG(FATAL) << \"Bad method index; this should never happen.\";\n" + " break;\n" + " }\n" + "}\n" + "\n"); +} + +void ServiceGenerator::GenerateGetPrototype(RequestOrResponse which, + io::Printer* printer) { + Formatter format(printer, vars_); + if (which == REQUEST) { + format("const ::$proto_ns$::Message& $classname$::GetRequestPrototype(\n"); + } else { + format("const ::$proto_ns$::Message& $classname$::GetResponsePrototype(\n"); + } + + format( + " const ::$proto_ns$::MethodDescriptor* method) const {\n" + " GOOGLE_DCHECK_EQ(method->service(), descriptor());\n" + " switch(method->index()) {\n"); + + for (int i = 0; i < descriptor_->method_count(); i++) { + const MethodDescriptor* method = descriptor_->method(i); + const Descriptor* type = + (which == REQUEST) ? method->input_type() : method->output_type(); + + format( + " case $1$:\n" + " return $2$::default_instance();\n", + i, QualifiedClassName(type, options_)); + } + + format( + " default:\n" + " GOOGLE_LOG(FATAL) << \"Bad method index; this should never happen.\";\n" + " return *::$proto_ns$::MessageFactory::generated_factory()\n" + " ->GetPrototype(method->$1$_type());\n" + " }\n" + "}\n" + "\n", + which == REQUEST ? "input" : "output"); +} + +void ServiceGenerator::GenerateStubMethods(io::Printer* printer) { + for (int i = 0; i < descriptor_->method_count(); i++) { + const MethodDescriptor* method = descriptor_->method(i); + Formatter format(printer, vars_); + InitMethodVariables(method, options_, &format); + format( + "void $classname$_Stub::$name$(::$proto_ns$::RpcController* " + "controller,\n" + " const $input_type$* request,\n" + " $output_type$* response,\n" + " ::google::protobuf::Closure* done) {\n" + " channel_->CallMethod(descriptor()->method($1$),\n" + " controller, request, response, done);\n" + "}\n", + i); + } +} + +} // namespace cpp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_service.h b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_service.h new file mode 100644 index 00000000..7d1a1880 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_service.h @@ -0,0 +1,122 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_SERVICE_H__ +#define GOOGLE_PROTOBUF_COMPILER_CPP_SERVICE_H__ + +#include <map> +#include <string> +#include <compiler/cpp/cpp_options.h> +#include <descriptor.h> + +namespace google { +namespace protobuf { +namespace io { +class Printer; // printer.h +} +} // namespace protobuf +} // namespace google + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { + +class ServiceGenerator { + public: + // See generator.cc for the meaning of dllexport_decl. + explicit ServiceGenerator(const ServiceDescriptor* descriptor, + const std::map<std::string, std::string>& vars, + const Options& options); + ~ServiceGenerator(); + + // Header stuff. + + // Generate the class definitions for the service's interface and the + // stub implementation. + void GenerateDeclarations(io::Printer* printer); + + // Source file stuff. + + // Generate implementations of everything declared by + // GenerateDeclarations(). + void GenerateImplementation(io::Printer* printer); + + private: + enum RequestOrResponse { REQUEST, RESPONSE }; + enum VirtualOrNon { VIRTUAL, NON_VIRTUAL }; + + // Header stuff. + + // Generate the service abstract interface. + void GenerateInterface(io::Printer* printer); + + // Generate the stub class definition. + void GenerateStubDefinition(io::Printer* printer); + + // Prints signatures for all methods in the + void GenerateMethodSignatures(VirtualOrNon virtual_or_non, + io::Printer* printer); + + // Source file stuff. + + // Generate the default implementations of the service methods, which + // produce a "not implemented" error. + void GenerateNotImplementedMethods(io::Printer* printer); + + // Generate the CallMethod() method of the service. + void GenerateCallMethod(io::Printer* printer); + + // Generate the Get{Request,Response}Prototype() methods. + void GenerateGetPrototype(RequestOrResponse which, io::Printer* printer); + + // Generate the stub's implementations of the service methods. + void GenerateStubMethods(io::Printer* printer); + + const ServiceDescriptor* descriptor_; + std::map<std::string, std::string> vars_; + const Options& options_; + + int index_in_metadata_; + + friend class FileGenerator; + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ServiceGenerator); +}; + +} // namespace cpp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_CPP_SERVICE_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_string_field.cc b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_string_field.cc new file mode 100644 index 00000000..0faa2eea --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_string_field.cc @@ -0,0 +1,915 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <compiler/cpp/cpp_string_field.h> +#include <compiler/cpp/cpp_helpers.h> +#include <descriptor.pb.h> +#include <io/printer.h> +#include <stubs/strutil.h> + + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { + +namespace { + +void SetStringVariables(const FieldDescriptor* descriptor, + std::map<std::string, std::string>* variables, + const Options& options) { + SetCommonFieldVariables(descriptor, variables, options); + (*variables)["default"] = DefaultValue(options, descriptor); + (*variables)["default_length"] = + StrCat(descriptor->default_value_string().length()); + std::string default_variable_string = MakeDefaultName(descriptor); + (*variables)["default_variable_name"] = default_variable_string; + + if (!descriptor->default_value_string().empty()) { + (*variables)["lazy_variable"] = + QualifiedClassName(descriptor->containing_type(), options) + + "::" + default_variable_string; + } + + (*variables)["default_string"] = + descriptor->default_value_string().empty() + ? "::" + (*variables)["proto_ns"] + + "::internal::GetEmptyStringAlreadyInited()" + : (*variables)["lazy_variable"] + ".get()"; + (*variables)["init_value"] = + descriptor->default_value_string().empty() + ? "&::" + (*variables)["proto_ns"] + + "::internal::GetEmptyStringAlreadyInited()" + : "nullptr"; + (*variables)["default_value_tag"] = + "::" + (*variables)["proto_ns"] + "::internal::ArenaStringPtr::" + + (descriptor->default_value_string().empty() ? "Empty" : "NonEmpty") + + "Default{}"; + (*variables)["default_variable_or_tag"] = + (*variables)[descriptor->default_value_string().empty() + ? "default_value_tag" + : "lazy_variable"]; + (*variables)["pointer_type"] = + descriptor->type() == FieldDescriptor::TYPE_BYTES ? "void" : "char"; + (*variables)["setter"] = + descriptor->type() == FieldDescriptor::TYPE_BYTES ? "SetBytes" : "Set"; + (*variables)["null_check"] = (*variables)["DCHK"] + "(value != nullptr);\n"; + // NOTE: Escaped here to unblock proto1->proto2 migration. + // TODO(liujisi): Extend this to apply for other conflicting methods. + (*variables)["release_name"] = + SafeFunctionName(descriptor->containing_type(), descriptor, "release_"); + (*variables)["full_name"] = descriptor->full_name(); + + if (options.opensource_runtime) { + (*variables)["string_piece"] = "::std::string"; + } else { + (*variables)["string_piece"] = "::StringPiece"; + } +} + +} // namespace + +// =================================================================== + +StringFieldGenerator::StringFieldGenerator(const FieldDescriptor* descriptor, + const Options& options) + : FieldGenerator(descriptor, options), + inlined_(IsStringInlined(descriptor, options)) { + SetStringVariables(descriptor, &variables_, options); +} + +StringFieldGenerator::~StringFieldGenerator() {} + +void StringFieldGenerator::GeneratePrivateMembers(io::Printer* printer) const { + Formatter format(printer, variables_); + if (!inlined_) { + format("::$proto_ns$::internal::ArenaStringPtr $name$_;\n"); + } else { + // `_init_inline_xxx` is used for initializing default instances. + format( + "::$proto_ns$::internal::InlinedStringField $name$_;\n" + "static std::true_type _init_inline_$name$_;\n"); + } +} + +void StringFieldGenerator::GenerateStaticMembers(io::Printer* printer) const { + Formatter format(printer, variables_); + if (!descriptor_->default_value_string().empty()) { + format( + "static const ::$proto_ns$::internal::LazyString" + " $default_variable_name$;\n"); + } +} + +void StringFieldGenerator::GenerateAccessorDeclarations( + io::Printer* printer) const { + Formatter format(printer, variables_); + // If we're using StringFieldGenerator for a field with a ctype, it's + // because that ctype isn't actually implemented. In particular, this is + // true of ctype=CORD and ctype=STRING_PIECE in the open source release. + // We aren't releasing Cord because it has too many Google-specific + // dependencies and we aren't releasing StringPiece because it's hardly + // useful outside of Google and because it would get confusing to have + // multiple instances of the StringPiece class in different libraries (PCRE + // already includes it for their C++ bindings, which came from Google). + // + // In any case, we make all the accessors private while still actually + // using a string to represent the field internally. This way, we can + // guarantee that if we do ever implement the ctype, it won't break any + // existing users who might be -- for whatever reason -- already using .proto + // files that applied the ctype. The field can still be accessed via the + // reflection interface since the reflection interface is independent of + // the string's underlying representation. + + bool unknown_ctype = descriptor_->options().ctype() != + EffectiveStringCType(descriptor_, options_); + + if (unknown_ctype) { + format.Outdent(); + format( + " private:\n" + " // Hidden due to unknown ctype option.\n"); + format.Indent(); + } + + format( + "$deprecated_attr$const std::string& ${1$$name$$}$() const;\n" + "template <typename ArgT0 = const std::string&, typename... ArgT>\n" + "$deprecated_attr$void ${1$set_$name$$}$(ArgT0&& arg0, ArgT... args);\n", + descriptor_); + format( + "$deprecated_attr$std::string* ${1$mutable_$name$$}$();\n" + "PROTOBUF_NODISCARD $deprecated_attr$std::string* " + "${1$$release_name$$}$();\n" + "$deprecated_attr$void ${1$set_allocated_$name$$}$(std::string* " + "$name$);\n", + descriptor_); + format( + "private:\n" + "const std::string& _internal_$name$() const;\n" + "inline PROTOBUF_ALWAYS_INLINE void " + "_internal_set_$name$(const std::string& value);\n" + "std::string* _internal_mutable_$name$();\n"); + if (inlined_) { + format( + "inline PROTOBUF_ALWAYS_INLINE bool _internal_$name$_donated() " + "const;\n"); + } + format("public:\n"); + + if (unknown_ctype) { + format.Outdent(); + format(" public:\n"); + format.Indent(); + } +} + +void StringFieldGenerator::GenerateInlineAccessorDefinitions( + io::Printer* printer) const { + Formatter format(printer, variables_); + format( + "inline const std::string& $classname$::$name$() const {\n" + "$annotate_get$" + " // @@protoc_insertion_point(field_get:$full_name$)\n"); + if (!descriptor_->default_value_string().empty()) { + format( + " if ($name$_.IsDefault(nullptr)) return " + "$default_variable_name$.get();\n"); + } + format( + " return _internal_$name$();\n" + "}\n"); + if (!inlined_) { + format( + "template <typename ArgT0, typename... ArgT>\n" + "inline PROTOBUF_ALWAYS_INLINE\n" + "void $classname$::set_$name$(ArgT0&& arg0, ArgT... args) {\n" + " $set_hasbit$\n" + " $name$_.$setter$($default_value_tag$, static_cast<ArgT0 &&>(arg0)," + " args..., GetArenaForAllocation());\n" + "$annotate_set$" + " // @@protoc_insertion_point(field_set:$full_name$)\n" + "}\n"); + } else { + format( + "template <typename ArgT0, typename... ArgT>\n" + "inline PROTOBUF_ALWAYS_INLINE\n" + "void $classname$::set_$name$(ArgT0&& arg0, ArgT... args) {\n" + " $set_hasbit$\n" + " $name$_.$setter$(nullptr, static_cast<ArgT0 &&>(arg0)," + " args..., GetArenaForAllocation(), _internal_$name$_donated(), " + "&$donating_states_word$, $mask_for_undonate$);\n" + "$annotate_set$" + " // @@protoc_insertion_point(field_set:$full_name$)\n" + "}\n" + "inline bool $classname$::_internal_$name$_donated() const {\n" + " bool value = $inlined_string_donated$\n" + " return value;\n" + "}\n"); + } + format( + "inline std::string* $classname$::mutable_$name$() {\n" + " std::string* _s = _internal_mutable_$name$();\n" + "$annotate_mutable$" + " // @@protoc_insertion_point(field_mutable:$full_name$)\n" + " return _s;\n" + "}\n" + "inline const std::string& $classname$::_internal_$name$() const {\n" + " return $name$_.Get();\n" + "}\n" + "inline void $classname$::_internal_set_$name$(const std::string& " + "value) {\n" + " $set_hasbit$\n"); + if (!inlined_) { + format( + " $name$_.Set($default_value_tag$, value, GetArenaForAllocation());\n" + "}\n"); + } else { + format( + " $name$_.Set(nullptr, value, GetArenaForAllocation(),\n" + " _internal_$name$_donated(), &$donating_states_word$, " + "$mask_for_undonate$);\n" + "}\n"); + } + format( + "inline std::string* $classname$::_internal_mutable_$name$() {\n" + " $set_hasbit$\n"); + if (!inlined_) { + format( + " return $name$_.Mutable($default_variable_or_tag$, " + "GetArenaForAllocation());\n" + "}\n"); + } else { + format( + " return $name$_.Mutable($default_variable_or_tag$, " + "GetArenaForAllocation(), _internal_$name$_donated(), " + "&$donating_states_word$, $mask_for_undonate$);\n" + "}\n"); + } + format( + "inline std::string* $classname$::$release_name$() {\n" + "$annotate_release$" + " // @@protoc_insertion_point(field_release:$full_name$)\n"); + + if (HasHasbit(descriptor_)) { + format( + " if (!_internal_has_$name$()) {\n" + " return nullptr;\n" + " }\n" + " $clear_hasbit$\n"); + if (!inlined_) { + format( + " auto* p = $name$_.ReleaseNonDefault($init_value$, " + "GetArenaForAllocation());\n"); + if (descriptor_->default_value_string().empty()) { + format( + "#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING\n" + " if ($name$_.IsDefault($init_value$)) {\n" + " $name$_.Set($init_value$, \"\", GetArenaForAllocation());\n" + " }\n" + "#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING\n"); + } + format(" return p;\n"); + } else { + format( + " return $name$_.Release(nullptr, GetArenaForAllocation(), " + "_internal_$name$_donated());\n"); + } + } else { + format( + " return $name$_.Release($init_value$, GetArenaForAllocation());\n"); + } + + format( + "}\n" + "inline void $classname$::set_allocated_$name$(std::string* $name$) {\n" + " if ($name$ != nullptr) {\n" + " $set_hasbit$\n" + " } else {\n" + " $clear_hasbit$\n" + " }\n"); + if (!inlined_) { + format( + " $name$_.SetAllocated($init_value$, $name$,\n" + " GetArenaForAllocation());\n"); + if (descriptor_->default_value_string().empty()) { + format( + "#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING\n" + " if ($name$_.IsDefault($init_value$)) {\n" + " $name$_.Set($init_value$, \"\", GetArenaForAllocation());\n" + " }\n" + "#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING\n"); + } + } else { + // Currently, string fields with default value can't be inlined. + format( + " $name$_.SetAllocated(nullptr, $name$, GetArenaForAllocation(), " + "_internal_$name$_donated(), &$donating_states_word$, " + "$mask_for_undonate$);\n"); + } + format( + "$annotate_set$" + " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" + "}\n"); +} + +void StringFieldGenerator::GenerateNonInlineAccessorDefinitions( + io::Printer* printer) const { + Formatter format(printer, variables_); + if (!descriptor_->default_value_string().empty()) { + format( + "const ::$proto_ns$::internal::LazyString " + "$classname$::$default_variable_name$" + "{{{$default$, $default_length$}}, {nullptr}};\n"); + } +} + +void StringFieldGenerator::GenerateClearingCode(io::Printer* printer) const { + Formatter format(printer, variables_); + if (descriptor_->default_value_string().empty()) { + format("$name$_.ClearToEmpty();\n"); + } else { + GOOGLE_DCHECK(!inlined_); + format( + "$name$_.ClearToDefault($lazy_variable$, GetArenaForAllocation());\n"); + } +} + +void StringFieldGenerator::GenerateMessageClearingCode( + io::Printer* printer) const { + Formatter format(printer, variables_); + // Two-dimension specialization here: supporting arenas, field presence, or + // not, and default value is the empty string or not. Complexity here ensures + // the minimal number of branches / amount of extraneous code at runtime + // (given that the below methods are inlined one-liners)! + + // If we have a hasbit, then the Clear() method of the protocol buffer + // will have checked that this field is set. If so, we can avoid redundant + // checks against the default variable. + const bool must_be_present = HasHasbit(descriptor_); + + if (inlined_ && must_be_present) { + // Calling mutable_$name$() gives us a string reference and sets the has bit + // for $name$ (in proto2). We may get here when the string field is inlined + // but the string's contents have not been changed by the user, so we cannot + // make an assertion about the contents of the string and could never make + // an assertion about the string instance. + // + // For non-inlined strings, we distinguish from non-default by comparing + // instances, rather than contents. + format("$DCHK$(!$name$_.IsDefault(nullptr));\n"); + } + + if (descriptor_->default_value_string().empty()) { + if (must_be_present) { + format("$name$_.ClearNonDefaultToEmpty();\n"); + } else { + format("$name$_.ClearToEmpty();\n"); + } + } else { + // Clear to a non-empty default is more involved, as we try to use the + // Arena if one is present and may need to reallocate the string. + format( + "$name$_.ClearToDefault($lazy_variable$, GetArenaForAllocation());\n "); + } +} + +void StringFieldGenerator::GenerateMergingCode(io::Printer* printer) const { + Formatter format(printer, variables_); + // TODO(gpike): improve this + format("_internal_set_$name$(from._internal_$name$());\n"); +} + +void StringFieldGenerator::GenerateSwappingCode(io::Printer* printer) const { + Formatter format(printer, variables_); + if (!inlined_) { + format( + "::$proto_ns$::internal::ArenaStringPtr::InternalSwap(\n" + " $init_value$,\n" + " &$name$_, lhs_arena,\n" + " &other->$name$_, rhs_arena\n" + ");\n"); + } else { + // At this point, it's guaranteed that the two fields being swapped are on + // the same arena. + format( + "$name$_.Swap(&other->$name$_, nullptr, GetArenaForAllocation(), " + "_internal_$name$_donated(), other->_internal_$name$_donated(), " + "&$donating_states_word$, &(other->$donating_states_word$), " + "$mask_for_undonate$);\n"); + } +} + +void StringFieldGenerator::GenerateConstructorCode(io::Printer* printer) const { + Formatter format(printer, variables_); + if (inlined_ && descriptor_->default_value_string().empty()) { + // Automatic initialization will construct the string. + return; + } + GOOGLE_DCHECK(!inlined_); + format("$name$_.UnsafeSetDefault($init_value$);\n"); + if (IsString(descriptor_, options_) && + descriptor_->default_value_string().empty()) { + format( + "#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING\n" + " $name$_.Set($init_value$, \"\", GetArenaForAllocation());\n" + "#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING\n"); + } +} + +void StringFieldGenerator::GenerateCopyConstructorCode( + io::Printer* printer) const { + Formatter format(printer, variables_); + GenerateConstructorCode(printer); + + if (HasHasbit(descriptor_)) { + format("if (from._internal_has_$name$()) {\n"); + } else { + format("if (!from._internal_$name$().empty()) {\n"); + } + + format.Indent(); + + if (!inlined_) { + format( + "$name$_.Set($default_value_tag$, from._internal_$name$(), \n" + " GetArenaForAllocation());\n"); + } else { + format( + "$name$_.Set(nullptr, from._internal_$name$(),\n" + " GetArenaForAllocation(), _internal_$name$_donated(), " + "&$donating_states_word$, $mask_for_undonate$);\n"); + } + + format.Outdent(); + format("}\n"); +} + +void StringFieldGenerator::GenerateDestructorCode(io::Printer* printer) const { + Formatter format(printer, variables_); + if (inlined_) { + // The destructor is automatically invoked. + return; + } + + format("$name$_.DestroyNoArena($init_value$);\n"); +} + +void StringFieldGenerator::GenerateSerializeWithCachedSizesToArray( + io::Printer* printer) const { + Formatter format(printer, variables_); + if (descriptor_->type() == FieldDescriptor::TYPE_STRING) { + GenerateUtf8CheckCodeForString( + descriptor_, options_, false, + "this->_internal_$name$().data(), " + "static_cast<int>(this->_internal_$name$().length()),\n", + format); + } + format( + "target = stream->Write$declared_type$MaybeAliased(\n" + " $number$, this->_internal_$name$(), target);\n"); +} + +void StringFieldGenerator::GenerateByteSize(io::Printer* printer) const { + Formatter format(printer, variables_); + format( + "total_size += $tag_size$ +\n" + " ::$proto_ns$::internal::WireFormatLite::$declared_type$Size(\n" + " this->_internal_$name$());\n"); +} + +void StringFieldGenerator::GenerateConstinitInitializer( + io::Printer* printer) const { + Formatter format(printer, variables_); + if (inlined_) { + format("$name$_(nullptr, false)"); + return; + } + if (descriptor_->default_value_string().empty()) { + format("$name$_(&::$proto_ns$::internal::fixed_address_empty_string)"); + } else { + format("$name$_(nullptr)"); + } +} + +// =================================================================== + +StringOneofFieldGenerator::StringOneofFieldGenerator( + const FieldDescriptor* descriptor, const Options& options) + : StringFieldGenerator(descriptor, options) { + SetCommonOneofFieldVariables(descriptor, &variables_); + variables_["field_name"] = UnderscoresToCamelCase(descriptor->name(), true); + variables_["oneof_index"] = + StrCat(descriptor->containing_oneof()->index()); +} + +StringOneofFieldGenerator::~StringOneofFieldGenerator() {} + +void StringOneofFieldGenerator::GenerateInlineAccessorDefinitions( + io::Printer* printer) const { + Formatter format(printer, variables_); + format( + "inline const std::string& $classname$::$name$() const {\n" + "$annotate_get$" + " // @@protoc_insertion_point(field_get:$full_name$)\n" + " return _internal_$name$();\n" + "}\n" + "template <typename ArgT0, typename... ArgT>\n" + "inline void $classname$::set_$name$(ArgT0&& arg0, ArgT... args) {\n" + " if (!_internal_has_$name$()) {\n" + " clear_$oneof_name$();\n" + " set_has_$name$();\n" + " $field_member$.UnsafeSetDefault($init_value$);\n" + " }\n" + " $field_member$.$setter$($default_value_tag$," + " static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());\n" + "$annotate_set$" + " // @@protoc_insertion_point(field_set:$full_name$)\n" + "}\n" + "inline std::string* $classname$::mutable_$name$() {\n" + " std::string* _s = _internal_mutable_$name$();\n" + "$annotate_mutable$" + " // @@protoc_insertion_point(field_mutable:$full_name$)\n" + " return _s;\n" + "}\n" + "inline const std::string& $classname$::_internal_$name$() const {\n" + " if (_internal_has_$name$()) {\n" + " return $field_member$.Get();\n" + " }\n" + " return $default_string$;\n" + "}\n" + "inline void $classname$::_internal_set_$name$(const std::string& " + "value) {\n" + " if (!_internal_has_$name$()) {\n" + " clear_$oneof_name$();\n" + " set_has_$name$();\n" + " $field_member$.UnsafeSetDefault($init_value$);\n" + " }\n" + " $field_member$.Set($default_value_tag$, value, " + "GetArenaForAllocation());\n" + "}\n"); + format( + "inline std::string* $classname$::_internal_mutable_$name$() {\n" + " if (!_internal_has_$name$()) {\n" + " clear_$oneof_name$();\n" + " set_has_$name$();\n" + " $field_member$.UnsafeSetDefault($init_value$);\n" + " }\n" + " return $field_member$.Mutable(\n" + " $default_variable_or_tag$, GetArenaForAllocation());\n" + "}\n" + "inline std::string* $classname$::$release_name$() {\n" + "$annotate_release$" + " // @@protoc_insertion_point(field_release:$full_name$)\n" + " if (_internal_has_$name$()) {\n" + " clear_has_$oneof_name$();\n" + " return $field_member$.ReleaseNonDefault($init_value$, " + "GetArenaForAllocation());\n" + " } else {\n" + " return nullptr;\n" + " }\n" + "}\n" + "inline void $classname$::set_allocated_$name$(std::string* $name$) {\n" + " if (has_$oneof_name$()) {\n" + " clear_$oneof_name$();\n" + " }\n" + " if ($name$ != nullptr) {\n" + " set_has_$name$();\n" + " $field_member$.UnsafeSetDefault($name$);\n" + " ::$proto_ns$::Arena* arena = GetArenaForAllocation();\n" + " if (arena != nullptr) {\n" + " arena->Own($name$);\n" + " }\n" + " }\n" + "$annotate_set$" + " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" + "}\n"); +} + +void StringOneofFieldGenerator::GenerateClearingCode( + io::Printer* printer) const { + Formatter format(printer, variables_); + format( + "$field_member$.Destroy($default_value_tag$, " + "GetArenaForAllocation());\n"); +} + +void StringOneofFieldGenerator::GenerateMessageClearingCode( + io::Printer* printer) const { + return GenerateClearingCode(printer); +} + +void StringOneofFieldGenerator::GenerateSwappingCode( + io::Printer* printer) const { + // Don't print any swapping code. Swapping the union will swap this field. +} + +void StringOneofFieldGenerator::GenerateConstructorCode( + io::Printer* printer) const { + // Nothing required here. +} + +// =================================================================== + +RepeatedStringFieldGenerator::RepeatedStringFieldGenerator( + const FieldDescriptor* descriptor, const Options& options) + : FieldGenerator(descriptor, options) { + SetStringVariables(descriptor, &variables_, options); +} + +RepeatedStringFieldGenerator::~RepeatedStringFieldGenerator() {} + +void RepeatedStringFieldGenerator::GeneratePrivateMembers( + io::Printer* printer) const { + Formatter format(printer, variables_); + format("::$proto_ns$::RepeatedPtrField<std::string> $name$_;\n"); +} + +void RepeatedStringFieldGenerator::GenerateAccessorDeclarations( + io::Printer* printer) const { + Formatter format(printer, variables_); + // See comment above about unknown ctypes. + bool unknown_ctype = descriptor_->options().ctype() != + EffectiveStringCType(descriptor_, options_); + + if (unknown_ctype) { + format.Outdent(); + format( + " private:\n" + " // Hidden due to unknown ctype option.\n"); + format.Indent(); + } + + format( + "$deprecated_attr$const std::string& ${1$$name$$}$(int index) const;\n" + "$deprecated_attr$std::string* ${1$mutable_$name$$}$(int index);\n" + "$deprecated_attr$void ${1$set_$name$$}$(int index, const " + "std::string& value);\n" + "$deprecated_attr$void ${1$set_$name$$}$(int index, std::string&& " + "value);\n" + "$deprecated_attr$void ${1$set_$name$$}$(int index, const " + "char* value);\n", + descriptor_); + if (!options_.opensource_runtime) { + format( + "$deprecated_attr$void ${1$set_$name$$}$(int index, " + "StringPiece value);\n", + descriptor_); + } + format( + "$deprecated_attr$void ${1$set_$name$$}$(" + "int index, const $pointer_type$* value, size_t size);\n" + "$deprecated_attr$std::string* ${1$add_$name$$}$();\n" + "$deprecated_attr$void ${1$add_$name$$}$(const std::string& value);\n" + "$deprecated_attr$void ${1$add_$name$$}$(std::string&& value);\n" + "$deprecated_attr$void ${1$add_$name$$}$(const char* value);\n", + descriptor_); + if (!options_.opensource_runtime) { + format( + "$deprecated_attr$void ${1$add_$name$$}$(StringPiece value);\n", + descriptor_); + } + format( + "$deprecated_attr$void ${1$add_$name$$}$(const $pointer_type$* " + "value, size_t size)" + ";\n" + "$deprecated_attr$const ::$proto_ns$::RepeatedPtrField<std::string>& " + "${1$$name$$}$() " + "const;\n" + "$deprecated_attr$::$proto_ns$::RepeatedPtrField<std::string>* " + "${1$mutable_$name$$}$()" + ";\n" + "private:\n" + "const std::string& ${1$_internal_$name$$}$(int index) const;\n" + "std::string* _internal_add_$name$();\n" + "public:\n", + descriptor_); + + if (unknown_ctype) { + format.Outdent(); + format(" public:\n"); + format.Indent(); + } +} + +void RepeatedStringFieldGenerator::GenerateInlineAccessorDefinitions( + io::Printer* printer) const { + Formatter format(printer, variables_); + format( + "inline std::string* $classname$::add_$name$() {\n" + " std::string* _s = _internal_add_$name$();\n" + "$annotate_add_mutable$" + " // @@protoc_insertion_point(field_add_mutable:$full_name$)\n" + " return _s;\n" + "}\n"); + if (options_.safe_boundary_check) { + format( + "inline const std::string& $classname$::_internal_$name$(int index) " + "const {\n" + " return $name$_.InternalCheckedGet(\n" + " index, ::$proto_ns$::internal::GetEmptyStringAlreadyInited());\n" + "}\n"); + } else { + format( + "inline const std::string& $classname$::_internal_$name$(int index) " + "const {\n" + " return $name$_.Get(index);\n" + "}\n"); + } + format( + "inline const std::string& $classname$::$name$(int index) const {\n" + "$annotate_get$" + " // @@protoc_insertion_point(field_get:$full_name$)\n" + " return _internal_$name$(index);\n" + "}\n" + "inline std::string* $classname$::mutable_$name$(int index) {\n" + "$annotate_mutable$" + " // @@protoc_insertion_point(field_mutable:$full_name$)\n" + " return $name$_.Mutable(index);\n" + "}\n" + "inline void $classname$::set_$name$(int index, const std::string& " + "value) " + "{\n" + " $name$_.Mutable(index)->assign(value);\n" + "$annotate_set$" + " // @@protoc_insertion_point(field_set:$full_name$)\n" + "}\n" + "inline void $classname$::set_$name$(int index, std::string&& value) {\n" + " $name$_.Mutable(index)->assign(std::move(value));\n" + "$annotate_set$" + " // @@protoc_insertion_point(field_set:$full_name$)\n" + "}\n" + "inline void $classname$::set_$name$(int index, const char* value) {\n" + " $null_check$" + " $name$_.Mutable(index)->assign(value);\n" + "$annotate_set$" + " // @@protoc_insertion_point(field_set_char:$full_name$)\n" + "}\n"); + if (!options_.opensource_runtime) { + format( + "inline void " + "$classname$::set_$name$(int index, StringPiece value) {\n" + " $name$_.Mutable(index)->assign(value.data(), value.size());\n" + "$annotate_set$" + " // @@protoc_insertion_point(field_set_string_piece:$full_name$)\n" + "}\n"); + } + format( + "inline void " + "$classname$::set_$name$" + "(int index, const $pointer_type$* value, size_t size) {\n" + " $name$_.Mutable(index)->assign(\n" + " reinterpret_cast<const char*>(value), size);\n" + "$annotate_set$" + " // @@protoc_insertion_point(field_set_pointer:$full_name$)\n" + "}\n" + "inline std::string* $classname$::_internal_add_$name$() {\n" + " return $name$_.Add();\n" + "}\n" + "inline void $classname$::add_$name$(const std::string& value) {\n" + " $name$_.Add()->assign(value);\n" + "$annotate_add$" + " // @@protoc_insertion_point(field_add:$full_name$)\n" + "}\n" + "inline void $classname$::add_$name$(std::string&& value) {\n" + " $name$_.Add(std::move(value));\n" + "$annotate_add$" + " // @@protoc_insertion_point(field_add:$full_name$)\n" + "}\n" + "inline void $classname$::add_$name$(const char* value) {\n" + " $null_check$" + " $name$_.Add()->assign(value);\n" + "$annotate_add$" + " // @@protoc_insertion_point(field_add_char:$full_name$)\n" + "}\n"); + if (!options_.opensource_runtime) { + format( + "inline void $classname$::add_$name$(StringPiece value) {\n" + " $name$_.Add()->assign(value.data(), value.size());\n" + "$annotate_add$" + " // @@protoc_insertion_point(field_add_string_piece:$full_name$)\n" + "}\n"); + } + format( + "inline void " + "$classname$::add_$name$(const $pointer_type$* value, size_t size) {\n" + " $name$_.Add()->assign(reinterpret_cast<const char*>(value), size);\n" + "$annotate_add$" + " // @@protoc_insertion_point(field_add_pointer:$full_name$)\n" + "}\n" + "inline const ::$proto_ns$::RepeatedPtrField<std::string>&\n" + "$classname$::$name$() const {\n" + "$annotate_list$" + " // @@protoc_insertion_point(field_list:$full_name$)\n" + " return $name$_;\n" + "}\n" + "inline ::$proto_ns$::RepeatedPtrField<std::string>*\n" + "$classname$::mutable_$name$() {\n" + "$annotate_mutable_list$" + " // @@protoc_insertion_point(field_mutable_list:$full_name$)\n" + " return &$name$_;\n" + "}\n"); +} + +void RepeatedStringFieldGenerator::GenerateClearingCode( + io::Printer* printer) const { + Formatter format(printer, variables_); + format("$name$_.Clear();\n"); +} + +void RepeatedStringFieldGenerator::GenerateMergingCode( + io::Printer* printer) const { + Formatter format(printer, variables_); + format("$name$_.MergeFrom(from.$name$_);\n"); +} + +void RepeatedStringFieldGenerator::GenerateSwappingCode( + io::Printer* printer) const { + Formatter format(printer, variables_); + format("$name$_.InternalSwap(&other->$name$_);\n"); +} + +void RepeatedStringFieldGenerator::GenerateConstructorCode( + io::Printer* printer) const { + // Not needed for repeated fields. +} + +void RepeatedStringFieldGenerator::GenerateCopyConstructorCode( + io::Printer* printer) const { + Formatter format(printer, variables_); + format("$name$_.CopyFrom(from.$name$_);"); +} + +void RepeatedStringFieldGenerator::GenerateSerializeWithCachedSizesToArray( + io::Printer* printer) const { + Formatter format(printer, variables_); + format( + "for (int i = 0, n = this->_internal_$name$_size(); i < n; i++) {\n" + " const auto& s = this->_internal_$name$(i);\n"); + // format("for (const std::string& s : this->$name$()) {\n"); + format.Indent(); + if (descriptor_->type() == FieldDescriptor::TYPE_STRING) { + GenerateUtf8CheckCodeForString(descriptor_, options_, false, + "s.data(), static_cast<int>(s.length()),\n", + format); + } + format.Outdent(); + format( + " target = stream->Write$declared_type$($number$, s, target);\n" + "}\n"); +} + +void RepeatedStringFieldGenerator::GenerateByteSize( + io::Printer* printer) const { + Formatter format(printer, variables_); + format( + "total_size += $tag_size$ *\n" + " ::$proto_ns$::internal::FromIntSize($name$_.size());\n" + "for (int i = 0, n = $name$_.size(); i < n; i++) {\n" + " total_size += " + "::$proto_ns$::internal::WireFormatLite::$declared_type$Size(\n" + " $name$_.Get(i));\n" + "}\n"); +} + +void RepeatedStringFieldGenerator::GenerateConstinitInitializer( + io::Printer* printer) const { + Formatter format(printer, variables_); + format("$name$_()"); +} + +} // namespace cpp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_string_field.h b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_string_field.h new file mode 100644 index 00000000..c3240355 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_string_field.h @@ -0,0 +1,127 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_STRING_FIELD_H__ +#define GOOGLE_PROTOBUF_COMPILER_CPP_STRING_FIELD_H__ + +#include <map> +#include <string> +#include <compiler/cpp/cpp_field.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { + +class StringFieldGenerator : public FieldGenerator { + public: + StringFieldGenerator(const FieldDescriptor* descriptor, + const Options& options); + ~StringFieldGenerator(); + + // implements FieldGenerator --------------------------------------- + void GeneratePrivateMembers(io::Printer* printer) const override; + void GenerateStaticMembers(io::Printer* printer) const override; + void GenerateAccessorDeclarations(io::Printer* printer) const override; + void GenerateInlineAccessorDefinitions(io::Printer* printer) const override; + void GenerateNonInlineAccessorDefinitions( + io::Printer* printer) const override; + void GenerateClearingCode(io::Printer* printer) const override; + void GenerateMessageClearingCode(io::Printer* printer) const override; + void GenerateMergingCode(io::Printer* printer) const override; + void GenerateSwappingCode(io::Printer* printer) const override; + void GenerateConstructorCode(io::Printer* printer) const override; + void GenerateCopyConstructorCode(io::Printer* printer) const override; + void GenerateDestructorCode(io::Printer* printer) const override; + void GenerateSerializeWithCachedSizesToArray( + io::Printer* printer) const override; + void GenerateByteSize(io::Printer* printer) const override; + void GenerateConstinitInitializer(io::Printer* printer) const override; + bool IsInlined() const override { return inlined_; } + + private: + bool inlined_; + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StringFieldGenerator); +}; + +class StringOneofFieldGenerator : public StringFieldGenerator { + public: + StringOneofFieldGenerator(const FieldDescriptor* descriptor, + const Options& options); + ~StringOneofFieldGenerator(); + + // implements FieldGenerator --------------------------------------- + void GenerateInlineAccessorDefinitions(io::Printer* printer) const override; + void GenerateClearingCode(io::Printer* printer) const override; + + // StringFieldGenerator, from which we inherit, overrides this so we need to + // override it as well. + void GenerateMessageClearingCode(io::Printer* printer) const override; + void GenerateSwappingCode(io::Printer* printer) const override; + void GenerateConstructorCode(io::Printer* printer) const override; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StringOneofFieldGenerator); +}; + +class RepeatedStringFieldGenerator : public FieldGenerator { + public: + RepeatedStringFieldGenerator(const FieldDescriptor* descriptor, + const Options& options); + ~RepeatedStringFieldGenerator(); + + // implements FieldGenerator --------------------------------------- + void GeneratePrivateMembers(io::Printer* printer) const override; + void GenerateAccessorDeclarations(io::Printer* printer) const override; + void GenerateInlineAccessorDefinitions(io::Printer* printer) const override; + void GenerateClearingCode(io::Printer* printer) const override; + void GenerateMergingCode(io::Printer* printer) const override; + void GenerateSwappingCode(io::Printer* printer) const override; + void GenerateConstructorCode(io::Printer* printer) const override; + void GenerateCopyConstructorCode(io::Printer* printer) const override; + void GenerateSerializeWithCachedSizesToArray( + io::Printer* printer) const override; + void GenerateByteSize(io::Printer* printer) const override; + void GenerateConstinitInitializer(io::Printer* printer) const override; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedStringFieldGenerator); +}; + +} // namespace cpp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_CPP_STRING_FIELD_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto new file mode 100644 index 00000000..466a8419 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto @@ -0,0 +1,184 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// This file tests that various identifiers work as field and type names even +// though the same identifiers are used internally by the C++ code generator. + +// LINT: LEGACY_NAMES + +syntax = "proto2"; + +// Some generic_services option(s) added automatically. +// See: http://go/proto2-generic-services-default +option cc_generic_services = true; // auto-added + +// We don't put this in a package within proto2 because we need to make sure +// that the generated code doesn't depend on being in the proto2 namespace. +package protobuf_unittest; + +// Test that fields can have names like "input" and "i" which are also used +// internally by the code generator for local variables. +message TestConflictingSymbolNames { + message BuildDescriptors {} + message TypeTraits {} + + optional int32 input = 1; + optional int32 output = 2; + optional string length = 3; + repeated int32 i = 4; + repeated string new_element = 5 [ctype = STRING_PIECE]; + optional int32 total_size = 6; + optional int32 tag = 7; + + enum TestEnum { FOO = 0; } + message Data1 { + repeated int32 data = 1; + } + message Data2 { + repeated TestEnum data = 1; + } + message Data3 { + repeated string data = 1; + } + message Data4 { + repeated Data4 data = 1; + } + message Data5 { + repeated string data = 1 [ctype = STRING_PIECE]; + } + message Data6 { + repeated string data = 1 [ctype = CORD]; + } + + optional int32 source = 8; + optional int32 value = 9; + optional int32 file = 10; + optional int32 from = 11; + optional int32 handle_uninterpreted = 12; + repeated int32 index = 13; + optional int32 controller = 14; + optional int32 already_here = 15; + + optional uint32 uint32 = 16; + optional uint64 uint64 = 17; + optional string string = 18; + optional int32 memset = 19; + optional int32 int32 = 20; + optional int64 int64 = 21; + + optional uint32 cached_size = 22; + optional uint32 extensions = 23; + optional uint32 bit = 24; + optional uint32 bits = 25; + optional uint32 offsets = 26; + optional uint32 reflection = 27; + + message Cord {} + optional string some_cord = 28 [ctype = CORD]; + + message StringPiece {} + optional string some_string_piece = 29 [ctype = STRING_PIECE]; + + // Some keywords. + optional uint32 int = 30; + optional uint32 friend = 31; + optional uint32 class = 37; + optional uint32 typedecl = 39; + optional uint32 auto = 40; + + // The generator used to #define a macro called "DO" inside the .cc file. + message DO {} + optional DO do = 32; + + // Some template parameter names for extensions. + optional int32 field_type = 33; + optional bool is_packed = 34; + + // test conflicting release_$name$. "length" and "do" field in this message + // must remain string or message fields to make the test valid. + optional string release_length = 35; + // A more extreme case, the field name "do" here is a keyword, which will be + // escaped to "do_" already. Test there is no conflict even with escaped field + // names. + optional DO release_do = 36; + + // For clashing local variables in Serialize and ByteSize calculation. + optional string target = 38; + + extensions 1000 to max; // NO_PROTO3 +} + +message TestConflictingSymbolNamesExtension { // NO_PROTO3 + extend TestConflictingSymbolNames { // NO_PROTO3 + repeated int32 repeated_int32_ext = 20423638 [packed = true]; // NO_PROTO3 + } // NO_PROTO3 +} // NO_PROTO3 + +message TestConflictingEnumNames { // NO_PROTO3 + enum while { // NO_PROTO3 + default = 0; // NO_PROTO3 + and = 1; // NO_PROTO3 + class = 2; // NO_PROTO3 + int = 3; // NO_PROTO3 + typedef = 4; // NO_PROTO3 + XOR = 5; // NO_PROTO3 + } // NO_PROTO3 + + optional while conflicting_enum = 1; // NO_PROTO3 +} // NO_PROTO3 + +enum bool { // NO_PROTO3 + default = 0; // NO_PROTO3 + NOT_EQ = 1; // NO_PROTO3 + volatile = 2; // NO_PROTO3 + return = 3; // NO_PROTO3 +} // NO_PROTO3 + +message DummyMessage {} + +message NULL { + optional int32 int = 1; +} + +extend TestConflictingSymbolNames { // NO_PROTO3 + optional int32 void = 314253; // NO_PROTO3 +} // NO_PROTO3 + +// Message names that could conflict. +message Shutdown {} +message TableStruct {} + +service TestConflictingMethodNames { + rpc Closure(DummyMessage) returns (DummyMessage); +} diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_test_large_enum_value.proto b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_test_large_enum_value.proto new file mode 100644 index 00000000..cb6ca1b1 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_test_large_enum_value.proto @@ -0,0 +1,43 @@ +// 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. + +// Test that proto2 compiler can generate valid code when the enum value +// is INT_MAX. Note that this is a compile-only test and this proto is not +// referenced in any C++ code. +syntax = "proto2"; + +package protobuf_unittest; + +message TestLargeEnumValue { + enum EnumWithLargeValue { + VALUE_1 = 1; + VALUE_MAX = 0x7fffffff; + } +} diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_unittest.cc b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_unittest.cc new file mode 100644 index 00000000..fa6f4d02 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_unittest.cc @@ -0,0 +1,134 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// To test the code generator, we actually use it to generate code for +// net/proto2/internal/unittest.proto, then test that. This means that we +// are actually testing the parser and other parts of the system at the same +// time, and that problems in the generator may show up as compile-time errors +// rather than unittest failures, which may be surprising. However, testing +// the output of the C++ generator directly would be very hard. We can't very +// well just check it against golden files since those files would have to be +// updated for any small change; such a test would be very brittle and probably +// not very helpful. What we really want to test is that the code compiles +// correctly and produces the interfaces we expect, which is why this test +// is written this way. + +#include <compiler/cpp/cpp_unittest.h> + +#include <unittest.pb.h> +#include <unittest_embed_optimize_for.pb.h> +#include <unittest_optimize_for.pb.h> + +#include <test_util.h> + +#define MESSAGE_TEST_NAME MessageTest +#define GENERATED_DESCRIPTOR_TEST_NAME GeneratedDescriptorTest +#define GENERATED_MESSAGE_TEST_NAME GeneratedMessageTest +#define GENERATED_ENUM_TEST_NAME GeneratedEnumTest +#define GENERATED_SERVICE_TEST_NAME GeneratedServiceTest +#define HELPERS_TEST_NAME HelpersTest +#define DESCRIPTOR_INIT_TEST_NAME DescriptorInitializationTest + +#define UNITTEST_PROTO_PATH "net/proto2/internal/unittest.proto" +#define UNITTEST ::protobuf_unittest +#define UNITTEST_IMPORT ::protobuf_unittest_import + +// Must include after the above macros. +#include <compiler/cpp/cpp_unittest.inc> + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { + +// Can't use an anonymous namespace here due to brokenness of Tru64 compiler. +namespace cpp_unittest { + +namespace protobuf_unittest = ::protobuf_unittest; + +TEST(GENERATED_MESSAGE_TEST_NAME, TestConflictingSymbolNames) { + // test_bad_identifiers.proto successfully compiled, then it works. The + // following is just a token usage to insure that the code is, in fact, + // being compiled and linked. + + protobuf_unittest::TestConflictingSymbolNames message; + message.set_uint32(1); + EXPECT_EQ(3, message.ByteSizeLong()); + + message.set_friend_(5); + EXPECT_EQ(5, message.friend_()); + + message.set_class_(6); + EXPECT_EQ(6, message.class_()); + + // Instantiate extension template functions to test conflicting template + // parameter names. + typedef protobuf_unittest::TestConflictingSymbolNamesExtension ExtensionMessage; + message.AddExtension(ExtensionMessage::repeated_int32_ext, 123); + EXPECT_EQ(123, message.GetExtension(ExtensionMessage::repeated_int32_ext, 0)); +} + +TEST(GENERATED_MESSAGE_TEST_NAME, TestConflictingEnumNames) { + protobuf_unittest::TestConflictingEnumNames message; + message.set_conflicting_enum( + protobuf_unittest::TestConflictingEnumNames_while_and_); + EXPECT_EQ(1, message.conflicting_enum()); + message.set_conflicting_enum( + protobuf_unittest::TestConflictingEnumNames_while_XOR); + EXPECT_EQ(5, message.conflicting_enum()); + + protobuf_unittest::bool_ conflicting_enum; + conflicting_enum = protobuf_unittest::NOT_EQ; + EXPECT_EQ(1, conflicting_enum); + conflicting_enum = protobuf_unittest::return_; + EXPECT_EQ(3, conflicting_enum); +} + +TEST(GENERATED_MESSAGE_TEST_NAME, TestConflictingMessageNames) { + protobuf_unittest::NULL_ message; + message.set_int_(123); + EXPECT_EQ(message.int_(), 123); +} + +TEST(GENERATED_MESSAGE_TEST_NAME, TestConflictingExtension) { + protobuf_unittest::TestConflictingSymbolNames message; + message.SetExtension(protobuf_unittest::void_, 123); + EXPECT_EQ(123, message.GetExtension(protobuf_unittest::void_)); +} + +} // namespace cpp_unittest +} // namespace cpp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_unittest.h b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_unittest.h new file mode 100644 index 00000000..c5dc767a --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_unittest.h @@ -0,0 +1,51 @@ +// 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. + +// This header declares the namespace google::protobuf::protobuf_unittest in order to expose +// any problems with the generated class names. We use this header to ensure +// unittest.cc will declare the namespace prior to other includes, while obeying +// normal include ordering. +// +// When generating a class name of "foo.Bar" we must ensure we prefix the class +// name with "::", in case the namespace google::protobuf::foo exists. We intentionally +// trigger that case here by declaring google::protobuf::protobuf_unittest. +// +// See ClassName in helpers.h for more details. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_UNITTEST_H__ +#define GOOGLE_PROTOBUF_COMPILER_CPP_UNITTEST_H__ + +namespace google { +namespace protobuf { +namespace protobuf_unittest {} +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_CPP_UNITTEST_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_unittest.inc b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_unittest.inc new file mode 100644 index 00000000..effb7de4 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/cpp_unittest.inc @@ -0,0 +1,2234 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// To test the code generator, we actually use it to generate code for +// net/proto2/internal/unittest.proto, then test that. This means that we +// are actually testing the parser and other parts of the system at the same +// time, and that problems in the generator may show up as compile-time errors +// rather than unittest failures, which may be surprising. However, testing +// the output of the C++ generator directly would be very hard. We can't very +// well just check it against golden files since those files would have to be +// updated for any small change; such a test would be very brittle and probably +// not very helpful. What we really want to test is that the code compiles +// correctly and produces the interfaces we expect, which is why this test +// is written this way. + +#include <cstdint> +#include <limits> +#include <memory> +#include <vector> + +#include <compiler/cpp/cpp_unittest.h> +#include <stubs/strutil.h> +#if !defined(GOOGLE_PROTOBUF_CMAKE_BUILD) && !defined(_MSC_VER) +// We exclude this large proto from cmake build because it's too large for +// visual studio to compile (report internal errors). +#include <unittest_enormous_descriptor.pb.h> +#endif +#include <compiler/cpp/cpp_helpers.h> +#include <compiler/cpp/cpp_test_bad_identifiers.pb.h> +#include <compiler/scc.h> +#include <compiler/importer.h> +#include <test_util2.h> +#include <unittest_no_generic_services.pb.h> +#include <io/coded_stream.h> +#include <io/zero_copy_stream_impl.h> +#include <descriptor.pb.h> +#include <arena.h> +#include <descriptor.h> +#include <dynamic_message.h> + +#include <stubs/callback.h> +#include <stubs/common.h> +#include <stubs/logging.h> +#include <testing/googletest.h> +#include <gtest/gtest.h> +#include <stubs/casts.h> +#include <stubs/substitute.h> +#include <stubs/stl_util.h> + +// Must be included last. +#include <port_def.inc> + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { + +// Can't use an anonymous namespace here due to brokenness of Tru64 compiler. +namespace cpp_unittest { + + +void DoNothing() {} + +class MockErrorCollector : public MultiFileErrorCollector { + public: + MockErrorCollector() {} + ~MockErrorCollector() {} + + std::string text_; + + // implements ErrorCollector --------------------------------------- + void AddError(const std::string& filename, int line, int column, + const std::string& message) override { + strings::SubstituteAndAppend(&text_, "$0:$1:$2: $3\n", filename, line, column, + message); + } +}; + +#ifndef PROTOBUF_TEST_NO_DESCRIPTORS + +// Test that generated code has proper descriptors: +// Parse a descriptor directly (using google::protobuf::compiler::Importer) and +// compare it to the one that was produced by generated code. +TEST(GENERATED_DESCRIPTOR_TEST_NAME, IdenticalDescriptors) { + const FileDescriptor* generated_descriptor = + UNITTEST::TestAllTypes::descriptor()->file(); + + // Set up the Importer. + MockErrorCollector error_collector; + DiskSourceTree source_tree; + source_tree.MapPath("", TestUtil::TestSourceDir()); + Importer importer(&source_tree, &error_collector); + + // Import (parse) unittest.proto. + const FileDescriptor* parsed_descriptor = + importer.Import(TestUtil::MaybeTranslatePath(UNITTEST_PROTO_PATH)); + EXPECT_EQ("", error_collector.text_); + ASSERT_TRUE(parsed_descriptor != NULL); + + // Test that descriptors are generated correctly by converting them to + // FileDescriptorProtos and comparing. + FileDescriptorProto generated_descriptor_proto, parsed_descriptor_proto; + generated_descriptor->CopyTo(&generated_descriptor_proto); + parsed_descriptor->CopyTo(&parsed_descriptor_proto); + + EXPECT_EQ(parsed_descriptor_proto.DebugString(), + generated_descriptor_proto.DebugString()); +} + +#if !defined(GOOGLE_PROTOBUF_CMAKE_BUILD) && !defined(_MSC_VER) +// Test that generated code has proper descriptors: +// Touch a descriptor generated from an enormous message to validate special +// handling for descriptors exceeding the C++ standard's recommended minimum +// limit for string literal size +TEST(GENERATED_DESCRIPTOR_TEST_NAME, EnormousDescriptor) { + const Descriptor* generated_descriptor = + ::protobuf_unittest::TestEnormousDescriptor::descriptor(); + + EXPECT_TRUE(generated_descriptor != NULL); +} +#endif + +#endif // !PROTOBUF_TEST_NO_DESCRIPTORS + +// =================================================================== + +TEST(GENERATED_MESSAGE_TEST_NAME, Defaults) { + // Check that all default values are set correctly in the initial message. + UNITTEST::TestAllTypes message; + + TestUtil::ExpectClear(message); + + // Messages should return pointers to default instances until first use. + // (This is not checked by ExpectClear() since it is not actually true after + // the fields have been set and then cleared.) + EXPECT_EQ(&UNITTEST::TestAllTypes::OptionalGroup::default_instance(), + &message.optionalgroup()); + EXPECT_EQ(&UNITTEST::TestAllTypes::NestedMessage::default_instance(), + &message.optional_nested_message()); + EXPECT_EQ(&UNITTEST::ForeignMessage::default_instance(), + &message.optional_foreign_message()); + EXPECT_EQ(&UNITTEST_IMPORT::ImportMessage::default_instance(), + &message.optional_import_message()); +} + +TEST(GENERATED_MESSAGE_TEST_NAME, FloatingPointDefaults) { + const UNITTEST::TestExtremeDefaultValues& extreme_default = + UNITTEST::TestExtremeDefaultValues::default_instance(); + + EXPECT_EQ(0.0f, extreme_default.zero_float()); + EXPECT_EQ(1.0f, extreme_default.one_float()); + EXPECT_EQ(1.5f, extreme_default.small_float()); + EXPECT_EQ(-1.0f, extreme_default.negative_one_float()); + EXPECT_EQ(-1.5f, extreme_default.negative_float()); + EXPECT_EQ(2.0e8f, extreme_default.large_float()); + EXPECT_EQ(-8e-28f, extreme_default.small_negative_float()); + EXPECT_EQ(std::numeric_limits<double>::infinity(), + extreme_default.inf_double()); + EXPECT_EQ(-std::numeric_limits<double>::infinity(), + extreme_default.neg_inf_double()); + EXPECT_TRUE(extreme_default.nan_double() != extreme_default.nan_double()); + EXPECT_EQ(std::numeric_limits<float>::infinity(), + extreme_default.inf_float()); + EXPECT_EQ(-std::numeric_limits<float>::infinity(), + extreme_default.neg_inf_float()); + EXPECT_TRUE(extreme_default.nan_float() != extreme_default.nan_float()); +} + +TEST(GENERATED_MESSAGE_TEST_NAME, Trigraph) { + const UNITTEST::TestExtremeDefaultValues& extreme_default = + UNITTEST::TestExtremeDefaultValues::default_instance(); + + EXPECT_EQ("? ? ?? ?? ??? ?\?/ ?\?-", extreme_default.cpp_trigraph()); +} + +TEST(GENERATED_MESSAGE_TEST_NAME, ExtremeSmallIntegerDefault) { + const UNITTEST::TestExtremeDefaultValues& extreme_default = + UNITTEST::TestExtremeDefaultValues::default_instance(); + EXPECT_EQ(std::numeric_limits<int32_t>::min(), + extreme_default.really_small_int32()); + EXPECT_EQ(std::numeric_limits<int64_t>::min(), + extreme_default.really_small_int64()); +} + +TEST(GENERATED_MESSAGE_TEST_NAME, Accessors) { + // Set every field to a unique value then go back and check all those + // values. + UNITTEST::TestAllTypes message; + + TestUtil::SetAllFields(&message); + TestUtil::ExpectAllFieldsSet(message); + + TestUtil::ModifyRepeatedFields(&message); + TestUtil::ExpectRepeatedFieldsModified(message); +} + +TEST(GENERATED_MESSAGE_TEST_NAME, MutableStringDefault) { + // mutable_foo() for a string should return a string initialized to its + // default value. + UNITTEST::TestAllTypes message; + + EXPECT_EQ("hello", *message.mutable_default_string()); + + // Note that the first time we call mutable_foo(), we get a newly-allocated + // string, but if we clear it and call it again, we get the same object again. + // We should verify that it has its default value in both cases. + message.set_default_string("blah"); + message.Clear(); + + EXPECT_EQ("hello", *message.mutable_default_string()); +} + +TEST(GENERATED_MESSAGE_TEST_NAME, StringDefaults) { + UNITTEST::TestExtremeDefaultValues message; + // Check if '\000' can be used in default string value. + EXPECT_EQ(std::string("hel\000lo", 6), message.string_with_zero()); + EXPECT_EQ(std::string("wor\000ld", 6), message.bytes_with_zero()); +} + +TEST(GENERATED_MESSAGE_TEST_NAME, ReleaseString) { + // Check that release_foo() starts out NULL, and gives us a value + // that we can delete after it's been set. + UNITTEST::TestAllTypes message; + + EXPECT_EQ(NULL, message.release_default_string()); + EXPECT_FALSE(message.has_default_string()); + EXPECT_EQ("hello", message.default_string()); + + message.set_default_string("blah"); + EXPECT_TRUE(message.has_default_string()); + std::unique_ptr<std::string> str(message.release_default_string()); + EXPECT_FALSE(message.has_default_string()); + ASSERT_TRUE(str != NULL); + EXPECT_EQ("blah", *str); + + EXPECT_EQ(NULL, message.release_default_string()); + EXPECT_FALSE(message.has_default_string()); + EXPECT_EQ("hello", message.default_string()); +} + +TEST(GENERATED_MESSAGE_TEST_NAME, ReleaseMessage) { + // Check that release_foo() starts out NULL, and gives us a value + // that we can delete after it's been set. + UNITTEST::TestAllTypes message; + + EXPECT_EQ(NULL, message.release_optional_nested_message()); + EXPECT_FALSE(message.has_optional_nested_message()); + + message.mutable_optional_nested_message()->set_bb(1); + std::unique_ptr<UNITTEST::TestAllTypes::NestedMessage> nest( + message.release_optional_nested_message()); + EXPECT_FALSE(message.has_optional_nested_message()); + ASSERT_TRUE(nest != NULL); + EXPECT_EQ(1, nest->bb()); + + EXPECT_EQ(NULL, message.release_optional_nested_message()); + EXPECT_FALSE(message.has_optional_nested_message()); +} + +TEST(GENERATED_MESSAGE_TEST_NAME, SetAllocatedString) { + // Check that set_allocated_foo() works for strings. + UNITTEST::TestAllTypes message; + + EXPECT_FALSE(message.has_optional_string()); + const std::string kHello("hello"); + message.set_optional_string(kHello); + EXPECT_TRUE(message.has_optional_string()); + + message.set_allocated_optional_string(NULL); + EXPECT_FALSE(message.has_optional_string()); + EXPECT_EQ("", message.optional_string()); + + message.set_allocated_optional_string(new std::string(kHello)); + EXPECT_TRUE(message.has_optional_string()); + EXPECT_EQ(kHello, message.optional_string()); +} + +TEST(GENERATED_MESSAGE_TEST_NAME, SetAllocatedMessage) { + // Check that set_allocated_foo() can be called in all cases. + UNITTEST::TestAllTypes message; + + EXPECT_FALSE(message.has_optional_nested_message()); + + message.mutable_optional_nested_message()->set_bb(1); + EXPECT_TRUE(message.has_optional_nested_message()); + + message.set_allocated_optional_nested_message(NULL); + EXPECT_FALSE(message.has_optional_nested_message()); + EXPECT_EQ(&UNITTEST::TestAllTypes::NestedMessage::default_instance(), + &message.optional_nested_message()); + + message.mutable_optional_nested_message()->set_bb(1); + UNITTEST::TestAllTypes::NestedMessage* nest = + message.release_optional_nested_message(); + ASSERT_TRUE(nest != NULL); + EXPECT_FALSE(message.has_optional_nested_message()); + + message.set_allocated_optional_nested_message(nest); + EXPECT_TRUE(message.has_optional_nested_message()); + EXPECT_EQ(1, message.optional_nested_message().bb()); +} + +TEST(GENERATED_MESSAGE_TEST_NAME, Clear) { + // Set every field to a unique value, clear the message, then check that + // it is cleared. + UNITTEST::TestAllTypes message; + + TestUtil::SetAllFields(&message); + message.Clear(); + TestUtil::ExpectClear(message); + + // Unlike with the defaults test, we do NOT expect that requesting embedded + // messages will return a pointer to the default instance. Instead, they + // should return the objects that were created when mutable_blah() was + // called. + EXPECT_NE(&UNITTEST::TestAllTypes::OptionalGroup::default_instance(), + &message.optionalgroup()); + EXPECT_NE(&UNITTEST::TestAllTypes::NestedMessage::default_instance(), + &message.optional_nested_message()); + EXPECT_NE(&UNITTEST::ForeignMessage::default_instance(), + &message.optional_foreign_message()); + EXPECT_NE(&UNITTEST_IMPORT::ImportMessage::default_instance(), + &message.optional_import_message()); +} + +TEST(GENERATED_MESSAGE_TEST_NAME, EmbeddedNullsInBytesCharStar) { + UNITTEST::TestAllTypes message; + + const char* value = "\0lalala\0\0"; + message.set_optional_bytes(value, 9); + ASSERT_EQ(9, message.optional_bytes().size()); + EXPECT_EQ(0, memcmp(value, message.optional_bytes().data(), 9)); + + message.add_repeated_bytes(value, 9); + ASSERT_EQ(9, message.repeated_bytes(0).size()); + EXPECT_EQ(0, memcmp(value, message.repeated_bytes(0).data(), 9)); +} + +TEST(GENERATED_MESSAGE_TEST_NAME, ClearOneField) { + // Set every field to a unique value, then clear one value and insure that + // only that one value is cleared. + UNITTEST::TestAllTypes message; + + TestUtil::SetAllFields(&message); + int64_t original_value = message.optional_int64(); + + // Clear the field and make sure it shows up as cleared. + message.clear_optional_int64(); + EXPECT_FALSE(message.has_optional_int64()); + EXPECT_EQ(0, message.optional_int64()); + + // Other adjacent fields should not be cleared. + EXPECT_TRUE(message.has_optional_int32()); + EXPECT_TRUE(message.has_optional_uint32()); + + // Make sure if we set it again, then all fields are set. + message.set_optional_int64(original_value); + TestUtil::ExpectAllFieldsSet(message); +} + +TEST(GENERATED_MESSAGE_TEST_NAME, StringCharStarLength) { + // Verify that we can use a char*,length to set one of the string fields. + UNITTEST::TestAllTypes message; + message.set_optional_string("abcdef", 3); + EXPECT_EQ("abc", message.optional_string()); + + // Verify that we can use a char*,length to add to a repeated string field. + message.add_repeated_string("abcdef", 3); + EXPECT_EQ(1, message.repeated_string_size()); + EXPECT_EQ("abc", message.repeated_string(0)); + + // Verify that we can use a char*,length to set a repeated string field. + message.set_repeated_string(0, "wxyz", 2); + EXPECT_EQ("wx", message.repeated_string(0)); +} + + +TEST(GENERATED_MESSAGE_TEST_NAME, CopyFrom) { + UNITTEST::TestAllTypes message1, message2; + + TestUtil::SetAllFields(&message1); + message2.CopyFrom(message1); + TestUtil::ExpectAllFieldsSet(message2); + + // Copying from self should be a no-op. + message2.CopyFrom(message2); + TestUtil::ExpectAllFieldsSet(message2); +} + + +TEST(GENERATED_MESSAGE_TEST_NAME, SwapWithEmpty) { + UNITTEST::TestAllTypes message1, message2; + TestUtil::SetAllFields(&message1); + + TestUtil::ExpectAllFieldsSet(message1); + TestUtil::ExpectClear(message2); + message1.Swap(&message2); + TestUtil::ExpectAllFieldsSet(message2); + TestUtil::ExpectClear(message1); +} + +TEST(GENERATED_MESSAGE_TEST_NAME, SwapWithSelf) { + UNITTEST::TestAllTypes message; + TestUtil::SetAllFields(&message); + TestUtil::ExpectAllFieldsSet(message); + message.Swap(&message); + TestUtil::ExpectAllFieldsSet(message); +} + +TEST(GENERATED_MESSAGE_TEST_NAME, SwapWithOther) { + UNITTEST::TestAllTypes message1, message2; + + message1.set_optional_int32(123); + message1.set_optional_string("abc"); + message1.mutable_optional_nested_message()->set_bb(1); + message1.set_optional_nested_enum(UNITTEST::TestAllTypes::FOO); + message1.add_repeated_int32(1); + message1.add_repeated_int32(2); + message1.add_repeated_string("a"); + message1.add_repeated_string("b"); + message1.add_repeated_nested_message()->set_bb(7); + message1.add_repeated_nested_message()->set_bb(8); + message1.add_repeated_nested_enum(UNITTEST::TestAllTypes::FOO); + message1.add_repeated_nested_enum(UNITTEST::TestAllTypes::BAR); + + message2.set_optional_int32(456); + message2.set_optional_string("def"); + message2.mutable_optional_nested_message()->set_bb(2); + message2.set_optional_nested_enum(UNITTEST::TestAllTypes::BAR); + message2.add_repeated_int32(3); + message2.add_repeated_string("c"); + message2.add_repeated_nested_message()->set_bb(9); + message2.add_repeated_nested_enum(UNITTEST::TestAllTypes::BAZ); + + message1.Swap(&message2); + + EXPECT_EQ(456, message1.optional_int32()); + EXPECT_EQ("def", message1.optional_string()); + EXPECT_EQ(2, message1.optional_nested_message().bb()); + EXPECT_EQ(UNITTEST::TestAllTypes::BAR, message1.optional_nested_enum()); + ASSERT_EQ(1, message1.repeated_int32_size()); + EXPECT_EQ(3, message1.repeated_int32(0)); + ASSERT_EQ(1, message1.repeated_string_size()); + EXPECT_EQ("c", message1.repeated_string(0)); + ASSERT_EQ(1, message1.repeated_nested_message_size()); + EXPECT_EQ(9, message1.repeated_nested_message(0).bb()); + ASSERT_EQ(1, message1.repeated_nested_enum_size()); + EXPECT_EQ(UNITTEST::TestAllTypes::BAZ, message1.repeated_nested_enum(0)); + + EXPECT_EQ(123, message2.optional_int32()); + EXPECT_EQ("abc", message2.optional_string()); + EXPECT_EQ(1, message2.optional_nested_message().bb()); + EXPECT_EQ(UNITTEST::TestAllTypes::FOO, message2.optional_nested_enum()); + ASSERT_EQ(2, message2.repeated_int32_size()); + EXPECT_EQ(1, message2.repeated_int32(0)); + EXPECT_EQ(2, message2.repeated_int32(1)); + ASSERT_EQ(2, message2.repeated_string_size()); + EXPECT_EQ("a", message2.repeated_string(0)); + EXPECT_EQ("b", message2.repeated_string(1)); + ASSERT_EQ(2, message2.repeated_nested_message_size()); + EXPECT_EQ(7, message2.repeated_nested_message(0).bb()); + EXPECT_EQ(8, message2.repeated_nested_message(1).bb()); + ASSERT_EQ(2, message2.repeated_nested_enum_size()); + EXPECT_EQ(UNITTEST::TestAllTypes::FOO, message2.repeated_nested_enum(0)); + EXPECT_EQ(UNITTEST::TestAllTypes::BAR, message2.repeated_nested_enum(1)); +} + +TEST(GENERATED_MESSAGE_TEST_NAME, ADLSwap) { + UNITTEST::TestAllTypes message1, message2; + TestUtil::SetAllFields(&message1); + + // Note the address of one of the repeated fields, to verify it was swapped + // rather than copied. + const int32_t* addr = &message1.repeated_int32().Get(0); + + using std::swap; + swap(message1, message2); + + TestUtil::ExpectAllFieldsSet(message2); + TestUtil::ExpectClear(message1); + +#ifdef PROTOBUF_FORCE_COPY_IN_SWAP + EXPECT_NE(addr, &message2.repeated_int32().Get(0)); + EXPECT_EQ(*addr, message2.repeated_int32().Get(0)); +#else + EXPECT_EQ(addr, &message2.repeated_int32().Get(0)); +#endif +} + +TEST(GENERATED_MESSAGE_TEST_NAME, CopyConstructor) { + // All set. + { + UNITTEST::TestAllTypes message1; + TestUtil::SetAllFields(&message1); + + UNITTEST::TestAllTypes message2(message1); + TestUtil::ExpectAllFieldsSet(message2); + } + + // None set. + { + UNITTEST::TestAllTypes message1; + UNITTEST::TestAllTypes message2(message1); + + EXPECT_FALSE(message1.has_optional_string()); + EXPECT_FALSE(message2.has_optional_string()); + EXPECT_EQ(message1.optional_string(), message2.optional_string()); + + EXPECT_FALSE(message1.has_optional_bytes()); + EXPECT_FALSE(message2.has_optional_bytes()); + EXPECT_EQ(message1.optional_bytes(), message2.optional_bytes()); + + EXPECT_FALSE(message1.has_optional_nested_message()); + EXPECT_FALSE(message2.has_optional_nested_message()); + EXPECT_EQ(&message1.optional_nested_message(), + &message2.optional_nested_message()); + + EXPECT_FALSE(message1.has_optional_foreign_message()); + EXPECT_FALSE(message2.has_optional_foreign_message()); + EXPECT_EQ(&message1.optional_foreign_message(), + &message2.optional_foreign_message()); + + EXPECT_FALSE(message1.has_optional_import_message()); + EXPECT_FALSE(message2.has_optional_import_message()); + EXPECT_EQ(&message1.optional_import_message(), + &message2.optional_import_message()); + + EXPECT_FALSE(message1.has_optional_public_import_message()); + EXPECT_FALSE(message2.has_optional_public_import_message()); + EXPECT_EQ(&message1.optional_public_import_message(), + &message2.optional_public_import_message()); + + EXPECT_FALSE(message1.has_optional_lazy_message()); + EXPECT_FALSE(message2.has_optional_lazy_message()); + EXPECT_EQ(&message1.optional_lazy_message(), + &message2.optional_lazy_message()); + } +} + +TEST(GENERATED_MESSAGE_TEST_NAME, CopyConstructorWithArenas) { + Arena arena; + UNITTEST::TestAllTypes* message1 = + Arena::CreateMessage<UNITTEST::TestAllTypes>(&arena); + TestUtil::SetAllFields(message1); + + UNITTEST::TestAllTypes message2_stack(*message1); + TestUtil::ExpectAllFieldsSet(message2_stack); + + std::unique_ptr<UNITTEST::TestAllTypes> message2_heap( + new UNITTEST::TestAllTypes(*message1)); + TestUtil::ExpectAllFieldsSet(*message2_heap); + + arena.Reset(); + + // Verify that the copies are still intact. + TestUtil::ExpectAllFieldsSet(message2_stack); + TestUtil::ExpectAllFieldsSet(*message2_heap); +} + +TEST(GENERATED_MESSAGE_TEST_NAME, CopyAssignmentOperator) { + UNITTEST::TestAllTypes message1; + TestUtil::SetAllFields(&message1); + + UNITTEST::TestAllTypes message2; + message2 = message1; + TestUtil::ExpectAllFieldsSet(message2); + + // Make sure that self-assignment does something sane. + message2.operator=(message2); + TestUtil::ExpectAllFieldsSet(message2); +} + +#if !defined(PROTOBUF_TEST_NO_DESCRIPTORS) || PROTOBUF_RTTI +TEST(GENERATED_MESSAGE_TEST_NAME, UpcastCopyFrom) { + // Test the CopyFrom method that takes in the generic const Message& + // parameter. + UNITTEST::TestAllTypes message1, message2; + + TestUtil::SetAllFields(&message1); + + const Message* source = implicit_cast<const Message*>(&message1); + message2.CopyFrom(*source); + + TestUtil::ExpectAllFieldsSet(message2); +} +#endif + +#ifndef PROTOBUF_TEST_NO_DESCRIPTORS + +TEST(GENERATED_MESSAGE_TEST_NAME, DynamicMessageCopyFrom) { + // Test copying from a DynamicMessage, which must fall back to using + // reflection. + UNITTEST::TestAllTypes message2; + + // Construct a new version of the dynamic message via the factory. + DynamicMessageFactory factory; + std::unique_ptr<Message> message1; + message1.reset(factory.GetPrototype( + UNITTEST::TestAllTypes::descriptor())->New()); + + TestUtil::ReflectionTester reflection_tester( + UNITTEST::TestAllTypes::descriptor()); + reflection_tester.SetAllFieldsViaReflection(message1.get()); + + message2.CopyFrom(*message1); + + TestUtil::ExpectAllFieldsSet(message2); +} + +#endif // !PROTOBUF_TEST_NO_DESCRIPTORS + +TEST(GENERATED_MESSAGE_TEST_NAME, NonEmptyMergeFrom) { + // Test merging with a non-empty message. Code is a modified form + // of that found in net/proto2/internal/reflection_ops_unittest.cc. + UNITTEST::TestAllTypes message1, message2; + + TestUtil::SetAllFields(&message1); + + // This field will test merging into an empty spot. + message2.set_optional_int32(message1.optional_int32()); + message1.clear_optional_int32(); + + // This tests overwriting. + message2.set_optional_string(message1.optional_string()); + message1.set_optional_string("something else"); + + // This tests concatenating. + message2.add_repeated_int32(message1.repeated_int32(1)); + int32_t i = message1.repeated_int32(0); + message1.clear_repeated_int32(); + message1.add_repeated_int32(i); + + message1.MergeFrom(message2); + + TestUtil::ExpectAllFieldsSet(message1); +} + + +// Test the generated SerializeWithCachedSizesToArray(), +TEST(GENERATED_MESSAGE_TEST_NAME, SerializationToArray) { + UNITTEST::TestAllTypes message1, message2; + std::string data; + TestUtil::SetAllFields(&message1); + int size = message1.ByteSizeLong(); + data.resize(size); + uint8_t* start = reinterpret_cast<uint8_t*>(::google::protobuf::string_as_array(&data)); + uint8_t* end = message1.SerializeWithCachedSizesToArray(start); + EXPECT_EQ(size, end - start); + EXPECT_TRUE(message2.ParseFromString(data)); + TestUtil::ExpectAllFieldsSet(message2); + +} + +TEST(GENERATED_MESSAGE_TEST_NAME, PackedFieldsSerializationToArray) { + UNITTEST::TestPackedTypes packed_message1, packed_message2; + std::string packed_data; + TestUtil::SetPackedFields(&packed_message1); + int packed_size = packed_message1.ByteSizeLong(); + packed_data.resize(packed_size); + uint8_t* start = + reinterpret_cast<uint8_t*>(::google::protobuf::string_as_array(&packed_data)); + uint8_t* end = packed_message1.SerializeWithCachedSizesToArray(start); + EXPECT_EQ(packed_size, end - start); + EXPECT_TRUE(packed_message2.ParseFromString(packed_data)); + TestUtil::ExpectPackedFieldsSet(packed_message2); +} + +// Test the generated SerializeWithCachedSizes() by forcing the buffer to write +// one byte at a time. +TEST(GENERATED_MESSAGE_TEST_NAME, SerializationToStream) { + UNITTEST::TestAllTypes message1, message2; + TestUtil::SetAllFields(&message1); + int size = message1.ByteSizeLong(); + std::string data; + data.resize(size); + { + // Allow the output stream to buffer only one byte at a time. + io::ArrayOutputStream array_stream(::google::protobuf::string_as_array(&data), size, 1); + io::CodedOutputStream output_stream(&array_stream); + message1.SerializeWithCachedSizes(&output_stream); + EXPECT_FALSE(output_stream.HadError()); + EXPECT_EQ(size, output_stream.ByteCount()); + } + EXPECT_TRUE(message2.ParseFromString(data)); + TestUtil::ExpectAllFieldsSet(message2); + +} + +TEST(GENERATED_MESSAGE_TEST_NAME, PackedFieldsSerializationToStream) { + UNITTEST::TestPackedTypes message1, message2; + TestUtil::SetPackedFields(&message1); + int size = message1.ByteSizeLong(); + std::string data; + data.resize(size); + { + // Allow the output stream to buffer only one byte at a time. + io::ArrayOutputStream array_stream(::google::protobuf::string_as_array(&data), size, 1); + io::CodedOutputStream output_stream(&array_stream); + message1.SerializeWithCachedSizes(&output_stream); + EXPECT_FALSE(output_stream.HadError()); + EXPECT_EQ(size, output_stream.ByteCount()); + } + EXPECT_TRUE(message2.ParseFromString(data)); + TestUtil::ExpectPackedFieldsSet(message2); +} + + +TEST(GENERATED_MESSAGE_TEST_NAME, Required) { + // Test that IsInitialized() returns false if required fields are missing. + UNITTEST::TestRequired message; + + EXPECT_FALSE(message.IsInitialized()); + message.set_a(1); + EXPECT_FALSE(message.IsInitialized()); + message.set_b(2); + EXPECT_FALSE(message.IsInitialized()); + message.set_c(3); + EXPECT_TRUE(message.IsInitialized()); +} + +TEST(GENERATED_MESSAGE_TEST_NAME, RequiredForeign) { + // Test that IsInitialized() returns false if required fields in nested + // messages are missing. + UNITTEST::TestRequiredForeign message; + + EXPECT_TRUE(message.IsInitialized()); + + message.mutable_optional_message(); + EXPECT_FALSE(message.IsInitialized()); + + message.mutable_optional_message()->set_a(1); + message.mutable_optional_message()->set_b(2); + message.mutable_optional_message()->set_c(3); + EXPECT_TRUE(message.IsInitialized()); + + message.add_repeated_message(); + EXPECT_FALSE(message.IsInitialized()); + + message.mutable_repeated_message(0)->set_a(1); + message.mutable_repeated_message(0)->set_b(2); + message.mutable_repeated_message(0)->set_c(3); + EXPECT_TRUE(message.IsInitialized()); +} + +TEST(GENERATED_MESSAGE_TEST_NAME, ForeignNested) { + // Test that TestAllTypes::NestedMessage can be embedded directly into + // another message. + UNITTEST::TestForeignNested message; + + // If this compiles and runs without crashing, it must work. We have + // nothing more to test. + UNITTEST::TestAllTypes::NestedMessage* nested = + message.mutable_foreign_nested(); + nested->set_bb(1); +} + +TEST(GENERATED_MESSAGE_TEST_NAME, ReallyLargeTagNumber) { + // Test that really large tag numbers don't break anything. + UNITTEST::TestReallyLargeTagNumber message1, message2; + std::string data; + + // For the most part, if this compiles and runs then we're probably good. + // (The most likely cause for failure would be if something were attempting + // to allocate a lookup table of some sort using tag numbers as the index.) + // We'll try serializing just for fun. + message1.set_a(1234); + message1.set_bb(5678); + message1.SerializeToString(&data); + EXPECT_TRUE(message2.ParseFromString(data)); + EXPECT_EQ(1234, message2.a()); + EXPECT_EQ(5678, message2.bb()); +} + +TEST(GENERATED_MESSAGE_TEST_NAME, MutualRecursion) { + // Test that mutually-recursive message types work. + UNITTEST::TestMutualRecursionA message; + UNITTEST::TestMutualRecursionA* nested = message.mutable_bb()->mutable_a(); + UNITTEST::TestMutualRecursionA* nested2 = nested->mutable_bb()->mutable_a(); + + // Again, if the above compiles and runs, that's all we really have to + // test, but just for run we'll check that the system didn't somehow come + // up with a pointer loop... + EXPECT_NE(&message, nested); + EXPECT_NE(&message, nested2); + EXPECT_NE(nested, nested2); +} + +TEST(GENERATED_MESSAGE_TEST_NAME, CamelCaseFieldNames) { + // This test is mainly checking that the following compiles, which verifies + // that the field names were coerced to lower-case. + // + // Protocol buffers standard style is to use lowercase-with-underscores for + // field names. Some old proto1 .protos unfortunately used camel-case field + // names. In proto1, these names were forced to lower-case. So, we do the + // same thing in proto2. + + UNITTEST::TestCamelCaseFieldNames message; + + message.set_primitivefield(2); + message.set_stringfield("foo"); + message.set_enumfield(UNITTEST::FOREIGN_FOO); + message.mutable_messagefield()->set_c(6); + + message.add_repeatedprimitivefield(8); + message.add_repeatedstringfield("qux"); + message.add_repeatedenumfield(UNITTEST::FOREIGN_BAR); + message.add_repeatedmessagefield()->set_c(15); + + EXPECT_EQ(2, message.primitivefield()); + EXPECT_EQ("foo", message.stringfield()); + EXPECT_EQ(UNITTEST::FOREIGN_FOO, message.enumfield()); + EXPECT_EQ(6, message.messagefield().c()); + + EXPECT_EQ(8, message.repeatedprimitivefield(0)); + EXPECT_EQ("qux", message.repeatedstringfield(0)); + EXPECT_EQ(UNITTEST::FOREIGN_BAR, message.repeatedenumfield(0)); + EXPECT_EQ(15, message.repeatedmessagefield(0).c()); +} + +#ifndef PROTOBUF_TEST_NO_DESCRIPTORS + +TEST(GENERATED_MESSAGE_TEST_NAME, TestOptimizedForSize) { + // We rely on the tests in reflection_ops_unittest and wire_format_unittest + // to really test that reflection-based methods work. Here we are mostly + // just making sure that TestOptimizedForSize actually builds and seems to + // function. + + UNITTEST::TestOptimizedForSize message, message2; + message.set_i(1); + message.mutable_msg()->set_c(2); + message2.CopyFrom(message); + EXPECT_EQ(1, message2.i()); + EXPECT_EQ(2, message2.msg().c()); +} + +TEST(GENERATED_MESSAGE_TEST_NAME, TestEmbedOptimizedForSize) { + // Verifies that something optimized for speed can contain something optimized + // for size. + + UNITTEST::TestEmbedOptimizedForSize message, message2; + message.mutable_optional_message()->set_i(1); + message.add_repeated_message()->mutable_msg()->set_c(2); + std::string data; + message.SerializeToString(&data); + ASSERT_TRUE(message2.ParseFromString(data)); + EXPECT_EQ(1, message2.optional_message().i()); + EXPECT_EQ(2, message2.repeated_message(0).msg().c()); +} + +TEST(GENERATED_MESSAGE_TEST_NAME, TestSpaceUsed) { + UNITTEST::TestAllTypes message1; + // sizeof provides a lower bound on SpaceUsedLong(). + EXPECT_LE(sizeof(UNITTEST::TestAllTypes), message1.SpaceUsedLong()); + const size_t empty_message_size = message1.SpaceUsedLong(); + + // Setting primitive types shouldn't affect the space used. + message1.set_optional_int32(123); + message1.set_optional_int64(12345); + message1.set_optional_uint32(123); + message1.set_optional_uint64(12345); + EXPECT_EQ(empty_message_size, message1.SpaceUsedLong()); + + // On some STL implementations, setting the string to a small value should + // only increase SpaceUsedLong() by the size of a string object, though this + // is not true everywhere. + message1.set_optional_string("abc"); + EXPECT_LE(empty_message_size + message1.optional_string().size(), + message1.SpaceUsedLong()); + + // Setting a string to a value larger than the string object itself should + // increase SpaceUsedLong(), because it cannot store the value internally. + message1.set_optional_string(std::string(sizeof(std::string) + 1, 'x')); + int min_expected_increase = message1.optional_string().capacity(); + EXPECT_LE(empty_message_size + min_expected_increase, + message1.SpaceUsedLong()); + + size_t previous_size = message1.SpaceUsedLong(); + // Adding an optional message should increase the size by the size of the + // nested message type. NestedMessage is simple enough (1 int field) that it + // is equal to sizeof(NestedMessage) + message1.mutable_optional_nested_message(); + ASSERT_EQ(sizeof(UNITTEST::TestAllTypes::NestedMessage), + message1.optional_nested_message().SpaceUsedLong()); + EXPECT_EQ(previous_size + + sizeof(UNITTEST::TestAllTypes::NestedMessage), + message1.SpaceUsedLong()); +} + +TEST(GENERATED_MESSAGE_TEST_NAME, TestOneofSpaceUsed) { + UNITTEST::TestOneof2 message1; + EXPECT_LE(sizeof(UNITTEST::TestOneof2), message1.SpaceUsedLong()); + + const size_t empty_message_size = message1.SpaceUsedLong(); + // Setting primitive types shouldn't affect the space used. + message1.set_foo_int(123); + message1.set_bar_int(12345); + EXPECT_EQ(empty_message_size, message1.SpaceUsedLong()); + + // Setting a string in oneof to a small value should only increase + // SpaceUsedLong() by the size of a string object. + message1.set_foo_string("abc"); + EXPECT_LE(empty_message_size + sizeof(std::string), message1.SpaceUsedLong()); + + // Setting a string in oneof to a value larger than the string object itself + // should increase SpaceUsedLong(), because it cannot store the value + // internally. + message1.set_foo_string(std::string(sizeof(std::string) + 1, 'x')); + int min_expected_increase = + message1.foo_string().capacity() + sizeof(std::string); + EXPECT_LE(empty_message_size + min_expected_increase, + message1.SpaceUsedLong()); + + // Setting a message in oneof should delete the other fields and increase the + // size by the size of the nested message type. NestedMessage is simple enough + // that it is equal to sizeof(NestedMessage). It may be backed by LazyField, + // increasing space used by LazyField and backing Cord. + message1.mutable_foo_message(); + ASSERT_EQ(sizeof(UNITTEST::TestOneof2::NestedMessage), + message1.foo_message().SpaceUsedLong()); + EXPECT_LE(empty_message_size + sizeof(UNITTEST::TestOneof2::NestedMessage), + message1.SpaceUsedLong()); +} + +#endif // !PROTOBUF_TEST_NO_DESCRIPTORS + + +TEST(GENERATED_MESSAGE_TEST_NAME, FieldConstantValues) { + UNITTEST::TestRequired message; + EXPECT_EQ(UNITTEST::TestAllTypes_NestedMessage::kBbFieldNumber, 1); + EXPECT_EQ(UNITTEST::TestAllTypes::kOptionalInt32FieldNumber, 1); + EXPECT_EQ(UNITTEST::TestAllTypes::kOptionalgroupFieldNumber, 16); + EXPECT_EQ(UNITTEST::TestAllTypes::kOptionalNestedMessageFieldNumber, 18); + EXPECT_EQ(UNITTEST::TestAllTypes::kOptionalNestedEnumFieldNumber, 21); + EXPECT_EQ(UNITTEST::TestAllTypes::kRepeatedInt32FieldNumber, 31); + EXPECT_EQ(UNITTEST::TestAllTypes::kRepeatedgroupFieldNumber, 46); + EXPECT_EQ(UNITTEST::TestAllTypes::kRepeatedNestedMessageFieldNumber, 48); + EXPECT_EQ(UNITTEST::TestAllTypes::kRepeatedNestedEnumFieldNumber, 51); +} + +TEST(GENERATED_MESSAGE_TEST_NAME, ExtensionConstantValues) { + EXPECT_EQ(UNITTEST::TestRequired::kSingleFieldNumber, 1000); + EXPECT_EQ(UNITTEST::TestRequired::kMultiFieldNumber, 1001); + EXPECT_EQ(UNITTEST::kOptionalInt32ExtensionFieldNumber, 1); + EXPECT_EQ(UNITTEST::kOptionalgroupExtensionFieldNumber, 16); + EXPECT_EQ(UNITTEST::kOptionalNestedMessageExtensionFieldNumber, 18); + EXPECT_EQ(UNITTEST::kOptionalNestedEnumExtensionFieldNumber, 21); + EXPECT_EQ(UNITTEST::kRepeatedInt32ExtensionFieldNumber, 31); + EXPECT_EQ(UNITTEST::kRepeatedgroupExtensionFieldNumber, 46); + EXPECT_EQ(UNITTEST::kRepeatedNestedMessageExtensionFieldNumber, 48); + EXPECT_EQ(UNITTEST::kRepeatedNestedEnumExtensionFieldNumber, 51); +} + +TEST(GENERATED_MESSAGE_TEST_NAME, ParseFromTruncated) { + const std::string long_string = std::string(128, 'q'); + FileDescriptorProto p; + p.add_extension()->set_name(long_string); + const std::string msg = p.SerializeAsString(); + int successful_count = 0; + for (int i = 0; i <= msg.size(); i++) { + if (p.ParseFromArray(msg.c_str(), i)) { + ++successful_count; + } + } + // We don't really care about how often we succeeded. + // As long as we didn't crash, we're happy. + EXPECT_GE(successful_count, 1); +} + +// =================================================================== + +TEST(GENERATED_ENUM_TEST_NAME, EnumValuesAsSwitchCases) { + // Test that our nested enum values can be used as switch cases. This test + // doesn't actually do anything, the proof that it works is that it + // compiles. + int i =0; + UNITTEST::TestAllTypes::NestedEnum a = UNITTEST::TestAllTypes::BAR; + switch (a) { + case UNITTEST::TestAllTypes::FOO: + i = 1; + break; + case UNITTEST::TestAllTypes::BAR: + i = 2; + break; + case UNITTEST::TestAllTypes::BAZ: + i = 3; + break; + case UNITTEST::TestAllTypes::NEG: + i = -1; + break; + // no default case: We want to make sure the compiler recognizes that + // all cases are covered. (GCC warns if you do not cover all cases of + // an enum in a switch.) + } + + // Token check just for fun. + EXPECT_EQ(2, i); +} + +TEST(GENERATED_ENUM_TEST_NAME, IsValidValue) { + // Test enum IsValidValue. + EXPECT_TRUE(UNITTEST::TestAllTypes::NestedEnum_IsValid(1)); + EXPECT_TRUE(UNITTEST::TestAllTypes::NestedEnum_IsValid(2)); + EXPECT_TRUE(UNITTEST::TestAllTypes::NestedEnum_IsValid(3)); + + EXPECT_FALSE(UNITTEST::TestAllTypes::NestedEnum_IsValid(0)); + EXPECT_FALSE(UNITTEST::TestAllTypes::NestedEnum_IsValid(4)); + + // Make sure it also works when there are dups. + EXPECT_TRUE(UNITTEST::TestEnumWithDupValue_IsValid(1)); + EXPECT_TRUE(UNITTEST::TestEnumWithDupValue_IsValid(2)); + EXPECT_TRUE(UNITTEST::TestEnumWithDupValue_IsValid(3)); + + EXPECT_FALSE(UNITTEST::TestEnumWithDupValue_IsValid(0)); + EXPECT_FALSE(UNITTEST::TestEnumWithDupValue_IsValid(4)); +} + +TEST(GENERATED_ENUM_TEST_NAME, MinAndMax) { + EXPECT_EQ(UNITTEST::TestAllTypes::NEG, + UNITTEST::TestAllTypes::NestedEnum_MIN); + EXPECT_EQ(UNITTEST::TestAllTypes::BAZ, + UNITTEST::TestAllTypes::NestedEnum_MAX); + EXPECT_EQ(4, UNITTEST::TestAllTypes::NestedEnum_ARRAYSIZE); + + EXPECT_EQ(UNITTEST::FOREIGN_FOO, UNITTEST::ForeignEnum_MIN); + EXPECT_EQ(UNITTEST::FOREIGN_BAZ, UNITTEST::ForeignEnum_MAX); + EXPECT_EQ(7, UNITTEST::ForeignEnum_ARRAYSIZE); + + EXPECT_EQ(1, UNITTEST::TestEnumWithDupValue_MIN); + EXPECT_EQ(3, UNITTEST::TestEnumWithDupValue_MAX); + EXPECT_EQ(4, UNITTEST::TestEnumWithDupValue_ARRAYSIZE); + + EXPECT_EQ(UNITTEST::SPARSE_E, UNITTEST::TestSparseEnum_MIN); + EXPECT_EQ(UNITTEST::SPARSE_C, UNITTEST::TestSparseEnum_MAX); + EXPECT_EQ(12589235, UNITTEST::TestSparseEnum_ARRAYSIZE); + + // Make sure we can take the address of _MIN, _MAX and _ARRAYSIZE. + void* null_pointer = 0; // NULL may be integer-type, not pointer-type. + EXPECT_NE(null_pointer, &UNITTEST::TestAllTypes::NestedEnum_MIN); + EXPECT_NE(null_pointer, &UNITTEST::TestAllTypes::NestedEnum_MAX); + EXPECT_NE(null_pointer, &UNITTEST::TestAllTypes::NestedEnum_ARRAYSIZE); + + EXPECT_NE(null_pointer, &UNITTEST::ForeignEnum_MIN); + EXPECT_NE(null_pointer, &UNITTEST::ForeignEnum_MAX); + EXPECT_NE(null_pointer, &UNITTEST::ForeignEnum_ARRAYSIZE); + + // Make sure we can use _MIN and _MAX as switch cases. + switch (UNITTEST::SPARSE_A) { + case UNITTEST::TestSparseEnum_MIN: + case UNITTEST::TestSparseEnum_MAX: + break; + default: + break; + } +} + +#ifndef PROTOBUF_TEST_NO_DESCRIPTORS + +TEST(GENERATED_ENUM_TEST_NAME, Name) { + // "Names" in the presence of dup values map to the first alias. + EXPECT_EQ("FOO1", UNITTEST::TestEnumWithDupValue_Name(UNITTEST::FOO1)); + EXPECT_EQ("FOO1", UNITTEST::TestEnumWithDupValue_Name(UNITTEST::FOO2)); + + EXPECT_EQ("SPARSE_A", UNITTEST::TestSparseEnum_Name(UNITTEST::SPARSE_A)); + EXPECT_EQ("SPARSE_B", UNITTEST::TestSparseEnum_Name(UNITTEST::SPARSE_B)); + EXPECT_EQ("SPARSE_C", UNITTEST::TestSparseEnum_Name(UNITTEST::SPARSE_C)); + EXPECT_EQ("SPARSE_D", UNITTEST::TestSparseEnum_Name(UNITTEST::SPARSE_D)); + EXPECT_EQ("SPARSE_E", UNITTEST::TestSparseEnum_Name(UNITTEST::SPARSE_E)); + EXPECT_EQ("SPARSE_F", UNITTEST::TestSparseEnum_Name(UNITTEST::SPARSE_F)); + EXPECT_EQ("SPARSE_G", UNITTEST::TestSparseEnum_Name(UNITTEST::SPARSE_G)); +} + +TEST(GENERATED_ENUM_TEST_NAME, Parse) { + UNITTEST::TestEnumWithDupValue dup_value = UNITTEST::FOO1; + EXPECT_TRUE(UNITTEST::TestEnumWithDupValue_Parse("FOO1", &dup_value)); + EXPECT_EQ(UNITTEST::FOO1, dup_value); + EXPECT_TRUE(UNITTEST::TestEnumWithDupValue_Parse("FOO2", &dup_value)); + EXPECT_EQ(UNITTEST::FOO2, dup_value); + EXPECT_FALSE(UNITTEST::TestEnumWithDupValue_Parse("FOO", &dup_value)); +} + +TEST(GENERATED_ENUM_TEST_NAME, GetEnumDescriptor) { + EXPECT_EQ(UNITTEST::TestAllTypes::NestedEnum_descriptor(), + GetEnumDescriptor<UNITTEST::TestAllTypes::NestedEnum>()); + EXPECT_EQ(UNITTEST::ForeignEnum_descriptor(), + GetEnumDescriptor<UNITTEST::ForeignEnum>()); + EXPECT_EQ(UNITTEST::TestEnumWithDupValue_descriptor(), + GetEnumDescriptor<UNITTEST::TestEnumWithDupValue>()); + EXPECT_EQ(UNITTEST::TestSparseEnum_descriptor(), + GetEnumDescriptor<UNITTEST::TestSparseEnum>()); +} + +enum NonProtoEnum { + kFoo = 1, +}; + +TEST(GENERATED_ENUM_TEST_NAME, IsProtoEnumTypeTrait) { + EXPECT_TRUE(is_proto_enum<UNITTEST::TestAllTypes::NestedEnum>::value); + EXPECT_TRUE(is_proto_enum<UNITTEST::ForeignEnum>::value); + EXPECT_TRUE(is_proto_enum<UNITTEST::TestEnumWithDupValue>::value); + EXPECT_TRUE(is_proto_enum<UNITTEST::TestSparseEnum>::value); + + EXPECT_FALSE(is_proto_enum<int>::value); + EXPECT_FALSE(is_proto_enum<NonProtoEnum>::value); +} + +#endif // PROTOBUF_TEST_NO_DESCRIPTORS + +// =================================================================== + +#ifndef PROTOBUF_TEST_NO_DESCRIPTORS + +// Support code for testing services. +class GENERATED_SERVICE_TEST_NAME : public testing::Test { + protected: + class MockTestService : public UNITTEST::TestService { + public: + MockTestService() + : called_(false), + method_(""), + controller_(NULL), + request_(NULL), + response_(NULL), + done_(NULL) {} + + ~MockTestService() {} + + void Reset() { called_ = false; } + + // implements TestService ---------------------------------------- + + void Foo(RpcController* controller, const UNITTEST::FooRequest* request, + UNITTEST::FooResponse* response, Closure* done) override { + ASSERT_FALSE(called_); + called_ = true; + method_ = "Foo"; + controller_ = controller; + request_ = request; + response_ = response; + done_ = done; + } + + void Bar(RpcController* controller, const UNITTEST::BarRequest* request, + UNITTEST::BarResponse* response, Closure* done) override { + ASSERT_FALSE(called_); + called_ = true; + method_ = "Bar"; + controller_ = controller; + request_ = request; + response_ = response; + done_ = done; + } + + // --------------------------------------------------------------- + + bool called_; + std::string method_; + RpcController* controller_; + const Message* request_; + Message* response_; + Closure* done_; + }; + + class MockRpcChannel : public RpcChannel { + public: + MockRpcChannel() + : called_(false), + method_(NULL), + controller_(NULL), + request_(NULL), + response_(NULL), + done_(NULL), + destroyed_(NULL) {} + + ~MockRpcChannel() { + if (destroyed_ != NULL) *destroyed_ = true; + } + + void Reset() { called_ = false; } + + // implements TestService ---------------------------------------- + + void CallMethod(const MethodDescriptor* method, RpcController* controller, + const Message* request, Message* response, + Closure* done) override { + ASSERT_FALSE(called_); + called_ = true; + method_ = method; + controller_ = controller; + request_ = request; + response_ = response; + done_ = done; + } + + // --------------------------------------------------------------- + + bool called_; + const MethodDescriptor* method_; + RpcController* controller_; + const Message* request_; + Message* response_; + Closure* done_; + bool* destroyed_; + }; + + class MockController : public RpcController { + public: + void Reset() override { + ADD_FAILURE() << "Reset() not expected during this test."; + } + bool Failed() const override { + ADD_FAILURE() << "Failed() not expected during this test."; + return false; + } + std::string ErrorText() const override { + ADD_FAILURE() << "ErrorText() not expected during this test."; + return ""; + } + void StartCancel() override { + ADD_FAILURE() << "StartCancel() not expected during this test."; + } + void SetFailed(const std::string& reason) override { + ADD_FAILURE() << "SetFailed() not expected during this test."; + } + bool IsCanceled() const override { + ADD_FAILURE() << "IsCanceled() not expected during this test."; + return false; + } + void NotifyOnCancel(Closure* callback) override { + ADD_FAILURE() << "NotifyOnCancel() not expected during this test."; + } + }; + + GENERATED_SERVICE_TEST_NAME() + : descriptor_(UNITTEST::TestService::descriptor()), + foo_(descriptor_->FindMethodByName("Foo")), + bar_(descriptor_->FindMethodByName("Bar")), + stub_(&mock_channel_), + done_(::google::protobuf::NewPermanentCallback(&DoNothing)) {} + + void SetUp() override { + ASSERT_TRUE(foo_ != NULL); + ASSERT_TRUE(bar_ != NULL); + } + + const ServiceDescriptor* descriptor_; + const MethodDescriptor* foo_; + const MethodDescriptor* bar_; + + MockTestService mock_service_; + MockController mock_controller_; + + MockRpcChannel mock_channel_; + UNITTEST::TestService::Stub stub_; + + // Just so we don't have to re-define these with every test. + UNITTEST::FooRequest foo_request_; + UNITTEST::FooResponse foo_response_; + UNITTEST::BarRequest bar_request_; + UNITTEST::BarResponse bar_response_; + std::unique_ptr<Closure> done_; +}; + +TEST_F(GENERATED_SERVICE_TEST_NAME, GetDescriptor) { + // Test that GetDescriptor() works. + + EXPECT_EQ(descriptor_, mock_service_.GetDescriptor()); +} + +TEST_F(GENERATED_SERVICE_TEST_NAME, GetChannel) { + EXPECT_EQ(&mock_channel_, stub_.channel()); +} + +TEST_F(GENERATED_SERVICE_TEST_NAME, OwnsChannel) { + MockRpcChannel* channel = new MockRpcChannel; + bool destroyed = false; + channel->destroyed_ = &destroyed; + + { + UNITTEST::TestService::Stub owning_stub(channel, + Service::STUB_OWNS_CHANNEL); + EXPECT_FALSE(destroyed); + } + + EXPECT_TRUE(destroyed); +} + +TEST_F(GENERATED_SERVICE_TEST_NAME, CallMethod) { + // Test that CallMethod() works. + + // Call Foo() via CallMethod(). + mock_service_.CallMethod(foo_, &mock_controller_, + &foo_request_, &foo_response_, done_.get()); + + ASSERT_TRUE(mock_service_.called_); + + EXPECT_EQ("Foo" , mock_service_.method_ ); + EXPECT_EQ(&mock_controller_, mock_service_.controller_); + EXPECT_EQ(&foo_request_ , mock_service_.request_ ); + EXPECT_EQ(&foo_response_ , mock_service_.response_ ); + EXPECT_EQ(done_.get() , mock_service_.done_ ); + + // Try again, but call Bar() instead. + mock_service_.Reset(); + mock_service_.CallMethod(bar_, &mock_controller_, + &bar_request_, &bar_response_, done_.get()); + + ASSERT_TRUE(mock_service_.called_); + EXPECT_EQ("Bar", mock_service_.method_); +} + +TEST_F(GENERATED_SERVICE_TEST_NAME, CallMethodTypeFailure) { + // Verify death if we call Foo() with Bar's message types. + +#ifdef PROTOBUF_HAS_DEATH_TEST // death tests do not work on Windows yet + EXPECT_DEBUG_DEATH( + mock_service_.CallMethod(foo_, &mock_controller_, + &foo_request_, &bar_response_, done_.get()), + "dynamic_cast"); + + mock_service_.Reset(); + EXPECT_DEBUG_DEATH( + mock_service_.CallMethod(foo_, &mock_controller_, + &bar_request_, &foo_response_, done_.get()), + "dynamic_cast"); +#endif // PROTOBUF_HAS_DEATH_TEST +} + +TEST_F(GENERATED_SERVICE_TEST_NAME, GetPrototypes) { + // Test Get{Request,Response}Prototype() methods. + + EXPECT_EQ(&UNITTEST::FooRequest::default_instance(), + &mock_service_.GetRequestPrototype(foo_)); + EXPECT_EQ(&UNITTEST::BarRequest::default_instance(), + &mock_service_.GetRequestPrototype(bar_)); + + EXPECT_EQ(&UNITTEST::FooResponse::default_instance(), + &mock_service_.GetResponsePrototype(foo_)); + EXPECT_EQ(&UNITTEST::BarResponse::default_instance(), + &mock_service_.GetResponsePrototype(bar_)); +} + +TEST_F(GENERATED_SERVICE_TEST_NAME, Stub) { + // Test that the stub class works. + + // Call Foo() via the stub. + stub_.Foo(&mock_controller_, &foo_request_, &foo_response_, done_.get()); + + ASSERT_TRUE(mock_channel_.called_); + + EXPECT_EQ(foo_ , mock_channel_.method_ ); + EXPECT_EQ(&mock_controller_, mock_channel_.controller_); + EXPECT_EQ(&foo_request_ , mock_channel_.request_ ); + EXPECT_EQ(&foo_response_ , mock_channel_.response_ ); + EXPECT_EQ(done_.get() , mock_channel_.done_ ); + + // Call Bar() via the stub. + mock_channel_.Reset(); + stub_.Bar(&mock_controller_, &bar_request_, &bar_response_, done_.get()); + + ASSERT_TRUE(mock_channel_.called_); + EXPECT_EQ(bar_, mock_channel_.method_); +} + +TEST_F(GENERATED_SERVICE_TEST_NAME, NotImplemented) { + // Test that failing to implement a method of a service causes it to fail + // with a "not implemented" error message. + + // A service which doesn't implement any methods. + class UnimplementedService : public UNITTEST::TestService { + public: + UnimplementedService() {} + }; + + UnimplementedService unimplemented_service; + + // And a controller which expects to get a "not implemented" error. + class ExpectUnimplementedController : public MockController { + public: + ExpectUnimplementedController() : called_(false) {} + + void SetFailed(const std::string& reason) override { + EXPECT_FALSE(called_); + called_ = true; + EXPECT_EQ("Method Foo() not implemented.", reason); + } + + bool called_; + }; + + ExpectUnimplementedController controller; + + // Call Foo. + unimplemented_service.Foo(&controller, &foo_request_, &foo_response_, + done_.get()); + + EXPECT_TRUE(controller.called_); +} + +// =================================================================== + +class OneofTest : public testing::Test { + protected: + void SetUp() override {} + + void ExpectEnumCasesWork(const UNITTEST::TestOneof2 &message) { + switch (message.foo_case()) { + case UNITTEST::TestOneof2::kFooInt: + EXPECT_TRUE(message.has_foo_int()); + break; + case UNITTEST::TestOneof2::kFooString: + EXPECT_TRUE(message.has_foo_string()); + break; + case UNITTEST::TestOneof2::kFooCord: + EXPECT_TRUE(message.has_foo_cord()); + break; + case UNITTEST::TestOneof2::kFooStringPiece: + EXPECT_TRUE(message.has_foo_string_piece()); + break; + case UNITTEST::TestOneof2::kFooBytes: + EXPECT_TRUE(message.has_foo_bytes()); + break; + case UNITTEST::TestOneof2::kFooEnum: + EXPECT_TRUE(message.has_foo_enum()); + break; + case UNITTEST::TestOneof2::kFooMessage: + EXPECT_TRUE(message.has_foo_message()); + break; + case UNITTEST::TestOneof2::kFoogroup: + EXPECT_TRUE(message.has_foogroup()); + break; + case UNITTEST::TestOneof2::kFooLazyMessage: + EXPECT_TRUE(message.has_foo_lazy_message()); + break; + case UNITTEST::TestOneof2::FOO_NOT_SET: + break; + } + } +}; + +TEST_F(OneofTest, SettingOneFieldClearsOthers) { + UNITTEST::TestOneof2 message; + + message.set_foo_int(123); + EXPECT_TRUE(message.has_foo_int()); + TestUtil::ExpectAtMostOneFieldSetInOneof(message); + + message.set_foo_string("foo"); + EXPECT_TRUE(message.has_foo_string()); + TestUtil::ExpectAtMostOneFieldSetInOneof(message); + + + message.set_foo_bytes("qux"); + EXPECT_TRUE(message.has_foo_bytes()); + TestUtil::ExpectAtMostOneFieldSetInOneof(message); + + message.set_foo_enum(UNITTEST::TestOneof2::FOO); + EXPECT_TRUE(message.has_foo_enum()); + TestUtil::ExpectAtMostOneFieldSetInOneof(message); + + message.mutable_foo_message()->set_qux_int(234); + EXPECT_TRUE(message.has_foo_message()); + TestUtil::ExpectAtMostOneFieldSetInOneof(message); + + message.mutable_foogroup()->set_a(345); + EXPECT_TRUE(message.has_foogroup()); + TestUtil::ExpectAtMostOneFieldSetInOneof(message); + + + // we repeat this because we didn't test if this properly clears other fields + // at the beginning. + message.set_foo_int(123); + EXPECT_TRUE(message.has_foo_int()); + TestUtil::ExpectAtMostOneFieldSetInOneof(message); +} + +TEST_F(OneofTest, EnumCases) { + UNITTEST::TestOneof2 message; + + message.set_foo_int(123); + ExpectEnumCasesWork(message); + message.set_foo_string("foo"); + ExpectEnumCasesWork(message); + message.set_foo_bytes("qux"); + ExpectEnumCasesWork(message); + message.set_foo_enum(UNITTEST::TestOneof2::FOO); + ExpectEnumCasesWork(message); + message.mutable_foo_message()->set_qux_int(234); + ExpectEnumCasesWork(message); + message.mutable_foogroup()->set_a(345); + ExpectEnumCasesWork(message); +} + +TEST_F(OneofTest, PrimitiveType) { + UNITTEST::TestOneof2 message; + // Unset field returns default value + EXPECT_EQ(message.foo_int(), 0); + + message.set_foo_int(123); + EXPECT_TRUE(message.has_foo_int()); + EXPECT_EQ(message.foo_int(), 123); + message.clear_foo_int(); + EXPECT_FALSE(message.has_foo_int()); +} + +TEST_F(OneofTest, EnumType) { + UNITTEST::TestOneof2 message; + // Unset field returns default value + EXPECT_EQ(message.foo_enum(), 1); + + message.set_foo_enum(UNITTEST::TestOneof2::FOO); + EXPECT_TRUE(message.has_foo_enum()); + EXPECT_EQ(message.foo_enum(), UNITTEST::TestOneof2::FOO); + message.clear_foo_enum(); + EXPECT_FALSE(message.has_foo_enum()); +} + +TEST_F(OneofTest, SetString) { + // Check that setting a string field in various ways works + UNITTEST::TestOneof2 message; + + // Unset field returns default value + EXPECT_EQ(message.foo_string(), ""); + + message.set_foo_string("foo"); + EXPECT_TRUE(message.has_foo_string()); + EXPECT_EQ(message.foo_string(), "foo"); + message.clear_foo_string(); + EXPECT_FALSE(message.has_foo_string()); + + message.set_foo_string(std::string("bar")); + EXPECT_TRUE(message.has_foo_string()); + EXPECT_EQ(message.foo_string(), "bar"); + message.clear_foo_string(); + EXPECT_FALSE(message.has_foo_string()); + + + message.set_foo_string("qux", 3); + EXPECT_TRUE(message.has_foo_string()); + EXPECT_EQ(message.foo_string(), "qux"); + message.clear_foo_string(); + EXPECT_FALSE(message.has_foo_string()); + + message.mutable_foo_string()->assign("quux"); + EXPECT_TRUE(message.has_foo_string()); + EXPECT_EQ(message.foo_string(), "quux"); + message.clear_foo_string(); + EXPECT_FALSE(message.has_foo_string()); + + message.set_foo_string("corge"); + EXPECT_TRUE(message.has_foo_string()); + EXPECT_EQ(message.foo_string(), "corge"); + message.clear_foo_string(); + EXPECT_FALSE(message.has_foo_string()); +} + +TEST_F(OneofTest, ReleaseString) { + // Check that release_foo() starts out NULL, and gives us a value + // that we can delete after it's been set. + UNITTEST::TestOneof2 message; + + EXPECT_EQ(NULL, message.release_foo_string()); + EXPECT_FALSE(message.has_foo_string()); + + message.set_foo_string("blah"); + EXPECT_TRUE(message.has_foo_string()); + std::unique_ptr<std::string> str(message.release_foo_string()); + EXPECT_FALSE(message.has_foo_string()); + ASSERT_TRUE(str != NULL); + EXPECT_EQ("blah", *str); + + EXPECT_EQ(NULL, message.release_foo_string()); + EXPECT_FALSE(message.has_foo_string()); +} + +TEST_F(OneofTest, SetAllocatedString) { + // Check that set_allocated_foo() works for strings. + UNITTEST::TestOneof2 message; + + EXPECT_FALSE(message.has_foo_string()); + const std::string kHello("hello"); + message.set_foo_string(kHello); + EXPECT_TRUE(message.has_foo_string()); + + message.set_allocated_foo_string(NULL); + EXPECT_FALSE(message.has_foo_string()); + EXPECT_EQ("", message.foo_string()); + + message.set_allocated_foo_string(new std::string(kHello)); + EXPECT_TRUE(message.has_foo_string()); + EXPECT_EQ(kHello, message.foo_string()); +} + +TEST_F(OneofTest, ArenaSetAllocatedString) { + // Check that set_allocated_foo() works for strings. + Arena arena; + UNITTEST::TestOneof2* message = + Arena::CreateMessage<UNITTEST::TestOneof2>(&arena); + + EXPECT_FALSE(message->has_foo_string()); + const std::string kHello("hello"); + message->set_foo_string(kHello); + EXPECT_TRUE(message->has_foo_string()); + + message->set_allocated_foo_string(NULL); + EXPECT_FALSE(message->has_foo_string()); + EXPECT_EQ("", message->foo_string()); + + message->set_allocated_foo_string(new std::string(kHello)); + EXPECT_TRUE(message->has_foo_string()); + EXPECT_EQ(kHello, message->foo_string()); +} + + +TEST_F(OneofTest, SetMessage) { + // Check that setting a message field works + UNITTEST::TestOneof2 message; + + // Unset field returns default instance + EXPECT_EQ(&message.foo_message(), + &UNITTEST::TestOneof2_NestedMessage::default_instance()); + EXPECT_EQ(message.foo_message().qux_int(), 0); + + message.mutable_foo_message()->set_qux_int(234); + EXPECT_TRUE(message.has_foo_message()); + EXPECT_EQ(message.foo_message().qux_int(), 234); + message.clear_foo_message(); + EXPECT_FALSE(message.has_foo_message()); +} + +TEST_F(OneofTest, ReleaseMessage) { + // Check that release_foo() starts out NULL, and gives us a value + // that we can delete after it's been set. + UNITTEST::TestOneof2 message; + + EXPECT_EQ(NULL, message.release_foo_message()); + EXPECT_FALSE(message.has_foo_message()); + + message.mutable_foo_message()->set_qux_int(1); + EXPECT_TRUE(message.has_foo_message()); + std::unique_ptr<UNITTEST::TestOneof2_NestedMessage> mes( + message.release_foo_message()); + EXPECT_FALSE(message.has_foo_message()); + ASSERT_TRUE(mes != NULL); + EXPECT_EQ(1, mes->qux_int()); + + EXPECT_EQ(NULL, message.release_foo_message()); + EXPECT_FALSE(message.has_foo_message()); +} + +TEST_F(OneofTest, SetAllocatedMessage) { + // Check that set_allocated_foo() works for messages. + UNITTEST::TestOneof2 message; + + EXPECT_FALSE(message.has_foo_message()); + + message.mutable_foo_message()->set_qux_int(1); + EXPECT_TRUE(message.has_foo_message()); + + message.set_allocated_foo_message(NULL); + EXPECT_FALSE(message.has_foo_message()); + EXPECT_EQ(&message.foo_message(), + &UNITTEST::TestOneof2_NestedMessage::default_instance()); + + message.mutable_foo_message()->set_qux_int(1); + UNITTEST::TestOneof2_NestedMessage* mes = message.release_foo_message(); + ASSERT_TRUE(mes != NULL); + EXPECT_FALSE(message.has_foo_message()); + + message.set_allocated_foo_message(mes); + EXPECT_TRUE(message.has_foo_message()); + EXPECT_EQ(1, message.foo_message().qux_int()); +} + + +TEST_F(OneofTest, Clear) { + UNITTEST::TestOneof2 message; + + message.set_foo_int(1); + EXPECT_TRUE(message.has_foo_int()); + message.clear_foo_int(); + EXPECT_FALSE(message.has_foo_int()); +} + +TEST_F(OneofTest, Defaults) { + UNITTEST::TestOneof2 message; + + EXPECT_FALSE(message.has_foo_int()); + EXPECT_EQ(message.foo_int(), 0); + + EXPECT_FALSE(message.has_foo_string()); + EXPECT_EQ(message.foo_string(), ""); + + + EXPECT_FALSE(message.has_foo_bytes()); + EXPECT_EQ(message.foo_bytes(), ""); + + EXPECT_FALSE(message.has_foo_enum()); + EXPECT_EQ(message.foo_enum(), 1); + + EXPECT_FALSE(message.has_foo_message()); + EXPECT_EQ(message.foo_message().qux_int(), 0); + + EXPECT_FALSE(message.has_foogroup()); + EXPECT_EQ(message.foogroup().a(), 0); + + + EXPECT_FALSE(message.has_bar_int()); + EXPECT_EQ(message.bar_int(), 5); + + EXPECT_FALSE(message.has_bar_string()); + EXPECT_EQ(message.bar_string(), "STRING"); + + + EXPECT_FALSE(message.has_bar_bytes()); + EXPECT_EQ(message.bar_bytes(), "BYTES"); + + EXPECT_FALSE(message.has_bar_enum()); + EXPECT_EQ(message.bar_enum(), 2); +} + +TEST_F(OneofTest, SwapWithEmpty) { + UNITTEST::TestOneof2 message1, message2; + message1.set_foo_string("FOO"); + EXPECT_TRUE(message1.has_foo_string()); + message1.Swap(&message2); + EXPECT_FALSE(message1.has_foo_string()); + EXPECT_TRUE(message2.has_foo_string()); + EXPECT_EQ(message2.foo_string(), "FOO"); +} + +TEST_F(OneofTest, SwapWithSelf) { + UNITTEST::TestOneof2 message; + message.set_foo_string("FOO"); + EXPECT_TRUE(message.has_foo_string()); + message.Swap(&message); + EXPECT_TRUE(message.has_foo_string()); + EXPECT_EQ(message.foo_string(), "FOO"); +} + +TEST_F(OneofTest, SwapBothHasFields) { + UNITTEST::TestOneof2 message1, message2; + + message1.set_foo_string("FOO"); + EXPECT_TRUE(message1.has_foo_string()); + message2.mutable_foo_message()->set_qux_int(1); + EXPECT_TRUE(message2.has_foo_message()); + + message1.Swap(&message2); + EXPECT_FALSE(message1.has_foo_string()); + EXPECT_FALSE(message2.has_foo_message()); + EXPECT_TRUE(message1.has_foo_message()); + EXPECT_EQ(message1.foo_message().qux_int(), 1); + EXPECT_TRUE(message2.has_foo_string()); + EXPECT_EQ(message2.foo_string(), "FOO"); +} + +TEST_F(OneofTest, CopyConstructor) { + UNITTEST::TestOneof2 message1; + message1.set_foo_bytes("FOO"); + + UNITTEST::TestOneof2 message2(message1); + EXPECT_TRUE(message2.has_foo_bytes()); + EXPECT_EQ(message2.foo_bytes(), "FOO"); +} + +TEST_F(OneofTest, CopyFrom) { + UNITTEST::TestOneof2 message1, message2; + message1.set_foo_enum(UNITTEST::TestOneof2::BAR); + EXPECT_TRUE(message1.has_foo_enum()); + + message2.CopyFrom(message1); + EXPECT_TRUE(message2.has_foo_enum()); + EXPECT_EQ(message2.foo_enum(), UNITTEST::TestOneof2::BAR); + + // Copying from self should be a no-op. + message2.CopyFrom(message2); + EXPECT_TRUE(message2.has_foo_enum()); + EXPECT_EQ(message2.foo_enum(), UNITTEST::TestOneof2::BAR); +} + +TEST_F(OneofTest, CopyAssignmentOperator) { + UNITTEST::TestOneof2 message1; + message1.mutable_foo_message()->set_qux_int(123); + EXPECT_TRUE(message1.has_foo_message()); + + UNITTEST::TestOneof2 message2; + message2 = message1; + EXPECT_EQ(message2.foo_message().qux_int(), 123); + + // Make sure that self-assignment does something sane. + message2 = *&message2; // Avoid -Wself-assign. + EXPECT_EQ(message2.foo_message().qux_int(), 123); +} + +TEST_F(OneofTest, UpcastCopyFrom) { + // Test the CopyFrom method that takes in the generic const Message& + // parameter. + UNITTEST::TestOneof2 message1, message2; + message1.mutable_foogroup()->set_a(123); + EXPECT_TRUE(message1.has_foogroup()); + + const Message* source = implicit_cast<const Message*>(&message1); + message2.CopyFrom(*source); + + EXPECT_TRUE(message2.has_foogroup()); + EXPECT_EQ(message2.foogroup().a(), 123); +} + +// Test the generated SerializeWithCachedSizesToArray(), +// This indirectly tests MergePartialFromCodedStream() +// We have to test each field type separately because we cannot set them at the +// same time +TEST_F(OneofTest, SerializationToArray) { + // Primitive type + { + UNITTEST::TestOneof2 message1, message2; +std::string data; +message1.set_foo_int(123); +int size = message1.ByteSizeLong(); +data.resize(size); +uint8_t* start = reinterpret_cast<uint8_t*>(::google::protobuf::string_as_array(&data)); +uint8_t* end = message1.SerializeWithCachedSizesToArray(start); +EXPECT_EQ(size, end - start); +EXPECT_TRUE(message2.ParseFromString(data)); +EXPECT_EQ(message2.foo_int(), 123); + } + + // String + { + UNITTEST::TestOneof2 message1, message2; + std::string data; + message1.set_foo_string("foo"); + int size = message1.ByteSizeLong(); + data.resize(size); + uint8_t* start = reinterpret_cast<uint8_t*>(::google::protobuf::string_as_array(&data)); + uint8_t* end = message1.SerializeWithCachedSizesToArray(start); + EXPECT_EQ(size, end - start); + EXPECT_TRUE(message2.ParseFromString(data)); + EXPECT_EQ(message2.foo_string(), "foo"); + } + + + // Bytes + { + UNITTEST::TestOneof2 message1, message2; + std::string data; + message1.set_foo_bytes("qux"); + int size = message1.ByteSizeLong(); + data.resize(size); + uint8_t* start = reinterpret_cast<uint8_t*>(::google::protobuf::string_as_array(&data)); + uint8_t* end = message1.SerializeWithCachedSizesToArray(start); + EXPECT_EQ(size, end - start); + EXPECT_TRUE(message2.ParseFromString(data)); + EXPECT_EQ(message2.foo_bytes(), "qux"); + } + + // Enum + { + UNITTEST::TestOneof2 message1, message2; + std::string data; + message1.set_foo_enum(UNITTEST::TestOneof2::FOO); + int size = message1.ByteSizeLong(); + data.resize(size); + uint8_t* start = reinterpret_cast<uint8_t*>(::google::protobuf::string_as_array(&data)); + uint8_t* end = message1.SerializeWithCachedSizesToArray(start); + EXPECT_EQ(size, end - start); + EXPECT_TRUE(message2.ParseFromString(data)); + EXPECT_EQ(message2.foo_enum(), UNITTEST::TestOneof2::FOO); + } + + // Message + { + UNITTEST::TestOneof2 message1, message2; + std::string data; + message1.mutable_foo_message()->set_qux_int(234); + int size = message1.ByteSizeLong(); + data.resize(size); + uint8_t* start = reinterpret_cast<uint8_t*>(::google::protobuf::string_as_array(&data)); + uint8_t* end = message1.SerializeWithCachedSizesToArray(start); + EXPECT_EQ(size, end - start); + EXPECT_TRUE(message2.ParseFromString(data)); + EXPECT_EQ(message2.foo_message().qux_int(), 234); + } + + // Group + { + UNITTEST::TestOneof2 message1, message2; + std::string data; + message1.mutable_foogroup()->set_a(345); + int size = message1.ByteSizeLong(); + data.resize(size); + uint8_t* start = reinterpret_cast<uint8_t*>(::google::protobuf::string_as_array(&data)); + uint8_t* end = message1.SerializeWithCachedSizesToArray(start); + EXPECT_EQ(size, end - start); + EXPECT_TRUE(message2.ParseFromString(data)); + EXPECT_EQ(message2.foogroup().a(), 345); + } + +} + +// Test the generated SerializeWithCachedSizes() by forcing the buffer to write +// one byte at a time. +// This indirectly tests MergePartialFromCodedStream() +// We have to test each field type separately because we cannot set them at the +// same time +TEST_F(OneofTest, SerializationToStream) { + // Primitive type + { + UNITTEST::TestOneof2 message1, message2; +std::string data; +message1.set_foo_int(123); +int size = message1.ByteSizeLong(); +data.resize(size); + +{ + // Allow the output stream to buffer only one byte at a time. + io::ArrayOutputStream array_stream(::google::protobuf::string_as_array(&data), size, 1); + io::CodedOutputStream output_stream(&array_stream); + message1.SerializeWithCachedSizes(&output_stream); + EXPECT_FALSE(output_stream.HadError()); + EXPECT_EQ(size, output_stream.ByteCount()); +} + + EXPECT_TRUE(message2.ParseFromString(data)); + EXPECT_EQ(message2.foo_int(), 123); + } + + // String + { + UNITTEST::TestOneof2 message1, message2; + std::string data; + message1.set_foo_string("foo"); + int size = message1.ByteSizeLong(); + data.resize(size); + + { + // Allow the output stream to buffer only one byte at a time. + io::ArrayOutputStream array_stream(::google::protobuf::string_as_array(&data), size, 1); + io::CodedOutputStream output_stream(&array_stream); + message1.SerializeWithCachedSizes(&output_stream); + EXPECT_FALSE(output_stream.HadError()); + EXPECT_EQ(size, output_stream.ByteCount()); + } + + EXPECT_TRUE(message2.ParseFromString(data)); + EXPECT_EQ(message2.foo_string(), "foo"); + } + + + // Bytes + { + UNITTEST::TestOneof2 message1, message2; + std::string data; + message1.set_foo_bytes("qux"); + int size = message1.ByteSizeLong(); + data.resize(size); + + { + // Allow the output stream to buffer only one byte at a time. + io::ArrayOutputStream array_stream(::google::protobuf::string_as_array(&data), size, 1); + io::CodedOutputStream output_stream(&array_stream); + message1.SerializeWithCachedSizes(&output_stream); + EXPECT_FALSE(output_stream.HadError()); + EXPECT_EQ(size, output_stream.ByteCount()); + } + + EXPECT_TRUE(message2.ParseFromString(data)); + EXPECT_EQ(message2.foo_bytes(), "qux"); + } + + // Enum + { + UNITTEST::TestOneof2 message1, message2; + std::string data; + message1.set_foo_enum(UNITTEST::TestOneof2::FOO); + int size = message1.ByteSizeLong(); + data.resize(size); + + { + // Allow the output stream to buffer only one byte at a time. + io::ArrayOutputStream array_stream(::google::protobuf::string_as_array(&data), size, 1); + io::CodedOutputStream output_stream(&array_stream); + message1.SerializeWithCachedSizes(&output_stream); + EXPECT_FALSE(output_stream.HadError()); + EXPECT_EQ(size, output_stream.ByteCount()); + } + + EXPECT_TRUE(message2.ParseFromString(data)); + EXPECT_EQ(message2.foo_enum(), UNITTEST::TestOneof2::FOO); + } + + // Message + { + UNITTEST::TestOneof2 message1, message2; + std::string data; + message1.mutable_foo_message()->set_qux_int(234); + int size = message1.ByteSizeLong(); + data.resize(size); + + { + // Allow the output stream to buffer only one byte at a time. + io::ArrayOutputStream array_stream(::google::protobuf::string_as_array(&data), size, 1); + io::CodedOutputStream output_stream(&array_stream); + message1.SerializeWithCachedSizes(&output_stream); + EXPECT_FALSE(output_stream.HadError()); + EXPECT_EQ(size, output_stream.ByteCount()); + } + + EXPECT_TRUE(message2.ParseFromString(data)); + EXPECT_EQ(message2.foo_message().qux_int(), 234); + } + + // Group + { + UNITTEST::TestOneof2 message1, message2; + std::string data; + message1.mutable_foogroup()->set_a(345); + int size = message1.ByteSizeLong(); + data.resize(size); + + { + // Allow the output stream to buffer only one byte at a time. + io::ArrayOutputStream array_stream(::google::protobuf::string_as_array(&data), size, 1); + io::CodedOutputStream output_stream(&array_stream); + message1.SerializeWithCachedSizes(&output_stream); + EXPECT_FALSE(output_stream.HadError()); + EXPECT_EQ(size, output_stream.ByteCount()); + } + + EXPECT_TRUE(message2.ParseFromString(data)); + EXPECT_EQ(message2.foogroup().a(), 345); + } + +} + +TEST_F(OneofTest, MergeFrom) { + UNITTEST::TestOneof2 message1, message2; + + message1.set_foo_int(123); + message2.MergeFrom(message1); + TestUtil::ExpectAtMostOneFieldSetInOneof(message2); + EXPECT_TRUE(message2.has_foo_int()); + EXPECT_EQ(message2.foo_int(), 123); + + message1.set_foo_string("foo"); + message2.MergeFrom(message1); + TestUtil::ExpectAtMostOneFieldSetInOneof(message2); + EXPECT_TRUE(message2.has_foo_string()); + EXPECT_EQ(message2.foo_string(), "foo"); + + + message1.set_foo_bytes("qux"); + message2.MergeFrom(message1); + TestUtil::ExpectAtMostOneFieldSetInOneof(message2); + EXPECT_TRUE(message2.has_foo_bytes()); + EXPECT_EQ(message2.foo_bytes(), "qux"); + + message1.set_foo_enum(UNITTEST::TestOneof2::FOO); + message2.MergeFrom(message1); + TestUtil::ExpectAtMostOneFieldSetInOneof(message2); + EXPECT_TRUE(message2.has_foo_enum()); + EXPECT_EQ(message2.foo_enum(), UNITTEST::TestOneof2::FOO); + + message1.mutable_foo_message()->set_qux_int(234); + message2.MergeFrom(message1); + TestUtil::ExpectAtMostOneFieldSetInOneof(message2); + EXPECT_TRUE(message2.has_foo_message()); + EXPECT_EQ(message2.foo_message().qux_int(), 234); + + message1.mutable_foogroup()->set_a(345); + message2.MergeFrom(message1); + TestUtil::ExpectAtMostOneFieldSetInOneof(message2); + EXPECT_TRUE(message2.has_foogroup()); + EXPECT_EQ(message2.foogroup().a(), 345); + +} + +TEST(HELPERS_TEST_NAME, TestSCC) { + UNITTEST::TestMutualRecursionA a; + MessageSCCAnalyzer scc_analyzer((Options())); + const SCC* scc = scc_analyzer.GetSCC(a.GetDescriptor()); + std::vector<std::string> names; + names.reserve(scc->descriptors.size()); + for (int i = 0; i < scc->descriptors.size(); i++) { + names.push_back(scc->descriptors[i]->full_name()); + } + std::string package = a.GetDescriptor()->file()->package(); + ASSERT_EQ(names.size(), 4); + std::sort(names.begin(), names.end()); + EXPECT_EQ(names[0], package + ".TestMutualRecursionA"); + EXPECT_EQ(names[1], package + ".TestMutualRecursionA.SubGroup"); + EXPECT_EQ(names[2], package + ".TestMutualRecursionA.SubMessage"); + EXPECT_EQ(names[3], package + ".TestMutualRecursionB"); + + MessageAnalysis result = scc_analyzer.GetSCCAnalysis(scc); + EXPECT_EQ(result.is_recursive, true); + EXPECT_EQ(result.contains_required, false); + EXPECT_EQ(result.contains_cord, true); // TestAllTypes + EXPECT_EQ(result.contains_extension, false); // TestAllTypes +} + +TEST(HELPERS_TEST_NAME, TestSCCAnalysis) { + { + UNITTEST::TestRecursiveMessage msg; + MessageSCCAnalyzer scc_analyzer((Options())); + const SCC* scc = scc_analyzer.GetSCC(msg.GetDescriptor()); + MessageAnalysis result = scc_analyzer.GetSCCAnalysis(scc); + EXPECT_EQ(result.is_recursive, true); + EXPECT_EQ(result.contains_required, false); + EXPECT_EQ(result.contains_cord, false); + EXPECT_EQ(result.contains_extension, false); + } + { + UNITTEST::TestAllExtensions msg; + MessageSCCAnalyzer scc_analyzer((Options())); + const SCC* scc = scc_analyzer.GetSCC(msg.GetDescriptor()); + MessageAnalysis result = scc_analyzer.GetSCCAnalysis(scc); + EXPECT_EQ(result.is_recursive, false); + EXPECT_EQ(result.contains_required, false); + EXPECT_EQ(result.contains_cord, false); + EXPECT_EQ(result.contains_extension, true); + } + { + UNITTEST::TestRequired msg; + MessageSCCAnalyzer scc_analyzer((Options())); + const SCC* scc = scc_analyzer.GetSCC(msg.GetDescriptor()); + MessageAnalysis result = scc_analyzer.GetSCCAnalysis(scc); + EXPECT_EQ(result.is_recursive, false); + EXPECT_EQ(result.contains_required, true); + EXPECT_EQ(result.contains_cord, false); + EXPECT_EQ(result.contains_extension, false); + } +} + +} // namespace cpp_unittest +} // namespace cpp +} // namespace compiler + +namespace no_generic_services_test { + // Verify that no class called "TestService" was defined in + // unittest_no_generic_services.pb.h by defining a different type by the same + // name. If such a service was generated, this will not compile. + struct TestService { + int i; + }; +} + +namespace compiler { +namespace cpp { +namespace cpp_unittest { + +TEST_F(GENERATED_SERVICE_TEST_NAME, NoGenericServices) { + // Verify that non-services in unittest_no_generic_services.proto were + // generated. + ::protobuf_unittest::no_generic_services_test::TestMessage message; + message.set_a(1); + message.SetExtension( + ::protobuf_unittest::no_generic_services_test::test_extension, 123); + ::protobuf_unittest::no_generic_services_test::TestEnum e = + ::protobuf_unittest::no_generic_services_test::FOO; + EXPECT_EQ(e, 1); + + // Verify that a ServiceDescriptor is generated for the service even if the + // class itself is not. + const FileDescriptor* file = + ::google::protobuf::unittest::no_generic_services_test::TestMessage::descriptor() + ->file(); + + ASSERT_EQ(1, file->service_count()); + EXPECT_EQ("TestService", file->service(0)->name()); + ASSERT_EQ(1, file->service(0)->method_count()); + EXPECT_EQ("Foo", file->service(0)->method(0)->name()); +} + +#endif // !PROTOBUF_TEST_NO_DESCRIPTORS + +// =================================================================== + +// This test must run last. It verifies that descriptors were or were not +// initialized depending on whether PROTOBUF_TEST_NO_DESCRIPTORS was defined. +// When this is defined, we skip all tests which are expected to trigger +// descriptor initialization. This verifies that everything else still works +// if descriptors are not initialized. +TEST(DESCRIPTOR_INIT_TEST_NAME, Initialized) { +#ifdef PROTOBUF_TEST_NO_DESCRIPTORS + bool should_have_descriptors = false; +#else + bool should_have_descriptors = true; +#endif + + EXPECT_EQ(should_have_descriptors, + DescriptorPool::generated_pool()->InternalIsFileLoaded( + TestUtil::MaybeTranslatePath(UNITTEST_PROTO_PATH))); +} + +} // namespace cpp_unittest + +} // namespace cpp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#include <port_undef.inc> diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/cpp/metadata_test.cc b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/metadata_test.cc new file mode 100644 index 00000000..bbd043d1 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/cpp/metadata_test.cc @@ -0,0 +1,161 @@ +// 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 <memory> + +#include <testing/file.h> +#include <testing/file.h> +#include <compiler/cpp/cpp_helpers.h> +#include <compiler/cpp/cpp_generator.h> +#include <compiler/annotation_test_util.h> +#include <compiler/command_line_interface.h> +#include <descriptor.pb.h> +#include <testing/googletest.h> +#include <gtest/gtest.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { + +namespace atu = annotation_test_util; + +namespace { + +class CppMetadataTest : public ::testing::Test { + public: + // Tries to capture a FileDescriptorProto, GeneratedCodeInfo, and output + // code from the previously added file with name `filename`. Returns true on + // success. If pb_h is non-null, expects a .pb.h and a .pb.h.meta (copied to + // pb_h and pb_h_info respecfively); similarly for proto_h and proto_h_info. + bool CaptureMetadata(const std::string& filename, FileDescriptorProto* file, + std::string* pb_h, GeneratedCodeInfo* pb_h_info, + std::string* proto_h, GeneratedCodeInfo* proto_h_info, + std::string* pb_cc) { + CommandLineInterface cli; + CppGenerator cpp_generator; + cli.RegisterGenerator("--cpp_out", &cpp_generator, ""); + std::string cpp_out = + "--cpp_out=annotate_headers=true," + "annotation_pragma_name=pragma_name," + "annotation_guard_name=guard_name:" + + TestTempDir(); + + const bool result = atu::RunProtoCompiler(filename, cpp_out, &cli, file); + + if (!result) { + return result; + } + + std::string output_base = TestTempDir() + "/" + StripProto(filename); + + if (pb_cc != NULL) { + GOOGLE_CHECK_OK( + File::GetContents(output_base + ".pb.cc", pb_cc, true)); + } + + if (pb_h != NULL && pb_h_info != NULL) { + GOOGLE_CHECK_OK( + File::GetContents(output_base + ".pb.h", pb_h, true)); + if (!atu::DecodeMetadata(output_base + ".pb.h.meta", pb_h_info)) { + return false; + } + } + + if (proto_h != NULL && proto_h_info != NULL) { + GOOGLE_CHECK_OK(File::GetContents(output_base + ".proto.h", proto_h, + true)); + if (!atu::DecodeMetadata(output_base + ".proto.h.meta", proto_h_info)) { + return false; + } + } + + return true; + } +}; + +const char kSmallTestFile[] = + "syntax = \"proto2\";\n" + "package foo;\n" + "enum Enum { VALUE = 0; }\n" + "message Message { }\n"; + +TEST_F(CppMetadataTest, CapturesEnumNames) { + FileDescriptorProto file; + GeneratedCodeInfo info; + std::string pb_h; + atu::AddFile("test.proto", kSmallTestFile); + EXPECT_TRUE( + CaptureMetadata("test.proto", &file, &pb_h, &info, NULL, NULL, NULL)); + EXPECT_EQ("Enum", file.enum_type(0).name()); + std::vector<int> enum_path; + enum_path.push_back(FileDescriptorProto::kEnumTypeFieldNumber); + enum_path.push_back(0); + const GeneratedCodeInfo::Annotation* enum_annotation = + atu::FindAnnotationOnPath(info, "test.proto", enum_path); + EXPECT_TRUE(NULL != enum_annotation); + EXPECT_TRUE(atu::AnnotationMatchesSubstring(pb_h, enum_annotation, "Enum")); +} + +TEST_F(CppMetadataTest, AddsPragma) { + FileDescriptorProto file; + GeneratedCodeInfo info; + std::string pb_h; + atu::AddFile("test.proto", kSmallTestFile); + EXPECT_TRUE( + CaptureMetadata("test.proto", &file, &pb_h, &info, NULL, NULL, NULL)); + EXPECT_TRUE(pb_h.find("#ifdef guard_name") != std::string::npos); + EXPECT_TRUE(pb_h.find("#pragma pragma_name \"test.pb.h.meta\"") != + std::string::npos); +} + +TEST_F(CppMetadataTest, CapturesMessageNames) { + FileDescriptorProto file; + GeneratedCodeInfo info; + std::string pb_h; + atu::AddFile("test.proto", kSmallTestFile); + EXPECT_TRUE( + CaptureMetadata("test.proto", &file, &pb_h, &info, NULL, NULL, NULL)); + EXPECT_EQ("Message", file.message_type(0).name()); + std::vector<int> message_path; + message_path.push_back(FileDescriptorProto::kMessageTypeFieldNumber); + message_path.push_back(0); + const GeneratedCodeInfo::Annotation* message_annotation = + atu::FindAnnotationOnPath(info, "test.proto", message_path); + EXPECT_TRUE(NULL != message_annotation); + EXPECT_TRUE( + atu::AnnotationMatchesSubstring(pb_h, message_annotation, "Message")); +} + +} // namespace +} // namespace cpp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_bootstrap_unittest.cc b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_bootstrap_unittest.cc new file mode 100644 index 00000000..371b12ca --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_bootstrap_unittest.cc @@ -0,0 +1,194 @@ +// 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. + +// This test insures that +// csharp/src/Google.Protobuf/Reflection/Descriptor.cs match exactly +// what would be generated by the protocol compiler. The file is not +// generated automatically at build time. +// +// If this test fails, run the script +// "generate_descriptor_proto.sh" and add the changed files under +// csharp/src/ to your changelist. + +#include <map> + +#include <compiler/csharp/csharp_generator.h> +#include <compiler/importer.h> +#include <descriptor.h> +#include <io/zero_copy_stream_impl.h> +#include <stubs/map_util.h> +#include <stubs/stl_util.h> +#include <stubs/strutil.h> +#include <stubs/substitute.h> + +#include <testing/file.h> +#include <testing/file.h> +#include <testing/googletest.h> +#include <gtest/gtest.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +namespace { + +class MockErrorCollector : public MultiFileErrorCollector { + public: + MockErrorCollector() {} + ~MockErrorCollector() {} + + std::string text_; + + // implements ErrorCollector --------------------------------------- + void AddError(const std::string& filename, int line, int column, + const std::string& message) { + strings::SubstituteAndAppend(&text_, "$0:$1:$2: $3\n", + filename, line, column, message); + } +}; + +class MockGeneratorContext : public GeneratorContext { + public: + void ExpectFileMatches(const std::string& virtual_filename, + const std::string& physical_filename) { + auto it = files_.find(virtual_filename); + ASSERT_TRUE(it != files_.end()) + << "Generator failed to generate file: " << virtual_filename; + std::string expected_contents = *it->second; + + std::string actual_contents; + GOOGLE_CHECK_OK( + File::GetContentsAsText(TestSourceDir() + "/" + physical_filename, + &actual_contents, true)) + << "Unable to get " << physical_filename; + EXPECT_TRUE(actual_contents == expected_contents) + << physical_filename << " needs to be regenerated. Please run " + "generate_descriptor_proto.sh. Then add this file " + "to your CL."; + } + + // implements GeneratorContext -------------------------------------- + + virtual io::ZeroCopyOutputStream* Open(const std::string& filename) { + auto& map_slot = files_[filename]; + map_slot.reset(new std::string); + return new io::StringOutputStream(map_slot.get()); + } + + private: + std::map<std::string, std::unique_ptr<std::string>> files_; +}; + +class GenerateAndTest { + public: + GenerateAndTest() {} + void Run(const FileDescriptor* proto_file, std::string file1, std::string file2) { + ASSERT_TRUE(proto_file != NULL) << TestSourceDir(); + ASSERT_TRUE(generator_.Generate(proto_file, parameter_, + &context_, &error_)); + context_.ExpectFileMatches(file1, file2); + } + void SetParameter(string parameter) { + parameter_ = parameter; + } + + private: + Generator generator_; + MockGeneratorContext context_; + std::string error_; + std::string parameter_; +}; + +TEST(CsharpBootstrapTest, GeneratedCsharpDescriptorMatches) { + // Skip this whole test if the csharp directory doesn't exist (i.e., a C++11 + // only distribution). + std::string descriptor_file_name = + "../csharp/src/Google.Protobuf/Reflection/Descriptor.cs"; + if (!File::Exists(TestSourceDir() + "/" + descriptor_file_name)) { + return; + } + + MockErrorCollector error_collector; + DiskSourceTree source_tree; + Importer importer(&source_tree, &error_collector); + GenerateAndTest generate_test; + + generate_test.SetParameter("base_namespace=Google.Protobuf"); + source_tree.MapPath("", TestSourceDir()); + generate_test.Run(importer.Import("google/protobuf/descriptor.proto"), + "Reflection/Descriptor.cs", + "../csharp/src/Google.Protobuf/Reflection/Descriptor.cs"); + generate_test.Run(importer.Import("google/protobuf/any.proto"), + "WellKnownTypes/Any.cs", + "../csharp/src/Google.Protobuf/WellKnownTypes/Any.cs"); + generate_test.Run(importer.Import("google/protobuf/api.proto"), + "WellKnownTypes/Api.cs", + "../csharp/src/Google.Protobuf/WellKnownTypes/Api.cs"); + generate_test.Run(importer.Import("google/protobuf/duration.proto"), + "WellKnownTypes/Duration.cs", + "../csharp/src/Google.Protobuf/WellKnownTypes/Duration.cs"); + generate_test.Run(importer.Import("google/protobuf/empty.proto"), + "WellKnownTypes/Empty.cs", + "../csharp/src/Google.Protobuf/WellKnownTypes/Empty.cs"); + generate_test.Run(importer.Import("google/protobuf/field_mask.proto"), + "WellKnownTypes/FieldMask.cs", + "../csharp/src/Google.Protobuf/WellKnownTypes/FieldMask.cs"); + generate_test.Run(importer.Import("google/protobuf/source_context.proto"), + "WellKnownTypes/SourceContext.cs", + "../csharp/src/Google.Protobuf/WellKnownTypes/SourceContext.cs"); + generate_test.Run(importer.Import("google/protobuf/struct.proto"), + "WellKnownTypes/Struct.cs", + "../csharp/src/Google.Protobuf/WellKnownTypes/Struct.cs"); + generate_test.Run(importer.Import("google/protobuf/timestamp.proto"), + "WellKnownTypes/Timestamp.cs", + "../csharp/src/Google.Protobuf/WellKnownTypes/Timestamp.cs"); + generate_test.Run(importer.Import("google/protobuf/type.proto"), + "WellKnownTypes/Type.cs", + "../csharp/src/Google.Protobuf/WellKnownTypes/Type.cs"); + generate_test.Run(importer.Import("google/protobuf/wrappers.proto"), + "WellKnownTypes/Wrappers.cs", + "../csharp/src/Google.Protobuf/WellKnownTypes/Wrappers.cs"); + + generate_test.SetParameter(""); + source_tree.MapPath("", TestSourceDir() + "/../conformance"); + generate_test.Run(importer.Import("conformance.proto"), + "Conformance.cs", + "../csharp/src/Google.Protobuf.Conformance/Conformance.cs"); + + EXPECT_EQ("", error_collector.text_); +} + +} // namespace + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_doc_comment.cc b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_doc_comment.cc new file mode 100644 index 00000000..12dabe04 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_doc_comment.cc @@ -0,0 +1,116 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +#include <compiler/csharp/csharp_doc_comment.h> +#include <descriptor.h> +#include <io/printer.h> +#include <stubs/strutil.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +// Functions to create C# XML documentation comments. +// Currently this only includes documentation comments containing text specified as comments +// in the .proto file; documentation comments generated just from field/message/enum/proto names +// is inlined in the relevant code. If more control is required, that code can be moved here. + +void WriteDocCommentBodyImpl(io::Printer* printer, SourceLocation location) { + std::string comments = location.leading_comments.empty() ? + location.trailing_comments : location.leading_comments; + if (comments.empty()) { + return; + } + // XML escaping... no need for apostrophes etc as the whole text is going to be a child + // node of a summary element, not part of an attribute. + comments = StringReplace(comments, "&", "&", true); + comments = StringReplace(comments, "<", "<", true); + std::vector<std::string> lines; + lines = Split(comments, "\n", false); + // TODO: We really should work out which part to put in the summary and which to put in the remarks... + // but that needs to be part of a bigger effort to understand the markdown better anyway. + printer->Print("/// <summary>\n"); + bool last_was_empty = false; + // We squash multiple blank lines down to one, and remove any trailing blank lines. We need + // to preserve the blank lines themselves, as this is relevant in the markdown. + // Note that we can't remove leading or trailing whitespace as *that's* relevant in markdown too. + // (We don't skip "just whitespace" lines, either.) + for (std::vector<std::string>::iterator it = lines.begin(); + it != lines.end(); ++it) { + std::string line = *it; + if (line.empty()) { + last_was_empty = true; + } else { + if (last_was_empty) { + printer->Print("///\n"); + } + last_was_empty = false; + printer->Print("///$line$\n", "line", *it); + } + } + printer->Print("/// </summary>\n"); +} + +template <typename DescriptorType> +static void WriteDocCommentBody( + io::Printer* printer, const DescriptorType* descriptor) { + SourceLocation location; + if (descriptor->GetSourceLocation(&location)) { + WriteDocCommentBodyImpl(printer, location); + } +} + +void WriteMessageDocComment(io::Printer* printer, const Descriptor* message) { + WriteDocCommentBody(printer, message); +} + +void WritePropertyDocComment(io::Printer* printer, const FieldDescriptor* field) { + WriteDocCommentBody(printer, field); +} + +void WriteEnumDocComment(io::Printer* printer, const EnumDescriptor* enumDescriptor) { + WriteDocCommentBody(printer, enumDescriptor); +} +void WriteEnumValueDocComment(io::Printer* printer, const EnumValueDescriptor* value) { + WriteDocCommentBody(printer, value); +} + +void WriteMethodDocComment(io::Printer* printer, const MethodDescriptor* method) { + WriteDocCommentBody(printer, method); +} + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_doc_comment.h b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_doc_comment.h new file mode 100644 index 00000000..ca78e251 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_doc_comment.h @@ -0,0 +1,51 @@ +// 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. + + +#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_DOC_COMMENT_H__ +#define GOOGLE_PROTOBUF_COMPILER_CSHARP_DOC_COMMENT_H__ + +#include <io/printer.h> +#include <descriptor.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + void WriteMessageDocComment(io::Printer* printer, const Descriptor* message); + void WritePropertyDocComment(io::Printer* printer, const FieldDescriptor* field); + void WriteEnumDocComment(io::Printer* printer, const EnumDescriptor* enumDescriptor); + void WriteEnumValueDocComment(io::Printer* printer, const EnumValueDescriptor* value); + void WriteMethodDocComment(io::Printer* printer, const MethodDescriptor* method); +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_DOC_COMMENT_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_enum.cc b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_enum.cc new file mode 100644 index 00000000..fd96c571 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_enum.cc @@ -0,0 +1,99 @@ +// 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 <sstream> + +#include <compiler/code_generator.h> +#include <descriptor.h> +#include <descriptor.pb.h> +#include <io/printer.h> +#include <io/zero_copy_stream.h> +#include <stubs/strutil.h> + +#include <compiler/csharp/csharp_doc_comment.h> +#include <compiler/csharp/csharp_enum.h> +#include <compiler/csharp/csharp_helpers.h> +#include <compiler/csharp/csharp_options.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor, const Options* options) : + SourceGeneratorBase(options), + descriptor_(descriptor) { +} + +EnumGenerator::~EnumGenerator() { +} + +void EnumGenerator::Generate(io::Printer* printer) { + WriteEnumDocComment(printer, descriptor_); + printer->Print("$access_level$ enum $name$ {\n", + "access_level", class_access_level(), + "name", descriptor_->name()); + printer->Indent(); + std::set<std::string> used_names; + std::set<int> used_number; + for (int i = 0; i < descriptor_->value_count(); i++) { + WriteEnumValueDocComment(printer, descriptor_->value(i)); + std::string original_name = descriptor_->value(i)->name(); + std::string name = + GetEnumValueName(descriptor_->name(), descriptor_->value(i)->name()); + // Make sure we don't get any duplicate names due to prefix removal. + while (!used_names.insert(name).second) { + // It's possible we'll end up giving this warning multiple times, but that's better than not at all. + GOOGLE_LOG(WARNING) << "Duplicate enum value " << name << " (originally " << original_name + << ") in " << descriptor_->name() << "; adding underscore to distinguish"; + name += "_"; + } + int number = descriptor_->value(i)->number(); + if (!used_number.insert(number).second) { + printer->Print("[pbr::OriginalName(\"$original_name$\", PreferredAlias = false)] $name$ = $number$,\n", + "original_name", original_name, + "name", name, + "number", StrCat(number)); + } else { + printer->Print("[pbr::OriginalName(\"$original_name$\")] $name$ = $number$,\n", + "original_name", original_name, + "name", name, + "number", StrCat(number)); + } + } + printer->Outdent(); + printer->Print("}\n"); + printer->Print("\n"); +} + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_enum.h b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_enum.h new file mode 100644 index 00000000..d589ae50 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_enum.h @@ -0,0 +1,66 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_ENUM_H__ +#define GOOGLE_PROTOBUF_COMPILER_CSHARP_ENUM_H__ + +#include <string> + +#include <compiler/code_generator.h> +#include <compiler/csharp/csharp_source_generator_base.h> +#include <descriptor.h> +#include <io/printer.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +class EnumGenerator : public SourceGeneratorBase { + public: + EnumGenerator(const EnumDescriptor* descriptor, const Options* options); + ~EnumGenerator(); + + EnumGenerator(const EnumGenerator&) = delete; + EnumGenerator& operator=(const EnumGenerator&) = delete; + + void Generate(io::Printer* printer); + + private: + const EnumDescriptor* descriptor_; +}; + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_ENUM_H__ + diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_enum_field.cc b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_enum_field.cc new file mode 100644 index 00000000..76a47674 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_enum_field.cc @@ -0,0 +1,135 @@ +// 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 <sstream> + +#include <compiler/code_generator.h> +#include <descriptor.h> +#include <descriptor.pb.h> +#include <io/printer.h> +#include <io/zero_copy_stream.h> + +#include <compiler/csharp/csharp_doc_comment.h> +#include <compiler/csharp/csharp_helpers.h> +#include <compiler/csharp/csharp_options.h> +#include <compiler/csharp/csharp_enum_field.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +EnumFieldGenerator::EnumFieldGenerator(const FieldDescriptor* descriptor, + int presenceIndex, const Options *options) + : PrimitiveFieldGenerator(descriptor, presenceIndex, options) { +} + +EnumFieldGenerator::~EnumFieldGenerator() { +} + +void EnumFieldGenerator::GenerateParsingCode(io::Printer* printer) { + printer->Print(variables_, + "$property_name$ = ($type_name$) input.ReadEnum();\n"); +} + +void EnumFieldGenerator::GenerateSerializationCode(io::Printer* printer) { + printer->Print(variables_, + "if ($has_property_check$) {\n" + " output.WriteRawTag($tag_bytes$);\n" + " output.WriteEnum((int) $property_name$);\n" + "}\n"); +} + +void EnumFieldGenerator::GenerateSerializedSizeCode(io::Printer* printer) { + printer->Print( + variables_, + "if ($has_property_check$) {\n" + " size += $tag_size$ + pb::CodedOutputStream.ComputeEnumSize((int) $property_name$);\n" + "}\n"); +} + +void EnumFieldGenerator::GenerateCodecCode(io::Printer* printer) { + printer->Print( + variables_, + "pb::FieldCodec.ForEnum($tag$, x => (int) x, x => ($type_name$) x, $default_value$)"); +} + +void EnumFieldGenerator::GenerateExtensionCode(io::Printer* printer) { + WritePropertyDocComment(printer, descriptor_); + AddDeprecatedFlag(printer); + printer->Print( + variables_, + "$access_level$ static readonly pb::Extension<$extended_type$, $type_name$> $property_name$ =\n" + " new pb::Extension<$extended_type$, $type_name$>($number$, "); + GenerateCodecCode(printer); + printer->Print(");\n"); +} + +EnumOneofFieldGenerator::EnumOneofFieldGenerator( + const FieldDescriptor* descriptor, int presenceIndex, const Options *options) + : PrimitiveOneofFieldGenerator(descriptor, presenceIndex, options) { +} + +EnumOneofFieldGenerator::~EnumOneofFieldGenerator() { +} + +void EnumOneofFieldGenerator::GenerateMergingCode(io::Printer* printer) { + printer->Print(variables_, "$property_name$ = other.$property_name$;\n"); +} + +void EnumOneofFieldGenerator::GenerateParsingCode(io::Printer* printer) { + // TODO(jonskeet): What about if we read the default value? + printer->Print( + variables_, + "$oneof_name$_ = input.ReadEnum();\n" + "$oneof_name$Case_ = $oneof_property_name$OneofCase.$property_name$;\n"); +} + +void EnumOneofFieldGenerator::GenerateSerializationCode(io::Printer* printer) { + printer->Print( + variables_, + "if ($has_property_check$) {\n" + " output.WriteRawTag($tag_bytes$);\n" + " output.WriteEnum((int) $property_name$);\n" + "}\n"); +} + +void EnumOneofFieldGenerator::GenerateSerializedSizeCode(io::Printer* printer) { + printer->Print( + variables_, + "if ($has_property_check$) {\n" + " size += $tag_size$ + pb::CodedOutputStream.ComputeEnumSize((int) $property_name$);\n" + "}\n"); +} + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_enum_field.h b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_enum_field.h new file mode 100644 index 00000000..791ff21a --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_enum_field.h @@ -0,0 +1,83 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_ENUM_FIELD_H__ +#define GOOGLE_PROTOBUF_COMPILER_CSHARP_ENUM_FIELD_H__ + +#include <string> + +#include <compiler/code_generator.h> +#include <compiler/csharp/csharp_primitive_field.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +class EnumFieldGenerator : public PrimitiveFieldGenerator { + public: + EnumFieldGenerator(const FieldDescriptor* descriptor, + int presenceIndex, + const Options *options); + ~EnumFieldGenerator(); + + EnumFieldGenerator(const EnumFieldGenerator&) = delete; + EnumFieldGenerator& operator=(const EnumFieldGenerator&) = delete; + + virtual void GenerateCodecCode(io::Printer* printer) override; + virtual void GenerateParsingCode(io::Printer* printer) override; + virtual void GenerateSerializationCode(io::Printer* printer) override; + virtual void GenerateSerializedSizeCode(io::Printer* printer) override; + virtual void GenerateExtensionCode(io::Printer* printer) override; +}; + +class EnumOneofFieldGenerator : public PrimitiveOneofFieldGenerator { + public: + EnumOneofFieldGenerator(const FieldDescriptor* descriptor, + int presenceIndex, + const Options *options); + ~EnumOneofFieldGenerator(); + + EnumOneofFieldGenerator(const EnumOneofFieldGenerator&) = delete; + EnumOneofFieldGenerator& operator=(const EnumOneofFieldGenerator&) = delete; + + virtual void GenerateMergingCode(io::Printer* printer) override; + virtual void GenerateParsingCode(io::Printer* printer) override; + virtual void GenerateSerializationCode(io::Printer* printer) override; + virtual void GenerateSerializedSizeCode(io::Printer* printer) override; +}; + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_ENUM_FIELD_H__ + diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_field_base.cc b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_field_base.cc new file mode 100644 index 00000000..52934b04 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_field_base.cc @@ -0,0 +1,459 @@ +// 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 <cmath> +#include <limits> +#include <sstream> + +#include <compiler/code_generator.h> +#include <descriptor.h> +#include <descriptor.pb.h> +#include <io/coded_stream.h> +#include <io/printer.h> +#include <io/zero_copy_stream.h> +#include <stubs/strutil.h> +#include <wire_format.h> + +#include <compiler/csharp/csharp_field_base.h> +#include <compiler/csharp/csharp_helpers.h> +#include <compiler/csharp/csharp_names.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +void FieldGeneratorBase::SetCommonFieldVariables( + std::map<std::string, std::string>* variables) { + // Note: this will be valid even though the tag emitted for packed and unpacked versions of + // repeated fields varies by wire format. The wire format is encoded in the bottom 3 bits, which + // never effects the tag size. + int tag_size = internal::WireFormat::TagSize(descriptor_->number(), descriptor_->type()); + int part_tag_size = tag_size; + if (descriptor_->type() == FieldDescriptor::TYPE_GROUP) { + part_tag_size /= 2; + } + uint tag = internal::WireFormat::MakeTag(descriptor_); + uint8 tag_array[5]; + io::CodedOutputStream::WriteTagToArray(tag, tag_array); + std::string tag_bytes = StrCat(tag_array[0]); + for (int i = 1; i < part_tag_size; i++) { + tag_bytes += ", " + StrCat(tag_array[i]); + } + + (*variables)["tag"] = StrCat(tag); + (*variables)["tag_size"] = StrCat(tag_size); + (*variables)["tag_bytes"] = tag_bytes; + + if (descriptor_->type() == FieldDescriptor::Type::TYPE_GROUP) { + tag = internal::WireFormatLite::MakeTag( + descriptor_->number(), + internal::WireFormatLite::WIRETYPE_END_GROUP); + io::CodedOutputStream::WriteTagToArray(tag, tag_array); + tag_bytes = StrCat(tag_array[0]); + for (int i = 1; i < part_tag_size; i++) { + tag_bytes += ", " + StrCat(tag_array[i]); + } + + variables_["end_tag"] = StrCat(tag); + variables_["end_tag_bytes"] = tag_bytes; + } + + (*variables)["access_level"] = "public"; + + (*variables)["property_name"] = property_name(); + (*variables)["type_name"] = type_name(); + (*variables)["extended_type"] = GetClassName(descriptor_->containing_type()); + (*variables)["name"] = name(); + (*variables)["descriptor_name"] = descriptor_->name(); + (*variables)["default_value"] = default_value(); + (*variables)["capitalized_type_name"] = capitalized_type_name(); + (*variables)["number"] = number(); + if (has_default_value() && !SupportsPresenceApi(descriptor_)) { + (*variables)["name_def_message"] = + (*variables)["name"] + "_ = " + (*variables)["default_value"]; + } else { + (*variables)["name_def_message"] = (*variables)["name"] + "_"; + } + if (SupportsPresenceApi(descriptor_)) { + (*variables)["has_property_check"] = "Has" + (*variables)["property_name"]; + (*variables)["other_has_property_check"] = "other.Has" + (*variables)["property_name"]; + (*variables)["has_not_property_check"] = "!" + (*variables)["has_property_check"]; + (*variables)["other_has_not_property_check"] = "!" + (*variables)["other_has_property_check"]; + if (presenceIndex_ != -1) { + std::string hasBitsNumber = StrCat(presenceIndex_ / 32); + std::string hasBitsMask = StrCat(1 << (presenceIndex_ % 32)); + (*variables)["has_field_check"] = "(_hasBits" + hasBitsNumber + " & " + hasBitsMask + ") != 0"; + (*variables)["set_has_field"] = "_hasBits" + hasBitsNumber + " |= " + hasBitsMask; + (*variables)["clear_has_field"] = "_hasBits" + hasBitsNumber + " &= ~" + hasBitsMask; + } + } else { + (*variables)["has_property_check"] = + (*variables)["property_name"] + " != " + (*variables)["default_value"]; + (*variables)["other_has_property_check"] = "other." + + (*variables)["property_name"] + " != " + (*variables)["default_value"]; + } +} + +void FieldGeneratorBase::SetCommonOneofFieldVariables( + std::map<std::string, std::string>* variables) { + (*variables)["oneof_name"] = oneof_name(); + if (SupportsPresenceApi(descriptor_)) { + (*variables)["has_property_check"] = "Has" + property_name(); + } else { + (*variables)["has_property_check"] = + oneof_name() + "Case_ == " + oneof_property_name() + + "OneofCase." + property_name(); + } + (*variables)["oneof_property_name"] = oneof_property_name(); +} + +FieldGeneratorBase::FieldGeneratorBase(const FieldDescriptor* descriptor, + int presenceIndex, const Options* options) + : SourceGeneratorBase(options), + descriptor_(descriptor), + presenceIndex_(presenceIndex) { + SetCommonFieldVariables(&variables_); +} + +FieldGeneratorBase::~FieldGeneratorBase() { +} + +void FieldGeneratorBase::GenerateFreezingCode(io::Printer* printer) { + // No-op: only message fields and repeated fields need + // special handling for freezing, so default to not generating any code. +} + +void FieldGeneratorBase::GenerateCodecCode(io::Printer* printer) { + // No-op: expect this to be overridden by appropriate types. + // Could fail if we get called here though... +} + +void FieldGeneratorBase::GenerateExtensionCode(io::Printer* printer) { + // No-op: only message fields, enum fields, primitives, + // and repeated fields need this default is to not generate any code +} + +void FieldGeneratorBase::GenerateParsingCode(io::Printer* printer, bool use_parse_context) { + // for some field types the value of "use_parse_context" doesn't matter, + // so we fallback to the default implementation. + GenerateParsingCode(printer); +} + +void FieldGeneratorBase::GenerateSerializationCode(io::Printer* printer, bool use_write_context) { + // for some field types the value of "use_write_context" doesn't matter, + // so we fallback to the default implementation. + GenerateSerializationCode(printer); +} + +void FieldGeneratorBase::AddDeprecatedFlag(io::Printer* printer) { + if (descriptor_->options().deprecated()) { + printer->Print("[global::System.ObsoleteAttribute]\n"); + } else if (descriptor_->type() == FieldDescriptor::TYPE_MESSAGE && + descriptor_->message_type()->options().deprecated()) { + printer->Print("[global::System.ObsoleteAttribute]\n"); + } +} + +void FieldGeneratorBase::AddPublicMemberAttributes(io::Printer* printer) { + AddDeprecatedFlag(printer); + WriteGeneratedCodeAttributes(printer); +} + +std::string FieldGeneratorBase::oneof_property_name() { + return UnderscoresToCamelCase(descriptor_->containing_oneof()->name(), true); +} + +std::string FieldGeneratorBase::oneof_name() { + return UnderscoresToCamelCase(descriptor_->containing_oneof()->name(), false); +} + +std::string FieldGeneratorBase::property_name() { + return GetPropertyName(descriptor_); +} + +std::string FieldGeneratorBase::name() { + return UnderscoresToCamelCase(GetFieldName(descriptor_), false); +} + +std::string FieldGeneratorBase::type_name() { + return type_name(descriptor_); +} + +std::string FieldGeneratorBase::type_name(const FieldDescriptor* descriptor) { + switch (descriptor->type()) { + case FieldDescriptor::TYPE_ENUM: + return GetClassName(descriptor->enum_type()); + case FieldDescriptor::TYPE_MESSAGE: + case FieldDescriptor::TYPE_GROUP: + if (IsWrapperType(descriptor)) { + const FieldDescriptor* wrapped_field = + descriptor->message_type()->field(0); + std::string wrapped_field_type_name = type_name(wrapped_field); + // String and ByteString go to the same type; other wrapped types + // go to the nullable equivalent. + if (wrapped_field->type() == FieldDescriptor::TYPE_STRING || + wrapped_field->type() == FieldDescriptor::TYPE_BYTES) { + return wrapped_field_type_name; + } else { + return wrapped_field_type_name + "?"; + } + } + return GetClassName(descriptor->message_type()); + case FieldDescriptor::TYPE_DOUBLE: + return "double"; + case FieldDescriptor::TYPE_FLOAT: + return "float"; + case FieldDescriptor::TYPE_INT64: + return "long"; + case FieldDescriptor::TYPE_UINT64: + return "ulong"; + case FieldDescriptor::TYPE_INT32: + return "int"; + case FieldDescriptor::TYPE_FIXED64: + return "ulong"; + case FieldDescriptor::TYPE_FIXED32: + return "uint"; + case FieldDescriptor::TYPE_BOOL: + return "bool"; + case FieldDescriptor::TYPE_STRING: + return "string"; + case FieldDescriptor::TYPE_BYTES: + return "pb::ByteString"; + case FieldDescriptor::TYPE_UINT32: + return "uint"; + case FieldDescriptor::TYPE_SFIXED32: + return "int"; + case FieldDescriptor::TYPE_SFIXED64: + return "long"; + case FieldDescriptor::TYPE_SINT32: + return "int"; + case FieldDescriptor::TYPE_SINT64: + return "long"; + default: + GOOGLE_LOG(FATAL)<< "Unknown field type."; + return ""; + } +} + +bool FieldGeneratorBase::has_default_value() { + switch (descriptor_->type()) { + case FieldDescriptor::TYPE_ENUM: + case FieldDescriptor::TYPE_MESSAGE: + case FieldDescriptor::TYPE_GROUP: + return true; + case FieldDescriptor::TYPE_DOUBLE: + return descriptor_->default_value_double() != 0.0; + case FieldDescriptor::TYPE_FLOAT: + return descriptor_->default_value_float() != 0.0; + case FieldDescriptor::TYPE_INT64: + return descriptor_->default_value_int64() != 0L; + case FieldDescriptor::TYPE_UINT64: + return descriptor_->default_value_uint64() != 0L; + case FieldDescriptor::TYPE_INT32: + return descriptor_->default_value_int32() != 0; + case FieldDescriptor::TYPE_FIXED64: + return descriptor_->default_value_uint64() != 0L; + case FieldDescriptor::TYPE_FIXED32: + return descriptor_->default_value_uint32() != 0; + case FieldDescriptor::TYPE_BOOL: + return descriptor_->default_value_bool(); + case FieldDescriptor::TYPE_STRING: + return true; + case FieldDescriptor::TYPE_BYTES: + return true; + case FieldDescriptor::TYPE_UINT32: + return descriptor_->default_value_uint32() != 0; + case FieldDescriptor::TYPE_SFIXED32: + return descriptor_->default_value_int32() != 0; + case FieldDescriptor::TYPE_SFIXED64: + return descriptor_->default_value_int64() != 0L; + case FieldDescriptor::TYPE_SINT32: + return descriptor_->default_value_int32() != 0; + case FieldDescriptor::TYPE_SINT64: + return descriptor_->default_value_int64() != 0L; + default: + GOOGLE_LOG(FATAL)<< "Unknown field type."; + return true; + } +} + +bool AllPrintableAscii(const std::string& text) { + for(int i = 0; i < text.size(); i++) { + if (text[i] < 0x20 || text[i] > 0x7e) { + return false; + } + } + return true; +} + +std::string FieldGeneratorBase::GetStringDefaultValueInternal(const FieldDescriptor* descriptor) { + if (descriptor->default_value_string().empty()) + return "\"\""; + else + return "global::System.Text.Encoding.UTF8.GetString(global::System." + "Convert.FromBase64String(\"" + + StringToBase64(descriptor->default_value_string()) + "\"), 0, " + StrCat(descriptor->default_value_string().length()) + ")"; +} + +std::string FieldGeneratorBase::GetBytesDefaultValueInternal(const FieldDescriptor* descriptor) { + if (descriptor->default_value_string().empty()) + return "pb::ByteString.Empty"; + else + return "pb::ByteString.FromBase64(\"" + StringToBase64(descriptor->default_value_string()) + "\")"; +} + +std::string FieldGeneratorBase::default_value() { + return default_value(descriptor_); +} + +std::string FieldGeneratorBase::default_value(const FieldDescriptor* descriptor) { + switch (descriptor->type()) { + case FieldDescriptor::TYPE_ENUM: + return GetClassName(descriptor->default_value_enum()->type()) + "." + + GetEnumValueName(descriptor->default_value_enum()->type()->name(), descriptor->default_value_enum()->name()); + case FieldDescriptor::TYPE_MESSAGE: + case FieldDescriptor::TYPE_GROUP: + if (IsWrapperType(descriptor)) { + const FieldDescriptor* wrapped_field = descriptor->message_type()->field(0); + return default_value(wrapped_field); + } else { + return "null"; + } + case FieldDescriptor::TYPE_DOUBLE: { + double value = descriptor->default_value_double(); + if (value == std::numeric_limits<double>::infinity()) { + return "double.PositiveInfinity"; + } else if (value == -std::numeric_limits<double>::infinity()) { + return "double.NegativeInfinity"; + } else if (std::isnan(value)) { + return "double.NaN"; + } + return StrCat(value) + "D"; + } + case FieldDescriptor::TYPE_FLOAT: { + float value = descriptor->default_value_float(); + if (value == std::numeric_limits<float>::infinity()) { + return "float.PositiveInfinity"; + } else if (value == -std::numeric_limits<float>::infinity()) { + return "float.NegativeInfinity"; + } else if (std::isnan(value)) { + return "float.NaN"; + } + return StrCat(value) + "F"; + } + case FieldDescriptor::TYPE_INT64: + return StrCat(descriptor->default_value_int64()) + "L"; + case FieldDescriptor::TYPE_UINT64: + return StrCat(descriptor->default_value_uint64()) + "UL"; + case FieldDescriptor::TYPE_INT32: + return StrCat(descriptor->default_value_int32()); + case FieldDescriptor::TYPE_FIXED64: + return StrCat(descriptor->default_value_uint64()) + "UL"; + case FieldDescriptor::TYPE_FIXED32: + return StrCat(descriptor->default_value_uint32()); + case FieldDescriptor::TYPE_BOOL: + if (descriptor->default_value_bool()) { + return "true"; + } else { + return "false"; + } + case FieldDescriptor::TYPE_STRING: + return GetStringDefaultValueInternal(descriptor); + case FieldDescriptor::TYPE_BYTES: + return GetBytesDefaultValueInternal(descriptor); + case FieldDescriptor::TYPE_UINT32: + return StrCat(descriptor->default_value_uint32()); + case FieldDescriptor::TYPE_SFIXED32: + return StrCat(descriptor->default_value_int32()); + case FieldDescriptor::TYPE_SFIXED64: + return StrCat(descriptor->default_value_int64()) + "L"; + case FieldDescriptor::TYPE_SINT32: + return StrCat(descriptor->default_value_int32()); + case FieldDescriptor::TYPE_SINT64: + return StrCat(descriptor->default_value_int64()) + "L"; + default: + GOOGLE_LOG(FATAL)<< "Unknown field type."; + return ""; + } +} + +std::string FieldGeneratorBase::number() { + return StrCat(descriptor_->number()); +} + +std::string FieldGeneratorBase::capitalized_type_name() { + switch (descriptor_->type()) { + case FieldDescriptor::TYPE_ENUM: + return "Enum"; + case FieldDescriptor::TYPE_MESSAGE: + return "Message"; + case FieldDescriptor::TYPE_GROUP: + return "Group"; + case FieldDescriptor::TYPE_DOUBLE: + return "Double"; + case FieldDescriptor::TYPE_FLOAT: + return "Float"; + case FieldDescriptor::TYPE_INT64: + return "Int64"; + case FieldDescriptor::TYPE_UINT64: + return "UInt64"; + case FieldDescriptor::TYPE_INT32: + return "Int32"; + case FieldDescriptor::TYPE_FIXED64: + return "Fixed64"; + case FieldDescriptor::TYPE_FIXED32: + return "Fixed32"; + case FieldDescriptor::TYPE_BOOL: + return "Bool"; + case FieldDescriptor::TYPE_STRING: + return "String"; + case FieldDescriptor::TYPE_BYTES: + return "Bytes"; + case FieldDescriptor::TYPE_UINT32: + return "UInt32"; + case FieldDescriptor::TYPE_SFIXED32: + return "SFixed32"; + case FieldDescriptor::TYPE_SFIXED64: + return "SFixed64"; + case FieldDescriptor::TYPE_SINT32: + return "SInt32"; + case FieldDescriptor::TYPE_SINT64: + return "SInt64"; + default: + GOOGLE_LOG(FATAL)<< "Unknown field type."; + return ""; + } +} + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_field_base.h b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_field_base.h new file mode 100644 index 00000000..f0221b6c --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_field_base.h @@ -0,0 +1,111 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_FIELD_BASE_H__ +#define GOOGLE_PROTOBUF_COMPILER_CSHARP_FIELD_BASE_H__ + +#include <string> +#include <stubs/strutil.h> + +#include <compiler/code_generator.h> +#include <compiler/csharp/csharp_source_generator_base.h> +#include <descriptor.h> +#include <io/printer.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +class FieldGeneratorBase : public SourceGeneratorBase { + public: + FieldGeneratorBase(const FieldDescriptor* descriptor, + int presenceIndex, + const Options* options); + ~FieldGeneratorBase(); + + FieldGeneratorBase(const FieldGeneratorBase&) = delete; + FieldGeneratorBase& operator=(const FieldGeneratorBase&) = delete; + + virtual void GenerateCloningCode(io::Printer* printer) = 0; + virtual void GenerateFreezingCode(io::Printer* printer); + virtual void GenerateCodecCode(io::Printer* printer); + virtual void GenerateExtensionCode(io::Printer* printer); + virtual void GenerateMembers(io::Printer* printer) = 0; + virtual void GenerateMergingCode(io::Printer* printer) = 0; + virtual void GenerateParsingCode(io::Printer* printer) = 0; + virtual void GenerateParsingCode(io::Printer* printer, bool use_parse_context); + virtual void GenerateSerializationCode(io::Printer* printer) = 0; + virtual void GenerateSerializationCode(io::Printer* printer, bool use_write_context); + virtual void GenerateSerializedSizeCode(io::Printer* printer) = 0; + + virtual void WriteHash(io::Printer* printer) = 0; + virtual void WriteEquals(io::Printer* printer) = 0; + // Currently unused, as we use reflection to generate JSON + virtual void WriteToString(io::Printer* printer) = 0; + + protected: + const FieldDescriptor* descriptor_; + const int presenceIndex_; + std::map<std::string, std::string> variables_; + + void AddDeprecatedFlag(io::Printer* printer); + void AddNullCheck(io::Printer* printer); + void AddNullCheck(io::Printer* printer, const std::string& name); + + void AddPublicMemberAttributes(io::Printer* printer); + void SetCommonOneofFieldVariables( + std::map<std::string, std::string>* variables); + + std::string oneof_property_name(); + std::string oneof_name(); + std::string property_name(); + std::string name(); + std::string type_name(); + std::string type_name(const FieldDescriptor* descriptor); + bool has_default_value(); + std::string default_value(); + std::string default_value(const FieldDescriptor* descriptor); + std::string number(); + std::string capitalized_type_name(); + + private: + void SetCommonFieldVariables(std::map<std::string, std::string>* variables); + std::string GetStringDefaultValueInternal(const FieldDescriptor* descriptor); + std::string GetBytesDefaultValueInternal(const FieldDescriptor* descriptor); +}; + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_FIELD_BASE_H__ + diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_generator.cc b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_generator.cc new file mode 100644 index 00000000..ded055fb --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_generator.cc @@ -0,0 +1,112 @@ +// 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 <sstream> + +#include <compiler/code_generator.h> +#include <descriptor.h> +#include <descriptor.pb.h> +#include <io/printer.h> +#include <io/zero_copy_stream.h> +#include <stubs/strutil.h> + +#include <compiler/csharp/csharp_generator.h> +#include <compiler/csharp/csharp_helpers.h> +#include <compiler/csharp/csharp_names.h> +#include <compiler/csharp/csharp_options.h> +#include <compiler/csharp/csharp_reflection_class.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +Generator::Generator() {} +Generator::~Generator() {} + +uint64_t Generator::GetSupportedFeatures() const { + return CodeGenerator::Feature::FEATURE_PROTO3_OPTIONAL; +} + +void GenerateFile(const FileDescriptor* file, io::Printer* printer, + const Options* options) { + ReflectionClassGenerator reflectionClassGenerator(file, options); + reflectionClassGenerator.Generate(printer); +} + +bool Generator::Generate(const FileDescriptor* file, + const std::string& parameter, + GeneratorContext* generator_context, + std::string* error) const { + std::vector<std::pair<std::string, std::string> > options; + ParseGeneratorParameter(parameter, &options); + + struct Options cli_options; + + for (int i = 0; i < options.size(); i++) { + if (options[i].first == "file_extension") { + cli_options.file_extension = options[i].second; + } else if (options[i].first == "base_namespace") { + cli_options.base_namespace = options[i].second; + cli_options.base_namespace_specified = true; + } else if (options[i].first == "internal_access") { + cli_options.internal_access = true; + } else if (options[i].first == "serializable") { + cli_options.serializable = true; + } else { + *error = "Unknown generator option: " + options[i].first; + return false; + } + } + + std::string filename_error = ""; + std::string filename = GetOutputFile(file, + cli_options.file_extension, + cli_options.base_namespace_specified, + cli_options.base_namespace, + &filename_error); + + if (filename.empty()) { + *error = filename_error; + return false; + } + std::unique_ptr<io::ZeroCopyOutputStream> output( + generator_context->Open(filename)); + io::Printer printer(output.get(), '$'); + + GenerateFile(file, &printer, &cli_options); + + return true; +} + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_generator.h b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_generator.h new file mode 100644 index 00000000..6f030cb2 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_generator.h @@ -0,0 +1,70 @@ +// 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. + +// Generates C# code for a given .proto file. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_GENERATOR_H__ +#define GOOGLE_PROTOBUF_COMPILER_CSHARP_GENERATOR_H__ + +#include <string> + +#include <compiler/code_generator.h> + +#include <port_def.inc> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +// CodeGenerator implementation which generates a C# source file and +// header. If you create your own protocol compiler binary and you want +// it to support C# output, you can do so by registering an instance of this +// CodeGenerator with the CommandLineInterface in your main() function. +class PROTOC_EXPORT Generator : public CodeGenerator { + public: + Generator(); + ~Generator(); + bool Generate( + const FileDescriptor* file, + const std::string& parameter, + GeneratorContext* generator_context, + std::string* error) const override; + uint64_t GetSupportedFeatures() const override; +}; + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#include <port_undef.inc> + +#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_GENERATOR_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_generator_unittest.cc b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_generator_unittest.cc new file mode 100644 index 00000000..c03f8855 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_generator_unittest.cc @@ -0,0 +1,70 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2014 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 <memory> + +#include <compiler/command_line_interface.h> +#include <compiler/csharp/csharp_helpers.h> +#include <io/zero_copy_stream.h> +#include <io/printer.h> + +#include <testing/googletest.h> +#include <gtest/gtest.h> +#include <testing/file.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { +namespace { + +TEST(CSharpEnumValue, PascalCasedPrefixStripping) { + EXPECT_EQ("Bar", GetEnumValueName("Foo", "BAR")); + EXPECT_EQ("BarBaz", GetEnumValueName("Foo", "BAR_BAZ")); + EXPECT_EQ("Bar", GetEnumValueName("Foo", "FOO_BAR")); + EXPECT_EQ("Bar", GetEnumValueName("Foo", "FOO__BAR")); + EXPECT_EQ("BarBaz", GetEnumValueName("Foo", "FOO_BAR_BAZ")); + EXPECT_EQ("BarBaz", GetEnumValueName("Foo", "Foo_BarBaz")); + EXPECT_EQ("Bar", GetEnumValueName("FO_O", "FOO_BAR")); + EXPECT_EQ("Bar", GetEnumValueName("FOO", "F_O_O_BAR")); + EXPECT_EQ("Bar", GetEnumValueName("Foo", "BAR")); + EXPECT_EQ("BarBaz", GetEnumValueName("Foo", "BAR_BAZ")); + EXPECT_EQ("Foo", GetEnumValueName("Foo", "FOO")); + EXPECT_EQ("Foo", GetEnumValueName("Foo", "FOO___")); + // Identifiers can't start with digits + EXPECT_EQ("_2Bar", GetEnumValueName("Foo", "FOO_2_BAR")); + EXPECT_EQ("_2", GetEnumValueName("Foo", "FOO___2")); +} + +} // namespace +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_helpers.cc b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_helpers.cc new file mode 100644 index 00000000..b703187d --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_helpers.cc @@ -0,0 +1,592 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <algorithm> +#include <limits> +#include <vector> +#include <sstream> + +#include <compiler/csharp/csharp_helpers.h> +#include <compiler/csharp/csharp_names.h> +#include <descriptor.pb.h> +#include <io/printer.h> +#include <wire_format.h> +#include <stubs/strutil.h> + +#include <compiler/csharp/csharp_field_base.h> +#include <compiler/csharp/csharp_enum_field.h> +#include <compiler/csharp/csharp_map_field.h> +#include <compiler/csharp/csharp_message_field.h> +#include <compiler/csharp/csharp_options.h> +#include <compiler/csharp/csharp_primitive_field.h> +#include <compiler/csharp/csharp_repeated_enum_field.h> +#include <compiler/csharp/csharp_repeated_message_field.h> +#include <compiler/csharp/csharp_repeated_primitive_field.h> +#include <compiler/csharp/csharp_wrapper_field.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +CSharpType GetCSharpType(FieldDescriptor::Type type) { + switch (type) { + case FieldDescriptor::TYPE_INT32: + return CSHARPTYPE_INT32; + case FieldDescriptor::TYPE_INT64: + return CSHARPTYPE_INT64; + case FieldDescriptor::TYPE_UINT32: + return CSHARPTYPE_UINT32; + case FieldDescriptor::TYPE_UINT64: + return CSHARPTYPE_UINT32; + case FieldDescriptor::TYPE_SINT32: + return CSHARPTYPE_INT32; + case FieldDescriptor::TYPE_SINT64: + return CSHARPTYPE_INT64; + case FieldDescriptor::TYPE_FIXED32: + return CSHARPTYPE_UINT32; + case FieldDescriptor::TYPE_FIXED64: + return CSHARPTYPE_UINT64; + case FieldDescriptor::TYPE_SFIXED32: + return CSHARPTYPE_INT32; + case FieldDescriptor::TYPE_SFIXED64: + return CSHARPTYPE_INT64; + case FieldDescriptor::TYPE_FLOAT: + return CSHARPTYPE_FLOAT; + case FieldDescriptor::TYPE_DOUBLE: + return CSHARPTYPE_DOUBLE; + case FieldDescriptor::TYPE_BOOL: + return CSHARPTYPE_BOOL; + case FieldDescriptor::TYPE_ENUM: + return CSHARPTYPE_ENUM; + case FieldDescriptor::TYPE_STRING: + return CSHARPTYPE_STRING; + case FieldDescriptor::TYPE_BYTES: + return CSHARPTYPE_BYTESTRING; + case FieldDescriptor::TYPE_GROUP: + return CSHARPTYPE_MESSAGE; + case FieldDescriptor::TYPE_MESSAGE: + return CSHARPTYPE_MESSAGE; + + // No default because we want the compiler to complain if any new + // types are added. + } + GOOGLE_LOG(FATAL)<< "Can't get here."; + return (CSharpType) -1; +} + +std::string StripDotProto(const std::string& proto_file) { + int lastindex = proto_file.find_last_of("."); + return proto_file.substr(0, lastindex); +} + +std::string GetFileNamespace(const FileDescriptor* descriptor) { + if (descriptor->options().has_csharp_namespace()) { + return descriptor->options().csharp_namespace(); + } + return UnderscoresToCamelCase(descriptor->package(), true, true); +} + +// Returns the Pascal-cased last part of the proto file. For example, +// input of "google/protobuf/foo_bar.proto" would result in "FooBar". +std::string GetFileNameBase(const FileDescriptor* descriptor) { + std::string proto_file = descriptor->name(); + int lastslash = proto_file.find_last_of("/"); + std::string base = proto_file.substr(lastslash + 1); + return UnderscoresToPascalCase(StripDotProto(base)); +} + +std::string GetReflectionClassUnqualifiedName(const FileDescriptor* descriptor) { + // TODO: Detect collisions with existing messages, + // and append an underscore if necessary. + return GetFileNameBase(descriptor) + "Reflection"; +} + +std::string GetExtensionClassUnqualifiedName(const FileDescriptor* descriptor) { + // TODO: Detect collisions with existing messages, + // and append an underscore if necessary. + return GetFileNameBase(descriptor) + "Extensions"; +} + +// TODO(jtattermusch): can we reuse a utility function? +std::string UnderscoresToCamelCase(const std::string& input, + bool cap_next_letter, + bool preserve_period) { + 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; + if (input[i] == '.' && preserve_period) { + result += '.'; + } + } + } + // Add a trailing "_" if the name should be altered. + if (input.size() > 0 && input[input.size() - 1] == '#') { + result += '_'; + } + return result; +} + +std::string UnderscoresToPascalCase(const std::string& input) { + return UnderscoresToCamelCase(input, true); +} + +// Convert a string which is expected to be SHOUTY_CASE (but may not be *precisely* shouty) +// into a PascalCase string. Precise rules implemented: + +// Previous input character Current character Case +// Any Non-alphanumeric Skipped +// None - first char of input Alphanumeric Upper +// Non-letter (e.g. _ or 1) Alphanumeric Upper +// Numeric Alphanumeric Upper +// Lower letter Alphanumeric Same as current +// Upper letter Alphanumeric Lower +std::string ShoutyToPascalCase(const std::string& input) { + std::string result; + // Simple way of implementing "always start with upper" + char previous = '_'; + for (int i = 0; i < input.size(); i++) { + char current = input[i]; + if (!ascii_isalnum(current)) { + previous = current; + continue; + } + if (!ascii_isalnum(previous)) { + result += ascii_toupper(current); + } else if (ascii_isdigit(previous)) { + result += ascii_toupper(current); + } else if (ascii_islower(previous)) { + result += current; + } else { + result += ascii_tolower(current); + } + previous = current; + } + return result; +} + +// Attempt to remove a prefix from a value, ignoring casing and skipping underscores. +// (foo, foo_bar) => bar - underscore after prefix is skipped +// (FOO, foo_bar) => bar - casing is ignored +// (foo_bar, foobarbaz) => baz - underscore in prefix is ignored +// (foobar, foo_barbaz) => baz - underscore in value is ignored +// (foo, bar) => bar - prefix isn't matched; return original value +std::string TryRemovePrefix(const std::string& prefix, const std::string& value) { + // First normalize to a lower-case no-underscores prefix to match against + std::string prefix_to_match = ""; + for (size_t i = 0; i < prefix.size(); i++) { + if (prefix[i] != '_') { + prefix_to_match += ascii_tolower(prefix[i]); + } + } + + // This keeps track of how much of value we've consumed + size_t prefix_index, value_index; + for (prefix_index = 0, value_index = 0; + prefix_index < prefix_to_match.size() && value_index < value.size(); + value_index++) { + // Skip over underscores in the value + if (value[value_index] == '_') { + continue; + } + if (ascii_tolower(value[value_index]) != prefix_to_match[prefix_index++]) { + // Failed to match the prefix - bail out early. + return value; + } + } + + // If we didn't finish looking through the prefix, we can't strip it. + if (prefix_index < prefix_to_match.size()) { + return value; + } + + // Step over any underscores after the prefix + while (value_index < value.size() && value[value_index] == '_') { + value_index++; + } + + // If there's nothing left (e.g. it was a prefix with only underscores afterwards), don't strip. + if (value_index == value.size()) { + return value; + } + + return value.substr(value_index); +} + +// Format the enum value name in a pleasant way for C#: +// - Strip the enum name as a prefix if possible +// - Convert to PascalCase. +// For example, an enum called Color with a value of COLOR_BLUE should +// result in an enum value in C# called just Blue +std::string GetEnumValueName(const std::string& enum_name, const std::string& enum_value_name) { + std::string stripped = TryRemovePrefix(enum_name, enum_value_name); + std::string result = ShoutyToPascalCase(stripped); + // Just in case we have an enum name of FOO and a value of FOO_2... make sure the returned + // string is a valid identifier. + if (ascii_isdigit(result[0])) { + result = "_" + result; + } + return result; +} + +uint GetGroupEndTag(const Descriptor* descriptor) { + const Descriptor* containing_type = descriptor->containing_type(); + if (containing_type != NULL) { + const FieldDescriptor* field; + for (int i = 0; i < containing_type->field_count(); i++) { + field = containing_type->field(i); + if (field->type() == FieldDescriptor::Type::TYPE_GROUP && + field->message_type() == descriptor) { + return internal::WireFormatLite::MakeTag( + field->number(), internal::WireFormatLite::WIRETYPE_END_GROUP); + } + } + for (int i = 0; i < containing_type->extension_count(); i++) { + field = containing_type->extension(i); + if (field->type() == FieldDescriptor::Type::TYPE_GROUP && + field->message_type() == descriptor) { + return internal::WireFormatLite::MakeTag( + field->number(), internal::WireFormatLite::WIRETYPE_END_GROUP); + } + } + } else { + const FileDescriptor* containing_file = descriptor->file(); + if (containing_file != NULL) { + const FieldDescriptor* field; + for (int i = 0; i < containing_file->extension_count(); i++) { + field = containing_file->extension(i); + if (field->type() == FieldDescriptor::Type::TYPE_GROUP && + field->message_type() == descriptor) { + return internal::WireFormatLite::MakeTag( + field->number(), internal::WireFormatLite::WIRETYPE_END_GROUP); + } + } + } + } + + return 0; +} + +std::string ToCSharpName(const std::string& name, const FileDescriptor* file) { + std::string result = GetFileNamespace(file); + if (!result.empty()) { + result += '.'; + } + std::string classname; + if (file->package().empty()) { + classname = name; + } else { + // Strip the proto package from full_name since we've replaced it with + // the C# namespace. + classname = name.substr(file->package().size() + 1); + } + result += StringReplace(classname, ".", ".Types.", true); + return "global::" + result; +} + +std::string GetReflectionClassName(const FileDescriptor* descriptor) { + std::string result = GetFileNamespace(descriptor); + if (!result.empty()) { + result += '.'; + } + result += GetReflectionClassUnqualifiedName(descriptor); + return "global::" + result; +} + +std::string GetFullExtensionName(const FieldDescriptor* descriptor) { + if (descriptor->extension_scope()) { + return GetClassName(descriptor->extension_scope()) + ".Extensions." + GetPropertyName(descriptor); + } + else { + return GetExtensionClassUnqualifiedName(descriptor->file()) + "." + GetPropertyName(descriptor); + } +} + +std::string GetClassName(const Descriptor* descriptor) { + return ToCSharpName(descriptor->full_name(), descriptor->file()); +} + +std::string GetClassName(const EnumDescriptor* descriptor) { + return ToCSharpName(descriptor->full_name(), descriptor->file()); +} + +// Groups are hacky: The name of the field is just the lower-cased name +// of the group type. In C#, though, we would like to retain the original +// capitalization of the type name. +std::string GetFieldName(const FieldDescriptor* descriptor) { + if (descriptor->type() == FieldDescriptor::TYPE_GROUP) { + return descriptor->message_type()->name(); + } else { + return descriptor->name(); + } +} + +std::string GetFieldConstantName(const FieldDescriptor* field) { + return GetPropertyName(field) + "FieldNumber"; +} + +std::string GetPropertyName(const FieldDescriptor* descriptor) { + // TODO(jtattermusch): consider introducing csharp_property_name field option + std::string property_name = UnderscoresToPascalCase(GetFieldName(descriptor)); + // Avoid either our own type name or reserved names. Note that not all names + // are reserved - a field called to_string, write_to etc would still cause a problem. + // There are various ways of ending up with naming collisions, but we try to avoid obvious + // ones. + if (property_name == descriptor->containing_type()->name() + || property_name == "Types" + || property_name == "Descriptor") { + property_name += "_"; + } + return property_name; +} + +std::string GetOutputFile(const FileDescriptor* descriptor, + const std::string file_extension, + const bool generate_directories, + const std::string base_namespace, + std::string* error) { + std::string relative_filename = GetFileNameBase(descriptor) + file_extension; + if (!generate_directories) { + return relative_filename; + } + std::string ns = GetFileNamespace(descriptor); + std::string namespace_suffix = ns; + if (!base_namespace.empty()) { + // Check that the base_namespace is either equal to or a leading part of + // the file namespace. This isn't just a simple prefix; "Foo.B" shouldn't + // be regarded as a prefix of "Foo.Bar". The simplest option is to add "." + // to both. + std::string extended_ns = ns + "."; + if (extended_ns.find(base_namespace + ".") != 0) { + *error = "Namespace " + ns + " is not a prefix namespace of base namespace " + base_namespace; + return ""; // This will be ignored, because we've set an error. + } + namespace_suffix = ns.substr(base_namespace.length()); + if (namespace_suffix.find(".") == 0) { + namespace_suffix = namespace_suffix.substr(1); + } + } + + std::string namespace_dir = StringReplace(namespace_suffix, ".", "/", true); + if (!namespace_dir.empty()) { + namespace_dir += "/"; + } + return namespace_dir + relative_filename; +} + +// TODO: c&p from Java protoc plugin +// For encodings with fixed sizes, returns that size in bytes. Otherwise +// returns -1. +int GetFixedSize(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 internal::WireFormatLite::kFixed32Size; + case FieldDescriptor::TYPE_FIXED64 : return internal::WireFormatLite::kFixed64Size; + case FieldDescriptor::TYPE_SFIXED32: return internal::WireFormatLite::kSFixed32Size; + case FieldDescriptor::TYPE_SFIXED64: return internal::WireFormatLite::kSFixed64Size; + case FieldDescriptor::TYPE_FLOAT : return internal::WireFormatLite::kFloatSize; + case FieldDescriptor::TYPE_DOUBLE : return internal::WireFormatLite::kDoubleSize; + + case FieldDescriptor::TYPE_BOOL : return internal::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. + } + GOOGLE_LOG(FATAL) << "Can't get here."; + return -1; +} + +static const char base64_chars[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +std::string StringToBase64(const std::string& input) { + std::string result; + size_t remaining = input.size(); + const unsigned char *src = (const unsigned char*) input.c_str(); + while (remaining > 2) { + result += base64_chars[src[0] >> 2]; + result += base64_chars[((src[0] & 0x3) << 4) | (src[1] >> 4)]; + result += base64_chars[((src[1] & 0xf) << 2) | (src[2] >> 6)]; + result += base64_chars[src[2] & 0x3f]; + remaining -= 3; + src += 3; + } + switch (remaining) { + case 2: + result += base64_chars[src[0] >> 2]; + result += base64_chars[((src[0] & 0x3) << 4) | (src[1] >> 4)]; + result += base64_chars[(src[1] & 0xf) << 2]; + result += '='; + src += 2; + break; + case 1: + result += base64_chars[src[0] >> 2]; + result += base64_chars[((src[0] & 0x3) << 4)]; + result += '='; + result += '='; + src += 1; + break; + } + return result; +} + +std::string FileDescriptorToBase64(const FileDescriptor* descriptor) { + std::string fdp_bytes; + FileDescriptorProto fdp; + descriptor->CopyTo(&fdp); + fdp.SerializeToString(&fdp_bytes); + return StringToBase64(fdp_bytes); +} + +FieldGeneratorBase* CreateFieldGenerator(const FieldDescriptor* descriptor, + int presenceIndex, + const Options* options) { + switch (descriptor->type()) { + case FieldDescriptor::TYPE_GROUP: + case FieldDescriptor::TYPE_MESSAGE: + if (descriptor->is_repeated()) { + if (descriptor->is_map()) { + return new MapFieldGenerator(descriptor, presenceIndex, options); + } else { + return new RepeatedMessageFieldGenerator(descriptor, presenceIndex, options); + } + } else { + if (IsWrapperType(descriptor)) { + if (descriptor->real_containing_oneof()) { + return new WrapperOneofFieldGenerator(descriptor, presenceIndex, options); + } else { + return new WrapperFieldGenerator(descriptor, presenceIndex, options); + } + } else { + if (descriptor->real_containing_oneof()) { + return new MessageOneofFieldGenerator(descriptor, presenceIndex, options); + } else { + return new MessageFieldGenerator(descriptor, presenceIndex, options); + } + } + } + case FieldDescriptor::TYPE_ENUM: + if (descriptor->is_repeated()) { + return new RepeatedEnumFieldGenerator(descriptor, presenceIndex, options); + } else { + if (descriptor->real_containing_oneof()) { + return new EnumOneofFieldGenerator(descriptor, presenceIndex, options); + } else { + return new EnumFieldGenerator(descriptor, presenceIndex, options); + } + } + default: + if (descriptor->is_repeated()) { + return new RepeatedPrimitiveFieldGenerator(descriptor, presenceIndex, options); + } else { + if (descriptor->real_containing_oneof()) { + return new PrimitiveOneofFieldGenerator(descriptor, presenceIndex, options); + } else { + return new PrimitiveFieldGenerator(descriptor, presenceIndex, options); + } + } + } +} + +bool IsNullable(const FieldDescriptor* descriptor) { + if (descriptor->is_repeated()) { + return true; + } + + switch (descriptor->type()) { + case FieldDescriptor::TYPE_ENUM: + case FieldDescriptor::TYPE_DOUBLE: + case FieldDescriptor::TYPE_FLOAT: + case FieldDescriptor::TYPE_INT64: + case FieldDescriptor::TYPE_UINT64: + case FieldDescriptor::TYPE_INT32: + case FieldDescriptor::TYPE_FIXED64: + case FieldDescriptor::TYPE_FIXED32: + case FieldDescriptor::TYPE_BOOL: + case FieldDescriptor::TYPE_UINT32: + case FieldDescriptor::TYPE_SFIXED32: + case FieldDescriptor::TYPE_SFIXED64: + case FieldDescriptor::TYPE_SINT32: + case FieldDescriptor::TYPE_SINT64: + return false; + + case FieldDescriptor::TYPE_MESSAGE: + case FieldDescriptor::TYPE_GROUP: + case FieldDescriptor::TYPE_STRING: + case FieldDescriptor::TYPE_BYTES: + return true; + + default: + GOOGLE_LOG(FATAL) << "Unknown field type."; + return true; + } +} + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_helpers.h b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_helpers.h new file mode 100644 index 00000000..74d97152 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_helpers.h @@ -0,0 +1,195 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_HELPERS_H__ +#define GOOGLE_PROTOBUF_COMPILER_CSHARP_HELPERS_H__ + +#include <string> +#include <port.h> +#include <stubs/common.h> +#include <descriptor.pb.h> +#include <descriptor.h> +#include <compiler/code_generator.h> +#include <io/printer.h> + +#include <port_def.inc> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +struct Options; +class FieldGeneratorBase; + +// TODO: start using this enum. +enum CSharpType { + CSHARPTYPE_INT32 = 1, + CSHARPTYPE_INT64 = 2, + CSHARPTYPE_UINT32 = 3, + CSHARPTYPE_UINT64 = 4, + CSHARPTYPE_FLOAT = 5, + CSHARPTYPE_DOUBLE = 6, + CSHARPTYPE_BOOL = 7, + CSHARPTYPE_STRING = 8, + CSHARPTYPE_BYTESTRING = 9, + CSHARPTYPE_MESSAGE = 10, + CSHARPTYPE_ENUM = 11, + MAX_CSHARPTYPE = 11 +}; + +// Converts field type to corresponding C# type. +CSharpType GetCSharpType(FieldDescriptor::Type type); + +std::string StripDotProto(const std::string& proto_file); + +// Gets unqualified name of the reflection class +std::string GetReflectionClassUnqualifiedName(const FileDescriptor* descriptor); +// Gets unqualified name of the extension class +std::string GetExtensionClassUnqualifiedName(const FileDescriptor* descriptor); + +std::string GetClassName(const EnumDescriptor* descriptor); + +std::string GetFieldName(const FieldDescriptor* descriptor); + +std::string GetFieldConstantName(const FieldDescriptor* field); + +std::string GetPropertyName(const FieldDescriptor* descriptor); + +int GetFixedSize(FieldDescriptor::Type type); + +std::string UnderscoresToCamelCase(const std::string& input, + bool cap_next_letter, + bool preserve_period); + +inline std::string UnderscoresToCamelCase(const std::string& input, bool cap_next_letter) { + return UnderscoresToCamelCase(input, cap_next_letter, false); +} + +std::string UnderscoresToPascalCase(const std::string& input); + +// Note that we wouldn't normally want to export this (we're not expecting +// it to be used outside libprotoc itself) but this exposes it for testing. +std::string PROTOC_EXPORT GetEnumValueName(const std::string& enum_name, + const std::string& enum_value_name); + +// TODO(jtattermusch): perhaps we could move this to strutil +std::string StringToBase64(const std::string& input); + +std::string FileDescriptorToBase64(const FileDescriptor* descriptor); + +FieldGeneratorBase* CreateFieldGenerator(const FieldDescriptor* descriptor, + int presenceIndex, + const Options* options); + +std::string GetFullExtensionName(const FieldDescriptor* descriptor); + +bool IsNullable(const FieldDescriptor* descriptor); + +// Determines whether the given message is a map entry message, +// i.e. one implicitly created by protoc due to a map<key, value> field. +inline bool IsMapEntryMessage(const Descriptor* descriptor) { + return descriptor->options().map_entry(); +} + +// Checks if this descriptor is for a group and gets its end tag or 0 if it's not a group +uint GetGroupEndTag(const Descriptor* descriptor); + +// Determines whether we're generating code for the proto representation of +// descriptors etc, for use in the runtime. This is the only type which is +// allowed to use proto2 syntax, and it generates internal classes. +inline bool IsDescriptorProto(const FileDescriptor* descriptor) { + return descriptor->name() == "google/protobuf/descriptor.proto"; +} + +// Determines whether the given message is an options message within descriptor.proto. +inline bool IsDescriptorOptionMessage(const Descriptor* descriptor) { + if (!IsDescriptorProto(descriptor->file())) { + return false; + } + const std::string name = descriptor->full_name(); + return name == "google.protobuf.FileOptions" || + name == "google.protobuf.MessageOptions" || + name == "google.protobuf.FieldOptions" || + name == "google.protobuf.OneofOptions" || + name == "google.protobuf.EnumOptions" || + name == "google.protobuf.EnumValueOptions" || + name == "google.protobuf.ServiceOptions" || + name == "google.protobuf.MethodOptions"; +} + +inline bool IsWrapperType(const FieldDescriptor* descriptor) { + return descriptor->type() == FieldDescriptor::TYPE_MESSAGE && + descriptor->message_type()->file()->name() == "google/protobuf/wrappers.proto"; +} + +inline bool IsProto2(const FileDescriptor* descriptor) { + return descriptor->syntax() == FileDescriptor::SYNTAX_PROTO2; +} + +inline bool SupportsPresenceApi(const FieldDescriptor* descriptor) { + // Unlike most languages, we don't generate Has/Clear members for message + // types, because they can always be set to null in C#. They're not really + // needed for oneof fields in proto2 either, as everything can be done via + // oneof case, but we follow the convention from other languages. Proto3 + // oneof fields never have Has/Clear members - but will also never have + // the explicit optional keyword either. + // + // None of the built-in helpers (descriptor->has_presence() etc) describe + // quite the behavior we want, so the rules are explicit below. + + if (descriptor->is_repeated() || + descriptor->type() == FieldDescriptor::TYPE_MESSAGE) { + return false; + } + // has_optional_keyword() has more complex rules for proto2, but that + // doesn't matter given the first part of this condition. + return IsProto2(descriptor->file()) || descriptor->has_optional_keyword(); +} + +inline bool RequiresPresenceBit(const FieldDescriptor* descriptor) { + return SupportsPresenceApi(descriptor) && + !IsNullable(descriptor) && + !descriptor->is_extension() && + !descriptor->real_containing_oneof(); +} + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#include <port_undef.inc> + +#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_HELPERS_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_map_field.cc b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_map_field.cc new file mode 100644 index 00000000..7b4015da --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_map_field.cc @@ -0,0 +1,152 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2015 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 <sstream> + +#include <compiler/code_generator.h> +#include <descriptor.h> +#include <descriptor.pb.h> +#include <io/printer.h> +#include <io/zero_copy_stream.h> +#include <stubs/strutil.h> + +#include <compiler/csharp/csharp_doc_comment.h> +#include <compiler/csharp/csharp_helpers.h> +#include <compiler/csharp/csharp_map_field.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +MapFieldGenerator::MapFieldGenerator(const FieldDescriptor* descriptor, + int presenceIndex, + const Options* options) + : FieldGeneratorBase(descriptor, presenceIndex, options) { +} + +MapFieldGenerator::~MapFieldGenerator() { +} + +void MapFieldGenerator::GenerateMembers(io::Printer* printer) { + const FieldDescriptor* key_descriptor = + descriptor_->message_type()->FindFieldByName("key"); + const FieldDescriptor* value_descriptor = + descriptor_->message_type()->FindFieldByName("value"); + variables_["key_type_name"] = type_name(key_descriptor); + variables_["value_type_name"] = type_name(value_descriptor); + std::unique_ptr<FieldGeneratorBase> key_generator( + CreateFieldGenerator(key_descriptor, 1, this->options())); + std::unique_ptr<FieldGeneratorBase> value_generator( + CreateFieldGenerator(value_descriptor, 2, this->options())); + + printer->Print( + variables_, + "private static readonly pbc::MapField<$key_type_name$, $value_type_name$>.Codec _map_$name$_codec\n" + " = new pbc::MapField<$key_type_name$, $value_type_name$>.Codec("); + key_generator->GenerateCodecCode(printer); + printer->Print(", "); + value_generator->GenerateCodecCode(printer); + printer->Print( + variables_, + ", $tag$);\n" + "private readonly pbc::MapField<$key_type_name$, $value_type_name$> $name$_ = new pbc::MapField<$key_type_name$, $value_type_name$>();\n"); + WritePropertyDocComment(printer, descriptor_); + AddPublicMemberAttributes(printer); + printer->Print( + variables_, + "$access_level$ pbc::MapField<$key_type_name$, $value_type_name$> $property_name$ {\n" + " get { return $name$_; }\n" + "}\n"); +} + +void MapFieldGenerator::GenerateMergingCode(io::Printer* printer) { + printer->Print( + variables_, + "$name$_.Add(other.$name$_);\n"); +} + +void MapFieldGenerator::GenerateParsingCode(io::Printer* printer) { + GenerateParsingCode(printer, true); +} + +void MapFieldGenerator::GenerateParsingCode(io::Printer* printer, bool use_parse_context) { + printer->Print( + variables_, + use_parse_context + ? "$name$_.AddEntriesFrom(ref input, _map_$name$_codec);\n" + : "$name$_.AddEntriesFrom(input, _map_$name$_codec);\n"); +} + +void MapFieldGenerator::GenerateSerializationCode(io::Printer* printer) { + GenerateSerializationCode(printer, true); +} + +void MapFieldGenerator::GenerateSerializationCode(io::Printer* printer, bool use_write_context) { + printer->Print( + variables_, + use_write_context + ? "$name$_.WriteTo(ref output, _map_$name$_codec);\n" + : "$name$_.WriteTo(output, _map_$name$_codec);\n"); +} + +void MapFieldGenerator::GenerateSerializedSizeCode(io::Printer* printer) { + printer->Print( + variables_, + "size += $name$_.CalculateSize(_map_$name$_codec);\n"); +} + +void MapFieldGenerator::WriteHash(io::Printer* printer) { + printer->Print( + variables_, + "hash ^= $property_name$.GetHashCode();\n"); +} +void MapFieldGenerator::WriteEquals(io::Printer* printer) { + printer->Print( + variables_, + "if (!$property_name$.Equals(other.$property_name$)) return false;\n"); +} + +void MapFieldGenerator::WriteToString(io::Printer* printer) { + // TODO: If we ever actually use ToString, we'll need to impleme this... +} + +void MapFieldGenerator::GenerateCloningCode(io::Printer* printer) { + printer->Print(variables_, + "$name$_ = other.$name$_.Clone();\n"); +} + +void MapFieldGenerator::GenerateFreezingCode(io::Printer* printer) { +} + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_map_field.h b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_map_field.h new file mode 100644 index 00000000..de16588c --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_map_field.h @@ -0,0 +1,75 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_MAP_FIELD_H__ +#define GOOGLE_PROTOBUF_COMPILER_CSHARP_MAP_FIELD_H__ + +#include <string> + +#include <compiler/code_generator.h> +#include <compiler/csharp/csharp_field_base.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +class MapFieldGenerator : public FieldGeneratorBase { + public: + MapFieldGenerator(const FieldDescriptor* descriptor, + int presenceIndex, + const Options* options); + ~MapFieldGenerator(); + + MapFieldGenerator(const MapFieldGenerator&) = delete; + MapFieldGenerator& operator=(const MapFieldGenerator&) = delete; + + virtual void GenerateCloningCode(io::Printer* printer) override; + virtual void GenerateFreezingCode(io::Printer* printer) override; + virtual void GenerateMembers(io::Printer* printer) override; + virtual void GenerateMergingCode(io::Printer* printer) override; + virtual void GenerateParsingCode(io::Printer* printer) override; + virtual void GenerateParsingCode(io::Printer* printer, bool use_parse_context) override; + virtual void GenerateSerializationCode(io::Printer* printer) override; + virtual void GenerateSerializationCode(io::Printer* printer, bool use_write_context) override; + virtual void GenerateSerializedSizeCode(io::Printer* printer) override; + + virtual void WriteHash(io::Printer* printer) override; + virtual void WriteEquals(io::Printer* printer) override; + virtual void WriteToString(io::Printer* printer) override; +}; + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_MAP_FIELD_H__ + diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_message.cc b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_message.cc new file mode 100644 index 00000000..963b9c87 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_message.cc @@ -0,0 +1,779 @@ +// 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 <sstream> +#include <algorithm> +#include <map> + +#include <compiler/code_generator.h> +#include <descriptor.h> +#include <descriptor.pb.h> +#include <io/printer.h> +#include <io/zero_copy_stream.h> +#include <stubs/strutil.h> +#include <wire_format.h> +#include <wire_format_lite.h> + +#include <compiler/csharp/csharp_options.h> +#include <compiler/csharp/csharp_doc_comment.h> +#include <compiler/csharp/csharp_enum.h> +#include <compiler/csharp/csharp_field_base.h> +#include <compiler/csharp/csharp_helpers.h> +#include <compiler/csharp/csharp_message.h> +#include <compiler/csharp/csharp_names.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +bool CompareFieldNumbers(const FieldDescriptor* d1, const FieldDescriptor* d2) { + return d1->number() < d2->number(); +} + +MessageGenerator::MessageGenerator(const Descriptor* descriptor, + const Options* options) + : SourceGeneratorBase(options), + descriptor_(descriptor), + has_bit_field_count_(0), + end_tag_(GetGroupEndTag(descriptor)), + has_extension_ranges_(descriptor->extension_range_count() > 0) { + // fields by number + for (int i = 0; i < descriptor_->field_count(); i++) { + fields_by_number_.push_back(descriptor_->field(i)); + } + std::sort(fields_by_number_.begin(), fields_by_number_.end(), + CompareFieldNumbers); + + int presence_bit_count = 0; + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = descriptor_->field(i); + if (RequiresPresenceBit(field)) { + presence_bit_count++; + if (has_bit_field_count_ == 0 || (presence_bit_count % 32) == 0) { + has_bit_field_count_++; + } + } + } +} + +MessageGenerator::~MessageGenerator() { +} + +std::string MessageGenerator::class_name() { + return descriptor_->name(); +} + +std::string MessageGenerator::full_class_name() { + return GetClassName(descriptor_); +} + +const std::vector<const FieldDescriptor*>& MessageGenerator::fields_by_number() { + return fields_by_number_; +} + +void MessageGenerator::AddDeprecatedFlag(io::Printer* printer) { + if (descriptor_->options().deprecated()) { + printer->Print("[global::System.ObsoleteAttribute]\n"); + } +} + +void MessageGenerator::AddSerializableAttribute(io::Printer* printer) { + if (this->options()->serializable) { + printer->Print("[global::System.SerializableAttribute]\n"); + } +} + +void MessageGenerator::Generate(io::Printer* printer) { + std::map<std::string, std::string> vars; + vars["class_name"] = class_name(); + vars["access_level"] = class_access_level(); + + WriteMessageDocComment(printer, descriptor_); + AddDeprecatedFlag(printer); + AddSerializableAttribute(printer); + + printer->Print( + vars, + "$access_level$ sealed partial class $class_name$ : "); + + if (has_extension_ranges_) { + printer->Print(vars, "pb::IExtendableMessage<$class_name$>\n"); + } + else { + printer->Print(vars, "pb::IMessage<$class_name$>\n"); + } + printer->Print("#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE\n"); + printer->Print(" , pb::IBufferMessage\n"); + printer->Print("#endif\n"); + printer->Print("{\n"); + printer->Indent(); + + // All static fields and properties + printer->Print( + vars, + "private static readonly pb::MessageParser<$class_name$> _parser = new pb::MessageParser<$class_name$>(() => new $class_name$());\n"); + + printer->Print( + "private pb::UnknownFieldSet _unknownFields;\n"); + + if (has_extension_ranges_) { + if (IsDescriptorProto(descriptor_->file())) { + printer->Print(vars, "internal pb::ExtensionSet<$class_name$> _extensions;\n"); // CustomOptions compatibility + } else { + printer->Print(vars, "private pb::ExtensionSet<$class_name$> _extensions;\n"); + } + + // a read-only property for fast + // retrieval of the set in IsInitialized + printer->Print(vars, + "private pb::ExtensionSet<$class_name$> _Extensions { get { " + "return _extensions; } }\n"); + } + + for (int i = 0; i < has_bit_field_count_; i++) { + // don't use arrays since all arrays are heap allocated, saving allocations + // use ints instead of bytes since bytes lack bitwise operators, saving casts + printer->Print("private int _hasBits$i$;\n", "i", StrCat(i)); + } + + WriteGeneratedCodeAttributes(printer); + + printer->Print( + vars, + "public static pb::MessageParser<$class_name$> Parser { get { return _parser; } }\n\n"); + + // Access the message descriptor via the relevant file descriptor or containing message descriptor. + if (!descriptor_->containing_type()) { + vars["descriptor_accessor"] = GetReflectionClassName(descriptor_->file()) + + ".Descriptor.MessageTypes[" + StrCat(descriptor_->index()) + "]"; + } else { + vars["descriptor_accessor"] = GetClassName(descriptor_->containing_type()) + + ".Descriptor.NestedTypes[" + StrCat(descriptor_->index()) + "]"; + } + + WriteGeneratedCodeAttributes(printer); + printer->Print( + vars, + "public static pbr::MessageDescriptor Descriptor {\n" + " get { return $descriptor_accessor$; }\n" + "}\n" + "\n"); + WriteGeneratedCodeAttributes(printer); + printer->Print( + vars, + "pbr::MessageDescriptor pb::IMessage.Descriptor {\n" + " get { return Descriptor; }\n" + "}\n" + "\n"); + + // Parameterless constructor and partial OnConstruction method. + WriteGeneratedCodeAttributes(printer); + printer->Print( + vars, + "public $class_name$() {\n" + " OnConstruction();\n" + "}\n\n" + "partial void OnConstruction();\n\n"); + + GenerateCloningCode(printer); + GenerateFreezingCode(printer); + + // Fields/properties + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* fieldDescriptor = descriptor_->field(i); + + // Rats: we lose the debug comment here :( + printer->Print( + "/// <summary>Field number for the \"$field_name$\" field.</summary>\n" + "public const int $field_constant_name$ = $index$;\n", + "field_name", fieldDescriptor->name(), + "field_constant_name", GetFieldConstantName(fieldDescriptor), + "index", StrCat(fieldDescriptor->number())); + std::unique_ptr<FieldGeneratorBase> generator( + CreateFieldGeneratorInternal(fieldDescriptor)); + generator->GenerateMembers(printer); + printer->Print("\n"); + } + + // oneof properties (for real oneofs, which come before synthetic ones) + for (int i = 0; i < descriptor_->real_oneof_decl_count(); i++) { + const OneofDescriptor* oneof = descriptor_->oneof_decl(i); + vars["name"] = UnderscoresToCamelCase(oneof->name(), false); + vars["property_name"] = UnderscoresToCamelCase(oneof->name(), true); + vars["original_name"] = oneof->name(); + printer->Print( + vars, + "private object $name$_;\n" + "/// <summary>Enum of possible cases for the \"$original_name$\" oneof.</summary>\n" + "public enum $property_name$OneofCase {\n"); + printer->Indent(); + printer->Print("None = 0,\n"); + for (int j = 0; j < oneof->field_count(); j++) { + const FieldDescriptor* field = oneof->field(j); + printer->Print("$field_property_name$ = $index$,\n", + "field_property_name", GetPropertyName(field), + "index", StrCat(field->number())); + } + printer->Outdent(); + printer->Print("}\n"); + // TODO: Should we put the oneof .proto comments here? + // It's unclear exactly where they should go. + printer->Print( + vars, + "private $property_name$OneofCase $name$Case_ = $property_name$OneofCase.None;\n"); + WriteGeneratedCodeAttributes(printer); + printer->Print( + vars, + "public $property_name$OneofCase $property_name$Case {\n" + " get { return $name$Case_; }\n" + "}\n\n"); + WriteGeneratedCodeAttributes(printer); + printer->Print( + vars, + "public void Clear$property_name$() {\n" + " $name$Case_ = $property_name$OneofCase.None;\n" + " $name$_ = null;\n" + "}\n\n"); + } + + // Standard methods + GenerateFrameworkMethods(printer); + GenerateMessageSerializationMethods(printer); + GenerateMergingMethods(printer); + + if (has_extension_ranges_) { + printer->Print( + vars, + "public TValue GetExtension<TValue>(pb::Extension<$class_name$, " + "TValue> extension) {\n" + " return pb::ExtensionSet.Get(ref _extensions, extension);\n" + "}\n" + "public pbc::RepeatedField<TValue> " + "GetExtension<TValue>(pb::RepeatedExtension<$class_name$, TValue> " + "extension) {\n" + " return pb::ExtensionSet.Get(ref _extensions, extension);\n" + "}\n" + "public pbc::RepeatedField<TValue> " + "GetOrInitializeExtension<TValue>(pb::RepeatedExtension<$class_name$, " + "TValue> extension) {\n" + " return pb::ExtensionSet.GetOrInitialize(ref _extensions, " + "extension);\n" + "}\n" + "public void SetExtension<TValue>(pb::Extension<$class_name$, TValue> " + "extension, TValue value) {\n" + " pb::ExtensionSet.Set(ref _extensions, extension, value);\n" + "}\n" + "public bool HasExtension<TValue>(pb::Extension<$class_name$, TValue> " + "extension) {\n" + " return pb::ExtensionSet.Has(ref _extensions, extension);\n" + "}\n" + "public void ClearExtension<TValue>(pb::Extension<$class_name$, " + "TValue> extension) {\n" + " pb::ExtensionSet.Clear(ref _extensions, extension);\n" + "}\n" + "public void " + "ClearExtension<TValue>(pb::RepeatedExtension<$class_name$, TValue> " + "extension) {\n" + " pb::ExtensionSet.Clear(ref _extensions, extension);\n" + "}\n\n"); + } + + // Nested messages and enums + if (HasNestedGeneratedTypes()) { + printer->Print( + vars, + "#region Nested types\n" + "/// <summary>Container for nested types declared in the $class_name$ message type.</summary>\n"); + WriteGeneratedCodeAttributes(printer); + printer->Print("public static partial class Types {\n"); + printer->Indent(); + for (int i = 0; i < descriptor_->enum_type_count(); i++) { + EnumGenerator enumGenerator(descriptor_->enum_type(i), this->options()); + enumGenerator.Generate(printer); + } + for (int i = 0; i < descriptor_->nested_type_count(); i++) { + // Don't generate nested types for maps... + if (!IsMapEntryMessage(descriptor_->nested_type(i))) { + MessageGenerator messageGenerator( + descriptor_->nested_type(i), this->options()); + messageGenerator.Generate(printer); + } + } + printer->Outdent(); + printer->Print("}\n" + "#endregion\n" + "\n"); + } + + if (descriptor_->extension_count() > 0) { + printer->Print( + vars, + "#region Extensions\n" + "/// <summary>Container for extensions for other messages declared in the $class_name$ message type.</summary>\n"); + WriteGeneratedCodeAttributes(printer); + printer->Print("public static partial class Extensions {\n"); + printer->Indent(); + for (int i = 0; i < descriptor_->extension_count(); i++) { + std::unique_ptr<FieldGeneratorBase> generator( + CreateFieldGeneratorInternal(descriptor_->extension(i))); + generator->GenerateExtensionCode(printer); + } + printer->Outdent(); + printer->Print( + "}\n" + "#endregion\n" + "\n"); + } + + printer->Outdent(); + printer->Print("}\n"); + printer->Print("\n"); +} + +// Helper to work out whether we need to generate a class to hold nested types/enums. +// Only tricky because we don't want to generate map entry types. +bool MessageGenerator::HasNestedGeneratedTypes() +{ + if (descriptor_->enum_type_count() > 0) { + return true; + } + for (int i = 0; i < descriptor_->nested_type_count(); i++) { + if (!IsMapEntryMessage(descriptor_->nested_type(i))) { + return true; + } + } + return false; +} + +void MessageGenerator::GenerateCloningCode(io::Printer* printer) { + std::map<std::string, std::string> vars; + WriteGeneratedCodeAttributes(printer); + vars["class_name"] = class_name(); + printer->Print( + vars, + "public $class_name$($class_name$ other) : this() {\n"); + printer->Indent(); + for (int i = 0; i < has_bit_field_count_; i++) { + printer->Print("_hasBits$i$ = other._hasBits$i$;\n", "i", StrCat(i)); + } + // Clone non-oneof fields first (treating optional proto3 fields as non-oneof) + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = descriptor_->field(i); + if (field->real_containing_oneof()) { + continue; + } + std::unique_ptr<FieldGeneratorBase> generator(CreateFieldGeneratorInternal(field)); + generator->GenerateCloningCode(printer); + } + // Clone just the right field for each real oneof + for (int i = 0; i < descriptor_->real_oneof_decl_count(); ++i) { + const OneofDescriptor* oneof = descriptor_->oneof_decl(i); + vars["name"] = UnderscoresToCamelCase(oneof->name(), false); + vars["property_name"] = UnderscoresToCamelCase(oneof->name(), true); + printer->Print(vars, "switch (other.$property_name$Case) {\n"); + printer->Indent(); + for (int j = 0; j < oneof->field_count(); j++) { + const FieldDescriptor* field = oneof->field(j); + std::unique_ptr<FieldGeneratorBase> generator(CreateFieldGeneratorInternal(field)); + vars["field_property_name"] = GetPropertyName(field); + printer->Print( + vars, + "case $property_name$OneofCase.$field_property_name$:\n"); + printer->Indent(); + generator->GenerateCloningCode(printer); + printer->Print("break;\n"); + printer->Outdent(); + } + printer->Outdent(); + printer->Print("}\n\n"); + } + // Clone unknown fields + printer->Print( + "_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);\n"); + if (has_extension_ranges_) { + printer->Print( + "_extensions = pb::ExtensionSet.Clone(other._extensions);\n"); + } + + printer->Outdent(); + printer->Print("}\n\n"); + + WriteGeneratedCodeAttributes(printer); + printer->Print( + vars, + "public $class_name$ Clone() {\n" + " return new $class_name$(this);\n" + "}\n\n"); +} + +void MessageGenerator::GenerateFreezingCode(io::Printer* printer) { +} + +void MessageGenerator::GenerateFrameworkMethods(io::Printer* printer) { + std::map<std::string, std::string> vars; + vars["class_name"] = class_name(); + + // Equality + WriteGeneratedCodeAttributes(printer); + printer->Print( + vars, + "public override bool Equals(object other) {\n" + " return Equals(other as $class_name$);\n" + "}\n\n"); + WriteGeneratedCodeAttributes(printer); + printer->Print( + vars, + "public bool Equals($class_name$ other) {\n" + " if (ReferenceEquals(other, null)) {\n" + " return false;\n" + " }\n" + " if (ReferenceEquals(other, this)) {\n" + " return true;\n" + " }\n"); + printer->Indent(); + for (int i = 0; i < descriptor_->field_count(); i++) { + std::unique_ptr<FieldGeneratorBase> generator( + CreateFieldGeneratorInternal(descriptor_->field(i))); + generator->WriteEquals(printer); + } + for (int i = 0; i < descriptor_->real_oneof_decl_count(); i++) { + printer->Print("if ($property_name$Case != other.$property_name$Case) return false;\n", + "property_name", UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), true)); + } + if (has_extension_ranges_) { + printer->Print( + "if (!Equals(_extensions, other._extensions)) {\n" + " return false;\n" + "}\n"); + } + printer->Outdent(); + printer->Print( + " return Equals(_unknownFields, other._unknownFields);\n" + "}\n\n"); + + // GetHashCode + // Start with a non-zero value to easily distinguish between null and "empty" messages. + WriteGeneratedCodeAttributes(printer); + printer->Print( + "public override int GetHashCode() {\n" + " int hash = 1;\n"); + printer->Indent(); + for (int i = 0; i < descriptor_->field_count(); i++) { + std::unique_ptr<FieldGeneratorBase> generator( + CreateFieldGeneratorInternal(descriptor_->field(i))); + generator->WriteHash(printer); + } + for (int i = 0; i < descriptor_->real_oneof_decl_count(); i++) { + printer->Print("hash ^= (int) $name$Case_;\n", + "name", UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), false)); + } + if (has_extension_ranges_) { + printer->Print( + "if (_extensions != null) {\n" + " hash ^= _extensions.GetHashCode();\n" + "}\n"); + } + printer->Print( + "if (_unknownFields != null) {\n" + " hash ^= _unknownFields.GetHashCode();\n" + "}\n" + "return hash;\n"); + printer->Outdent(); + printer->Print("}\n\n"); + + WriteGeneratedCodeAttributes(printer); + printer->Print( + "public override string ToString() {\n" + " return pb::JsonFormatter.ToDiagnosticString(this);\n" + "}\n\n"); +} + +void MessageGenerator::GenerateMessageSerializationMethods(io::Printer* printer) { + WriteGeneratedCodeAttributes(printer); + printer->Print( + "public void WriteTo(pb::CodedOutputStream output) {\n"); + printer->Print("#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE\n"); + printer->Indent(); + printer->Print("output.WriteRawMessage(this);\n"); + printer->Outdent(); + printer->Print("#else\n"); + printer->Indent(); + GenerateWriteToBody(printer, false); + printer->Outdent(); + printer->Print("#endif\n"); + printer->Print("}\n\n"); + + printer->Print("#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE\n"); + WriteGeneratedCodeAttributes(printer); + printer->Print("void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) {\n"); + printer->Indent(); + GenerateWriteToBody(printer, true); + printer->Outdent(); + printer->Print("}\n"); + printer->Print("#endif\n\n"); + + WriteGeneratedCodeAttributes(printer); + printer->Print( + "public int CalculateSize() {\n"); + printer->Indent(); + printer->Print("int size = 0;\n"); + for (int i = 0; i < descriptor_->field_count(); i++) { + std::unique_ptr<FieldGeneratorBase> generator( + CreateFieldGeneratorInternal(descriptor_->field(i))); + generator->GenerateSerializedSizeCode(printer); + } + + if (has_extension_ranges_) { + printer->Print( + "if (_extensions != null) {\n" + " size += _extensions.CalculateSize();\n" + "}\n"); + } + + printer->Print( + "if (_unknownFields != null) {\n" + " size += _unknownFields.CalculateSize();\n" + "}\n"); + + printer->Print("return size;\n"); + printer->Outdent(); + printer->Print("}\n\n"); +} + +void MessageGenerator::GenerateWriteToBody(io::Printer* printer, bool use_write_context) { + // Serialize all the fields + for (int i = 0; i < fields_by_number().size(); i++) { + std::unique_ptr<FieldGeneratorBase> generator( + CreateFieldGeneratorInternal(fields_by_number()[i])); + generator->GenerateSerializationCode(printer, use_write_context); + } + + if (has_extension_ranges_) { + // Serialize extensions + printer->Print( + use_write_context + ? "if (_extensions != null) {\n" + " _extensions.WriteTo(ref output);\n" + "}\n" + : "if (_extensions != null) {\n" + " _extensions.WriteTo(output);\n" + "}\n"); + } + + // Serialize unknown fields + printer->Print( + use_write_context + ? "if (_unknownFields != null) {\n" + " _unknownFields.WriteTo(ref output);\n" + "}\n" + : "if (_unknownFields != null) {\n" + " _unknownFields.WriteTo(output);\n" + "}\n"); + + // TODO(jonskeet): Memoize size of frozen messages? +} + +void MessageGenerator::GenerateMergingMethods(io::Printer* printer) { + // Note: These are separate from GenerateMessageSerializationMethods() + // because they need to be generated even for messages that are optimized + // for code size. + std::map<std::string, std::string> vars; + vars["class_name"] = class_name(); + + WriteGeneratedCodeAttributes(printer); + printer->Print( + vars, + "public void MergeFrom($class_name$ other) {\n"); + printer->Indent(); + printer->Print( + "if (other == null) {\n" + " return;\n" + "}\n"); + // Merge non-oneof fields, treating optional proto3 fields as normal fields + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = descriptor_->field(i); + if (field->real_containing_oneof()) { + continue; + } + std::unique_ptr<FieldGeneratorBase> generator(CreateFieldGeneratorInternal(field)); + generator->GenerateMergingCode(printer); + } + // Merge oneof fields (for non-synthetic oneofs) + for (int i = 0; i < descriptor_->real_oneof_decl_count(); ++i) { + const OneofDescriptor* oneof = descriptor_->oneof_decl(i); + vars["name"] = UnderscoresToCamelCase(oneof->name(), false); + vars["property_name"] = UnderscoresToCamelCase(oneof->name(), true); + printer->Print(vars, "switch (other.$property_name$Case) {\n"); + printer->Indent(); + for (int j = 0; j < oneof->field_count(); j++) { + const FieldDescriptor* field = oneof->field(j); + vars["field_property_name"] = GetPropertyName(field); + printer->Print( + vars, + "case $property_name$OneofCase.$field_property_name$:\n"); + printer->Indent(); + std::unique_ptr<FieldGeneratorBase> generator(CreateFieldGeneratorInternal(field)); + generator->GenerateMergingCode(printer); + printer->Print("break;\n"); + printer->Outdent(); + } + printer->Outdent(); + printer->Print("}\n\n"); + } + // Merge extensions + if (has_extension_ranges_) { + printer->Print("pb::ExtensionSet.MergeFrom(ref _extensions, other._extensions);\n"); + } + + // Merge unknown fields. + printer->Print( + "_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);\n"); + + printer->Outdent(); + printer->Print("}\n\n"); + + WriteGeneratedCodeAttributes(printer); + printer->Print("public void MergeFrom(pb::CodedInputStream input) {\n"); + printer->Print("#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE\n"); + printer->Indent(); + printer->Print("input.ReadRawMessage(this);\n"); + printer->Outdent(); + printer->Print("#else\n"); + printer->Indent(); + GenerateMainParseLoop(printer, false); + printer->Outdent(); + printer->Print("#endif\n"); + printer->Print("}\n\n"); + + printer->Print("#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE\n"); + WriteGeneratedCodeAttributes(printer); + printer->Print("void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) {\n"); + printer->Indent(); + GenerateMainParseLoop(printer, true); + printer->Outdent(); + printer->Print("}\n"); // method + printer->Print("#endif\n\n"); + +} + +void MessageGenerator::GenerateMainParseLoop(io::Printer* printer, bool use_parse_context) { + std::map<std::string, std::string> vars; + vars["maybe_ref_input"] = use_parse_context ? "ref input" : "input"; + + printer->Print( + "uint tag;\n" + "while ((tag = input.ReadTag()) != 0) {\n" + " switch(tag) {\n"); + printer->Indent(); + printer->Indent(); + if (end_tag_ != 0) { + printer->Print( + "case $end_tag$:\n" + " return;\n", + "end_tag", StrCat(end_tag_)); + } + if (has_extension_ranges_) { + printer->Print(vars, + "default:\n" + " if (!pb::ExtensionSet.TryMergeFieldFrom(ref _extensions, $maybe_ref_input$)) {\n" + " _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, $maybe_ref_input$);\n" + " }\n" + " break;\n"); + } else { + printer->Print(vars, + "default:\n" + " _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, $maybe_ref_input$);\n" + " break;\n"); + } + for (int i = 0; i < fields_by_number().size(); i++) { + const FieldDescriptor* field = fields_by_number()[i]; + internal::WireFormatLite::WireType wt = + internal::WireFormat::WireTypeForFieldType(field->type()); + uint32 tag = internal::WireFormatLite::MakeTag(field->number(), wt); + // Handle both packed and unpacked repeated fields with the same Read*Array call; + // the two generated cases are the packed and unpacked tags. + // TODO(jonskeet): Check that is_packable is equivalent to + // is_repeated && wt in { VARINT, FIXED32, FIXED64 }. + // It looks like it is... + if (field->is_packable()) { + printer->Print( + "case $packed_tag$:\n", + "packed_tag", + StrCat( + internal::WireFormatLite::MakeTag( + field->number(), + internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED))); + } + + printer->Print("case $tag$: {\n", "tag", StrCat(tag)); + printer->Indent(); + std::unique_ptr<FieldGeneratorBase> generator( + CreateFieldGeneratorInternal(field)); + generator->GenerateParsingCode(printer, use_parse_context); + printer->Print("break;\n"); + printer->Outdent(); + printer->Print("}\n"); + } + printer->Outdent(); + printer->Print("}\n"); // switch + printer->Outdent(); + printer->Print("}\n"); // while +} + +// it's a waste of space to track presence for all values, so we only track them if they're not nullable +int MessageGenerator::GetPresenceIndex(const FieldDescriptor* descriptor) { + if (!RequiresPresenceBit(descriptor)) { + return -1; + } + + int index = 0; + for (int i = 0; i < fields_by_number().size(); i++) { + const FieldDescriptor* field = fields_by_number()[i]; + if (field == descriptor) { + return index; + } + if (RequiresPresenceBit(field)) { + index++; + } + } + GOOGLE_LOG(DFATAL)<< "Could not find presence index for field " << descriptor->name(); + return -1; +} + +FieldGeneratorBase* MessageGenerator::CreateFieldGeneratorInternal( + const FieldDescriptor* descriptor) { + return CreateFieldGenerator(descriptor, GetPresenceIndex(descriptor), this->options()); +} + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_message.h b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_message.h new file mode 100644 index 00000000..cdb31f80 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_message.h @@ -0,0 +1,94 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_MESSAGE_H__ +#define GOOGLE_PROTOBUF_COMPILER_CSHARP_MESSAGE_H__ + +#include <string> +#include <vector> + +#include <compiler/code_generator.h> +#include <compiler/csharp/csharp_source_generator_base.h> +#include <compiler/csharp/csharp_helpers.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +class FieldGeneratorBase; + +class MessageGenerator : public SourceGeneratorBase { + public: + MessageGenerator(const Descriptor* descriptor, const Options* options); + ~MessageGenerator(); + + MessageGenerator(const MessageGenerator&) = delete; + MessageGenerator& operator=(const MessageGenerator&) = delete; + + void GenerateCloningCode(io::Printer* printer); + void GenerateFreezingCode(io::Printer* printer); + void GenerateFrameworkMethods(io::Printer* printer); + void Generate(io::Printer* printer); + + private: + const Descriptor* descriptor_; + std::vector<const FieldDescriptor*> fields_by_number_; + int has_bit_field_count_; + uint end_tag_; + bool has_extension_ranges_; + + void GenerateMessageSerializationMethods(io::Printer* printer); + void GenerateWriteToBody(io::Printer* printer, bool use_write_context); + void GenerateMergingMethods(io::Printer* printer); + void GenerateMainParseLoop(io::Printer* printer, bool use_parse_context); + + int GetPresenceIndex(const FieldDescriptor* descriptor); + FieldGeneratorBase* CreateFieldGeneratorInternal( + const FieldDescriptor* descriptor); + + bool HasNestedGeneratedTypes(); + + void AddDeprecatedFlag(io::Printer* printer); + void AddSerializableAttribute(io::Printer* printer); + + std::string class_name(); + std::string full_class_name(); + + // field descriptors sorted by number + const std::vector<const FieldDescriptor*>& fields_by_number(); +}; + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_MESSAGE_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_message_field.cc b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_message_field.cc new file mode 100644 index 00000000..1252202e --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_message_field.cc @@ -0,0 +1,293 @@ +// 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 <sstream> + +#include <compiler/code_generator.h> +#include <descriptor.h> +#include <descriptor.pb.h> +#include <io/printer.h> +#include <io/zero_copy_stream.h> +#include <stubs/strutil.h> +#include <wire_format.h> +#include <wire_format_lite.h> + +#include <compiler/csharp/csharp_doc_comment.h> +#include <compiler/csharp/csharp_helpers.h> +#include <compiler/csharp/csharp_message_field.h> +#include <compiler/csharp/csharp_options.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +MessageFieldGenerator::MessageFieldGenerator(const FieldDescriptor* descriptor, + int presenceIndex, + const Options *options) + : FieldGeneratorBase(descriptor, presenceIndex, options) { + if (!SupportsPresenceApi(descriptor_)) { + variables_["has_property_check"] = name() + "_ != null"; + variables_["has_not_property_check"] = name() + "_ == null"; + } +} + +MessageFieldGenerator::~MessageFieldGenerator() { + +} + +void MessageFieldGenerator::GenerateMembers(io::Printer* printer) { + printer->Print( + variables_, + "private $type_name$ $name$_;\n"); + WritePropertyDocComment(printer, descriptor_); + AddPublicMemberAttributes(printer); + printer->Print( + variables_, + "$access_level$ $type_name$ $property_name$ {\n" + " get { return $name$_; }\n" + " set {\n" + " $name$_ = value;\n" + " }\n" + "}\n"); + if (SupportsPresenceApi(descriptor_)) { + printer->Print( + variables_, + "/// <summary>Gets whether the $descriptor_name$ field is set</summary>\n"); + AddPublicMemberAttributes(printer); + printer->Print( + variables_, + "$access_level$ bool Has$property_name$ {\n" + " get { return $name$_ != null; }\n" + "}\n"); + printer->Print( + variables_, + "/// <summary>Clears the value of the $descriptor_name$ field</summary>\n"); + AddPublicMemberAttributes(printer); + printer->Print( + variables_, + "$access_level$ void Clear$property_name$() {\n" + " $name$_ = null;\n" + "}\n"); + } +} + +void MessageFieldGenerator::GenerateMergingCode(io::Printer* printer) { + printer->Print( + variables_, + "if (other.$has_property_check$) {\n" + " if ($has_not_property_check$) {\n" + " $property_name$ = new $type_name$();\n" + " }\n" + " $property_name$.MergeFrom(other.$property_name$);\n" + "}\n"); +} + +void MessageFieldGenerator::GenerateParsingCode(io::Printer* printer) { + printer->Print( + variables_, + "if ($has_not_property_check$) {\n" + " $property_name$ = new $type_name$();\n" + "}\n"); + if (descriptor_->type() == FieldDescriptor::Type::TYPE_MESSAGE) { + printer->Print(variables_, "input.ReadMessage($property_name$);\n"); + } else { + printer->Print(variables_, "input.ReadGroup($property_name$);\n"); + } +} + +void MessageFieldGenerator::GenerateSerializationCode(io::Printer* printer) { + if (descriptor_->type() == FieldDescriptor::Type::TYPE_MESSAGE) { + printer->Print( + variables_, + "if ($has_property_check$) {\n" + " output.WriteRawTag($tag_bytes$);\n" + " output.WriteMessage($property_name$);\n" + "}\n"); + } else { + printer->Print( + variables_, + "if ($has_property_check$) {\n" + " output.WriteRawTag($tag_bytes$);\n" + " output.WriteGroup($property_name$);\n" + " output.WriteRawTag($end_tag_bytes$);\n" + "}\n"); + } +} + +void MessageFieldGenerator::GenerateSerializedSizeCode(io::Printer* printer) { + if (descriptor_->type() == FieldDescriptor::Type::TYPE_MESSAGE) { + printer->Print( + variables_, + "if ($has_property_check$) {\n" + " size += $tag_size$ + pb::CodedOutputStream.ComputeMessageSize($property_name$);\n" + "}\n"); + } else { + printer->Print( + variables_, + "if ($has_property_check$) {\n" + " size += $tag_size$ + pb::CodedOutputStream.ComputeGroupSize($property_name$);\n" + "}\n"); + } +} + +void MessageFieldGenerator::WriteHash(io::Printer* printer) { + printer->Print( + variables_, + "if ($has_property_check$) hash ^= $property_name$.GetHashCode();\n"); +} +void MessageFieldGenerator::WriteEquals(io::Printer* printer) { + printer->Print( + variables_, + "if (!object.Equals($property_name$, other.$property_name$)) return false;\n"); +} +void MessageFieldGenerator::WriteToString(io::Printer* printer) { + variables_["field_name"] = GetFieldName(descriptor_); + printer->Print( + variables_, + "PrintField(\"$field_name$\", has$property_name$, $name$_, writer);\n"); +} +void MessageFieldGenerator::GenerateExtensionCode(io::Printer* printer) { + WritePropertyDocComment(printer, descriptor_); + AddDeprecatedFlag(printer); + printer->Print( + variables_, + "$access_level$ static readonly pb::Extension<$extended_type$, $type_name$> $property_name$ =\n" + " new pb::Extension<$extended_type$, $type_name$>($number$, "); + GenerateCodecCode(printer); + printer->Print(");\n"); +} +void MessageFieldGenerator::GenerateCloningCode(io::Printer* printer) { + printer->Print(variables_, + "$name$_ = other.$has_property_check$ ? other.$name$_.Clone() : null;\n"); +} + +void MessageFieldGenerator::GenerateFreezingCode(io::Printer* printer) { +} + +void MessageFieldGenerator::GenerateCodecCode(io::Printer* printer) { + if (descriptor_->type() == FieldDescriptor::Type::TYPE_MESSAGE) { + printer->Print( + variables_, + "pb::FieldCodec.ForMessage($tag$, $type_name$.Parser)"); + } else { + printer->Print( + variables_, + "pb::FieldCodec.ForGroup($tag$, $end_tag$, $type_name$.Parser)"); + } +} + +MessageOneofFieldGenerator::MessageOneofFieldGenerator( + const FieldDescriptor* descriptor, + int presenceIndex, + const Options *options) + : MessageFieldGenerator(descriptor, presenceIndex, options) { + SetCommonOneofFieldVariables(&variables_); +} + +MessageOneofFieldGenerator::~MessageOneofFieldGenerator() { + +} + +void MessageOneofFieldGenerator::GenerateMembers(io::Printer* printer) { + WritePropertyDocComment(printer, descriptor_); + AddPublicMemberAttributes(printer); + printer->Print( + variables_, + "$access_level$ $type_name$ $property_name$ {\n" + " get { return $has_property_check$ ? ($type_name$) $oneof_name$_ : null; }\n" + " set {\n" + " $oneof_name$_ = value;\n" + " $oneof_name$Case_ = value == null ? $oneof_property_name$OneofCase.None : $oneof_property_name$OneofCase.$property_name$;\n" + " }\n" + "}\n"); + if (SupportsPresenceApi(descriptor_)) { + printer->Print( + variables_, + "/// <summary>Gets whether the \"$descriptor_name$\" field is set</summary>\n"); + AddPublicMemberAttributes(printer); + printer->Print( + variables_, + "$access_level$ bool Has$property_name$ {\n" + " get { return $oneof_name$Case_ == $oneof_property_name$OneofCase.$property_name$; }\n" + "}\n"); + printer->Print( + variables_, + "/// <summary> Clears the value of the oneof if it's currently set to \"$descriptor_name$\" </summary>\n"); + AddPublicMemberAttributes(printer); + printer->Print( + variables_, + "$access_level$ void Clear$property_name$() {\n" + " if ($has_property_check$) {\n" + " Clear$oneof_property_name$();\n" + " }\n" + "}\n"); + } +} + +void MessageOneofFieldGenerator::GenerateMergingCode(io::Printer* printer) { + printer->Print(variables_, + "if ($property_name$ == null) {\n" + " $property_name$ = new $type_name$();\n" + "}\n" + "$property_name$.MergeFrom(other.$property_name$);\n"); +} + +void MessageOneofFieldGenerator::GenerateParsingCode(io::Printer* printer) { + // TODO(jonskeet): We may be able to do better than this + printer->Print( + variables_, + "$type_name$ subBuilder = new $type_name$();\n" + "if ($has_property_check$) {\n" + " subBuilder.MergeFrom($property_name$);\n" + "}\n"); + if (descriptor_->type() == FieldDescriptor::Type::TYPE_MESSAGE) { + printer->Print("input.ReadMessage(subBuilder);\n"); + } else { + printer->Print("input.ReadGroup(subBuilder);\n"); + } + printer->Print(variables_, "$property_name$ = subBuilder;\n"); +} + +void MessageOneofFieldGenerator::WriteToString(io::Printer* printer) { + printer->Print( + variables_, + "PrintField(\"$descriptor_name$\", $has_property_check$, $oneof_name$_, writer);\n"); +} + +void MessageOneofFieldGenerator::GenerateCloningCode(io::Printer* printer) { + printer->Print(variables_, + "$property_name$ = other.$property_name$.Clone();\n"); +} + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_message_field.h b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_message_field.h new file mode 100644 index 00000000..4cea5197 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_message_field.h @@ -0,0 +1,93 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_MESSAGE_FIELD_H__ +#define GOOGLE_PROTOBUF_COMPILER_CSHARP_MESSAGE_FIELD_H__ + +#include <string> + +#include <compiler/code_generator.h> +#include <compiler/csharp/csharp_field_base.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +class MessageFieldGenerator : public FieldGeneratorBase { + public: + MessageFieldGenerator(const FieldDescriptor* descriptor, + int presenceIndex, + const Options *options); + ~MessageFieldGenerator(); + + MessageFieldGenerator(const MessageFieldGenerator&) = delete; + MessageFieldGenerator& operator=(const MessageFieldGenerator&) = delete; + + virtual void GenerateCodecCode(io::Printer* printer) override; + virtual void GenerateCloningCode(io::Printer* printer) override; + virtual void GenerateFreezingCode(io::Printer* printer) override; + virtual void GenerateMembers(io::Printer* printer) override; + virtual void GenerateMergingCode(io::Printer* printer) override; + virtual void GenerateParsingCode(io::Printer* printer) override; + virtual void GenerateSerializationCode(io::Printer* printer) override; + virtual void GenerateSerializedSizeCode(io::Printer* printer) override; + virtual void GenerateExtensionCode(io::Printer* printer) override; + + virtual void WriteHash(io::Printer* printer) override; + virtual void WriteEquals(io::Printer* printer) override; + virtual void WriteToString(io::Printer* printer) override; +}; + +class MessageOneofFieldGenerator : public MessageFieldGenerator { + public: + MessageOneofFieldGenerator(const FieldDescriptor* descriptor, + int presenceIndex, + const Options *options); + ~MessageOneofFieldGenerator(); + + MessageOneofFieldGenerator(const MessageOneofFieldGenerator&) = delete; + MessageOneofFieldGenerator& operator=(const MessageOneofFieldGenerator&) = + delete; + + virtual void GenerateCloningCode(io::Printer* printer) override; + virtual void GenerateMembers(io::Printer* printer) override; + virtual void GenerateMergingCode(io::Printer* printer) override; + virtual void WriteToString(io::Printer* printer) override; + virtual void GenerateParsingCode(io::Printer* printer) override; +}; + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_MESSAGE_FIELD_H__ + diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_names.h b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_names.h new file mode 100644 index 00000000..247951ef --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_names.h @@ -0,0 +1,109 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// Provides a mechanism for mapping a descriptor to the +// fully-qualified name of the corresponding C# class. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_NAMES_H__ +#define GOOGLE_PROTOBUF_COMPILER_CSHARP_NAMES_H__ + +#include <string> +#include <port.h> +#include <stubs/common.h> + +#include <port_def.inc> + +namespace google { +namespace protobuf { + +class Descriptor; +class EnumDescriptor; +class FileDescriptor; +class ServiceDescriptor; + +namespace compiler { +namespace csharp { + +// Requires: +// descriptor != NULL +// +// Returns: +// The namespace to use for given file descriptor. +std::string PROTOC_EXPORT GetFileNamespace(const FileDescriptor* descriptor); + +// Requires: +// descriptor != NULL +// +// Returns: +// The fully-qualified C# class name. +std::string PROTOC_EXPORT GetClassName(const Descriptor* descriptor); + +// Requires: +// descriptor != NULL +// +// Returns: +// The fully-qualified name of the C# class that provides +// access to the file descriptor. Proto compiler generates +// such class for each .proto file processed. +std::string PROTOC_EXPORT +GetReflectionClassName(const FileDescriptor* descriptor); + +// Generates output file name for given file descriptor. If generate_directories +// is true, the output file will be put under directory corresponding to file's +// namespace. base_namespace can be used to strip some of the top level +// directories. E.g. for file with namespace "Bar.Foo" and base_namespace="Bar", +// the resulting file will be put under directory "Foo" (and not "Bar/Foo"). +// +// Requires: +// descriptor != NULL +// error != NULL +// +// Returns: +// The file name to use as output file for given file descriptor. In case +// of failure, this function will return empty string and error parameter +// will contain the error message. +std::string PROTOC_EXPORT GetOutputFile(const FileDescriptor* descriptor, + const std::string file_extension, + const bool generate_directories, + const std::string base_namespace, + std::string* error); + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#include <port_undef.inc> + +#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_NAMES_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_options.h b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_options.h new file mode 100644 index 00000000..42ff6d86 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_options.h @@ -0,0 +1,81 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_OPTIONS_H__ +#define GOOGLE_PROTOBUF_COMPILER_CSHARP_OPTIONS_H__ + +#include <string> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +// Generator options (used by csharp_generator.cc): +struct Options { + Options() : + file_extension(".cs"), + base_namespace(""), + base_namespace_specified(false), + internal_access(false), + serializable(false) { + } + // Extension of the generated file. Defaults to ".cs" + std::string file_extension; + // Base namespace to use to create directory hierarchy. Defaults to "". + // This option allows the simple creation of a conventional C# file layout, + // where directories are created relative to a project-specific base + // namespace. For example, in a project with a base namespace of PetShop, a + // proto of user.proto with a C# namespace of PetShop.Model.Shared would + // generate Model/Shared/User.cs underneath the specified --csharp_out + // directory. + // + // If no base namespace is specified, all files are generated in the + // --csharp_out directory, with no subdirectories created automatically. + std::string base_namespace; + // Whether the base namespace has been explicitly specified by the user. + // This is required as the base namespace can be explicitly set to the empty + // string, meaning "create a full directory hierarchy, starting from the first + // segment of the namespace." + bool base_namespace_specified; + // Whether the generated classes should have accessibility level of "internal". + // Defaults to false that generates "public" classes. + bool internal_access; + // Whether the generated classes should have a global::System.Serializable attribute added + // Defaults to false + bool serializable; +}; + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_OPTIONS_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_primitive_field.cc b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_primitive_field.cc new file mode 100644 index 00000000..6f695aa8 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_primitive_field.cc @@ -0,0 +1,349 @@ +// 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 <sstream> + +#include <compiler/code_generator.h> +#include <descriptor.h> +#include <descriptor.pb.h> +#include <io/printer.h> +#include <io/zero_copy_stream.h> +#include <stubs/strutil.h> + +#include <compiler/csharp/csharp_doc_comment.h> +#include <compiler/csharp/csharp_helpers.h> +#include <compiler/csharp/csharp_options.h> +#include <compiler/csharp/csharp_primitive_field.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +PrimitiveFieldGenerator::PrimitiveFieldGenerator( + const FieldDescriptor* descriptor, int presenceIndex, const Options *options) + : FieldGeneratorBase(descriptor, presenceIndex, options) { + // TODO(jonskeet): Make this cleaner... + is_value_type = descriptor->type() != FieldDescriptor::TYPE_STRING + && descriptor->type() != FieldDescriptor::TYPE_BYTES; + if (!is_value_type && !SupportsPresenceApi(descriptor_)) { + variables_["has_property_check"] = variables_["property_name"] + ".Length != 0"; + variables_["other_has_property_check"] = "other." + variables_["property_name"] + ".Length != 0"; + } +} + +PrimitiveFieldGenerator::~PrimitiveFieldGenerator() { +} + +void PrimitiveFieldGenerator::GenerateMembers(io::Printer* printer) { + + // Note: in multiple places, this code assumes that all fields + // that support presence are either nullable, or use a presence field bit. + // Fields which are oneof members are not generated here; they're generated in PrimitiveOneofFieldGenerator below. + // Extensions are not generated here either. + + + // Proto2 allows different default values to be specified. These are retained + // via static fields. They don't particularly need to be, but we don't need + // to change that. In Proto3 the default value we don't generate these + // fields, just using the literal instead. + if (IsProto2(descriptor_->file())) { + // Note: "private readonly static" isn't as idiomatic as + // "private static readonly", but changing this now would create a lot of + // churn in generated code with near-to-zero benefit. + printer->Print( + variables_, + "private readonly static $type_name$ $property_name$DefaultValue = $default_value$;\n\n"); + variables_["default_value_access"] = + variables_["property_name"] + "DefaultValue"; + } else { + variables_["default_value_access"] = variables_["default_value"]; + } + + // Declare the field itself. + printer->Print( + variables_, + "private $type_name$ $name_def_message$;\n"); + + WritePropertyDocComment(printer, descriptor_); + AddPublicMemberAttributes(printer); + + // Most of the work is done in the property: + // Declare the property itself (the same for all options) + printer->Print(variables_, "$access_level$ $type_name$ $property_name$ {\n"); + + // Specify the "getter", which may need to check for a presence field. + if (SupportsPresenceApi(descriptor_)) { + if (IsNullable(descriptor_)) { + printer->Print( + variables_, + " get { return $name$_ ?? $default_value_access$; }\n"); + } else { + printer->Print( + variables_, + // Note: it's possible that this could be rewritten as a + // conditional ?: expression, but there's no significant benefit + // to changing it. + " get { if ($has_field_check$) { return $name$_; } else { return $default_value_access$; } }\n"); + } + } else { + printer->Print( + variables_, + " get { return $name$_; }\n"); + } + + // Specify the "setter", which may need to set a field bit as well as the + // value. + printer->Print(" set {\n"); + if (presenceIndex_ != -1) { + printer->Print( + variables_, + " $set_has_field$;\n"); + } + if (is_value_type) { + printer->Print( + variables_, + " $name$_ = value;\n"); + } else { + printer->Print( + variables_, + " $name$_ = pb::ProtoPreconditions.CheckNotNull(value, \"value\");\n"); + } + printer->Print( + " }\n" + "}\n"); + + // The "HasFoo" property, where required. + if (SupportsPresenceApi(descriptor_)) { + printer->Print(variables_, + "/// <summary>Gets whether the \"$descriptor_name$\" field is set</summary>\n"); + AddPublicMemberAttributes(printer); + printer->Print( + variables_, + "$access_level$ bool Has$property_name$ {\n" + " get { return "); + if (IsNullable(descriptor_)) { + printer->Print( + variables_, + "$name$_ != null; }\n}\n"); + } else { + printer->Print( + variables_, + "$has_field_check$; }\n}\n"); + } + } + + // The "ClearFoo" method, where required. + if (SupportsPresenceApi(descriptor_)) { + printer->Print(variables_, + "/// <summary>Clears the value of the \"$descriptor_name$\" field</summary>\n"); + AddPublicMemberAttributes(printer); + printer->Print( + variables_, + "$access_level$ void Clear$property_name$() {\n"); + if (IsNullable(descriptor_)) { + printer->Print(variables_, " $name$_ = null;\n"); + } else { + printer->Print(variables_, " $clear_has_field$;\n"); + } + printer->Print("}\n"); + } +} + +void PrimitiveFieldGenerator::GenerateMergingCode(io::Printer* printer) { + printer->Print( + variables_, + "if ($other_has_property_check$) {\n" + " $property_name$ = other.$property_name$;\n" + "}\n"); +} + +void PrimitiveFieldGenerator::GenerateParsingCode(io::Printer* printer) { + // Note: invoke the property setter rather than writing straight to the field, + // so that we can normalize "null to empty" for strings and bytes. + printer->Print( + variables_, + "$property_name$ = input.Read$capitalized_type_name$();\n"); +} + +void PrimitiveFieldGenerator::GenerateSerializationCode(io::Printer* printer) { + printer->Print( + variables_, + "if ($has_property_check$) {\n" + " output.WriteRawTag($tag_bytes$);\n" + " output.Write$capitalized_type_name$($property_name$);\n" + "}\n"); +} + +void PrimitiveFieldGenerator::GenerateSerializedSizeCode(io::Printer* printer) { + printer->Print( + variables_, + "if ($has_property_check$) {\n"); + printer->Indent(); + int fixedSize = GetFixedSize(descriptor_->type()); + if (fixedSize == -1) { + printer->Print( + variables_, + "size += $tag_size$ + pb::CodedOutputStream.Compute$capitalized_type_name$Size($property_name$);\n"); + } else { + printer->Print( + "size += $tag_size$ + $fixed_size$;\n", + "fixed_size", StrCat(fixedSize), + "tag_size", variables_["tag_size"]); + } + printer->Outdent(); + printer->Print("}\n"); +} + +void PrimitiveFieldGenerator::WriteHash(io::Printer* printer) { + const char *text = "if ($has_property_check$) hash ^= $property_name$.GetHashCode();\n"; + if (descriptor_->type() == FieldDescriptor::TYPE_FLOAT) { + text = "if ($has_property_check$) hash ^= pbc::ProtobufEqualityComparers.BitwiseSingleEqualityComparer.GetHashCode($property_name$);\n"; + } else if (descriptor_->type() == FieldDescriptor::TYPE_DOUBLE) { + text = "if ($has_property_check$) hash ^= pbc::ProtobufEqualityComparers.BitwiseDoubleEqualityComparer.GetHashCode($property_name$);\n"; + } + printer->Print(variables_, text); +} +void PrimitiveFieldGenerator::WriteEquals(io::Printer* printer) { + const char *text = "if ($property_name$ != other.$property_name$) return false;\n"; + if (descriptor_->type() == FieldDescriptor::TYPE_FLOAT) { + text = "if (!pbc::ProtobufEqualityComparers.BitwiseSingleEqualityComparer.Equals($property_name$, other.$property_name$)) return false;\n"; + } else if (descriptor_->type() == FieldDescriptor::TYPE_DOUBLE) { + text = "if (!pbc::ProtobufEqualityComparers.BitwiseDoubleEqualityComparer.Equals($property_name$, other.$property_name$)) return false;\n"; + } + printer->Print(variables_, text); +} +void PrimitiveFieldGenerator::WriteToString(io::Printer* printer) { + printer->Print( + variables_, + "PrintField(\"$descriptor_name$\", $has_property_check$, $property_name$, writer);\n"); +} + +void PrimitiveFieldGenerator::GenerateCloningCode(io::Printer* printer) { + printer->Print(variables_, + "$name$_ = other.$name$_;\n"); +} + +void PrimitiveFieldGenerator::GenerateCodecCode(io::Printer* printer) { + printer->Print( + variables_, + "pb::FieldCodec.For$capitalized_type_name$($tag$, $default_value$)"); +} + +void PrimitiveFieldGenerator::GenerateExtensionCode(io::Printer* printer) { + WritePropertyDocComment(printer, descriptor_); + AddDeprecatedFlag(printer); + printer->Print( + variables_, + "$access_level$ static readonly pb::Extension<$extended_type$, $type_name$> $property_name$ =\n" + " new pb::Extension<$extended_type$, $type_name$>($number$, "); + GenerateCodecCode(printer); + printer->Print(");\n"); +} + +PrimitiveOneofFieldGenerator::PrimitiveOneofFieldGenerator( + const FieldDescriptor* descriptor, int presenceIndex, const Options *options) + : PrimitiveFieldGenerator(descriptor, presenceIndex, options) { + SetCommonOneofFieldVariables(&variables_); +} + +PrimitiveOneofFieldGenerator::~PrimitiveOneofFieldGenerator() { +} + +void PrimitiveOneofFieldGenerator::GenerateMembers(io::Printer* printer) { + WritePropertyDocComment(printer, descriptor_); + AddPublicMemberAttributes(printer); + printer->Print( + variables_, + "$access_level$ $type_name$ $property_name$ {\n" + " get { return $has_property_check$ ? ($type_name$) $oneof_name$_ : $default_value$; }\n" + " set {\n"); + if (is_value_type) { + printer->Print( + variables_, + " $oneof_name$_ = value;\n"); + } else { + printer->Print( + variables_, + " $oneof_name$_ = pb::ProtoPreconditions.CheckNotNull(value, \"value\");\n"); + } + printer->Print( + variables_, + " $oneof_name$Case_ = $oneof_property_name$OneofCase.$property_name$;\n" + " }\n" + "}\n"); + if (SupportsPresenceApi(descriptor_)) { + printer->Print( + variables_, + "/// <summary>Gets whether the \"$descriptor_name$\" field is set</summary>\n"); + AddPublicMemberAttributes(printer); + printer->Print( + variables_, + "$access_level$ bool Has$property_name$ {\n" + " get { return $oneof_name$Case_ == $oneof_property_name$OneofCase.$property_name$; }\n" + "}\n"); + printer->Print( + variables_, + "/// <summary> Clears the value of the oneof if it's currently set to \"$descriptor_name$\" </summary>\n"); + AddPublicMemberAttributes(printer); + printer->Print( + variables_, + "$access_level$ void Clear$property_name$() {\n" + " if ($has_property_check$) {\n" + " Clear$oneof_property_name$();\n" + " }\n" + "}\n"); + } +} + +void PrimitiveOneofFieldGenerator::GenerateMergingCode(io::Printer* printer) { + printer->Print(variables_, "$property_name$ = other.$property_name$;\n"); +} + +void PrimitiveOneofFieldGenerator::WriteToString(io::Printer* printer) { + printer->Print(variables_, + "PrintField(\"$descriptor_name$\", $has_property_check$, $oneof_name$_, writer);\n"); +} + +void PrimitiveOneofFieldGenerator::GenerateParsingCode(io::Printer* printer) { + printer->Print( + variables_, + "$property_name$ = input.Read$capitalized_type_name$();\n"); +} + +void PrimitiveOneofFieldGenerator::GenerateCloningCode(io::Printer* printer) { + printer->Print(variables_, + "$property_name$ = other.$property_name$;\n"); +} + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_primitive_field.h b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_primitive_field.h new file mode 100644 index 00000000..2386331e --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_primitive_field.h @@ -0,0 +1,97 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_PRIMITIVE_FIELD_H__ +#define GOOGLE_PROTOBUF_COMPILER_CSHARP_PRIMITIVE_FIELD_H__ + +#include <string> + +#include <compiler/code_generator.h> +#include <compiler/csharp/csharp_field_base.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +struct Options; + +class PrimitiveFieldGenerator : public FieldGeneratorBase { + public: + PrimitiveFieldGenerator(const FieldDescriptor* descriptor, + int presenceIndex, + const Options *options); + ~PrimitiveFieldGenerator(); + + PrimitiveFieldGenerator(const PrimitiveFieldGenerator&) = delete; + PrimitiveFieldGenerator& operator=(const PrimitiveFieldGenerator&) = delete; + + virtual void GenerateCodecCode(io::Printer* printer) override; + virtual void GenerateCloningCode(io::Printer* printer) override; + virtual void GenerateMembers(io::Printer* printer) override; + virtual void GenerateMergingCode(io::Printer* printer) override; + virtual void GenerateParsingCode(io::Printer* printer) override; + virtual void GenerateSerializationCode(io::Printer* printer) override; + virtual void GenerateSerializedSizeCode(io::Printer* printer) override; + virtual void GenerateExtensionCode(io::Printer* printer) override; + + virtual void WriteHash(io::Printer* printer) override; + virtual void WriteEquals(io::Printer* printer) override; + virtual void WriteToString(io::Printer* printer) override; + + protected: + bool is_value_type; +}; + +class PrimitiveOneofFieldGenerator : public PrimitiveFieldGenerator { + public: + PrimitiveOneofFieldGenerator(const FieldDescriptor* descriptor, + int presenceIndex, + const Options *options); + ~PrimitiveOneofFieldGenerator(); + + PrimitiveOneofFieldGenerator(const PrimitiveOneofFieldGenerator&) = delete; + PrimitiveOneofFieldGenerator& operator=(const PrimitiveOneofFieldGenerator&) = + delete; + + virtual void GenerateCloningCode(io::Printer* printer) override; + virtual void GenerateMembers(io::Printer* printer) override; + virtual void GenerateMergingCode(io::Printer* printer) override; + virtual void WriteToString(io::Printer* printer) override; + virtual void GenerateParsingCode(io::Printer* printer) override; +}; + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_PRIMITIVE_FIELD_H__ + diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_reflection_class.cc b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_reflection_class.cc new file mode 100644 index 00000000..5975f313 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_reflection_class.cc @@ -0,0 +1,330 @@ +// 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 <sstream> + +#include <compiler/code_generator.h> +#include <descriptor.h> +#include <descriptor.pb.h> +#include <io/printer.h> +#include <io/zero_copy_stream.h> +#include <stubs/strutil.h> + + +#include <compiler/csharp/csharp_enum.h> +#include <compiler/csharp/csharp_helpers.h> +#include <compiler/csharp/csharp_field_base.h> +#include <compiler/csharp/csharp_message.h> +#include <compiler/csharp/csharp_names.h> +#include <compiler/csharp/csharp_options.h> +#include <compiler/csharp/csharp_reflection_class.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +ReflectionClassGenerator::ReflectionClassGenerator(const FileDescriptor* file, + const Options* options) + : SourceGeneratorBase(options), + file_(file) { + namespace_ = GetFileNamespace(file); + reflectionClassname_ = GetReflectionClassUnqualifiedName(file); + extensionClassname_ = GetExtensionClassUnqualifiedName(file); +} + +ReflectionClassGenerator::~ReflectionClassGenerator() { +} + +void ReflectionClassGenerator::Generate(io::Printer* printer) { + WriteIntroduction(printer); + + WriteDescriptor(printer); + // Close the class declaration. + printer->Outdent(); + printer->Print("}\n"); + + if (file_->extension_count() > 0) { + printer->Print( + "/// <summary>Holder for extension identifiers generated from the top " + "level of $file_name$</summary>\n" + "$access_level$ static partial class $class_name$ {\n", + "access_level", class_access_level(), "class_name", extensionClassname_, + "file_name", file_->name()); + printer->Indent(); + for (int i = 0; i < file_->extension_count(); i++) { + std::unique_ptr<FieldGeneratorBase> generator( + CreateFieldGenerator(file_->extension(i), -1, this->options())); + generator->GenerateExtensionCode(printer); + } + printer->Outdent(); + printer->Print( + "}\n" + "\n"); + } + + // write children: Enums + if (file_->enum_type_count() > 0) { + printer->Print("#region Enums\n"); + for (int i = 0; i < file_->enum_type_count(); i++) { + EnumGenerator enumGenerator(file_->enum_type(i), this->options()); + enumGenerator.Generate(printer); + } + printer->Print("#endregion\n"); + printer->Print("\n"); + } + + // write children: Messages + if (file_->message_type_count() > 0) { + printer->Print("#region Messages\n"); + for (int i = 0; i < file_->message_type_count(); i++) { + MessageGenerator messageGenerator(file_->message_type(i), this->options()); + messageGenerator.Generate(printer); + } + printer->Print("#endregion\n"); + printer->Print("\n"); + } + + // TODO(jtattermusch): add insertion point for services. + + if (!namespace_.empty()) { + printer->Outdent(); + printer->Print("}\n"); + } + printer->Print("\n"); + printer->Print("#endregion Designer generated code\n"); +} + +void ReflectionClassGenerator::WriteIntroduction(io::Printer* printer) { + printer->Print( + "// <auto-generated>\n" + "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" + "// source: $file_name$\n" + "// </auto-generated>\n" + "#pragma warning disable 1591, 0612, 3021\n" + "#region Designer generated code\n" + "\n" + "using pb = global::Google.Protobuf;\n" + "using pbc = global::Google.Protobuf.Collections;\n" + "using pbr = global::Google.Protobuf.Reflection;\n" + "using scg = global::System.Collections.Generic;\n", + "file_name", file_->name()); + + if (!namespace_.empty()) { + printer->Print("namespace $namespace$ {\n", "namespace", namespace_); + printer->Indent(); + printer->Print("\n"); + } + + printer->Print( + "/// <summary>Holder for reflection information generated from $file_name$</summary>\n" + "$access_level$ static partial class $reflection_class_name$ {\n" + "\n", + "file_name", file_->name(), + "access_level", class_access_level(), + "reflection_class_name", reflectionClassname_); + printer->Indent(); +} + +void ReflectionClassGenerator::WriteDescriptor(io::Printer* printer) { + printer->Print( + "#region Descriptor\n" + "/// <summary>File descriptor for $file_name$</summary>\n" + "public static pbr::FileDescriptor Descriptor {\n" + " get { return descriptor; }\n" + "}\n" + "private static pbr::FileDescriptor descriptor;\n" + "\n" + "static $reflection_class_name$() {\n", + "file_name", file_->name(), + "reflection_class_name", reflectionClassname_); + printer->Indent(); + printer->Print( + "byte[] descriptorData = global::System.Convert.FromBase64String(\n"); + printer->Indent(); + printer->Indent(); + printer->Print("string.Concat(\n"); + printer->Indent(); + + // TODO(jonskeet): Consider a C#-escaping format here instead of just Base64. + std::string base64 = FileDescriptorToBase64(file_); + while (base64.size() > 60) { + printer->Print("\"$base64$\",\n", "base64", base64.substr(0, 60)); + base64 = base64.substr(60); + } + printer->Print("\"$base64$\"));\n", "base64", base64); + printer->Outdent(); + printer->Outdent(); + printer->Outdent(); + + // ----------------------------------------------------------------- + // Invoke InternalBuildGeneratedFileFrom() to build the file. + printer->Print( + "descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,\n"); + printer->Print(" new pbr::FileDescriptor[] { "); + for (int i = 0; i < file_->dependency_count(); i++) { + printer->Print( + "$full_reflection_class_name$.Descriptor, ", + "full_reflection_class_name", + GetReflectionClassName(file_->dependency(i))); + } + printer->Print("},\n" + " new pbr::GeneratedClrTypeInfo("); + // Specify all the generated code information, recursively. + if (file_->enum_type_count() > 0) { + printer->Print("new[] {"); + for (int i = 0; i < file_->enum_type_count(); i++) { + printer->Print("typeof($type_name$), ", "type_name", GetClassName(file_->enum_type(i))); + } + printer->Print("}, "); + } + else { + printer->Print("null, "); + } + if (file_->extension_count() > 0) { + std::vector<std::string> extensions; + for (int i = 0; i < file_->extension_count(); i++) { + extensions.push_back(GetFullExtensionName(file_->extension(i))); + } + printer->Print("new pb::Extension[] { $extensions$ }, ", "extensions", Join(extensions, ", ")); + } + else { + printer->Print("null, "); + } + if (file_->message_type_count() > 0) { + printer->Print("new pbr::GeneratedClrTypeInfo[] {\n"); + printer->Indent(); + printer->Indent(); + printer->Indent(); + for (int i = 0; i < file_->message_type_count(); i++) { + WriteGeneratedCodeInfo(file_->message_type(i), printer, i == file_->message_type_count() - 1); + } + printer->Outdent(); + printer->Print("\n}));\n"); + printer->Outdent(); + printer->Outdent(); + } + else { + printer->Print("null));\n"); + } + + printer->Outdent(); + printer->Print("}\n"); + printer->Print("#endregion\n\n"); +} + +// Write out the generated code for a particular message. This consists of the CLR type, property names +// corresponding to fields, names corresponding to oneofs, nested enums, and nested types. Each array part +// can be specified as null if it would be empty, to make the generated code somewhat simpler to read. +// We write a line break at the end of each generated code info, so that in the final file we'll see all +// the types, pre-ordered depth first, one per line. The indentation will be slightly unusual, +// in that it will look like a single array when it's actually constructing a tree, but it'll be easy to +// read even with multiple levels of nesting. +// The "last" parameter indicates whether this message descriptor is the last one being printed in this immediate +// context. It governs whether or not a trailing comma and newline is written after the constructor, effectively +// just controlling the formatting in the generated code. +void ReflectionClassGenerator::WriteGeneratedCodeInfo(const Descriptor* descriptor, io::Printer* printer, bool last) { + if (IsMapEntryMessage(descriptor)) { + printer->Print("null, "); + return; + } + // Generated message type + printer->Print("new pbr::GeneratedClrTypeInfo(typeof($type_name$), $type_name$.Parser, ", "type_name", GetClassName(descriptor)); + + // Fields + if (descriptor->field_count() > 0) { + std::vector<std::string> fields; + fields.reserve(descriptor->field_count()); + for (int i = 0; i < descriptor->field_count(); i++) { + fields.push_back(GetPropertyName(descriptor->field(i))); + } + printer->Print("new[]{ \"$fields$\" }, ", "fields", Join(fields, "\", \"")); + } + else { + printer->Print("null, "); + } + + // Oneofs + if (descriptor->oneof_decl_count() > 0) { + std::vector<std::string> oneofs; + oneofs.reserve(descriptor->oneof_decl_count()); + for (int i = 0; i < descriptor->oneof_decl_count(); i++) { + oneofs.push_back(UnderscoresToCamelCase(descriptor->oneof_decl(i)->name(), true)); + } + printer->Print("new[]{ \"$oneofs$\" }, ", "oneofs", Join(oneofs, "\", \"")); + } + else { + printer->Print("null, "); + } + + // Nested enums + if (descriptor->enum_type_count() > 0) { + std::vector<std::string> enums; + enums.reserve(descriptor->enum_type_count()); + for (int i = 0; i < descriptor->enum_type_count(); i++) { + enums.push_back(GetClassName(descriptor->enum_type(i))); + } + printer->Print("new[]{ typeof($enums$) }, ", "enums", Join(enums, "), typeof(")); + } + else { + printer->Print("null, "); + } + + // Extensions + if (descriptor->extension_count() > 0) { + std::vector<std::string> extensions; + for (int i = 0; i < descriptor->extension_count(); i++) { + extensions.push_back(GetFullExtensionName(descriptor->extension(i))); + } + printer->Print("new pb::Extension[] { $extensions$ }, ", "extensions", Join(extensions, ", ")); + } + else { + printer->Print("null, "); + } + + // Nested types + if (descriptor->nested_type_count() > 0) { + // Need to specify array type explicitly here, as all elements may be null. + printer->Print("new pbr::GeneratedClrTypeInfo[] { "); + for (int i = 0; i < descriptor->nested_type_count(); i++) { + WriteGeneratedCodeInfo(descriptor->nested_type(i), printer, i == descriptor->nested_type_count() - 1); + } + printer->Print("}"); + } + else { + printer->Print("null"); + } + printer->Print(last ? ")" : "),\n"); +} + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_reflection_class.h b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_reflection_class.h new file mode 100644 index 00000000..4834708b --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_reflection_class.h @@ -0,0 +1,75 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_REFLECTION_CLASS_H__ +#define GOOGLE_PROTOBUF_COMPILER_CSHARP_REFLECTION_CLASS_H__ + +#include <string> + +#include <compiler/code_generator.h> +#include <compiler/csharp/csharp_source_generator_base.h> +#include <descriptor.h> +#include <io/printer.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +class ReflectionClassGenerator : public SourceGeneratorBase { + public: + ReflectionClassGenerator(const FileDescriptor* file, const Options* options); + ~ReflectionClassGenerator(); + + ReflectionClassGenerator(const ReflectionClassGenerator&) = delete; + ReflectionClassGenerator& operator=(const ReflectionClassGenerator&) = delete; + + void Generate(io::Printer* printer); + + private: + const FileDescriptor* file_; + + std::string namespace_; + std::string reflectionClassname_; + std::string extensionClassname_; + + void WriteIntroduction(io::Printer* printer); + void WriteDescriptor(io::Printer* printer); + void WriteGeneratedCodeInfo(const Descriptor* descriptor, + io::Printer* printer, + bool last); +}; + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_REFLECTION_CLASS_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_repeated_enum_field.cc b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_repeated_enum_field.cc new file mode 100644 index 00000000..57e83266 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_repeated_enum_field.cc @@ -0,0 +1,148 @@ +// 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 <sstream> + +#include <compiler/code_generator.h> +#include <descriptor.h> +#include <descriptor.pb.h> +#include <io/printer.h> +#include <io/zero_copy_stream.h> +#include <wire_format.h> + +#include <compiler/csharp/csharp_doc_comment.h> +#include <compiler/csharp/csharp_helpers.h> +#include <compiler/csharp/csharp_repeated_enum_field.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +RepeatedEnumFieldGenerator::RepeatedEnumFieldGenerator( + const FieldDescriptor* descriptor, int presenceIndex, const Options *options) + : FieldGeneratorBase(descriptor, presenceIndex, options) { +} + +RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() { + +} + +void RepeatedEnumFieldGenerator::GenerateMembers(io::Printer* printer) { + printer->Print( + variables_, + "private static readonly pb::FieldCodec<$type_name$> _repeated_$name$_codec\n" + " = pb::FieldCodec.ForEnum($tag$, x => (int) x, x => ($type_name$) x);\n"); + printer->Print(variables_, + "private readonly pbc::RepeatedField<$type_name$> $name$_ = new pbc::RepeatedField<$type_name$>();\n"); + WritePropertyDocComment(printer, descriptor_); + AddPublicMemberAttributes(printer); + printer->Print( + variables_, + "$access_level$ pbc::RepeatedField<$type_name$> $property_name$ {\n" + " get { return $name$_; }\n" + "}\n"); +} + +void RepeatedEnumFieldGenerator::GenerateMergingCode(io::Printer* printer) { + printer->Print( + variables_, + "$name$_.Add(other.$name$_);\n"); +} + +void RepeatedEnumFieldGenerator::GenerateParsingCode(io::Printer* printer) { + GenerateParsingCode(printer, true); +} + +void RepeatedEnumFieldGenerator::GenerateParsingCode(io::Printer* printer, bool use_parse_context) { + printer->Print( + variables_, + use_parse_context + ? "$name$_.AddEntriesFrom(ref input, _repeated_$name$_codec);\n" + : "$name$_.AddEntriesFrom(input, _repeated_$name$_codec);\n"); +} + +void RepeatedEnumFieldGenerator::GenerateSerializationCode(io::Printer* printer) { + GenerateSerializationCode(printer, true); +} + +void RepeatedEnumFieldGenerator::GenerateSerializationCode(io::Printer* printer, bool use_write_context) { + printer->Print( + variables_, + use_write_context + ? "$name$_.WriteTo(ref output, _repeated_$name$_codec);\n" + : "$name$_.WriteTo(output, _repeated_$name$_codec);\n"); +} + +void RepeatedEnumFieldGenerator::GenerateSerializedSizeCode(io::Printer* printer) { + printer->Print( + variables_, + "size += $name$_.CalculateSize(_repeated_$name$_codec);\n"); +} + +void RepeatedEnumFieldGenerator::WriteHash(io::Printer* printer) { + printer->Print( + variables_, + "hash ^= $name$_.GetHashCode();\n"); +} + +void RepeatedEnumFieldGenerator::WriteEquals(io::Printer* printer) { + printer->Print( + variables_, + "if(!$name$_.Equals(other.$name$_)) return false;\n"); +} + +void RepeatedEnumFieldGenerator::WriteToString(io::Printer* printer) { + printer->Print(variables_, + "PrintField(\"$descriptor_name$\", $name$_, writer);\n"); +} + +void RepeatedEnumFieldGenerator::GenerateCloningCode(io::Printer* printer) { + printer->Print(variables_, + "$name$_ = other.$name$_.Clone();\n"); +} + +void RepeatedEnumFieldGenerator::GenerateExtensionCode(io::Printer* printer) { + WritePropertyDocComment(printer, descriptor_); + AddDeprecatedFlag(printer); + printer->Print( + variables_, + "$access_level$ static readonly pb::RepeatedExtension<$extended_type$, $type_name$> $property_name$ =\n" + " new pb::RepeatedExtension<$extended_type$, $type_name$>($number$, " + "pb::FieldCodec.ForEnum($tag$, x => (int) x, x => ($type_name$) x));\n"); +} + +void RepeatedEnumFieldGenerator::GenerateFreezingCode(io::Printer* printer) { +} + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_repeated_enum_field.h b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_repeated_enum_field.h new file mode 100644 index 00000000..cce82868 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_repeated_enum_field.h @@ -0,0 +1,79 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_REPEATED_ENUM_FIELD_H__ +#define GOOGLE_PROTOBUF_COMPILER_CSHARP_REPEATED_ENUM_FIELD_H__ + +#include <string> + +#include <compiler/code_generator.h> +#include <compiler/csharp/csharp_field_base.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +// TODO(jonskeet): Refactor repeated field support; all the implementations are +// *really* similar. We should probably have a RepeatedFieldGeneratorBase. +class RepeatedEnumFieldGenerator : public FieldGeneratorBase { + public: + RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor, + int presenceIndex, + const Options *options); + ~RepeatedEnumFieldGenerator(); + + RepeatedEnumFieldGenerator(const RepeatedEnumFieldGenerator&) = delete; + RepeatedEnumFieldGenerator& operator=(const RepeatedEnumFieldGenerator&) = + delete; + + virtual void GenerateCloningCode(io::Printer* printer) override; + virtual void GenerateFreezingCode(io::Printer* printer) override; + virtual void GenerateMembers(io::Printer* printer) override; + virtual void GenerateMergingCode(io::Printer* printer) override; + virtual void GenerateParsingCode(io::Printer* printer) override; + virtual void GenerateParsingCode(io::Printer* printer, bool use_parse_context) override; + virtual void GenerateSerializationCode(io::Printer* printer) override; + virtual void GenerateSerializationCode(io::Printer* printer, bool use_write_context) override; + virtual void GenerateSerializedSizeCode(io::Printer* printer) override; + virtual void GenerateExtensionCode(io::Printer* printer) override; + + virtual void WriteHash(io::Printer* printer) override; + virtual void WriteEquals(io::Printer* printer) override; + virtual void WriteToString(io::Printer* printer) override; +}; + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_REPEATED_ENUM_FIELD_H__ + diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_repeated_message_field.cc b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_repeated_message_field.cc new file mode 100644 index 00000000..bd2c22a3 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_repeated_message_field.cc @@ -0,0 +1,174 @@ +// 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 <sstream> + +#include <compiler/code_generator.h> +#include <descriptor.h> +#include <descriptor.pb.h> +#include <io/printer.h> +#include <io/zero_copy_stream.h> + +#include <compiler/csharp/csharp_doc_comment.h> +#include <compiler/csharp/csharp_helpers.h> +#include <compiler/csharp/csharp_repeated_message_field.h> +#include <compiler/csharp/csharp_message_field.h> +#include <compiler/csharp/csharp_wrapper_field.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +RepeatedMessageFieldGenerator::RepeatedMessageFieldGenerator( + const FieldDescriptor* descriptor, int presenceIndex, const Options *options) + : FieldGeneratorBase(descriptor, presenceIndex, options) { +} + +RepeatedMessageFieldGenerator::~RepeatedMessageFieldGenerator() { + +} + +void RepeatedMessageFieldGenerator::GenerateMembers(io::Printer* printer) { + printer->Print( + variables_, + "private static readonly pb::FieldCodec<$type_name$> _repeated_$name$_codec\n" + " = "); + // Don't want to duplicate the codec code here... maybe we should have a + // "create single field generator for this repeated field" + // function, but it doesn't seem worth it for just this. + if (IsWrapperType(descriptor_)) { + std::unique_ptr<FieldGeneratorBase> single_generator( + new WrapperFieldGenerator(descriptor_, presenceIndex_, this->options())); + single_generator->GenerateCodecCode(printer); + } else { + std::unique_ptr<FieldGeneratorBase> single_generator( + new MessageFieldGenerator(descriptor_, presenceIndex_, this->options())); + single_generator->GenerateCodecCode(printer); + } + printer->Print(";\n"); + printer->Print( + variables_, + "private readonly pbc::RepeatedField<$type_name$> $name$_ = new pbc::RepeatedField<$type_name$>();\n"); + WritePropertyDocComment(printer, descriptor_); + AddPublicMemberAttributes(printer); + printer->Print( + variables_, + "$access_level$ pbc::RepeatedField<$type_name$> $property_name$ {\n" + " get { return $name$_; }\n" + "}\n"); +} + +void RepeatedMessageFieldGenerator::GenerateMergingCode(io::Printer* printer) { + printer->Print( + variables_, + "$name$_.Add(other.$name$_);\n"); +} + +void RepeatedMessageFieldGenerator::GenerateParsingCode(io::Printer* printer) { + GenerateParsingCode(printer, true); +} + +void RepeatedMessageFieldGenerator::GenerateParsingCode(io::Printer* printer, bool use_parse_context) { + printer->Print( + variables_, + use_parse_context + ? "$name$_.AddEntriesFrom(ref input, _repeated_$name$_codec);\n" + : "$name$_.AddEntriesFrom(input, _repeated_$name$_codec);\n"); +} + +void RepeatedMessageFieldGenerator::GenerateSerializationCode(io::Printer* printer) { + GenerateSerializationCode(printer, true); +} + +void RepeatedMessageFieldGenerator::GenerateSerializationCode(io::Printer* printer, bool use_write_context) { + printer->Print( + variables_, + use_write_context + ? "$name$_.WriteTo(ref output, _repeated_$name$_codec);\n" + : "$name$_.WriteTo(output, _repeated_$name$_codec);\n"); +} + +void RepeatedMessageFieldGenerator::GenerateSerializedSizeCode(io::Printer* printer) { + printer->Print( + variables_, + "size += $name$_.CalculateSize(_repeated_$name$_codec);\n"); +} + +void RepeatedMessageFieldGenerator::WriteHash(io::Printer* printer) { + printer->Print( + variables_, + "hash ^= $name$_.GetHashCode();\n"); +} + +void RepeatedMessageFieldGenerator::WriteEquals(io::Printer* printer) { + printer->Print( + variables_, + "if(!$name$_.Equals(other.$name$_)) return false;\n"); +} + +void RepeatedMessageFieldGenerator::WriteToString(io::Printer* printer) { + variables_["field_name"] = GetFieldName(descriptor_); + printer->Print( + variables_, + "PrintField(\"$field_name$\", $name$_, writer);\n"); +} + +void RepeatedMessageFieldGenerator::GenerateCloningCode(io::Printer* printer) { + printer->Print(variables_, + "$name$_ = other.$name$_.Clone();\n"); +} + +void RepeatedMessageFieldGenerator::GenerateFreezingCode(io::Printer* printer) { +} + +void RepeatedMessageFieldGenerator::GenerateExtensionCode(io::Printer* printer) { + WritePropertyDocComment(printer, descriptor_); + AddDeprecatedFlag(printer); + printer->Print( + variables_, + "$access_level$ static readonly pb::RepeatedExtension<$extended_type$, $type_name$> $property_name$ =\n" + " new pb::RepeatedExtension<$extended_type$, $type_name$>($number$, "); + if (IsWrapperType(descriptor_)) { + std::unique_ptr<FieldGeneratorBase> single_generator( + new WrapperFieldGenerator(descriptor_, -1, this->options())); + single_generator->GenerateCodecCode(printer); + } else { + std::unique_ptr<FieldGeneratorBase> single_generator( + new MessageFieldGenerator(descriptor_, -1, this->options())); + single_generator->GenerateCodecCode(printer); + } + printer->Print(");\n"); +} + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_repeated_message_field.h b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_repeated_message_field.h new file mode 100644 index 00000000..dc975888 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_repeated_message_field.h @@ -0,0 +1,79 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_REPEATED_MESSAGE_FIELD_H__ +#define GOOGLE_PROTOBUF_COMPILER_CSHARP_REPEATED_MESSAGE_FIELD_H__ + +#include <string> + +#include <compiler/code_generator.h> +#include <compiler/csharp/csharp_field_base.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +struct Options; + +class RepeatedMessageFieldGenerator : public FieldGeneratorBase { + public: + RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor, + int presenceIndex, + const Options *options); + ~RepeatedMessageFieldGenerator(); + + RepeatedMessageFieldGenerator(const RepeatedMessageFieldGenerator&) = delete; + RepeatedMessageFieldGenerator& operator=( + const RepeatedMessageFieldGenerator&) = delete; + + virtual void GenerateCloningCode(io::Printer* printer) override; + virtual void GenerateFreezingCode(io::Printer* printer) override; + virtual void GenerateMembers(io::Printer* printer) override; + virtual void GenerateMergingCode(io::Printer* printer) override; + virtual void GenerateParsingCode(io::Printer* printer) override; + virtual void GenerateParsingCode(io::Printer* printer, bool use_parse_context) override; + virtual void GenerateSerializationCode(io::Printer* printer) override; + virtual void GenerateSerializationCode(io::Printer* printer, bool use_write_context) override; + virtual void GenerateSerializedSizeCode(io::Printer* printer) override; + virtual void GenerateExtensionCode(io::Printer* printer) override; + + virtual void WriteHash(io::Printer* printer) override; + virtual void WriteEquals(io::Printer* printer) override; + virtual void WriteToString(io::Printer* printer) override; +}; + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_REPEATED_MESSAGE_FIELD_H__ + diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc new file mode 100644 index 00000000..6df3edc5 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc @@ -0,0 +1,145 @@ +// 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 <sstream> + +#include <compiler/code_generator.h> +#include <descriptor.h> +#include <descriptor.pb.h> +#include <io/printer.h> +#include <io/zero_copy_stream.h> +#include <wire_format.h> + +#include <compiler/csharp/csharp_doc_comment.h> +#include <compiler/csharp/csharp_helpers.h> +#include <compiler/csharp/csharp_repeated_primitive_field.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +RepeatedPrimitiveFieldGenerator::RepeatedPrimitiveFieldGenerator( + const FieldDescriptor* descriptor, int presenceIndex, const Options *options) + : FieldGeneratorBase(descriptor, presenceIndex, options) { +} + +RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() { + +} + +void RepeatedPrimitiveFieldGenerator::GenerateMembers(io::Printer* printer) { + printer->Print( + variables_, + "private static readonly pb::FieldCodec<$type_name$> _repeated_$name$_codec\n" + " = pb::FieldCodec.For$capitalized_type_name$($tag$);\n"); + printer->Print(variables_, + "private readonly pbc::RepeatedField<$type_name$> $name$_ = new pbc::RepeatedField<$type_name$>();\n"); + WritePropertyDocComment(printer, descriptor_); + AddPublicMemberAttributes(printer); + printer->Print( + variables_, + "$access_level$ pbc::RepeatedField<$type_name$> $property_name$ {\n" + " get { return $name$_; }\n" + "}\n"); +} + +void RepeatedPrimitiveFieldGenerator::GenerateMergingCode(io::Printer* printer) { + printer->Print( + variables_, + "$name$_.Add(other.$name$_);\n"); +} + +void RepeatedPrimitiveFieldGenerator::GenerateParsingCode(io::Printer* printer) { + GenerateParsingCode(printer, true); +} + +void RepeatedPrimitiveFieldGenerator::GenerateParsingCode(io::Printer* printer, bool use_parse_context) { + printer->Print( + variables_, + use_parse_context + ? "$name$_.AddEntriesFrom(ref input, _repeated_$name$_codec);\n" + : "$name$_.AddEntriesFrom(input, _repeated_$name$_codec);\n"); +} + +void RepeatedPrimitiveFieldGenerator::GenerateSerializationCode(io::Printer* printer) { + GenerateSerializationCode(printer, true); +} + +void RepeatedPrimitiveFieldGenerator::GenerateSerializationCode(io::Printer* printer, bool use_write_context) { + printer->Print( + variables_, + use_write_context + ? "$name$_.WriteTo(ref output, _repeated_$name$_codec);\n" + : "$name$_.WriteTo(output, _repeated_$name$_codec);\n"); +} + +void RepeatedPrimitiveFieldGenerator::GenerateSerializedSizeCode(io::Printer* printer) { + printer->Print( + variables_, + "size += $name$_.CalculateSize(_repeated_$name$_codec);\n"); +} + +void RepeatedPrimitiveFieldGenerator::WriteHash(io::Printer* printer) { + printer->Print( + variables_, + "hash ^= $name$_.GetHashCode();\n"); +} +void RepeatedPrimitiveFieldGenerator::WriteEquals(io::Printer* printer) { + printer->Print( + variables_, + "if(!$name$_.Equals(other.$name$_)) return false;\n"); +} +void RepeatedPrimitiveFieldGenerator::WriteToString(io::Printer* printer) { + printer->Print(variables_, + "PrintField(\"$descriptor_name$\", $name$_, writer);\n"); +} + +void RepeatedPrimitiveFieldGenerator::GenerateCloningCode(io::Printer* printer) { + printer->Print(variables_, + "$name$_ = other.$name$_.Clone();\n"); +} + +void RepeatedPrimitiveFieldGenerator::GenerateFreezingCode(io::Printer* printer) { +} + +void RepeatedPrimitiveFieldGenerator::GenerateExtensionCode(io::Printer* printer) { + WritePropertyDocComment(printer, descriptor_); + AddDeprecatedFlag(printer); + printer->Print( + variables_, + "$access_level$ static readonly pb::RepeatedExtension<$extended_type$, $type_name$> $property_name$ =\n" + " new pb::RepeatedExtension<$extended_type$, $type_name$>($number$, pb::FieldCodec.For$capitalized_type_name$($tag$));\n"); +} + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_repeated_primitive_field.h b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_repeated_primitive_field.h new file mode 100644 index 00000000..83bb41f2 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_repeated_primitive_field.h @@ -0,0 +1,75 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_REPEATED_PRIMITIVE_FIELD_H__ +#define GOOGLE_PROTOBUF_COMPILER_CSHARP_REPEATED_PRIMITIVE_FIELD_H__ + +#include <string> + +#include <compiler/code_generator.h> +#include <compiler/csharp/csharp_field_base.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +class RepeatedPrimitiveFieldGenerator : public FieldGeneratorBase { + public: + RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor, + int presenceIndex, const Options* options); + ~RepeatedPrimitiveFieldGenerator(); + + RepeatedPrimitiveFieldGenerator(const RepeatedPrimitiveFieldGenerator&) = delete; + RepeatedPrimitiveFieldGenerator& operator=(const RepeatedPrimitiveFieldGenerator&) = delete; + + virtual void GenerateCloningCode(io::Printer* printer) override; + virtual void GenerateFreezingCode(io::Printer* printer) override; + virtual void GenerateMembers(io::Printer* printer) override; + virtual void GenerateMergingCode(io::Printer* printer) override; + virtual void GenerateParsingCode(io::Printer* printer) override; + virtual void GenerateParsingCode(io::Printer* printer, bool use_parse_context) override; + virtual void GenerateSerializationCode(io::Printer* printer) override; + virtual void GenerateSerializationCode(io::Printer* printer, bool use_write_context) override; + virtual void GenerateSerializedSizeCode(io::Printer* printer) override; + virtual void GenerateExtensionCode(io::Printer* printer) override; + + virtual void WriteHash(io::Printer* printer) override; + virtual void WriteEquals(io::Printer* printer) override; + virtual void WriteToString(io::Printer* printer) override; +}; + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_REPEATED_PRIMITIVE_FIELD_H__ + diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_source_generator_base.cc b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_source_generator_base.cc new file mode 100644 index 00000000..213422ad --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_source_generator_base.cc @@ -0,0 +1,75 @@ +// 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 <sstream> + +#include <compiler/code_generator.h> +#include <descriptor.h> +#include <descriptor.pb.h> +#include <io/printer.h> +#include <io/zero_copy_stream.h> + +#include <compiler/csharp/csharp_source_generator_base.h> +#include <compiler/csharp/csharp_helpers.h> +#include <compiler/csharp/csharp_names.h> +#include <compiler/csharp/csharp_options.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +SourceGeneratorBase::SourceGeneratorBase( + const Options *options) : options_(options) { +} + +SourceGeneratorBase::~SourceGeneratorBase() { +} + +void SourceGeneratorBase::WriteGeneratedCodeAttributes(io::Printer* printer) { + printer->Print("[global::System.Diagnostics.DebuggerNonUserCodeAttribute]\n"); + // The second argument of the [GeneratedCode] attribute could be set to current protoc + // version, but that would cause excessive code churn in the pre-generated + // code in the repository every time the protobuf version number is updated. + printer->Print("[global::System.CodeDom.Compiler.GeneratedCode(\"protoc\", null)]\n"); +} + +std::string SourceGeneratorBase::class_access_level() { + return this->options()->internal_access ? "internal" : "public"; +} + +const Options* SourceGeneratorBase::options() { + return this->options_; +} + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_source_generator_base.h b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_source_generator_base.h new file mode 100644 index 00000000..b09c92b6 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_source_generator_base.h @@ -0,0 +1,71 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_SOURCE_GENERATOR_BASE_H__ +#define GOOGLE_PROTOBUF_COMPILER_CSHARP_SOURCE_GENERATOR_BASE_H__ + +#include <string> + +#include <compiler/code_generator.h> +#include <io/printer.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +struct Options; + +class SourceGeneratorBase { + protected: + SourceGeneratorBase(const Options* options); + virtual ~SourceGeneratorBase(); + + SourceGeneratorBase(const SourceGeneratorBase&) = delete; + SourceGeneratorBase& operator=(const SourceGeneratorBase&) = delete; + + std::string class_access_level(); + const Options* options(); + + // Write any attributes used to decorate generated function members (methods and properties). + // Should not be used to decorate types. + void WriteGeneratedCodeAttributes(io::Printer* printer); + + private: + const Options *options_; +}; + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_SOURCE_GENERATOR_BASE_H__ + diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_wrapper_field.cc b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_wrapper_field.cc new file mode 100644 index 00000000..4a45017e --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_wrapper_field.cc @@ -0,0 +1,308 @@ +// 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 <sstream> + +#include <compiler/code_generator.h> +#include <descriptor.h> +#include <descriptor.pb.h> +#include <io/printer.h> +#include <io/zero_copy_stream.h> + +#include <compiler/csharp/csharp_doc_comment.h> +#include <compiler/csharp/csharp_helpers.h> +#include <compiler/csharp/csharp_options.h> +#include <compiler/csharp/csharp_wrapper_field.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +WrapperFieldGenerator::WrapperFieldGenerator(const FieldDescriptor* descriptor, + int presenceIndex, const Options *options) + : FieldGeneratorBase(descriptor, presenceIndex, options) { + variables_["has_property_check"] = name() + "_ != null"; + variables_["has_not_property_check"] = name() + "_ == null"; + const FieldDescriptor* wrapped_field = descriptor->message_type()->field(0); + is_value_type = wrapped_field->type() != FieldDescriptor::TYPE_STRING && + wrapped_field->type() != FieldDescriptor::TYPE_BYTES; + if (is_value_type) { + variables_["nonnullable_type_name"] = type_name(wrapped_field); + } +} + +WrapperFieldGenerator::~WrapperFieldGenerator() { +} + +void WrapperFieldGenerator::GenerateMembers(io::Printer* printer) { + printer->Print( + variables_, + "private static readonly pb::FieldCodec<$type_name$> _single_$name$_codec = "); + GenerateCodecCode(printer); + printer->Print( + variables_, + ";\n" + "private $type_name$ $name$_;\n"); + WritePropertyDocComment(printer, descriptor_); + AddPublicMemberAttributes(printer); + printer->Print( + variables_, + "$access_level$ $type_name$ $property_name$ {\n" + " get { return $name$_; }\n" + " set {\n" + " $name$_ = value;\n" + " }\n" + "}\n\n"); + if (SupportsPresenceApi(descriptor_)) { + printer->Print( + variables_, + "/// <summary>Gets whether the $descriptor_name$ field is set</summary>\n"); + AddPublicMemberAttributes(printer); + printer->Print( + variables_, + "$access_level$ bool Has$property_name$ {\n" + " get { return $name$_ != null; }\n" + "}\n\n"); + printer->Print( + variables_, + "/// <summary>Clears the value of the $descriptor_name$ field</summary>\n"); + AddPublicMemberAttributes(printer); + printer->Print( + variables_, + "$access_level$ void Clear$property_name$() {\n" + " $name$_ = null;\n" + "}\n"); + } +} + +void WrapperFieldGenerator::GenerateMergingCode(io::Printer* printer) { + printer->Print( + variables_, + "if (other.$has_property_check$) {\n" + " if ($has_not_property_check$ || other.$property_name$ != $default_value$) {\n" + " $property_name$ = other.$property_name$;\n" + " }\n" + "}\n"); +} + +void WrapperFieldGenerator::GenerateParsingCode(io::Printer* printer) { + GenerateParsingCode(printer, true); +} + +void WrapperFieldGenerator::GenerateParsingCode(io::Printer* printer, bool use_parse_context) { + printer->Print( + variables_, + use_parse_context + ? "$type_name$ value = _single_$name$_codec.Read(ref input);\n" + "if ($has_not_property_check$ || value != $default_value$) {\n" + " $property_name$ = value;\n" + "}\n" + : "$type_name$ value = _single_$name$_codec.Read(input);\n" + "if ($has_not_property_check$ || value != $default_value$) {\n" + " $property_name$ = value;\n" + "}\n"); +} + +void WrapperFieldGenerator::GenerateSerializationCode(io::Printer* printer) { + GenerateSerializationCode(printer, true); +} + +void WrapperFieldGenerator::GenerateSerializationCode(io::Printer* printer, bool use_write_context) { + printer->Print( + variables_, + use_write_context + ? "if ($has_property_check$) {\n" + " _single_$name$_codec.WriteTagAndValue(ref output, $property_name$);\n" + "}\n" + : "if ($has_property_check$) {\n" + " _single_$name$_codec.WriteTagAndValue(output, $property_name$);\n" + "}\n"); +} + +void WrapperFieldGenerator::GenerateSerializedSizeCode(io::Printer* printer) { + printer->Print( + variables_, + "if ($has_property_check$) {\n" + " size += _single_$name$_codec.CalculateSizeWithTag($property_name$);\n" + "}\n"); +} + +void WrapperFieldGenerator::WriteHash(io::Printer* printer) { + const char *text = "if ($has_property_check$) hash ^= $property_name$.GetHashCode();\n"; + if (descriptor_->message_type()->field(0)->type() == FieldDescriptor::TYPE_FLOAT) { + text = "if ($has_property_check$) hash ^= pbc::ProtobufEqualityComparers.BitwiseNullableSingleEqualityComparer.GetHashCode($property_name$);\n"; + } + else if (descriptor_->message_type()->field(0)->type() == FieldDescriptor::TYPE_DOUBLE) { + text = "if ($has_property_check$) hash ^= pbc::ProtobufEqualityComparers.BitwiseNullableDoubleEqualityComparer.GetHashCode($property_name$);\n"; + } + printer->Print(variables_, text); +} + +void WrapperFieldGenerator::WriteEquals(io::Printer* printer) { + const char *text = "if ($property_name$ != other.$property_name$) return false;\n"; + if (descriptor_->message_type()->field(0)->type() == FieldDescriptor::TYPE_FLOAT) { + text = "if (!pbc::ProtobufEqualityComparers.BitwiseNullableSingleEqualityComparer.Equals($property_name$, other.$property_name$)) return false;\n"; + } + else if (descriptor_->message_type()->field(0)->type() == FieldDescriptor::TYPE_DOUBLE) { + text = "if (!pbc::ProtobufEqualityComparers.BitwiseNullableDoubleEqualityComparer.Equals($property_name$, other.$property_name$)) return false;\n"; + } + printer->Print(variables_, text); +} + +void WrapperFieldGenerator::WriteToString(io::Printer* printer) { + // TODO: Implement if we ever actually need it... +} + +void WrapperFieldGenerator::GenerateCloningCode(io::Printer* printer) { + printer->Print(variables_, + "$property_name$ = other.$property_name$;\n"); +} + +void WrapperFieldGenerator::GenerateCodecCode(io::Printer* printer) { + if (is_value_type) { + printer->Print( + variables_, + "pb::FieldCodec.ForStructWrapper<$nonnullable_type_name$>($tag$)"); + } else { + printer->Print( + variables_, + "pb::FieldCodec.ForClassWrapper<$type_name$>($tag$)"); + } +} + +void WrapperFieldGenerator::GenerateExtensionCode(io::Printer* printer) { + WritePropertyDocComment(printer, descriptor_); + AddDeprecatedFlag(printer); + printer->Print( + variables_, + "$access_level$ static readonly pb::Extension<$extended_type$, $type_name$> $property_name$ =\n" + " new pb::Extension<$extended_type$, $type_name$>($number$, "); + GenerateCodecCode(printer); + printer->Print(");\n"); +} + +WrapperOneofFieldGenerator::WrapperOneofFieldGenerator( + const FieldDescriptor* descriptor, int presenceIndex, const Options *options) + : WrapperFieldGenerator(descriptor, presenceIndex, options) { + SetCommonOneofFieldVariables(&variables_); +} + +WrapperOneofFieldGenerator::~WrapperOneofFieldGenerator() { +} + +void WrapperOneofFieldGenerator::GenerateMembers(io::Printer* printer) { + // Note: deliberately _oneof_$name$_codec, not _$oneof_name$_codec... we have one codec per field. + printer->Print( + variables_, + "private static readonly pb::FieldCodec<$type_name$> _oneof_$name$_codec = "); + GenerateCodecCode(printer); + printer->Print(";\n"); + WritePropertyDocComment(printer, descriptor_); + AddPublicMemberAttributes(printer); + printer->Print( + variables_, + "$access_level$ $type_name$ $property_name$ {\n" + " get { return $has_property_check$ ? ($type_name$) $oneof_name$_ : ($type_name$) null; }\n" + " set {\n" + " $oneof_name$_ = value;\n" + " $oneof_name$Case_ = value == null ? $oneof_property_name$OneofCase.None : $oneof_property_name$OneofCase.$property_name$;\n" + " }\n" + "}\n"); + if (SupportsPresenceApi(descriptor_)) { + printer->Print( + variables_, + "/// <summary>Gets whether the \"$descriptor_name$\" field is set</summary>\n"); + AddPublicMemberAttributes(printer); + printer->Print( + variables_, + "$access_level$ bool Has$property_name$ {\n" + " get { return $oneof_name$Case_ == $oneof_property_name$OneofCase.$property_name$; }\n" + "}\n"); + printer->Print( + variables_, + "/// <summary> Clears the value of the oneof if it's currently set to \"$descriptor_name$\" </summary>\n"); + AddPublicMemberAttributes(printer); + printer->Print( + variables_, + "$access_level$ void Clear$property_name$() {\n" + " if ($has_property_check$) {\n" + " Clear$oneof_property_name$();\n" + " }\n" + "}\n"); + } +} + +void WrapperOneofFieldGenerator::GenerateMergingCode(io::Printer* printer) { + printer->Print(variables_, "$property_name$ = other.$property_name$;\n"); +} + +void WrapperOneofFieldGenerator::GenerateParsingCode(io::Printer* printer) { + GenerateParsingCode(printer, true); +} + +void WrapperOneofFieldGenerator::GenerateParsingCode(io::Printer* printer, bool use_parse_context) { + printer->Print( + variables_, + use_parse_context + ? "$property_name$ = _oneof_$name$_codec.Read(ref input);\n" + : "$property_name$ = _oneof_$name$_codec.Read(input);\n"); +} + +void WrapperOneofFieldGenerator::GenerateSerializationCode(io::Printer* printer) { + GenerateSerializationCode(printer, true); +} + +void WrapperOneofFieldGenerator::GenerateSerializationCode(io::Printer* printer, bool use_write_context) { + // TODO: I suspect this is wrong... + printer->Print( + variables_, + use_write_context + ? "if ($has_property_check$) {\n" + " _oneof_$name$_codec.WriteTagAndValue(ref output, ($type_name$) $oneof_name$_);\n" + "}\n" + : "if ($has_property_check$) {\n" + " _oneof_$name$_codec.WriteTagAndValue(output, ($type_name$) $oneof_name$_);\n" + "}\n"); +} + +void WrapperOneofFieldGenerator::GenerateSerializedSizeCode(io::Printer* printer) { + // TODO: I suspect this is wrong... + printer->Print( + variables_, + "if ($has_property_check$) {\n" + " size += _oneof_$name$_codec.CalculateSizeWithTag($property_name$);\n" + "}\n"); +} + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_wrapper_field.h b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_wrapper_field.h new file mode 100644 index 00000000..86d5b7fc --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/csharp/csharp_wrapper_field.h @@ -0,0 +1,99 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_WRAPPER_FIELD_H__ +#define GOOGLE_PROTOBUF_COMPILER_CSHARP_WRAPPER_FIELD_H__ + +#include <string> + +#include <compiler/code_generator.h> +#include <compiler/csharp/csharp_field_base.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +struct Options; + +class WrapperFieldGenerator : public FieldGeneratorBase { + public: + WrapperFieldGenerator(const FieldDescriptor* descriptor, + int presenceIndex, + const Options *options); + ~WrapperFieldGenerator(); + + WrapperFieldGenerator(const WrapperFieldGenerator&) = delete; + WrapperFieldGenerator& operator=(const WrapperFieldGenerator&) = delete; + + virtual void GenerateCodecCode(io::Printer* printer) override; + virtual void GenerateCloningCode(io::Printer* printer) override; + virtual void GenerateMembers(io::Printer* printer) override; + virtual void GenerateMergingCode(io::Printer* printer) override; + virtual void GenerateParsingCode(io::Printer* printer) override; + virtual void GenerateParsingCode(io::Printer* printer, bool use_parse_context) override; + virtual void GenerateSerializationCode(io::Printer* printer) override; + virtual void GenerateSerializationCode(io::Printer* printer, bool use_write_context) override; + virtual void GenerateSerializedSizeCode(io::Printer* printer) override; + virtual void GenerateExtensionCode(io::Printer* printer) override; + + virtual void WriteHash(io::Printer* printer) override; + virtual void WriteEquals(io::Printer* printer) override; + virtual void WriteToString(io::Printer* printer) override; + + private: + bool is_value_type; // True for int32 etc; false for bytes and string +}; + +class WrapperOneofFieldGenerator : public WrapperFieldGenerator { + public: + WrapperOneofFieldGenerator(const FieldDescriptor* descriptor, + int presenceIndex, + const Options *options); + ~WrapperOneofFieldGenerator(); + + WrapperOneofFieldGenerator(const WrapperOneofFieldGenerator&) = delete; + WrapperOneofFieldGenerator& operator=(const WrapperOneofFieldGenerator&) = delete; + + virtual void GenerateMembers(io::Printer* printer) override; + virtual void GenerateMergingCode(io::Printer* printer) override; + virtual void GenerateParsingCode(io::Printer* printer) override; + virtual void GenerateParsingCode(io::Printer* printer, bool use_parse_context) override; + virtual void GenerateSerializationCode(io::Printer* printer) override; + virtual void GenerateSerializationCode(io::Printer* printer, bool use_write_context) override; + virtual void GenerateSerializedSizeCode(io::Printer* printer) override; +}; + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_WRAPPER_FIELD_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/importer.cc b/NorthstarDedicatedTest/include/protobuf/compiler/importer.cc new file mode 100644 index 00000000..e2e6cd32 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/importer.cc @@ -0,0 +1,524 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifdef _MSC_VER +#include <direct.h> +#else +#include <unistd.h> +#endif +#include <errno.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <sys/types.h> + +#include <algorithm> +#include <memory> + +#include <compiler/importer.h> +#include <compiler/parser.h> +#include <io/tokenizer.h> +#include <io/zero_copy_stream_impl.h> +#include <stubs/strutil.h> +#include <io/io_win32.h> + +#ifdef _WIN32 +#include <ctype.h> +#endif + +namespace google { +namespace protobuf { +namespace compiler { + +#ifdef _WIN32 +// DO NOT include <io.h>, instead create functions in io_win32.{h,cc} and import +// them like we do below. +using google::protobuf::io::win32::access; +using google::protobuf::io::win32::open; +#endif + +// Returns true if the text looks like a Windows-style absolute path, starting +// with a drive letter. Example: "C:\foo". TODO(kenton): Share this with +// copy in command_line_interface.cc? +static bool IsWindowsAbsolutePath(const std::string& text) { +#if defined(_WIN32) || defined(__CYGWIN__) + return text.size() >= 3 && text[1] == ':' && isalpha(text[0]) && + (text[2] == '/' || text[2] == '\\') && text.find_last_of(':') == 1; +#else + return false; +#endif +} + +MultiFileErrorCollector::~MultiFileErrorCollector() {} + +// This class serves two purposes: +// - It implements the ErrorCollector interface (used by Tokenizer and Parser) +// in terms of MultiFileErrorCollector, using a particular filename. +// - It lets us check if any errors have occurred. +class SourceTreeDescriptorDatabase::SingleFileErrorCollector + : public io::ErrorCollector { + public: + SingleFileErrorCollector(const std::string& filename, + MultiFileErrorCollector* multi_file_error_collector) + : filename_(filename), + multi_file_error_collector_(multi_file_error_collector), + had_errors_(false) {} + ~SingleFileErrorCollector() {} + + bool had_errors() { return had_errors_; } + + // implements ErrorCollector --------------------------------------- + void AddError(int line, int column, const std::string& message) override { + if (multi_file_error_collector_ != NULL) { + multi_file_error_collector_->AddError(filename_, line, column, message); + } + had_errors_ = true; + } + + private: + std::string filename_; + MultiFileErrorCollector* multi_file_error_collector_; + bool had_errors_; +}; + +// =================================================================== + +SourceTreeDescriptorDatabase::SourceTreeDescriptorDatabase( + SourceTree* source_tree) + : source_tree_(source_tree), + fallback_database_(nullptr), + error_collector_(nullptr), + using_validation_error_collector_(false), + validation_error_collector_(this) {} + +SourceTreeDescriptorDatabase::SourceTreeDescriptorDatabase( + SourceTree* source_tree, DescriptorDatabase* fallback_database) + : source_tree_(source_tree), + fallback_database_(fallback_database), + error_collector_(nullptr), + using_validation_error_collector_(false), + validation_error_collector_(this) {} + +SourceTreeDescriptorDatabase::~SourceTreeDescriptorDatabase() {} + +bool SourceTreeDescriptorDatabase::FindFileByName(const std::string& filename, + FileDescriptorProto* output) { + std::unique_ptr<io::ZeroCopyInputStream> input(source_tree_->Open(filename)); + if (input == NULL) { + if (fallback_database_ != nullptr && + fallback_database_->FindFileByName(filename, output)) { + return true; + } + if (error_collector_ != NULL) { + error_collector_->AddError(filename, -1, 0, + source_tree_->GetLastErrorMessage()); + } + return false; + } + + // Set up the tokenizer and parser. + SingleFileErrorCollector file_error_collector(filename, error_collector_); + io::Tokenizer tokenizer(input.get(), &file_error_collector); + + Parser parser; + if (error_collector_ != NULL) { + parser.RecordErrorsTo(&file_error_collector); + } + if (using_validation_error_collector_) { + parser.RecordSourceLocationsTo(&source_locations_); + } + + // Parse it. + output->set_name(filename); + return parser.Parse(&tokenizer, output) && !file_error_collector.had_errors(); +} + +bool SourceTreeDescriptorDatabase::FindFileContainingSymbol( + const std::string& symbol_name, FileDescriptorProto* output) { + return false; +} + +bool SourceTreeDescriptorDatabase::FindFileContainingExtension( + const std::string& containing_type, int field_number, + FileDescriptorProto* output) { + return false; +} + +// ------------------------------------------------------------------- + +SourceTreeDescriptorDatabase::ValidationErrorCollector:: + ValidationErrorCollector(SourceTreeDescriptorDatabase* owner) + : owner_(owner) {} + +SourceTreeDescriptorDatabase::ValidationErrorCollector:: + ~ValidationErrorCollector() {} + +void SourceTreeDescriptorDatabase::ValidationErrorCollector::AddError( + const std::string& filename, const std::string& element_name, + const Message* descriptor, ErrorLocation location, + const std::string& message) { + if (owner_->error_collector_ == NULL) return; + + int line, column; + if (location == DescriptorPool::ErrorCollector::IMPORT) { + owner_->source_locations_.FindImport(descriptor, element_name, &line, + &column); + } else { + owner_->source_locations_.Find(descriptor, location, &line, &column); + } + owner_->error_collector_->AddError(filename, line, column, message); +} + +void SourceTreeDescriptorDatabase::ValidationErrorCollector::AddWarning( + const std::string& filename, const std::string& element_name, + const Message* descriptor, ErrorLocation location, + const std::string& message) { + if (owner_->error_collector_ == NULL) return; + + int line, column; + if (location == DescriptorPool::ErrorCollector::IMPORT) { + owner_->source_locations_.FindImport(descriptor, element_name, &line, + &column); + } else { + owner_->source_locations_.Find(descriptor, location, &line, &column); + } + owner_->error_collector_->AddWarning(filename, line, column, message); +} + +// =================================================================== + +Importer::Importer(SourceTree* source_tree, + MultiFileErrorCollector* error_collector) + : database_(source_tree), + pool_(&database_, database_.GetValidationErrorCollector()) { + pool_.EnforceWeakDependencies(true); + database_.RecordErrorsTo(error_collector); +} + +Importer::~Importer() {} + +const FileDescriptor* Importer::Import(const std::string& filename) { + return pool_.FindFileByName(filename); +} + +void Importer::AddUnusedImportTrackFile(const std::string& file_name, + bool is_error) { + pool_.AddUnusedImportTrackFile(file_name, is_error); +} + +void Importer::ClearUnusedImportTrackFiles() { + pool_.ClearUnusedImportTrackFiles(); +} + + +// =================================================================== + +SourceTree::~SourceTree() {} + +std::string SourceTree::GetLastErrorMessage() { return "File not found."; } + +DiskSourceTree::DiskSourceTree() {} + +DiskSourceTree::~DiskSourceTree() {} + +static inline char LastChar(const std::string& str) { + return str[str.size() - 1]; +} + +// Given a path, returns an equivalent path with these changes: +// - On Windows, any backslashes are replaced with forward slashes. +// - Any instances of the directory "." are removed. +// - Any consecutive '/'s are collapsed into a single slash. +// Note that the resulting string may be empty. +// +// TODO(kenton): It would be nice to handle "..", e.g. so that we can figure +// out that "foo/bar.proto" is inside "baz/../foo". However, if baz is a +// symlink or doesn't exist, then things get complicated, and we can't +// actually determine this without investigating the filesystem, probably +// in non-portable ways. So, we punt. +// +// TODO(kenton): It would be nice to use realpath() here except that it +// resolves symbolic links. This could cause problems if people place +// symbolic links in their source tree. For example, if you executed: +// protoc --proto_path=foo foo/bar/baz.proto +// then if foo/bar is a symbolic link, foo/bar/baz.proto will canonicalize +// to a path which does not appear to be under foo, and thus the compiler +// will complain that baz.proto is not inside the --proto_path. +static std::string CanonicalizePath(std::string path) { +#ifdef _WIN32 + // The Win32 API accepts forward slashes as a path delimiter even though + // backslashes are standard. Let's avoid confusion and use only forward + // slashes. + if (HasPrefixString(path, "\\\\")) { + // Avoid converting two leading backslashes. + path = "\\\\" + StringReplace(path.substr(2), "\\", "/", true); + } else { + path = StringReplace(path, "\\", "/", true); + } +#endif + + std::vector<std::string> canonical_parts; + std::vector<std::string> parts = Split( + path, "/", true); // Note: Removes empty parts. + for (const std::string& part : parts) { + if (part == ".") { + // Ignore. + } else { + canonical_parts.push_back(part); + } + } + std::string result = Join(canonical_parts, "/"); + if (!path.empty() && path[0] == '/') { + // Restore leading slash. + result = '/' + result; + } + if (!path.empty() && LastChar(path) == '/' && !result.empty() && + LastChar(result) != '/') { + // Restore trailing slash. + result += '/'; + } + return result; +} + +static inline bool ContainsParentReference(const std::string& path) { + return path == ".." || HasPrefixString(path, "../") || + HasSuffixString(path, "/..") || path.find("/../") != std::string::npos; +} + +// Maps a file from an old location to a new one. Typically, old_prefix is +// a virtual path and new_prefix is its corresponding disk path. Returns +// false if the filename did not start with old_prefix, otherwise replaces +// old_prefix with new_prefix and stores the result in *result. Examples: +// string result; +// assert(ApplyMapping("foo/bar", "", "baz", &result)); +// assert(result == "baz/foo/bar"); +// +// assert(ApplyMapping("foo/bar", "foo", "baz", &result)); +// assert(result == "baz/bar"); +// +// assert(ApplyMapping("foo", "foo", "bar", &result)); +// assert(result == "bar"); +// +// assert(!ApplyMapping("foo/bar", "baz", "qux", &result)); +// assert(!ApplyMapping("foo/bar", "baz", "qux", &result)); +// assert(!ApplyMapping("foobar", "foo", "baz", &result)); +static bool ApplyMapping(const std::string& filename, + const std::string& old_prefix, + const std::string& new_prefix, std::string* result) { + if (old_prefix.empty()) { + // old_prefix matches any relative path. + if (ContainsParentReference(filename)) { + // We do not allow the file name to use "..". + return false; + } + if (HasPrefixString(filename, "/") || IsWindowsAbsolutePath(filename)) { + // This is an absolute path, so it isn't matched by the empty string. + return false; + } + result->assign(new_prefix); + if (!result->empty()) result->push_back('/'); + result->append(filename); + return true; + } else if (HasPrefixString(filename, old_prefix)) { + // old_prefix is a prefix of the filename. Is it the whole filename? + if (filename.size() == old_prefix.size()) { + // Yep, it's an exact match. + *result = new_prefix; + return true; + } else { + // Not an exact match. Is the next character a '/'? Otherwise, + // this isn't actually a match at all. E.g. the prefix "foo/bar" + // does not match the filename "foo/barbaz". + int after_prefix_start = -1; + if (filename[old_prefix.size()] == '/') { + after_prefix_start = old_prefix.size() + 1; + } else if (filename[old_prefix.size() - 1] == '/') { + // old_prefix is never empty, and canonicalized paths never have + // consecutive '/' characters. + after_prefix_start = old_prefix.size(); + } + if (after_prefix_start != -1) { + // Yep. So the prefixes are directories and the filename is a file + // inside them. + std::string after_prefix = filename.substr(after_prefix_start); + if (ContainsParentReference(after_prefix)) { + // We do not allow the file name to use "..". + return false; + } + result->assign(new_prefix); + if (!result->empty()) result->push_back('/'); + result->append(after_prefix); + return true; + } + } + } + + return false; +} + +void DiskSourceTree::MapPath(const std::string& virtual_path, + const std::string& disk_path) { + mappings_.push_back(Mapping(virtual_path, CanonicalizePath(disk_path))); +} + +DiskSourceTree::DiskFileToVirtualFileResult +DiskSourceTree::DiskFileToVirtualFile(const std::string& disk_file, + std::string* virtual_file, + std::string* shadowing_disk_file) { + int mapping_index = -1; + std::string canonical_disk_file = CanonicalizePath(disk_file); + + for (int i = 0; i < mappings_.size(); i++) { + // Apply the mapping in reverse. + if (ApplyMapping(canonical_disk_file, mappings_[i].disk_path, + mappings_[i].virtual_path, virtual_file)) { + // Success. + mapping_index = i; + break; + } + } + + if (mapping_index == -1) { + return NO_MAPPING; + } + + // Iterate through all mappings with higher precedence and verify that none + // of them map this file to some other existing file. + for (int i = 0; i < mapping_index; i++) { + if (ApplyMapping(*virtual_file, mappings_[i].virtual_path, + mappings_[i].disk_path, shadowing_disk_file)) { + if (access(shadowing_disk_file->c_str(), F_OK) >= 0) { + // File exists. + return SHADOWED; + } + } + } + shadowing_disk_file->clear(); + + // Verify that we can open the file. Note that this also has the side-effect + // of verifying that we are not canonicalizing away any non-existent + // directories. + std::unique_ptr<io::ZeroCopyInputStream> stream(OpenDiskFile(disk_file)); + if (stream == NULL) { + return CANNOT_OPEN; + } + + return SUCCESS; +} + +bool DiskSourceTree::VirtualFileToDiskFile(const std::string& virtual_file, + std::string* disk_file) { + std::unique_ptr<io::ZeroCopyInputStream> stream( + OpenVirtualFile(virtual_file, disk_file)); + return stream != NULL; +} + +io::ZeroCopyInputStream* DiskSourceTree::Open(const std::string& filename) { + return OpenVirtualFile(filename, NULL); +} + +std::string DiskSourceTree::GetLastErrorMessage() { + return last_error_message_; +} + +io::ZeroCopyInputStream* DiskSourceTree::OpenVirtualFile( + const std::string& virtual_file, std::string* disk_file) { + if (virtual_file != CanonicalizePath(virtual_file) || + ContainsParentReference(virtual_file)) { + // We do not allow importing of paths containing things like ".." or + // consecutive slashes since the compiler expects files to be uniquely + // identified by file name. + last_error_message_ = + "Backslashes, consecutive slashes, \".\", or \"..\" " + "are not allowed in the virtual path"; + return NULL; + } + + for (const auto& mapping : mappings_) { + std::string temp_disk_file; + if (ApplyMapping(virtual_file, mapping.virtual_path, mapping.disk_path, + &temp_disk_file)) { + io::ZeroCopyInputStream* stream = OpenDiskFile(temp_disk_file); + if (stream != NULL) { + if (disk_file != NULL) { + *disk_file = temp_disk_file; + } + return stream; + } + + if (errno == EACCES) { + // The file exists but is not readable. + last_error_message_ = + "Read access is denied for file: " + temp_disk_file; + return NULL; + } + } + } + last_error_message_ = "File not found."; + return NULL; +} + +io::ZeroCopyInputStream* DiskSourceTree::OpenDiskFile( + const std::string& filename) { + struct stat sb; + int ret = 0; + do { + ret = stat(filename.c_str(), &sb); + } while (ret != 0 && errno == EINTR); +#if defined(_WIN32) + if (ret == 0 && sb.st_mode & S_IFDIR) { + last_error_message_ = "Input file is a directory."; + return NULL; + } +#else + if (ret == 0 && S_ISDIR(sb.st_mode)) { + last_error_message_ = "Input file is a directory."; + return NULL; + } +#endif + int file_descriptor; + do { + file_descriptor = open(filename.c_str(), O_RDONLY); + } while (file_descriptor < 0 && errno == EINTR); + if (file_descriptor >= 0) { + io::FileInputStream* result = new io::FileInputStream(file_descriptor); + result->SetCloseOnDelete(true); + return result; + } else { + return NULL; + } +} + +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/importer.h b/NorthstarDedicatedTest/include/protobuf/compiler/importer.h new file mode 100644 index 00000000..10c7feb3 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/importer.h @@ -0,0 +1,336 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// This file is the public interface to the .proto file parser. + +#ifndef GOOGLE_PROTOBUF_COMPILER_IMPORTER_H__ +#define GOOGLE_PROTOBUF_COMPILER_IMPORTER_H__ + +#include <set> +#include <string> +#include <utility> +#include <vector> +#include <compiler/parser.h> +#include <descriptor.h> +#include <descriptor_database.h> + +#include <port_def.inc> + +namespace google { +namespace protobuf { + +namespace io { +class ZeroCopyInputStream; +} + +namespace compiler { + +// Defined in this file. +class Importer; +class MultiFileErrorCollector; +class SourceTree; +class DiskSourceTree; + +// TODO(kenton): Move all SourceTree stuff to a separate file? + +// An implementation of DescriptorDatabase which loads files from a SourceTree +// and parses them. +// +// Note: This class is not thread-safe since it maintains a table of source +// code locations for error reporting. However, when a DescriptorPool wraps +// a DescriptorDatabase, it uses mutex locking to make sure only one method +// of the database is called at a time, even if the DescriptorPool is used +// from multiple threads. Therefore, there is only a problem if you create +// multiple DescriptorPools wrapping the same SourceTreeDescriptorDatabase +// and use them from multiple threads. +// +// Note: This class does not implement FindFileContainingSymbol() or +// FindFileContainingExtension(); these will always return false. +class PROTOBUF_EXPORT SourceTreeDescriptorDatabase : public DescriptorDatabase { + public: + SourceTreeDescriptorDatabase(SourceTree* source_tree); + + // If non-NULL, fallback_database will be checked if a file doesn't exist in + // the specified source_tree. + SourceTreeDescriptorDatabase(SourceTree* source_tree, + DescriptorDatabase* fallback_database); + ~SourceTreeDescriptorDatabase(); + + // Instructs the SourceTreeDescriptorDatabase to report any parse errors + // to the given MultiFileErrorCollector. This should be called before + // parsing. error_collector must remain valid until either this method + // is called again or the SourceTreeDescriptorDatabase is destroyed. + void RecordErrorsTo(MultiFileErrorCollector* error_collector) { + error_collector_ = error_collector; + } + + // Gets a DescriptorPool::ErrorCollector which records errors to the + // MultiFileErrorCollector specified with RecordErrorsTo(). This collector + // has the ability to determine exact line and column numbers of errors + // from the information given to it by the DescriptorPool. + DescriptorPool::ErrorCollector* GetValidationErrorCollector() { + using_validation_error_collector_ = true; + return &validation_error_collector_; + } + + // implements DescriptorDatabase ----------------------------------- + bool FindFileByName(const std::string& filename, + FileDescriptorProto* output) override; + bool FindFileContainingSymbol(const std::string& symbol_name, + FileDescriptorProto* output) override; + bool FindFileContainingExtension(const std::string& containing_type, + int field_number, + FileDescriptorProto* output) override; + + private: + class SingleFileErrorCollector; + + SourceTree* source_tree_; + DescriptorDatabase* fallback_database_; + MultiFileErrorCollector* error_collector_; + + class PROTOBUF_EXPORT ValidationErrorCollector + : public DescriptorPool::ErrorCollector { + public: + ValidationErrorCollector(SourceTreeDescriptorDatabase* owner); + ~ValidationErrorCollector(); + + // implements ErrorCollector --------------------------------------- + void AddError(const std::string& filename, const std::string& element_name, + const Message* descriptor, ErrorLocation location, + const std::string& message) override; + + void AddWarning(const std::string& filename, + const std::string& element_name, const Message* descriptor, + ErrorLocation location, + const std::string& message) override; + + private: + SourceTreeDescriptorDatabase* owner_; + }; + friend class ValidationErrorCollector; + + bool using_validation_error_collector_; + SourceLocationTable source_locations_; + ValidationErrorCollector validation_error_collector_; +}; + +// Simple interface for parsing .proto files. This wraps the process +// of opening the file, parsing it with a Parser, recursively parsing all its +// imports, and then cross-linking the results to produce a FileDescriptor. +// +// This is really just a thin wrapper around SourceTreeDescriptorDatabase. +// You may find that SourceTreeDescriptorDatabase is more flexible. +// +// TODO(kenton): I feel like this class is not well-named. +class PROTOBUF_EXPORT Importer { + public: + Importer(SourceTree* source_tree, MultiFileErrorCollector* error_collector); + ~Importer(); + + // Import the given file and build a FileDescriptor representing it. If + // the file is already in the DescriptorPool, the existing FileDescriptor + // will be returned. The FileDescriptor is property of the DescriptorPool, + // and will remain valid until it is destroyed. If any errors occur, they + // will be reported using the error collector and Import() will return NULL. + // + // A particular Importer object will only report errors for a particular + // file once. All future attempts to import the same file will return NULL + // without reporting any errors. The idea is that you might want to import + // a lot of files without seeing the same errors over and over again. If + // you want to see errors for the same files repeatedly, you can use a + // separate Importer object to import each one (but use the same + // DescriptorPool so that they can be cross-linked). + const FileDescriptor* Import(const std::string& filename); + + // The DescriptorPool in which all imported FileDescriptors and their + // contents are stored. + inline const DescriptorPool* pool() const { return &pool_; } + + void AddUnusedImportTrackFile(const std::string& file_name, + bool is_error = false); + void ClearUnusedImportTrackFiles(); + + + private: + SourceTreeDescriptorDatabase database_; + DescriptorPool pool_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Importer); +}; + +// If the importer encounters problems while trying to import the proto files, +// it reports them to a MultiFileErrorCollector. +class PROTOBUF_EXPORT MultiFileErrorCollector { + public: + inline MultiFileErrorCollector() {} + virtual ~MultiFileErrorCollector(); + + // Line and column numbers are zero-based. A line number of -1 indicates + // an error with the entire file (e.g. "not found"). + virtual void AddError(const std::string& filename, int line, int column, + const std::string& message) = 0; + + virtual void AddWarning(const std::string& /* filename */, int /* line */, + int /* column */, const std::string& /* message */) {} + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MultiFileErrorCollector); +}; + +// Abstract interface which represents a directory tree containing proto files. +// Used by the default implementation of Importer to resolve import statements +// Most users will probably want to use the DiskSourceTree implementation, +// below. +class PROTOBUF_EXPORT SourceTree { + public: + inline SourceTree() {} + virtual ~SourceTree(); + + // Open the given file and return a stream that reads it, or NULL if not + // found. The caller takes ownership of the returned object. The filename + // must be a path relative to the root of the source tree and must not + // contain "." or ".." components. + virtual io::ZeroCopyInputStream* Open(const std::string& filename) = 0; + + // If Open() returns NULL, calling this method immediately will return an + // description of the error. + // Subclasses should implement this method and return a meaningful value for + // better error reporting. + // TODO(xiaofeng): change this to a pure virtual function. + virtual std::string GetLastErrorMessage(); + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(SourceTree); +}; + +// An implementation of SourceTree which loads files from locations on disk. +// Multiple mappings can be set up to map locations in the DiskSourceTree to +// locations in the physical filesystem. +class PROTOBUF_EXPORT DiskSourceTree : public SourceTree { + public: + DiskSourceTree(); + ~DiskSourceTree(); + + // Map a path on disk to a location in the SourceTree. The path may be + // either a file or a directory. If it is a directory, the entire tree + // under it will be mapped to the given virtual location. To map a directory + // to the root of the source tree, pass an empty string for virtual_path. + // + // If multiple mapped paths apply when opening a file, they will be searched + // in order. For example, if you do: + // MapPath("bar", "foo/bar"); + // MapPath("", "baz"); + // and then you do: + // Open("bar/qux"); + // the DiskSourceTree will first try to open foo/bar/qux, then baz/bar/qux, + // returning the first one that opens successfully. + // + // disk_path may be an absolute path or relative to the current directory, + // just like a path you'd pass to open(). + void MapPath(const std::string& virtual_path, const std::string& disk_path); + + // Return type for DiskFileToVirtualFile(). + enum DiskFileToVirtualFileResult { + SUCCESS, + SHADOWED, + CANNOT_OPEN, + NO_MAPPING + }; + + // Given a path to a file on disk, find a virtual path mapping to that + // file. The first mapping created with MapPath() whose disk_path contains + // the filename is used. However, that virtual path may not actually be + // usable to open the given file. Possible return values are: + // * SUCCESS: The mapping was found. *virtual_file is filled in so that + // calling Open(*virtual_file) will open the file named by disk_file. + // * SHADOWED: A mapping was found, but using Open() to open this virtual + // path will end up returning some different file. This is because some + // other mapping with a higher precedence also matches this virtual path + // and maps it to a different file that exists on disk. *virtual_file + // is filled in as it would be in the SUCCESS case. *shadowing_disk_file + // is filled in with the disk path of the file which would be opened if + // you were to call Open(*virtual_file). + // * CANNOT_OPEN: The mapping was found and was not shadowed, but the + // file specified cannot be opened. When this value is returned, + // errno will indicate the reason the file cannot be opened. *virtual_file + // will be set to the virtual path as in the SUCCESS case, even though + // it is not useful. + // * NO_MAPPING: Indicates that no mapping was found which contains this + // file. + DiskFileToVirtualFileResult DiskFileToVirtualFile( + const std::string& disk_file, std::string* virtual_file, + std::string* shadowing_disk_file); + + // Given a virtual path, find the path to the file on disk. + // Return true and update disk_file with the on-disk path if the file exists. + // Return false and leave disk_file untouched if the file doesn't exist. + bool VirtualFileToDiskFile(const std::string& virtual_file, + std::string* disk_file); + + // implements SourceTree ------------------------------------------- + io::ZeroCopyInputStream* Open(const std::string& filename) override; + + std::string GetLastErrorMessage() override; + + private: + struct Mapping { + std::string virtual_path; + std::string disk_path; + + inline Mapping(const std::string& virtual_path_param, + const std::string& disk_path_param) + : virtual_path(virtual_path_param), disk_path(disk_path_param) {} + }; + std::vector<Mapping> mappings_; + std::string last_error_message_; + + // Like Open(), but returns the on-disk path in disk_file if disk_file is + // non-NULL and the file could be successfully opened. + io::ZeroCopyInputStream* OpenVirtualFile(const std::string& virtual_file, + std::string* disk_file); + + // Like Open() but given the actual on-disk path. + io::ZeroCopyInputStream* OpenDiskFile(const std::string& filename); + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DiskSourceTree); +}; + +} // namespace compiler +} // namespace protobuf +} // namespace google + +#include <port_undef.inc> + +#endif // GOOGLE_PROTOBUF_COMPILER_IMPORTER_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/importer_unittest.cc b/NorthstarDedicatedTest/include/protobuf/compiler/importer_unittest.cc new file mode 100644 index 00000000..16ff90f2 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/importer_unittest.cc @@ -0,0 +1,548 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <compiler/importer.h> + +#include <memory> +#include <unordered_map> + +#include <stubs/logging.h> +#include <stubs/common.h> +#include <testing/file.h> +#include <testing/file.h> +#include <testing/file.h> +#include <io/zero_copy_stream_impl.h> +#include <descriptor.h> +#include <testing/googletest.h> +#include <gtest/gtest.h> +#include <stubs/substitute.h> +#include <stubs/map_util.h> +#include <stubs/strutil.h> + +namespace google { +namespace protobuf { +namespace compiler { + +namespace { + +bool FileExists(const std::string& path) { + return File::Exists(path); +} + +#define EXPECT_SUBSTRING(needle, haystack) \ + EXPECT_PRED_FORMAT2(testing::IsSubstring, (needle), (haystack)) + +class MockErrorCollector : public MultiFileErrorCollector { + public: + MockErrorCollector() {} + ~MockErrorCollector() {} + + std::string text_; + std::string warning_text_; + + // implements ErrorCollector --------------------------------------- + void AddError(const std::string& filename, int line, int column, + const std::string& message) { + strings::SubstituteAndAppend(&text_, "$0:$1:$2: $3\n", filename, line, column, + message); + } + + void AddWarning(const std::string& filename, int line, int column, + const std::string& message) { + strings::SubstituteAndAppend(&warning_text_, "$0:$1:$2: $3\n", filename, line, + column, message); + } +}; + +// ------------------------------------------------------------------- + +// A dummy implementation of SourceTree backed by a simple map. +class MockSourceTree : public SourceTree { + public: + MockSourceTree() {} + ~MockSourceTree() {} + + void AddFile(const std::string& name, const char* contents) { + files_[name] = contents; + } + + // implements SourceTree ------------------------------------------- + io::ZeroCopyInputStream* Open(const std::string& filename) { + const char* contents = FindPtrOrNull(files_, filename); + if (contents == NULL) { + return NULL; + } else { + return new io::ArrayInputStream(contents, strlen(contents)); + } + } + + std::string GetLastErrorMessage() { return "File not found."; } + + private: + std::unordered_map<std::string, const char*> files_; +}; + +// =================================================================== + +class ImporterTest : public testing::Test { + protected: + ImporterTest() : importer_(&source_tree_, &error_collector_) {} + + void AddFile(const std::string& filename, const char* text) { + source_tree_.AddFile(filename, text); + } + + // Return the collected error text + std::string warning() const { return error_collector_.warning_text_; } + + MockErrorCollector error_collector_; + MockSourceTree source_tree_; + Importer importer_; +}; + +TEST_F(ImporterTest, Import) { + // Test normal importing. + AddFile("foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); + + const FileDescriptor* file = importer_.Import("foo.proto"); + EXPECT_EQ("", error_collector_.text_); + ASSERT_TRUE(file != NULL); + + ASSERT_EQ(1, file->message_type_count()); + EXPECT_EQ("Foo", file->message_type(0)->name()); + + // Importing again should return same object. + EXPECT_EQ(file, importer_.Import("foo.proto")); +} + +TEST_F(ImporterTest, ImportNested) { + // Test that importing a file which imports another file works. + AddFile("foo.proto", + "syntax = \"proto2\";\n" + "import \"bar.proto\";\n" + "message Foo {\n" + " optional Bar bar = 1;\n" + "}\n"); + AddFile("bar.proto", + "syntax = \"proto2\";\n" + "message Bar {}\n"); + + // Note that both files are actually parsed by the first call to Import() + // here, since foo.proto imports bar.proto. The second call just returns + // the same ProtoFile for bar.proto which was constructed while importing + // foo.proto. We test that this is the case below by checking that bar + // is among foo's dependencies (by pointer). + const FileDescriptor* foo = importer_.Import("foo.proto"); + const FileDescriptor* bar = importer_.Import("bar.proto"); + EXPECT_EQ("", error_collector_.text_); + ASSERT_TRUE(foo != NULL); + ASSERT_TRUE(bar != NULL); + + // Check that foo's dependency is the same object as bar. + ASSERT_EQ(1, foo->dependency_count()); + EXPECT_EQ(bar, foo->dependency(0)); + + // Check that foo properly cross-links bar. + ASSERT_EQ(1, foo->message_type_count()); + ASSERT_EQ(1, bar->message_type_count()); + ASSERT_EQ(1, foo->message_type(0)->field_count()); + ASSERT_EQ(FieldDescriptor::TYPE_MESSAGE, + foo->message_type(0)->field(0)->type()); + EXPECT_EQ(bar->message_type(0), + foo->message_type(0)->field(0)->message_type()); +} + +TEST_F(ImporterTest, FileNotFound) { + // Error: Parsing a file that doesn't exist. + EXPECT_TRUE(importer_.Import("foo.proto") == NULL); + EXPECT_EQ("foo.proto:-1:0: File not found.\n", error_collector_.text_); +} + +TEST_F(ImporterTest, ImportNotFound) { + // Error: Importing a file that doesn't exist. + AddFile("foo.proto", + "syntax = \"proto2\";\n" + "import \"bar.proto\";\n"); + + EXPECT_TRUE(importer_.Import("foo.proto") == NULL); + EXPECT_EQ( + "bar.proto:-1:0: File not found.\n" + "foo.proto:1:0: Import \"bar.proto\" was not found or had errors.\n", + error_collector_.text_); +} + +TEST_F(ImporterTest, RecursiveImport) { + // Error: Recursive import. + AddFile("recursive1.proto", + "syntax = \"proto2\";\n" + "\n" + "import \"recursive2.proto\";\n"); + AddFile("recursive2.proto", + "syntax = \"proto2\";\n" + "import \"recursive1.proto\";\n"); + + EXPECT_TRUE(importer_.Import("recursive1.proto") == NULL); + EXPECT_EQ( + "recursive1.proto:2:0: File recursively imports itself: " + "recursive1.proto " + "-> recursive2.proto -> recursive1.proto\n" + "recursive2.proto:1:0: Import \"recursive1.proto\" was not found " + "or had errors.\n" + "recursive1.proto:2:0: Import \"recursive2.proto\" was not found " + "or had errors.\n", + error_collector_.text_); +} + +TEST_F(ImporterTest, RecursiveImportSelf) { + // Error: Recursive import. + AddFile("recursive.proto", + "syntax = \"proto2\";\n" + "\n" + "import \"recursive.proto\";\n"); + + EXPECT_TRUE(importer_.Import("recursive.proto") == nullptr); + EXPECT_EQ( + "recursive.proto:2:0: File recursively imports itself: " + "recursive.proto -> recursive.proto\n", + error_collector_.text_); +} + +TEST_F(ImporterTest, LiteRuntimeImport) { + // Error: Recursive import. + AddFile("bar.proto", + "syntax = \"proto2\";\n" + "option optimize_for = LITE_RUNTIME;\n"); + AddFile("foo.proto", + "syntax = \"proto2\";\n" + "import \"bar.proto\";\n"); + + EXPECT_TRUE(importer_.Import("foo.proto") == nullptr); + EXPECT_EQ( + "foo.proto:1:0: Files that do not use optimize_for = LITE_RUNTIME " + "cannot import files which do use this option. This file is not " + "lite, but it imports \"bar.proto\" which is.\n", + error_collector_.text_); +} + + +// =================================================================== + +class DiskSourceTreeTest : public testing::Test { + protected: + virtual void SetUp() { + dirnames_.push_back(TestTempDir() + "/test_proto2_import_path_1"); + dirnames_.push_back(TestTempDir() + "/test_proto2_import_path_2"); + + for (int i = 0; i < dirnames_.size(); i++) { + if (FileExists(dirnames_[i])) { + File::DeleteRecursively(dirnames_[i], NULL, NULL); + } + GOOGLE_CHECK_OK(File::CreateDir(dirnames_[i], 0777)); + } + } + + virtual void TearDown() { + for (int i = 0; i < dirnames_.size(); i++) { + if (FileExists(dirnames_[i])) { + File::DeleteRecursively(dirnames_[i], NULL, NULL); + } + } + } + + void AddFile(const std::string& filename, const char* contents) { + GOOGLE_CHECK_OK(File::SetContents(filename, contents, true)); + } + + void AddSubdir(const std::string& dirname) { + GOOGLE_CHECK_OK(File::CreateDir(dirname, 0777)); + } + + void ExpectFileContents(const std::string& filename, + const char* expected_contents) { + std::unique_ptr<io::ZeroCopyInputStream> input(source_tree_.Open(filename)); + + ASSERT_FALSE(input == NULL); + + // Read all the data from the file. + std::string file_contents; + const void* data; + int size; + while (input->Next(&data, &size)) { + file_contents.append(reinterpret_cast<const char*>(data), size); + } + + EXPECT_EQ(expected_contents, file_contents); + } + + void ExpectCannotOpenFile(const std::string& filename, + const std::string& error_message) { + std::unique_ptr<io::ZeroCopyInputStream> input(source_tree_.Open(filename)); + EXPECT_TRUE(input == NULL); + EXPECT_EQ(error_message, source_tree_.GetLastErrorMessage()); + } + + DiskSourceTree source_tree_; + + // Paths of two on-disk directories to use during the test. + std::vector<std::string> dirnames_; +}; + +TEST_F(DiskSourceTreeTest, MapRoot) { + // Test opening a file in a directory that is mapped to the root of the + // source tree. + AddFile(dirnames_[0] + "/foo", "Hello World!"); + source_tree_.MapPath("", dirnames_[0]); + + ExpectFileContents("foo", "Hello World!"); + ExpectCannotOpenFile("bar", "File not found."); +} + +TEST_F(DiskSourceTreeTest, MapDirectory) { + // Test opening a file in a directory that is mapped to somewhere other + // than the root of the source tree. + + AddFile(dirnames_[0] + "/foo", "Hello World!"); + source_tree_.MapPath("baz", dirnames_[0]); + + ExpectFileContents("baz/foo", "Hello World!"); + ExpectCannotOpenFile("baz/bar", "File not found."); + ExpectCannotOpenFile("foo", "File not found."); + ExpectCannotOpenFile("bar", "File not found."); + + // Non-canonical file names should not work. + ExpectCannotOpenFile("baz//foo", + "Backslashes, consecutive slashes, \".\", or \"..\" are " + "not allowed in the virtual path"); + ExpectCannotOpenFile("baz/../baz/foo", + "Backslashes, consecutive slashes, \".\", or \"..\" are " + "not allowed in the virtual path"); + ExpectCannotOpenFile("baz/./foo", + "Backslashes, consecutive slashes, \".\", or \"..\" are " + "not allowed in the virtual path"); + ExpectCannotOpenFile("baz/foo/", "File not found."); +} + +TEST_F(DiskSourceTreeTest, NoParent) { + // Test that we cannot open files in a parent of a mapped directory. + + AddFile(dirnames_[0] + "/foo", "Hello World!"); + AddSubdir(dirnames_[0] + "/bar"); + AddFile(dirnames_[0] + "/bar/baz", "Blah."); + source_tree_.MapPath("", dirnames_[0] + "/bar"); + + ExpectFileContents("baz", "Blah."); + ExpectCannotOpenFile("../foo", + "Backslashes, consecutive slashes, \".\", or \"..\" are " + "not allowed in the virtual path"); + ExpectCannotOpenFile("../bar/baz", + "Backslashes, consecutive slashes, \".\", or \"..\" are " + "not allowed in the virtual path"); +} + +TEST_F(DiskSourceTreeTest, MapFile) { + // Test opening a file that is mapped directly into the source tree. + + AddFile(dirnames_[0] + "/foo", "Hello World!"); + source_tree_.MapPath("foo", dirnames_[0] + "/foo"); + + ExpectFileContents("foo", "Hello World!"); + ExpectCannotOpenFile("bar", "File not found."); +} + +TEST_F(DiskSourceTreeTest, SearchMultipleDirectories) { + // Test mapping and searching multiple directories. + + AddFile(dirnames_[0] + "/foo", "Hello World!"); + AddFile(dirnames_[1] + "/foo", "This file should be hidden."); + AddFile(dirnames_[1] + "/bar", "Goodbye World!"); + source_tree_.MapPath("", dirnames_[0]); + source_tree_.MapPath("", dirnames_[1]); + + ExpectFileContents("foo", "Hello World!"); + ExpectFileContents("bar", "Goodbye World!"); + ExpectCannotOpenFile("baz", "File not found."); +} + +TEST_F(DiskSourceTreeTest, OrderingTrumpsSpecificity) { + // Test that directories are always searched in order, even when a latter + // directory is more-specific than a former one. + + // Create the "bar" directory so we can put a file in it. + GOOGLE_CHECK_OK(File::CreateDir(dirnames_[0] + "/bar", 0777)); + + // Add files and map paths. + AddFile(dirnames_[0] + "/bar/foo", "Hello World!"); + AddFile(dirnames_[1] + "/foo", "This file should be hidden."); + source_tree_.MapPath("", dirnames_[0]); + source_tree_.MapPath("bar", dirnames_[1]); + + // Check. + ExpectFileContents("bar/foo", "Hello World!"); +} + +TEST_F(DiskSourceTreeTest, DiskFileToVirtualFile) { + // Test DiskFileToVirtualFile. + + AddFile(dirnames_[0] + "/foo", "Hello World!"); + AddFile(dirnames_[1] + "/foo", "This file should be hidden."); + source_tree_.MapPath("bar", dirnames_[0]); + source_tree_.MapPath("bar", dirnames_[1]); + + std::string virtual_file; + std::string shadowing_disk_file; + + EXPECT_EQ(DiskSourceTree::NO_MAPPING, + source_tree_.DiskFileToVirtualFile("/foo", &virtual_file, + &shadowing_disk_file)); + + EXPECT_EQ(DiskSourceTree::SHADOWED, + source_tree_.DiskFileToVirtualFile( + dirnames_[1] + "/foo", &virtual_file, &shadowing_disk_file)); + EXPECT_EQ("bar/foo", virtual_file); + EXPECT_EQ(dirnames_[0] + "/foo", shadowing_disk_file); + + EXPECT_EQ(DiskSourceTree::CANNOT_OPEN, + source_tree_.DiskFileToVirtualFile( + dirnames_[1] + "/baz", &virtual_file, &shadowing_disk_file)); + EXPECT_EQ("bar/baz", virtual_file); + + EXPECT_EQ(DiskSourceTree::SUCCESS, + source_tree_.DiskFileToVirtualFile( + dirnames_[0] + "/foo", &virtual_file, &shadowing_disk_file)); + EXPECT_EQ("bar/foo", virtual_file); +} + +TEST_F(DiskSourceTreeTest, DiskFileToVirtualFileCanonicalization) { + // Test handling of "..", ".", etc. in DiskFileToVirtualFile(). + + source_tree_.MapPath("dir1", ".."); + source_tree_.MapPath("dir2", "../../foo"); + source_tree_.MapPath("dir3", "./foo/bar/."); + source_tree_.MapPath("dir4", "."); + source_tree_.MapPath("", "/qux"); + source_tree_.MapPath("dir5", "/quux/"); + + std::string virtual_file; + std::string shadowing_disk_file; + + // "../.." should not be considered to be under "..". + EXPECT_EQ(DiskSourceTree::NO_MAPPING, + source_tree_.DiskFileToVirtualFile("../../baz", &virtual_file, + &shadowing_disk_file)); + + // "/foo" is not mapped (it should not be misinterpreted as being under "."). + EXPECT_EQ(DiskSourceTree::NO_MAPPING, + source_tree_.DiskFileToVirtualFile("/foo", &virtual_file, + &shadowing_disk_file)); + +#ifdef WIN32 + // "C:\foo" is not mapped (it should not be misinterpreted as being under + // "."). + EXPECT_EQ(DiskSourceTree::NO_MAPPING, + source_tree_.DiskFileToVirtualFile("C:\\foo", &virtual_file, + &shadowing_disk_file)); +#endif // WIN32 + + // But "../baz" should be. + EXPECT_EQ(DiskSourceTree::CANNOT_OPEN, + source_tree_.DiskFileToVirtualFile("../baz", &virtual_file, + &shadowing_disk_file)); + EXPECT_EQ("dir1/baz", virtual_file); + + // "../../foo/baz" is under "../../foo". + EXPECT_EQ(DiskSourceTree::CANNOT_OPEN, + source_tree_.DiskFileToVirtualFile("../../foo/baz", &virtual_file, + &shadowing_disk_file)); + EXPECT_EQ("dir2/baz", virtual_file); + + // "foo/./bar/baz" is under "./foo/bar/.". + EXPECT_EQ(DiskSourceTree::CANNOT_OPEN, + source_tree_.DiskFileToVirtualFile("foo/bar/baz", &virtual_file, + &shadowing_disk_file)); + EXPECT_EQ("dir3/baz", virtual_file); + + // "bar" is under ".". + EXPECT_EQ(DiskSourceTree::CANNOT_OPEN, + source_tree_.DiskFileToVirtualFile("bar", &virtual_file, + &shadowing_disk_file)); + EXPECT_EQ("dir4/bar", virtual_file); + + // "/qux/baz" is under "/qux". + EXPECT_EQ(DiskSourceTree::CANNOT_OPEN, + source_tree_.DiskFileToVirtualFile("/qux/baz", &virtual_file, + &shadowing_disk_file)); + EXPECT_EQ("baz", virtual_file); + + // "/quux/bar" is under "/quux". + EXPECT_EQ(DiskSourceTree::CANNOT_OPEN, + source_tree_.DiskFileToVirtualFile("/quux/bar", &virtual_file, + &shadowing_disk_file)); + EXPECT_EQ("dir5/bar", virtual_file); +} + +TEST_F(DiskSourceTreeTest, VirtualFileToDiskFile) { + // Test VirtualFileToDiskFile. + + AddFile(dirnames_[0] + "/foo", "Hello World!"); + AddFile(dirnames_[1] + "/foo", "This file should be hidden."); + AddFile(dirnames_[1] + "/quux", "This file should not be hidden."); + source_tree_.MapPath("bar", dirnames_[0]); + source_tree_.MapPath("bar", dirnames_[1]); + + // Existent files, shadowed and non-shadowed case. + std::string disk_file; + EXPECT_TRUE(source_tree_.VirtualFileToDiskFile("bar/foo", &disk_file)); + EXPECT_EQ(dirnames_[0] + "/foo", disk_file); + EXPECT_TRUE(source_tree_.VirtualFileToDiskFile("bar/quux", &disk_file)); + EXPECT_EQ(dirnames_[1] + "/quux", disk_file); + + // Nonexistent file in existent directory and vice versa. + std::string not_touched = "not touched"; + EXPECT_FALSE(source_tree_.VirtualFileToDiskFile("bar/baz", ¬_touched)); + EXPECT_EQ("not touched", not_touched); + EXPECT_FALSE(source_tree_.VirtualFileToDiskFile("baz/foo", ¬_touched)); + EXPECT_EQ("not touched", not_touched); + + // Accept NULL as output parameter. + EXPECT_TRUE(source_tree_.VirtualFileToDiskFile("bar/foo", NULL)); + EXPECT_FALSE(source_tree_.VirtualFileToDiskFile("baz/foo", NULL)); +} + +} // namespace + +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/java/java_context.cc b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_context.cc new file mode 100644 index 00000000..00ffc946 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_context.cc @@ -0,0 +1,202 @@ +// 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 <compiler/java/java_context.h> + +#include <compiler/java/java_field.h> +#include <compiler/java/java_helpers.h> +#include <compiler/java/java_name_resolver.h> +#include <descriptor.h> +#include <stubs/strutil.h> +#include <stubs/map_util.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +Context::Context(const FileDescriptor* file, const Options& options) + : name_resolver_(new ClassNameResolver), options_(options) { + InitializeFieldGeneratorInfo(file); +} + +Context::~Context() {} + +ClassNameResolver* Context::GetNameResolver() const { + return name_resolver_.get(); +} + +namespace { +// Whether two fields have conflicting accessors (assuming name1 and name2 +// are different). name1 and name2 are field1 and field2's camel-case name +// respectively. +bool IsConflicting(const FieldDescriptor* field1, const std::string& name1, + const FieldDescriptor* field2, const std::string& name2, + std::string* info) { + if (field1->is_repeated()) { + if (field2->is_repeated()) { + // Both fields are repeated. + return false; + } else { + // field1 is repeated, and field2 is not. + if (name1 + "Count" == name2) { + *info = "both repeated field \"" + field1->name() + "\" and singular " + + "field \"" + field2->name() + "\" generate the method \"" + + "get" + name1 + "Count()\""; + return true; + } + if (name1 + "List" == name2) { + *info = "both repeated field \"" + field1->name() + "\" and singular " + + "field \"" + field2->name() + "\" generate the method \"" + + "get" + name1 + "List()\""; + return true; + } + // Well, there are obviously many more conflicting cases, but it probably + // doesn't worth the effort to exhaust all of them because they rarely + // happen and as we are continuing adding new methods/changing existing + // methods the number of different conflicting cases will keep growing. + // We can just add more cases here when they are found in the real world. + return false; + } + } else { + if (field2->is_repeated()) { + return IsConflicting(field2, name2, field1, name1, info); + } else { + // None of the two fields are repeated. + return false; + } + } +} +} // namespace + +void Context::InitializeFieldGeneratorInfo(const FileDescriptor* file) { + for (int i = 0; i < file->message_type_count(); ++i) { + InitializeFieldGeneratorInfoForMessage(file->message_type(i)); + } +} + +void Context::InitializeFieldGeneratorInfoForMessage( + const Descriptor* message) { + for (int i = 0; i < message->nested_type_count(); ++i) { + InitializeFieldGeneratorInfoForMessage(message->nested_type(i)); + } + std::vector<const FieldDescriptor*> fields; + fields.reserve(message->field_count()); + for (int i = 0; i < message->field_count(); ++i) { + fields.push_back(message->field(i)); + } + InitializeFieldGeneratorInfoForFields(fields); + + for (int i = 0; i < message->oneof_decl_count(); ++i) { + const OneofDescriptor* oneof = message->oneof_decl(i); + OneofGeneratorInfo info; + info.name = UnderscoresToCamelCase(oneof->name(), false); + info.capitalized_name = UnderscoresToCamelCase(oneof->name(), true); + oneof_generator_info_map_[oneof] = info; + } +} + +void Context::InitializeFieldGeneratorInfoForFields( + const std::vector<const FieldDescriptor*>& fields) { + // Find out all fields that conflict with some other field in the same + // message. + std::vector<bool> is_conflict(fields.size()); + std::vector<std::string> conflict_reason(fields.size()); + for (int i = 0; i < fields.size(); ++i) { + const FieldDescriptor* field = fields[i]; + const std::string& name = UnderscoresToCapitalizedCamelCase(field); + for (int j = i + 1; j < fields.size(); ++j) { + const FieldDescriptor* other = fields[j]; + const std::string& other_name = UnderscoresToCapitalizedCamelCase(other); + if (name == other_name) { + is_conflict[i] = is_conflict[j] = true; + conflict_reason[i] = conflict_reason[j] = + "capitalized name of field \"" + field->name() + + "\" conflicts with field \"" + other->name() + "\""; + } else if (IsConflicting(field, name, other, other_name, + &conflict_reason[j])) { + is_conflict[i] = is_conflict[j] = true; + conflict_reason[i] = conflict_reason[j]; + } + } + if (is_conflict[i]) { + GOOGLE_LOG(WARNING) << "field \"" << field->full_name() << "\" is conflicting " + << "with another field: " << conflict_reason[i]; + } + } + for (int i = 0; i < fields.size(); ++i) { + const FieldDescriptor* field = fields[i]; + FieldGeneratorInfo info; + info.name = CamelCaseFieldName(field); + info.capitalized_name = UnderscoresToCapitalizedCamelCase(field); + // For fields conflicting with some other fields, we append the field + // number to their field names in generated code to avoid conflicts. + if (is_conflict[i]) { + info.name += StrCat(field->number()); + info.capitalized_name += StrCat(field->number()); + info.disambiguated_reason = conflict_reason[i]; + } + field_generator_info_map_[field] = info; + } +} + +const FieldGeneratorInfo* Context::GetFieldGeneratorInfo( + const FieldDescriptor* field) const { + const FieldGeneratorInfo* result = + FindOrNull(field_generator_info_map_, field); + if (result == NULL) { + GOOGLE_LOG(FATAL) << "Can not find FieldGeneratorInfo for field: " + << field->full_name(); + } + return result; +} + +const OneofGeneratorInfo* Context::GetOneofGeneratorInfo( + const OneofDescriptor* oneof) const { + const OneofGeneratorInfo* result = + FindOrNull(oneof_generator_info_map_, oneof); + if (result == NULL) { + GOOGLE_LOG(FATAL) << "Can not find OneofGeneratorInfo for oneof: " + << oneof->name(); + } + return result; +} + +// Does this message class have generated parsing, serialization, and other +// standard methods for which reflection-based fallback implementations exist? +bool Context::HasGeneratedMethods(const Descriptor* descriptor) const { + return options_.enforce_lite || + descriptor->file()->options().optimize_for() != FileOptions::CODE_SIZE; +} + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/java/java_context.h b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_context.h new file mode 100644 index 00000000..ed6e9e9c --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_context.h @@ -0,0 +1,113 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_CONTEXT_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVA_CONTEXT_H__ + +#include <map> +#include <memory> +#include <vector> + +#include <stubs/common.h> +#include <compiler/java/java_options.h> + +namespace google { +namespace protobuf { +class FileDescriptor; +class FieldDescriptor; +class OneofDescriptor; +class Descriptor; +class EnumDescriptor; +namespace compiler { +namespace java { +class ClassNameResolver; // name_resolver.h +} +} // namespace compiler +} // namespace protobuf +} // namespace google + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +struct FieldGeneratorInfo; +struct OneofGeneratorInfo; +// A context object holds the information that is shared among all code +// generators. +class Context { + public: + Context(const FileDescriptor* file, const Options& options); + ~Context(); + + // Get the name resolver associated with this context. The resolver + // can be used to map descriptors to Java class names. + ClassNameResolver* GetNameResolver() const; + + // Get the FieldGeneratorInfo for a given field. + const FieldGeneratorInfo* GetFieldGeneratorInfo( + const FieldDescriptor* field) const; + + // Get the OneofGeneratorInfo for a given oneof. + const OneofGeneratorInfo* GetOneofGeneratorInfo( + const OneofDescriptor* oneof) const; + + const Options& options() const { return options_; } + + // Enforces all the files (including transitive dependencies) to use + // LiteRuntime. + + bool EnforceLite() const { return options_.enforce_lite; } + + // Does this message class have generated parsing, serialization, and other + // standard methods for which reflection-based fallback implementations exist? + bool HasGeneratedMethods(const Descriptor* descriptor) const; + + private: + void InitializeFieldGeneratorInfo(const FileDescriptor* file); + void InitializeFieldGeneratorInfoForMessage(const Descriptor* message); + void InitializeFieldGeneratorInfoForFields( + const std::vector<const FieldDescriptor*>& fields); + + std::unique_ptr<ClassNameResolver> name_resolver_; + std::map<const FieldDescriptor*, FieldGeneratorInfo> + field_generator_info_map_; + std::map<const OneofDescriptor*, OneofGeneratorInfo> + oneof_generator_info_map_; + Options options_; + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Context); +}; + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_CONTEXT_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/java/java_doc_comment.cc b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_doc_comment.cc new file mode 100644 index 00000000..ed9f0d27 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_doc_comment.cc @@ -0,0 +1,435 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <compiler/java/java_doc_comment.h> + +#include <vector> + +#include <descriptor.pb.h> +#include <io/printer.h> +#include <stubs/strutil.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +std::string EscapeJavadoc(const std::string& input) { + std::string result; + result.reserve(input.size() * 2); + + char prev = '*'; + + for (std::string::size_type i = 0; i < input.size(); i++) { + char c = input[i]; + switch (c) { + case '*': + // Avoid "/*". + if (prev == '/') { + result.append("*"); + } else { + result.push_back(c); + } + break; + case '/': + // Avoid "*/". + if (prev == '*') { + result.append("/"); + } else { + result.push_back(c); + } + break; + case '@': + // '@' starts javadoc tags including the @deprecated tag, which will + // cause a compile-time error if inserted before a declaration that + // does not have a corresponding @Deprecated annotation. + result.append("@"); + break; + case '<': + // Avoid interpretation as HTML. + result.append("<"); + break; + case '>': + // Avoid interpretation as HTML. + result.append(">"); + break; + case '&': + // Avoid interpretation as HTML. + result.append("&"); + break; + case '\\': + // Java interprets Unicode escape sequences anywhere! + result.append("\"); + break; + default: + result.push_back(c); + break; + } + + prev = c; + } + + return result; +} + +static void WriteDocCommentBodyForLocation(io::Printer* printer, + const SourceLocation& location) { + std::string comments = location.leading_comments.empty() + ? location.trailing_comments + : location.leading_comments; + if (!comments.empty()) { + // TODO(kenton): Ideally we should parse the comment text as Markdown and + // write it back as HTML, but this requires a Markdown parser. For now + // we just use <pre> to get fixed-width text formatting. + + // If the comment itself contains block comment start or end markers, + // HTML-escape them so that they don't accidentally close the doc comment. + comments = EscapeJavadoc(comments); + + std::vector<std::string> lines = Split(comments, "\n"); + while (!lines.empty() && lines.back().empty()) { + lines.pop_back(); + } + + printer->Print(" * <pre>\n"); + for (int i = 0; i < lines.size(); i++) { + // Most lines should start with a space. Watch out for lines that start + // with a /, since putting that right after the leading asterisk will + // close the comment. + if (!lines[i].empty() && lines[i][0] == '/') { + printer->Print(" * $line$\n", "line", lines[i]); + } else { + printer->Print(" *$line$\n", "line", lines[i]); + } + } + printer->Print( + " * </pre>\n" + " *\n"); + } +} + +template <typename DescriptorType> +static void WriteDocCommentBody(io::Printer* printer, + const DescriptorType* descriptor) { + SourceLocation location; + if (descriptor->GetSourceLocation(&location)) { + WriteDocCommentBodyForLocation(printer, location); + } +} + +static std::string FirstLineOf(const std::string& value) { + std::string result = value; + + std::string::size_type pos = result.find_first_of('\n'); + if (pos != std::string::npos) { + result.erase(pos); + } + + // If line ends in an opening brace, make it "{ ... }" so it looks nice. + if (!result.empty() && result[result.size() - 1] == '{') { + result.append(" ... }"); + } + + return result; +} + +void WriteMessageDocComment(io::Printer* printer, const Descriptor* message) { + printer->Print("/**\n"); + WriteDocCommentBody(printer, message); + printer->Print( + " * Protobuf type {@code $fullname$}\n" + " */\n", + "fullname", EscapeJavadoc(message->full_name())); +} + +void WriteFieldDocComment(io::Printer* printer, const FieldDescriptor* field) { + // We start the comment with the main body based on the comments from the + // .proto file (if present). We then continue with the field declaration, + // e.g.: + // optional string foo = 5; + // And then we end with the javadoc tags if applicable. + // If the field is a group, the debug string might end with {. + printer->Print("/**\n"); + WriteDocCommentBody(printer, field); + printer->Print(" * <code>$def$</code>\n", "def", + EscapeJavadoc(FirstLineOf(field->DebugString()))); + printer->Print(" */\n"); +} + +void WriteDeprecatedJavadoc(io::Printer* printer, const FieldDescriptor* field, + const FieldAccessorType type) { + if (!field->options().deprecated()) { + return; + } + + // Lite codegen does not annotate set & clear methods with @Deprecated. + if (field->file()->options().optimize_for() == FileOptions::LITE_RUNTIME && + (type == SETTER || type == CLEARER)) { + return; + } + + printer->Print(" * @deprecated\n"); +} + +void WriteFieldAccessorDocComment(io::Printer* printer, + const FieldDescriptor* field, + const FieldAccessorType type, + const bool builder) { + printer->Print("/**\n"); + WriteDocCommentBody(printer, field); + printer->Print(" * <code>$def$</code>\n", "def", + EscapeJavadoc(FirstLineOf(field->DebugString()))); + WriteDeprecatedJavadoc(printer, field, type); + switch (type) { + case HAZZER: + printer->Print(" * @return Whether the $name$ field is set.\n", "name", + field->camelcase_name()); + break; + case GETTER: + printer->Print(" * @return The $name$.\n", "name", + field->camelcase_name()); + break; + case SETTER: + printer->Print(" * @param value The $name$ to set.\n", "name", + field->camelcase_name()); + break; + case CLEARER: + // Print nothing + break; + // Repeated + case LIST_COUNT: + printer->Print(" * @return The count of $name$.\n", "name", + field->camelcase_name()); + break; + case LIST_GETTER: + printer->Print(" * @return A list containing the $name$.\n", "name", + field->camelcase_name()); + break; + case LIST_INDEXED_GETTER: + printer->Print(" * @param index The index of the element to return.\n"); + printer->Print(" * @return The $name$ at the given index.\n", "name", + field->camelcase_name()); + break; + case LIST_INDEXED_SETTER: + printer->Print(" * @param index The index to set the value at.\n"); + printer->Print(" * @param value The $name$ to set.\n", "name", + field->camelcase_name()); + break; + case LIST_ADDER: + printer->Print(" * @param value The $name$ to add.\n", "name", + field->camelcase_name()); + break; + case LIST_MULTI_ADDER: + printer->Print(" * @param values The $name$ to add.\n", "name", + field->camelcase_name()); + break; + } + if (builder) { + printer->Print(" * @return This builder for chaining.\n"); + } + printer->Print(" */\n"); +} + +void WriteFieldEnumValueAccessorDocComment(io::Printer* printer, + const FieldDescriptor* field, + const FieldAccessorType type, + const bool builder) { + printer->Print("/**\n"); + WriteDocCommentBody(printer, field); + printer->Print(" * <code>$def$</code>\n", "def", + EscapeJavadoc(FirstLineOf(field->DebugString()))); + WriteDeprecatedJavadoc(printer, field, type); + switch (type) { + case HAZZER: + // Should never happen + break; + case GETTER: + printer->Print( + " * @return The enum numeric value on the wire for $name$.\n", "name", + field->camelcase_name()); + break; + case SETTER: + printer->Print( + " * @param value The enum numeric value on the wire for $name$ to " + "set.\n", + "name", field->camelcase_name()); + break; + case CLEARER: + // Print nothing + break; + // Repeated + case LIST_COUNT: + // Should never happen + break; + case LIST_GETTER: + printer->Print( + " * @return A list containing the enum numeric values on the wire " + "for $name$.\n", + "name", field->camelcase_name()); + break; + case LIST_INDEXED_GETTER: + printer->Print(" * @param index The index of the value to return.\n"); + printer->Print( + " * @return The enum numeric value on the wire of $name$ at the " + "given index.\n", + "name", field->camelcase_name()); + break; + case LIST_INDEXED_SETTER: + printer->Print(" * @param index The index to set the value at.\n"); + printer->Print( + " * @param value The enum numeric value on the wire for $name$ to " + "set.\n", + "name", field->camelcase_name()); + break; + case LIST_ADDER: + printer->Print( + " * @param value The enum numeric value on the wire for $name$ to " + "add.\n", + "name", field->camelcase_name()); + break; + case LIST_MULTI_ADDER: + printer->Print( + " * @param values The enum numeric values on the wire for $name$ to " + "add.\n", + "name", field->camelcase_name()); + break; + } + if (builder) { + printer->Print(" * @return This builder for chaining.\n"); + } + printer->Print(" */\n"); +} + +void WriteFieldStringBytesAccessorDocComment(io::Printer* printer, + const FieldDescriptor* field, + const FieldAccessorType type, + const bool builder) { + printer->Print("/**\n"); + WriteDocCommentBody(printer, field); + printer->Print(" * <code>$def$</code>\n", "def", + EscapeJavadoc(FirstLineOf(field->DebugString()))); + WriteDeprecatedJavadoc(printer, field, type); + switch (type) { + case HAZZER: + // Should never happen + break; + case GETTER: + printer->Print(" * @return The bytes for $name$.\n", "name", + field->camelcase_name()); + break; + case SETTER: + printer->Print(" * @param value The bytes for $name$ to set.\n", "name", + field->camelcase_name()); + break; + case CLEARER: + // Print nothing + break; + // Repeated + case LIST_COUNT: + // Should never happen + break; + case LIST_GETTER: + printer->Print(" * @return A list containing the bytes for $name$.\n", + "name", field->camelcase_name()); + break; + case LIST_INDEXED_GETTER: + printer->Print(" * @param index The index of the value to return.\n"); + printer->Print(" * @return The bytes of the $name$ at the given index.\n", + "name", field->camelcase_name()); + break; + case LIST_INDEXED_SETTER: + printer->Print(" * @param index The index to set the value at.\n"); + printer->Print(" * @param value The bytes of the $name$ to set.\n", + "name", field->camelcase_name()); + break; + case LIST_ADDER: + printer->Print(" * @param value The bytes of the $name$ to add.\n", + "name", field->camelcase_name()); + break; + case LIST_MULTI_ADDER: + printer->Print(" * @param values The bytes of the $name$ to add.\n", + "name", field->camelcase_name()); + break; + } + if (builder) { + printer->Print(" * @return This builder for chaining.\n"); + } + printer->Print(" */\n"); +} + +// Enum + +void WriteEnumDocComment(io::Printer* printer, const EnumDescriptor* enum_) { + printer->Print("/**\n"); + WriteDocCommentBody(printer, enum_); + printer->Print( + " * Protobuf enum {@code $fullname$}\n" + " */\n", + "fullname", EscapeJavadoc(enum_->full_name())); +} + +void WriteEnumValueDocComment(io::Printer* printer, + const EnumValueDescriptor* value) { + printer->Print("/**\n"); + WriteDocCommentBody(printer, value); + printer->Print( + " * <code>$def$</code>\n" + " */\n", + "def", EscapeJavadoc(FirstLineOf(value->DebugString()))); +} + +void WriteServiceDocComment(io::Printer* printer, + const ServiceDescriptor* service) { + printer->Print("/**\n"); + WriteDocCommentBody(printer, service); + printer->Print( + " * Protobuf service {@code $fullname$}\n" + " */\n", + "fullname", EscapeJavadoc(service->full_name())); +} + +void WriteMethodDocComment(io::Printer* printer, + const MethodDescriptor* method) { + printer->Print("/**\n"); + WriteDocCommentBody(printer, method); + printer->Print( + " * <code>$def$</code>\n" + " */\n", + "def", EscapeJavadoc(FirstLineOf(method->DebugString()))); +} + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/java/java_doc_comment.h b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_doc_comment.h new file mode 100644 index 00000000..2706effb --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_doc_comment.h @@ -0,0 +1,101 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_DOC_COMMENT_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVA_DOC_COMMENT_H__ + +#include <descriptor.h> + +#include <port_def.inc> + +namespace google { +namespace protobuf { +namespace io { +class Printer; // printer.h +} +} // namespace protobuf +} // namespace google + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +enum FieldAccessorType { + HAZZER, + GETTER, + SETTER, + CLEARER, + // Repeated + LIST_COUNT, + LIST_GETTER, + LIST_INDEXED_GETTER, + LIST_INDEXED_SETTER, + LIST_ADDER, + LIST_MULTI_ADDER +}; + +void WriteMessageDocComment(io::Printer* printer, const Descriptor* message); +void WriteFieldDocComment(io::Printer* printer, const FieldDescriptor* field); +void WriteFieldAccessorDocComment(io::Printer* printer, + const FieldDescriptor* field, + const FieldAccessorType type, + const bool builder = false); +void WriteFieldEnumValueAccessorDocComment(io::Printer* printer, + const FieldDescriptor* field, + const FieldAccessorType type, + const bool builder = false); +void WriteFieldStringBytesAccessorDocComment(io::Printer* printer, + const FieldDescriptor* field, + const FieldAccessorType type, + const bool builder = false); +void WriteEnumDocComment(io::Printer* printer, const EnumDescriptor* enum_); +void WriteEnumValueDocComment(io::Printer* printer, + const EnumValueDescriptor* value); +void WriteServiceDocComment(io::Printer* printer, + const ServiceDescriptor* service); +void WriteMethodDocComment(io::Printer* printer, + const MethodDescriptor* method); + +// Exposed for testing only. +PROTOC_EXPORT std::string EscapeJavadoc(const std::string& input); + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google + +#include <port_undef.inc> + +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_DOC_COMMENT_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/java/java_doc_comment_unittest.cc b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_doc_comment_unittest.cc new file mode 100644 index 00000000..cbeadd0e --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_doc_comment_unittest.cc @@ -0,0 +1,67 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) + +#include <compiler/java/java_doc_comment.h> + +#include <gtest/gtest.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { +namespace { + +TEST(JavaDocCommentTest, Escaping) { + EXPECT_EQ("foo /* bar */ baz", EscapeJavadoc("foo /* bar */ baz")); + EXPECT_EQ("foo /*/ baz", EscapeJavadoc("foo /*/ baz")); + EXPECT_EQ("{@foo}", EscapeJavadoc("{@foo}")); + EXPECT_EQ("<i>&</i>", EscapeJavadoc("<i>&</i>")); + EXPECT_EQ("foo\u1234bar", EscapeJavadoc("foo\\u1234bar")); + EXPECT_EQ("@deprecated", EscapeJavadoc("@deprecated")); +} + +// TODO(kenton): It's hard to write a robust test of the doc comments -- we +// can only really compare the output against a golden value, which is a +// fairly tedious and fragile testing strategy. If we want to go that route, +// it probably makes sense to bite the bullet and write a test that compares +// the whole generated output for unittest.proto against a golden value, with +// a very simple script that can be run to regenerate it with the latest code. +// This would mean that updates to the golden file would have to be included +// in any change to the code generator, which would actually be fairly useful +// as it allows the reviewer to see clearly how the generated code is +// changing. + +} // namespace +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/java/java_enum.cc b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_enum.cc new file mode 100644 index 00000000..f3eb4bc2 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_enum.cc @@ -0,0 +1,391 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <map> +#include <string> + +#include <compiler/java/java_context.h> +#include <compiler/java/java_doc_comment.h> +#include <compiler/java/java_enum.h> +#include <compiler/java/java_helpers.h> +#include <compiler/java/java_name_resolver.h> +#include <descriptor.pb.h> +#include <io/printer.h> +#include <stubs/strutil.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor, + bool immutable_api, Context* context) + : descriptor_(descriptor), + immutable_api_(immutable_api), + context_(context), + name_resolver_(context->GetNameResolver()) { + for (int i = 0; i < descriptor_->value_count(); i++) { + const EnumValueDescriptor* value = descriptor_->value(i); + const EnumValueDescriptor* canonical_value = + descriptor_->FindValueByNumber(value->number()); + + if (value == canonical_value) { + canonical_values_.push_back(value); + } else { + Alias alias; + alias.value = value; + alias.canonical_value = canonical_value; + aliases_.push_back(alias); + } + } +} + +EnumGenerator::~EnumGenerator() {} + +void EnumGenerator::Generate(io::Printer* printer) { + WriteEnumDocComment(printer, descriptor_); + MaybePrintGeneratedAnnotation(context_, printer, descriptor_, immutable_api_); + printer->Print( + "$deprecation$public enum $classname$\n" + " implements com.google.protobuf.ProtocolMessageEnum {\n", + "classname", descriptor_->name(), "deprecation", + descriptor_->options().deprecated() ? "@java.lang.Deprecated " : ""); + printer->Annotate("classname", descriptor_); + printer->Indent(); + + bool ordinal_is_index = true; + std::string index_text = "ordinal()"; + for (int i = 0; i < canonical_values_.size(); i++) { + if (canonical_values_[i]->index() != i) { + ordinal_is_index = false; + index_text = "index"; + break; + } + } + + for (int i = 0; i < canonical_values_.size(); i++) { + std::map<std::string, std::string> vars; + vars["name"] = canonical_values_[i]->name(); + vars["index"] = StrCat(canonical_values_[i]->index()); + vars["number"] = StrCat(canonical_values_[i]->number()); + WriteEnumValueDocComment(printer, canonical_values_[i]); + if (canonical_values_[i]->options().deprecated()) { + printer->Print("@java.lang.Deprecated\n"); + } + if (ordinal_is_index) { + printer->Print(vars, "$name$($number$),\n"); + } else { + printer->Print(vars, "$name$($index$, $number$),\n"); + } + printer->Annotate("name", canonical_values_[i]); + } + + if (SupportUnknownEnumValue(descriptor_->file())) { + if (ordinal_is_index) { + printer->Print("${$UNRECOGNIZED$}$(-1),\n", "{", "", "}", ""); + } else { + printer->Print("${$UNRECOGNIZED$}$(-1, -1),\n", "{", "", "}", ""); + } + printer->Annotate("{", "}", descriptor_); + } + + printer->Print( + ";\n" + "\n"); + + // ----------------------------------------------------------------- + + for (int i = 0; i < aliases_.size(); i++) { + std::map<std::string, std::string> vars; + vars["classname"] = descriptor_->name(); + vars["name"] = aliases_[i].value->name(); + vars["canonical_name"] = aliases_[i].canonical_value->name(); + WriteEnumValueDocComment(printer, aliases_[i].value); + printer->Print( + vars, "public static final $classname$ $name$ = $canonical_name$;\n"); + printer->Annotate("name", aliases_[i].value); + } + + for (int i = 0; i < descriptor_->value_count(); i++) { + std::map<std::string, std::string> vars; + vars["name"] = descriptor_->value(i)->name(); + vars["number"] = StrCat(descriptor_->value(i)->number()); + vars["{"] = ""; + vars["}"] = ""; + vars["deprecation"] = descriptor_->value(i)->options().deprecated() + ? "@java.lang.Deprecated " + : ""; + WriteEnumValueDocComment(printer, descriptor_->value(i)); + printer->Print(vars, + "$deprecation$public static final int ${$$name$_VALUE$}$ = " + "$number$;\n"); + printer->Annotate("{", "}", descriptor_->value(i)); + } + printer->Print("\n"); + + // ----------------------------------------------------------------- + + printer->Print( + "\n" + "public final int getNumber() {\n"); + if (SupportUnknownEnumValue(descriptor_->file())) { + if (ordinal_is_index) { + printer->Print( + " if (this == UNRECOGNIZED) {\n" + " throw new java.lang.IllegalArgumentException(\n" + " \"Can't get the number of an unknown enum value.\");\n" + " }\n"); + } else { + printer->Print( + " if (index == -1) {\n" + " throw new java.lang.IllegalArgumentException(\n" + " \"Can't get the number of an unknown enum value.\");\n" + " }\n"); + } + } + printer->Print( + " return value;\n" + "}\n" + "\n" + "/**\n" + " * @param value The numeric wire value of the corresponding enum " + "entry.\n" + " * @return The enum associated with the given numeric wire value.\n" + " * @deprecated Use {@link #forNumber(int)} instead.\n" + " */\n" + "@java.lang.Deprecated\n" + "public static $classname$ valueOf(int value) {\n" + " return forNumber(value);\n" + "}\n" + "\n" + "/**\n" + " * @param value The numeric wire value of the corresponding enum " + "entry.\n" + " * @return The enum associated with the given numeric wire value.\n" + " */\n" + "public static $classname$ forNumber(int value) {\n" + " switch (value) {\n", + "classname", descriptor_->name()); + printer->Indent(); + printer->Indent(); + + for (int i = 0; i < canonical_values_.size(); i++) { + printer->Print("case $number$: return $name$;\n", "name", + canonical_values_[i]->name(), "number", + StrCat(canonical_values_[i]->number())); + } + + printer->Outdent(); + printer->Outdent(); + printer->Print( + " default: return null;\n" + " }\n" + "}\n" + "\n" + "public static com.google.protobuf.Internal.EnumLiteMap<$classname$>\n" + " internalGetValueMap() {\n" + " return internalValueMap;\n" + "}\n" + "private static final com.google.protobuf.Internal.EnumLiteMap<\n" + " $classname$> internalValueMap =\n" + " new com.google.protobuf.Internal.EnumLiteMap<$classname$>() {\n" + " public $classname$ findValueByNumber(int number) {\n" + " return $classname$.forNumber(number);\n" + " }\n" + " };\n" + "\n", + "classname", descriptor_->name()); + + // ----------------------------------------------------------------- + // Reflection + + if (HasDescriptorMethods(descriptor_, context_->EnforceLite())) { + printer->Print( + "public final com.google.protobuf.Descriptors.EnumValueDescriptor\n" + " getValueDescriptor() {\n"); + if (SupportUnknownEnumValue(descriptor_->file())) { + if (ordinal_is_index) { + printer->Print( + " if (this == UNRECOGNIZED) {\n" + " throw new java.lang.IllegalStateException(\n" + " \"Can't get the descriptor of an unrecognized enum " + "value.\");\n" + " }\n"); + } else { + printer->Print( + " if (index == -1) {\n" + " throw new java.lang.IllegalStateException(\n" + " \"Can't get the descriptor of an unrecognized enum " + "value.\");\n" + " }\n"); + } + } + printer->Print( + " return getDescriptor().getValues().get($index_text$);\n" + "}\n" + "public final com.google.protobuf.Descriptors.EnumDescriptor\n" + " getDescriptorForType() {\n" + " return getDescriptor();\n" + "}\n" + "public static final com.google.protobuf.Descriptors.EnumDescriptor\n" + " getDescriptor() {\n", + "index_text", index_text); + + // TODO(kenton): Cache statically? Note that we can't access descriptors + // at module init time because it wouldn't work with descriptor.proto, but + // we can cache the value the first time getDescriptor() is called. + if (descriptor_->containing_type() == NULL) { + // The class generated for the File fully populates the descriptor with + // extensions in both the mutable and immutable cases. (In the mutable api + // this is accomplished by attempting to load the immutable outer class). + printer->Print( + " return $file$.getDescriptor().getEnumTypes().get($index$);\n", + "file", + name_resolver_->GetClassName(descriptor_->file(), immutable_api_), + "index", StrCat(descriptor_->index())); + } else { + printer->Print( + " return $parent$.$descriptor$.getEnumTypes().get($index$);\n", + "parent", + name_resolver_->GetClassName(descriptor_->containing_type(), + immutable_api_), + "descriptor", + descriptor_->containing_type() + ->options() + .no_standard_descriptor_accessor() + ? "getDefaultInstance().getDescriptorForType()" + : "getDescriptor()", + "index", StrCat(descriptor_->index())); + } + + printer->Print( + "}\n" + "\n" + "private static final $classname$[] VALUES = ", + "classname", descriptor_->name()); + + if (CanUseEnumValues()) { + // If the constants we are going to output are exactly the ones we + // have declared in the Java enum in the same order, then we can use + // the values() method that the Java compiler automatically generates + // for every enum. + printer->Print("values();\n"); + } else { + printer->Print("getStaticValuesArray();\n"); + printer->Print("private static $classname$[] getStaticValuesArray() {\n", + "classname", descriptor_->name()); + printer->Indent(); + printer->Print( + "return new $classname$[] {\n" + " ", + "classname", descriptor_->name()); + for (int i = 0; i < descriptor_->value_count(); i++) { + printer->Print("$name$, ", "name", descriptor_->value(i)->name()); + } + printer->Print( + "\n" + "};\n"); + printer->Outdent(); + printer->Print("}"); + } + + printer->Print( + "\n" + "public static $classname$ valueOf(\n" + " com.google.protobuf.Descriptors.EnumValueDescriptor desc) {\n" + " if (desc.getType() != getDescriptor()) {\n" + " throw new java.lang.IllegalArgumentException(\n" + " \"EnumValueDescriptor is not for this type.\");\n" + " }\n", + "classname", descriptor_->name()); + if (SupportUnknownEnumValue(descriptor_->file())) { + printer->Print( + " if (desc.getIndex() == -1) {\n" + " return UNRECOGNIZED;\n" + " }\n"); + } + printer->Print( + " return VALUES[desc.getIndex()];\n" + "}\n" + "\n"); + + if (!ordinal_is_index) { + printer->Print("private final int index;\n"); + } + } + + // ----------------------------------------------------------------- + + printer->Print("private final int value;\n\n"); + + if (ordinal_is_index) { + printer->Print("private $classname$(int value) {\n", "classname", + descriptor_->name()); + } else { + printer->Print("private $classname$(int index, int value) {\n", "classname", + descriptor_->name()); + } + if (HasDescriptorMethods(descriptor_, context_->EnforceLite()) && + !ordinal_is_index) { + printer->Print(" this.index = index;\n"); + } + printer->Print( + " this.value = value;\n" + "}\n"); + + printer->Print( + "\n" + "// @@protoc_insertion_point(enum_scope:$full_name$)\n", + "full_name", descriptor_->full_name()); + + printer->Outdent(); + printer->Print("}\n\n"); +} + +bool EnumGenerator::CanUseEnumValues() { + if (canonical_values_.size() != descriptor_->value_count()) { + return false; + } + for (int i = 0; i < descriptor_->value_count(); i++) { + if (descriptor_->value(i)->name() != canonical_values_[i]->name()) { + return false; + } + } + return true; +} + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/java/java_enum.h b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_enum.h new file mode 100644 index 00000000..cae2ffea --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_enum.h @@ -0,0 +1,100 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_H__ + +#include <string> +#include <vector> +#include <descriptor.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { +class Context; // context.h +class ClassNameResolver; // name_resolver.h +} // namespace java +} // namespace compiler +namespace io { +class Printer; // printer.h +} +} // namespace protobuf +} // namespace google + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +class EnumGenerator { + public: + EnumGenerator(const EnumDescriptor* descriptor, bool immutable_api, + Context* context); + ~EnumGenerator(); + + void Generate(io::Printer* printer); + + private: + const EnumDescriptor* descriptor_; + + // The proto language allows multiple enum constants to have the same + // numeric value. Java, however, does not allow multiple enum constants to + // be considered equivalent. We treat the first defined constant for any + // given numeric value as "canonical" and the rest as aliases of that + // canonical value. + std::vector<const EnumValueDescriptor*> canonical_values_; + + struct Alias { + const EnumValueDescriptor* value; + const EnumValueDescriptor* canonical_value; + }; + std::vector<Alias> aliases_; + + bool immutable_api_; + + Context* context_; + ClassNameResolver* name_resolver_; + + bool CanUseEnumValues(); + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumGenerator); +}; + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/java/java_enum_field.cc b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_enum_field.cc new file mode 100644 index 00000000..51e944df --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_enum_field.cc @@ -0,0 +1,1176 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <compiler/java/java_enum_field.h> + +#include <cstdint> +#include <map> +#include <string> + +#include <stubs/logging.h> +#include <stubs/common.h> +#include <compiler/java/java_context.h> +#include <compiler/java/java_doc_comment.h> +#include <compiler/java/java_helpers.h> +#include <compiler/java/java_name_resolver.h> +#include <io/printer.h> +#include <wire_format.h> +#include <stubs/strutil.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +namespace { + +void SetEnumVariables(const FieldDescriptor* descriptor, int messageBitIndex, + int builderBitIndex, const FieldGeneratorInfo* info, + ClassNameResolver* name_resolver, + std::map<std::string, std::string>* variables) { + SetCommonFieldVariables(descriptor, info, variables); + + (*variables)["type"] = + name_resolver->GetImmutableClassName(descriptor->enum_type()); + (*variables)["kt_type"] = (*variables)["type"]; + (*variables)["mutable_type"] = + name_resolver->GetMutableClassName(descriptor->enum_type()); + (*variables)["default"] = ImmutableDefaultValue(descriptor, name_resolver); + (*variables)["default_number"] = + StrCat(descriptor->default_value_enum()->number()); + (*variables)["tag"] = StrCat( + static_cast<int32_t>(internal::WireFormat::MakeTag(descriptor))); + (*variables)["tag_size"] = StrCat( + internal::WireFormat::TagSize(descriptor->number(), GetType(descriptor))); + // TODO(birdo): Add @deprecated javadoc when generating javadoc is supported + // by the proto compiler + (*variables)["deprecation"] = + descriptor->options().deprecated() ? "@java.lang.Deprecated " : ""; + (*variables)["kt_deprecation"] = + descriptor->options().deprecated() + ? "@kotlin.Deprecated(message = \"Field " + (*variables)["name"] + + " is deprecated\") " + : ""; + (*variables)["on_changed"] = "onChanged();"; + // Use deprecated valueOf() method to be compatible with old generated code + // for v2.5.0/v2.6.1. + // TODO(xiaofeng): Use "forNumber" when we no longer support compatibility + // with v2.5.0/v2.6.1, and remove the @SuppressWarnings annotations. + (*variables)["for_number"] = "valueOf"; + + if (HasHasbit(descriptor)) { + // For singular messages and builders, one bit is used for the hasField bit. + (*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex); + (*variables)["get_has_field_bit_builder"] = GenerateGetBit(builderBitIndex); + + // Note that these have a trailing ";". + (*variables)["set_has_field_bit_message"] = + GenerateSetBit(messageBitIndex) + ";"; + (*variables)["set_has_field_bit_builder"] = + GenerateSetBit(builderBitIndex) + ";"; + (*variables)["clear_has_field_bit_builder"] = + GenerateClearBit(builderBitIndex) + ";"; + + (*variables)["is_field_present_message"] = GenerateGetBit(messageBitIndex); + } else { + (*variables)["set_has_field_bit_message"] = ""; + (*variables)["set_has_field_bit_builder"] = ""; + (*variables)["clear_has_field_bit_builder"] = ""; + + (*variables)["is_field_present_message"] = + (*variables)["name"] + "_ != " + (*variables)["default"] + + ".getNumber()"; + } + + // For repeated builders, one bit is used for whether the array is immutable. + (*variables)["get_mutable_bit_builder"] = GenerateGetBit(builderBitIndex); + (*variables)["set_mutable_bit_builder"] = GenerateSetBit(builderBitIndex); + (*variables)["clear_mutable_bit_builder"] = GenerateClearBit(builderBitIndex); + + // For repeated fields, one bit is used for whether the array is immutable + // in the parsing constructor. + (*variables)["get_mutable_bit_parser"] = + GenerateGetBitMutableLocal(builderBitIndex); + (*variables)["set_mutable_bit_parser"] = + GenerateSetBitMutableLocal(builderBitIndex); + + (*variables)["get_has_field_bit_from_local"] = + GenerateGetBitFromLocal(builderBitIndex); + (*variables)["set_has_field_bit_to_local"] = + GenerateSetBitToLocal(messageBitIndex); + + if (SupportUnknownEnumValue(descriptor->file())) { + (*variables)["unknown"] = (*variables)["type"] + ".UNRECOGNIZED"; + } else { + (*variables)["unknown"] = (*variables)["default"]; + } +} + +} // namespace + +// =================================================================== + +ImmutableEnumFieldGenerator::ImmutableEnumFieldGenerator( + const FieldDescriptor* descriptor, int messageBitIndex, int builderBitIndex, + Context* context) + : descriptor_(descriptor), name_resolver_(context->GetNameResolver()) { + SetEnumVariables(descriptor, messageBitIndex, builderBitIndex, + context->GetFieldGeneratorInfo(descriptor), name_resolver_, + &variables_); +} + +ImmutableEnumFieldGenerator::~ImmutableEnumFieldGenerator() {} + +int ImmutableEnumFieldGenerator::GetNumBitsForMessage() const { + return HasHasbit(descriptor_) ? 1 : 0; +} + +int ImmutableEnumFieldGenerator::GetNumBitsForBuilder() const { + return GetNumBitsForMessage(); +} + +void ImmutableEnumFieldGenerator::GenerateInterfaceMembers( + io::Printer* printer) const { + if (HasHazzer(descriptor_)) { + WriteFieldAccessorDocComment(printer, descriptor_, HAZZER); + printer->Print(variables_, + "$deprecation$boolean has$capitalized_name$();\n"); + } + if (SupportUnknownEnumValue(descriptor_->file())) { + WriteFieldEnumValueAccessorDocComment(printer, descriptor_, GETTER); + printer->Print(variables_, + "$deprecation$int get$capitalized_name$Value();\n"); + } + WriteFieldAccessorDocComment(printer, descriptor_, GETTER); + printer->Print(variables_, "$deprecation$$type$ get$capitalized_name$();\n"); +} + +void ImmutableEnumFieldGenerator::GenerateMembers(io::Printer* printer) const { + printer->Print(variables_, "private int $name$_;\n"); + PrintExtraFieldInfo(variables_, printer); + if (HasHazzer(descriptor_)) { + WriteFieldAccessorDocComment(printer, descriptor_, HAZZER); + printer->Print(variables_, + "@java.lang.Override $deprecation$public boolean " + "${$has$capitalized_name$$}$() {\n" + " return $get_has_field_bit_message$;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + } + if (SupportUnknownEnumValue(descriptor_->file())) { + WriteFieldEnumValueAccessorDocComment(printer, descriptor_, GETTER); + printer->Print(variables_, + "@java.lang.Override $deprecation$public int " + "${$get$capitalized_name$Value$}$() {\n" + " return $name$_;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + } + WriteFieldAccessorDocComment(printer, descriptor_, GETTER); + printer->Print(variables_, + "@java.lang.Override $deprecation$public $type$ " + "${$get$capitalized_name$$}$() {\n" + " @SuppressWarnings(\"deprecation\")\n" + " $type$ result = $type$.$for_number$($name$_);\n" + " return result == null ? $unknown$ : result;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); +} + +void ImmutableEnumFieldGenerator::GenerateBuilderMembers( + io::Printer* printer) const { + printer->Print(variables_, "private int $name$_ = $default_number$;\n"); + if (HasHazzer(descriptor_)) { + WriteFieldAccessorDocComment(printer, descriptor_, HAZZER); + printer->Print(variables_, + "@java.lang.Override $deprecation$public boolean " + "${$has$capitalized_name$$}$() {\n" + " return $get_has_field_bit_builder$;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + } + if (SupportUnknownEnumValue(descriptor_->file())) { + WriteFieldEnumValueAccessorDocComment(printer, descriptor_, GETTER); + printer->Print(variables_, + "@java.lang.Override $deprecation$public int " + "${$get$capitalized_name$Value$}$() {\n" + " return $name$_;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldEnumValueAccessorDocComment(printer, descriptor_, SETTER, + /* builder */ true); + printer->Print(variables_, + "$deprecation$public Builder " + "${$set$capitalized_name$Value$}$(int value) {\n" + " $set_has_field_bit_builder$\n" + " $name$_ = value;\n" + " $on_changed$\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + } + WriteFieldAccessorDocComment(printer, descriptor_, GETTER); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$public $type$ ${$get$capitalized_name$$}$() {\n" + " @SuppressWarnings(\"deprecation\")\n" + " $type$ result = $type$.$for_number$($name$_);\n" + " return result == null ? $unknown$ : result;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldAccessorDocComment(printer, descriptor_, SETTER, + /* builder */ true); + printer->Print(variables_, + "$deprecation$public Builder " + "${$set$capitalized_name$$}$($type$ value) {\n" + " if (value == null) {\n" + " throw new NullPointerException();\n" + " }\n" + " $set_has_field_bit_builder$\n" + " $name$_ = value.getNumber();\n" + " $on_changed$\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldAccessorDocComment(printer, descriptor_, CLEARER, + /* builder */ true); + printer->Print( + variables_, + "$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n" + " $clear_has_field_bit_builder$\n" + " $name$_ = $default_number$;\n" + " $on_changed$\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); +} + +void ImmutableEnumFieldGenerator::GenerateKotlinDslMembers( + io::Printer* printer) const { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$kt_deprecation$public var $kt_name$: $kt_type$\n" + " @JvmName(\"${$get$kt_capitalized_name$$}$\")\n" + " get() = $kt_dsl_builder$.${$get$capitalized_name$$}$()\n" + " @JvmName(\"${$set$kt_capitalized_name$$}$\")\n" + " set(value) {\n" + " $kt_dsl_builder$.${$set$capitalized_name$$}$(value)\n" + " }\n"); + + WriteFieldAccessorDocComment(printer, descriptor_, CLEARER, + /* builder */ false); + printer->Print(variables_, + "public fun ${$clear$kt_capitalized_name$$}$() {\n" + " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n" + "}\n"); + + if (HasHazzer(descriptor_)) { + WriteFieldAccessorDocComment(printer, descriptor_, HAZZER); + printer->Print( + variables_, + "public fun ${$has$kt_capitalized_name$$}$(): kotlin.Boolean {\n" + " return $kt_dsl_builder$.${$has$capitalized_name$$}$()\n" + "}\n"); + } +} + +void ImmutableEnumFieldGenerator::GenerateFieldBuilderInitializationCode( + io::Printer* printer) const { + // noop for enums +} + +void ImmutableEnumFieldGenerator::GenerateInitializationCode( + io::Printer* printer) const { + printer->Print(variables_, "$name$_ = $default_number$;\n"); +} + +void ImmutableEnumFieldGenerator::GenerateBuilderClearCode( + io::Printer* printer) const { + printer->Print(variables_, + "$name$_ = $default_number$;\n" + "$clear_has_field_bit_builder$\n"); +} + +void ImmutableEnumFieldGenerator::GenerateMergingCode( + io::Printer* printer) const { + if (HasHazzer(descriptor_)) { + printer->Print(variables_, + "if (other.has$capitalized_name$()) {\n" + " set$capitalized_name$(other.get$capitalized_name$());\n" + "}\n"); + } else if (SupportUnknownEnumValue(descriptor_->file())) { + printer->Print( + variables_, + "if (other.$name$_ != $default_number$) {\n" + " set$capitalized_name$Value(other.get$capitalized_name$Value());\n" + "}\n"); + } else { + GOOGLE_LOG(FATAL) << "Can't reach here."; + } +} + +void ImmutableEnumFieldGenerator::GenerateBuildingCode( + io::Printer* printer) const { + if (HasHazzer(descriptor_)) { + printer->Print(variables_, + "if ($get_has_field_bit_from_local$) {\n" + " $set_has_field_bit_to_local$;\n" + "}\n"); + } + printer->Print(variables_, "result.$name$_ = $name$_;\n"); +} + +void ImmutableEnumFieldGenerator::GenerateParsingCode( + io::Printer* printer) const { + if (SupportUnknownEnumValue(descriptor_->file())) { + printer->Print(variables_, + "int rawValue = input.readEnum();\n" + "$set_has_field_bit_message$\n" + "$name$_ = rawValue;\n"); + } else { + printer->Print(variables_, + "int rawValue = input.readEnum();\n" + " @SuppressWarnings(\"deprecation\")\n" + "$type$ value = $type$.$for_number$(rawValue);\n" + "if (value == null) {\n" + " unknownFields.mergeVarintField($number$, rawValue);\n" + "} else {\n" + " $set_has_field_bit_message$\n" + " $name$_ = rawValue;\n" + "}\n"); + } +} + +void ImmutableEnumFieldGenerator::GenerateParsingDoneCode( + io::Printer* printer) const { + // noop for enums +} + +void ImmutableEnumFieldGenerator::GenerateSerializationCode( + io::Printer* printer) const { + printer->Print(variables_, + "if ($is_field_present_message$) {\n" + " output.writeEnum($number$, $name$_);\n" + "}\n"); +} + +void ImmutableEnumFieldGenerator::GenerateSerializedSizeCode( + io::Printer* printer) const { + printer->Print(variables_, + "if ($is_field_present_message$) {\n" + " size += com.google.protobuf.CodedOutputStream\n" + " .computeEnumSize($number$, $name$_);\n" + "}\n"); +} + +void ImmutableEnumFieldGenerator::GenerateEqualsCode( + io::Printer* printer) const { + printer->Print(variables_, "if ($name$_ != other.$name$_) return false;\n"); +} + +void ImmutableEnumFieldGenerator::GenerateHashCode(io::Printer* printer) const { + printer->Print(variables_, + "hash = (37 * hash) + $constant_name$;\n" + "hash = (53 * hash) + $name$_;\n"); +} + +std::string ImmutableEnumFieldGenerator::GetBoxedType() const { + return name_resolver_->GetImmutableClassName(descriptor_->enum_type()); +} + +// =================================================================== + +ImmutableEnumOneofFieldGenerator::ImmutableEnumOneofFieldGenerator( + const FieldDescriptor* descriptor, int messageBitIndex, int builderBitIndex, + Context* context) + : ImmutableEnumFieldGenerator(descriptor, messageBitIndex, builderBitIndex, + context) { + const OneofGeneratorInfo* info = + context->GetOneofGeneratorInfo(descriptor->containing_oneof()); + SetCommonOneofVariables(descriptor, info, &variables_); +} + +ImmutableEnumOneofFieldGenerator::~ImmutableEnumOneofFieldGenerator() {} + +void ImmutableEnumOneofFieldGenerator::GenerateMembers( + io::Printer* printer) const { + PrintExtraFieldInfo(variables_, printer); + GOOGLE_DCHECK(HasHazzer(descriptor_)); + WriteFieldAccessorDocComment(printer, descriptor_, HAZZER); + printer->Print(variables_, + "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n" + " return $has_oneof_case_message$;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + if (SupportUnknownEnumValue(descriptor_->file())) { + WriteFieldEnumValueAccessorDocComment(printer, descriptor_, GETTER); + printer->Print( + variables_, + "$deprecation$public int ${$get$capitalized_name$Value$}$() {\n" + " if ($has_oneof_case_message$) {\n" + " return (java.lang.Integer) $oneof_name$_;\n" + " }\n" + " return $default_number$;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + } + WriteFieldAccessorDocComment(printer, descriptor_, GETTER); + printer->Print(variables_, + "$deprecation$public $type$ ${$get$capitalized_name$$}$() {\n" + " if ($has_oneof_case_message$) {\n" + " @SuppressWarnings(\"deprecation\")\n" + " $type$ result = $type$.$for_number$(\n" + " (java.lang.Integer) $oneof_name$_);\n" + " return result == null ? $unknown$ : result;\n" + " }\n" + " return $default$;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); +} + +void ImmutableEnumOneofFieldGenerator::GenerateBuilderMembers( + io::Printer* printer) const { + GOOGLE_DCHECK(HasHazzer(descriptor_)); + WriteFieldAccessorDocComment(printer, descriptor_, HAZZER); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n" + " return $has_oneof_case_message$;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + if (SupportUnknownEnumValue(descriptor_->file())) { + WriteFieldEnumValueAccessorDocComment(printer, descriptor_, GETTER); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$public int ${$get$capitalized_name$Value$}$() {\n" + " if ($has_oneof_case_message$) {\n" + " return ((java.lang.Integer) $oneof_name$_).intValue();\n" + " }\n" + " return $default_number$;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldEnumValueAccessorDocComment(printer, descriptor_, SETTER, + /* builder */ true); + printer->Print(variables_, + "$deprecation$public Builder " + "${$set$capitalized_name$Value$}$(int value) {\n" + " $set_oneof_case_message$;\n" + " $oneof_name$_ = value;\n" + " $on_changed$\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + } + WriteFieldAccessorDocComment(printer, descriptor_, GETTER); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$public $type$ ${$get$capitalized_name$$}$() {\n" + " if ($has_oneof_case_message$) {\n" + " @SuppressWarnings(\"deprecation\")\n" + " $type$ result = $type$.$for_number$(\n" + " (java.lang.Integer) $oneof_name$_);\n" + " return result == null ? $unknown$ : result;\n" + " }\n" + " return $default$;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldAccessorDocComment(printer, descriptor_, SETTER, + /* builder */ true); + printer->Print(variables_, + "$deprecation$public Builder " + "${$set$capitalized_name$$}$($type$ value) {\n" + " if (value == null) {\n" + " throw new NullPointerException();\n" + " }\n" + " $set_oneof_case_message$;\n" + " $oneof_name$_ = value.getNumber();\n" + " $on_changed$\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldAccessorDocComment(printer, descriptor_, CLEARER, + /* builder */ true); + printer->Print( + variables_, + "$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n" + " if ($has_oneof_case_message$) {\n" + " $clear_oneof_case_message$;\n" + " $oneof_name$_ = null;\n" + " $on_changed$\n" + " }\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); +} + +void ImmutableEnumOneofFieldGenerator::GenerateBuildingCode( + io::Printer* printer) const { + printer->Print(variables_, + "if ($has_oneof_case_message$) {\n" + " result.$oneof_name$_ = $oneof_name$_;\n" + "}\n"); +} + +void ImmutableEnumOneofFieldGenerator::GenerateMergingCode( + io::Printer* printer) const { + if (SupportUnknownEnumValue(descriptor_->file())) { + printer->Print( + variables_, + "set$capitalized_name$Value(other.get$capitalized_name$Value());\n"); + } else { + printer->Print(variables_, + "set$capitalized_name$(other.get$capitalized_name$());\n"); + } +} + +void ImmutableEnumOneofFieldGenerator::GenerateParsingCode( + io::Printer* printer) const { + if (SupportUnknownEnumValue(descriptor_->file())) { + printer->Print(variables_, + "int rawValue = input.readEnum();\n" + "$set_oneof_case_message$;\n" + "$oneof_name$_ = rawValue;\n"); + } else { + printer->Print(variables_, + "int rawValue = input.readEnum();\n" + "@SuppressWarnings(\"deprecation\")\n" + "$type$ value = $type$.$for_number$(rawValue);\n" + "if (value == null) {\n" + " unknownFields.mergeVarintField($number$, rawValue);\n" + "} else {\n" + " $set_oneof_case_message$;\n" + " $oneof_name$_ = rawValue;\n" + "}\n"); + } +} + +void ImmutableEnumOneofFieldGenerator::GenerateSerializationCode( + io::Printer* printer) const { + printer->Print( + variables_, + "if ($has_oneof_case_message$) {\n" + " output.writeEnum($number$, ((java.lang.Integer) $oneof_name$_));\n" + "}\n"); +} + +void ImmutableEnumOneofFieldGenerator::GenerateSerializedSizeCode( + io::Printer* printer) const { + printer->Print( + variables_, + "if ($has_oneof_case_message$) {\n" + " size += com.google.protobuf.CodedOutputStream\n" + " .computeEnumSize($number$, ((java.lang.Integer) $oneof_name$_));\n" + "}\n"); +} + +void ImmutableEnumOneofFieldGenerator::GenerateEqualsCode( + io::Printer* printer) const { + if (SupportUnknownEnumValue(descriptor_->file())) { + printer->Print( + variables_, + "if (get$capitalized_name$Value()\n" + " != other.get$capitalized_name$Value()) return false;\n"); + } else { + printer->Print( + variables_, + "if (!get$capitalized_name$()\n" + " .equals(other.get$capitalized_name$())) return false;\n"); + } +} + +void ImmutableEnumOneofFieldGenerator::GenerateHashCode( + io::Printer* printer) const { + if (SupportUnknownEnumValue(descriptor_->file())) { + printer->Print(variables_, + "hash = (37 * hash) + $constant_name$;\n" + "hash = (53 * hash) + get$capitalized_name$Value();\n"); + } else { + printer->Print( + variables_, + "hash = (37 * hash) + $constant_name$;\n" + "hash = (53 * hash) + get$capitalized_name$().getNumber();\n"); + } +} + +// =================================================================== + +RepeatedImmutableEnumFieldGenerator::RepeatedImmutableEnumFieldGenerator( + const FieldDescriptor* descriptor, int messageBitIndex, int builderBitIndex, + Context* context) + : descriptor_(descriptor), name_resolver_(context->GetNameResolver()) { + SetEnumVariables(descriptor, messageBitIndex, builderBitIndex, + context->GetFieldGeneratorInfo(descriptor), name_resolver_, + &variables_); +} + +RepeatedImmutableEnumFieldGenerator::~RepeatedImmutableEnumFieldGenerator() {} + +int RepeatedImmutableEnumFieldGenerator::GetNumBitsForMessage() const { + return 0; +} + +int RepeatedImmutableEnumFieldGenerator::GetNumBitsForBuilder() const { + return 1; +} + +void RepeatedImmutableEnumFieldGenerator::GenerateInterfaceMembers( + io::Printer* printer) const { + WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER); + printer->Print( + variables_, + "$deprecation$java.util.List<$type$> get$capitalized_name$List();\n"); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_COUNT); + printer->Print(variables_, + "$deprecation$int get$capitalized_name$Count();\n"); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_GETTER); + printer->Print(variables_, + "$deprecation$$type$ get$capitalized_name$(int index);\n"); + if (SupportUnknownEnumValue(descriptor_->file())) { + WriteFieldEnumValueAccessorDocComment(printer, descriptor_, LIST_GETTER); + printer->Print(variables_, + "$deprecation$java.util.List<java.lang.Integer>\n" + "get$capitalized_name$ValueList();\n"); + WriteFieldEnumValueAccessorDocComment(printer, descriptor_, + LIST_INDEXED_GETTER); + printer->Print(variables_, + "$deprecation$int get$capitalized_name$Value(int index);\n"); + } +} + +void RepeatedImmutableEnumFieldGenerator::GenerateMembers( + io::Printer* printer) const { + printer->Print( + variables_, + "private java.util.List<java.lang.Integer> $name$_;\n" + "private static final " + "com.google.protobuf.Internal.ListAdapter.Converter<\n" + " java.lang.Integer, $type$> $name$_converter_ =\n" + " new com.google.protobuf.Internal.ListAdapter.Converter<\n" + " java.lang.Integer, $type$>() {\n" + " public $type$ convert(java.lang.Integer from) {\n" + " @SuppressWarnings(\"deprecation\")\n" + " $type$ result = $type$.$for_number$(from);\n" + " return result == null ? $unknown$ : result;\n" + " }\n" + " };\n"); + PrintExtraFieldInfo(variables_, printer); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$public java.util.List<$type$> " + "${$get$capitalized_name$List$}$() {\n" + " return new com.google.protobuf.Internal.ListAdapter<\n" + " java.lang.Integer, $type$>($name$_, $name$_converter_);\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_COUNT); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$public int ${$get$capitalized_name$Count$}$() {\n" + " return $name$_.size();\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_GETTER); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$public $type$ ${$get$capitalized_name$$}$(int index) {\n" + " return $name$_converter_.convert($name$_.get(index));\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + if (SupportUnknownEnumValue(descriptor_->file())) { + WriteFieldEnumValueAccessorDocComment(printer, descriptor_, LIST_GETTER); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$public java.util.List<java.lang.Integer>\n" + "${$get$capitalized_name$ValueList$}$() {\n" + " return $name$_;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldEnumValueAccessorDocComment(printer, descriptor_, + LIST_INDEXED_GETTER); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$public int " + "${$get$capitalized_name$Value$}$(int index) {\n" + " return $name$_.get(index);\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + } + + if (descriptor_->is_packed()) { + printer->Print(variables_, "private int $name$MemoizedSerializedSize;\n"); + } +} + +void RepeatedImmutableEnumFieldGenerator::GenerateBuilderMembers( + io::Printer* printer) const { + printer->Print( + variables_, + // One field is the list and the other field keeps track of whether the + // list is immutable. If it's immutable, the invariant is that it must + // either an instance of Collections.emptyList() or it's an ArrayList + // wrapped in a Collections.unmodifiableList() wrapper and nobody else has + // a reference to the underlying ArrayList. This invariant allows us to + // share instances of lists between protocol buffers avoiding expensive + // memory allocations. Note, immutable is a strong guarantee here -- not + // just that the list cannot be modified via the reference but that the + // list can never be modified. + "private java.util.List<java.lang.Integer> $name$_ =\n" + " java.util.Collections.emptyList();\n" + + "private void ensure$capitalized_name$IsMutable() {\n" + " if (!$get_mutable_bit_builder$) {\n" + " $name$_ = new java.util.ArrayList<java.lang.Integer>($name$_);\n" + " $set_mutable_bit_builder$;\n" + " }\n" + "}\n"); + + WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER); + printer->Print( + variables_, + // Note: We return an unmodifiable list because otherwise the caller + // could hold on to the returned list and modify it after the message + // has been built, thus mutating the message which is supposed to be + // immutable. + "$deprecation$public java.util.List<$type$> " + "${$get$capitalized_name$List$}$() {\n" + " return new com.google.protobuf.Internal.ListAdapter<\n" + " java.lang.Integer, $type$>($name$_, $name$_converter_);\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_COUNT); + printer->Print( + variables_, + "$deprecation$public int ${$get$capitalized_name$Count$}$() {\n" + " return $name$_.size();\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_GETTER); + printer->Print( + variables_, + "$deprecation$public $type$ ${$get$capitalized_name$$}$(int index) {\n" + " return $name$_converter_.convert($name$_.get(index));\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_SETTER, + /* builder */ true); + printer->Print(variables_, + "$deprecation$public Builder ${$set$capitalized_name$$}$(\n" + " int index, $type$ value) {\n" + " if (value == null) {\n" + " throw new NullPointerException();\n" + " }\n" + " ensure$capitalized_name$IsMutable();\n" + " $name$_.set(index, value.getNumber());\n" + " $on_changed$\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER, + /* builder */ true); + printer->Print(variables_, + "$deprecation$public Builder " + "${$add$capitalized_name$$}$($type$ value) {\n" + " if (value == null) {\n" + " throw new NullPointerException();\n" + " }\n" + " ensure$capitalized_name$IsMutable();\n" + " $name$_.add(value.getNumber());\n" + " $on_changed$\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER, + /* builder */ true); + printer->Print(variables_, + "$deprecation$public Builder ${$addAll$capitalized_name$$}$(\n" + " java.lang.Iterable<? extends $type$> values) {\n" + " ensure$capitalized_name$IsMutable();\n" + " for ($type$ value : values) {\n" + " $name$_.add(value.getNumber());\n" + " }\n" + " $on_changed$\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldAccessorDocComment(printer, descriptor_, CLEARER, + /* builder */ true); + printer->Print( + variables_, + "$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n" + " $name$_ = java.util.Collections.emptyList();\n" + " $clear_mutable_bit_builder$;\n" + " $on_changed$\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + if (SupportUnknownEnumValue(descriptor_->file())) { + WriteFieldEnumValueAccessorDocComment(printer, descriptor_, LIST_GETTER); + printer->Print(variables_, + "$deprecation$public java.util.List<java.lang.Integer>\n" + "${$get$capitalized_name$ValueList$}$() {\n" + " return java.util.Collections.unmodifiableList($name$_);\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldEnumValueAccessorDocComment(printer, descriptor_, + LIST_INDEXED_GETTER); + printer->Print(variables_, + "$deprecation$public int " + "${$get$capitalized_name$Value$}$(int index) {\n" + " return $name$_.get(index);\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldEnumValueAccessorDocComment(printer, descriptor_, + LIST_INDEXED_GETTER, + /* builder */ true); + printer->Print( + variables_, + "$deprecation$public Builder ${$set$capitalized_name$Value$}$(\n" + " int index, int value) {\n" + " ensure$capitalized_name$IsMutable();\n" + " $name$_.set(index, value);\n" + " $on_changed$\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldEnumValueAccessorDocComment(printer, descriptor_, LIST_ADDER, + /* builder */ true); + printer->Print(variables_, + "$deprecation$public Builder " + "${$add$capitalized_name$Value$}$(int value) {\n" + " ensure$capitalized_name$IsMutable();\n" + " $name$_.add(value);\n" + " $on_changed$\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldEnumValueAccessorDocComment(printer, descriptor_, + LIST_MULTI_ADDER, /* builder */ true); + printer->Print( + variables_, + "$deprecation$public Builder ${$addAll$capitalized_name$Value$}$(\n" + " java.lang.Iterable<java.lang.Integer> values) {\n" + " ensure$capitalized_name$IsMutable();\n" + " for (int value : values) {\n" + " $name$_.add(value);\n" + " }\n" + " $on_changed$\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + } +} + +void RepeatedImmutableEnumFieldGenerator:: + GenerateFieldBuilderInitializationCode(io::Printer* printer) const { + // noop for enums +} + +void RepeatedImmutableEnumFieldGenerator::GenerateInitializationCode( + io::Printer* printer) const { + printer->Print(variables_, "$name$_ = java.util.Collections.emptyList();\n"); +} + +void RepeatedImmutableEnumFieldGenerator::GenerateBuilderClearCode( + io::Printer* printer) const { + printer->Print(variables_, + "$name$_ = java.util.Collections.emptyList();\n" + "$clear_mutable_bit_builder$;\n"); +} + +void RepeatedImmutableEnumFieldGenerator::GenerateMergingCode( + io::Printer* printer) const { + // The code below does two optimizations: + // 1. If the other list is empty, there's nothing to do. This ensures we + // don't allocate a new array if we already have an immutable one. + // 2. If the other list is non-empty and our current list is empty, we can + // reuse the other list which is guaranteed to be immutable. + printer->Print(variables_, + "if (!other.$name$_.isEmpty()) {\n" + " if ($name$_.isEmpty()) {\n" + " $name$_ = other.$name$_;\n" + " $clear_mutable_bit_builder$;\n" + " } else {\n" + " ensure$capitalized_name$IsMutable();\n" + " $name$_.addAll(other.$name$_);\n" + " }\n" + " $on_changed$\n" + "}\n"); +} + +void RepeatedImmutableEnumFieldGenerator::GenerateBuildingCode( + io::Printer* printer) const { + // The code below ensures that the result has an immutable list. If our + // list is immutable, we can just reuse it. If not, we make it immutable. + printer->Print( + variables_, + "if ($get_mutable_bit_builder$) {\n" + " $name$_ = java.util.Collections.unmodifiableList($name$_);\n" + " $clear_mutable_bit_builder$;\n" + "}\n" + "result.$name$_ = $name$_;\n"); +} + +void RepeatedImmutableEnumFieldGenerator::GenerateParsingCode( + io::Printer* printer) const { + // Read and store the enum + if (SupportUnknownEnumValue(descriptor_->file())) { + printer->Print(variables_, + "int rawValue = input.readEnum();\n" + "if (!$get_mutable_bit_parser$) {\n" + " $name$_ = new java.util.ArrayList<java.lang.Integer>();\n" + " $set_mutable_bit_parser$;\n" + "}\n" + "$name$_.add(rawValue);\n"); + } else { + printer->Print( + variables_, + "int rawValue = input.readEnum();\n" + "@SuppressWarnings(\"deprecation\")\n" + "$type$ value = $type$.$for_number$(rawValue);\n" + "if (value == null) {\n" + " unknownFields.mergeVarintField($number$, rawValue);\n" + "} else {\n" + " if (!$get_mutable_bit_parser$) {\n" + " $name$_ = new java.util.ArrayList<java.lang.Integer>();\n" + " $set_mutable_bit_parser$;\n" + " }\n" + " $name$_.add(rawValue);\n" + "}\n"); + } +} + +void RepeatedImmutableEnumFieldGenerator::GenerateParsingCodeFromPacked( + io::Printer* printer) const { + // Wrap GenerateParsingCode's contents with a while loop. + + printer->Print(variables_, + "int length = input.readRawVarint32();\n" + "int oldLimit = input.pushLimit(length);\n" + "while(input.getBytesUntilLimit() > 0) {\n"); + printer->Indent(); + + GenerateParsingCode(printer); + + printer->Outdent(); + printer->Print(variables_, + "}\n" + "input.popLimit(oldLimit);\n"); +} + +void RepeatedImmutableEnumFieldGenerator::GenerateParsingDoneCode( + io::Printer* printer) const { + printer->Print( + variables_, + "if ($get_mutable_bit_parser$) {\n" + " $name$_ = java.util.Collections.unmodifiableList($name$_);\n" + "}\n"); +} + +void RepeatedImmutableEnumFieldGenerator::GenerateSerializationCode( + io::Printer* printer) const { + if (descriptor_->is_packed()) { + printer->Print(variables_, + "if (get$capitalized_name$List().size() > 0) {\n" + " output.writeUInt32NoTag($tag$);\n" + " output.writeUInt32NoTag($name$MemoizedSerializedSize);\n" + "}\n" + "for (int i = 0; i < $name$_.size(); i++) {\n" + " output.writeEnumNoTag($name$_.get(i));\n" + "}\n"); + } else { + printer->Print(variables_, + "for (int i = 0; i < $name$_.size(); i++) {\n" + " output.writeEnum($number$, $name$_.get(i));\n" + "}\n"); + } +} + +void RepeatedImmutableEnumFieldGenerator::GenerateSerializedSizeCode( + io::Printer* printer) const { + printer->Print(variables_, + "{\n" + " int dataSize = 0;\n"); + printer->Indent(); + + printer->Print(variables_, + "for (int i = 0; i < $name$_.size(); i++) {\n" + " dataSize += com.google.protobuf.CodedOutputStream\n" + " .computeEnumSizeNoTag($name$_.get(i));\n" + "}\n"); + printer->Print("size += dataSize;\n"); + if (descriptor_->is_packed()) { + printer->Print(variables_, + "if (!get$capitalized_name$List().isEmpty()) {" + " size += $tag_size$;\n" + " size += com.google.protobuf.CodedOutputStream\n" + " .computeUInt32SizeNoTag(dataSize);\n" + "}"); + } else { + printer->Print(variables_, "size += $tag_size$ * $name$_.size();\n"); + } + + // cache the data size for packed fields. + if (descriptor_->is_packed()) { + printer->Print(variables_, "$name$MemoizedSerializedSize = dataSize;\n"); + } + + printer->Outdent(); + printer->Print("}\n"); +} + +void RepeatedImmutableEnumFieldGenerator::GenerateEqualsCode( + io::Printer* printer) const { + printer->Print(variables_, + "if (!$name$_.equals(other.$name$_)) return false;\n"); +} + +void RepeatedImmutableEnumFieldGenerator::GenerateHashCode( + io::Printer* printer) const { + printer->Print(variables_, + "if (get$capitalized_name$Count() > 0) {\n" + " hash = (37 * hash) + $constant_name$;\n" + " hash = (53 * hash) + $name$_.hashCode();\n" + "}\n"); +} + +void RepeatedImmutableEnumFieldGenerator::GenerateKotlinDslMembers( + io::Printer* printer) const { + printer->Print( + variables_, + "/**\n" + " * An uninstantiable, behaviorless type to represent the field in\n" + " * generics.\n" + " */\n" + "@kotlin.OptIn" + "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n" + "public class ${$$kt_capitalized_name$Proxy$}$ private constructor()" + " : com.google.protobuf.kotlin.DslProxy()\n"); + + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$kt_deprecation$ public val $kt_name$: " + "com.google.protobuf.kotlin.DslList" + "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>\n" + " @kotlin.jvm.JvmSynthetic\n" + " get() = com.google.protobuf.kotlin.DslList(\n" + " $kt_dsl_builder$.${$get$capitalized_name$List$}$()\n" + " )\n"); + + WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER, + /* builder */ false); + printer->Print(variables_, + "@kotlin.jvm.JvmSynthetic\n" + "@kotlin.jvm.JvmName(\"add$kt_capitalized_name$\")\n" + "public fun com.google.protobuf.kotlin.DslList" + "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." + "add(value: $kt_type$) {\n" + " $kt_dsl_builder$.${$add$capitalized_name$$}$(value)\n" + "}"); + + WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER, + /* builder */ false); + printer->Print(variables_, + "@kotlin.jvm.JvmSynthetic\n" + "@kotlin.jvm.JvmName(\"plusAssign$kt_capitalized_name$\")\n" + "@Suppress(\"NOTHING_TO_INLINE\")\n" + "public inline operator fun com.google.protobuf.kotlin.DslList" + "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." + "plusAssign(value: $kt_type$) {\n" + " add(value)\n" + "}"); + + WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER, + /* builder */ false); + printer->Print(variables_, + "@kotlin.jvm.JvmSynthetic\n" + "@kotlin.jvm.JvmName(\"addAll$kt_capitalized_name$\")\n" + "public fun com.google.protobuf.kotlin.DslList" + "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." + "addAll(values: kotlin.collections.Iterable<$kt_type$>) {\n" + " $kt_dsl_builder$.${$addAll$capitalized_name$$}$(values)\n" + "}"); + + WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER, + /* builder */ false); + printer->Print( + variables_, + "@kotlin.jvm.JvmSynthetic\n" + "@kotlin.jvm.JvmName(\"plusAssignAll$kt_capitalized_name$\")\n" + "@Suppress(\"NOTHING_TO_INLINE\")\n" + "public inline operator fun com.google.protobuf.kotlin.DslList" + "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." + "plusAssign(values: kotlin.collections.Iterable<$kt_type$>) {\n" + " addAll(values)\n" + "}"); + + WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_SETTER, + /* builder */ false); + printer->Print( + variables_, + "@kotlin.jvm.JvmSynthetic\n" + "@kotlin.jvm.JvmName(\"set$kt_capitalized_name$\")\n" + "public operator fun com.google.protobuf.kotlin.DslList" + "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." + "set(index: kotlin.Int, value: $kt_type$) {\n" + " $kt_dsl_builder$.${$set$capitalized_name$$}$(index, value)\n" + "}"); + + WriteFieldAccessorDocComment(printer, descriptor_, CLEARER, + /* builder */ false); + printer->Print(variables_, + "@kotlin.jvm.JvmSynthetic\n" + "@kotlin.jvm.JvmName(\"clear$kt_capitalized_name$\")\n" + "public fun com.google.protobuf.kotlin.DslList" + "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." + "clear() {\n" + " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n" + "}"); +} + +std::string RepeatedImmutableEnumFieldGenerator::GetBoxedType() const { + return name_resolver_->GetImmutableClassName(descriptor_->enum_type()); +} + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/java/java_enum_field.h b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_enum_field.h new file mode 100644 index 00000000..1e88bbf3 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_enum_field.h @@ -0,0 +1,161 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_FIELD_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_FIELD_H__ + +#include <map> +#include <string> +#include <compiler/java/java_field.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { +class Context; // context.h +class ClassNameResolver; // name_resolver.h +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +class ImmutableEnumFieldGenerator : public ImmutableFieldGenerator { + public: + explicit ImmutableEnumFieldGenerator(const FieldDescriptor* descriptor, + int messageBitIndex, int builderBitIndex, + Context* context); + ~ImmutableEnumFieldGenerator() override; + + // implements ImmutableFieldGenerator + // --------------------------------------- + int GetNumBitsForMessage() const override; + int GetNumBitsForBuilder() const override; + void GenerateInterfaceMembers(io::Printer* printer) const override; + void GenerateMembers(io::Printer* printer) const override; + void GenerateBuilderMembers(io::Printer* printer) const override; + void GenerateInitializationCode(io::Printer* printer) const override; + void GenerateBuilderClearCode(io::Printer* printer) const override; + void GenerateMergingCode(io::Printer* printer) const override; + void GenerateBuildingCode(io::Printer* printer) const override; + void GenerateParsingCode(io::Printer* printer) const override; + void GenerateParsingDoneCode(io::Printer* printer) const override; + void GenerateSerializationCode(io::Printer* printer) const override; + void GenerateSerializedSizeCode(io::Printer* printer) const override; + void GenerateFieldBuilderInitializationCode( + io::Printer* printer) const override; + void GenerateEqualsCode(io::Printer* printer) const override; + void GenerateHashCode(io::Printer* printer) const override; + void GenerateKotlinDslMembers(io::Printer* printer) const override; + + std::string GetBoxedType() const override; + + protected: + const FieldDescriptor* descriptor_; + std::map<std::string, std::string> variables_; + ClassNameResolver* name_resolver_; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableEnumFieldGenerator); +}; + +class ImmutableEnumOneofFieldGenerator : public ImmutableEnumFieldGenerator { + public: + ImmutableEnumOneofFieldGenerator(const FieldDescriptor* descriptor, + int messageBitIndex, int builderBitIndex, + Context* context); + ~ImmutableEnumOneofFieldGenerator(); + + void GenerateMembers(io::Printer* printer) const override; + void GenerateBuilderMembers(io::Printer* printer) const override; + void GenerateMergingCode(io::Printer* printer) const override; + void GenerateBuildingCode(io::Printer* printer) const override; + void GenerateParsingCode(io::Printer* printer) const override; + void GenerateSerializationCode(io::Printer* printer) const override; + void GenerateSerializedSizeCode(io::Printer* printer) const override; + void GenerateEqualsCode(io::Printer* printer) const override; + void GenerateHashCode(io::Printer* printer) const override; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableEnumOneofFieldGenerator); +}; + +class RepeatedImmutableEnumFieldGenerator : public ImmutableFieldGenerator { + public: + explicit RepeatedImmutableEnumFieldGenerator( + const FieldDescriptor* descriptor, int messageBitIndex, + int builderBitIndex, Context* context); + ~RepeatedImmutableEnumFieldGenerator() override; + + // implements ImmutableFieldGenerator --------------------------------------- + int GetNumBitsForMessage() const override; + int GetNumBitsForBuilder() const override; + void GenerateInterfaceMembers(io::Printer* printer) const override; + void GenerateMembers(io::Printer* printer) const override; + void GenerateBuilderMembers(io::Printer* printer) const override; + void GenerateInitializationCode(io::Printer* printer) const override; + void GenerateBuilderClearCode(io::Printer* printer) const override; + void GenerateMergingCode(io::Printer* printer) const override; + void GenerateBuildingCode(io::Printer* printer) const override; + void GenerateParsingCode(io::Printer* printer) const override; + void GenerateParsingCodeFromPacked(io::Printer* printer) const override; + void GenerateParsingDoneCode(io::Printer* printer) const override; + void GenerateSerializationCode(io::Printer* printer) const override; + void GenerateSerializedSizeCode(io::Printer* printer) const override; + void GenerateFieldBuilderInitializationCode( + io::Printer* printer) const override; + void GenerateEqualsCode(io::Printer* printer) const override; + void GenerateHashCode(io::Printer* printer) const override; + void GenerateKotlinDslMembers(io::Printer* printer) const override; + + std::string GetBoxedType() const override; + + private: + const FieldDescriptor* descriptor_; + std::map<std::string, std::string> variables_; + ClassNameResolver* name_resolver_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedImmutableEnumFieldGenerator); +}; + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_FIELD_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/java/java_enum_field_lite.cc b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_enum_field_lite.cc new file mode 100644 index 00000000..ffc28ef0 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_enum_field_lite.cc @@ -0,0 +1,918 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <compiler/java/java_enum_field_lite.h> + +#include <cstdint> +#include <map> +#include <string> + +#include <stubs/logging.h> +#include <stubs/common.h> +#include <compiler/java/java_context.h> +#include <compiler/java/java_doc_comment.h> +#include <compiler/java/java_helpers.h> +#include <compiler/java/java_name_resolver.h> +#include <io/printer.h> +#include <wire_format.h> +#include <stubs/strutil.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +namespace { +bool EnableExperimentalRuntimeForLite() { +#ifdef PROTOBUF_EXPERIMENT + return PROTOBUF_EXPERIMENT; +#else // PROTOBUF_EXPERIMENT + return false; +#endif // !PROTOBUF_EXPERIMENT +} + +void SetEnumVariables(const FieldDescriptor* descriptor, int messageBitIndex, + int builderBitIndex, const FieldGeneratorInfo* info, + ClassNameResolver* name_resolver, + std::map<std::string, std::string>* variables) { + SetCommonFieldVariables(descriptor, info, variables); + + (*variables)["type"] = + name_resolver->GetImmutableClassName(descriptor->enum_type()); + (*variables)["kt_type"] = (*variables)["type"]; + (*variables)["mutable_type"] = + name_resolver->GetMutableClassName(descriptor->enum_type()); + (*variables)["default"] = ImmutableDefaultValue(descriptor, name_resolver); + (*variables)["default_number"] = + StrCat(descriptor->default_value_enum()->number()); + (*variables)["tag"] = StrCat( + static_cast<int32_t>(internal::WireFormat::MakeTag(descriptor))); + (*variables)["tag_size"] = StrCat( + internal::WireFormat::TagSize(descriptor->number(), GetType(descriptor))); + // TODO(birdo): Add @deprecated javadoc when generating javadoc is supported + // by the proto compiler + (*variables)["deprecation"] = + descriptor->options().deprecated() ? "@java.lang.Deprecated " : ""; + (*variables)["kt_deprecation"] = + descriptor->options().deprecated() + ? "@kotlin.Deprecated(message = \"Field " + (*variables)["name"] + + " is deprecated\") " + : ""; + (*variables)["required"] = descriptor->is_required() ? "true" : "false"; + + if (HasHasbit(descriptor)) { + // For singular messages and builders, one bit is used for the hasField bit. + (*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex); + + // Note that these have a trailing ";". + (*variables)["set_has_field_bit_message"] = + GenerateSetBit(messageBitIndex) + ";"; + (*variables)["clear_has_field_bit_message"] = + GenerateClearBit(messageBitIndex) + ";"; + + (*variables)["is_field_present_message"] = GenerateGetBit(messageBitIndex); + } else { + (*variables)["set_has_field_bit_message"] = ""; + (*variables)["clear_has_field_bit_message"] = ""; + + (*variables)["is_field_present_message"] = + (*variables)["name"] + "_ != " + (*variables)["default"] + + ".getNumber()"; + } + + (*variables)["get_has_field_bit_from_local"] = + GenerateGetBitFromLocal(builderBitIndex); + (*variables)["set_has_field_bit_to_local"] = + GenerateSetBitToLocal(messageBitIndex); + + if (SupportUnknownEnumValue(descriptor->file())) { + (*variables)["unknown"] = (*variables)["type"] + ".UNRECOGNIZED"; + } else { + (*variables)["unknown"] = (*variables)["default"]; + } + + // We use `x.getClass()` as a null check because it generates less bytecode + // than an `if (x == null) { throw ... }` statement. + (*variables)["null_check"] = "value.getClass();\n"; +} + +} // namespace + +// =================================================================== + +ImmutableEnumFieldLiteGenerator::ImmutableEnumFieldLiteGenerator( + const FieldDescriptor* descriptor, int messageBitIndex, Context* context) + : descriptor_(descriptor), + messageBitIndex_(messageBitIndex), + context_(context), + name_resolver_(context->GetNameResolver()) { + SetEnumVariables(descriptor, messageBitIndex, 0, + context->GetFieldGeneratorInfo(descriptor), name_resolver_, + &variables_); +} + +ImmutableEnumFieldLiteGenerator::~ImmutableEnumFieldLiteGenerator() {} + +int ImmutableEnumFieldLiteGenerator::GetNumBitsForMessage() const { + return HasHasbit(descriptor_) ? 1 : 0; +} + +void ImmutableEnumFieldLiteGenerator::GenerateInterfaceMembers( + io::Printer* printer) const { + if (HasHazzer(descriptor_)) { + WriteFieldAccessorDocComment(printer, descriptor_, HAZZER); + printer->Print(variables_, + "$deprecation$boolean has$capitalized_name$();\n"); + } + if (SupportUnknownEnumValue(descriptor_->file())) { + WriteFieldEnumValueAccessorDocComment(printer, descriptor_, GETTER); + printer->Print(variables_, + "$deprecation$int get$capitalized_name$Value();\n"); + } + WriteFieldAccessorDocComment(printer, descriptor_, GETTER); + printer->Print(variables_, "$deprecation$$type$ get$capitalized_name$();\n"); +} + +void ImmutableEnumFieldLiteGenerator::GenerateMembers( + io::Printer* printer) const { + printer->Print(variables_, "private int $name$_;\n"); + PrintExtraFieldInfo(variables_, printer); + if (HasHazzer(descriptor_)) { + WriteFieldAccessorDocComment(printer, descriptor_, HAZZER); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n" + " return $get_has_field_bit_message$;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + } + if (SupportUnknownEnumValue(descriptor_->file())) { + WriteFieldEnumValueAccessorDocComment(printer, descriptor_, GETTER); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$public int ${$get$capitalized_name$Value$}$() {\n" + " return $name$_;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + } + WriteFieldAccessorDocComment(printer, descriptor_, GETTER); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$public $type$ ${$get$capitalized_name$$}$() {\n" + " $type$ result = $type$.forNumber($name$_);\n" + " return result == null ? $unknown$ : result;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + // Generate private setters for the builder to proxy into. + if (SupportUnknownEnumValue(descriptor_->file())) { + WriteFieldEnumValueAccessorDocComment(printer, descriptor_, SETTER); + printer->Print(variables_, + "private void set$capitalized_name$Value(int value) {\n" + " $set_has_field_bit_message$" + " $name$_ = value;\n" + "}\n"); + } + WriteFieldAccessorDocComment(printer, descriptor_, SETTER); + printer->Print(variables_, + "private void set$capitalized_name$($type$ value) {\n" + " $name$_ = value.getNumber();\n" + " $set_has_field_bit_message$\n" + "}\n"); + WriteFieldAccessorDocComment(printer, descriptor_, CLEARER); + printer->Print(variables_, + "private void clear$capitalized_name$() {\n" + " $clear_has_field_bit_message$\n" + " $name$_ = $default_number$;\n" + "}\n"); +} + +void ImmutableEnumFieldLiteGenerator::GenerateBuilderMembers( + io::Printer* printer) const { + if (HasHazzer(descriptor_)) { + WriteFieldAccessorDocComment(printer, descriptor_, HAZZER); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n" + " return instance.has$capitalized_name$();\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + } + if (SupportUnknownEnumValue(descriptor_->file())) { + WriteFieldEnumValueAccessorDocComment(printer, descriptor_, GETTER); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$public int ${$get$capitalized_name$Value$}$() {\n" + " return instance.get$capitalized_name$Value();\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldAccessorDocComment(printer, descriptor_, SETTER, + /* builder */ true); + printer->Print(variables_, + "$deprecation$public Builder " + "${$set$capitalized_name$Value$}$(int value) {\n" + " copyOnWrite();\n" + " instance.set$capitalized_name$Value(value);\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + } + WriteFieldAccessorDocComment(printer, descriptor_, GETTER); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$public $type$ ${$get$capitalized_name$$}$() {\n" + " return instance.get$capitalized_name$();\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldEnumValueAccessorDocComment(printer, descriptor_, SETTER, + /* builder */ true); + printer->Print(variables_, + "$deprecation$public Builder " + "${$set$capitalized_name$$}$($type$ value) {\n" + " copyOnWrite();\n" + " instance.set$capitalized_name$(value);\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldAccessorDocComment(printer, descriptor_, CLEARER, + /* builder */ true); + printer->Print( + variables_, + "$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n" + " copyOnWrite();\n" + " instance.clear$capitalized_name$();\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); +} + +void ImmutableEnumFieldLiteGenerator::GenerateKotlinDslMembers( + io::Printer* printer) const { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$kt_deprecation$public var $kt_name$: $kt_type$\n" + " @JvmName(\"${$get$kt_capitalized_name$$}$\")\n" + " get() = $kt_dsl_builder$.${$get$capitalized_name$$}$()\n" + " @JvmName(\"${$set$kt_capitalized_name$$}$\")\n" + " set(value) {\n" + " $kt_dsl_builder$.${$set$capitalized_name$$}$(value)\n" + " }\n"); + + WriteFieldAccessorDocComment(printer, descriptor_, CLEARER, + /* builder */ false); + printer->Print(variables_, + "public fun ${$clear$kt_capitalized_name$$}$() {\n" + " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n" + "}\n"); + + if (HasHazzer(descriptor_)) { + WriteFieldAccessorDocComment(printer, descriptor_, HAZZER); + printer->Print( + variables_, + "public fun ${$has$kt_capitalized_name$$}$(): kotlin.Boolean {\n" + " return $kt_dsl_builder$.${$has$capitalized_name$$}$()\n" + "}\n"); + } +} + +void ImmutableEnumFieldLiteGenerator::GenerateInitializationCode( + io::Printer* printer) const { + if (!IsDefaultValueJavaDefault(descriptor_)) { + printer->Print(variables_, "$name$_ = $default_number$;\n"); + } +} + +void ImmutableEnumFieldLiteGenerator::GenerateFieldInfo( + io::Printer* printer, std::vector<uint16_t>* output) const { + WriteIntToUtf16CharSequence(descriptor_->number(), output); + WriteIntToUtf16CharSequence(GetExperimentalJavaFieldType(descriptor_), + output); + if (HasHasbit(descriptor_)) { + WriteIntToUtf16CharSequence(messageBitIndex_, output); + } + printer->Print(variables_, "\"$name$_\",\n"); + if (!SupportUnknownEnumValue((descriptor_))) { + PrintEnumVerifierLogic(printer, descriptor_, variables_, + /*var_name=*/"$type$", + /*terminating_string=*/",\n", + /*enforce_lite=*/context_->EnforceLite()); + } +} + +std::string ImmutableEnumFieldLiteGenerator::GetBoxedType() const { + return name_resolver_->GetImmutableClassName(descriptor_->enum_type()); +} + +// =================================================================== + +ImmutableEnumOneofFieldLiteGenerator::ImmutableEnumOneofFieldLiteGenerator( + const FieldDescriptor* descriptor, int messageBitIndex, Context* context) + : ImmutableEnumFieldLiteGenerator(descriptor, messageBitIndex, context) { + const OneofGeneratorInfo* info = + context->GetOneofGeneratorInfo(descriptor->containing_oneof()); + SetCommonOneofVariables(descriptor, info, &variables_); +} + +ImmutableEnumOneofFieldLiteGenerator::~ImmutableEnumOneofFieldLiteGenerator() {} + +void ImmutableEnumOneofFieldLiteGenerator::GenerateMembers( + io::Printer* printer) const { + PrintExtraFieldInfo(variables_, printer); + GOOGLE_DCHECK(HasHazzer(descriptor_)); + WriteFieldAccessorDocComment(printer, descriptor_, HAZZER); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n" + " return $has_oneof_case_message$;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + if (SupportUnknownEnumValue(descriptor_->file())) { + WriteFieldEnumValueAccessorDocComment(printer, descriptor_, GETTER); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$public int ${$get$capitalized_name$Value$}$() {\n" + " if ($has_oneof_case_message$) {\n" + " return (java.lang.Integer) $oneof_name$_;\n" + " }\n" + " return $default_number$;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + } + WriteFieldAccessorDocComment(printer, descriptor_, GETTER); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$public $type$ ${$get$capitalized_name$$}$() {\n" + " if ($has_oneof_case_message$) {\n" + " $type$ result = $type$.forNumber((java.lang.Integer) " + "$oneof_name$_);\n" + " return result == null ? $unknown$ : result;\n" + " }\n" + " return $default$;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + // Generate private setters for the builder to proxy into. + if (SupportUnknownEnumValue(descriptor_->file())) { + WriteFieldEnumValueAccessorDocComment(printer, descriptor_, SETTER); + printer->Print(variables_, + "private void set$capitalized_name$Value(int value) {\n" + " $set_oneof_case_message$;\n" + " $oneof_name$_ = value;\n" + "}\n"); + } + WriteFieldAccessorDocComment(printer, descriptor_, SETTER); + printer->Print(variables_, + "private void set$capitalized_name$($type$ value) {\n" + " $oneof_name$_ = value.getNumber();\n" + " $set_oneof_case_message$;\n" + "}\n"); + WriteFieldAccessorDocComment(printer, descriptor_, CLEARER); + printer->Print(variables_, + "private void clear$capitalized_name$() {\n" + " if ($has_oneof_case_message$) {\n" + " $clear_oneof_case_message$;\n" + " $oneof_name$_ = null;\n" + " }\n" + "}\n"); +} + +void ImmutableEnumOneofFieldLiteGenerator::GenerateFieldInfo( + io::Printer* printer, std::vector<uint16_t>* output) const { + WriteIntToUtf16CharSequence(descriptor_->number(), output); + WriteIntToUtf16CharSequence(GetExperimentalJavaFieldType(descriptor_), + output); + WriteIntToUtf16CharSequence(descriptor_->containing_oneof()->index(), output); + if (!SupportUnknownEnumValue(descriptor_)) { + PrintEnumVerifierLogic(printer, descriptor_, variables_, + /*var_name=*/"$type$", + /*terminating_string=*/",\n", + /*enforce_lite=*/context_->EnforceLite()); + } +} + +void ImmutableEnumOneofFieldLiteGenerator::GenerateBuilderMembers( + io::Printer* printer) const { + GOOGLE_DCHECK(HasHazzer(descriptor_)); + WriteFieldAccessorDocComment(printer, descriptor_, HAZZER); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n" + " return instance.has$capitalized_name$();\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + if (SupportUnknownEnumValue(descriptor_->file())) { + WriteFieldEnumValueAccessorDocComment(printer, descriptor_, GETTER); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$public int ${$get$capitalized_name$Value$}$() {\n" + " return instance.get$capitalized_name$Value();\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldEnumValueAccessorDocComment(printer, descriptor_, SETTER, + /* builder */ true); + printer->Print(variables_, + "$deprecation$public Builder " + "${$set$capitalized_name$Value$}$(int value) {\n" + " copyOnWrite();\n" + " instance.set$capitalized_name$Value(value);\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + } + WriteFieldAccessorDocComment(printer, descriptor_, GETTER); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$public $type$ ${$get$capitalized_name$$}$() {\n" + " return instance.get$capitalized_name$();\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldAccessorDocComment(printer, descriptor_, SETTER, + /* builder */ true); + printer->Print(variables_, + "$deprecation$public Builder " + "${$set$capitalized_name$$}$($type$ value) {\n" + " copyOnWrite();\n" + " instance.set$capitalized_name$(value);\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldAccessorDocComment(printer, descriptor_, CLEARER, + /* builder */ true); + printer->Print( + variables_, + "$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n" + " copyOnWrite();\n" + " instance.clear$capitalized_name$();\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); +} + +// =================================================================== + +RepeatedImmutableEnumFieldLiteGenerator:: + RepeatedImmutableEnumFieldLiteGenerator(const FieldDescriptor* descriptor, + int messageBitIndex, + Context* context) + : descriptor_(descriptor), + context_(context), + name_resolver_(context->GetNameResolver()) { + SetEnumVariables(descriptor, messageBitIndex, 0, + context->GetFieldGeneratorInfo(descriptor), name_resolver_, + &variables_); +} + +RepeatedImmutableEnumFieldLiteGenerator:: + ~RepeatedImmutableEnumFieldLiteGenerator() {} + +int RepeatedImmutableEnumFieldLiteGenerator::GetNumBitsForMessage() const { + return 0; +} + +void RepeatedImmutableEnumFieldLiteGenerator::GenerateInterfaceMembers( + io::Printer* printer) const { + WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER); + printer->Print( + variables_, + "$deprecation$java.util.List<$type$> get$capitalized_name$List();\n"); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_COUNT); + printer->Print(variables_, + "$deprecation$int get$capitalized_name$Count();\n"); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_GETTER); + printer->Print(variables_, + "$deprecation$$type$ get$capitalized_name$(int index);\n"); + if (SupportUnknownEnumValue(descriptor_->file())) { + WriteFieldEnumValueAccessorDocComment(printer, descriptor_, LIST_GETTER); + printer->Print(variables_, + "$deprecation$java.util.List<java.lang.Integer>\n" + "get$capitalized_name$ValueList();\n"); + WriteFieldEnumValueAccessorDocComment(printer, descriptor_, + LIST_INDEXED_GETTER); + printer->Print(variables_, + "$deprecation$int get$capitalized_name$Value(int index);\n"); + } +} + +void RepeatedImmutableEnumFieldLiteGenerator::GenerateMembers( + io::Printer* printer) const { + printer->Print( + variables_, + "private com.google.protobuf.Internal.IntList $name$_;\n" + "private static final " + "com.google.protobuf.Internal.ListAdapter.Converter<\n" + " java.lang.Integer, $type$> $name$_converter_ =\n" + " new com.google.protobuf.Internal.ListAdapter.Converter<\n" + " java.lang.Integer, $type$>() {\n" + " @java.lang.Override\n" + " public $type$ convert(java.lang.Integer from) {\n" + " $type$ result = $type$.forNumber(from);\n" + " return result == null ? $unknown$ : result;\n" + " }\n" + " };\n"); + PrintExtraFieldInfo(variables_, printer); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$public java.util.List<$type$> " + "${$get$capitalized_name$List$}$() {\n" + " return new com.google.protobuf.Internal.ListAdapter<\n" + " java.lang.Integer, $type$>($name$_, $name$_converter_);\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_COUNT); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$public int ${$get$capitalized_name$Count$}$() {\n" + " return $name$_.size();\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_GETTER); + printer->Print( + variables_, + // NB: Do not use the "$name$_converter_" field; the usage of generics + // (and requisite upcasts to Object) prevent optimizations. Even + // without any optimizations, the below code is cheaper because it + // avoids boxing an int and a checkcast from the generics. + "@java.lang.Override\n" + "$deprecation$public $type$ ${$get$capitalized_name$$}$(int index) {\n" + " $type$ result = $type$.forNumber($name$_.getInt(index));\n" + " return result == null ? $unknown$ : result;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + if (SupportUnknownEnumValue(descriptor_->file())) { + WriteFieldEnumValueAccessorDocComment(printer, descriptor_, LIST_GETTER); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$public java.util.List<java.lang.Integer>\n" + "${$get$capitalized_name$ValueList$}$() {\n" + " return $name$_;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldEnumValueAccessorDocComment(printer, descriptor_, + LIST_INDEXED_GETTER); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$public int " + "${$get$capitalized_name$Value$}$(int index) {\n" + " return $name$_.getInt(index);\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + } + + if (!EnableExperimentalRuntimeForLite() && descriptor_->is_packed() && + context_->HasGeneratedMethods(descriptor_->containing_type())) { + printer->Print(variables_, "private int $name$MemoizedSerializedSize;\n"); + } + + // Generate private setters for the builder to proxy into. + printer->Print( + variables_, + "private void ensure$capitalized_name$IsMutable() {\n" + // Use a temporary to avoid a redundant iget-object. + " com.google.protobuf.Internal.IntList tmp = $name$_;\n" + " if (!tmp.isModifiable()) {\n" + " $name$_ =\n" + " com.google.protobuf.GeneratedMessageLite.mutableCopy(tmp);\n" + " }\n" + "}\n"); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_SETTER); + printer->Print(variables_, + "private void set$capitalized_name$(\n" + " int index, $type$ value) {\n" + " $null_check$" + " ensure$capitalized_name$IsMutable();\n" + " $name$_.setInt(index, value.getNumber());\n" + "}\n"); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER); + printer->Print(variables_, + "private void add$capitalized_name$($type$ value) {\n" + " $null_check$" + " ensure$capitalized_name$IsMutable();\n" + " $name$_.addInt(value.getNumber());\n" + "}\n"); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER); + printer->Print(variables_, + "private void addAll$capitalized_name$(\n" + " java.lang.Iterable<? extends $type$> values) {\n" + " ensure$capitalized_name$IsMutable();\n" + " for ($type$ value : values) {\n" + " $name$_.addInt(value.getNumber());\n" + " }\n" + "}\n"); + WriteFieldAccessorDocComment(printer, descriptor_, CLEARER); + printer->Print(variables_, + "private void clear$capitalized_name$() {\n" + " $name$_ = emptyIntList();\n" + "}\n"); + + if (SupportUnknownEnumValue(descriptor_->file())) { + WriteFieldEnumValueAccessorDocComment(printer, descriptor_, SETTER); + printer->Print(variables_, + "private void set$capitalized_name$Value(\n" + " int index, int value) {\n" + " ensure$capitalized_name$IsMutable();\n" + " $name$_.setInt(index, value);\n" + "}\n"); + WriteFieldEnumValueAccessorDocComment(printer, descriptor_, LIST_ADDER); + printer->Print(variables_, + "private void add$capitalized_name$Value(int value) {\n" + " ensure$capitalized_name$IsMutable();\n" + " $name$_.addInt(value);\n" + "}\n"); + WriteFieldEnumValueAccessorDocComment(printer, descriptor_, + LIST_MULTI_ADDER); + printer->Print(variables_, + "private void addAll$capitalized_name$Value(\n" + " java.lang.Iterable<java.lang.Integer> values) {\n" + " ensure$capitalized_name$IsMutable();\n" + " for (int value : values) {\n" + " $name$_.addInt(value);\n" + " }\n" + "}\n"); + } +} + +void RepeatedImmutableEnumFieldLiteGenerator::GenerateFieldInfo( + io::Printer* printer, std::vector<uint16_t>* output) const { + WriteIntToUtf16CharSequence(descriptor_->number(), output); + WriteIntToUtf16CharSequence(GetExperimentalJavaFieldType(descriptor_), + output); + printer->Print(variables_, "\"$name$_\",\n"); + if (!SupportUnknownEnumValue(descriptor_->file())) { + PrintEnumVerifierLogic(printer, descriptor_, variables_, + /*var_name=*/"$type$", + /*terminating_string=*/",\n", + /*enforce_lite=*/context_->EnforceLite()); + } +} + +void RepeatedImmutableEnumFieldLiteGenerator::GenerateBuilderMembers( + io::Printer* printer) const { + WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$public java.util.List<$type$> " + "${$get$capitalized_name$List$}$() {\n" + " return instance.get$capitalized_name$List();\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_COUNT); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$public int ${$get$capitalized_name$Count$}$() {\n" + " return instance.get$capitalized_name$Count();\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_GETTER); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$public $type$ ${$get$capitalized_name$$}$(int index) {\n" + " return instance.get$capitalized_name$(index);\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_SETTER, + /* builder */ true); + printer->Print(variables_, + "$deprecation$public Builder ${$set$capitalized_name$$}$(\n" + " int index, $type$ value) {\n" + " copyOnWrite();\n" + " instance.set$capitalized_name$(index, value);\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER, + /* builder */ true); + printer->Print(variables_, + "$deprecation$public Builder " + "${$add$capitalized_name$$}$($type$ value) {\n" + " copyOnWrite();\n" + " instance.add$capitalized_name$(value);\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER, + /* builder */ true); + printer->Print(variables_, + "$deprecation$public Builder ${$addAll$capitalized_name$$}$(\n" + " java.lang.Iterable<? extends $type$> values) {\n" + " copyOnWrite();\n" + " instance.addAll$capitalized_name$(values);" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldAccessorDocComment(printer, descriptor_, CLEARER, + /* builder */ true); + printer->Print( + variables_, + "$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n" + " copyOnWrite();\n" + " instance.clear$capitalized_name$();\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + if (SupportUnknownEnumValue(descriptor_->file())) { + WriteFieldEnumValueAccessorDocComment(printer, descriptor_, LIST_GETTER); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$public java.util.List<java.lang.Integer>\n" + "${$get$capitalized_name$ValueList$}$() {\n" + " return java.util.Collections.unmodifiableList(\n" + " instance.get$capitalized_name$ValueList());\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldEnumValueAccessorDocComment(printer, descriptor_, + LIST_INDEXED_GETTER); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$public int " + "${$get$capitalized_name$Value$}$(int index) {\n" + " return instance.get$capitalized_name$Value(index);\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldEnumValueAccessorDocComment(printer, descriptor_, + LIST_INDEXED_SETTER, + /* builder */ true); + printer->Print( + variables_, + "$deprecation$public Builder ${$set$capitalized_name$Value$}$(\n" + " int index, int value) {\n" + " copyOnWrite();\n" + " instance.set$capitalized_name$Value(index, value);\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldEnumValueAccessorDocComment(printer, descriptor_, LIST_ADDER, + /* builder */ true); + printer->Print(variables_, + "$deprecation$public Builder " + "${$add$capitalized_name$Value$}$(int value) {\n" + " instance.add$capitalized_name$Value(value);\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldEnumValueAccessorDocComment(printer, descriptor_, + LIST_MULTI_ADDER, + /* builder */ true); + printer->Print( + variables_, + "$deprecation$public Builder ${$addAll$capitalized_name$Value$}$(\n" + " java.lang.Iterable<java.lang.Integer> values) {\n" + " copyOnWrite();\n" + " instance.addAll$capitalized_name$Value(values);\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + } +} + +void RepeatedImmutableEnumFieldLiteGenerator::GenerateInitializationCode( + io::Printer* printer) const { + printer->Print(variables_, "$name$_ = emptyIntList();\n"); +} + +void RepeatedImmutableEnumFieldLiteGenerator::GenerateKotlinDslMembers( + io::Printer* printer) const { + printer->Print( + variables_, + "/**\n" + " * An uninstantiable, behaviorless type to represent the field in\n" + " * generics.\n" + " */\n" + "@kotlin.OptIn" + "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n" + "public class ${$$kt_capitalized_name$Proxy$}$ private constructor()" + " : com.google.protobuf.kotlin.DslProxy()\n"); + + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$kt_deprecation$ public val $kt_name$: " + "com.google.protobuf.kotlin.DslList" + "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>\n" + " @kotlin.jvm.JvmSynthetic\n" + " get() = com.google.protobuf.kotlin.DslList(\n" + " $kt_dsl_builder$.${$get$capitalized_name$List$}$()\n" + " )\n"); + + WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER, + /* builder */ false); + printer->Print(variables_, + "@kotlin.jvm.JvmSynthetic\n" + "@kotlin.jvm.JvmName(\"add$kt_capitalized_name$\")\n" + "public fun com.google.protobuf.kotlin.DslList" + "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." + "add(value: $kt_type$) {\n" + " $kt_dsl_builder$.${$add$capitalized_name$$}$(value)\n" + "}"); + + WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER, + /* builder */ false); + printer->Print(variables_, + "@kotlin.jvm.JvmSynthetic\n" + "@kotlin.jvm.JvmName(\"plusAssign$kt_capitalized_name$\")\n" + "@Suppress(\"NOTHING_TO_INLINE\")\n" + "public inline operator fun com.google.protobuf.kotlin.DslList" + "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." + "plusAssign(value: $kt_type$) {\n" + " add(value)\n" + "}"); + + WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER, + /* builder */ false); + printer->Print(variables_, + "@kotlin.jvm.JvmSynthetic\n" + "@kotlin.jvm.JvmName(\"addAll$kt_capitalized_name$\")\n" + "public fun com.google.protobuf.kotlin.DslList" + "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." + "addAll(values: kotlin.collections.Iterable<$kt_type$>) {\n" + " $kt_dsl_builder$.${$addAll$capitalized_name$$}$(values)\n" + "}"); + + WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER, + /* builder */ false); + printer->Print( + variables_, + "@kotlin.jvm.JvmSynthetic\n" + "@kotlin.jvm.JvmName(\"plusAssignAll$kt_capitalized_name$\")\n" + "@Suppress(\"NOTHING_TO_INLINE\")\n" + "public inline operator fun com.google.protobuf.kotlin.DslList" + "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." + "plusAssign(values: kotlin.collections.Iterable<$kt_type$>) {\n" + " addAll(values)\n" + "}"); + + WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_SETTER, + /* builder */ false); + printer->Print( + variables_, + "@kotlin.jvm.JvmSynthetic\n" + "@kotlin.jvm.JvmName(\"set$kt_capitalized_name$\")\n" + "public operator fun com.google.protobuf.kotlin.DslList" + "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." + "set(index: kotlin.Int, value: $kt_type$) {\n" + " $kt_dsl_builder$.${$set$capitalized_name$$}$(index, value)\n" + "}"); + + WriteFieldAccessorDocComment(printer, descriptor_, CLEARER, + /* builder */ false); + printer->Print(variables_, + "@kotlin.jvm.JvmSynthetic\n" + "@kotlin.jvm.JvmName(\"clear$kt_capitalized_name$\")\n" + "public fun com.google.protobuf.kotlin.DslList" + "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." + "clear() {\n" + " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n" + "}"); +} + +std::string RepeatedImmutableEnumFieldLiteGenerator::GetBoxedType() const { + return name_resolver_->GetImmutableClassName(descriptor_->enum_type()); +} + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/java/java_enum_field_lite.h b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_enum_field_lite.h new file mode 100644 index 00000000..8073f393 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_enum_field_lite.h @@ -0,0 +1,140 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_FIELD_LITE_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_FIELD_LITE_H__ + +#include <cstdint> +#include <map> +#include <string> + +#include <compiler/java/java_field.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { +class Context; // context.h +class ClassNameResolver; // name_resolver.h +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +class ImmutableEnumFieldLiteGenerator : public ImmutableFieldLiteGenerator { + public: + explicit ImmutableEnumFieldLiteGenerator(const FieldDescriptor* descriptor, + int messageBitIndex, + Context* context); + ~ImmutableEnumFieldLiteGenerator() override; + + // implements ImmutableFieldLiteGenerator + // ------------------------------------ + int GetNumBitsForMessage() const override; + void GenerateInterfaceMembers(io::Printer* printer) const override; + void GenerateMembers(io::Printer* printer) const override; + void GenerateBuilderMembers(io::Printer* printer) const override; + void GenerateInitializationCode(io::Printer* printer) const override; + void GenerateFieldInfo(io::Printer* printer, + std::vector<uint16_t>* output) const override; + void GenerateKotlinDslMembers(io::Printer* printer) const override; + + std::string GetBoxedType() const override; + + protected: + const FieldDescriptor* descriptor_; + std::map<std::string, std::string> variables_; + const int messageBitIndex_; + Context* context_; + ClassNameResolver* name_resolver_; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableEnumFieldLiteGenerator); +}; + +class ImmutableEnumOneofFieldLiteGenerator + : public ImmutableEnumFieldLiteGenerator { + public: + ImmutableEnumOneofFieldLiteGenerator(const FieldDescriptor* descriptor, + int messageBitIndex, Context* context); + ~ImmutableEnumOneofFieldLiteGenerator() override; + + void GenerateMembers(io::Printer* printer) const override; + void GenerateBuilderMembers(io::Printer* printer) const override; + void GenerateFieldInfo(io::Printer* printer, + std::vector<uint16_t>* output) const override; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableEnumOneofFieldLiteGenerator); +}; + +class RepeatedImmutableEnumFieldLiteGenerator + : public ImmutableFieldLiteGenerator { + public: + explicit RepeatedImmutableEnumFieldLiteGenerator( + const FieldDescriptor* descriptor, int messageBitIndex, Context* context); + ~RepeatedImmutableEnumFieldLiteGenerator() override; + + // implements ImmutableFieldLiteGenerator ------------------------------------ + int GetNumBitsForMessage() const override; + void GenerateInterfaceMembers(io::Printer* printer) const override; + void GenerateMembers(io::Printer* printer) const override; + void GenerateBuilderMembers(io::Printer* printer) const override; + void GenerateInitializationCode(io::Printer* printer) const override; + void GenerateFieldInfo(io::Printer* printer, + std::vector<uint16_t>* output) const override; + void GenerateKotlinDslMembers(io::Printer* printer) const override; + + std::string GetBoxedType() const override; + + private: + const FieldDescriptor* descriptor_; + std::map<std::string, std::string> variables_; + Context* context_; + ClassNameResolver* name_resolver_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedImmutableEnumFieldLiteGenerator); +}; + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_FIELD_LITE_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/java/java_enum_lite.cc b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_enum_lite.cc new file mode 100644 index 00000000..7cfad624 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_enum_lite.cc @@ -0,0 +1,235 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <map> +#include <string> + +#include <compiler/java/java_context.h> +#include <compiler/java/java_doc_comment.h> +#include <compiler/java/java_enum_lite.h> +#include <compiler/java/java_helpers.h> +#include <compiler/java/java_name_resolver.h> +#include <descriptor.pb.h> +#include <io/printer.h> +#include <stubs/strutil.h> +#include <stubs/map_util.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +EnumLiteGenerator::EnumLiteGenerator(const EnumDescriptor* descriptor, + bool immutable_api, Context* context) + : descriptor_(descriptor), + immutable_api_(immutable_api), + context_(context), + name_resolver_(context->GetNameResolver()) { + for (int i = 0; i < descriptor_->value_count(); i++) { + const EnumValueDescriptor* value = descriptor_->value(i); + const EnumValueDescriptor* canonical_value = + descriptor_->FindValueByNumber(value->number()); + + if (value == canonical_value) { + canonical_values_.push_back(value); + } else { + Alias alias; + alias.value = value; + alias.canonical_value = canonical_value; + aliases_.push_back(alias); + } + } +} + +EnumLiteGenerator::~EnumLiteGenerator() {} + +void EnumLiteGenerator::Generate(io::Printer* printer) { + WriteEnumDocComment(printer, descriptor_); + MaybePrintGeneratedAnnotation(context_, printer, descriptor_, immutable_api_); + printer->Print( + "$deprecation$public enum $classname$\n" + " implements com.google.protobuf.Internal.EnumLite {\n", + "classname", descriptor_->name(), "deprecation", + descriptor_->options().deprecated() ? "@java.lang.Deprecated " : ""); + printer->Annotate("classname", descriptor_); + printer->Indent(); + + for (int i = 0; i < canonical_values_.size(); i++) { + std::map<std::string, std::string> vars; + vars["name"] = canonical_values_[i]->name(); + vars["number"] = StrCat(canonical_values_[i]->number()); + WriteEnumValueDocComment(printer, canonical_values_[i]); + if (canonical_values_[i]->options().deprecated()) { + printer->Print("@java.lang.Deprecated\n"); + } + printer->Print(vars, "$name$($number$),\n"); + printer->Annotate("name", canonical_values_[i]); + } + + if (SupportUnknownEnumValue(descriptor_->file())) { + printer->Print("${$UNRECOGNIZED$}$(-1),\n", "{", "", "}", ""); + printer->Annotate("{", "}", descriptor_); + } + + printer->Print( + ";\n" + "\n"); + + // ----------------------------------------------------------------- + + for (int i = 0; i < aliases_.size(); i++) { + std::map<std::string, std::string> vars; + vars["classname"] = descriptor_->name(); + vars["name"] = aliases_[i].value->name(); + vars["canonical_name"] = aliases_[i].canonical_value->name(); + WriteEnumValueDocComment(printer, aliases_[i].value); + printer->Print( + vars, "public static final $classname$ $name$ = $canonical_name$;\n"); + printer->Annotate("name", aliases_[i].value); + } + + for (int i = 0; i < descriptor_->value_count(); i++) { + std::map<std::string, std::string> vars; + vars["name"] = descriptor_->value(i)->name(); + vars["number"] = StrCat(descriptor_->value(i)->number()); + vars["{"] = ""; + vars["}"] = ""; + vars["deprecation"] = descriptor_->value(i)->options().deprecated() + ? "@java.lang.Deprecated " + : ""; + WriteEnumValueDocComment(printer, descriptor_->value(i)); + printer->Print(vars, + "$deprecation$public static final int ${$$name$_VALUE$}$ = " + "$number$;\n"); + printer->Annotate("{", "}", descriptor_->value(i)); + } + printer->Print("\n"); + + // ----------------------------------------------------------------- + + printer->Print( + "\n" + "@java.lang.Override\n" + "public final int getNumber() {\n"); + if (SupportUnknownEnumValue(descriptor_->file())) { + printer->Print( + " if (this == UNRECOGNIZED) {\n" + " throw new java.lang.IllegalArgumentException(\n" + " \"Can't get the number of an unknown enum value.\");\n" + " }\n"); + } + printer->Print( + " return value;\n" + "}\n" + "\n" + "/**\n" + " * @param value The number of the enum to look for.\n" + " * @return The enum associated with the given number.\n" + " * @deprecated Use {@link #forNumber(int)} instead.\n" + " */\n" + "@java.lang.Deprecated\n" + "public static $classname$ valueOf(int value) {\n" + " return forNumber(value);\n" + "}\n" + "\n" + "public static $classname$ forNumber(int value) {\n" + " switch (value) {\n", + "classname", descriptor_->name()); + printer->Indent(); + printer->Indent(); + + for (int i = 0; i < canonical_values_.size(); i++) { + printer->Print("case $number$: return $name$;\n", "name", + canonical_values_[i]->name(), "number", + StrCat(canonical_values_[i]->number())); + } + + printer->Outdent(); + printer->Outdent(); + printer->Print( + " default: return null;\n" + " }\n" + "}\n" + "\n" + "public static com.google.protobuf.Internal.EnumLiteMap<$classname$>\n" + " internalGetValueMap() {\n" + " return internalValueMap;\n" + "}\n" + "private static final com.google.protobuf.Internal.EnumLiteMap<\n" + " $classname$> internalValueMap =\n" + " new com.google.protobuf.Internal.EnumLiteMap<$classname$>() {\n" + " @java.lang.Override\n" + " public $classname$ findValueByNumber(int number) {\n" + " return $classname$.forNumber(number);\n" + " }\n" + " };\n" + "\n" + "public static com.google.protobuf.Internal.EnumVerifier \n" + " internalGetVerifier() {\n" + " return $classname$Verifier.INSTANCE;\n" + "}\n" + "\n" + "private static final class $classname$Verifier implements \n" + " com.google.protobuf.Internal.EnumVerifier { \n" + " static final com.google.protobuf.Internal.EnumVerifier " + " INSTANCE = new $classname$Verifier();\n" + " @java.lang.Override\n" + " public boolean isInRange(int number) {\n" + " return $classname$.forNumber(number) != null;\n" + " }\n" + " };\n" + "\n", + "classname", descriptor_->name()); + + printer->Print( + "private final int value;\n\n" + "private $classname$(int value) {\n", + "classname", descriptor_->name()); + printer->Print( + " this.value = value;\n" + "}\n"); + + printer->Print( + "\n" + "// @@protoc_insertion_point(enum_scope:$full_name$)\n", + "full_name", descriptor_->full_name()); + + printer->Outdent(); + printer->Print("}\n\n"); +} + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/java/java_enum_lite.h b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_enum_lite.h new file mode 100644 index 00000000..0b706d8e --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_enum_lite.h @@ -0,0 +1,98 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_LITE_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_LITE_H__ + +#include <string> +#include <vector> +#include <descriptor.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { +class Context; // context.h +class ClassNameResolver; // name_resolver.h +} // namespace java +} // namespace compiler +namespace io { +class Printer; // printer.h +} +} // namespace protobuf +} // namespace google + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +class EnumLiteGenerator { + public: + EnumLiteGenerator(const EnumDescriptor* descriptor, bool immutable_api, + Context* context); + ~EnumLiteGenerator(); + + void Generate(io::Printer* printer); + + private: + const EnumDescriptor* descriptor_; + + // The proto language allows multiple enum constants to have the same + // numeric value. Java, however, does not allow multiple enum constants to + // be considered equivalent. We treat the first defined constant for any + // given numeric value as "canonical" and the rest as aliases of that + // canonical value. + std::vector<const EnumValueDescriptor*> canonical_values_; + + struct Alias { + const EnumValueDescriptor* value; + const EnumValueDescriptor* canonical_value; + }; + std::vector<Alias> aliases_; + + bool immutable_api_; + + Context* context_; + ClassNameResolver* name_resolver_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumLiteGenerator); +}; + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_LITE_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/java/java_extension.cc b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_extension.cc new file mode 100644 index 00000000..d45fd9c1 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_extension.cc @@ -0,0 +1,172 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <compiler/java/java_extension.h> + +#include <compiler/java/java_context.h> +#include <compiler/java/java_doc_comment.h> +#include <compiler/java/java_helpers.h> +#include <compiler/java/java_name_resolver.h> +#include <io/printer.h> +#include <stubs/strutil.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +ImmutableExtensionGenerator::ImmutableExtensionGenerator( + const FieldDescriptor* descriptor, Context* context) + : descriptor_(descriptor), name_resolver_(context->GetNameResolver()) { + if (descriptor_->extension_scope() != NULL) { + scope_ = + name_resolver_->GetImmutableClassName(descriptor_->extension_scope()); + } else { + scope_ = name_resolver_->GetImmutableClassName(descriptor_->file()); + } +} + +ImmutableExtensionGenerator::~ImmutableExtensionGenerator() {} + +// Initializes the vars referenced in the generated code templates. +void ExtensionGenerator::InitTemplateVars( + const FieldDescriptor* descriptor, const std::string& scope, bool immutable, + ClassNameResolver* name_resolver, + std::map<std::string, std::string>* vars_pointer) { + std::map<std::string, std::string>& vars = *vars_pointer; + vars["scope"] = scope; + vars["name"] = UnderscoresToCamelCaseCheckReserved(descriptor); + vars["containing_type"] = + name_resolver->GetClassName(descriptor->containing_type(), immutable); + vars["number"] = StrCat(descriptor->number()); + vars["constant_name"] = FieldConstantName(descriptor); + vars["index"] = StrCat(descriptor->index()); + vars["default"] = descriptor->is_repeated() + ? "" + : DefaultValue(descriptor, immutable, name_resolver); + vars["type_constant"] = FieldTypeName(GetType(descriptor)); + vars["packed"] = descriptor->is_packed() ? "true" : "false"; + vars["enum_map"] = "null"; + vars["prototype"] = "null"; + + JavaType java_type = GetJavaType(descriptor); + std::string singular_type; + switch (java_type) { + case JAVATYPE_MESSAGE: + singular_type = + name_resolver->GetClassName(descriptor->message_type(), immutable); + vars["prototype"] = singular_type + ".getDefaultInstance()"; + break; + case JAVATYPE_ENUM: + singular_type = + name_resolver->GetClassName(descriptor->enum_type(), immutable); + vars["enum_map"] = singular_type + ".internalGetValueMap()"; + break; + case JAVATYPE_STRING: + singular_type = "java.lang.String"; + break; + case JAVATYPE_BYTES: + singular_type = immutable ? "com.google.protobuf.ByteString" : "byte[]"; + break; + default: + singular_type = BoxedPrimitiveTypeName(java_type); + break; + } + vars["type"] = descriptor->is_repeated() + ? "java.util.List<" + singular_type + ">" + : singular_type; + vars["singular_type"] = singular_type; +} + +void ImmutableExtensionGenerator::Generate(io::Printer* printer) { + std::map<std::string, std::string> vars; + const bool kUseImmutableNames = true; + InitTemplateVars(descriptor_, scope_, kUseImmutableNames, name_resolver_, + &vars); + printer->Print(vars, "public static final int $constant_name$ = $number$;\n"); + + WriteFieldDocComment(printer, descriptor_); + if (descriptor_->extension_scope() == NULL) { + // Non-nested + printer->Print( + vars, + "public static final\n" + " com.google.protobuf.GeneratedMessage.GeneratedExtension<\n" + " $containing_type$,\n" + " $type$> $name$ = com.google.protobuf.GeneratedMessage\n" + " .newFileScopedGeneratedExtension(\n" + " $singular_type$.class,\n" + " $prototype$);\n"); + } else { + // Nested + printer->Print( + vars, + "public static final\n" + " com.google.protobuf.GeneratedMessage.GeneratedExtension<\n" + " $containing_type$,\n" + " $type$> $name$ = com.google.protobuf.GeneratedMessage\n" + " .newMessageScopedGeneratedExtension(\n" + " $scope$.getDefaultInstance(),\n" + " $index$,\n" + " $singular_type$.class,\n" + " $prototype$);\n"); + } + printer->Annotate("name", descriptor_); +} + +int ImmutableExtensionGenerator::GenerateNonNestedInitializationCode( + io::Printer* printer) { + int bytecode_estimate = 0; + if (descriptor_->extension_scope() == NULL) { + // Only applies to non-nested extensions. + printer->Print( + "$name$.internalInit(descriptor.getExtensions().get($index$));\n", + "name", UnderscoresToCamelCaseCheckReserved(descriptor_), "index", + StrCat(descriptor_->index())); + bytecode_estimate += 21; + } + return bytecode_estimate; +} + +int ImmutableExtensionGenerator::GenerateRegistrationCode( + io::Printer* printer) { + printer->Print("registry.add($scope$.$name$);\n", "scope", scope_, "name", + UnderscoresToCamelCaseCheckReserved(descriptor_)); + return 7; +} + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/java/java_extension.h b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_extension.h new file mode 100644 index 00000000..823190d7 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_extension.h @@ -0,0 +1,115 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_EXTENSION_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVA_EXTENSION_H__ + +#include <map> +#include <string> + +#include <stubs/common.h> + +namespace google { +namespace protobuf { +class FieldDescriptor; // descriptor.h +namespace compiler { +namespace java { +class Context; // context.h +class ClassNameResolver; // name_resolver.h +} // namespace java +} // namespace compiler +namespace io { +class Printer; // printer.h +} +} // namespace protobuf +} // namespace google + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +// Generates code for an extension, which may be within the scope of some +// message or may be at file scope. This is much simpler than FieldGenerator +// since extensions are just simple identifiers with interesting types. +class ExtensionGenerator { + public: + explicit ExtensionGenerator() {} + virtual ~ExtensionGenerator() {} + + virtual void Generate(io::Printer* printer) = 0; + + // Returns an estimate of the number of bytes the printed code will compile + // to + virtual int GenerateNonNestedInitializationCode(io::Printer* printer) = 0; + + // Returns an estimate of the number of bytes the printed code will compile + // to + virtual int GenerateRegistrationCode(io::Printer* printer) = 0; + + protected: + static void InitTemplateVars( + const FieldDescriptor* descriptor, const std::string& scope, + bool immutable, ClassNameResolver* name_resolver, + std::map<std::string, std::string>* vars_pointer); + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ExtensionGenerator); +}; + +class ImmutableExtensionGenerator : public ExtensionGenerator { + public: + explicit ImmutableExtensionGenerator(const FieldDescriptor* descriptor, + Context* context); + virtual ~ImmutableExtensionGenerator(); + + void Generate(io::Printer* printer) override; + int GenerateNonNestedInitializationCode(io::Printer* printer) override; + int GenerateRegistrationCode(io::Printer* printer) override; + + protected: + const FieldDescriptor* descriptor_; + ClassNameResolver* name_resolver_; + std::string scope_; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableExtensionGenerator); +}; + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_EXTENSION_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/java/java_extension_lite.cc b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_extension_lite.cc new file mode 100644 index 00000000..cf1975a0 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_extension_lite.cc @@ -0,0 +1,115 @@ +// 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 <compiler/java/java_extension_lite.h> + +#include <compiler/java/java_context.h> +#include <compiler/java/java_doc_comment.h> +#include <compiler/java/java_helpers.h> +#include <compiler/java/java_name_resolver.h> +#include <io/printer.h> +#include <stubs/strutil.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +ImmutableExtensionLiteGenerator::ImmutableExtensionLiteGenerator( + const FieldDescriptor* descriptor, Context* context) + : descriptor_(descriptor), name_resolver_(context->GetNameResolver()) { + if (descriptor_->extension_scope() != NULL) { + scope_ = + name_resolver_->GetImmutableClassName(descriptor_->extension_scope()); + } else { + scope_ = name_resolver_->GetImmutableClassName(descriptor_->file()); + } +} + +ImmutableExtensionLiteGenerator::~ImmutableExtensionLiteGenerator() {} + +void ImmutableExtensionLiteGenerator::Generate(io::Printer* printer) { + std::map<std::string, std::string> vars; + const bool kUseImmutableNames = true; + InitTemplateVars(descriptor_, scope_, kUseImmutableNames, name_resolver_, + &vars); + printer->Print(vars, "public static final int $constant_name$ = $number$;\n"); + + WriteFieldDocComment(printer, descriptor_); + if (descriptor_->is_repeated()) { + printer->Print( + vars, + "public static final\n" + " com.google.protobuf.GeneratedMessageLite.GeneratedExtension<\n" + " $containing_type$,\n" + " $type$> $name$ = com.google.protobuf.GeneratedMessageLite\n" + " .newRepeatedGeneratedExtension(\n" + " $containing_type$.getDefaultInstance(),\n" + " $prototype$,\n" + " $enum_map$,\n" + " $number$,\n" + " com.google.protobuf.WireFormat.FieldType.$type_constant$,\n" + " $packed$,\n" + " $singular_type$.class);\n"); + } else { + printer->Print( + vars, + "public static final\n" + " com.google.protobuf.GeneratedMessageLite.GeneratedExtension<\n" + " $containing_type$,\n" + " $type$> $name$ = com.google.protobuf.GeneratedMessageLite\n" + " .newSingularGeneratedExtension(\n" + " $containing_type$.getDefaultInstance(),\n" + " $default$,\n" + " $prototype$,\n" + " $enum_map$,\n" + " $number$,\n" + " com.google.protobuf.WireFormat.FieldType.$type_constant$,\n" + " $singular_type$.class);\n"); + } + printer->Annotate("name", descriptor_); +} + +int ImmutableExtensionLiteGenerator::GenerateNonNestedInitializationCode( + io::Printer* printer) { + return 0; +} + +int ImmutableExtensionLiteGenerator::GenerateRegistrationCode( + io::Printer* printer) { + printer->Print("registry.add($scope$.$name$);\n", "scope", scope_, "name", + UnderscoresToCamelCaseCheckReserved(descriptor_)); + return 7; +} + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/java/java_extension_lite.h b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_extension_lite.h new file mode 100644 index 00000000..0e38079f --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_extension_lite.h @@ -0,0 +1,75 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_EXTENSION_LITE_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVA_EXTENSION_LITE_H__ + +#include <map> +#include <string> + +#include <stubs/common.h> +#include <compiler/java/java_extension.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +// Generates code for a lite extension, which may be within the scope of some +// message or may be at file scope. This is much simpler than FieldGenerator +// since extensions are just simple identifiers with interesting types. +class ImmutableExtensionLiteGenerator : public ExtensionGenerator { + public: + explicit ImmutableExtensionLiteGenerator(const FieldDescriptor* descriptor, + Context* context); + virtual ~ImmutableExtensionLiteGenerator(); + + void Generate(io::Printer* printer) override; + + // Returns an estimate of the number of bytes the printed code will compile to + int GenerateNonNestedInitializationCode(io::Printer* printer) override; + + // Returns an estimate of the number of bytes the printed code will compile to + int GenerateRegistrationCode(io::Printer* printer) override; + + private: + const FieldDescriptor* descriptor_; + ClassNameResolver* name_resolver_; + std::string scope_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableExtensionLiteGenerator); +}; + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_EXTENSION_LITE_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/java/java_field.cc b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_field.cc new file mode 100644 index 00000000..5da51b22 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_field.cc @@ -0,0 +1,312 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <compiler/java/java_field.h> + +#include <memory> + +#include <stubs/logging.h> +#include <stubs/common.h> +#include <compiler/java/java_context.h> +#include <compiler/java/java_enum_field.h> +#include <compiler/java/java_enum_field_lite.h> +#include <compiler/java/java_helpers.h> +#include <compiler/java/java_map_field.h> +#include <compiler/java/java_map_field_lite.h> +#include <compiler/java/java_message_field.h> +#include <compiler/java/java_message_field_lite.h> +#include <compiler/java/java_primitive_field.h> +#include <compiler/java/java_primitive_field_lite.h> +#include <compiler/java/java_string_field.h> +#include <compiler/java/java_string_field_lite.h> +#include <io/printer.h> +#include <stubs/strutil.h> +#include <stubs/substitute.h> + + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +namespace { + +ImmutableFieldGenerator* MakeImmutableGenerator(const FieldDescriptor* field, + int messageBitIndex, + int builderBitIndex, + Context* context) { + if (field->is_repeated()) { + switch (GetJavaType(field)) { + case JAVATYPE_MESSAGE: + if (IsMapEntry(field->message_type())) { + return new ImmutableMapFieldGenerator(field, messageBitIndex, + builderBitIndex, context); + } else { + return new RepeatedImmutableMessageFieldGenerator( + field, messageBitIndex, builderBitIndex, context); + } + case JAVATYPE_ENUM: + return new RepeatedImmutableEnumFieldGenerator( + field, messageBitIndex, builderBitIndex, context); + case JAVATYPE_STRING: + return new RepeatedImmutableStringFieldGenerator( + field, messageBitIndex, builderBitIndex, context); + default: + return new RepeatedImmutablePrimitiveFieldGenerator( + field, messageBitIndex, builderBitIndex, context); + } + } else { + if (IsRealOneof(field)) { + switch (GetJavaType(field)) { + case JAVATYPE_MESSAGE: + return new ImmutableMessageOneofFieldGenerator( + field, messageBitIndex, builderBitIndex, context); + case JAVATYPE_ENUM: + return new ImmutableEnumOneofFieldGenerator(field, messageBitIndex, + builderBitIndex, context); + case JAVATYPE_STRING: + return new ImmutableStringOneofFieldGenerator( + field, messageBitIndex, builderBitIndex, context); + default: + return new ImmutablePrimitiveOneofFieldGenerator( + field, messageBitIndex, builderBitIndex, context); + } + } else { + switch (GetJavaType(field)) { + case JAVATYPE_MESSAGE: + return new ImmutableMessageFieldGenerator(field, messageBitIndex, + builderBitIndex, context); + case JAVATYPE_ENUM: + return new ImmutableEnumFieldGenerator(field, messageBitIndex, + builderBitIndex, context); + case JAVATYPE_STRING: + return new ImmutableStringFieldGenerator(field, messageBitIndex, + builderBitIndex, context); + default: + return new ImmutablePrimitiveFieldGenerator(field, messageBitIndex, + builderBitIndex, context); + } + } + } +} + +ImmutableFieldLiteGenerator* MakeImmutableLiteGenerator( + const FieldDescriptor* field, int messageBitIndex, Context* context) { + if (field->is_repeated()) { + switch (GetJavaType(field)) { + case JAVATYPE_MESSAGE: + if (IsMapEntry(field->message_type())) { + return new ImmutableMapFieldLiteGenerator(field, messageBitIndex, + context); + } else { + return new RepeatedImmutableMessageFieldLiteGenerator( + field, messageBitIndex, context); + } + case JAVATYPE_ENUM: + return new RepeatedImmutableEnumFieldLiteGenerator( + field, messageBitIndex, context); + case JAVATYPE_STRING: + return new RepeatedImmutableStringFieldLiteGenerator( + field, messageBitIndex, context); + default: + return new RepeatedImmutablePrimitiveFieldLiteGenerator( + field, messageBitIndex, context); + } + } else { + if (IsRealOneof(field)) { + switch (GetJavaType(field)) { + case JAVATYPE_MESSAGE: + return new ImmutableMessageOneofFieldLiteGenerator( + field, messageBitIndex, context); + case JAVATYPE_ENUM: + return new ImmutableEnumOneofFieldLiteGenerator( + field, messageBitIndex, context); + case JAVATYPE_STRING: + return new ImmutableStringOneofFieldLiteGenerator( + field, messageBitIndex, context); + default: + return new ImmutablePrimitiveOneofFieldLiteGenerator( + field, messageBitIndex, context); + } + } else { + switch (GetJavaType(field)) { + case JAVATYPE_MESSAGE: + return new ImmutableMessageFieldLiteGenerator(field, messageBitIndex, + context); + case JAVATYPE_ENUM: + return new ImmutableEnumFieldLiteGenerator(field, messageBitIndex, + context); + case JAVATYPE_STRING: + return new ImmutableStringFieldLiteGenerator(field, messageBitIndex, + context); + default: + return new ImmutablePrimitiveFieldLiteGenerator( + field, messageBitIndex, context); + } + } + } +} + + +static inline void ReportUnexpectedPackedFieldsCall(io::Printer* printer) { + // Reaching here indicates a bug. Cases are: + // - This FieldGenerator should support packing, + // but this method should be overridden. + // - This FieldGenerator doesn't support packing, and this method + // should never have been called. + GOOGLE_LOG(FATAL) << "GenerateParsingCodeFromPacked() " + << "called on field generator that does not support packing."; +} + +} // namespace + +ImmutableFieldGenerator::~ImmutableFieldGenerator() {} + +void ImmutableFieldGenerator::GenerateParsingCodeFromPacked( + io::Printer* printer) const { + ReportUnexpectedPackedFieldsCall(printer); +} + +ImmutableFieldLiteGenerator::~ImmutableFieldLiteGenerator() {} + +// =================================================================== + +template <> +FieldGeneratorMap<ImmutableFieldGenerator>::FieldGeneratorMap( + const Descriptor* descriptor, Context* context) + : descriptor_(descriptor), field_generators_(descriptor->field_count()) { + // Construct all the FieldGenerators and assign them bit indices for their + // bit fields. + int messageBitIndex = 0; + int builderBitIndex = 0; + for (int i = 0; i < descriptor->field_count(); i++) { + ImmutableFieldGenerator* generator = MakeImmutableGenerator( + descriptor->field(i), messageBitIndex, builderBitIndex, context); + field_generators_[i].reset(generator); + messageBitIndex += generator->GetNumBitsForMessage(); + builderBitIndex += generator->GetNumBitsForBuilder(); + } +} + +template <> +FieldGeneratorMap<ImmutableFieldGenerator>::~FieldGeneratorMap() {} + +template <> +FieldGeneratorMap<ImmutableFieldLiteGenerator>::FieldGeneratorMap( + const Descriptor* descriptor, Context* context) + : descriptor_(descriptor), field_generators_(descriptor->field_count()) { + // Construct all the FieldGenerators and assign them bit indices for their + // bit fields. + int messageBitIndex = 0; + for (int i = 0; i < descriptor->field_count(); i++) { + ImmutableFieldLiteGenerator* generator = MakeImmutableLiteGenerator( + descriptor->field(i), messageBitIndex, context); + field_generators_[i].reset(generator); + messageBitIndex += generator->GetNumBitsForMessage(); + } +} + +template <> +FieldGeneratorMap<ImmutableFieldLiteGenerator>::~FieldGeneratorMap() {} + + +void SetCommonFieldVariables(const FieldDescriptor* descriptor, + const FieldGeneratorInfo* info, + std::map<std::string, std::string>* variables) { + (*variables)["field_name"] = descriptor->name(); + (*variables)["name"] = info->name; + (*variables)["classname"] = descriptor->containing_type()->name(); + (*variables)["capitalized_name"] = info->capitalized_name; + (*variables)["disambiguated_reason"] = info->disambiguated_reason; + (*variables)["constant_name"] = FieldConstantName(descriptor); + (*variables)["number"] = StrCat(descriptor->number()); + (*variables)["kt_dsl_builder"] = "_builder"; + // These variables are placeholders to pick out the beginning and ends of + // identifiers for annotations (when doing so with existing variables would + // be ambiguous or impossible). They should never be set to anything but the + // empty string. + (*variables)["{"] = ""; + (*variables)["}"] = ""; + (*variables)["kt_name"] = + IsForbiddenKotlin(info->name) ? info->name + "_" : info->name; + (*variables)["kt_capitalized_name"] = IsForbiddenKotlin(info->name) + ? info->capitalized_name + "_" + : info->capitalized_name; + if (!descriptor->is_repeated()) { + (*variables)["annotation_field_type"] = FieldTypeName(descriptor->type()); + } else if (GetJavaType(descriptor) == JAVATYPE_MESSAGE && + IsMapEntry(descriptor->message_type())) { + (*variables)["annotation_field_type"] = + std::string(FieldTypeName(descriptor->type())) + "MAP"; + } else { + (*variables)["annotation_field_type"] = + std::string(FieldTypeName(descriptor->type())) + "_LIST"; + if (descriptor->is_packed()) { + (*variables)["annotation_field_type"] = + (*variables)["annotation_field_type"] + "_PACKED"; + } + } +} + +void SetCommonOneofVariables(const FieldDescriptor* descriptor, + const OneofGeneratorInfo* info, + std::map<std::string, std::string>* variables) { + (*variables)["oneof_name"] = info->name; + (*variables)["oneof_capitalized_name"] = info->capitalized_name; + (*variables)["oneof_index"] = + StrCat(descriptor->containing_oneof()->index()); + (*variables)["oneof_stored_type"] = GetOneofStoredType(descriptor); + (*variables)["set_oneof_case_message"] = + info->name + "Case_ = " + StrCat(descriptor->number()); + (*variables)["clear_oneof_case_message"] = info->name + "Case_ = 0"; + (*variables)["has_oneof_case_message"] = + info->name + "Case_ == " + StrCat(descriptor->number()); +} + +void PrintExtraFieldInfo(const std::map<std::string, std::string>& variables, + io::Printer* printer) { + const std::map<std::string, std::string>::const_iterator it = + variables.find("disambiguated_reason"); + if (it != variables.end() && !it->second.empty()) { + printer->Print( + variables, + "// An alternative name is used for field \"$field_name$\" because:\n" + "// $disambiguated_reason$\n"); + } +} + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/java/java_field.h b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_field.h new file mode 100644 index 00000000..d010faac --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_field.h @@ -0,0 +1,191 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_FIELD_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVA_FIELD_H__ + +#include <cstdint> +#include <map> +#include <memory> +#include <string> + +#include <stubs/logging.h> +#include <stubs/common.h> +#include <descriptor.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { +class Context; // context.h +class ClassNameResolver; // name_resolver.h +} // namespace java +} // namespace compiler +namespace io { +class Printer; // printer.h +} +} // namespace protobuf +} // namespace google + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +class ImmutableFieldGenerator { + public: + ImmutableFieldGenerator() {} + virtual ~ImmutableFieldGenerator(); + + virtual int GetNumBitsForMessage() const = 0; + virtual int GetNumBitsForBuilder() const = 0; + virtual void GenerateInterfaceMembers(io::Printer* printer) const = 0; + virtual void GenerateMembers(io::Printer* printer) const = 0; + virtual void GenerateBuilderMembers(io::Printer* printer) const = 0; + virtual void GenerateInitializationCode(io::Printer* printer) const = 0; + virtual void GenerateBuilderClearCode(io::Printer* printer) const = 0; + virtual void GenerateMergingCode(io::Printer* printer) const = 0; + virtual void GenerateBuildingCode(io::Printer* printer) const = 0; + virtual void GenerateParsingCode(io::Printer* printer) const = 0; + virtual void GenerateParsingCodeFromPacked(io::Printer* printer) const; + virtual void GenerateParsingDoneCode(io::Printer* printer) const = 0; + virtual void GenerateSerializationCode(io::Printer* printer) const = 0; + virtual void GenerateSerializedSizeCode(io::Printer* printer) const = 0; + virtual void GenerateFieldBuilderInitializationCode( + io::Printer* printer) const = 0; + virtual void GenerateKotlinDslMembers(io::Printer* printer) const = 0; + + virtual void GenerateEqualsCode(io::Printer* printer) const = 0; + virtual void GenerateHashCode(io::Printer* printer) const = 0; + + virtual std::string GetBoxedType() const = 0; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableFieldGenerator); +}; + +class ImmutableFieldLiteGenerator { + public: + ImmutableFieldLiteGenerator() {} + virtual ~ImmutableFieldLiteGenerator(); + + virtual int GetNumBitsForMessage() const = 0; + virtual void GenerateInterfaceMembers(io::Printer* printer) const = 0; + virtual void GenerateMembers(io::Printer* printer) const = 0; + virtual void GenerateBuilderMembers(io::Printer* printer) const = 0; + virtual void GenerateInitializationCode(io::Printer* printer) const = 0; + virtual void GenerateFieldInfo(io::Printer* printer, + std::vector<uint16_t>* output) const = 0; + virtual void GenerateKotlinDslMembers(io::Printer* printer) const = 0; + + virtual std::string GetBoxedType() const = 0; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableFieldLiteGenerator); +}; + + +// Convenience class which constructs FieldGenerators for a Descriptor. +template <typename FieldGeneratorType> +class FieldGeneratorMap { + public: + explicit FieldGeneratorMap(const Descriptor* descriptor, Context* context); + ~FieldGeneratorMap(); + + const FieldGeneratorType& get(const FieldDescriptor* field) const; + + private: + const Descriptor* descriptor_; + std::vector<std::unique_ptr<FieldGeneratorType>> field_generators_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGeneratorMap); +}; + +template <typename FieldGeneratorType> +inline const FieldGeneratorType& FieldGeneratorMap<FieldGeneratorType>::get( + const FieldDescriptor* field) const { + GOOGLE_CHECK_EQ(field->containing_type(), descriptor_); + return *field_generators_[field->index()]; +} + +// Instantiate template for mutable and immutable maps. +template <> +FieldGeneratorMap<ImmutableFieldGenerator>::FieldGeneratorMap( + const Descriptor* descriptor, Context* context); + +template <> +FieldGeneratorMap<ImmutableFieldGenerator>::~FieldGeneratorMap(); + + +template <> +FieldGeneratorMap<ImmutableFieldLiteGenerator>::FieldGeneratorMap( + const Descriptor* descriptor, Context* context); + +template <> +FieldGeneratorMap<ImmutableFieldLiteGenerator>::~FieldGeneratorMap(); + + +// Field information used in FieldGeneartors. +struct FieldGeneratorInfo { + std::string name; + std::string capitalized_name; + std::string disambiguated_reason; +}; + +// Oneof information used in OneofFieldGenerators. +struct OneofGeneratorInfo { + std::string name; + std::string capitalized_name; +}; + +// Set some common variables used in variable FieldGenerators. +void SetCommonFieldVariables(const FieldDescriptor* descriptor, + const FieldGeneratorInfo* info, + std::map<std::string, std::string>* variables); + +// Set some common oneof variables used in OneofFieldGenerators. +void SetCommonOneofVariables(const FieldDescriptor* descriptor, + const OneofGeneratorInfo* info, + std::map<std::string, std::string>* variables); + +// Print useful comments before a field's accessors. +void PrintExtraFieldInfo(const std::map<std::string, std::string>& variables, + io::Printer* printer); + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_FIELD_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/java/java_file.cc b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_file.cc new file mode 100644 index 00000000..71a49ed4 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_file.cc @@ -0,0 +1,734 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <compiler/java/java_file.h> + +#include <memory> +#include <set> + +#include <compiler/java/java_context.h> +#include <compiler/java/java_enum.h> +#include <compiler/java/java_enum_lite.h> +#include <compiler/java/java_extension.h> +#include <compiler/java/java_generator_factory.h> +#include <compiler/java/java_helpers.h> +#include <compiler/java/java_message.h> +#include <compiler/java/java_name_resolver.h> +#include <compiler/java/java_service.h> +#include <compiler/java/java_shared_code_generator.h> +#include <compiler/code_generator.h> +#include <descriptor.pb.h> +#include <io/printer.h> +#include <io/zero_copy_stream.h> +#include <dynamic_message.h> +#include <stubs/strutil.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +namespace { + +struct FieldDescriptorCompare { + bool operator()(const FieldDescriptor* f1, const FieldDescriptor* f2) const { + if (f1 == NULL) { + return false; + } + if (f2 == NULL) { + return true; + } + return f1->full_name() < f2->full_name(); + } +}; + +typedef std::set<const FieldDescriptor*, FieldDescriptorCompare> + FieldDescriptorSet; + +// Recursively searches the given message to collect extensions. +// Returns true if all the extensions can be recognized. The extensions will be +// appended in to the extensions parameter. +// Returns false when there are unknown fields, in which case the data in the +// extensions output parameter is not reliable and should be discarded. +bool CollectExtensions(const Message& message, FieldDescriptorSet* extensions) { + const Reflection* reflection = message.GetReflection(); + + // There are unknown fields that could be extensions, thus this call fails. + if (reflection->GetUnknownFields(message).field_count() > 0) return false; + + std::vector<const FieldDescriptor*> fields; + reflection->ListFields(message, &fields); + + for (int i = 0; i < fields.size(); i++) { + if (fields[i]->is_extension()) { + extensions->insert(fields[i]); + } + + if (GetJavaType(fields[i]) == JAVATYPE_MESSAGE) { + if (fields[i]->is_repeated()) { + int size = reflection->FieldSize(message, fields[i]); + for (int j = 0; j < size; j++) { + const Message& sub_message = + reflection->GetRepeatedMessage(message, fields[i], j); + if (!CollectExtensions(sub_message, extensions)) return false; + } + } else { + const Message& sub_message = reflection->GetMessage(message, fields[i]); + if (!CollectExtensions(sub_message, extensions)) return false; + } + } + } + + return true; +} + +// Finds all extensions in the given message and its sub-messages. If the +// message contains unknown fields (which could be extensions), then those +// extensions are defined in alternate_pool. +// The message will be converted to a DynamicMessage backed by alternate_pool +// in order to handle this case. +void CollectExtensions(const FileDescriptorProto& file_proto, + const DescriptorPool& alternate_pool, + FieldDescriptorSet* extensions, + const std::string& file_data) { + if (!CollectExtensions(file_proto, extensions)) { + // There are unknown fields in the file_proto, which are probably + // extensions. We need to parse the data into a dynamic message based on the + // builder-pool to find out all extensions. + const Descriptor* file_proto_desc = alternate_pool.FindMessageTypeByName( + file_proto.GetDescriptor()->full_name()); + GOOGLE_CHECK(file_proto_desc) + << "Find unknown fields in FileDescriptorProto when building " + << file_proto.name() + << ". It's likely that those fields are custom options, however, " + "descriptor.proto is not in the transitive dependencies. " + "This normally should not happen. Please report a bug."; + DynamicMessageFactory factory; + std::unique_ptr<Message> dynamic_file_proto( + factory.GetPrototype(file_proto_desc)->New()); + GOOGLE_CHECK(dynamic_file_proto.get() != NULL); + GOOGLE_CHECK(dynamic_file_proto->ParseFromString(file_data)); + + // Collect the extensions again from the dynamic message. There should be no + // more unknown fields this time, i.e. all the custom options should be + // parsed as extensions now. + extensions->clear(); + GOOGLE_CHECK(CollectExtensions(*dynamic_file_proto, extensions)) + << "Find unknown fields in FileDescriptorProto when building " + << file_proto.name() + << ". It's likely that those fields are custom options, however, " + "those options cannot be recognized in the builder pool. " + "This normally should not happen. Please report a bug."; + } +} + +// Our static initialization methods can become very, very large. +// So large that if we aren't careful we end up blowing the JVM's +// 64K bytes of bytecode/method. Fortunately, since these static +// methods are executed only once near the beginning of a program, +// there's usually plenty of stack space available and we can +// extend our methods by simply chaining them to another method +// with a tail call. This inserts the sequence call-next-method, +// end this one, begin-next-method as needed. +void MaybeRestartJavaMethod(io::Printer* printer, int* bytecode_estimate, + int* method_num, const char* chain_statement, + const char* method_decl) { + // The goal here is to stay under 64K bytes of jvm bytecode/method, + // since otherwise we hit a hardcoded limit in the jvm and javac will + // then fail with the error "code too large". This limit lets our + // estimates be off by a factor of two and still we're okay. + static const int bytesPerMethod = kMaxStaticSize; + + if ((*bytecode_estimate) > bytesPerMethod) { + ++(*method_num); + printer->Print(chain_statement, "method_num", StrCat(*method_num)); + printer->Outdent(); + printer->Print("}\n"); + printer->Print(method_decl, "method_num", StrCat(*method_num)); + printer->Indent(); + *bytecode_estimate = 0; + } +} +} // namespace + +FileGenerator::FileGenerator(const FileDescriptor* file, const Options& options, + bool immutable_api) + : file_(file), + java_package_(FileJavaPackage(file, immutable_api)), + message_generators_(file->message_type_count()), + extension_generators_(file->extension_count()), + context_(new Context(file, options)), + name_resolver_(context_->GetNameResolver()), + options_(options), + immutable_api_(immutable_api) { + classname_ = name_resolver_->GetFileClassName(file, immutable_api); + generator_factory_.reset(new ImmutableGeneratorFactory(context_.get())); + for (int i = 0; i < file_->message_type_count(); ++i) { + message_generators_[i].reset( + generator_factory_->NewMessageGenerator(file_->message_type(i))); + } + for (int i = 0; i < file_->extension_count(); ++i) { + extension_generators_[i].reset( + generator_factory_->NewExtensionGenerator(file_->extension(i))); + } +} + +FileGenerator::~FileGenerator() {} + +bool FileGenerator::Validate(std::string* error) { + // Check that no class name matches the file's class name. This is a common + // problem that leads to Java compile errors that can be hard to understand. + // It's especially bad when using the java_multiple_files, since we would + // end up overwriting the outer class with one of the inner ones. + if (name_resolver_->HasConflictingClassName(file_, classname_, + NameEquality::EXACT_EQUAL)) { + error->assign(file_->name()); + error->append( + ": Cannot generate Java output because the file's outer class name, " + "\""); + error->append(classname_); + error->append( + "\", matches the name of one of the types declared inside it. " + "Please either rename the type or use the java_outer_classname " + "option to specify a different outer class name for the .proto file."); + return false; + } + // Similar to the check above, but ignore the case this time. This is not a + // problem on Linux, but will lead to Java compile errors on Windows / Mac + // because filenames are case-insensitive on those platforms. + if (name_resolver_->HasConflictingClassName( + file_, classname_, NameEquality::EQUAL_IGNORE_CASE)) { + GOOGLE_LOG(WARNING) + << file_->name() << ": The file's outer class name, \"" << classname_ + << "\", matches the name of one of the types declared inside it when " + << "case is ignored. This can cause compilation issues on Windows / " + << "MacOS. Please either rename the type or use the " + << "java_outer_classname option to specify a different outer class " + << "name for the .proto file to be safe."; + } + + // Print a warning if optimize_for = LITE_RUNTIME is used. + if (file_->options().optimize_for() == FileOptions::LITE_RUNTIME && + !options_.enforce_lite) { + GOOGLE_LOG(WARNING) + << "The optimize_for = LITE_RUNTIME option is no longer supported by " + << "protobuf Java code generator and is ignored--protoc will always " + << "generate full runtime code for Java. To use Java Lite runtime, " + << "users should use the Java Lite plugin instead. See:\n" + << " " + "https://github.com/protocolbuffers/protobuf/blob/master/java/" + "lite.md"; + } + return true; +} + +void FileGenerator::Generate(io::Printer* printer) { + // We don't import anything because we refer to all classes by their + // fully-qualified names in the generated source. + printer->Print( + "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" + "// source: $filename$\n" + "\n", + "filename", file_->name()); + if (!java_package_.empty()) { + printer->Print( + "package $package$;\n" + "\n", + "package", java_package_); + } + PrintGeneratedAnnotation( + printer, '$', options_.annotate_code ? classname_ + ".java.pb.meta" : ""); + + printer->Print( + "$deprecation$public final class $classname$ {\n" + " private $ctor$() {}\n", + "deprecation", + file_->options().deprecated() ? "@java.lang.Deprecated " : "", + "classname", classname_, "ctor", classname_); + printer->Annotate("classname", file_->name()); + printer->Indent(); + + // ----------------------------------------------------------------- + + printer->Print( + "public static void registerAllExtensions(\n" + " com.google.protobuf.ExtensionRegistryLite registry) {\n"); + + printer->Indent(); + + for (int i = 0; i < file_->extension_count(); i++) { + extension_generators_[i]->GenerateRegistrationCode(printer); + } + + for (int i = 0; i < file_->message_type_count(); i++) { + message_generators_[i]->GenerateExtensionRegistrationCode(printer); + } + + printer->Outdent(); + printer->Print("}\n"); + if (HasDescriptorMethods(file_, context_->EnforceLite())) { + // Overload registerAllExtensions for the non-lite usage to + // redundantly maintain the original signature (this is + // redundant because ExtensionRegistryLite now invokes + // ExtensionRegistry in the non-lite usage). Intent is + // to remove this in the future. + printer->Print( + "\n" + "public static void registerAllExtensions(\n" + " com.google.protobuf.ExtensionRegistry registry) {\n" + " registerAllExtensions(\n" + " (com.google.protobuf.ExtensionRegistryLite) registry);\n" + "}\n"); + } + + // ----------------------------------------------------------------- + + if (!MultipleJavaFiles(file_, immutable_api_)) { + for (int i = 0; i < file_->enum_type_count(); i++) { + if (HasDescriptorMethods(file_, context_->EnforceLite())) { + EnumGenerator(file_->enum_type(i), immutable_api_, context_.get()) + .Generate(printer); + } else { + EnumLiteGenerator(file_->enum_type(i), immutable_api_, context_.get()) + .Generate(printer); + } + } + for (int i = 0; i < file_->message_type_count(); i++) { + message_generators_[i]->GenerateInterface(printer); + message_generators_[i]->Generate(printer); + } + if (HasGenericServices(file_, context_->EnforceLite())) { + for (int i = 0; i < file_->service_count(); i++) { + std::unique_ptr<ServiceGenerator> generator( + generator_factory_->NewServiceGenerator(file_->service(i))); + generator->Generate(printer); + } + } + } + + // Extensions must be generated in the outer class since they are values, + // not classes. + for (int i = 0; i < file_->extension_count(); i++) { + extension_generators_[i]->Generate(printer); + } + + // Static variables. We'd like them to be final if possible, but due to + // the JVM's 64k size limit on static blocks, we have to initialize some + // of them in methods; thus they cannot be final. + int static_block_bytecode_estimate = 0; + for (int i = 0; i < file_->message_type_count(); i++) { + message_generators_[i]->GenerateStaticVariables( + printer, &static_block_bytecode_estimate); + } + + printer->Print("\n"); + + if (HasDescriptorMethods(file_, context_->EnforceLite())) { + if (immutable_api_) { + GenerateDescriptorInitializationCodeForImmutable(printer); + } else { + GenerateDescriptorInitializationCodeForMutable(printer); + } + } else { + printer->Print("static {\n"); + printer->Indent(); + int bytecode_estimate = 0; + int method_num = 0; + + for (int i = 0; i < file_->message_type_count(); i++) { + bytecode_estimate += + message_generators_[i]->GenerateStaticVariableInitializers(printer); + MaybeRestartJavaMethod( + printer, &bytecode_estimate, &method_num, + "_clinit_autosplit_$method_num$();\n", + "private static void _clinit_autosplit_$method_num$() {\n"); + } + + printer->Outdent(); + printer->Print("}\n"); + } + + printer->Print( + "\n" + "// @@protoc_insertion_point(outer_class_scope)\n"); + + printer->Outdent(); + printer->Print("}\n"); +} + +void FileGenerator::GenerateDescriptorInitializationCodeForImmutable( + io::Printer* printer) { + printer->Print( + "public static com.google.protobuf.Descriptors.FileDescriptor\n" + " getDescriptor() {\n" + " return descriptor;\n" + "}\n" + "private static $final$ com.google.protobuf.Descriptors.FileDescriptor\n" + " descriptor;\n" + "static {\n", + // TODO(dweis): Mark this as final. + "final", ""); + printer->Indent(); + + SharedCodeGenerator shared_code_generator(file_, options_); + shared_code_generator.GenerateDescriptors(printer); + + int bytecode_estimate = 0; + int method_num = 0; + + for (int i = 0; i < file_->message_type_count(); i++) { + bytecode_estimate += + message_generators_[i]->GenerateStaticVariableInitializers(printer); + MaybeRestartJavaMethod( + printer, &bytecode_estimate, &method_num, + "_clinit_autosplit_dinit_$method_num$();\n", + "private static void _clinit_autosplit_dinit_$method_num$() {\n"); + } + for (int i = 0; i < file_->extension_count(); i++) { + bytecode_estimate += + extension_generators_[i]->GenerateNonNestedInitializationCode(printer); + MaybeRestartJavaMethod( + printer, &bytecode_estimate, &method_num, + "_clinit_autosplit_dinit_$method_num$();\n", + "private static void _clinit_autosplit_dinit_$method_num$() {\n"); + } + + // Proto compiler builds a DescriptorPool, which holds all the descriptors to + // generate, when processing the ".proto" files. We call this DescriptorPool + // the parsed pool (a.k.a. file_->pool()). + // + // Note that when users try to extend the (.*)DescriptorProto in their + // ".proto" files, it does not affect the pre-built FileDescriptorProto class + // in proto compiler. When we put the descriptor data in the file_proto, those + // extensions become unknown fields. + // + // Now we need to find out all the extension value to the (.*)DescriptorProto + // in the file_proto message, and prepare an ExtensionRegistry to return. + // + // To find those extensions, we need to parse the data into a dynamic message + // of the FileDescriptor based on the builder-pool, then we can use + // reflections to find all extension fields + FileDescriptorProto file_proto; + file_->CopyTo(&file_proto); + std::string file_data; + file_proto.SerializeToString(&file_data); + FieldDescriptorSet extensions; + CollectExtensions(file_proto, *file_->pool(), &extensions, file_data); + + if (extensions.size() > 0) { + // Must construct an ExtensionRegistry containing all existing extensions + // and use it to parse the descriptor data again to recognize extensions. + printer->Print( + "com.google.protobuf.ExtensionRegistry registry =\n" + " com.google.protobuf.ExtensionRegistry.newInstance();\n"); + FieldDescriptorSet::iterator it; + for (it = extensions.begin(); it != extensions.end(); it++) { + std::unique_ptr<ExtensionGenerator> generator( + generator_factory_->NewExtensionGenerator(*it)); + bytecode_estimate += generator->GenerateRegistrationCode(printer); + MaybeRestartJavaMethod( + printer, &bytecode_estimate, &method_num, + "_clinit_autosplit_dinit_$method_num$(registry);\n", + "private static void _clinit_autosplit_dinit_$method_num$(\n" + " com.google.protobuf.ExtensionRegistry registry) {\n"); + } + printer->Print( + "com.google.protobuf.Descriptors.FileDescriptor\n" + " .internalUpdateFileDescriptor(descriptor, registry);\n"); + } + + // Force descriptor initialization of all dependencies. + for (int i = 0; i < file_->dependency_count(); i++) { + if (ShouldIncludeDependency(file_->dependency(i), true)) { + std::string dependency = + name_resolver_->GetImmutableClassName(file_->dependency(i)); + printer->Print("$dependency$.getDescriptor();\n", "dependency", + dependency); + } + } + + printer->Outdent(); + printer->Print("}\n"); +} + +void FileGenerator::GenerateDescriptorInitializationCodeForMutable( + io::Printer* printer) { + printer->Print( + "public static com.google.protobuf.Descriptors.FileDescriptor\n" + " getDescriptor() {\n" + " return descriptor;\n" + "}\n" + "private static final com.google.protobuf.Descriptors.FileDescriptor\n" + " descriptor;\n" + "static {\n"); + printer->Indent(); + + printer->Print( + "descriptor = $immutable_package$.$descriptor_classname$.descriptor;\n", + "immutable_package", FileJavaPackage(file_, true), "descriptor_classname", + name_resolver_->GetDescriptorClassName(file_)); + + for (int i = 0; i < file_->message_type_count(); i++) { + message_generators_[i]->GenerateStaticVariableInitializers(printer); + } + for (int i = 0; i < file_->extension_count(); i++) { + extension_generators_[i]->GenerateNonNestedInitializationCode(printer); + } + + // Check if custom options exist. If any, try to load immutable classes since + // custom options are only represented with immutable messages. + FileDescriptorProto file_proto; + file_->CopyTo(&file_proto); + std::string file_data; + file_proto.SerializeToString(&file_data); + FieldDescriptorSet extensions; + CollectExtensions(file_proto, *file_->pool(), &extensions, file_data); + + if (extensions.size() > 0) { + // Try to load immutable messages' outer class. Its initialization code + // will take care of interpreting custom options. + printer->Print( + "try {\n" + // Note that we have to load the immutable class dynamically here as + // we want the mutable code to be independent from the immutable code + // at compile time. It is required to implement dual-compile for + // mutable and immutable API in blaze. + " java.lang.Class<?> immutableClass = java.lang.Class.forName(\n" + " \"$immutable_classname$\");\n" + "} catch (java.lang.ClassNotFoundException e) {\n", + "immutable_classname", name_resolver_->GetImmutableClassName(file_)); + printer->Indent(); + + // The immutable class can not be found. We try our best to collect all + // custom option extensions to interpret the custom options. + printer->Print( + "com.google.protobuf.ExtensionRegistry registry =\n" + " com.google.protobuf.ExtensionRegistry.newInstance();\n" + "com.google.protobuf.MessageLite defaultExtensionInstance = null;\n"); + FieldDescriptorSet::iterator it; + for (it = extensions.begin(); it != extensions.end(); it++) { + const FieldDescriptor* field = *it; + std::string scope; + if (field->extension_scope() != NULL) { + scope = name_resolver_->GetMutableClassName(field->extension_scope()) + + ".getDescriptor()"; + } else { + scope = FileJavaPackage(field->file(), true) + "." + + name_resolver_->GetDescriptorClassName(field->file()) + + ".descriptor"; + } + if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + printer->Print( + "defaultExtensionInstance = com.google.protobuf.Internal\n" + " .getDefaultInstance(\"$class$\");\n" + "if (defaultExtensionInstance != null) {\n" + " registry.add(\n" + " $scope$.getExtensions().get($index$),\n" + " (com.google.protobuf.Message) defaultExtensionInstance);\n" + "}\n", + "scope", scope, "index", StrCat(field->index()), "class", + name_resolver_->GetImmutableClassName(field->message_type())); + } else { + printer->Print("registry.add($scope$.getExtensions().get($index$));\n", + "scope", scope, "index", StrCat(field->index())); + } + } + printer->Print( + "com.google.protobuf.Descriptors.FileDescriptor\n" + " .internalUpdateFileDescriptor(descriptor, registry);\n"); + + printer->Outdent(); + printer->Print("}\n"); + } + + // Force descriptor initialization of all dependencies. + for (int i = 0; i < file_->dependency_count(); i++) { + if (ShouldIncludeDependency(file_->dependency(i), false)) { + std::string dependency = + name_resolver_->GetMutableClassName(file_->dependency(i)); + printer->Print("$dependency$.getDescriptor();\n", "dependency", + dependency); + } + } + + printer->Outdent(); + printer->Print("}\n"); +} + +template <typename GeneratorClass, typename DescriptorClass> +static void GenerateSibling( + const std::string& package_dir, const std::string& java_package, + const DescriptorClass* descriptor, GeneratorContext* context, + std::vector<std::string>* file_list, bool annotate_code, + std::vector<std::string>* annotation_list, const std::string& name_suffix, + GeneratorClass* generator, + void (GeneratorClass::*pfn)(io::Printer* printer)) { + std::string filename = + package_dir + descriptor->name() + name_suffix + ".java"; + file_list->push_back(filename); + std::string info_full_path = filename + ".pb.meta"; + GeneratedCodeInfo annotations; + io::AnnotationProtoCollector<GeneratedCodeInfo> annotation_collector( + &annotations); + + std::unique_ptr<io::ZeroCopyOutputStream> output(context->Open(filename)); + io::Printer printer(output.get(), '$', + annotate_code ? &annotation_collector : NULL); + + printer.Print( + "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" + "// source: $filename$\n" + "\n", + "filename", descriptor->file()->name()); + if (!java_package.empty()) { + printer.Print( + "package $package$;\n" + "\n", + "package", java_package); + } + + (generator->*pfn)(&printer); + + if (annotate_code) { + std::unique_ptr<io::ZeroCopyOutputStream> info_output( + context->Open(info_full_path)); + annotations.SerializeToZeroCopyStream(info_output.get()); + annotation_list->push_back(info_full_path); + } +} + +void FileGenerator::GenerateSiblings( + const std::string& package_dir, GeneratorContext* context, + std::vector<std::string>* file_list, + std::vector<std::string>* annotation_list) { + if (MultipleJavaFiles(file_, immutable_api_)) { + for (int i = 0; i < file_->enum_type_count(); i++) { + if (HasDescriptorMethods(file_, context_->EnforceLite())) { + EnumGenerator generator(file_->enum_type(i), immutable_api_, + context_.get()); + GenerateSibling<EnumGenerator>( + package_dir, java_package_, file_->enum_type(i), context, file_list, + options_.annotate_code, annotation_list, "", &generator, + &EnumGenerator::Generate); + } else { + EnumLiteGenerator generator(file_->enum_type(i), immutable_api_, + context_.get()); + GenerateSibling<EnumLiteGenerator>( + package_dir, java_package_, file_->enum_type(i), context, file_list, + options_.annotate_code, annotation_list, "", &generator, + &EnumLiteGenerator::Generate); + } + } + for (int i = 0; i < file_->message_type_count(); i++) { + if (immutable_api_) { + GenerateSibling<MessageGenerator>( + package_dir, java_package_, file_->message_type(i), context, + file_list, options_.annotate_code, annotation_list, "OrBuilder", + message_generators_[i].get(), &MessageGenerator::GenerateInterface); + } + GenerateSibling<MessageGenerator>( + package_dir, java_package_, file_->message_type(i), context, + file_list, options_.annotate_code, annotation_list, "", + message_generators_[i].get(), &MessageGenerator::Generate); + } + if (HasGenericServices(file_, context_->EnforceLite())) { + for (int i = 0; i < file_->service_count(); i++) { + std::unique_ptr<ServiceGenerator> generator( + generator_factory_->NewServiceGenerator(file_->service(i))); + GenerateSibling<ServiceGenerator>( + package_dir, java_package_, file_->service(i), context, file_list, + options_.annotate_code, annotation_list, "", generator.get(), + &ServiceGenerator::Generate); + } + } + } +} + +std::string FileGenerator::GetKotlinClassname() { + return name_resolver_->GetFileClassName(file_, immutable_api_, true); +} + +void FileGenerator::GenerateKotlinSiblings( + const std::string& package_dir, GeneratorContext* context, + std::vector<std::string>* file_list, + std::vector<std::string>* annotation_list) { + for (int i = 0; i < file_->message_type_count(); i++) { + const Descriptor* descriptor = file_->message_type(i); + MessageGenerator* generator = message_generators_[i].get(); + auto open_file = [context](const std::string& filename) { + return std::unique_ptr<io::ZeroCopyOutputStream>(context->Open(filename)); + }; + std::string filename = package_dir + descriptor->name() + "Kt.kt"; + file_list->push_back(filename); + std::string info_full_path = filename + ".pb.meta"; + GeneratedCodeInfo annotations; + io::AnnotationProtoCollector<GeneratedCodeInfo> annotation_collector( + &annotations); + auto output = open_file(filename); + io::Printer printer( + output.get(), '$', + options_.annotate_code ? &annotation_collector : nullptr); + + printer.Print( + "//Generated by the protocol buffer compiler. DO NOT EDIT!\n" + "// source: $filename$\n" + "\n", + "filename", descriptor->file()->name()); + if (!java_package_.empty()) { + printer.Print( + "package $package$;\n" + "\n", + "package", java_package_); + } + + generator->GenerateKotlinMembers(&printer); + generator->GenerateTopLevelKotlinMembers(&printer); + + if (options_.annotate_code) { + auto info_output = open_file(info_full_path); + annotations.SerializeToZeroCopyStream(info_output.get()); + annotation_list->push_back(info_full_path); + } + } +} + +bool FileGenerator::ShouldIncludeDependency(const FileDescriptor* descriptor, + bool immutable_api) { + return true; +} + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/java/java_file.h b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_file.h new file mode 100644 index 00000000..80fb6e5d --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_file.h @@ -0,0 +1,125 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_FILE_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVA_FILE_H__ + +#include <memory> +#include <string> +#include <vector> +#include <stubs/common.h> +#include <compiler/java/java_options.h> + +namespace google { +namespace protobuf { +class FileDescriptor; // descriptor.h +namespace io { +class Printer; // printer.h +} +namespace compiler { +class GeneratorContext; // code_generator.h +namespace java { +class Context; // context.h +class MessageGenerator; // message.h +class GeneratorFactory; // generator_factory.h +class ExtensionGenerator; // extension.h +class ClassNameResolver; // name_resolver.h +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +class FileGenerator { + public: + FileGenerator(const FileDescriptor* file, const Options& options, + bool immutable_api = true); + ~FileGenerator(); + + // Checks for problems that would otherwise lead to cryptic compile errors. + // Returns true if there are no problems, or writes an error description to + // the given string and returns false otherwise. + bool Validate(std::string* error); + + void Generate(io::Printer* printer); + + std::string GetKotlinClassname(); + void GenerateKotlinSiblings(const std::string& package_dir, + GeneratorContext* generator_context, + std::vector<std::string>* file_list, + std::vector<std::string>* annotation_list); + + // If we aren't putting everything into one file, this will write all the + // files other than the outer file (i.e. one for each message, enum, and + // service type). + void GenerateSiblings(const std::string& package_dir, + GeneratorContext* generator_context, + std::vector<std::string>* file_list, + std::vector<std::string>* annotation_list); + + const std::string& java_package() { return java_package_; } + const std::string& classname() { return classname_; } + + private: + void GenerateDescriptorInitializationCodeForImmutable(io::Printer* printer); + void GenerateDescriptorInitializationCodeForMutable(io::Printer* printer); + + bool ShouldIncludeDependency(const FileDescriptor* descriptor, + bool immutable_api_); + + const FileDescriptor* file_; + std::string java_package_; + std::string classname_; + + std::vector<std::unique_ptr<MessageGenerator>> message_generators_; + std::vector<std::unique_ptr<ExtensionGenerator>> extension_generators_; + std::unique_ptr<GeneratorFactory> generator_factory_; + std::unique_ptr<Context> context_; + ClassNameResolver* name_resolver_; + const Options options_; + bool immutable_api_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileGenerator); +}; + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_FILE_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/java/java_generator.cc b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_generator.cc new file mode 100644 index 00000000..611a4d9c --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_generator.cc @@ -0,0 +1,211 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <compiler/java/java_generator.h> + + +#include <memory> + +#include <compiler/java/java_file.h> +#include <compiler/java/java_generator_factory.h> +#include <compiler/java/java_helpers.h> +#include <compiler/java/java_name_resolver.h> +#include <compiler/java/java_options.h> +#include <compiler/java/java_shared_code_generator.h> +#include <descriptor.pb.h> +#include <io/printer.h> +#include <io/zero_copy_stream.h> + +#include <stubs/strutil.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + + +JavaGenerator::JavaGenerator() {} +JavaGenerator::~JavaGenerator() {} + +uint64_t JavaGenerator::GetSupportedFeatures() const { + return CodeGenerator::Feature::FEATURE_PROTO3_OPTIONAL; +} + +bool JavaGenerator::Generate(const FileDescriptor* file, + const std::string& parameter, + GeneratorContext* context, + std::string* error) const { + // ----------------------------------------------------------------- + // parse generator options + + std::vector<std::pair<std::string, std::string> > options; + ParseGeneratorParameter(parameter, &options); + Options file_options; + + for (int i = 0; i < options.size(); i++) { + if (options[i].first == "output_list_file") { + file_options.output_list_file = options[i].second; + } else if (options[i].first == "immutable") { + file_options.generate_immutable_code = true; + } else if (options[i].first == "mutable") { + file_options.generate_mutable_code = true; + } else if (options[i].first == "shared") { + file_options.generate_shared_code = true; + } else if (options[i].first == "lite") { + // Note: Java Lite does not guarantee API/ABI stability. We may choose to + // break existing API in order to boost performance / reduce code size. + file_options.enforce_lite = true; + } else if (options[i].first == "annotate_code") { + file_options.annotate_code = true; + } else if (options[i].first == "annotation_list_file") { + file_options.annotation_list_file = options[i].second; + } else { + *error = "Unknown generator option: " + options[i].first; + return false; + } + } + + if (file_options.enforce_lite && file_options.generate_mutable_code) { + *error = "lite runtime generator option cannot be used with mutable API."; + return false; + } + + // By default we generate immutable code and shared code for immutable API. + if (!file_options.generate_immutable_code && + !file_options.generate_mutable_code && + !file_options.generate_shared_code) { + file_options.generate_immutable_code = true; + file_options.generate_shared_code = true; + } + + // ----------------------------------------------------------------- + + + std::vector<std::string> all_files; + std::vector<std::string> all_annotations; + + + std::vector<FileGenerator*> file_generators; + if (file_options.generate_immutable_code) { + file_generators.push_back(new FileGenerator(file, file_options, + /* immutable = */ true)); + } + if (file_options.generate_mutable_code) { + file_generators.push_back(new FileGenerator(file, file_options, + /* mutable = */ false)); + } + + for (int i = 0; i < file_generators.size(); ++i) { + if (!file_generators[i]->Validate(error)) { + for (int j = 0; j < file_generators.size(); ++j) { + delete file_generators[j]; + } + return false; + } + } + + for (int i = 0; i < file_generators.size(); ++i) { + FileGenerator* file_generator = file_generators[i]; + + std::string package_dir = JavaPackageToDir(file_generator->java_package()); + + std::string java_filename = package_dir; + java_filename += file_generator->classname(); + java_filename += ".java"; + all_files.push_back(java_filename); + std::string info_full_path = java_filename + ".pb.meta"; + if (file_options.annotate_code) { + all_annotations.push_back(info_full_path); + } + + // Generate main java file. + std::unique_ptr<io::ZeroCopyOutputStream> output( + context->Open(java_filename)); + GeneratedCodeInfo annotations; + io::AnnotationProtoCollector<GeneratedCodeInfo> annotation_collector( + &annotations); + io::Printer printer( + output.get(), '$', + file_options.annotate_code ? &annotation_collector : NULL); + + file_generator->Generate(&printer); + + // Generate sibling files. + file_generator->GenerateSiblings(package_dir, context, &all_files, + &all_annotations); + + if (file_options.annotate_code) { + std::unique_ptr<io::ZeroCopyOutputStream> info_output( + context->Open(info_full_path)); + annotations.SerializeToZeroCopyStream(info_output.get()); + } + } + + + for (int i = 0; i < file_generators.size(); ++i) { + delete file_generators[i]; + } + file_generators.clear(); + + // Generate output list if requested. + if (!file_options.output_list_file.empty()) { + // Generate output list. This is just a simple text file placed in a + // deterministic location which lists the .java files being generated. + std::unique_ptr<io::ZeroCopyOutputStream> srclist_raw_output( + context->Open(file_options.output_list_file)); + io::Printer srclist_printer(srclist_raw_output.get(), '$'); + for (int i = 0; i < all_files.size(); i++) { + srclist_printer.Print("$filename$\n", "filename", all_files[i]); + } + } + + if (!file_options.annotation_list_file.empty()) { + // Generate output list. This is just a simple text file placed in a + // deterministic location which lists the .java files being generated. + std::unique_ptr<io::ZeroCopyOutputStream> annotation_list_raw_output( + context->Open(file_options.annotation_list_file)); + io::Printer annotation_list_printer(annotation_list_raw_output.get(), '$'); + for (int i = 0; i < all_annotations.size(); i++) { + annotation_list_printer.Print("$filename$\n", "filename", + all_annotations[i]); + } + } + + return true; +} + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/java/java_generator.h b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_generator.h new file mode 100644 index 00000000..7910cc03 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_generator.h @@ -0,0 +1,76 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// Generates Java code for a given .proto file. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_GENERATOR_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVA_GENERATOR_H__ + +#include <string> +#include <compiler/code_generator.h> + +#include <port_def.inc> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +// CodeGenerator implementation which generates Java code. If you create your +// own protocol compiler binary and you want it to support Java output, you +// can do so by registering an instance of this CodeGenerator with the +// CommandLineInterface in your main() function. +class PROTOC_EXPORT JavaGenerator : public CodeGenerator { + public: + JavaGenerator(); + ~JavaGenerator(); + + // implements CodeGenerator ---------------------------------------- + bool Generate(const FileDescriptor* file, const std::string& parameter, + GeneratorContext* context, std::string* error) const override; + + uint64_t GetSupportedFeatures() const override; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(JavaGenerator); +}; + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google + +#include <port_undef.inc> + +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_GENERATOR_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/java/java_generator_factory.cc b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_generator_factory.cc new file mode 100644 index 00000000..50fa50b0 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_generator_factory.cc @@ -0,0 +1,86 @@ +// 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. + +// Author: liujisi@google.com (Pherl Liu) + +#include <compiler/java/java_generator_factory.h> + +#include <compiler/java/java_context.h> +#include <compiler/java/java_enum_field.h> +#include <compiler/java/java_extension.h> +#include <compiler/java/java_extension_lite.h> +#include <compiler/java/java_field.h> +#include <compiler/java/java_helpers.h> +#include <compiler/java/java_message.h> +#include <compiler/java/java_message_lite.h> +#include <compiler/java/java_service.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +GeneratorFactory::GeneratorFactory() {} +GeneratorFactory::~GeneratorFactory() {} + +// =================================================================== + +ImmutableGeneratorFactory::ImmutableGeneratorFactory(Context* context) + : context_(context) {} +ImmutableGeneratorFactory::~ImmutableGeneratorFactory() {} + +MessageGenerator* ImmutableGeneratorFactory::NewMessageGenerator( + const Descriptor* descriptor) const { + if (HasDescriptorMethods(descriptor, context_->EnforceLite())) { + return new ImmutableMessageGenerator(descriptor, context_); + } else { + return new ImmutableMessageLiteGenerator(descriptor, context_); + } +} + +ExtensionGenerator* ImmutableGeneratorFactory::NewExtensionGenerator( + const FieldDescriptor* descriptor) const { + if (HasDescriptorMethods(descriptor->file(), context_->EnforceLite())) { + return new ImmutableExtensionGenerator(descriptor, context_); + } else { + return new ImmutableExtensionLiteGenerator(descriptor, context_); + } +} + +ServiceGenerator* ImmutableGeneratorFactory::NewServiceGenerator( + const ServiceDescriptor* descriptor) const { + return new ImmutableServiceGenerator(descriptor, context_); +} + + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/java/java_generator_factory.h b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_generator_factory.h new file mode 100644 index 00000000..a0a827a5 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_generator_factory.h @@ -0,0 +1,103 @@ +// 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. + +// Author: liujisi@google.com (Pherl Liu) + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_GENERATOR_FACTORY_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVA_GENERATOR_FACTORY_H__ + +#include <stubs/common.h> + +namespace google { +namespace protobuf { +class FieldDescriptor; // descriptor.h +class Descriptor; // descriptor.h +class ServiceDescriptor; // descriptor.h +namespace compiler { +namespace java { +class MessageGenerator; // message.h +class ExtensionGenerator; // extension.h +class ServiceGenerator; // service.h +class Context; // context.h +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +class GeneratorFactory { + public: + GeneratorFactory(); + virtual ~GeneratorFactory(); + + virtual MessageGenerator* NewMessageGenerator( + const Descriptor* descriptor) const = 0; + + virtual ExtensionGenerator* NewExtensionGenerator( + const FieldDescriptor* descriptor) const = 0; + + virtual ServiceGenerator* NewServiceGenerator( + const ServiceDescriptor* descriptor) const = 0; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(GeneratorFactory); +}; + +// Factory that creates generators for immutable-default messages. +class ImmutableGeneratorFactory : public GeneratorFactory { + public: + ImmutableGeneratorFactory(Context* context); + virtual ~ImmutableGeneratorFactory(); + + MessageGenerator* NewMessageGenerator( + const Descriptor* descriptor) const override; + + ExtensionGenerator* NewExtensionGenerator( + const FieldDescriptor* descriptor) const override; + + ServiceGenerator* NewServiceGenerator( + const ServiceDescriptor* descriptor) const override; + + private: + Context* context_; + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableGeneratorFactory); +}; + + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_GENERATOR_FACTORY_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/java/java_helpers.cc b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_helpers.cc new file mode 100644 index 00000000..0ce86ba9 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_helpers.cc @@ -0,0 +1,1100 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <compiler/java/java_helpers.h> + +#include <algorithm> +#include <cstdint> +#include <limits> +#include <unordered_set> +#include <vector> + +#include <stubs/stringprintf.h> +#include <compiler/java/java_name_resolver.h> +#include <compiler/java/java_names.h> +#include <descriptor.pb.h> +#include <wire_format.h> +#include <stubs/strutil.h> +#include <stubs/substitute.h> +#include <stubs/hash.h> // for hash<T *> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +using internal::WireFormat; +using internal::WireFormatLite; + +const char kThickSeparator[] = + "// ===================================================================\n"; +const char kThinSeparator[] = + "// -------------------------------------------------------------------\n"; + +namespace { + +const char* kDefaultPackage = ""; + +// Names that should be avoided as field names. +// Using them will cause the compiler to generate accessors whose names are +// colliding with methods defined in base classes. +const char* kForbiddenWordList[] = { + // message base class: + "cached_size", + "serialized_size", + // java.lang.Object: + "class", +}; + +const std::unordered_set<std::string>* kReservedNames = + new std::unordered_set<std::string>({ + "abstract", "assert", "boolean", "break", "byte", + "case", "catch", "char", "class", "const", + "continue", "default", "do", "double", "else", + "enum", "extends", "final", "finally", "float", + "for", "goto", "if", "implements", "import", + "instanceof", "int", "interface", "long", "native", + "new", "package", "private", "protected", "public", + "return", "short", "static", "strictfp", "super", + "switch", "synchronized", "this", "throw", "throws", + "transient", "try", "void", "volatile", "while", + }); + +bool IsForbidden(const std::string& field_name) { + for (int i = 0; i < GOOGLE_ARRAYSIZE(kForbiddenWordList); ++i) { + if (field_name == kForbiddenWordList[i]) { + return true; + } + } + return false; +} + +std::string FieldName(const FieldDescriptor* field) { + std::string field_name; + // Groups are hacky: The name of the field is just the lower-cased name + // of the group type. In Java, though, we would like to retain the original + // capitalization of the type name. + if (GetType(field) == FieldDescriptor::TYPE_GROUP) { + field_name = field->message_type()->name(); + } else { + field_name = field->name(); + } + if (IsForbidden(field_name)) { + // Append a trailing "#" to indicate that the name should be decorated to + // avoid collision with other names. + field_name += "#"; + } + return field_name; +} + + +} // namespace + +void PrintGeneratedAnnotation(io::Printer* printer, char delimiter, + const std::string& annotation_file) { + 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 std::map<std::string, std::string>& variables, + const char* var_name, + const char* terminating_string, bool enforce_lite) { + std::string enum_verifier_string = + enforce_lite ? StrCat(var_name, ".internalGetVerifier()") + : 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, + StrCat(enum_verifier_string, terminating_string).c_str()); +} + +std::string UnderscoresToCamelCase(const std::string& input, + bool cap_next_letter) { + GOOGLE_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(const std::string& 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(ToUpperCh(i)); + capitalize_next = false; + } else { + result.push_back(i); + } + } + + // Lower-case the first letter. + if (lower_first && !result.empty()) { + result[0] = ToLowerCh(result[0]); + } + + return result; +} + +char ToUpperCh(char ch) { + return (ch >= 'a' && ch <= 'z') ? (ch - 'a' + 'A') : ch; +} + +char ToLowerCh(char ch) { + return (ch >= 'A' && ch <= 'Z') ? (ch - 'A' + 'a') : ch; +} + +std::string UnderscoresToCamelCase(const FieldDescriptor* field) { + return UnderscoresToCamelCase(FieldName(field), false); +} + +std::string UnderscoresToCapitalizedCamelCase(const FieldDescriptor* field) { + return UnderscoresToCamelCase(FieldName(field), true); +} + +std::string CapitalizedFieldName(const FieldDescriptor* field) { + return UnderscoresToCapitalizedCamelCase(field); +} + +std::string UnderscoresToCamelCase(const MethodDescriptor* method) { + return UnderscoresToCamelCase(method->name(), false); +} + +std::string UnderscoresToCamelCaseCheckReserved(const FieldDescriptor* field) { + std::string name = UnderscoresToCamelCase(field); + if (kReservedNames->find(name) != kReservedNames->end()) { + return name + "_"; + } + return name; +} + +bool IsForbiddenKotlin(const std::string& field_name) { + // Names that should be avoided as field names in Kotlin. + // All Kotlin hard keywords are in this list. + const std::unordered_set<std::string>* kKotlinForbiddenNames = + new std::unordered_set<std::string>({ + "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->find(field_name) != + kKotlinForbiddenNames->end(); +} + +std::string UniqueFileScopeIdentifier(const Descriptor* descriptor) { + return "static_" + StringReplace(descriptor->full_name(), ".", "_", true); +} + +std::string CamelCaseFieldName(const FieldDescriptor* field) { + std::string fieldName = UnderscoresToCamelCase(field); + if ('0' <= fieldName[0] && fieldName[0] <= '9') { + return '_' + fieldName; + } + return fieldName; +} + +std::string FileClassName(const FileDescriptor* file, bool immutable) { + ClassNameResolver name_resolver; + return name_resolver.GetFileClassName(file, immutable); +} + +std::string FileJavaPackage(const FileDescriptor* file, bool immutable) { + std::string result; + + if (file->options().has_java_package()) { + result = file->options().java_package(); + } else { + result = kDefaultPackage; + if (!file->package().empty()) { + if (!result.empty()) result += '.'; + result += file->package(); + } + } + + return result; +} + +std::string FileJavaPackage(const FileDescriptor* file) { + return FileJavaPackage(file, true /* immutable */); +} + +std::string JavaPackageToDir(std::string package_name) { + std::string package_dir = StringReplace(package_name, ".", "/", true); + if (!package_dir.empty()) package_dir += "/"; + return package_dir; +} + +std::string ClassName(const Descriptor* descriptor) { + ClassNameResolver name_resolver; + return name_resolver.GetClassName(descriptor, true); +} + +std::string ClassName(const EnumDescriptor* descriptor) { + ClassNameResolver name_resolver; + return name_resolver.GetClassName(descriptor, true); +} + +std::string ClassName(const ServiceDescriptor* descriptor) { + ClassNameResolver name_resolver; + return name_resolver.GetClassName(descriptor, true); +} + +std::string ClassName(const FileDescriptor* descriptor) { + ClassNameResolver name_resolver; + return name_resolver.GetClassName(descriptor, true); +} + + +std::string ExtraMessageInterfaces(const Descriptor* descriptor) { + std::string interfaces = "// @@protoc_insertion_point(message_implements:" + + descriptor->full_name() + ")"; + return interfaces; +} + + +std::string ExtraBuilderInterfaces(const Descriptor* descriptor) { + std::string interfaces = "// @@protoc_insertion_point(builder_implements:" + + descriptor->full_name() + ")"; + return interfaces; +} + +std::string ExtraMessageOrBuilderInterfaces(const Descriptor* descriptor) { + std::string interfaces = "// @@protoc_insertion_point(interface_extends:" + + descriptor->full_name() + ")"; + return interfaces; +} + +std::string FieldConstantName(const FieldDescriptor* field) { + std::string name = field->name() + "_FIELD_NUMBER"; + ToUpper(&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. + } + + GOOGLE_LOG(FATAL) << "Can't get here."; + return JAVATYPE_INT; +} + +const char* 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 NULL; + case JAVATYPE_MESSAGE: + return NULL; + + // No default because we want the compiler to complain if any new + // JavaTypes are added. + } + + GOOGLE_LOG(FATAL) << "Can't get here."; + return NULL; +} + +const char* PrimitiveTypeName(const FieldDescriptor* descriptor) { + return PrimitiveTypeName(GetJavaType(descriptor)); +} + +const char* 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 NULL; + case JAVATYPE_MESSAGE: + return NULL; + + // No default because we want the compiler to complain if any new + // JavaTypes are added. + } + + GOOGLE_LOG(FATAL) << "Can't get here."; + return NULL; +} + +const char* BoxedPrimitiveTypeName(const FieldDescriptor* descriptor) { + return BoxedPrimitiveTypeName(GetJavaType(descriptor)); +} + +const char* 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 NULL; + case JAVATYPE_MESSAGE: + return NULL; + + // No default because we want the compiler to complain if any new + // JavaTypes are added. + } + + GOOGLE_LOG(FATAL) << "Can't get here."; + return NULL; +} + +std::string GetOneofStoredType(const FieldDescriptor* field) { + const JavaType javaType = GetJavaType(field); + switch (javaType) { + case JAVATYPE_ENUM: + return "java.lang.Integer"; + case JAVATYPE_MESSAGE: + return ClassName(field->message_type()); + default: + return BoxedPrimitiveTypeName(javaType); + } +} + +const char* 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. + } + + GOOGLE_LOG(FATAL) << "Can't get here."; + return NULL; +} + +bool AllAscii(const std::string& 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) { + // 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 StrCat(field->default_value_int32()); + case FieldDescriptor::CPPTYPE_UINT32: + // Need to print as a signed int since Java has no unsigned. + return StrCat(static_cast<int32_t>(field->default_value_uint32())); + case FieldDescriptor::CPPTYPE_INT64: + return StrCat(field->default_value_int64()) + "L"; + case FieldDescriptor::CPPTYPE_UINT64: + return 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 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 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 strings::Substitute( + "com.google.protobuf.Internal.bytesDefaultValue(\"$0\")", + 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 "\"" + CEscape(field->default_value_string()) + "\""; + } else { + // See comments in Internal.java for gory details. + return strings::Substitute( + "com.google.protobuf.Internal.stringDefaultValue(\"$0\")", + CEscape(field->default_value_string())); + } + } + + case FieldDescriptor::CPPTYPE_ENUM: + return name_resolver->GetClassName(field->enum_type(), immutable) + "." + + field->default_value_enum()->name(); + + case FieldDescriptor::CPPTYPE_MESSAGE: + return name_resolver->GetClassName(field->message_type(), immutable) + + ".getDefaultInstance()"; + + // No default because we want the compiler to complain if any new + // types are added. + } + + GOOGLE_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. + } + + GOOGLE_LOG(FATAL) << "Can't get here."; + return false; +} + +bool IsByteStringWithCustomDefaultValue(const FieldDescriptor* field) { + return GetJavaType(field) == JAVATYPE_BYTES && + field->default_value_string() != ""; +} + +const char* 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) { + std::string varName = "bitField"; + varName += StrCat(index); + varName += "_"; + return varName; +} + +std::string GetBitFieldNameForBit(int bitIndex) { + return GetBitFieldName(bitIndex / 32); +} + +namespace { + +std::string GenerateGetBitInternal(const std::string& prefix, int bitIndex) { + std::string varName = prefix + GetBitFieldNameForBit(bitIndex); + int bitInVarIndex = bitIndex % 32; + + std::string mask = bit_masks[bitInVarIndex]; + std::string result = "((" + varName + " & " + mask + ") != 0)"; + return result; +} + +std::string GenerateSetBitInternal(const std::string& prefix, int bitIndex) { + std::string varName = prefix + GetBitFieldNameForBit(bitIndex); + int bitInVarIndex = bitIndex % 32; + + std::string mask = bit_masks[bitInVarIndex]; + std::string result = varName + " |= " + mask; + return result; +} + +} // 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; + + std::string mask = bit_masks[bitInVarIndex]; + std::string result = varName + " = (" + varName + " & ~" + mask + ")"; + return result; +} + +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. + } + + GOOGLE_LOG(FATAL) << "Can't get here."; + return false; +} + +const char* GetCapitalizedType(const FieldDescriptor* field, bool immutable) { + 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. + } + + GOOGLE_LOG(FATAL) << "Can't get here."; + return NULL; +} + +// 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. + } + GOOGLE_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, + std::unordered_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) { + std::unordered_set<const Descriptor*> already_seen; + return HasRequiredFields(type, &already_seen); +} + +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)); +} + +int GetExperimentalJavaFieldTypeForSingular(const FieldDescriptor* field) { + // j/c/g/protobuf/FieldType.java lists field types in a slightly different + // order from FieldDescriptor::Type so we can't do a simple cast. + // + // TODO(xiaofeng): Make j/c/g/protobuf/FieldType.java follow the same order. + int result = field->type(); + if (result == FieldDescriptor::TYPE_GROUP) { + return 17; + } else if (result < FieldDescriptor::TYPE_GROUP) { + return result - 1; + } else { + return result - 2; + } +} + +int GetExperimentalJavaFieldTypeForRepeated(const FieldDescriptor* field) { + if (field->type() == FieldDescriptor::TYPE_GROUP) { + return 49; + } else { + return GetExperimentalJavaFieldTypeForSingular(field) + 18; + } +} + +int GetExperimentalJavaFieldTypeForPacked(const FieldDescriptor* field) { + int result = field->type(); + if (result < FieldDescriptor::TYPE_STRING) { + return result + 34; + } else if (result > FieldDescriptor::TYPE_BYTES) { + return result + 30; + } else { + GOOGLE_LOG(FATAL) << field->full_name() << " can't be packed."; + return 0; + } +} + +int GetExperimentalJavaFieldType(const FieldDescriptor* field) { + static const int kMapFieldType = 50; + static const int kOneofFieldTypeOffset = 51; + static const int kRequiredBit = 0x100; + static const int kUtf8CheckBit = 0x200; + static const int kCheckInitialized = 0x400; + static const int kMapWithProto2EnumValue = 0x800; + static const int kHasHasBit = 0x1000; + int extra_bits = field->is_required() ? kRequiredBit : 0; + if (field->type() == FieldDescriptor::TYPE_STRING && CheckUtf8(field)) { + extra_bits |= kUtf8CheckBit; + } + if (field->is_required() || (GetJavaType(field) == JAVATYPE_MESSAGE && + HasRequiredFields(field->message_type()))) { + extra_bits |= kCheckInitialized; + } + if (HasHasbit(field)) { + extra_bits |= kHasHasBit; + } + + if (field->is_map()) { + if (!SupportUnknownEnumValue(field)) { + const FieldDescriptor* value = + field->message_type()->FindFieldByName("value"); + if (GetJavaType(value) == JAVATYPE_ENUM) { + extra_bits |= kMapWithProto2EnumValue; + } + } + return kMapFieldType | extra_bits; + } else if (field->is_packed()) { + return GetExperimentalJavaFieldTypeForPacked(field); + } else if (field->is_repeated()) { + return GetExperimentalJavaFieldTypeForRepeated(field) | extra_bits; + } else if (IsRealOneof(field)) { + return (GetExperimentalJavaFieldTypeForSingular(field) + + kOneofFieldTypeOffset) | + extra_bits; + } else { + return GetExperimentalJavaFieldTypeForSingular(field) | extra_bits; + } +} + +// Escape a UTF-16 character to be embedded in a Java string. +void EscapeUtf16ToString(uint16_t code, std::string* output) { + if (code == '\t') { + 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(StringPrintf("\\u%04x", code)); + } +} + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/java/java_helpers.h b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_helpers.h new file mode 100644 index 00000000..428aa254 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_helpers.h @@ -0,0 +1,459 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_HELPERS_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVA_HELPERS_H__ + +#include <cstdint> +#include <string> + +#include <compiler/java/java_context.h> +#include <descriptor.pb.h> +#include <io/printer.h> +#include <descriptor.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +// Commonly-used separator comments. Thick is a line of '=', thin is a line +// of '-'. +extern const char kThickSeparator[]; +extern const char kThinSeparator[]; + +bool IsForbiddenKotlin(const std::string& field_name); + +// If annotation_file is non-empty, prints a javax.annotation.Generated +// annotation to the given Printer. annotation_file will be referenced in the +// annotation's comments field. delimiter should be the Printer's delimiter +// character. annotation_file will be included verbatim into a Java literal +// string, so it should not contain quotes or invalid Java escape sequences; +// however, these are unlikely to appear in practice, as the value of +// annotation_file should be generated from the filename of the source file +// being annotated (which in turn must be a Java identifier plus ".java"). +void PrintGeneratedAnnotation(io::Printer* printer, char delimiter = '$', + const std::string& annotation_file = ""); + +// If a GeneratedMessageLite contains non-lite enums, then its verifier +// must be instantiated inline, rather than retrieved from the enum class. +void PrintEnumVerifierLogic(io::Printer* printer, + const FieldDescriptor* descriptor, + const std::map<std::string, std::string>& variables, + const char* var_name, + const char* terminating_string, bool enforce_lite); + +// Converts a name to camel-case. If cap_first_letter is true, capitalize the +// first letter. +std::string ToCamelCase(const std::string& input, bool lower_first); + +char ToUpperCh(char ch); +char ToLowerCh(char ch); + +// Converts a name to camel-case. If cap_first_letter is true, capitalize the +// first letter. +std::string UnderscoresToCamelCase(const std::string& name, + bool cap_first_letter); +// Converts the field's name to camel-case, e.g. "foo_bar_baz" becomes +// "fooBarBaz" or "FooBarBaz", respectively. +std::string UnderscoresToCamelCase(const FieldDescriptor* field); +std::string UnderscoresToCapitalizedCamelCase(const FieldDescriptor* field); + +// Similar, but for method names. (Typically, this merely has the effect +// of lower-casing the first letter of the name.) +std::string UnderscoresToCamelCase(const MethodDescriptor* method); + +// Same as UnderscoresToCamelCase, but checks for reserved keywords +std::string UnderscoresToCamelCaseCheckReserved(const FieldDescriptor* field); + +// Similar to UnderscoresToCamelCase, but guarantees that the result is a +// complete Java identifier by adding a _ if needed. +std::string CamelCaseFieldName(const FieldDescriptor* field); + +// Get an identifier that uniquely identifies this type within the file. +// This is used to declare static variables related to this type at the +// outermost file scope. +std::string UniqueFileScopeIdentifier(const Descriptor* descriptor); + +// Gets the unqualified class name for the file. For each .proto file, there +// will be one Java class containing all the immutable messages and another +// Java class containing all the mutable messages. +// TODO(xiaofeng): remove the default value after updating client code. +std::string FileClassName(const FileDescriptor* file, bool immutable = true); + +// Returns the file's Java package name. +std::string FileJavaPackage(const FileDescriptor* file, bool immutable); + +// Returns output directory for the given package name. +std::string JavaPackageToDir(std::string package_name); + +// Comma-separate list of option-specified interfaces implemented by the +// Message, to follow the "implements" declaration of the Message definition. +std::string ExtraMessageInterfaces(const Descriptor* descriptor); +// Comma-separate list of option-specified interfaces implemented by the +// MutableMessage, to follow the "implements" declaration of the MutableMessage +// definition. +std::string ExtraMutableMessageInterfaces(const Descriptor* descriptor); +// Comma-separate list of option-specified interfaces implemented by the +// Builder, to follow the "implements" declaration of the Builder definition. +std::string ExtraBuilderInterfaces(const Descriptor* descriptor); +// Comma-separate list of option-specified interfaces extended by the +// MessageOrBuilder, to follow the "extends" declaration of the +// MessageOrBuilder definition. +std::string ExtraMessageOrBuilderInterfaces(const Descriptor* descriptor); + +// Get the unqualified Java class name for mutable messages. i.e. without +// package or outer classnames. +inline std::string ShortMutableJavaClassName(const Descriptor* descriptor) { + return descriptor->name(); +} + +// Whether the given descriptor is for one of the core descriptor protos. We +// cannot currently use the new runtime with core protos since there is a +// bootstrapping problem with obtaining their descriptors. +inline bool IsDescriptorProto(const Descriptor* descriptor) { + return descriptor->file()->name() == "net/proto2/proto/descriptor.proto" || + descriptor->file()->name() == "google/protobuf/descriptor.proto"; +} + +// Returns the stored type string used by the experimental runtime for oneof +// fields. +std::string GetOneofStoredType(const FieldDescriptor* field); + + +// Whether we should generate multiple java files for messages. +inline bool MultipleJavaFiles(const FileDescriptor* descriptor, + bool immutable) { + (void)immutable; + return descriptor->options().java_multiple_files(); +} + + +// Returns true if `descriptor` will be written to its own .java file. +// `immutable` should be set to true if we're generating for the immutable API. +template <typename Descriptor> +bool IsOwnFile(const Descriptor* descriptor, bool immutable) { + return descriptor->containing_type() == NULL && + MultipleJavaFiles(descriptor->file(), immutable); +} + +template <> +inline bool IsOwnFile(const ServiceDescriptor* descriptor, bool immutable) { + return MultipleJavaFiles(descriptor->file(), immutable); +} + +// If `descriptor` describes an object with its own .java file, +// returns the name (relative to that .java file) of the file that stores +// annotation data for that descriptor. `suffix` is usually empty, but may +// (e.g.) be "OrBuilder" for some generated interfaces. +template <typename Descriptor> +std::string AnnotationFileName(const Descriptor* descriptor, + const std::string& suffix) { + return descriptor->name() + suffix + ".java.pb.meta"; +} + +template <typename Descriptor> +void MaybePrintGeneratedAnnotation(Context* context, io::Printer* printer, + Descriptor* descriptor, bool immutable, + const std::string& suffix = "") { + if (IsOwnFile(descriptor, immutable)) { + PrintGeneratedAnnotation(printer, '$', + context->options().annotate_code + ? AnnotationFileName(descriptor, suffix) + : ""); + } +} + +// Get the unqualified name that should be used for a field's field +// number constant. +std::string FieldConstantName(const FieldDescriptor* field); + +// Returns the type of the FieldDescriptor. +// This does nothing interesting for the open source release, but is used for +// hacks that improve compatibility with version 1 protocol buffers at Google. +FieldDescriptor::Type GetType(const FieldDescriptor* field); + +enum JavaType { + JAVATYPE_INT, + JAVATYPE_LONG, + JAVATYPE_FLOAT, + JAVATYPE_DOUBLE, + JAVATYPE_BOOLEAN, + JAVATYPE_STRING, + JAVATYPE_BYTES, + JAVATYPE_ENUM, + JAVATYPE_MESSAGE +}; + +JavaType GetJavaType(const FieldDescriptor* field); + +const char* PrimitiveTypeName(JavaType type); + +// Get the fully-qualified class name for a boxed primitive type, e.g. +// "java.lang.Integer" for JAVATYPE_INT. Returns NULL for enum and message +// types. +const char* BoxedPrimitiveTypeName(JavaType type); + +// Kotlin source does not distinguish between primitives and non-primitives, +// but does use Kotlin-specific qualified types for them. +const char* KotlinTypeName(JavaType type); + +// Get the name of the java enum constant representing this type. E.g., +// "INT32" for FieldDescriptor::TYPE_INT32. The enum constant's full +// name is "com.google.protobuf.WireFormat.FieldType.INT32". +const char* FieldTypeName(const FieldDescriptor::Type field_type); + +class ClassNameResolver; +std::string DefaultValue(const FieldDescriptor* field, bool immutable, + ClassNameResolver* name_resolver); +inline std::string ImmutableDefaultValue(const FieldDescriptor* field, + ClassNameResolver* name_resolver) { + return DefaultValue(field, true, name_resolver); +} +bool IsDefaultValueJavaDefault(const FieldDescriptor* field); +bool IsByteStringWithCustomDefaultValue(const FieldDescriptor* field); + +// Does this message class have descriptor and reflection methods? +inline bool HasDescriptorMethods(const Descriptor* /* descriptor */, + bool enforce_lite) { + return !enforce_lite; +} +inline bool HasDescriptorMethods(const EnumDescriptor* /* descriptor */, + bool enforce_lite) { + return !enforce_lite; +} +inline bool HasDescriptorMethods(const FileDescriptor* /* descriptor */, + bool enforce_lite) { + return !enforce_lite; +} + +// Should we generate generic services for this file? +inline bool HasGenericServices(const FileDescriptor* file, bool enforce_lite) { + return file->service_count() > 0 && + HasDescriptorMethods(file, enforce_lite) && + file->options().java_generic_services(); +} + +// Methods for shared bitfields. + +// Gets the name of the shared bitfield for the given index. +std::string GetBitFieldName(int index); + +// Gets the name of the shared bitfield for the given bit index. +// Effectively, GetBitFieldName(bitIndex / 32) +std::string GetBitFieldNameForBit(int bitIndex); + +// Generates the java code for the expression that returns the boolean value +// of the bit of the shared bitfields for the given bit index. +// Example: "((bitField1_ & 0x04) == 0x04)" +std::string GenerateGetBit(int bitIndex); + +// Generates the java code for the expression that sets the bit of the shared +// bitfields for the given bit index. +// Example: "bitField1_ = (bitField1_ | 0x04)" +std::string GenerateSetBit(int bitIndex); + +// Generates the java code for the expression that clears the bit of the shared +// bitfields for the given bit index. +// Example: "bitField1_ = (bitField1_ & ~0x04)" +std::string GenerateClearBit(int bitIndex); + +// Does the same as GenerateGetBit but operates on the bit field on a local +// variable. This is used by the builder to copy the value in the builder to +// the message. +// Example: "((from_bitField1_ & 0x04) == 0x04)" +std::string GenerateGetBitFromLocal(int bitIndex); + +// Does the same as GenerateSetBit but operates on the bit field on a local +// variable. This is used by the builder to copy the value in the builder to +// the message. +// Example: "to_bitField1_ = (to_bitField1_ | 0x04)" +std::string GenerateSetBitToLocal(int bitIndex); + +// Does the same as GenerateGetBit but operates on the bit field on a local +// variable. This is used by the parsing constructor to record if a repeated +// field is mutable. +// Example: "((mutable_bitField1_ & 0x04) == 0x04)" +std::string GenerateGetBitMutableLocal(int bitIndex); + +// Does the same as GenerateSetBit but operates on the bit field on a local +// variable. This is used by the parsing constructor to record if a repeated +// field is mutable. +// Example: "mutable_bitField1_ = (mutable_bitField1_ | 0x04)" +std::string GenerateSetBitMutableLocal(int bitIndex); + +// Returns whether the JavaType is a reference type. +bool IsReferenceType(JavaType type); + +// Returns the capitalized name for calling relative functions in +// CodedInputStream +const char* GetCapitalizedType(const FieldDescriptor* field, bool immutable); + +// For encodings with fixed sizes, returns that size in bytes. Otherwise +// returns -1. +int FixedSize(FieldDescriptor::Type type); + +// Comparators used to sort fields in MessageGenerator +struct FieldOrderingByNumber { + inline bool operator()(const FieldDescriptor* a, + const FieldDescriptor* b) const { + return a->number() < b->number(); + } +}; + +struct ExtensionRangeOrdering { + bool operator()(const Descriptor::ExtensionRange* a, + const Descriptor::ExtensionRange* b) const { + return a->start < b->start; + } +}; + +// 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); + +// Does this message class have any packed fields? +inline bool HasPackedFields(const Descriptor* descriptor) { + for (int i = 0; i < descriptor->field_count(); i++) { + if (descriptor->field(i)->is_packed()) { + return true; + } + } + return false; +} + +// Check a message type and its sub-message types recursively to see if any of +// them has a required field. Return true if a required field is found. +bool HasRequiredFields(const Descriptor* descriptor); + +inline bool IsProto2(const FileDescriptor* descriptor) { + return descriptor->syntax() == FileDescriptor::SYNTAX_PROTO2; +} + +inline bool IsRealOneof(const FieldDescriptor* descriptor) { + return descriptor->containing_oneof() && + !descriptor->containing_oneof()->is_synthetic(); +} + +inline bool HasHazzer(const FieldDescriptor* descriptor) { + return !descriptor->is_repeated() && + (descriptor->message_type() || descriptor->has_optional_keyword() || + IsProto2(descriptor->file()) || IsRealOneof(descriptor)); +} + +inline bool HasHasbit(const FieldDescriptor* descriptor) { + // Note that currently message fields inside oneofs have hasbits. This is + // surprising, as the oneof case should avoid any need for a hasbit. But if + // you change this method to remove hasbits for oneofs, a few tests fail. + // TODO(b/124347790): remove hasbits for oneofs + return !descriptor->is_repeated() && + (descriptor->has_optional_keyword() || IsProto2(descriptor->file())); +} + +// Whether generate classes expose public PARSER instances. +inline bool ExposePublicParser(const FileDescriptor* descriptor) { + // TODO(liujisi): Mark the PARSER private in 3.1.x releases. + return descriptor->syntax() == FileDescriptor::SYNTAX_PROTO2; +} + +// Whether unknown enum values are kept (i.e., not stored in UnknownFieldSet +// but in the message and can be queried using additional getters that return +// ints. +inline bool SupportUnknownEnumValue(const FileDescriptor* descriptor) { + return descriptor->syntax() == FileDescriptor::SYNTAX_PROTO3; +} + +inline bool SupportUnknownEnumValue(const FieldDescriptor* field) { + return field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3; +} + +// Check whether a message has repeated fields. +bool HasRepeatedFields(const Descriptor* descriptor); + +inline bool IsMapEntry(const Descriptor* descriptor) { + return descriptor->options().map_entry(); +} + +inline bool IsMapField(const FieldDescriptor* descriptor) { + return descriptor->is_map(); +} + +inline bool IsAnyMessage(const Descriptor* descriptor) { + return descriptor->full_name() == "google.protobuf.Any"; +} + +inline bool IsWrappersProtoFile(const FileDescriptor* descriptor) { + return descriptor->name() == "google/protobuf/wrappers.proto"; +} + +inline bool CheckUtf8(const FieldDescriptor* descriptor) { + return descriptor->file()->syntax() == FileDescriptor::SYNTAX_PROTO3 || + descriptor->file()->options().java_string_check_utf8(); +} + +inline std::string GeneratedCodeVersionSuffix() { + return "V3"; +} + +void WriteUInt32ToUtf16CharSequence(uint32_t number, + std::vector<uint16_t>* output); + +inline void WriteIntToUtf16CharSequence(int value, + std::vector<uint16_t>* output) { + WriteUInt32ToUtf16CharSequence(static_cast<uint32_t>(value), output); +} + +// Escape a UTF-16 character so it can be embedded in a Java string literal. +void EscapeUtf16ToString(uint16_t code, std::string* output); + +// Only the lowest two bytes of the return value are used. The lowest byte +// is the integer value of a j/c/g/protobuf/FieldType enum. For the other +// byte: +// bit 0: whether the field is required. +// bit 1: whether the field requires UTF-8 validation. +// bit 2: whether the field needs isInitialized check. +// bit 3: whether the field is a map field with proto2 enum value. +// bits 4-7: unused +int GetExperimentalJavaFieldType(const FieldDescriptor* field); + +// To get the total number of entries need to be built for experimental runtime +// and the first field number that are not in the table part +std::pair<int, int> GetTableDrivenNumberOfEntriesAndLookUpStartFieldNumber( + const FieldDescriptor** fields, int count); +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_HELPERS_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/java/java_kotlin_generator.cc b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_kotlin_generator.cc new file mode 100644 index 00000000..d043ed80 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_kotlin_generator.cc @@ -0,0 +1,162 @@ +// 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 <compiler/java/java_kotlin_generator.h> + +#include <compiler/java/java_file.h> +#include <compiler/java/java_helpers.h> +#include <compiler/java/java_options.h> +#include <compiler/java/java_generator.h> +#include <compiler/code_generator.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +KotlinGenerator::KotlinGenerator() {} +KotlinGenerator::~KotlinGenerator() {} + +uint64_t KotlinGenerator::GetSupportedFeatures() const { + return CodeGenerator::Feature::FEATURE_PROTO3_OPTIONAL; +} + +bool KotlinGenerator::Generate(const FileDescriptor* file, + const std::string& parameter, + GeneratorContext* context, + std::string* error) const { + // ----------------------------------------------------------------- + // parse generator options + + std::vector<std::pair<std::string, std::string> > options; + ParseGeneratorParameter(parameter, &options); + Options file_options; + + for (auto& option : options) { + if (option.first == "output_list_file") { + file_options.output_list_file = option.second; + } else if (option.first == "immutable") { + file_options.generate_immutable_code = true; + } else if (option.first == "mutable") { + *error = "Mutable not supported by Kotlin generator"; + return false; + } else if (option.first == "shared") { + file_options.generate_shared_code = true; + } else if (option.first == "lite") { + file_options.enforce_lite = true; + } else if (option.first == "annotate_code") { + file_options.annotate_code = true; + } else if (option.first == "annotation_list_file") { + file_options.annotation_list_file = option.second; + } else { + *error = "Unknown generator option: " + option.first; + return false; + } + } + + // By default we generate immutable code and shared code for immutable API. + if (!file_options.generate_immutable_code && + !file_options.generate_shared_code) { + file_options.generate_immutable_code = true; + file_options.generate_shared_code = true; + } + + std::vector<std::string> all_files; + std::vector<std::string> all_annotations; + + std::unique_ptr<FileGenerator> file_generator; + if (file_options.generate_immutable_code) { + file_generator.reset( + new FileGenerator(file, file_options, /* immutable_api = */ true)); + } + + if (!file_generator->Validate(error)) { + return false; + } + + auto open_file = [context](const std::string& filename) { + return std::unique_ptr<io::ZeroCopyOutputStream>(context->Open(filename)); + }; + std::string package_dir = JavaPackageToDir(file_generator->java_package()); + std::string kotlin_filename = package_dir; + kotlin_filename += file_generator->GetKotlinClassname(); + kotlin_filename += ".kt"; + all_files.push_back(kotlin_filename); + std::string info_full_path = kotlin_filename + ".pb.meta"; + if (file_options.annotate_code) { + all_annotations.push_back(info_full_path); + } + + // Generate main kotlin file. + auto output = open_file(kotlin_filename); + GeneratedCodeInfo annotations; + io::AnnotationProtoCollector<GeneratedCodeInfo> annotation_collector( + &annotations); + io::Printer printer( + output.get(), '$', + file_options.annotate_code ? &annotation_collector : nullptr); + + file_generator->GenerateKotlinSiblings(package_dir, context, &all_files, + &all_annotations); + + if (file_options.annotate_code) { + auto info_output = open_file(info_full_path); + annotations.SerializeToZeroCopyStream(info_output.get()); + } + + // Generate output list if requested. + if (!file_options.output_list_file.empty()) { + // Generate output list. This is just a simple text file placed in a + // deterministic location which lists the .kt files being generated. + auto srclist_raw_output = open_file(file_options.output_list_file); + io::Printer srclist_printer(srclist_raw_output.get(), '$'); + for (auto& all_file : all_files) { + srclist_printer.Print("$filename$\n", "filename", all_file); + } + } + + if (!file_options.annotation_list_file.empty()) { + // Generate output list. This is just a simple text file placed in a + // deterministic location which lists the .kt files being generated. + auto annotation_list_raw_output = + open_file(file_options.annotation_list_file); + io::Printer annotation_list_printer(annotation_list_raw_output.get(), '$'); + for (auto& all_annotation : all_annotations) { + annotation_list_printer.Print("$filename$\n", "filename", all_annotation); + } + } + + return true; +} + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/java/java_kotlin_generator.h b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_kotlin_generator.h new file mode 100644 index 00000000..87ae2507 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_kotlin_generator.h @@ -0,0 +1,72 @@ +// 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. + +// Generates Kotlin code for a given .proto file. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_KOTLIN_GENERATOR_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVA_KOTLIN_GENERATOR_H__ + +#include <string> + +#include <compiler/code_generator.h> +#include <port_def.inc> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +// CodeGenerator implementation which generates Kotlin code. If you create your +// own protocol compiler binary and you want it to support Kotlin output, you +// can do so by registering an instance of this CodeGenerator with the +// CommandLineInterface in your main() function. +class PROTOC_EXPORT KotlinGenerator : public CodeGenerator { + public: + KotlinGenerator(); + ~KotlinGenerator() override; + + // implements CodeGenerator ---------------------------------------- + bool Generate(const FileDescriptor* file, const std::string& parameter, + GeneratorContext* context, std::string* error) const override; + + uint64_t GetSupportedFeatures() const override; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(KotlinGenerator); +}; + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google + +#include <port_undef.inc> + +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_KOTLIN_GENERATOR_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/java/java_map_field.cc b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_map_field.cc new file mode 100644 index 00000000..602e5954 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_map_field.cc @@ -0,0 +1,876 @@ +// 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 <compiler/java/java_map_field.h> + +#include <compiler/java/java_context.h> +#include <compiler/java/java_doc_comment.h> +#include <compiler/java/java_helpers.h> +#include <compiler/java/java_name_resolver.h> +#include <io/printer.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +namespace { + +const FieldDescriptor* KeyField(const FieldDescriptor* descriptor) { + GOOGLE_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, descriptor->type()); + const Descriptor* message = descriptor->message_type(); + GOOGLE_CHECK(message->options().map_entry()); + return message->FindFieldByName("key"); +} + +const FieldDescriptor* ValueField(const FieldDescriptor* descriptor) { + GOOGLE_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, descriptor->type()); + const Descriptor* message = descriptor->message_type(); + GOOGLE_CHECK(message->options().map_entry()); + return message->FindFieldByName("value"); +} + +std::string TypeName(const FieldDescriptor* field, + ClassNameResolver* name_resolver, bool boxed) { + if (GetJavaType(field) == JAVATYPE_MESSAGE) { + return name_resolver->GetImmutableClassName(field->message_type()); + } else if (GetJavaType(field) == JAVATYPE_ENUM) { + return name_resolver->GetImmutableClassName(field->enum_type()); + } else { + return boxed ? BoxedPrimitiveTypeName(GetJavaType(field)) + : PrimitiveTypeName(GetJavaType(field)); + } +} + +std::string KotlinTypeName(const FieldDescriptor* field, + ClassNameResolver* name_resolver) { + if (GetJavaType(field) == JAVATYPE_MESSAGE) { + return name_resolver->GetImmutableClassName(field->message_type()); + } else if (GetJavaType(field) == JAVATYPE_ENUM) { + return name_resolver->GetImmutableClassName(field->enum_type()); + } else { + return KotlinTypeName(GetJavaType(field)); + } +} + +std::string WireType(const FieldDescriptor* field) { + return "com.google.protobuf.WireFormat.FieldType." + + std::string(FieldTypeName(field->type())); +} + +void SetMessageVariables(const FieldDescriptor* descriptor, int messageBitIndex, + int builderBitIndex, const FieldGeneratorInfo* info, + Context* context, + std::map<std::string, std::string>* variables) { + SetCommonFieldVariables(descriptor, info, variables); + ClassNameResolver* name_resolver = context->GetNameResolver(); + + (*variables)["type"] = + name_resolver->GetImmutableClassName(descriptor->message_type()); + const FieldDescriptor* key = KeyField(descriptor); + const FieldDescriptor* value = ValueField(descriptor); + const JavaType keyJavaType = GetJavaType(key); + const JavaType valueJavaType = GetJavaType(value); + + (*variables)["key_type"] = TypeName(key, name_resolver, false); + std::string boxed_key_type = TypeName(key, name_resolver, true); + (*variables)["boxed_key_type"] = boxed_key_type; + (*variables)["kt_key_type"] = KotlinTypeName(key, name_resolver); + (*variables)["kt_value_type"] = KotlinTypeName(value, name_resolver); + // Used for calling the serialization function. + (*variables)["short_key_type"] = + boxed_key_type.substr(boxed_key_type.rfind('.') + 1); + (*variables)["key_wire_type"] = WireType(key); + (*variables)["key_default_value"] = DefaultValue(key, true, name_resolver); + (*variables)["key_null_check"] = + IsReferenceType(keyJavaType) + ? "if (key == null) { throw new NullPointerException(\"map key\"); }" + : ""; + (*variables)["value_null_check"] = + valueJavaType != JAVATYPE_ENUM && IsReferenceType(valueJavaType) + ? "if (value == null) {\n" + " throw new NullPointerException(\"map value\");\n" + "}\n" + : ""; + if (valueJavaType == JAVATYPE_ENUM) { + // We store enums as Integers internally. + (*variables)["value_type"] = "int"; + (*variables)["boxed_value_type"] = "java.lang.Integer"; + (*variables)["value_wire_type"] = WireType(value); + (*variables)["value_default_value"] = + DefaultValue(value, true, name_resolver) + ".getNumber()"; + + (*variables)["value_enum_type"] = TypeName(value, name_resolver, false); + + if (SupportUnknownEnumValue(descriptor->file())) { + // Map unknown values to a special UNRECOGNIZED value if supported. + (*variables)["unrecognized_value"] = + (*variables)["value_enum_type"] + ".UNRECOGNIZED"; + } else { + // Map unknown values to the default value if we don't have UNRECOGNIZED. + (*variables)["unrecognized_value"] = + DefaultValue(value, true, name_resolver); + } + } else { + (*variables)["value_type"] = TypeName(value, name_resolver, false); + (*variables)["boxed_value_type"] = TypeName(value, name_resolver, true); + (*variables)["value_wire_type"] = WireType(value); + (*variables)["value_default_value"] = + DefaultValue(value, true, name_resolver); + } + (*variables)["type_parameters"] = + (*variables)["boxed_key_type"] + ", " + (*variables)["boxed_value_type"]; + // TODO(birdo): Add @deprecated javadoc when generating javadoc is supported + // by the proto compiler + (*variables)["deprecation"] = + descriptor->options().deprecated() ? "@java.lang.Deprecated " : ""; + (*variables)["kt_deprecation"] = + descriptor->options().deprecated() + ? "@kotlin.Deprecated(message = \"Field " + (*variables)["name"] + + " is deprecated\") " + : ""; + (*variables)["on_changed"] = "onChanged();"; + + // For repeated fields, one bit is used for whether the array is immutable + // in the parsing constructor. + (*variables)["get_mutable_bit_parser"] = + GenerateGetBitMutableLocal(builderBitIndex); + (*variables)["set_mutable_bit_parser"] = + GenerateSetBitMutableLocal(builderBitIndex); + + (*variables)["default_entry"] = + (*variables)["capitalized_name"] + "DefaultEntryHolder.defaultEntry"; + (*variables)["map_field_parameter"] = (*variables)["default_entry"]; + (*variables)["descriptor"] = + name_resolver->GetImmutableClassName(descriptor->file()) + ".internal_" + + UniqueFileScopeIdentifier(descriptor->message_type()) + "_descriptor, "; + (*variables)["ver"] = GeneratedCodeVersionSuffix(); +} + +} // namespace + +ImmutableMapFieldGenerator::ImmutableMapFieldGenerator( + const FieldDescriptor* descriptor, int messageBitIndex, int builderBitIndex, + Context* context) + : descriptor_(descriptor), name_resolver_(context->GetNameResolver()) { + SetMessageVariables(descriptor, messageBitIndex, builderBitIndex, + context->GetFieldGeneratorInfo(descriptor), context, + &variables_); +} + +ImmutableMapFieldGenerator::~ImmutableMapFieldGenerator() {} + +int ImmutableMapFieldGenerator::GetNumBitsForMessage() const { return 0; } + +int ImmutableMapFieldGenerator::GetNumBitsForBuilder() const { return 1; } + +void ImmutableMapFieldGenerator::GenerateInterfaceMembers( + io::Printer* printer) const { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$int ${$get$capitalized_name$Count$}$();\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$boolean ${$contains$capitalized_name$$}$(\n" + " $key_type$ key);\n"); + printer->Annotate("{", "}", descriptor_); + if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) { + printer->Print(variables_, + "/**\n" + " * Use {@link #get$capitalized_name$Map()} instead.\n" + " */\n" + "@java.lang.Deprecated\n" + "java.util.Map<$boxed_key_type$, $value_enum_type$>\n" + "${$get$capitalized_name$$}$();\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$java.util.Map<$boxed_key_type$, $value_enum_type$>\n" + "${$get$capitalized_name$Map$}$();\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$$value_enum_type$ ${$get$capitalized_name$OrDefault$}$(\n" + " $key_type$ key,\n" + " $value_enum_type$ defaultValue);\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$$value_enum_type$ ${$get$capitalized_name$OrThrow$}$(\n" + " $key_type$ key);\n"); + printer->Annotate("{", "}", descriptor_); + if (SupportUnknownEnumValue(descriptor_->file())) { + printer->Print( + variables_, + "/**\n" + " * Use {@link #get$capitalized_name$ValueMap()} instead.\n" + " */\n" + "@java.lang.Deprecated\n" + "java.util.Map<$type_parameters$>\n" + "${$get$capitalized_name$Value$}$();\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$java.util.Map<$type_parameters$>\n" + "${$get$capitalized_name$ValueMap$}$();\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$\n" + "$value_type$ ${$get$capitalized_name$ValueOrDefault$}$(\n" + " $key_type$ key,\n" + " $value_type$ defaultValue);\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$\n" + "$value_type$ ${$get$capitalized_name$ValueOrThrow$}$(\n" + " $key_type$ key);\n"); + printer->Annotate("{", "}", descriptor_); + } + } else { + printer->Print(variables_, + "/**\n" + " * Use {@link #get$capitalized_name$Map()} instead.\n" + " */\n" + "@java.lang.Deprecated\n" + "java.util.Map<$type_parameters$>\n" + "${$get$capitalized_name$$}$();\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$java.util.Map<$type_parameters$>\n" + "${$get$capitalized_name$Map$}$();\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$\n" + "$value_type$ ${$get$capitalized_name$OrDefault$}$(\n" + " $key_type$ key,\n" + " $value_type$ defaultValue);\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$\n" + "$value_type$ ${$get$capitalized_name$OrThrow$}$(\n" + " $key_type$ key);\n"); + printer->Annotate("{", "}", descriptor_); + } +} + +void ImmutableMapFieldGenerator::GenerateMembers(io::Printer* printer) const { + printer->Print( + variables_, + "private static final class $capitalized_name$DefaultEntryHolder {\n" + " static final com.google.protobuf.MapEntry<\n" + " $type_parameters$> defaultEntry =\n" + " com.google.protobuf.MapEntry\n" + " .<$type_parameters$>newDefaultInstance(\n" + " $descriptor$\n" + " $key_wire_type$,\n" + " $key_default_value$,\n" + " $value_wire_type$,\n" + " $value_default_value$);\n" + "}\n"); + printer->Print(variables_, + "private com.google.protobuf.MapField<\n" + " $type_parameters$> $name$_;\n" + "private com.google.protobuf.MapField<$type_parameters$>\n" + "internalGet$capitalized_name$() {\n" + " if ($name$_ == null) {\n" + " return com.google.protobuf.MapField.emptyMapField(\n" + " $map_field_parameter$);\n" + " }\n" + " return $name$_;\n" + "}\n"); + if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) { + printer->Print( + variables_, + "private static final\n" + "com.google.protobuf.Internal.MapAdapter.Converter<\n" + " java.lang.Integer, $value_enum_type$> $name$ValueConverter =\n" + " com.google.protobuf.Internal.MapAdapter.newEnumConverter(\n" + " $value_enum_type$.internalGetValueMap(),\n" + " $unrecognized_value$);\n"); + printer->Print( + variables_, + "private static final java.util.Map<$boxed_key_type$, " + "$value_enum_type$>\n" + "internalGetAdapted$capitalized_name$Map(\n" + " java.util.Map<$boxed_key_type$, $boxed_value_type$> map) {\n" + " return new com.google.protobuf.Internal.MapAdapter<\n" + " $boxed_key_type$, $value_enum_type$, java.lang.Integer>(\n" + " map, $name$ValueConverter);\n" + "}\n"); + } + GenerateMapGetters(printer); +} + +void ImmutableMapFieldGenerator::GenerateBuilderMembers( + io::Printer* printer) const { + printer->Print(variables_, + "private com.google.protobuf.MapField<\n" + " $type_parameters$> $name$_;\n" + "private com.google.protobuf.MapField<$type_parameters$>\n" + "internalGet$capitalized_name$() {\n" + " if ($name$_ == null) {\n" + " return com.google.protobuf.MapField.emptyMapField(\n" + " $map_field_parameter$);\n" + " }\n" + " return $name$_;\n" + "}\n" + "private com.google.protobuf.MapField<$type_parameters$>\n" + "internalGetMutable$capitalized_name$() {\n" + " $on_changed$;\n" + " if ($name$_ == null) {\n" + " $name$_ = com.google.protobuf.MapField.newMapField(\n" + " $map_field_parameter$);\n" + " }\n" + " if (!$name$_.isMutable()) {\n" + " $name$_ = $name$_.copy();\n" + " }\n" + " return $name$_;\n" + "}\n"); + GenerateMapGetters(printer); + printer->Print(variables_, + "$deprecation$\n" + "public Builder ${$clear$capitalized_name$$}$() {\n" + " internalGetMutable$capitalized_name$().getMutableMap()\n" + " .clear();\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$\n" + "public Builder ${$remove$capitalized_name$$}$(\n" + " $key_type$ key) {\n" + " $key_null_check$\n" + " internalGetMutable$capitalized_name$().getMutableMap()\n" + " .remove(key);\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) { + printer->Print( + variables_, + "/**\n" + " * Use alternate mutation accessors instead.\n" + " */\n" + "@java.lang.Deprecated\n" + "public java.util.Map<$boxed_key_type$, $value_enum_type$>\n" + "${$getMutable$capitalized_name$$}$() {\n" + " return internalGetAdapted$capitalized_name$Map(\n" + " internalGetMutable$capitalized_name$().getMutableMap());\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder ${$put$capitalized_name$$}$(\n" + " $key_type$ key,\n" + " $value_enum_type$ value) {\n" + " $key_null_check$\n" + " $value_null_check$\n" + " internalGetMutable$capitalized_name$().getMutableMap()\n" + " .put(key, $name$ValueConverter.doBackward(value));\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$public Builder ${$putAll$capitalized_name$$}$(\n" + " java.util.Map<$boxed_key_type$, $value_enum_type$> values) {\n" + " internalGetAdapted$capitalized_name$Map(\n" + " internalGetMutable$capitalized_name$().getMutableMap())\n" + " .putAll(values);\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + if (SupportUnknownEnumValue(descriptor_->file())) { + printer->Print( + variables_, + "/**\n" + " * Use alternate mutation accessors instead.\n" + " */\n" + "@java.lang.Deprecated\n" + "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n" + "${$getMutable$capitalized_name$Value$}$() {\n" + " return internalGetMutable$capitalized_name$().getMutableMap();\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$public Builder ${$put$capitalized_name$Value$}$(\n" + " $key_type$ key,\n" + " $value_type$ value) {\n" + " $key_null_check$\n" + " $value_null_check$\n" + " internalGetMutable$capitalized_name$().getMutableMap()\n" + " .put(key, value);\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$public Builder ${$putAll$capitalized_name$Value$}$(\n" + " java.util.Map<$boxed_key_type$, $boxed_value_type$> values) {\n" + " internalGetMutable$capitalized_name$().getMutableMap()\n" + " .putAll(values);\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + } + } else { + printer->Print( + variables_, + "/**\n" + " * Use alternate mutation accessors instead.\n" + " */\n" + "@java.lang.Deprecated\n" + "public java.util.Map<$type_parameters$>\n" + "${$getMutable$capitalized_name$$}$() {\n" + " return internalGetMutable$capitalized_name$().getMutableMap();\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$" + "public Builder ${$put$capitalized_name$$}$(\n" + " $key_type$ key,\n" + " $value_type$ value) {\n" + " $key_null_check$\n" + " $value_null_check$\n" + " internalGetMutable$capitalized_name$().getMutableMap()\n" + " .put(key, value);\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$\n" + "public Builder ${$putAll$capitalized_name$$}$(\n" + " java.util.Map<$type_parameters$> values) {\n" + " internalGetMutable$capitalized_name$().getMutableMap()\n" + " .putAll(values);\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + } +} + +void ImmutableMapFieldGenerator::GenerateMapGetters( + io::Printer* printer) const { + printer->Print(variables_, + "$deprecation$\n" + "public int ${$get$capitalized_name$Count$}$() {\n" + " return internalGet$capitalized_name$().getMap().size();\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$\n" + "@java.lang.Override\n" + "public boolean ${$contains$capitalized_name$$}$(\n" + " $key_type$ key) {\n" + " $key_null_check$\n" + " return internalGet$capitalized_name$().getMap().containsKey(key);\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) { + printer->Print(variables_, + "/**\n" + " * Use {@link #get$capitalized_name$Map()} instead.\n" + " */\n" + "@java.lang.Override\n" + "@java.lang.Deprecated\n" + "public java.util.Map<$boxed_key_type$, $value_enum_type$>\n" + "${$get$capitalized_name$$}$() {\n" + " return get$capitalized_name$Map();\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$\n" + "public java.util.Map<$boxed_key_type$, $value_enum_type$>\n" + "${$get$capitalized_name$Map$}$() {\n" + " return internalGetAdapted$capitalized_name$Map(\n" + " internalGet$capitalized_name$().getMap());" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$\n" + "public $value_enum_type$ ${$get$capitalized_name$OrDefault$}$(\n" + " $key_type$ key,\n" + " $value_enum_type$ defaultValue) {\n" + " $key_null_check$\n" + " java.util.Map<$boxed_key_type$, $boxed_value_type$> map =\n" + " internalGet$capitalized_name$().getMap();\n" + " return map.containsKey(key)\n" + " ? $name$ValueConverter.doForward(map.get(key))\n" + " : defaultValue;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$\n" + "public $value_enum_type$ ${$get$capitalized_name$OrThrow$}$(\n" + " $key_type$ key) {\n" + " $key_null_check$\n" + " java.util.Map<$boxed_key_type$, $boxed_value_type$> map =\n" + " internalGet$capitalized_name$().getMap();\n" + " if (!map.containsKey(key)) {\n" + " throw new java.lang.IllegalArgumentException();\n" + " }\n" + " return $name$ValueConverter.doForward(map.get(key));\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + if (SupportUnknownEnumValue(descriptor_->file())) { + printer->Print( + variables_, + "/**\n" + " * Use {@link #get$capitalized_name$ValueMap()} instead.\n" + " */\n" + "@java.lang.Override\n" + "@java.lang.Deprecated\n" + "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n" + "${$get$capitalized_name$Value$}$() {\n" + " return get$capitalized_name$ValueMap();\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$\n" + "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n" + "${$get$capitalized_name$ValueMap$}$() {\n" + " return internalGet$capitalized_name$().getMap();\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$\n" + "public $value_type$ ${$get$capitalized_name$ValueOrDefault$}$(\n" + " $key_type$ key,\n" + " $value_type$ defaultValue) {\n" + " $key_null_check$\n" + " java.util.Map<$boxed_key_type$, $boxed_value_type$> map =\n" + " internalGet$capitalized_name$().getMap();\n" + " return map.containsKey(key) ? map.get(key) : defaultValue;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$\n" + "public $value_type$ ${$get$capitalized_name$ValueOrThrow$}$(\n" + " $key_type$ key) {\n" + " $key_null_check$\n" + " java.util.Map<$boxed_key_type$, $boxed_value_type$> map =\n" + " internalGet$capitalized_name$().getMap();\n" + " if (!map.containsKey(key)) {\n" + " throw new java.lang.IllegalArgumentException();\n" + " }\n" + " return map.get(key);\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + } + } else { + printer->Print(variables_, + "/**\n" + " * Use {@link #get$capitalized_name$Map()} instead.\n" + " */\n" + "@java.lang.Override\n" + "@java.lang.Deprecated\n" + "public java.util.Map<$type_parameters$> " + "${$get$capitalized_name$$}$() {\n" + " return get$capitalized_name$Map();\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$\n" + "public java.util.Map<$type_parameters$> " + "${$get$capitalized_name$Map$}$() {\n" + " return internalGet$capitalized_name$().getMap();\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$\n" + "public $value_type$ ${$get$capitalized_name$OrDefault$}$(\n" + " $key_type$ key,\n" + " $value_type$ defaultValue) {\n" + " $key_null_check$\n" + " java.util.Map<$type_parameters$> map =\n" + " internalGet$capitalized_name$().getMap();\n" + " return map.containsKey(key) ? map.get(key) : defaultValue;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$\n" + "public $value_type$ ${$get$capitalized_name$OrThrow$}$(\n" + " $key_type$ key) {\n" + " $key_null_check$\n" + " java.util.Map<$type_parameters$> map =\n" + " internalGet$capitalized_name$().getMap();\n" + " if (!map.containsKey(key)) {\n" + " throw new java.lang.IllegalArgumentException();\n" + " }\n" + " return map.get(key);\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + } +} + +void ImmutableMapFieldGenerator::GenerateKotlinDslMembers( + io::Printer* printer) const { + printer->Print( + variables_, + "/**\n" + " * An uninstantiable, behaviorless type to represent the field in\n" + " * generics.\n" + " */\n" + "@kotlin.OptIn" + "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n" + "public class ${$$kt_capitalized_name$Proxy$}$ private constructor()" + " : com.google.protobuf.kotlin.DslProxy()\n"); + + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$kt_deprecation$ public val $kt_name$: " + "com.google.protobuf.kotlin.DslMap" + "<$kt_key_type$, $kt_value_type$, ${$$kt_capitalized_name$Proxy$}$>\n" + " @kotlin.jvm.JvmSynthetic\n" + " @JvmName(\"get$kt_capitalized_name$Map\")\n" + " get() = com.google.protobuf.kotlin.DslMap(\n" + " $kt_dsl_builder$.${$get$capitalized_name$Map$}$()\n" + " )\n"); + + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "@JvmName(\"put$kt_capitalized_name$\")\n" + "public fun com.google.protobuf.kotlin.DslMap" + "<$kt_key_type$, $kt_value_type$, ${$$kt_capitalized_name$Proxy$}$>\n" + " .put(key: $kt_key_type$, value: $kt_value_type$) {\n" + " $kt_dsl_builder$.${$put$capitalized_name$$}$(key, value)\n" + " }\n"); + + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "@kotlin.jvm.JvmSynthetic\n" + "@JvmName(\"set$kt_capitalized_name$\")\n" + "@Suppress(\"NOTHING_TO_INLINE\")\n" + "public inline operator fun com.google.protobuf.kotlin.DslMap" + "<$kt_key_type$, $kt_value_type$, ${$$kt_capitalized_name$Proxy$}$>\n" + " .set(key: $kt_key_type$, value: $kt_value_type$) {\n" + " put(key, value)\n" + " }\n"); + + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "@kotlin.jvm.JvmSynthetic\n" + "@JvmName(\"remove$kt_capitalized_name$\")\n" + "public fun com.google.protobuf.kotlin.DslMap" + "<$kt_key_type$, $kt_value_type$, ${$$kt_capitalized_name$Proxy$}$>\n" + " .remove(key: $kt_key_type$) {\n" + " $kt_dsl_builder$.${$remove$capitalized_name$$}$(key)\n" + " }\n"); + + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "@kotlin.jvm.JvmSynthetic\n" + "@JvmName(\"putAll$kt_capitalized_name$\")\n" + "public fun com.google.protobuf.kotlin.DslMap" + "<$kt_key_type$, $kt_value_type$, ${$$kt_capitalized_name$Proxy$}$>\n" + " .putAll(map: kotlin.collections.Map<$kt_key_type$, $kt_value_type$>) " + "{\n" + " $kt_dsl_builder$.${$putAll$capitalized_name$$}$(map)\n" + " }\n"); + + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "@kotlin.jvm.JvmSynthetic\n" + "@JvmName(\"clear$kt_capitalized_name$\")\n" + "public fun com.google.protobuf.kotlin.DslMap" + "<$kt_key_type$, $kt_value_type$, ${$$kt_capitalized_name$Proxy$}$>\n" + " .clear() {\n" + " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n" + " }\n"); +} + +void ImmutableMapFieldGenerator::GenerateFieldBuilderInitializationCode( + io::Printer* printer) const { + // Nothing to initialize. +} + +void ImmutableMapFieldGenerator::GenerateInitializationCode( + io::Printer* printer) const { + // Nothing to initialize. +} + +void ImmutableMapFieldGenerator::GenerateBuilderClearCode( + io::Printer* printer) const { + printer->Print(variables_, + "internalGetMutable$capitalized_name$().clear();\n"); +} + +void ImmutableMapFieldGenerator::GenerateMergingCode( + io::Printer* printer) const { + printer->Print(variables_, + "internalGetMutable$capitalized_name$().mergeFrom(\n" + " other.internalGet$capitalized_name$());\n"); +} + +void ImmutableMapFieldGenerator::GenerateBuildingCode( + io::Printer* printer) const { + printer->Print(variables_, + "result.$name$_ = internalGet$capitalized_name$();\n" + "result.$name$_.makeImmutable();\n"); +} + +void ImmutableMapFieldGenerator::GenerateParsingCode( + io::Printer* printer) const { + printer->Print(variables_, + "if (!$get_mutable_bit_parser$) {\n" + " $name$_ = com.google.protobuf.MapField.newMapField(\n" + " $map_field_parameter$);\n" + " $set_mutable_bit_parser$;\n" + "}\n"); + if (!SupportUnknownEnumValue(descriptor_->file()) && + GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) { + printer->Print( + variables_, + "com.google.protobuf.ByteString bytes = input.readBytes();\n" + "com.google.protobuf.MapEntry<$type_parameters$>\n" + "$name$__ = $default_entry$.getParserForType().parseFrom(bytes);\n"); + printer->Print( + variables_, + "if ($value_enum_type$.forNumber($name$__.getValue()) == null) {\n" + " unknownFields.mergeLengthDelimitedField($number$, bytes);\n" + "} else {\n" + " $name$_.getMutableMap().put(\n" + " $name$__.getKey(), $name$__.getValue());\n" + "}\n"); + } else { + printer->Print( + variables_, + "com.google.protobuf.MapEntry<$type_parameters$>\n" + "$name$__ = input.readMessage(\n" + " $default_entry$.getParserForType(), extensionRegistry);\n" + "$name$_.getMutableMap().put(\n" + " $name$__.getKey(), $name$__.getValue());\n"); + } +} + +void ImmutableMapFieldGenerator::GenerateParsingDoneCode( + io::Printer* printer) const { + // Nothing to do here. +} + +void ImmutableMapFieldGenerator::GenerateSerializationCode( + io::Printer* printer) const { + printer->Print(variables_, + "com.google.protobuf.GeneratedMessage$ver$\n" + " .serialize$short_key_type$MapTo(\n" + " output,\n" + " internalGet$capitalized_name$(),\n" + " $default_entry$,\n" + " $number$);\n"); +} + +void ImmutableMapFieldGenerator::GenerateSerializedSizeCode( + io::Printer* printer) const { + printer->Print( + variables_, + "for (java.util.Map.Entry<$type_parameters$> entry\n" + " : internalGet$capitalized_name$().getMap().entrySet()) {\n" + " com.google.protobuf.MapEntry<$type_parameters$>\n" + " $name$__ = $default_entry$.newBuilderForType()\n" + " .setKey(entry.getKey())\n" + " .setValue(entry.getValue())\n" + " .build();\n" + " size += com.google.protobuf.CodedOutputStream\n" + " .computeMessageSize($number$, $name$__);\n" + "}\n"); +} + +void ImmutableMapFieldGenerator::GenerateEqualsCode( + io::Printer* printer) const { + printer->Print(variables_, + "if (!internalGet$capitalized_name$().equals(\n" + " other.internalGet$capitalized_name$())) return false;\n"); +} + +void ImmutableMapFieldGenerator::GenerateHashCode(io::Printer* printer) const { + printer->Print( + variables_, + "if (!internalGet$capitalized_name$().getMap().isEmpty()) {\n" + " hash = (37 * hash) + $constant_name$;\n" + " hash = (53 * hash) + internalGet$capitalized_name$().hashCode();\n" + "}\n"); +} + +std::string ImmutableMapFieldGenerator::GetBoxedType() const { + return name_resolver_->GetImmutableClassName(descriptor_->message_type()); +} + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/java/java_map_field.h b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_map_field.h new file mode 100644 index 00000000..e309391f --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_map_field.h @@ -0,0 +1,82 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_MAP_FIELD_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVA_MAP_FIELD_H__ + +#include <compiler/java/java_field.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +class ImmutableMapFieldGenerator : public ImmutableFieldGenerator { + public: + explicit ImmutableMapFieldGenerator(const FieldDescriptor* descriptor, + int messageBitIndex, int builderBitIndex, + Context* context); + ~ImmutableMapFieldGenerator() override; + + // implements ImmutableFieldGenerator --------------------------------------- + int GetNumBitsForMessage() const override; + int GetNumBitsForBuilder() const override; + void GenerateInterfaceMembers(io::Printer* printer) const override; + void GenerateMembers(io::Printer* printer) const override; + void GenerateBuilderMembers(io::Printer* printer) const override; + void GenerateInitializationCode(io::Printer* printer) const override; + void GenerateBuilderClearCode(io::Printer* printer) const override; + void GenerateMergingCode(io::Printer* printer) const override; + void GenerateBuildingCode(io::Printer* printer) const override; + void GenerateParsingCode(io::Printer* printer) const override; + void GenerateParsingDoneCode(io::Printer* printer) const override; + void GenerateSerializationCode(io::Printer* printer) const override; + void GenerateSerializedSizeCode(io::Printer* printer) const override; + void GenerateFieldBuilderInitializationCode( + io::Printer* printer) const override; + void GenerateEqualsCode(io::Printer* printer) const override; + void GenerateHashCode(io::Printer* printer) const override; + void GenerateKotlinDslMembers(io::Printer* printer) const override; + + std::string GetBoxedType() const override; + + private: + const FieldDescriptor* descriptor_; + std::map<std::string, std::string> variables_; + ClassNameResolver* name_resolver_; + void GenerateMapGetters(io::Printer* printer) const; +}; + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_MAP_FIELD_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/java/java_map_field_lite.cc b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_map_field_lite.cc new file mode 100644 index 00000000..b210bc45 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_map_field_lite.cc @@ -0,0 +1,909 @@ +// 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 <compiler/java/java_map_field_lite.h> + +#include <cstdint> + +#include <compiler/java/java_context.h> +#include <compiler/java/java_doc_comment.h> +#include <compiler/java/java_helpers.h> +#include <compiler/java/java_name_resolver.h> +#include <io/printer.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +namespace { + +const FieldDescriptor* KeyField(const FieldDescriptor* descriptor) { + GOOGLE_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, descriptor->type()); + const Descriptor* message = descriptor->message_type(); + GOOGLE_CHECK(message->options().map_entry()); + return message->FindFieldByName("key"); +} + +const FieldDescriptor* ValueField(const FieldDescriptor* descriptor) { + GOOGLE_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, descriptor->type()); + const Descriptor* message = descriptor->message_type(); + GOOGLE_CHECK(message->options().map_entry()); + return message->FindFieldByName("value"); +} + +std::string TypeName(const FieldDescriptor* field, + ClassNameResolver* name_resolver, bool boxed) { + if (GetJavaType(field) == JAVATYPE_MESSAGE) { + return name_resolver->GetImmutableClassName(field->message_type()); + } else if (GetJavaType(field) == JAVATYPE_ENUM) { + return name_resolver->GetImmutableClassName(field->enum_type()); + } else { + return boxed ? BoxedPrimitiveTypeName(GetJavaType(field)) + : PrimitiveTypeName(GetJavaType(field)); + } +} + +std::string KotlinTypeName(const FieldDescriptor* field, + ClassNameResolver* name_resolver) { + if (GetJavaType(field) == JAVATYPE_MESSAGE) { + return name_resolver->GetImmutableClassName(field->message_type()); + } else if (GetJavaType(field) == JAVATYPE_ENUM) { + return name_resolver->GetImmutableClassName(field->enum_type()); + } else { + return KotlinTypeName(GetJavaType(field)); + } +} + +std::string WireType(const FieldDescriptor* field) { + return "com.google.protobuf.WireFormat.FieldType." + + std::string(FieldTypeName(field->type())); +} + +void SetMessageVariables(const FieldDescriptor* descriptor, int messageBitIndex, + int builderBitIndex, const FieldGeneratorInfo* info, + Context* context, + std::map<std::string, std::string>* variables) { + SetCommonFieldVariables(descriptor, info, variables); + + ClassNameResolver* name_resolver = context->GetNameResolver(); + (*variables)["type"] = + name_resolver->GetImmutableClassName(descriptor->message_type()); + const FieldDescriptor* key = KeyField(descriptor); + const FieldDescriptor* value = ValueField(descriptor); + const JavaType keyJavaType = GetJavaType(key); + const JavaType valueJavaType = GetJavaType(value); + + (*variables)["key_type"] = TypeName(key, name_resolver, false); + (*variables)["boxed_key_type"] = TypeName(key, name_resolver, true); + (*variables)["kt_key_type"] = KotlinTypeName(key, name_resolver); + (*variables)["kt_value_type"] = KotlinTypeName(value, name_resolver); + (*variables)["key_wire_type"] = WireType(key); + (*variables)["key_default_value"] = DefaultValue(key, true, name_resolver); + // We use `x.getClass()` as a null check because it generates less bytecode + // than an `if (x == null) { throw ... }` statement. + (*variables)["key_null_check"] = + IsReferenceType(keyJavaType) + ? "java.lang.Class<?> keyClass = key.getClass();" + : ""; + (*variables)["value_null_check"] = + IsReferenceType(valueJavaType) + ? "java.lang.Class<?> valueClass = value.getClass();" + : ""; + + if (GetJavaType(value) == JAVATYPE_ENUM) { + // We store enums as Integers internally. + (*variables)["value_type"] = "int"; + (*variables)["boxed_value_type"] = "java.lang.Integer"; + (*variables)["value_wire_type"] = WireType(value); + (*variables)["value_default_value"] = + DefaultValue(value, true, name_resolver) + ".getNumber()"; + + (*variables)["value_enum_type"] = TypeName(value, name_resolver, false); + + if (SupportUnknownEnumValue(descriptor->file())) { + // Map unknown values to a special UNRECOGNIZED value if supported. + (*variables)["unrecognized_value"] = + (*variables)["value_enum_type"] + ".UNRECOGNIZED"; + } else { + // Map unknown values to the default value if we don't have UNRECOGNIZED. + (*variables)["unrecognized_value"] = + DefaultValue(value, true, name_resolver); + } + } else { + (*variables)["value_type"] = TypeName(value, name_resolver, false); + (*variables)["boxed_value_type"] = TypeName(value, name_resolver, true); + (*variables)["value_wire_type"] = WireType(value); + (*variables)["value_default_value"] = + DefaultValue(value, true, name_resolver); + } + (*variables)["type_parameters"] = + (*variables)["boxed_key_type"] + ", " + (*variables)["boxed_value_type"]; + // TODO(birdo): Add @deprecated javadoc when generating javadoc is supported + // by the proto compiler + (*variables)["deprecation"] = + descriptor->options().deprecated() ? "@java.lang.Deprecated " : ""; + (*variables)["kt_deprecation"] = + descriptor->options().deprecated() + ? "@kotlin.Deprecated(message = \"Field " + (*variables)["name"] + + " is deprecated\") " + : ""; + + (*variables)["default_entry"] = + (*variables)["capitalized_name"] + "DefaultEntryHolder.defaultEntry"; +} + +} // namespace + +ImmutableMapFieldLiteGenerator::ImmutableMapFieldLiteGenerator( + const FieldDescriptor* descriptor, int messageBitIndex, Context* context) + : descriptor_(descriptor), + context_(context), + name_resolver_(context->GetNameResolver()) { + SetMessageVariables(descriptor, messageBitIndex, 0, + context->GetFieldGeneratorInfo(descriptor), context, + &variables_); +} + +ImmutableMapFieldLiteGenerator::~ImmutableMapFieldLiteGenerator() {} + +int ImmutableMapFieldLiteGenerator::GetNumBitsForMessage() const { return 0; } + +void ImmutableMapFieldLiteGenerator::GenerateInterfaceMembers( + io::Printer* printer) const { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$int ${$get$capitalized_name$Count$}$();\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$boolean ${$contains$capitalized_name$$}$(\n" + " $key_type$ key);\n"); + printer->Annotate("{", "}", descriptor_); + if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) { + printer->Print(variables_, + "/**\n" + " * Use {@link #get$capitalized_name$Map()} instead.\n" + " */\n" + "@java.lang.Deprecated\n" + "java.util.Map<$boxed_key_type$, $value_enum_type$>\n" + "${$get$capitalized_name$$}$();\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$java.util.Map<$boxed_key_type$, $value_enum_type$>\n" + "${$get$capitalized_name$Map$}$();\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$$value_enum_type$ ${$get$capitalized_name$OrDefault$}$(\n" + " $key_type$ key,\n" + " $value_enum_type$ defaultValue);\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$$value_enum_type$ ${$get$capitalized_name$OrThrow$}$(\n" + " $key_type$ key);\n"); + printer->Annotate("{", "}", descriptor_); + if (SupportUnknownEnumValue(descriptor_->file())) { + printer->Print( + variables_, + "/**\n" + " * Use {@link #get$capitalized_name$ValueMap()} instead.\n" + " */\n" + "@java.lang.Deprecated\n" + "java.util.Map<$type_parameters$>\n" + "${$get$capitalized_name$Value$}$();\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$java.util.Map<$type_parameters$>\n" + "${$get$capitalized_name$ValueMap$}$();\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$\n" + "$value_type$ ${$get$capitalized_name$ValueOrDefault$}$(\n" + " $key_type$ key,\n" + " $value_type$ defaultValue);\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$\n" + "$value_type$ ${$get$capitalized_name$ValueOrThrow$}$(\n" + " $key_type$ key);\n"); + printer->Annotate("{", "}", descriptor_); + } + } else { + printer->Print(variables_, + "/**\n" + " * Use {@link #get$capitalized_name$Map()} instead.\n" + " */\n" + "@java.lang.Deprecated\n" + "java.util.Map<$type_parameters$>\n" + "${$get$capitalized_name$$}$();\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$java.util.Map<$type_parameters$>\n" + "${$get$capitalized_name$Map$}$();\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$\n" + "$value_type$ ${$get$capitalized_name$OrDefault$}$(\n" + " $key_type$ key,\n" + " $value_type$ defaultValue);\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$\n" + "$value_type$ ${$get$capitalized_name$OrThrow$}$(\n" + " $key_type$ key);\n"); + printer->Annotate("{", "}", descriptor_); + } +} + +void ImmutableMapFieldLiteGenerator::GenerateMembers( + io::Printer* printer) const { + printer->Print( + variables_, + "private static final class $capitalized_name$DefaultEntryHolder {\n" + " static final com.google.protobuf.MapEntryLite<\n" + " $type_parameters$> defaultEntry =\n" + " com.google.protobuf.MapEntryLite\n" + " .<$type_parameters$>newDefaultInstance(\n" + " $key_wire_type$,\n" + " $key_default_value$,\n" + " $value_wire_type$,\n" + " $value_default_value$);\n" + "}\n"); + printer->Print(variables_, + "private com.google.protobuf.MapFieldLite<\n" + " $type_parameters$> $name$_ =\n" + " com.google.protobuf.MapFieldLite.emptyMapField();\n" + "private com.google.protobuf.MapFieldLite<$type_parameters$>\n" + "internalGet$capitalized_name$() {\n" + " return $name$_;\n" + "}\n" + "private com.google.protobuf.MapFieldLite<$type_parameters$>\n" + "internalGetMutable$capitalized_name$() {\n" + " if (!$name$_.isMutable()) {\n" + " $name$_ = $name$_.mutableCopy();\n" + " }\n" + " return $name$_;\n" + "}\n"); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$\n" + "public int ${$get$capitalized_name$Count$}$() {\n" + " return internalGet$capitalized_name$().size();\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$\n" + "public boolean ${$contains$capitalized_name$$}$(\n" + " $key_type$ key) {\n" + " $key_null_check$\n" + " return internalGet$capitalized_name$().containsKey(key);\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) { + printer->Print( + variables_, + "private static final\n" + "com.google.protobuf.Internal.MapAdapter.Converter<\n" + " java.lang.Integer, $value_enum_type$> $name$ValueConverter =\n" + " com.google.protobuf.Internal.MapAdapter.newEnumConverter(\n" + " $value_enum_type$.internalGetValueMap(),\n" + " $unrecognized_value$);\n"); + printer->Print(variables_, + "/**\n" + " * Use {@link #get$capitalized_name$Map()} instead.\n" + " */\n" + "@java.lang.Deprecated\n" + "public java.util.Map<$boxed_key_type$, $value_enum_type$>\n" + "${$get$capitalized_name$$}$() {\n" + " return get$capitalized_name$Map();\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$\n" + "public java.util.Map<$boxed_key_type$, $value_enum_type$>\n" + "${$get$capitalized_name$Map$}$() {\n" + " return java.util.Collections.unmodifiableMap(\n" + " new com.google.protobuf.Internal.MapAdapter<\n" + " $boxed_key_type$, $value_enum_type$, java.lang.Integer>(\n" + " internalGet$capitalized_name$(),\n" + " $name$ValueConverter));\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$\n" + "public $value_enum_type$ ${$get$capitalized_name$OrDefault$}$(\n" + " $key_type$ key,\n" + " $value_enum_type$ defaultValue) {\n" + " $key_null_check$\n" + " java.util.Map<$boxed_key_type$, $boxed_value_type$> map =\n" + " internalGet$capitalized_name$();\n" + " return map.containsKey(key)\n" + " ? $name$ValueConverter.doForward(map.get(key))\n" + " : defaultValue;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$\n" + "public $value_enum_type$ ${$get$capitalized_name$OrThrow$}$(\n" + " $key_type$ key) {\n" + " $key_null_check$\n" + " java.util.Map<$boxed_key_type$, $boxed_value_type$> map =\n" + " internalGet$capitalized_name$();\n" + " if (!map.containsKey(key)) {\n" + " throw new java.lang.IllegalArgumentException();\n" + " }\n" + " return $name$ValueConverter.doForward(map.get(key));\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + if (SupportUnknownEnumValue(descriptor_->file())) { + printer->Print( + variables_, + "/**\n" + " * Use {@link #get$capitalized_name$ValueMap()} instead.\n" + " */\n" + "@java.lang.Override\n" + "@java.lang.Deprecated\n" + "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n" + "${$get$capitalized_name$Value$}$() {\n" + " return get$capitalized_name$ValueMap();\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$\n" + "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n" + "${$get$capitalized_name$ValueMap$}$() {\n" + " return java.util.Collections.unmodifiableMap(\n" + " internalGet$capitalized_name$());\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$\n" + "public $value_type$ ${$get$capitalized_name$ValueOrDefault$}$(\n" + " $key_type$ key,\n" + " $value_type$ defaultValue) {\n" + " $key_null_check$\n" + " java.util.Map<$boxed_key_type$, $boxed_value_type$> map =\n" + " internalGet$capitalized_name$();\n" + " return map.containsKey(key) ? map.get(key) : defaultValue;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$\n" + "public $value_type$ ${$get$capitalized_name$ValueOrThrow$}$(\n" + " $key_type$ key) {\n" + " $key_null_check$\n" + " java.util.Map<$boxed_key_type$, $boxed_value_type$> map =\n" + " internalGet$capitalized_name$();\n" + " if (!map.containsKey(key)) {\n" + " throw new java.lang.IllegalArgumentException();\n" + " }\n" + " return map.get(key);\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + } + } else { + printer->Print(variables_, + "/**\n" + " * Use {@link #get$capitalized_name$Map()} instead.\n" + " */\n" + "@java.lang.Override\n" + "@java.lang.Deprecated\n" + "public java.util.Map<$type_parameters$> " + "${$get$capitalized_name$$}$() {\n" + " return get$capitalized_name$Map();\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$\n" + "public java.util.Map<$type_parameters$> " + "${$get$capitalized_name$Map$}$() {\n" + " return java.util.Collections.unmodifiableMap(\n" + " internalGet$capitalized_name$());\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$\n" + "public $value_type$ ${$get$capitalized_name$OrDefault$}$(\n" + " $key_type$ key,\n" + " $value_type$ defaultValue) {\n" + " $key_null_check$\n" + " java.util.Map<$type_parameters$> map =\n" + " internalGet$capitalized_name$();\n" + " return map.containsKey(key) ? map.get(key) : defaultValue;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$\n" + "public $value_type$ ${$get$capitalized_name$OrThrow$}$(\n" + " $key_type$ key) {\n" + " $key_null_check$\n" + " java.util.Map<$type_parameters$> map =\n" + " internalGet$capitalized_name$();\n" + " if (!map.containsKey(key)) {\n" + " throw new java.lang.IllegalArgumentException();\n" + " }\n" + " return map.get(key);\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + } + + // Generate private setters for the builder to proxy into. + if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) { + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "private java.util.Map<$boxed_key_type$, $value_enum_type$>\n" + "getMutable$capitalized_name$Map() {\n" + " return new com.google.protobuf.Internal.MapAdapter<\n" + " $boxed_key_type$, $value_enum_type$, java.lang.Integer>(\n" + " internalGetMutable$capitalized_name$(),\n" + " $name$ValueConverter);\n" + "}\n"); + if (SupportUnknownEnumValue(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "private java.util.Map<$boxed_key_type$, $boxed_value_type$>\n" + "getMutable$capitalized_name$ValueMap() {\n" + " return internalGetMutable$capitalized_name$();\n" + "}\n"); + } + } else { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private java.util.Map<$type_parameters$>\n" + "getMutable$capitalized_name$Map() {\n" + " return internalGetMutable$capitalized_name$();\n" + "}\n"); + } +} + +void ImmutableMapFieldLiteGenerator::GenerateFieldInfo( + io::Printer* printer, std::vector<uint16_t>* output) const { + WriteIntToUtf16CharSequence(descriptor_->number(), output); + WriteIntToUtf16CharSequence(GetExperimentalJavaFieldType(descriptor_), + output); + printer->Print(variables_, + "\"$name$_\",\n" + "$default_entry$,\n"); + if (!SupportUnknownEnumValue(descriptor_) && + GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) { + PrintEnumVerifierLogic(printer, ValueField(descriptor_), variables_, + /*var_name=*/"$value_enum_type$", + /*terminating_string=*/",\n", + /*enforce_lite=*/context_->EnforceLite()); + } +} + +void ImmutableMapFieldLiteGenerator::GenerateBuilderMembers( + io::Printer* printer) const { + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$\n" + "public int ${$get$capitalized_name$Count$}$() {\n" + " return instance.get$capitalized_name$Map().size();\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$\n" + "public boolean ${$contains$capitalized_name$$}$(\n" + " $key_type$ key) {\n" + " $key_null_check$\n" + " return instance.get$capitalized_name$Map().containsKey(key);\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + printer->Print(variables_, + "$deprecation$\n" + "public Builder ${$clear$capitalized_name$$}$() {\n" + " copyOnWrite();\n" + " instance.getMutable$capitalized_name$Map().clear();\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$\n" + "public Builder ${$remove$capitalized_name$$}$(\n" + " $key_type$ key) {\n" + " $key_null_check$\n" + " copyOnWrite();\n" + " instance.getMutable$capitalized_name$Map().remove(key);\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) { + printer->Print(variables_, + "/**\n" + " * Use {@link #get$capitalized_name$Map()} instead.\n" + " */\n" + "@java.lang.Deprecated\n" + "public java.util.Map<$boxed_key_type$, $value_enum_type$>\n" + "${$get$capitalized_name$$}$() {\n" + " return get$capitalized_name$Map();\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$\n" + "public java.util.Map<$boxed_key_type$, $value_enum_type$>\n" + "${$get$capitalized_name$Map$}$() {\n" + " return java.util.Collections.unmodifiableMap(\n" + " instance.get$capitalized_name$Map());\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$\n" + "public $value_enum_type$ ${$get$capitalized_name$OrDefault$}$(\n" + " $key_type$ key,\n" + " $value_enum_type$ defaultValue) {\n" + " $key_null_check$\n" + " java.util.Map<$boxed_key_type$, $value_enum_type$> map =\n" + " instance.get$capitalized_name$Map();\n" + " return map.containsKey(key)\n" + " ? map.get(key)\n" + " : defaultValue;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$\n" + "public $value_enum_type$ ${$get$capitalized_name$OrThrow$}$(\n" + " $key_type$ key) {\n" + " $key_null_check$\n" + " java.util.Map<$boxed_key_type$, $value_enum_type$> map =\n" + " instance.get$capitalized_name$Map();\n" + " if (!map.containsKey(key)) {\n" + " throw new java.lang.IllegalArgumentException();\n" + " }\n" + " return map.get(key);\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$public Builder ${$put$capitalized_name$$}$(\n" + " $key_type$ key,\n" + " $value_enum_type$ value) {\n" + " $key_null_check$\n" + " $value_null_check$\n" + " copyOnWrite();\n" + " instance.getMutable$capitalized_name$Map().put(key, value);\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$public Builder ${$putAll$capitalized_name$$}$(\n" + " java.util.Map<$boxed_key_type$, $value_enum_type$> values) {\n" + " copyOnWrite();\n" + " instance.getMutable$capitalized_name$Map().putAll(values);\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + if (SupportUnknownEnumValue(descriptor_->file())) { + printer->Print( + variables_, + "/**\n" + " * Use {@link #get$capitalized_name$ValueMap()} instead.\n" + " */\n" + "@java.lang.Override\n" + "@java.lang.Deprecated\n" + "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n" + "${$get$capitalized_name$Value$}$() {\n" + " return get$capitalized_name$ValueMap();\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$\n" + "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n" + "${$get$capitalized_name$ValueMap$}$() {\n" + " return java.util.Collections.unmodifiableMap(\n" + " instance.get$capitalized_name$ValueMap());\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$\n" + "public $value_type$ ${$get$capitalized_name$ValueOrDefault$}$(\n" + " $key_type$ key,\n" + " $value_type$ defaultValue) {\n" + " $key_null_check$\n" + " java.util.Map<$boxed_key_type$, $boxed_value_type$> map =\n" + " instance.get$capitalized_name$ValueMap();\n" + " return map.containsKey(key) ? map.get(key) : defaultValue;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$\n" + "public $value_type$ ${$get$capitalized_name$ValueOrThrow$}$(\n" + " $key_type$ key) {\n" + " $key_null_check$\n" + " java.util.Map<$boxed_key_type$, $boxed_value_type$> map =\n" + " instance.get$capitalized_name$ValueMap();\n" + " if (!map.containsKey(key)) {\n" + " throw new java.lang.IllegalArgumentException();\n" + " }\n" + " return map.get(key);\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$public Builder ${$put$capitalized_name$Value$}$(\n" + " $key_type$ key,\n" + " $value_type$ value) {\n" + " $key_null_check$\n" + " copyOnWrite();\n" + " instance.getMutable$capitalized_name$ValueMap().put(key, value);\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$public Builder ${$putAll$capitalized_name$Value$}$(\n" + " java.util.Map<$boxed_key_type$, $boxed_value_type$> values) {\n" + " copyOnWrite();\n" + " instance.getMutable$capitalized_name$ValueMap().putAll(values);\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + } + } else { + printer->Print(variables_, + "/**\n" + " * Use {@link #get$capitalized_name$Map()} instead.\n" + " */\n" + "@java.lang.Override\n" + "@java.lang.Deprecated\n" + "public java.util.Map<$type_parameters$> " + "${$get$capitalized_name$$}$() {\n" + " return get$capitalized_name$Map();\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$" + "public java.util.Map<$type_parameters$> " + "${$get$capitalized_name$Map$}$() {\n" + " return java.util.Collections.unmodifiableMap(\n" + " instance.get$capitalized_name$Map());\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$\n" + "public $value_type$ ${$get$capitalized_name$OrDefault$}$(\n" + " $key_type$ key,\n" + " $value_type$ defaultValue) {\n" + " $key_null_check$\n" + " java.util.Map<$type_parameters$> map =\n" + " instance.get$capitalized_name$Map();\n" + " return map.containsKey(key) ? map.get(key) : defaultValue;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$\n" + "public $value_type$ ${$get$capitalized_name$OrThrow$}$(\n" + " $key_type$ key) {\n" + " $key_null_check$\n" + " java.util.Map<$type_parameters$> map =\n" + " instance.get$capitalized_name$Map();\n" + " if (!map.containsKey(key)) {\n" + " throw new java.lang.IllegalArgumentException();\n" + " }\n" + " return map.get(key);\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$" + "public Builder ${$put$capitalized_name$$}$(\n" + " $key_type$ key,\n" + " $value_type$ value) {\n" + " $key_null_check$\n" + " $value_null_check$\n" + " copyOnWrite();\n" + " instance.getMutable$capitalized_name$Map().put(key, value);\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$" + "public Builder ${$putAll$capitalized_name$$}$(\n" + " java.util.Map<$type_parameters$> values) {\n" + " copyOnWrite();\n" + " instance.getMutable$capitalized_name$Map().putAll(values);\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + } +} + +void ImmutableMapFieldLiteGenerator::GenerateKotlinDslMembers( + io::Printer* printer) const { + printer->Print( + variables_, + "/**\n" + " * An uninstantiable, behaviorless type to represent the field in\n" + " * generics.\n" + " */\n" + "@kotlin.OptIn" + "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n" + "public class ${$$kt_capitalized_name$Proxy$}$ private constructor()" + " : com.google.protobuf.kotlin.DslProxy()\n"); + + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$kt_deprecation$ public val $kt_name$: " + "com.google.protobuf.kotlin.DslMap" + "<$kt_key_type$, $kt_value_type$, ${$$kt_capitalized_name$Proxy$}$>\n" + " @kotlin.jvm.JvmSynthetic\n" + " @JvmName(\"get$kt_capitalized_name$Map\")\n" + " get() = com.google.protobuf.kotlin.DslMap(\n" + " $kt_dsl_builder$.${$get$capitalized_name$Map$}$()\n" + " )\n"); + + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "@JvmName(\"put$kt_capitalized_name$\")\n" + "public fun com.google.protobuf.kotlin.DslMap" + "<$kt_key_type$, $kt_value_type$, ${$$kt_capitalized_name$Proxy$}$>\n" + " .put(key: $kt_key_type$, value: $kt_value_type$) {\n" + " $kt_dsl_builder$.${$put$capitalized_name$$}$(key, value)\n" + " }\n"); + + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "@kotlin.jvm.JvmSynthetic\n" + "@JvmName(\"set$kt_capitalized_name$\")\n" + "@Suppress(\"NOTHING_TO_INLINE\")\n" + "public inline operator fun com.google.protobuf.kotlin.DslMap" + "<$kt_key_type$, $kt_value_type$, ${$$kt_capitalized_name$Proxy$}$>\n" + " .set(key: $kt_key_type$, value: $kt_value_type$) {\n" + " put(key, value)\n" + " }\n"); + + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "@kotlin.jvm.JvmSynthetic\n" + "@JvmName(\"remove$kt_capitalized_name$\")\n" + "public fun com.google.protobuf.kotlin.DslMap" + "<$kt_key_type$, $kt_value_type$, ${$$kt_capitalized_name$Proxy$}$>\n" + " .remove(key: $kt_key_type$) {\n" + " $kt_dsl_builder$.${$remove$capitalized_name$$}$(key)\n" + " }\n"); + + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "@kotlin.jvm.JvmSynthetic\n" + "@JvmName(\"putAll$kt_capitalized_name$\")\n" + "public fun com.google.protobuf.kotlin.DslMap" + "<$kt_key_type$, $kt_value_type$, ${$$kt_capitalized_name$Proxy$}$>\n" + " .putAll(map: kotlin.collections.Map<$kt_key_type$, $kt_value_type$>) " + "{\n" + " $kt_dsl_builder$.${$putAll$capitalized_name$$}$(map)\n" + " }\n"); + + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "@kotlin.jvm.JvmSynthetic\n" + "@JvmName(\"clear$kt_capitalized_name$\")\n" + "public fun com.google.protobuf.kotlin.DslMap" + "<$kt_key_type$, $kt_value_type$, ${$$kt_capitalized_name$Proxy$}$>\n" + " .clear() {\n" + " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n" + " }\n"); +} + +void ImmutableMapFieldLiteGenerator::GenerateInitializationCode( + io::Printer* printer) const { + // Nothing to initialize. +} + +std::string ImmutableMapFieldLiteGenerator::GetBoxedType() const { + return name_resolver_->GetImmutableClassName(descriptor_->message_type()); +} + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/java/java_map_field_lite.h b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_map_field_lite.h new file mode 100644 index 00000000..7017982d --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_map_field_lite.h @@ -0,0 +1,74 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_MAP_FIELD_LITE_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVA_MAP_FIELD_LITE_H__ + +#include <cstdint> + +#include <compiler/java/java_field.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +class ImmutableMapFieldLiteGenerator : public ImmutableFieldLiteGenerator { + public: + explicit ImmutableMapFieldLiteGenerator(const FieldDescriptor* descriptor, + int messageBitIndex, + Context* context); + ~ImmutableMapFieldLiteGenerator() override; + + // implements ImmutableFieldLiteGenerator ------------------------------------ + int GetNumBitsForMessage() const override; + void GenerateInterfaceMembers(io::Printer* printer) const override; + void GenerateMembers(io::Printer* printer) const override; + void GenerateBuilderMembers(io::Printer* printer) const override; + void GenerateInitializationCode(io::Printer* printer) const override; + void GenerateFieldInfo(io::Printer* printer, + std::vector<uint16_t>* output) const override; + void GenerateKotlinDslMembers(io::Printer* printer) const override; + + std::string GetBoxedType() const override; + + private: + const FieldDescriptor* descriptor_; + std::map<std::string, std::string> variables_; + Context* context_; + ClassNameResolver* name_resolver_; +}; + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_MAP_FIELD_LITE_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/java/java_message.cc b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_message.cc new file mode 100644 index 00000000..38edc769 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_message.cc @@ -0,0 +1,1729 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <compiler/java/java_message.h> + +#include <algorithm> +#include <cstdint> +#include <map> +#include <memory> +#include <vector> + +#include <compiler/java/java_context.h> +#include <compiler/java/java_doc_comment.h> +#include <compiler/java/java_enum.h> +#include <compiler/java/java_extension.h> +#include <compiler/java/java_generator_factory.h> +#include <compiler/java/java_helpers.h> +#include <compiler/java/java_message_builder.h> +#include <compiler/java/java_message_builder_lite.h> +#include <compiler/java/java_name_resolver.h> +#include <descriptor.pb.h> +#include <io/coded_stream.h> +#include <io/printer.h> +#include <wire_format.h> +#include <stubs/strutil.h> +#include <stubs/substitute.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +using internal::WireFormat; +using internal::WireFormatLite; + +namespace { +std::string MapValueImmutableClassdName(const Descriptor* descriptor, + ClassNameResolver* name_resolver) { + const FieldDescriptor* value_field = descriptor->FindFieldByName("value"); + GOOGLE_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, value_field->type()); + return name_resolver->GetImmutableClassName(value_field->message_type()); +} +} // namespace + +// =================================================================== + +MessageGenerator::MessageGenerator(const Descriptor* descriptor) + : descriptor_(descriptor) { + for (int i = 0; i < descriptor_->field_count(); i++) { + if (IsRealOneof(descriptor_->field(i))) { + oneofs_.insert(descriptor_->field(i)->containing_oneof()); + } + } +} + +MessageGenerator::~MessageGenerator() {} + +// =================================================================== +ImmutableMessageGenerator::ImmutableMessageGenerator( + const Descriptor* descriptor, Context* context) + : MessageGenerator(descriptor), + context_(context), + name_resolver_(context->GetNameResolver()), + field_generators_(descriptor, context_) { + GOOGLE_CHECK(HasDescriptorMethods(descriptor->file(), context->EnforceLite())) + << "Generator factory error: A non-lite message generator is used to " + "generate lite messages."; +} + +ImmutableMessageGenerator::~ImmutableMessageGenerator() {} + +void ImmutableMessageGenerator::GenerateStaticVariables( + io::Printer* printer, int* bytecode_estimate) { + // Because descriptor.proto (com.google.protobuf.DescriptorProtos) is + // used in the construction of descriptors, we have a tricky bootstrapping + // problem. To help control static initialization order, we make sure all + // descriptors and other static data that depends on them are members of + // the outermost class in the file. This way, they will be initialized in + // a deterministic order. + + std::map<std::string, std::string> vars; + vars["identifier"] = UniqueFileScopeIdentifier(descriptor_); + vars["index"] = StrCat(descriptor_->index()); + vars["classname"] = name_resolver_->GetImmutableClassName(descriptor_); + if (descriptor_->containing_type() != NULL) { + vars["parent"] = UniqueFileScopeIdentifier(descriptor_->containing_type()); + } + if (MultipleJavaFiles(descriptor_->file(), /* immutable = */ true)) { + // We can only make these package-private since the classes that use them + // are in separate files. + vars["private"] = ""; + } else { + vars["private"] = "private "; + } + if (*bytecode_estimate <= kMaxStaticSize) { + vars["final"] = "final "; + } else { + vars["final"] = ""; + } + + // The descriptor for this type. + printer->Print( + vars, + // TODO(teboring): final needs to be added back. The way to fix it is to + // generate methods that can construct the types, and then still declare + // the types, and then init them in clinit with the new method calls. + "$private$static $final$com.google.protobuf.Descriptors.Descriptor\n" + " internal_$identifier$_descriptor;\n"); + *bytecode_estimate += 30; + + // And the FieldAccessorTable. + GenerateFieldAccessorTable(printer, bytecode_estimate); + + // Generate static members for all nested types. + for (int i = 0; i < descriptor_->nested_type_count(); i++) { + // TODO(kenton): Reuse MessageGenerator objects? + ImmutableMessageGenerator(descriptor_->nested_type(i), context_) + .GenerateStaticVariables(printer, bytecode_estimate); + } +} + +int ImmutableMessageGenerator::GenerateStaticVariableInitializers( + io::Printer* printer) { + int bytecode_estimate = 0; + std::map<std::string, std::string> vars; + vars["identifier"] = UniqueFileScopeIdentifier(descriptor_); + vars["index"] = StrCat(descriptor_->index()); + vars["classname"] = name_resolver_->GetImmutableClassName(descriptor_); + if (descriptor_->containing_type() != NULL) { + vars["parent"] = UniqueFileScopeIdentifier(descriptor_->containing_type()); + } + + // The descriptor for this type. + if (descriptor_->containing_type() == NULL) { + printer->Print(vars, + "internal_$identifier$_descriptor =\n" + " getDescriptor().getMessageTypes().get($index$);\n"); + bytecode_estimate += 30; + } else { + printer->Print( + vars, + "internal_$identifier$_descriptor =\n" + " internal_$parent$_descriptor.getNestedTypes().get($index$);\n"); + bytecode_estimate += 30; + } + + // And the FieldAccessorTable. + bytecode_estimate += GenerateFieldAccessorTableInitializer(printer); + + // Generate static member initializers for all nested types. + for (int i = 0; i < descriptor_->nested_type_count(); i++) { + // TODO(kenton): Reuse MessageGenerator objects? + bytecode_estimate += + ImmutableMessageGenerator(descriptor_->nested_type(i), context_) + .GenerateStaticVariableInitializers(printer); + } + return bytecode_estimate; +} + +void ImmutableMessageGenerator::GenerateFieldAccessorTable( + io::Printer* printer, int* bytecode_estimate) { + std::map<std::string, std::string> vars; + vars["identifier"] = UniqueFileScopeIdentifier(descriptor_); + if (MultipleJavaFiles(descriptor_->file(), /* immutable = */ true)) { + // We can only make these package-private since the classes that use them + // are in separate files. + vars["private"] = ""; + } else { + vars["private"] = "private "; + } + if (*bytecode_estimate <= kMaxStaticSize) { + vars["final"] = "final "; + } else { + vars["final"] = ""; + } + vars["ver"] = GeneratedCodeVersionSuffix(); + printer->Print( + vars, + "$private$static $final$\n" + " com.google.protobuf.GeneratedMessage$ver$.FieldAccessorTable\n" + " internal_$identifier$_fieldAccessorTable;\n"); + + // The following bytecode_estimate calculation logic must stay in sync with + // the similar logic in the GenerateFieldAccessorTableInitializer method below + // to make sure that the generated static final fields are initialized in the + // static initialization block directly. + // + // 6 bytes per field and oneof + *bytecode_estimate += + 10 + 6 * descriptor_->field_count() + 6 * descriptor_->oneof_decl_count(); +} + +int ImmutableMessageGenerator::GenerateFieldAccessorTableInitializer( + io::Printer* printer) { + int bytecode_estimate = 10; + printer->Print( + "internal_$identifier$_fieldAccessorTable = new\n" + " com.google.protobuf.GeneratedMessage$ver$.FieldAccessorTable(\n" + " internal_$identifier$_descriptor,\n" + " new java.lang.String[] { ", + "identifier", UniqueFileScopeIdentifier(descriptor_), "ver", + GeneratedCodeVersionSuffix()); + // All the bytecode_estimate calculation logic in this method must stay in + // sync with the similar logic in the GenerateFieldAccessorTable method + // above. See the corresponding comment in GenerateFieldAccessorTable for + // details. + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = descriptor_->field(i); + const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field); + bytecode_estimate += 6; + printer->Print("\"$field_name$\", ", "field_name", info->capitalized_name); + } + // We reproduce synthetic oneofs here since proto reflection needs these. + for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { + const OneofDescriptor* oneof = descriptor_->oneof_decl(i); + const OneofGeneratorInfo* info = context_->GetOneofGeneratorInfo(oneof); + bytecode_estimate += 6; + printer->Print("\"$oneof_name$\", ", "oneof_name", info->capitalized_name); + } + printer->Print("});\n"); + return bytecode_estimate; +} + +// =================================================================== + +void ImmutableMessageGenerator::GenerateInterface(io::Printer* printer) { + MaybePrintGeneratedAnnotation(context_, printer, descriptor_, + /* immutable = */ true, "OrBuilder"); + if (descriptor_->extension_range_count() > 0) { + printer->Print( + "$deprecation$public interface ${$$classname$OrBuilder$}$ extends\n" + " $extra_interfaces$\n" + " com.google.protobuf.GeneratedMessage$ver$.\n" + " ExtendableMessageOrBuilder<$classname$> {\n", + "deprecation", + descriptor_->options().deprecated() ? "@java.lang.Deprecated " : "", + "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_), + "classname", descriptor_->name(), "{", "", "}", "", "ver", + GeneratedCodeVersionSuffix()); + } else { + printer->Print( + "$deprecation$public interface ${$$classname$OrBuilder$}$ extends\n" + " $extra_interfaces$\n" + " com.google.protobuf.MessageOrBuilder {\n", + "deprecation", + descriptor_->options().deprecated() ? "@java.lang.Deprecated " : "", + "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_), + "classname", descriptor_->name(), "{", "", "}", ""); + } + printer->Annotate("{", "}", descriptor_); + + printer->Indent(); + for (int i = 0; i < descriptor_->field_count(); i++) { + printer->Print("\n"); + field_generators_.get(descriptor_->field(i)) + .GenerateInterfaceMembers(printer); + } + for (auto oneof : oneofs_) { + printer->Print( + "\n" + "public $classname$.$oneof_capitalized_name$Case " + "get$oneof_capitalized_name$Case();\n", + "oneof_capitalized_name", + context_->GetOneofGeneratorInfo(oneof)->capitalized_name, "classname", + context_->GetNameResolver()->GetImmutableClassName(descriptor_)); + } + printer->Outdent(); + + printer->Print("}\n"); +} + +// =================================================================== + +void ImmutableMessageGenerator::Generate(io::Printer* printer) { + bool is_own_file = IsOwnFile(descriptor_, /* immutable = */ true); + + std::map<std::string, std::string> variables; + variables["static"] = is_own_file ? "" : "static "; + variables["classname"] = descriptor_->name(); + variables["extra_interfaces"] = ExtraMessageInterfaces(descriptor_); + variables["ver"] = GeneratedCodeVersionSuffix(); + variables["deprecation"] = + descriptor_->options().deprecated() ? "@java.lang.Deprecated " : ""; + + WriteMessageDocComment(printer, descriptor_); + MaybePrintGeneratedAnnotation(context_, printer, descriptor_, + /* immutable = */ true); + // The builder_type stores the super type name of the nested Builder class. + std::string builder_type; + if (descriptor_->extension_range_count() > 0) { + printer->Print( + variables, + "$deprecation$public $static$final class $classname$ extends\n"); + printer->Annotate("classname", descriptor_); + printer->Print( + variables, + " com.google.protobuf.GeneratedMessage$ver$.ExtendableMessage<\n" + " $classname$> implements\n" + " $extra_interfaces$\n" + " $classname$OrBuilder {\n"); + builder_type = strings::Substitute( + "com.google.protobuf.GeneratedMessage$1.ExtendableBuilder<$0, ?>", + name_resolver_->GetImmutableClassName(descriptor_), + GeneratedCodeVersionSuffix()); + } else { + printer->Print( + variables, + "$deprecation$public $static$final class $classname$ extends\n"); + printer->Annotate("classname", descriptor_); + printer->Print(variables, + " com.google.protobuf.GeneratedMessage$ver$ implements\n" + " $extra_interfaces$\n" + " $classname$OrBuilder {\n"); + builder_type = + strings::Substitute("com.google.protobuf.GeneratedMessage$0.Builder<?>", + GeneratedCodeVersionSuffix()); + } + printer->Print("private static final long serialVersionUID = 0L;\n"); + + printer->Indent(); + // Using builder_type, instead of Builder, prevents the Builder class from + // being loaded into PermGen space when the default instance is created. + // This optimizes the PermGen space usage for clients that do not modify + // messages. + printer->Print( + "// Use $classname$.newBuilder() to construct.\n" + "private $classname$($buildertype$ builder) {\n" + " super(builder);\n" + "}\n", + "classname", descriptor_->name(), "buildertype", builder_type); + printer->Print("private $classname$() {\n", "classname", descriptor_->name()); + printer->Indent(); + GenerateInitializers(printer); + printer->Outdent(); + printer->Print( + "}\n" + "\n"); + + printer->Print(variables, + "@java.lang.Override\n" + "@SuppressWarnings({\"unused\"})\n" + "protected java.lang.Object newInstance(\n" + " UnusedPrivateParameter unused) {\n" + " return new $classname$();\n" + "}\n" + "\n"); + + printer->Print( + "@java.lang.Override\n" + "public final com.google.protobuf.UnknownFieldSet\n" + "getUnknownFields() {\n" + " return this.unknownFields;\n" + "}\n"); + + if (context_->HasGeneratedMethods(descriptor_)) { + GenerateParsingConstructor(printer); + } + + GenerateDescriptorMethods(printer); + + // Nested types + for (int i = 0; i < descriptor_->enum_type_count(); i++) { + EnumGenerator(descriptor_->enum_type(i), true, context_).Generate(printer); + } + + for (int i = 0; i < descriptor_->nested_type_count(); i++) { + // Don't generate Java classes for map entry messages. + if (IsMapEntry(descriptor_->nested_type(i))) continue; + ImmutableMessageGenerator messageGenerator(descriptor_->nested_type(i), + context_); + messageGenerator.GenerateInterface(printer); + messageGenerator.Generate(printer); + } + + // Integers for bit fields. + int totalBits = 0; + for (int i = 0; i < descriptor_->field_count(); i++) { + totalBits += + field_generators_.get(descriptor_->field(i)).GetNumBitsForMessage(); + } + int totalInts = (totalBits + 31) / 32; + for (int i = 0; i < totalInts; i++) { + printer->Print("private int $bit_field_name$;\n", "bit_field_name", + GetBitFieldName(i)); + } + + // oneof + std::map<std::string, std::string> vars; + for (auto oneof : oneofs_) { + vars["oneof_name"] = context_->GetOneofGeneratorInfo(oneof)->name; + vars["oneof_capitalized_name"] = + context_->GetOneofGeneratorInfo(oneof)->capitalized_name; + vars["oneof_index"] = StrCat((oneof)->index()); + // oneofCase_ and oneof_ + printer->Print(vars, + "private int $oneof_name$Case_ = 0;\n" + "private java.lang.Object $oneof_name$_;\n"); + // OneofCase enum + printer->Print( + vars, + "public enum $oneof_capitalized_name$Case\n" + // TODO(dweis): Remove EnumLite when we want to break compatibility with + // 3.x users + " implements com.google.protobuf.Internal.EnumLite,\n" + " com.google.protobuf.AbstractMessage.InternalOneOfEnum {\n"); + printer->Indent(); + for (int j = 0; j < (oneof)->field_count(); j++) { + const FieldDescriptor* field = (oneof)->field(j); + printer->Print( + "$deprecation$$field_name$($field_number$),\n", "deprecation", + field->options().deprecated() ? "@java.lang.Deprecated " : "", + "field_name", ToUpper(field->name()), "field_number", + StrCat(field->number())); + } + printer->Print("$cap_oneof_name$_NOT_SET(0);\n", "cap_oneof_name", + ToUpper(vars["oneof_name"])); + printer->Print(vars, + "private final int value;\n" + "private $oneof_capitalized_name$Case(int value) {\n" + " this.value = value;\n" + "}\n"); + printer->Print( + vars, + "/**\n" + " * @param value The number of the enum to look for.\n" + " * @return The enum associated with the given number.\n" + " * @deprecated Use {@link #forNumber(int)} instead.\n" + " */\n" + "@java.lang.Deprecated\n" + "public static $oneof_capitalized_name$Case valueOf(int value) {\n" + " return forNumber(value);\n" + "}\n" + "\n" + "public static $oneof_capitalized_name$Case forNumber(int value) {\n" + " switch (value) {\n"); + for (int j = 0; j < (oneof)->field_count(); j++) { + const FieldDescriptor* field = (oneof)->field(j); + printer->Print(" case $field_number$: return $field_name$;\n", + "field_number", StrCat(field->number()), + "field_name", ToUpper(field->name())); + } + printer->Print( + " case 0: return $cap_oneof_name$_NOT_SET;\n" + " default: return null;\n" + " }\n" + "}\n" + "public int getNumber() {\n" + " return this.value;\n" + "}\n", + "cap_oneof_name", ToUpper(vars["oneof_name"])); + printer->Outdent(); + printer->Print("};\n\n"); + // oneofCase() + printer->Print(vars, + "public $oneof_capitalized_name$Case\n" + "get$oneof_capitalized_name$Case() {\n" + " return $oneof_capitalized_name$Case.forNumber(\n" + " $oneof_name$Case_);\n" + "}\n" + "\n"); + } + + if (IsAnyMessage(descriptor_)) { + GenerateAnyMethods(printer); + } + + // Fields + for (int i = 0; i < descriptor_->field_count(); i++) { + printer->Print("public static final int $constant_name$ = $number$;\n", + "constant_name", FieldConstantName(descriptor_->field(i)), + "number", StrCat(descriptor_->field(i)->number())); + printer->Annotate("constant_name", descriptor_->field(i)); + field_generators_.get(descriptor_->field(i)).GenerateMembers(printer); + printer->Print("\n"); + } + + if (context_->HasGeneratedMethods(descriptor_)) { + GenerateIsInitialized(printer); + GenerateMessageSerializationMethods(printer); + GenerateEqualsAndHashCode(printer); + } + + + GenerateParseFromMethods(printer); + GenerateBuilder(printer); + + printer->Print( + "\n" + "// @@protoc_insertion_point(class_scope:$full_name$)\n", + "full_name", descriptor_->full_name()); + + // Carefully initialize the default instance in such a way that it doesn't + // conflict with other initialization. + printer->Print("private static final $classname$ DEFAULT_INSTANCE;\n", + "classname", + name_resolver_->GetImmutableClassName(descriptor_)); + printer->Print( + "static {\n" + " DEFAULT_INSTANCE = new $classname$();\n" + "}\n" + "\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_)); + + printer->Print( + "public static $classname$ getDefaultInstance() {\n" + " return DEFAULT_INSTANCE;\n" + "}\n" + "\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_)); + + // 'of' method for Wrappers + if (IsWrappersProtoFile(descriptor_->file())) { + printer->Print( + "public static $classname$ of($field_type$ value) {\n" + " return newBuilder().setValue(value).build();\n" + "}\n" + "\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_), + "field_type", PrimitiveTypeName(GetJavaType(descriptor_->field(0)))); + } + + GenerateParser(printer); + + printer->Print( + "@java.lang.Override\n" + "public $classname$ getDefaultInstanceForType() {\n" + " return DEFAULT_INSTANCE;\n" + "}\n" + "\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_)); + + // Extensions must be declared after the DEFAULT_INSTANCE is initialized + // because the DEFAULT_INSTANCE is used by the extension to lazily retrieve + // the outer class's FileDescriptor. + for (int i = 0; i < descriptor_->extension_count(); i++) { + ImmutableExtensionGenerator(descriptor_->extension(i), context_) + .Generate(printer); + } + + printer->Outdent(); + printer->Print("}\n\n"); +} + +// =================================================================== + +void ImmutableMessageGenerator::GenerateMessageSerializationMethods( + io::Printer* printer) { + std::unique_ptr<const FieldDescriptor*[]> sorted_fields( + SortFieldsByNumber(descriptor_)); + + std::vector<const Descriptor::ExtensionRange*> sorted_extensions; + sorted_extensions.reserve(descriptor_->extension_range_count()); + for (int i = 0; i < descriptor_->extension_range_count(); ++i) { + sorted_extensions.push_back(descriptor_->extension_range(i)); + } + std::sort(sorted_extensions.begin(), sorted_extensions.end(), + ExtensionRangeOrdering()); + printer->Print( + "@java.lang.Override\n" + "public void writeTo(com.google.protobuf.CodedOutputStream output)\n" + " throws java.io.IOException {\n"); + printer->Indent(); + + if (HasPackedFields(descriptor_)) { + // writeTo(CodedOutputStream output) might be invoked without + // getSerializedSize() ever being called, but we need the memoized + // sizes in case this message has packed fields. Rather than emit checks + // for each packed field, just call getSerializedSize() up front. In most + // cases, getSerializedSize() will have already been called anyway by one + // of the wrapper writeTo() methods, making this call cheap. + printer->Print("getSerializedSize();\n"); + } + + if (descriptor_->extension_range_count() > 0) { + if (descriptor_->options().message_set_wire_format()) { + printer->Print( + "com.google.protobuf.GeneratedMessage$ver$\n" + " .ExtendableMessage<$classname$>.ExtensionWriter\n" + " extensionWriter = newMessageSetExtensionWriter();\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_), + "ver", GeneratedCodeVersionSuffix()); + } else { + printer->Print( + "com.google.protobuf.GeneratedMessage$ver$\n" + " .ExtendableMessage<$classname$>.ExtensionWriter\n" + " extensionWriter = newExtensionWriter();\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_), + "ver", GeneratedCodeVersionSuffix()); + } + } + + // Merge the fields and the extension ranges, both sorted by field number. + for (int i = 0, j = 0; + i < descriptor_->field_count() || j < sorted_extensions.size();) { + if (i == descriptor_->field_count()) { + GenerateSerializeOneExtensionRange(printer, sorted_extensions[j++]); + } else if (j == sorted_extensions.size()) { + GenerateSerializeOneField(printer, sorted_fields[i++]); + } else if (sorted_fields[i]->number() < sorted_extensions[j]->start) { + GenerateSerializeOneField(printer, sorted_fields[i++]); + } else { + GenerateSerializeOneExtensionRange(printer, sorted_extensions[j++]); + } + } + + if (descriptor_->options().message_set_wire_format()) { + printer->Print("unknownFields.writeAsMessageSetTo(output);\n"); + } else { + printer->Print("unknownFields.writeTo(output);\n"); + } + + printer->Outdent(); + printer->Print( + "}\n" + "\n" + "@java.lang.Override\n" + "public int getSerializedSize() {\n" + " int size = memoizedSize;\n" + " if (size != -1) return size;\n" + "\n"); + printer->Indent(); + + printer->Print("size = 0;\n"); + + for (int i = 0; i < descriptor_->field_count(); i++) { + field_generators_.get(sorted_fields[i]).GenerateSerializedSizeCode(printer); + } + + if (descriptor_->extension_range_count() > 0) { + if (descriptor_->options().message_set_wire_format()) { + printer->Print("size += extensionsSerializedSizeAsMessageSet();\n"); + } else { + printer->Print("size += extensionsSerializedSize();\n"); + } + } + + if (descriptor_->options().message_set_wire_format()) { + printer->Print("size += unknownFields.getSerializedSizeAsMessageSet();\n"); + } else { + printer->Print("size += unknownFields.getSerializedSize();\n"); + } + + printer->Print( + "memoizedSize = size;\n" + "return size;\n"); + + printer->Outdent(); + printer->Print( + "}\n" + "\n"); +} + +void ImmutableMessageGenerator::GenerateParseFromMethods(io::Printer* printer) { + // Note: These are separate from GenerateMessageSerializationMethods() + // because they need to be generated even for messages that are optimized + // for code size. + printer->Print( + "public static $classname$ parseFrom(\n" + " java.nio.ByteBuffer data)\n" + " throws com.google.protobuf.InvalidProtocolBufferException {\n" + " return PARSER.parseFrom(data);\n" + "}\n" + "public static $classname$ parseFrom(\n" + " java.nio.ByteBuffer data,\n" + " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" + " throws com.google.protobuf.InvalidProtocolBufferException {\n" + " return PARSER.parseFrom(data, extensionRegistry);\n" + "}\n" + "public static $classname$ parseFrom(\n" + " com.google.protobuf.ByteString data)\n" + " throws com.google.protobuf.InvalidProtocolBufferException {\n" + " return PARSER.parseFrom(data);\n" + "}\n" + "public static $classname$ parseFrom(\n" + " com.google.protobuf.ByteString data,\n" + " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" + " throws com.google.protobuf.InvalidProtocolBufferException {\n" + " return PARSER.parseFrom(data, extensionRegistry);\n" + "}\n" + "public static $classname$ parseFrom(byte[] data)\n" + " throws com.google.protobuf.InvalidProtocolBufferException {\n" + " return PARSER.parseFrom(data);\n" + "}\n" + "public static $classname$ parseFrom(\n" + " byte[] data,\n" + " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" + " throws com.google.protobuf.InvalidProtocolBufferException {\n" + " return PARSER.parseFrom(data, extensionRegistry);\n" + "}\n" + "public static $classname$ parseFrom(java.io.InputStream input)\n" + " throws java.io.IOException {\n" + " return com.google.protobuf.GeneratedMessage$ver$\n" + " .parseWithIOException(PARSER, input);\n" + "}\n" + "public static $classname$ parseFrom(\n" + " java.io.InputStream input,\n" + " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" + " throws java.io.IOException {\n" + " return com.google.protobuf.GeneratedMessage$ver$\n" + " .parseWithIOException(PARSER, input, extensionRegistry);\n" + "}\n" + "public static $classname$ parseDelimitedFrom(java.io.InputStream " + "input)\n" + " throws java.io.IOException {\n" + " return com.google.protobuf.GeneratedMessage$ver$\n" + " .parseDelimitedWithIOException(PARSER, input);\n" + "}\n" + "public static $classname$ parseDelimitedFrom(\n" + " java.io.InputStream input,\n" + " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" + " throws java.io.IOException {\n" + " return com.google.protobuf.GeneratedMessage$ver$\n" + " .parseDelimitedWithIOException(PARSER, input, " + "extensionRegistry);\n" + "}\n" + "public static $classname$ parseFrom(\n" + " com.google.protobuf.CodedInputStream input)\n" + " throws java.io.IOException {\n" + " return com.google.protobuf.GeneratedMessage$ver$\n" + " .parseWithIOException(PARSER, input);\n" + "}\n" + "public static $classname$ parseFrom(\n" + " com.google.protobuf.CodedInputStream input,\n" + " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" + " throws java.io.IOException {\n" + " return com.google.protobuf.GeneratedMessage$ver$\n" + " .parseWithIOException(PARSER, input, extensionRegistry);\n" + "}\n" + "\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_), "ver", + GeneratedCodeVersionSuffix()); +} + +void ImmutableMessageGenerator::GenerateSerializeOneField( + io::Printer* printer, const FieldDescriptor* field) { + field_generators_.get(field).GenerateSerializationCode(printer); +} + +void ImmutableMessageGenerator::GenerateSerializeOneExtensionRange( + io::Printer* printer, const Descriptor::ExtensionRange* range) { + printer->Print("extensionWriter.writeUntil($end$, output);\n", "end", + StrCat(range->end)); +} + +// =================================================================== + +void ImmutableMessageGenerator::GenerateBuilder(io::Printer* printer) { + // LITE_RUNTIME implements this at the GeneratedMessageLite level. + printer->Print( + "@java.lang.Override\n" + "public Builder newBuilderForType() { return newBuilder(); }\n"); + + printer->Print( + "public static Builder newBuilder() {\n" + " return DEFAULT_INSTANCE.toBuilder();\n" + "}\n" + "public static Builder newBuilder($classname$ prototype) {\n" + " return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);\n" + "}\n" + "@java.lang.Override\n" + "public Builder toBuilder() {\n" + " return this == DEFAULT_INSTANCE\n" + " ? new Builder() : new Builder().mergeFrom(this);\n" + "}\n" + "\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_)); + + printer->Print( + "@java.lang.Override\n" + "protected Builder newBuilderForType(\n" + " com.google.protobuf.GeneratedMessage$ver$.BuilderParent parent) {\n" + " Builder builder = new Builder(parent);\n" + " return builder;\n" + "}\n", + "ver", GeneratedCodeVersionSuffix()); + + MessageBuilderGenerator builderGenerator(descriptor_, context_); + builderGenerator.Generate(printer); +} + +void ImmutableMessageGenerator::GenerateDescriptorMethods( + io::Printer* printer) { + if (!descriptor_->options().no_standard_descriptor_accessor()) { + printer->Print( + "public static final com.google.protobuf.Descriptors.Descriptor\n" + " getDescriptor() {\n" + " return $fileclass$.internal_$identifier$_descriptor;\n" + "}\n" + "\n", + "fileclass", name_resolver_->GetImmutableClassName(descriptor_->file()), + "identifier", UniqueFileScopeIdentifier(descriptor_)); + } + std::vector<const FieldDescriptor*> map_fields; + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = descriptor_->field(i); + if (GetJavaType(field) == JAVATYPE_MESSAGE && + IsMapEntry(field->message_type())) { + map_fields.push_back(field); + } + } + if (!map_fields.empty()) { + printer->Print( + "@SuppressWarnings({\"rawtypes\"})\n" + "@java.lang.Override\n" + "protected com.google.protobuf.MapField internalGetMapField(\n" + " int number) {\n" + " switch (number) {\n"); + printer->Indent(); + printer->Indent(); + for (int i = 0; i < map_fields.size(); ++i) { + const FieldDescriptor* field = map_fields[i]; + const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field); + printer->Print( + "case $number$:\n" + " return internalGet$capitalized_name$();\n", + "number", StrCat(field->number()), "capitalized_name", + info->capitalized_name); + } + printer->Print( + "default:\n" + " throw new RuntimeException(\n" + " \"Invalid map field number: \" + number);\n"); + printer->Outdent(); + printer->Outdent(); + printer->Print( + " }\n" + "}\n"); + } + printer->Print( + "@java.lang.Override\n" + "protected com.google.protobuf.GeneratedMessage$ver$.FieldAccessorTable\n" + " internalGetFieldAccessorTable() {\n" + " return $fileclass$.internal_$identifier$_fieldAccessorTable\n" + " .ensureFieldAccessorsInitialized(\n" + " $classname$.class, $classname$.Builder.class);\n" + "}\n" + "\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_), + "fileclass", name_resolver_->GetImmutableClassName(descriptor_->file()), + "identifier", UniqueFileScopeIdentifier(descriptor_), "ver", + GeneratedCodeVersionSuffix()); +} + +// =================================================================== + +void ImmutableMessageGenerator::GenerateIsInitialized(io::Printer* printer) { + // Memoizes whether the protocol buffer is fully initialized (has all + // required fields). -1 means not yet computed. 0 means false and 1 means + // true. + printer->Print("private byte memoizedIsInitialized = -1;\n"); + printer->Print( + "@java.lang.Override\n" + "public final boolean isInitialized() {\n"); + printer->Indent(); + + // Don't directly compare to -1 to avoid an Android x86 JIT bug. + printer->Print( + "byte isInitialized = memoizedIsInitialized;\n" + "if (isInitialized == 1) return true;\n" + "if (isInitialized == 0) return false;\n" + "\n"); + + // Check that all required fields in this message are set. + // TODO(kenton): We can optimize this when we switch to putting all the + // "has" fields into a single bitfield. + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = descriptor_->field(i); + const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field); + + if (field->is_required()) { + printer->Print( + "if (!has$name$()) {\n" + " memoizedIsInitialized = 0;\n" + " return false;\n" + "}\n", + "name", info->capitalized_name); + } + } + + // Now check that all embedded messages are initialized. + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = descriptor_->field(i); + const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field); + if (GetJavaType(field) == JAVATYPE_MESSAGE && + HasRequiredFields(field->message_type())) { + switch (field->label()) { + case FieldDescriptor::LABEL_REQUIRED: + printer->Print( + "if (!get$name$().isInitialized()) {\n" + " memoizedIsInitialized = 0;\n" + " return false;\n" + "}\n", + "type", + name_resolver_->GetImmutableClassName(field->message_type()), + "name", info->capitalized_name); + break; + case FieldDescriptor::LABEL_OPTIONAL: + printer->Print( + "if (has$name$()) {\n" + " if (!get$name$().isInitialized()) {\n" + " memoizedIsInitialized = 0;\n" + " return false;\n" + " }\n" + "}\n", + "name", info->capitalized_name); + break; + case FieldDescriptor::LABEL_REPEATED: + if (IsMapEntry(field->message_type())) { + printer->Print( + "for ($type$ item : get$name$Map().values()) {\n" + " if (!item.isInitialized()) {\n" + " memoizedIsInitialized = 0;\n" + " return false;\n" + " }\n" + "}\n", + "type", + MapValueImmutableClassdName(field->message_type(), + name_resolver_), + "name", info->capitalized_name); + } else { + printer->Print( + "for (int i = 0; i < get$name$Count(); i++) {\n" + " if (!get$name$(i).isInitialized()) {\n" + " memoizedIsInitialized = 0;\n" + " return false;\n" + " }\n" + "}\n", + "type", + name_resolver_->GetImmutableClassName(field->message_type()), + "name", info->capitalized_name); + } + break; + } + } + } + + if (descriptor_->extension_range_count() > 0) { + printer->Print( + "if (!extensionsAreInitialized()) {\n" + " memoizedIsInitialized = 0;\n" + " return false;\n" + "}\n"); + } + + printer->Outdent(); + + printer->Print(" memoizedIsInitialized = 1;\n"); + + printer->Print( + " return true;\n" + "}\n" + "\n"); +} + +// =================================================================== + +namespace { +bool CheckHasBitsForEqualsAndHashCode(const FieldDescriptor* field) { + if (field->is_repeated()) { + return false; + } + if (HasHasbit(field)) { + return true; + } + return GetJavaType(field) == JAVATYPE_MESSAGE && !IsRealOneof(field); +} +} // namespace + +void ImmutableMessageGenerator::GenerateEqualsAndHashCode( + io::Printer* printer) { + printer->Print( + "@java.lang.Override\n" + "public boolean equals("); + printer->Print("final java.lang.Object obj) {\n"); + printer->Indent(); + printer->Print( + "if (obj == this) {\n" + " return true;\n" + "}\n" + "if (!(obj instanceof $classname$)) {\n" + " return super.equals(obj);\n" + "}\n" + "$classname$ other = ($classname$) obj;\n" + "\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_)); + + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = descriptor_->field(i); + if (!IsRealOneof(field)) { + const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field); + bool check_has_bits = CheckHasBitsForEqualsAndHashCode(field); + if (check_has_bits) { + printer->Print( + "if (has$name$() != other.has$name$()) return false;\n" + "if (has$name$()) {\n", + "name", info->capitalized_name); + printer->Indent(); + } + field_generators_.get(field).GenerateEqualsCode(printer); + if (check_has_bits) { + printer->Outdent(); + printer->Print("}\n"); + } + } + } + + // Compare oneofs. + for (auto oneof : oneofs_) { + printer->Print( + "if (!get$oneof_capitalized_name$Case().equals(" + "other.get$oneof_capitalized_name$Case())) return false;\n", + "oneof_capitalized_name", + context_->GetOneofGeneratorInfo(oneof)->capitalized_name); + printer->Print("switch ($oneof_name$Case_) {\n", "oneof_name", + context_->GetOneofGeneratorInfo(oneof)->name); + printer->Indent(); + for (int j = 0; j < (oneof)->field_count(); j++) { + const FieldDescriptor* field = (oneof)->field(j); + printer->Print("case $field_number$:\n", "field_number", + StrCat(field->number())); + printer->Indent(); + field_generators_.get(field).GenerateEqualsCode(printer); + printer->Print("break;\n"); + printer->Outdent(); + } + printer->Print( + "case 0:\n" + "default:\n"); + printer->Outdent(); + printer->Print("}\n"); + } + + // Always consider unknown fields for equality. This will sometimes return + // false for non-canonical ordering when running in LITE_RUNTIME but it's + // the best we can do. + printer->Print( + "if (!unknownFields.equals(other.unknownFields)) return false;\n"); + if (descriptor_->extension_range_count() > 0) { + printer->Print( + "if (!getExtensionFields().equals(other.getExtensionFields()))\n" + " return false;\n"); + } + printer->Print("return true;\n"); + printer->Outdent(); + printer->Print( + "}\n" + "\n"); + + printer->Print( + "@java.lang.Override\n" + "public int hashCode() {\n"); + printer->Indent(); + printer->Print("if (memoizedHashCode != 0) {\n"); + printer->Indent(); + printer->Print("return memoizedHashCode;\n"); + printer->Outdent(); + printer->Print( + "}\n" + "int hash = 41;\n"); + + // If we output a getDescriptor() method, use that as it is more efficient. + if (descriptor_->options().no_standard_descriptor_accessor()) { + printer->Print("hash = (19 * hash) + getDescriptorForType().hashCode();\n"); + } else { + printer->Print("hash = (19 * hash) + getDescriptor().hashCode();\n"); + } + + // hashCode non-oneofs. + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = descriptor_->field(i); + if (!IsRealOneof(field)) { + const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field); + bool check_has_bits = CheckHasBitsForEqualsAndHashCode(field); + if (check_has_bits) { + printer->Print("if (has$name$()) {\n", "name", info->capitalized_name); + printer->Indent(); + } + field_generators_.get(field).GenerateHashCode(printer); + if (check_has_bits) { + printer->Outdent(); + printer->Print("}\n"); + } + } + } + + // hashCode oneofs. + for (auto oneof : oneofs_) { + printer->Print("switch ($oneof_name$Case_) {\n", "oneof_name", + context_->GetOneofGeneratorInfo(oneof)->name); + printer->Indent(); + for (int j = 0; j < (oneof)->field_count(); j++) { + const FieldDescriptor* field = (oneof)->field(j); + printer->Print("case $field_number$:\n", "field_number", + StrCat(field->number())); + printer->Indent(); + field_generators_.get(field).GenerateHashCode(printer); + printer->Print("break;\n"); + printer->Outdent(); + } + printer->Print( + "case 0:\n" + "default:\n"); + printer->Outdent(); + printer->Print("}\n"); + } + + if (descriptor_->extension_range_count() > 0) { + printer->Print("hash = hashFields(hash, getExtensionFields());\n"); + } + + printer->Print("hash = (29 * hash) + unknownFields.hashCode();\n"); + printer->Print( + "memoizedHashCode = hash;\n" + "return hash;\n"); + printer->Outdent(); + printer->Print( + "}\n" + "\n"); +} + +// =================================================================== + +void ImmutableMessageGenerator::GenerateExtensionRegistrationCode( + io::Printer* printer) { + for (int i = 0; i < descriptor_->extension_count(); i++) { + ImmutableExtensionGenerator(descriptor_->extension(i), context_) + .GenerateRegistrationCode(printer); + } + + for (int i = 0; i < descriptor_->nested_type_count(); i++) { + ImmutableMessageGenerator(descriptor_->nested_type(i), context_) + .GenerateExtensionRegistrationCode(printer); + } +} + +// =================================================================== +void ImmutableMessageGenerator::GenerateParsingConstructor( + io::Printer* printer) { + std::unique_ptr<const FieldDescriptor*[]> sorted_fields( + SortFieldsByNumber(descriptor_)); + + printer->Print( + "private $classname$(\n" + " com.google.protobuf.CodedInputStream input,\n" + " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" + " throws com.google.protobuf.InvalidProtocolBufferException {\n", + "classname", descriptor_->name()); + printer->Indent(); + + // Initialize all fields to default. + printer->Print( + "this();\n" + "if (extensionRegistry == null) {\n" + " throw new java.lang.NullPointerException();\n" + "}\n"); + + // Use builder bits to track mutable repeated fields. + int totalBuilderBits = 0; + for (int i = 0; i < descriptor_->field_count(); i++) { + const ImmutableFieldGenerator& field = + field_generators_.get(descriptor_->field(i)); + totalBuilderBits += field.GetNumBitsForBuilder(); + } + int totalBuilderInts = (totalBuilderBits + 31) / 32; + for (int i = 0; i < totalBuilderInts; i++) { + printer->Print("int mutable_$bit_field_name$ = 0;\n", "bit_field_name", + GetBitFieldName(i)); + } + + printer->Print( + "com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n" + " com.google.protobuf.UnknownFieldSet.newBuilder();\n"); + + printer->Print("try {\n"); + printer->Indent(); + + printer->Print( + "boolean done = false;\n" + "while (!done) {\n"); + printer->Indent(); + + printer->Print( + "int tag = input.readTag();\n" + "switch (tag) {\n"); + printer->Indent(); + + printer->Print( + "case 0:\n" // zero signals EOF / limit reached + " done = true;\n" + " break;\n"); + + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = sorted_fields[i]; + uint32_t tag = WireFormatLite::MakeTag( + field->number(), WireFormat::WireTypeForFieldType(field->type())); + + printer->Print("case $tag$: {\n", "tag", + StrCat(static_cast<int32_t>(tag))); + printer->Indent(); + + field_generators_.get(field).GenerateParsingCode(printer); + + printer->Outdent(); + printer->Print( + " break;\n" + "}\n"); + + if (field->is_packable()) { + // To make packed = true wire compatible, we generate parsing code from a + // packed version of this field regardless of field->options().packed(). + uint32_t packed_tag = WireFormatLite::MakeTag( + field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED); + printer->Print("case $tag$: {\n", "tag", + StrCat(static_cast<int32_t>(packed_tag))); + printer->Indent(); + + field_generators_.get(field).GenerateParsingCodeFromPacked(printer); + + printer->Outdent(); + printer->Print( + " break;\n" + "}\n"); + } + } + + printer->Print( + "default: {\n" + " if (!parseUnknownField(\n" + " input, unknownFields, extensionRegistry, tag)) {\n" + " done = true;\n" // it's an endgroup tag + " }\n" + " break;\n" + "}\n"); + + printer->Outdent(); + printer->Outdent(); + printer->Print( + " }\n" // switch (tag) + "}\n"); // while (!done) + + printer->Outdent(); + printer->Print( + "} catch (com.google.protobuf.InvalidProtocolBufferException e) {\n" + " throw e.setUnfinishedMessage(this);\n" + "} catch (java.io.IOException e) {\n" + " throw new com.google.protobuf.InvalidProtocolBufferException(\n" + " e).setUnfinishedMessage(this);\n" + "} finally {\n"); + printer->Indent(); + + // Make repeated field list immutable. + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = sorted_fields[i]; + field_generators_.get(field).GenerateParsingDoneCode(printer); + } + + // Make unknown fields immutable. + printer->Print("this.unknownFields = unknownFields.build();\n"); + + // Make extensions immutable. + printer->Print("makeExtensionsImmutable();\n"); + + printer->Outdent(); + printer->Outdent(); + printer->Print( + " }\n" // finally + "}\n"); +} + +// =================================================================== +void ImmutableMessageGenerator::GenerateParser(io::Printer* printer) { + printer->Print( + "$visibility$ static final com.google.protobuf.Parser<$classname$>\n" + " PARSER = new com.google.protobuf.AbstractParser<$classname$>() {\n", + "visibility", + ExposePublicParser(descriptor_->file()) ? "@java.lang.Deprecated public" + : "private", + "classname", descriptor_->name()); + printer->Indent(); + printer->Print( + "@java.lang.Override\n" + "public $classname$ parsePartialFrom(\n" + " com.google.protobuf.CodedInputStream input,\n" + " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" + " throws com.google.protobuf.InvalidProtocolBufferException {\n", + "classname", descriptor_->name()); + if (context_->HasGeneratedMethods(descriptor_)) { + printer->Print(" return new $classname$(input, extensionRegistry);\n", + "classname", descriptor_->name()); + } else { + // When parsing constructor isn't generated, use builder to parse + // messages. Note, will fallback to use reflection based mergeFieldFrom() + // in AbstractMessage.Builder. + printer->Indent(); + printer->Print( + "Builder builder = newBuilder();\n" + "try {\n" + " builder.mergeFrom(input, extensionRegistry);\n" + "} catch (com.google.protobuf.InvalidProtocolBufferException e) {\n" + " throw e.setUnfinishedMessage(builder.buildPartial());\n" + "} catch (java.io.IOException e) {\n" + " throw new com.google.protobuf.InvalidProtocolBufferException(\n" + " e.getMessage()).setUnfinishedMessage(\n" + " builder.buildPartial());\n" + "}\n" + "return builder.buildPartial();\n"); + printer->Outdent(); + } + printer->Print("}\n"); + printer->Outdent(); + printer->Print( + "};\n" + "\n"); + + printer->Print( + "public static com.google.protobuf.Parser<$classname$> parser() {\n" + " return PARSER;\n" + "}\n" + "\n" + "@java.lang.Override\n" + "public com.google.protobuf.Parser<$classname$> getParserForType() {\n" + " return PARSER;\n" + "}\n" + "\n", + "classname", descriptor_->name()); +} + +// =================================================================== +void ImmutableMessageGenerator::GenerateInitializers(io::Printer* printer) { + for (int i = 0; i < descriptor_->field_count(); i++) { + if (!IsRealOneof(descriptor_->field(i))) { + field_generators_.get(descriptor_->field(i)) + .GenerateInitializationCode(printer); + } + } +} + +// =================================================================== +void ImmutableMessageGenerator::GenerateMutableCopy(io::Printer* printer) { + printer->Print( + "protected com.google.protobuf.MutableMessage\n" + " internalMutableDefault() {\n" + " return MutableDefaultLoader.get();\n" + "}\n" + "\n" + "private static final class MutableDefaultLoader {\n" + " private static final java.lang.Object defaultOrRuntimeException;\n" + " static {\n" + " java.lang.Object local;\n" + " try {\n" + " local = internalMutableDefault(\"$mutable_name$\");\n" + " } catch (java.lang.RuntimeException e) {\n" + " local = e;\n" + " }\n" + " defaultOrRuntimeException = local;\n" + " }\n" + "\n" + " private MutableDefaultLoader() {}\n" + "\n" + " public static com.google.protobuf.MutableMessage get() {\n" + " if (defaultOrRuntimeException\n" + " instanceof java.lang.RuntimeException) {\n" + " throw (java.lang.RuntimeException) defaultOrRuntimeException;\n" + " }\n" + " return\n" + " (com.google.protobuf.MutableMessage) " + "defaultOrRuntimeException;\n" + " }\n" + "}\n", + "mutable_name", name_resolver_->GetJavaMutableClassName(descriptor_)); +} + +void ImmutableMessageGenerator::GenerateKotlinDsl(io::Printer* printer) const { + printer->Print( + "@kotlin.OptIn" + "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n" + "@com.google.protobuf.kotlin.ProtoDslMarker\n"); + printer->Print( + "public class Dsl private constructor(\n" + " private val _builder: $message$.Builder\n" + ") {\n" + " public companion object {\n" + " @kotlin.jvm.JvmSynthetic\n" + " @kotlin.PublishedApi\n" + " internal fun _create(builder: $message$.Builder): Dsl = " + "Dsl(builder)\n" + " }\n" + "\n" + " @kotlin.jvm.JvmSynthetic\n" + " @kotlin.PublishedApi\n" + " internal fun _build(): $message$ = _builder.build()\n", + "message", name_resolver_->GetClassName(descriptor_, true)); + + printer->Indent(); + + for (int i = 0; i < descriptor_->field_count(); i++) { + printer->Print("\n"); + field_generators_.get(descriptor_->field(i)) + .GenerateKotlinDslMembers(printer); + } + + for (auto oneof : oneofs_) { + printer->Print( + "public val $oneof_name$Case: $message$.$oneof_capitalized_name$Case\n" + " @JvmName(\"get$oneof_capitalized_name$Case\")\n" + " get() = _builder.get$oneof_capitalized_name$Case()\n\n" + "public fun clear$oneof_capitalized_name$() {\n" + " _builder.clear$oneof_capitalized_name$()\n" + "}\n", + "oneof_name", context_->GetOneofGeneratorInfo(oneof)->name, + "oneof_capitalized_name", + context_->GetOneofGeneratorInfo(oneof)->capitalized_name, "message", + name_resolver_->GetClassName(descriptor_, true)); + } + + if (descriptor_->extension_range_count() > 0) { + GenerateKotlinExtensions(printer); + } + + printer->Outdent(); + printer->Print("}\n"); +} + +void ImmutableMessageGenerator::GenerateKotlinMembers( + io::Printer* printer) const { + printer->Print( + "@kotlin.jvm.JvmSynthetic\n" + "public inline fun $camelcase_name$(block: $message_kt$.Dsl.() -> " + "kotlin.Unit): " + "$message$ " + "=\n" + " $message_kt$.Dsl._create($message$.newBuilder()).apply { block() " + "}._build()\n", + "camelcase_name", name_resolver_->GetKotlinFactoryName(descriptor_), + "message_kt", name_resolver_->GetKotlinExtensionsClassName(descriptor_), + "message", name_resolver_->GetClassName(descriptor_, true)); + + printer->Print("public object $name$Kt {\n", "name", descriptor_->name()); + printer->Indent(); + GenerateKotlinDsl(printer); + for (int i = 0; i < descriptor_->nested_type_count(); i++) { + if (IsMapEntry(descriptor_->nested_type(i))) continue; + ImmutableMessageGenerator(descriptor_->nested_type(i), context_) + .GenerateKotlinMembers(printer); + } + printer->Outdent(); + printer->Print("}\n"); +} + +void ImmutableMessageGenerator::GenerateTopLevelKotlinMembers( + io::Printer* printer) const { + printer->Print( + "@kotlin.jvm.JvmSynthetic\n" + "public inline fun $message$.copy(block: $message_kt$.Dsl.() -> " + "kotlin.Unit): " + "$message$ =\n" + " $message_kt$.Dsl._create(this.toBuilder()).apply { block() " + "}._build()\n", + "message", name_resolver_->GetClassName(descriptor_, true), "message_kt", + name_resolver_->GetKotlinExtensionsClassName(descriptor_)); + + for (int i = 0; i < descriptor_->nested_type_count(); i++) { + if (IsMapEntry(descriptor_->nested_type(i))) continue; + ImmutableMessageGenerator(descriptor_->nested_type(i), context_) + .GenerateTopLevelKotlinMembers(printer); + } +} + +void ImmutableMessageGenerator::GenerateKotlinExtensions( + io::Printer* printer) const { + std::string message_name = name_resolver_->GetClassName(descriptor_, true); + + printer->Print( + "@Suppress(\"UNCHECKED_CAST\")\n" + "@kotlin.jvm.JvmSynthetic\n" + "public operator fun <T> get(extension: " + "com.google.protobuf.ExtensionLite<$message$, T>): T {\n" + " return if (extension.isRepeated) {\n" + " get(extension as com.google.protobuf.ExtensionLite<$message$, " + "List<*>>) as T\n" + " } else {\n" + " _builder.getExtension(extension)\n" + " }\n" + "}\n\n", + "message", message_name); + + printer->Print( + "@kotlin.jvm.JvmSynthetic\n" + "@kotlin.OptIn" + "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n" + "@kotlin.jvm.JvmName(\"-getRepeatedExtension\")\n" + "public operator fun <E> get(\n" + " extension: com.google.protobuf.ExtensionLite<$message$, List<E>>\n" + "): com.google.protobuf.kotlin.ExtensionList<E, $message$> {\n" + " return com.google.protobuf.kotlin.ExtensionList(extension, " + "_builder.getExtension(extension))\n" + "}\n\n", + "message", message_name); + + printer->Print( + "@kotlin.jvm.JvmSynthetic\n" + "public operator fun contains(extension: " + "com.google.protobuf.ExtensionLite<$message$, *>): " + "Boolean {\n" + " return _builder.hasExtension(extension)\n" + "}\n\n", + "message", message_name); + + printer->Print( + "@kotlin.jvm.JvmSynthetic\n" + "public fun clear(extension: " + "com.google.protobuf.ExtensionLite<$message$, *>) " + "{\n" + " _builder.clearExtension(extension)\n" + "}\n\n", + "message", message_name); + + printer->Print( + "@kotlin.jvm.JvmSynthetic\n" + "@kotlin.PublishedApi\n" + "internal fun <T> setExtension(extension: " + "com.google.protobuf.ExtensionLite<$message$, T>, " + "value: T) {\n" + " _builder.setExtension(extension, value)\n" + "}\n\n", + "message", message_name); + + printer->Print( + "@kotlin.jvm.JvmSynthetic\n" + "@Suppress(\"NOTHING_TO_INLINE\")\n" + "public inline operator fun <T : Comparable<T>> set(\n" + " extension: com.google.protobuf.ExtensionLite<$message$, T>,\n" + " value: T\n" + ") {\n" + " setExtension(extension, value)\n" + "}\n\n", + "message", message_name); + + printer->Print( + "@kotlin.jvm.JvmSynthetic\n" + "@Suppress(\"NOTHING_TO_INLINE\")\n" + "public inline operator fun set(\n" + " extension: com.google.protobuf.ExtensionLite<$message$, " + "com.google.protobuf.ByteString>,\n" + " value: com.google.protobuf.ByteString\n" + ") {\n" + " setExtension(extension, value)\n" + "}\n\n", + "message", message_name); + + printer->Print( + "@kotlin.jvm.JvmSynthetic\n" + "@Suppress(\"NOTHING_TO_INLINE\")\n" + "public inline operator fun <T : com.google.protobuf.MessageLite> set(\n" + " extension: com.google.protobuf.ExtensionLite<$message$, T>,\n" + " value: T\n" + ") {\n" + " setExtension(extension, value)\n" + "}\n\n", + "message", message_name); + + printer->Print( + "@kotlin.jvm.JvmSynthetic\n" + "public fun <E> com.google.protobuf.kotlin.ExtensionList<E, " + "$message$>.add(value: E) {\n" + " _builder.addExtension(this.extension, value)\n" + "}\n\n", + "message", message_name); + + printer->Print( + "@kotlin.jvm.JvmSynthetic\n" + "@Suppress(\"NOTHING_TO_INLINE\")\n" + "public inline operator fun <E> " + "com.google.protobuf.kotlin.ExtensionList<E, " + "$message$>.plusAssign" + "(value: E) {\n" + " add(value)\n" + "}\n\n", + "message", message_name); + + printer->Print( + "@kotlin.jvm.JvmSynthetic\n" + "public fun <E> com.google.protobuf.kotlin.ExtensionList<E, " + "$message$>.addAll(values: Iterable<E>) {\n" + " for (value in values) {\n" + " add(value)\n" + " }\n" + "}\n\n", + "message", message_name); + + printer->Print( + "@kotlin.jvm.JvmSynthetic\n" + "@Suppress(\"NOTHING_TO_INLINE\")\n" + "public inline operator fun <E> " + "com.google.protobuf.kotlin.ExtensionList<E, " + "$message$>.plusAssign(values: " + "Iterable<E>) {\n" + " addAll(values)\n" + "}\n\n", + "message", message_name); + + printer->Print( + "@kotlin.jvm.JvmSynthetic\n" + "public operator fun <E> com.google.protobuf.kotlin.ExtensionList<E, " + "$message$>.set(index: Int, value: " + "E) {\n" + " _builder.setExtension(this.extension, index, value)\n" + "}\n\n", + "message", message_name); + + printer->Print( + "@kotlin.jvm.JvmSynthetic\n" + "@Suppress(\"NOTHING_TO_INLINE\")\n" + "public inline fun com.google.protobuf.kotlin.ExtensionList<*, " + "$message$>.clear() {\n" + " clear(extension)\n" + "}\n\n", + "message", message_name); +} + +void ImmutableMessageGenerator::GenerateAnyMethods(io::Printer* printer) { + printer->Print( + "private static String getTypeUrl(\n" + " java.lang.String typeUrlPrefix,\n" + " com.google.protobuf.Descriptors.Descriptor descriptor) {\n" + " return typeUrlPrefix.endsWith(\"/\")\n" + " ? typeUrlPrefix + descriptor.getFullName()\n" + " : typeUrlPrefix + \"/\" + descriptor.getFullName();\n" + "}\n" + "\n" + "private static String getTypeNameFromTypeUrl(\n" + " java.lang.String typeUrl) {\n" + " int pos = typeUrl.lastIndexOf('/');\n" + " return pos == -1 ? \"\" : typeUrl.substring(pos + 1);\n" + "}\n" + "\n" + "public static <T extends com.google.protobuf.Message> Any pack(\n" + " T message) {\n" + " return Any.newBuilder()\n" + " .setTypeUrl(getTypeUrl(\"type.googleapis.com\",\n" + " message.getDescriptorForType()))\n" + " .setValue(message.toByteString())\n" + " .build();\n" + "}\n" + "\n" + "/**\n" + " * Packs a message using the given type URL prefix. The type URL will\n" + " * be constructed by concatenating the message type's full name to the\n" + " * prefix with an optional \"/\" separator if the prefix doesn't end\n" + " * with \"/\" already.\n" + " */\n" + "public static <T extends com.google.protobuf.Message> Any pack(\n" + " T message, java.lang.String typeUrlPrefix) {\n" + " return Any.newBuilder()\n" + " .setTypeUrl(getTypeUrl(typeUrlPrefix,\n" + " message.getDescriptorForType()))\n" + " .setValue(message.toByteString())\n" + " .build();\n" + "}\n" + "\n" + "public <T extends com.google.protobuf.Message> boolean is(\n" + " java.lang.Class<T> clazz) {\n" + " T defaultInstance =\n" + " com.google.protobuf.Internal.getDefaultInstance(clazz);\n" + " return getTypeNameFromTypeUrl(getTypeUrl()).equals(\n" + " defaultInstance.getDescriptorForType().getFullName());\n" + "}\n" + "\n" + "private volatile com.google.protobuf.Message cachedUnpackValue;\n" + "\n" + "@java.lang.SuppressWarnings(\"unchecked\")\n" + "public <T extends com.google.protobuf.Message> T unpack(\n" + " java.lang.Class<T> clazz)\n" + " throws com.google.protobuf.InvalidProtocolBufferException {\n" + " boolean invalidClazz = false;\n" + " if (cachedUnpackValue != null) {\n" + " if (cachedUnpackValue.getClass() == clazz) {\n" + " return (T) cachedUnpackValue;\n" + " }\n" + " invalidClazz = true;\n" + " }\n" + " if (invalidClazz || !is(clazz)) {\n" + " throw new com.google.protobuf.InvalidProtocolBufferException(\n" + " \"Type of the Any message does not match the given class.\");\n" + " }\n" + " T defaultInstance =\n" + " com.google.protobuf.Internal.getDefaultInstance(clazz);\n" + " T result = (T) defaultInstance.getParserForType()\n" + " .parseFrom(getValue());\n" + " cachedUnpackValue = result;\n" + " return result;\n" + "}\n"); +} + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/java/java_message.h b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_message.h new file mode 100644 index 00000000..7ee4e431 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_message.h @@ -0,0 +1,153 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_H__ + +#include <map> +#include <string> +#include <compiler/java/java_field.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { +class Context; // context.h +class ClassNameResolver; // name_resolver.h +} // namespace java +} // namespace compiler +namespace io { +class Printer; // printer.h +} +} // namespace protobuf +} // namespace google + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +static const int kMaxStaticSize = 1 << 15; // aka 32k + +class MessageGenerator { + public: + explicit MessageGenerator(const Descriptor* descriptor); + virtual ~MessageGenerator(); + + // All static variables have to be declared at the top-level of the file + // so that we can control initialization order, which is important for + // DescriptorProto bootstrapping to work. + virtual void GenerateStaticVariables(io::Printer* printer, + int* bytecode_estimate) = 0; + + // Output code which initializes the static variables generated by + // GenerateStaticVariables(). Returns an estimate of bytecode size. + virtual int GenerateStaticVariableInitializers(io::Printer* printer) = 0; + + // Generate the class itself. + virtual void Generate(io::Printer* printer) = 0; + + // Generates the base interface that both the class and its builder + // implement + virtual void GenerateInterface(io::Printer* printer) = 0; + + // Generate code to register all contained extensions with an + // ExtensionRegistry. + virtual void GenerateExtensionRegistrationCode(io::Printer* printer) = 0; + virtual void GenerateKotlinDsl(io::Printer* printer) const = 0; + virtual void GenerateKotlinMembers(io::Printer* printer) const = 0; + virtual void GenerateTopLevelKotlinMembers(io::Printer* printer) const = 0; + + protected: + const Descriptor* descriptor_; + std::set<const OneofDescriptor*> oneofs_; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageGenerator); +}; + +class ImmutableMessageGenerator : public MessageGenerator { + public: + ImmutableMessageGenerator(const Descriptor* descriptor, Context* context); + virtual ~ImmutableMessageGenerator(); + + void Generate(io::Printer* printer) override; + void GenerateInterface(io::Printer* printer) override; + void GenerateExtensionRegistrationCode(io::Printer* printer) override; + void GenerateStaticVariables(io::Printer* printer, + int* bytecode_estimate) override; + + // Returns an estimate of the number of bytes the printed code will compile to + int GenerateStaticVariableInitializers(io::Printer* printer) override; + void GenerateKotlinDsl(io::Printer* printer) const override; + void GenerateKotlinMembers(io::Printer* printer) const override; + void GenerateTopLevelKotlinMembers(io::Printer* printer) const override; + + private: + void GenerateFieldAccessorTable(io::Printer* printer, int* bytecode_estimate); + + // Returns an estimate of the number of bytes the printed code will compile to + int GenerateFieldAccessorTableInitializer(io::Printer* printer); + + void GenerateMessageSerializationMethods(io::Printer* printer); + void GenerateParseFromMethods(io::Printer* printer); + void GenerateSerializeOneField(io::Printer* printer, + const FieldDescriptor* field); + void GenerateSerializeOneExtensionRange( + io::Printer* printer, const Descriptor::ExtensionRange* range); + + void GenerateBuilder(io::Printer* printer); + void GenerateIsInitialized(io::Printer* printer); + void GenerateDescriptorMethods(io::Printer* printer); + void GenerateInitializers(io::Printer* printer); + void GenerateEqualsAndHashCode(io::Printer* printer); + void GenerateParser(io::Printer* printer); + void GenerateParsingConstructor(io::Printer* printer); + void GenerateMutableCopy(io::Printer* printer); + void GenerateKotlinExtensions(io::Printer* printer) const; + void GenerateAnyMethods(io::Printer* printer); + + Context* context_; + ClassNameResolver* name_resolver_; + FieldGeneratorMap<ImmutableFieldGenerator> field_generators_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableMessageGenerator); +}; + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/java/java_message_builder.cc b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_message_builder.cc new file mode 100644 index 00000000..ac72da8e --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_message_builder.cc @@ -0,0 +1,712 @@ +// 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. + +// Author: dweis@google.com (Daniel Weis) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <compiler/java/java_message_builder.h> + +#include <algorithm> +#include <map> +#include <memory> +#include <vector> + +#include <compiler/java/java_context.h> +#include <compiler/java/java_doc_comment.h> +#include <compiler/java/java_enum.h> +#include <compiler/java/java_extension.h> +#include <compiler/java/java_generator_factory.h> +#include <compiler/java/java_helpers.h> +#include <compiler/java/java_name_resolver.h> +#include <descriptor.pb.h> +#include <io/coded_stream.h> +#include <io/printer.h> +#include <wire_format.h> +#include <stubs/strutil.h> +#include <stubs/substitute.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +namespace { +std::string MapValueImmutableClassdName(const Descriptor* descriptor, + ClassNameResolver* name_resolver) { + const FieldDescriptor* value_field = descriptor->FindFieldByName("value"); + GOOGLE_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, value_field->type()); + return name_resolver->GetImmutableClassName(value_field->message_type()); +} +} // namespace + +MessageBuilderGenerator::MessageBuilderGenerator(const Descriptor* descriptor, + Context* context) + : descriptor_(descriptor), + context_(context), + name_resolver_(context->GetNameResolver()), + field_generators_(descriptor, context_) { + GOOGLE_CHECK(HasDescriptorMethods(descriptor->file(), context->EnforceLite())) + << "Generator factory error: A non-lite message generator is used to " + "generate lite messages."; + for (int i = 0; i < descriptor_->field_count(); i++) { + if (IsRealOneof(descriptor_->field(i))) { + oneofs_.insert(descriptor_->field(i)->containing_oneof()); + } + } +} + +MessageBuilderGenerator::~MessageBuilderGenerator() {} + +void MessageBuilderGenerator::Generate(io::Printer* printer) { + WriteMessageDocComment(printer, descriptor_); + if (descriptor_->extension_range_count() > 0) { + printer->Print( + "public static final class Builder extends\n" + " com.google.protobuf.GeneratedMessage$ver$.ExtendableBuilder<\n" + " $classname$, Builder> implements\n" + " $extra_interfaces$\n" + " $classname$OrBuilder {\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_), + "extra_interfaces", ExtraBuilderInterfaces(descriptor_), "ver", + GeneratedCodeVersionSuffix()); + } else { + printer->Print( + "public static final class Builder extends\n" + " com.google.protobuf.GeneratedMessage$ver$.Builder<Builder> " + "implements\n" + " $extra_interfaces$\n" + " $classname$OrBuilder {\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_), + "extra_interfaces", ExtraBuilderInterfaces(descriptor_), "ver", + GeneratedCodeVersionSuffix()); + } + printer->Indent(); + + GenerateDescriptorMethods(printer); + GenerateCommonBuilderMethods(printer); + + if (context_->HasGeneratedMethods(descriptor_)) { + GenerateIsInitialized(printer); + GenerateBuilderParsingMethods(printer); + } + + // oneof + std::map<std::string, std::string> vars; + for (auto oneof : oneofs_) { + vars["oneof_name"] = context_->GetOneofGeneratorInfo(oneof)->name; + vars["oneof_capitalized_name"] = + context_->GetOneofGeneratorInfo(oneof)->capitalized_name; + vars["oneof_index"] = StrCat(oneof->index()); + // oneofCase_ and oneof_ + printer->Print(vars, + "private int $oneof_name$Case_ = 0;\n" + "private java.lang.Object $oneof_name$_;\n"); + // oneofCase() and clearOneof() + printer->Print(vars, + "public $oneof_capitalized_name$Case\n" + " get$oneof_capitalized_name$Case() {\n" + " return $oneof_capitalized_name$Case.forNumber(\n" + " $oneof_name$Case_);\n" + "}\n" + "\n" + "public Builder clear$oneof_capitalized_name$() {\n" + " $oneof_name$Case_ = 0;\n" + " $oneof_name$_ = null;\n"); + printer->Print(" onChanged();\n"); + printer->Print( + " return this;\n" + "}\n" + "\n"); + } + + // Integers for bit fields. + int totalBits = 0; + for (int i = 0; i < descriptor_->field_count(); i++) { + totalBits += + field_generators_.get(descriptor_->field(i)).GetNumBitsForBuilder(); + } + int totalInts = (totalBits + 31) / 32; + for (int i = 0; i < totalInts; i++) { + printer->Print("private int $bit_field_name$;\n", "bit_field_name", + GetBitFieldName(i)); + } + + for (int i = 0; i < descriptor_->field_count(); i++) { + printer->Print("\n"); + field_generators_.get(descriptor_->field(i)) + .GenerateBuilderMembers(printer); + } + + // Override methods declared in GeneratedMessage to return the concrete + // generated type so callsites won't depend on GeneratedMessage. This + // is needed to keep binary compatibility when we change generated code + // to subclass a different GeneratedMessage class (e.g., in v3.0.0 release + // we changed all generated code to subclass GeneratedMessageV3). + printer->Print( + "@java.lang.Override\n" + "public final Builder setUnknownFields(\n" + " final com.google.protobuf.UnknownFieldSet unknownFields) {\n" + " return super.setUnknownFields(unknownFields);\n" + "}\n" + "\n" + "@java.lang.Override\n" + "public final Builder mergeUnknownFields(\n" + " final com.google.protobuf.UnknownFieldSet unknownFields) {\n" + " return super.mergeUnknownFields(unknownFields);\n" + "}\n" + "\n"); + + printer->Print( + "\n" + "// @@protoc_insertion_point(builder_scope:$full_name$)\n", + "full_name", descriptor_->full_name()); + + printer->Outdent(); + printer->Print("}\n"); +} + +// =================================================================== + +void MessageBuilderGenerator::GenerateDescriptorMethods(io::Printer* printer) { + if (!descriptor_->options().no_standard_descriptor_accessor()) { + printer->Print( + "public static final com.google.protobuf.Descriptors.Descriptor\n" + " getDescriptor() {\n" + " return $fileclass$.internal_$identifier$_descriptor;\n" + "}\n" + "\n", + "fileclass", name_resolver_->GetImmutableClassName(descriptor_->file()), + "identifier", UniqueFileScopeIdentifier(descriptor_)); + } + std::vector<const FieldDescriptor*> map_fields; + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = descriptor_->field(i); + if (GetJavaType(field) == JAVATYPE_MESSAGE && + IsMapEntry(field->message_type())) { + map_fields.push_back(field); + } + } + if (!map_fields.empty()) { + printer->Print( + "@SuppressWarnings({\"rawtypes\"})\n" + "protected com.google.protobuf.MapField internalGetMapField(\n" + " int number) {\n" + " switch (number) {\n"); + printer->Indent(); + printer->Indent(); + for (int i = 0; i < map_fields.size(); ++i) { + const FieldDescriptor* field = map_fields[i]; + const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field); + printer->Print( + "case $number$:\n" + " return internalGet$capitalized_name$();\n", + "number", StrCat(field->number()), "capitalized_name", + info->capitalized_name); + } + printer->Print( + "default:\n" + " throw new RuntimeException(\n" + " \"Invalid map field number: \" + number);\n"); + printer->Outdent(); + printer->Outdent(); + printer->Print( + " }\n" + "}\n"); + printer->Print( + "@SuppressWarnings({\"rawtypes\"})\n" + "protected com.google.protobuf.MapField internalGetMutableMapField(\n" + " int number) {\n" + " switch (number) {\n"); + printer->Indent(); + printer->Indent(); + for (int i = 0; i < map_fields.size(); ++i) { + const FieldDescriptor* field = map_fields[i]; + const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field); + printer->Print( + "case $number$:\n" + " return internalGetMutable$capitalized_name$();\n", + "number", StrCat(field->number()), "capitalized_name", + info->capitalized_name); + } + printer->Print( + "default:\n" + " throw new RuntimeException(\n" + " \"Invalid map field number: \" + number);\n"); + printer->Outdent(); + printer->Outdent(); + printer->Print( + " }\n" + "}\n"); + } + printer->Print( + "@java.lang.Override\n" + "protected com.google.protobuf.GeneratedMessage$ver$.FieldAccessorTable\n" + " internalGetFieldAccessorTable() {\n" + " return $fileclass$.internal_$identifier$_fieldAccessorTable\n" + " .ensureFieldAccessorsInitialized(\n" + " $classname$.class, $classname$.Builder.class);\n" + "}\n" + "\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_), + "fileclass", name_resolver_->GetImmutableClassName(descriptor_->file()), + "identifier", UniqueFileScopeIdentifier(descriptor_), "ver", + GeneratedCodeVersionSuffix()); +} + +// =================================================================== + +void MessageBuilderGenerator::GenerateCommonBuilderMethods( + io::Printer* printer) { + printer->Print( + "// Construct using $classname$.newBuilder()\n" + "private Builder() {\n" + " maybeForceBuilderInitialization();\n" + "}\n" + "\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_)); + + printer->Print( + "private Builder(\n" + " com.google.protobuf.GeneratedMessage$ver$.BuilderParent parent) {\n" + " super(parent);\n" + " maybeForceBuilderInitialization();\n" + "}\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_), "ver", + GeneratedCodeVersionSuffix()); + + printer->Print( + "private void maybeForceBuilderInitialization() {\n" + " if (com.google.protobuf.GeneratedMessage$ver$\n" + " .alwaysUseFieldBuilders) {\n", + "ver", GeneratedCodeVersionSuffix()); + + printer->Indent(); + printer->Indent(); + for (int i = 0; i < descriptor_->field_count(); i++) { + if (!IsRealOneof(descriptor_->field(i))) { + field_generators_.get(descriptor_->field(i)) + .GenerateFieldBuilderInitializationCode(printer); + } + } + printer->Outdent(); + printer->Outdent(); + + printer->Print( + " }\n" + "}\n"); + + printer->Print( + "@java.lang.Override\n" + "public Builder clear() {\n" + " super.clear();\n"); + + printer->Indent(); + + for (int i = 0; i < descriptor_->field_count(); i++) { + if (!IsRealOneof(descriptor_->field(i))) { + field_generators_.get(descriptor_->field(i)) + .GenerateBuilderClearCode(printer); + } + } + + for (auto oneof : oneofs_) { + printer->Print( + "$oneof_name$Case_ = 0;\n" + "$oneof_name$_ = null;\n", + "oneof_name", context_->GetOneofGeneratorInfo(oneof)->name); + } + + printer->Outdent(); + + printer->Print( + " return this;\n" + "}\n" + "\n"); + + printer->Print( + "@java.lang.Override\n" + "public com.google.protobuf.Descriptors.Descriptor\n" + " getDescriptorForType() {\n" + " return $fileclass$.internal_$identifier$_descriptor;\n" + "}\n" + "\n", + "fileclass", name_resolver_->GetImmutableClassName(descriptor_->file()), + "identifier", UniqueFileScopeIdentifier(descriptor_)); + + // LITE runtime implements this in GeneratedMessageLite. + printer->Print( + "@java.lang.Override\n" + "public $classname$ getDefaultInstanceForType() {\n" + " return $classname$.getDefaultInstance();\n" + "}\n" + "\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_)); + + printer->Print( + "@java.lang.Override\n" + "public $classname$ build() {\n" + " $classname$ result = buildPartial();\n" + " if (!result.isInitialized()) {\n" + " throw newUninitializedMessageException(result);\n" + " }\n" + " return result;\n" + "}\n" + "\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_)); + + printer->Print( + "@java.lang.Override\n" + "public $classname$ buildPartial() {\n" + " $classname$ result = new $classname$(this);\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_)); + + printer->Indent(); + + int totalBuilderBits = 0; + int totalMessageBits = 0; + for (int i = 0; i < descriptor_->field_count(); i++) { + const ImmutableFieldGenerator& field = + field_generators_.get(descriptor_->field(i)); + totalBuilderBits += field.GetNumBitsForBuilder(); + totalMessageBits += field.GetNumBitsForMessage(); + } + int totalBuilderInts = (totalBuilderBits + 31) / 32; + int totalMessageInts = (totalMessageBits + 31) / 32; + + // Local vars for from and to bit fields to avoid accessing the builder and + // message over and over for these fields. Seems to provide a slight + // perforamance improvement in micro benchmark and this is also what proto1 + // code does. + for (int i = 0; i < totalBuilderInts; i++) { + printer->Print("int from_$bit_field_name$ = $bit_field_name$;\n", + "bit_field_name", GetBitFieldName(i)); + } + for (int i = 0; i < totalMessageInts; i++) { + printer->Print("int to_$bit_field_name$ = 0;\n", "bit_field_name", + GetBitFieldName(i)); + } + + // Output generation code for each field. + for (int i = 0; i < descriptor_->field_count(); i++) { + field_generators_.get(descriptor_->field(i)).GenerateBuildingCode(printer); + } + + // Copy the bit field results to the generated message + for (int i = 0; i < totalMessageInts; i++) { + printer->Print("result.$bit_field_name$ = to_$bit_field_name$;\n", + "bit_field_name", GetBitFieldName(i)); + } + + for (auto oneof : oneofs_) { + printer->Print("result.$oneof_name$Case_ = $oneof_name$Case_;\n", + "oneof_name", context_->GetOneofGeneratorInfo(oneof)->name); + } + + printer->Outdent(); + + printer->Print(" onBuilt();\n"); + + printer->Print( + " return result;\n" + "}\n" + "\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_)); + + // Override methods declared in GeneratedMessage to return the concrete + // generated type so callsites won't depend on GeneratedMessage. This + // is needed to keep binary compatibility when we change generated code + // to subclass a different GeneratedMessage class (e.g., in v3.0.0 release + // we changed all generated code to subclass GeneratedMessageV3). + printer->Print( + "@java.lang.Override\n" + "public Builder clone() {\n" + " return super.clone();\n" + "}\n" + "@java.lang.Override\n" + "public Builder setField(\n" + " com.google.protobuf.Descriptors.FieldDescriptor field,\n" + " java.lang.Object value) {\n" + " return super.setField(field, value);\n" + "}\n" + "@java.lang.Override\n" + "public Builder clearField(\n" + " com.google.protobuf.Descriptors.FieldDescriptor field) {\n" + " return super.clearField(field);\n" + "}\n" + "@java.lang.Override\n" + "public Builder clearOneof(\n" + " com.google.protobuf.Descriptors.OneofDescriptor oneof) {\n" + " return super.clearOneof(oneof);\n" + "}\n" + "@java.lang.Override\n" + "public Builder setRepeatedField(\n" + " com.google.protobuf.Descriptors.FieldDescriptor field,\n" + " int index, java.lang.Object value) {\n" + " return super.setRepeatedField(field, index, value);\n" + "}\n" + "@java.lang.Override\n" + "public Builder addRepeatedField(\n" + " com.google.protobuf.Descriptors.FieldDescriptor field,\n" + " java.lang.Object value) {\n" + " return super.addRepeatedField(field, value);\n" + "}\n"); + + if (descriptor_->extension_range_count() > 0) { + printer->Print( + "@java.lang.Override\n" + "public <Type> Builder setExtension(\n" + " com.google.protobuf.GeneratedMessage.GeneratedExtension<\n" + " $classname$, Type> extension,\n" + " Type value) {\n" + " return super.setExtension(extension, value);\n" + "}\n" + "@java.lang.Override\n" + "public <Type> Builder setExtension(\n" + " com.google.protobuf.GeneratedMessage.GeneratedExtension<\n" + " $classname$, java.util.List<Type>> extension,\n" + " int index, Type value) {\n" + " return super.setExtension(extension, index, value);\n" + "}\n" + "@java.lang.Override\n" + "public <Type> Builder addExtension(\n" + " com.google.protobuf.GeneratedMessage.GeneratedExtension<\n" + " $classname$, java.util.List<Type>> extension,\n" + " Type value) {\n" + " return super.addExtension(extension, value);\n" + "}\n" + "@java.lang.Override\n" + "public <Type> Builder clearExtension(\n" + " com.google.protobuf.GeneratedMessage.GeneratedExtension<\n" + " $classname$, ?> extension) {\n" + " return super.clearExtension(extension);\n" + "}\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_)); + } + + // ----------------------------------------------------------------- + + if (context_->HasGeneratedMethods(descriptor_)) { + printer->Print( + "@java.lang.Override\n" + "public Builder mergeFrom(com.google.protobuf.Message other) {\n" + " if (other instanceof $classname$) {\n" + " return mergeFrom(($classname$)other);\n" + " } else {\n" + " super.mergeFrom(other);\n" + " return this;\n" + " }\n" + "}\n" + "\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_)); + + printer->Print( + "public Builder mergeFrom($classname$ other) {\n" + // Optimization: If other is the default instance, we know none of its + // fields are set so we can skip the merge. + " if (other == $classname$.getDefaultInstance()) return this;\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_)); + printer->Indent(); + + for (int i = 0; i < descriptor_->field_count(); i++) { + if (!IsRealOneof(descriptor_->field(i))) { + field_generators_.get(descriptor_->field(i)) + .GenerateMergingCode(printer); + } + } + + // Merge oneof fields. + for (auto oneof : oneofs_) { + printer->Print("switch (other.get$oneof_capitalized_name$Case()) {\n", + "oneof_capitalized_name", + context_->GetOneofGeneratorInfo(oneof)->capitalized_name); + printer->Indent(); + for (int j = 0; j < oneof->field_count(); j++) { + const FieldDescriptor* field = oneof->field(j); + printer->Print("case $field_name$: {\n", "field_name", + ToUpper(field->name())); + printer->Indent(); + field_generators_.get(field).GenerateMergingCode(printer); + printer->Print("break;\n"); + printer->Outdent(); + printer->Print("}\n"); + } + printer->Print( + "case $cap_oneof_name$_NOT_SET: {\n" + " break;\n" + "}\n", + "cap_oneof_name", + ToUpper(context_->GetOneofGeneratorInfo(oneof)->name)); + printer->Outdent(); + printer->Print("}\n"); + } + + printer->Outdent(); + + // if message type has extensions + if (descriptor_->extension_range_count() > 0) { + printer->Print(" this.mergeExtensionFields(other);\n"); + } + + printer->Print(" this.mergeUnknownFields(other.unknownFields);\n"); + + printer->Print(" onChanged();\n"); + + printer->Print( + " return this;\n" + "}\n" + "\n"); + } +} + +// =================================================================== + +void MessageBuilderGenerator::GenerateBuilderParsingMethods( + io::Printer* printer) { + printer->Print( + "@java.lang.Override\n" + "public Builder mergeFrom(\n" + " com.google.protobuf.CodedInputStream input,\n" + " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" + " throws java.io.IOException {\n" + " $classname$ parsedMessage = null;\n" + " try {\n" + " parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n" + " } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n" + " parsedMessage = ($classname$) e.getUnfinishedMessage();\n" + " throw e.unwrapIOException();\n" + " } finally {\n" + " if (parsedMessage != null) {\n" + " mergeFrom(parsedMessage);\n" + " }\n" + " }\n" + " return this;\n" + "}\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_)); +} + +// =================================================================== + +void MessageBuilderGenerator::GenerateIsInitialized(io::Printer* printer) { + printer->Print( + "@java.lang.Override\n" + "public final boolean isInitialized() {\n"); + printer->Indent(); + + // Check that all required fields in this message are set. + // TODO(kenton): We can optimize this when we switch to putting all the + // "has" fields into a single bitfield. + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = descriptor_->field(i); + const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field); + + if (field->is_required()) { + printer->Print( + "if (!has$name$()) {\n" + " return false;\n" + "}\n", + "name", info->capitalized_name); + } + } + + // Now check that all embedded messages are initialized. + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = descriptor_->field(i); + const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field); + if (GetJavaType(field) == JAVATYPE_MESSAGE && + HasRequiredFields(field->message_type())) { + switch (field->label()) { + case FieldDescriptor::LABEL_REQUIRED: + printer->Print( + "if (!get$name$().isInitialized()) {\n" + " return false;\n" + "}\n", + "type", + name_resolver_->GetImmutableClassName(field->message_type()), + "name", info->capitalized_name); + break; + case FieldDescriptor::LABEL_OPTIONAL: + printer->Print( + "if (has$name$()) {\n" + " if (!get$name$().isInitialized()) {\n" + " return false;\n" + " }\n" + "}\n", + "name", info->capitalized_name); + break; + case FieldDescriptor::LABEL_REPEATED: + if (IsMapEntry(field->message_type())) { + printer->Print( + "for ($type$ item : get$name$Map().values()) {\n" + " if (!item.isInitialized()) {\n" + " return false;\n" + " }\n" + "}\n", + "type", + MapValueImmutableClassdName(field->message_type(), + name_resolver_), + "name", info->capitalized_name); + } else { + printer->Print( + "for (int i = 0; i < get$name$Count(); i++) {\n" + " if (!get$name$(i).isInitialized()) {\n" + " return false;\n" + " }\n" + "}\n", + "type", + name_resolver_->GetImmutableClassName(field->message_type()), + "name", info->capitalized_name); + } + break; + } + } + } + + if (descriptor_->extension_range_count() > 0) { + printer->Print( + "if (!extensionsAreInitialized()) {\n" + " return false;\n" + "}\n"); + } + + printer->Outdent(); + + printer->Print( + " return true;\n" + "}\n" + "\n"); +} + +// =================================================================== + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/java/java_message_builder.h b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_message_builder.h new file mode 100644 index 00000000..7d6da17d --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_message_builder.h @@ -0,0 +1,89 @@ +// 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. + +// Author: dweis@google.com (Daniel Weis) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_BUILDER_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_BUILDER_H__ + +#include <map> +#include <string> +#include <compiler/java/java_field.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { +class Context; // context.h +class ClassNameResolver; // name_resolver.h +} // namespace java +} // namespace compiler +namespace io { +class Printer; // printer.h +} +} // namespace protobuf +} // namespace google + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +class MessageBuilderGenerator { + public: + explicit MessageBuilderGenerator(const Descriptor* descriptor, + Context* context); + virtual ~MessageBuilderGenerator(); + + virtual void Generate(io::Printer* printer); + + private: + void GenerateCommonBuilderMethods(io::Printer* printer); + void GenerateDescriptorMethods(io::Printer* printer); + void GenerateBuilderParsingMethods(io::Printer* printer); + void GenerateIsInitialized(io::Printer* printer); + + const Descriptor* descriptor_; + Context* context_; + ClassNameResolver* name_resolver_; + FieldGeneratorMap<ImmutableFieldGenerator> field_generators_; + std::set<const OneofDescriptor*> oneofs_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageBuilderGenerator); +}; + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_BUILDER_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/java/java_message_builder_lite.cc b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_message_builder_lite.cc new file mode 100644 index 00000000..83f5d072 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_message_builder_lite.cc @@ -0,0 +1,151 @@ +// 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. + +// Author: dweis@google.com (Daniel Weis) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <compiler/java/java_message_builder_lite.h> + +#include <algorithm> +#include <map> +#include <memory> +#include <vector> + +#include <compiler/java/java_context.h> +#include <compiler/java/java_doc_comment.h> +#include <compiler/java/java_enum.h> +#include <compiler/java/java_extension.h> +#include <compiler/java/java_generator_factory.h> +#include <compiler/java/java_helpers.h> +#include <compiler/java/java_name_resolver.h> +#include <descriptor.pb.h> +#include <io/coded_stream.h> +#include <io/printer.h> +#include <wire_format.h> +#include <stubs/strutil.h> +#include <stubs/substitute.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +MessageBuilderLiteGenerator::MessageBuilderLiteGenerator( + const Descriptor* descriptor, Context* context) + : descriptor_(descriptor), + context_(context), + name_resolver_(context->GetNameResolver()), + field_generators_(descriptor, context_) { + GOOGLE_CHECK(!HasDescriptorMethods(descriptor->file(), context->EnforceLite())) + << "Generator factory error: A lite message generator is used to " + "generate non-lite messages."; + for (int i = 0; i < descriptor_->field_count(); i++) { + if (IsRealOneof(descriptor_->field(i))) { + oneofs_.insert(descriptor_->field(i)->containing_oneof()); + } + } +} + +MessageBuilderLiteGenerator::~MessageBuilderLiteGenerator() {} + +void MessageBuilderLiteGenerator::Generate(io::Printer* printer) { + WriteMessageDocComment(printer, descriptor_); + printer->Print( + "public static final class Builder extends\n" + " com.google.protobuf.GeneratedMessageLite.$extendible$Builder<\n" + " $classname$, Builder> implements\n" + " $extra_interfaces$\n" + " $classname$OrBuilder {\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_), + "extra_interfaces", ExtraBuilderInterfaces(descriptor_), "extendible", + descriptor_->extension_range_count() > 0 ? "Extendable" : ""); + printer->Indent(); + + GenerateCommonBuilderMethods(printer); + + // oneof + std::map<std::string, std::string> vars; + for (auto oneof : oneofs_) { + vars["oneof_name"] = context_->GetOneofGeneratorInfo(oneof)->name; + vars["oneof_capitalized_name"] = + context_->GetOneofGeneratorInfo(oneof)->capitalized_name; + vars["oneof_index"] = StrCat(oneof->index()); + + // oneofCase() and clearOneof() + printer->Print(vars, + "@java.lang.Override\n" + "public $oneof_capitalized_name$Case\n" + " get$oneof_capitalized_name$Case() {\n" + " return instance.get$oneof_capitalized_name$Case();\n" + "}\n" + "\n" + "public Builder clear$oneof_capitalized_name$() {\n" + " copyOnWrite();\n" + " instance.clear$oneof_capitalized_name$();\n" + " return this;\n" + "}\n" + "\n"); + } + + for (int i = 0; i < descriptor_->field_count(); i++) { + printer->Print("\n"); + field_generators_.get(descriptor_->field(i)) + .GenerateBuilderMembers(printer); + } + + printer->Print( + "\n" + "// @@protoc_insertion_point(builder_scope:$full_name$)\n", + "full_name", descriptor_->full_name()); + + printer->Outdent(); + printer->Print("}\n"); +} + +// =================================================================== + +void MessageBuilderLiteGenerator::GenerateCommonBuilderMethods( + io::Printer* printer) { + printer->Print( + "// Construct using $classname$.newBuilder()\n" + "private Builder() {\n" + " super(DEFAULT_INSTANCE);\n" + "}\n" + "\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_)); +} + +// =================================================================== + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/java/java_message_builder_lite.h b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_message_builder_lite.h new file mode 100644 index 00000000..8ad4e94b --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_message_builder_lite.h @@ -0,0 +1,86 @@ +// 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. + +// Author: dweis@google.com (Daniel Weis) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_BUILDER_LITE_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_BUILDER_LITE_H__ + +#include <map> +#include <string> +#include <compiler/java/java_field.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { +class Context; // context.h +class ClassNameResolver; // name_resolver.h +} // namespace java +} // namespace compiler +namespace io { +class Printer; // printer.h +} +} // namespace protobuf +} // namespace google + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +class MessageBuilderLiteGenerator { + public: + explicit MessageBuilderLiteGenerator(const Descriptor* descriptor, + Context* context); + virtual ~MessageBuilderLiteGenerator(); + + virtual void Generate(io::Printer* printer); + + private: + void GenerateCommonBuilderMethods(io::Printer* printer); + + const Descriptor* descriptor_; + Context* context_; + ClassNameResolver* name_resolver_; + FieldGeneratorMap<ImmutableFieldLiteGenerator> field_generators_; + std::set<const OneofDescriptor*> oneofs_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageBuilderLiteGenerator); +}; + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_BUILDER_LITE_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/java/java_message_field.cc b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_message_field.cc new file mode 100644 index 00000000..394735d1 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_message_field.cc @@ -0,0 +1,1494 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <map> +#include <string> + +#include <compiler/java/java_context.h> +#include <compiler/java/java_doc_comment.h> +#include <compiler/java/java_helpers.h> +#include <compiler/java/java_message_field.h> +#include <compiler/java/java_name_resolver.h> +#include <io/printer.h> +#include <wire_format.h> +#include <stubs/strutil.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + + +namespace { + +void SetMessageVariables(const FieldDescriptor* descriptor, int messageBitIndex, + int builderBitIndex, const FieldGeneratorInfo* info, + ClassNameResolver* name_resolver, + std::map<std::string, std::string>* variables) { + SetCommonFieldVariables(descriptor, info, variables); + + (*variables)["type"] = + name_resolver->GetImmutableClassName(descriptor->message_type()); + (*variables)["kt_type"] = (*variables)["type"]; + (*variables)["mutable_type"] = + name_resolver->GetMutableClassName(descriptor->message_type()); + (*variables)["group_or_message"] = + (GetType(descriptor) == FieldDescriptor::TYPE_GROUP) ? "Group" + : "Message"; + // TODO(birdo): Add @deprecated javadoc when generating javadoc is supported + // by the proto compiler + (*variables)["deprecation"] = + descriptor->options().deprecated() ? "@java.lang.Deprecated " : ""; + (*variables)["kt_deprecation"] = + descriptor->options().deprecated() + ? "@kotlin.Deprecated(message = \"Field " + (*variables)["name"] + + " is deprecated\") " + : ""; + (*variables)["on_changed"] = "onChanged();"; + (*variables)["ver"] = GeneratedCodeVersionSuffix(); + (*variables)["get_parser"] = + ExposePublicParser(descriptor->message_type()->file()) ? "PARSER" + : "parser()"; + + if (HasHasbit(descriptor)) { + // For singular messages and builders, one bit is used for the hasField bit. + (*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex); + (*variables)["get_has_field_bit_builder"] = GenerateGetBit(builderBitIndex); + + // Note that these have a trailing ";". + (*variables)["set_has_field_bit_message"] = + GenerateSetBit(messageBitIndex) + ";"; + (*variables)["set_has_field_bit_builder"] = + GenerateSetBit(builderBitIndex) + ";"; + (*variables)["clear_has_field_bit_builder"] = + GenerateClearBit(builderBitIndex) + ";"; + + (*variables)["is_field_present_message"] = GenerateGetBit(messageBitIndex); + } else { + (*variables)["set_has_field_bit_message"] = ""; + (*variables)["set_has_field_bit_builder"] = ""; + (*variables)["clear_has_field_bit_builder"] = ""; + + (*variables)["is_field_present_message"] = + (*variables)["name"] + "_ != null"; + } + + // For repeated builders, one bit is used for whether the array is immutable. + (*variables)["get_mutable_bit_builder"] = GenerateGetBit(builderBitIndex); + (*variables)["set_mutable_bit_builder"] = GenerateSetBit(builderBitIndex); + (*variables)["clear_mutable_bit_builder"] = GenerateClearBit(builderBitIndex); + + // For repeated fields, one bit is used for whether the array is immutable + // in the parsing constructor. + (*variables)["get_mutable_bit_parser"] = + GenerateGetBitMutableLocal(builderBitIndex); + (*variables)["set_mutable_bit_parser"] = + GenerateSetBitMutableLocal(builderBitIndex); + + (*variables)["get_has_field_bit_from_local"] = + GenerateGetBitFromLocal(builderBitIndex); + (*variables)["set_has_field_bit_to_local"] = + GenerateSetBitToLocal(messageBitIndex); +} + +} // namespace + +// =================================================================== + +ImmutableMessageFieldGenerator::ImmutableMessageFieldGenerator( + const FieldDescriptor* descriptor, int messageBitIndex, int builderBitIndex, + Context* context) + : descriptor_(descriptor), name_resolver_(context->GetNameResolver()) { + SetMessageVariables(descriptor, messageBitIndex, builderBitIndex, + context->GetFieldGeneratorInfo(descriptor), + name_resolver_, &variables_); +} + +ImmutableMessageFieldGenerator::~ImmutableMessageFieldGenerator() {} + +int ImmutableMessageFieldGenerator::GetNumBitsForMessage() const { + return HasHasbit(descriptor_) ? 1 : 0; +} + +int ImmutableMessageFieldGenerator::GetNumBitsForBuilder() const { + return GetNumBitsForMessage(); +} + +void ImmutableMessageFieldGenerator::GenerateInterfaceMembers( + io::Printer* printer) const { + // TODO(jonp): In the future, consider having a method specific to the + // interface so that builders can choose dynamically to either return a + // message or a nested builder, so that asking for the interface doesn't + // cause a message to ever be built. + WriteFieldAccessorDocComment(printer, descriptor_, HAZZER); + printer->Print(variables_, "$deprecation$boolean has$capitalized_name$();\n"); + WriteFieldAccessorDocComment(printer, descriptor_, GETTER); + printer->Print(variables_, "$deprecation$$type$ get$capitalized_name$();\n"); + + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$$type$OrBuilder get$capitalized_name$OrBuilder();\n"); +} + +void ImmutableMessageFieldGenerator::GenerateMembers( + io::Printer* printer) const { + printer->Print(variables_, "private $type$ $name$_;\n"); + PrintExtraFieldInfo(variables_, printer); + + if (HasHasbit(descriptor_)) { + WriteFieldAccessorDocComment(printer, descriptor_, HAZZER); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n" + " return $get_has_field_bit_message$;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldAccessorDocComment(printer, descriptor_, GETTER); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$public $type$ ${$get$capitalized_name$$}$() {\n" + " return $name$_ == null ? $type$.getDefaultInstance() : $name$_;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$public $type$OrBuilder " + "${$get$capitalized_name$OrBuilder$}$() {\n" + " return $name$_ == null ? $type$.getDefaultInstance() : $name$_;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + } else { + WriteFieldAccessorDocComment(printer, descriptor_, HAZZER); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n" + " return $name$_ != null;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldAccessorDocComment(printer, descriptor_, GETTER); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$public $type$ ${$get$capitalized_name$$}$() {\n" + " return $name$_ == null ? $type$.getDefaultInstance() : $name$_;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$public $type$OrBuilder " + "${$get$capitalized_name$OrBuilder$}$() {\n" + " return get$capitalized_name$();\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + } +} + +void ImmutableMessageFieldGenerator::PrintNestedBuilderCondition( + io::Printer* printer, const char* regular_case, + const char* nested_builder_case) const { + printer->Print(variables_, "if ($name$Builder_ == null) {\n"); + printer->Indent(); + printer->Print(variables_, regular_case); + printer->Outdent(); + printer->Print("} else {\n"); + printer->Indent(); + printer->Print(variables_, nested_builder_case); + printer->Outdent(); + printer->Print("}\n"); +} + +void ImmutableMessageFieldGenerator::PrintNestedBuilderFunction( + io::Printer* printer, const char* method_prototype, + const char* regular_case, const char* nested_builder_case, + const char* trailing_code) const { + printer->Print(variables_, method_prototype); + printer->Annotate("{", "}", descriptor_); + printer->Print(" {\n"); + printer->Indent(); + PrintNestedBuilderCondition(printer, regular_case, nested_builder_case); + if (trailing_code != NULL) { + printer->Print(variables_, trailing_code); + } + printer->Outdent(); + printer->Print("}\n"); +} + +void ImmutableMessageFieldGenerator::GenerateBuilderMembers( + io::Printer* printer) const { + // When using nested-builders, the code initially works just like the + // non-nested builder case. It only creates a nested builder lazily on + // demand and then forever delegates to it after creation. + + bool has_hasbit = HasHasbit(descriptor_); + + printer->Print(variables_, "private $type$ $name$_;\n"); + + printer->Print(variables_, + // If this builder is non-null, it is used and the other fields + // are ignored. + "private com.google.protobuf.SingleFieldBuilder$ver$<\n" + " $type$, $type$.Builder, $type$OrBuilder> $name$Builder_;" + "\n"); + + // The comments above the methods below are based on a hypothetical + // field of type "Field" called "Field". + + // boolean hasField() + WriteFieldAccessorDocComment(printer, descriptor_, HAZZER); + if (has_hasbit) { + printer->Print( + variables_, + "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n" + " return $get_has_field_bit_builder$;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + } else { + printer->Print( + variables_, + "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n" + " return $name$Builder_ != null || $name$_ != null;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + } + + // Field getField() + WriteFieldAccessorDocComment(printer, descriptor_, GETTER); + PrintNestedBuilderFunction( + printer, "$deprecation$public $type$ ${$get$capitalized_name$$}$()", + "return $name$_ == null ? $type$.getDefaultInstance() : $name$_;\n", + "return $name$Builder_.getMessage();\n", NULL); + + // Field.Builder setField(Field value) + WriteFieldDocComment(printer, descriptor_); + PrintNestedBuilderFunction( + printer, + "$deprecation$public Builder ${$set$capitalized_name$$}$($type$ value)", + + "if (value == null) {\n" + " throw new NullPointerException();\n" + "}\n" + "$name$_ = value;\n" + "$on_changed$\n", + + "$name$Builder_.setMessage(value);\n", + + "$set_has_field_bit_builder$\n" + "return this;\n"); + + // Field.Builder setField(Field.Builder builderForValue) + WriteFieldDocComment(printer, descriptor_); + PrintNestedBuilderFunction( + printer, + "$deprecation$public Builder ${$set$capitalized_name$$}$(\n" + " $type$.Builder builderForValue)", + + "$name$_ = builderForValue.build();\n" + "$on_changed$\n", + + "$name$Builder_.setMessage(builderForValue.build());\n", + + "$set_has_field_bit_builder$\n" + "return this;\n"); + + // Field.Builder mergeField(Field value) + WriteFieldDocComment(printer, descriptor_); + PrintNestedBuilderFunction( + printer, + "$deprecation$public Builder ${$merge$capitalized_name$$}$($type$ value)", + + has_hasbit + ? "if ($get_has_field_bit_builder$ &&\n" + " $name$_ != null &&\n" + " $name$_ != $type$.getDefaultInstance()) {\n" + " $name$_ =\n" + " $type$.newBuilder($name$_).mergeFrom(value).buildPartial();\n" + "} else {\n" + " $name$_ = value;\n" + "}\n" + "$on_changed$\n" + : "if ($name$_ != null) {\n" + " $name$_ =\n" + " $type$.newBuilder($name$_).mergeFrom(value).buildPartial();\n" + "} else {\n" + " $name$_ = value;\n" + "}\n" + "$on_changed$\n", + + "$name$Builder_.mergeFrom(value);\n", + + "$set_has_field_bit_builder$\n" + "return this;\n"); + + // Field.Builder clearField() + WriteFieldDocComment(printer, descriptor_); + PrintNestedBuilderFunction( + printer, "$deprecation$public Builder ${$clear$capitalized_name$$}$()", + + "$name$_ = null;\n" + "$on_changed$\n", + + has_hasbit ? "$name$Builder_.clear();\n" + : "$name$_ = null;\n" + "$name$Builder_ = null;\n", + + "$clear_has_field_bit_builder$\n" + "return this;\n"); + + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$.Builder " + "${$get$capitalized_name$Builder$}$() {\n" + " $set_has_field_bit_builder$\n" + " $on_changed$\n" + " return get$capitalized_name$FieldBuilder().getBuilder();\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$OrBuilder " + "${$get$capitalized_name$OrBuilder$}$() {\n" + " if ($name$Builder_ != null) {\n" + " return $name$Builder_.getMessageOrBuilder();\n" + " } else {\n" + " return $name$_ == null ?\n" + " $type$.getDefaultInstance() : $name$_;\n" + " }\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "private com.google.protobuf.SingleFieldBuilder$ver$<\n" + " $type$, $type$.Builder, $type$OrBuilder> \n" + " get$capitalized_name$FieldBuilder() {\n" + " if ($name$Builder_ == null) {\n" + " $name$Builder_ = new com.google.protobuf.SingleFieldBuilder$ver$<\n" + " $type$, $type$.Builder, $type$OrBuilder>(\n" + " get$capitalized_name$(),\n" + " getParentForChildren(),\n" + " isClean());\n" + " $name$_ = null;\n" + " }\n" + " return $name$Builder_;\n" + "}\n"); +} + +void ImmutableMessageFieldGenerator::GenerateKotlinDslMembers( + io::Printer* printer) const { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$kt_deprecation$public var $kt_name$: $kt_type$\n" + " @JvmName(\"${$get$kt_capitalized_name$$}$\")\n" + " get() = $kt_dsl_builder$.${$get$capitalized_name$$}$()\n" + " @JvmName(\"${$set$kt_capitalized_name$$}$\")\n" + " set(value) {\n" + " $kt_dsl_builder$.${$set$capitalized_name$$}$(value)\n" + " }\n"); + + WriteFieldAccessorDocComment(printer, descriptor_, CLEARER, + /* builder */ false); + printer->Print(variables_, + "public fun ${$clear$kt_capitalized_name$$}$() {\n" + " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n" + "}\n"); + + WriteFieldAccessorDocComment(printer, descriptor_, HAZZER); + printer->Print( + variables_, + "public fun ${$has$kt_capitalized_name$$}$(): kotlin.Boolean {\n" + " return $kt_dsl_builder$.${$has$capitalized_name$$}$()\n" + "}\n"); +} + +void ImmutableMessageFieldGenerator::GenerateFieldBuilderInitializationCode( + io::Printer* printer) const { + if (HasHasbit(descriptor_)) { + printer->Print(variables_, "get$capitalized_name$FieldBuilder();\n"); + } +} + +void ImmutableMessageFieldGenerator::GenerateInitializationCode( + io::Printer* printer) const {} + +void ImmutableMessageFieldGenerator::GenerateBuilderClearCode( + io::Printer* printer) const { + if (HasHasbit(descriptor_)) { + PrintNestedBuilderCondition(printer, "$name$_ = null;\n", + + "$name$Builder_.clear();\n"); + printer->Print(variables_, "$clear_has_field_bit_builder$\n"); + } else { + PrintNestedBuilderCondition(printer, "$name$_ = null;\n", + + "$name$_ = null;\n" + "$name$Builder_ = null;\n"); + } +} + +void ImmutableMessageFieldGenerator::GenerateMergingCode( + io::Printer* printer) const { + printer->Print(variables_, + "if (other.has$capitalized_name$()) {\n" + " merge$capitalized_name$(other.get$capitalized_name$());\n" + "}\n"); +} + +void ImmutableMessageFieldGenerator::GenerateBuildingCode( + io::Printer* printer) const { + if (HasHasbit(descriptor_)) { + printer->Print(variables_, "if ($get_has_field_bit_from_local$) {\n"); + printer->Indent(); + PrintNestedBuilderCondition(printer, "result.$name$_ = $name$_;\n", + "result.$name$_ = $name$Builder_.build();\n"); + printer->Outdent(); + printer->Print(variables_, + " $set_has_field_bit_to_local$;\n" + "}\n"); + } else { + PrintNestedBuilderCondition(printer, "result.$name$_ = $name$_;\n", + "result.$name$_ = $name$Builder_.build();\n"); + } +} + +void ImmutableMessageFieldGenerator::GenerateParsingCode( + io::Printer* printer) const { + printer->Print(variables_, + "$type$.Builder subBuilder = null;\n" + "if ($is_field_present_message$) {\n" + " subBuilder = $name$_.toBuilder();\n" + "}\n"); + + if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) { + printer->Print(variables_, + "$name$_ = input.readGroup($number$, $type$.$get_parser$,\n" + " extensionRegistry);\n"); + } else { + printer->Print(variables_, + "$name$_ = input.readMessage($type$.$get_parser$, " + "extensionRegistry);\n"); + } + + printer->Print(variables_, + "if (subBuilder != null) {\n" + " subBuilder.mergeFrom($name$_);\n" + " $name$_ = subBuilder.buildPartial();\n" + "}\n" + "$set_has_field_bit_message$\n"); +} + +void ImmutableMessageFieldGenerator::GenerateParsingDoneCode( + io::Printer* printer) const { + // noop for messages. +} + +void ImmutableMessageFieldGenerator::GenerateSerializationCode( + io::Printer* printer) const { + printer->Print( + variables_, + "if ($is_field_present_message$) {\n" + " output.write$group_or_message$($number$, get$capitalized_name$());\n" + "}\n"); +} + +void ImmutableMessageFieldGenerator::GenerateSerializedSizeCode( + io::Printer* printer) const { + printer->Print( + variables_, + "if ($is_field_present_message$) {\n" + " size += com.google.protobuf.CodedOutputStream\n" + " .compute$group_or_message$Size($number$, get$capitalized_name$());\n" + "}\n"); +} + +void ImmutableMessageFieldGenerator::GenerateEqualsCode( + io::Printer* printer) const { + printer->Print(variables_, + "if (!get$capitalized_name$()\n" + " .equals(other.get$capitalized_name$())) return false;\n"); +} + +void ImmutableMessageFieldGenerator::GenerateHashCode( + io::Printer* printer) const { + printer->Print(variables_, + "hash = (37 * hash) + $constant_name$;\n" + "hash = (53 * hash) + get$capitalized_name$().hashCode();\n"); +} + +std::string ImmutableMessageFieldGenerator::GetBoxedType() const { + return name_resolver_->GetImmutableClassName(descriptor_->message_type()); +} + +// =================================================================== + +ImmutableMessageOneofFieldGenerator::ImmutableMessageOneofFieldGenerator( + const FieldDescriptor* descriptor, int messageBitIndex, int builderBitIndex, + Context* context) + : ImmutableMessageFieldGenerator(descriptor, messageBitIndex, + builderBitIndex, context) { + const OneofGeneratorInfo* info = + context->GetOneofGeneratorInfo(descriptor->containing_oneof()); + SetCommonOneofVariables(descriptor, info, &variables_); +} + +ImmutableMessageOneofFieldGenerator::~ImmutableMessageOneofFieldGenerator() {} + +void ImmutableMessageOneofFieldGenerator::GenerateMembers( + io::Printer* printer) const { + PrintExtraFieldInfo(variables_, printer); + WriteFieldAccessorDocComment(printer, descriptor_, HAZZER); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n" + " return $has_oneof_case_message$;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldAccessorDocComment(printer, descriptor_, GETTER); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$public $type$ ${$get$capitalized_name$$}$() {\n" + " if ($has_oneof_case_message$) {\n" + " return ($type$) $oneof_name$_;\n" + " }\n" + " return $type$.getDefaultInstance();\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$public $type$OrBuilder " + "${$get$capitalized_name$OrBuilder$}$() {\n" + " if ($has_oneof_case_message$) {\n" + " return ($type$) $oneof_name$_;\n" + " }\n" + " return $type$.getDefaultInstance();\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); +} + +void ImmutableMessageOneofFieldGenerator::GenerateBuilderMembers( + io::Printer* printer) const { + // When using nested-builders, the code initially works just like the + // non-nested builder case. It only creates a nested builder lazily on + // demand and then forever delegates to it after creation. + printer->Print(variables_, + // If this builder is non-null, it is used and the other fields + // are ignored. + "private com.google.protobuf.SingleFieldBuilder$ver$<\n" + " $type$, $type$.Builder, $type$OrBuilder> $name$Builder_;" + "\n"); + + // The comments above the methods below are based on a hypothetical + // field of type "Field" called "Field". + + // boolean hasField() + WriteFieldAccessorDocComment(printer, descriptor_, HAZZER); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n" + " return $has_oneof_case_message$;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + // Field getField() + WriteFieldAccessorDocComment(printer, descriptor_, GETTER); + PrintNestedBuilderFunction( + printer, + "@java.lang.Override\n" + "$deprecation$public $type$ ${$get$capitalized_name$$}$()", + + "if ($has_oneof_case_message$) {\n" + " return ($type$) $oneof_name$_;\n" + "}\n" + "return $type$.getDefaultInstance();\n", + + "if ($has_oneof_case_message$) {\n" + " return $name$Builder_.getMessage();\n" + "}\n" + "return $type$.getDefaultInstance();\n", + + NULL); + + // Field.Builder setField(Field value) + WriteFieldDocComment(printer, descriptor_); + PrintNestedBuilderFunction( + printer, + "$deprecation$public Builder ${$set$capitalized_name$$}$($type$ value)", + + "if (value == null) {\n" + " throw new NullPointerException();\n" + "}\n" + "$oneof_name$_ = value;\n" + "$on_changed$\n", + + "$name$Builder_.setMessage(value);\n", + + "$set_oneof_case_message$;\n" + "return this;\n"); + + // Field.Builder setField(Field.Builder builderForValue) + WriteFieldDocComment(printer, descriptor_); + PrintNestedBuilderFunction( + printer, + "$deprecation$public Builder ${$set$capitalized_name$$}$(\n" + " $type$.Builder builderForValue)", + + "$oneof_name$_ = builderForValue.build();\n" + "$on_changed$\n", + + "$name$Builder_.setMessage(builderForValue.build());\n", + + "$set_oneof_case_message$;\n" + "return this;\n"); + + // Field.Builder mergeField(Field value) + WriteFieldDocComment(printer, descriptor_); + PrintNestedBuilderFunction( + printer, + "$deprecation$public Builder ${$merge$capitalized_name$$}$($type$ value)", + + "if ($has_oneof_case_message$ &&\n" + " $oneof_name$_ != $type$.getDefaultInstance()) {\n" + " $oneof_name$_ = $type$.newBuilder(($type$) $oneof_name$_)\n" + " .mergeFrom(value).buildPartial();\n" + "} else {\n" + " $oneof_name$_ = value;\n" + "}\n" + "$on_changed$\n", + + "if ($has_oneof_case_message$) {\n" + " $name$Builder_.mergeFrom(value);\n" + "}\n" + "$name$Builder_.setMessage(value);\n", + + "$set_oneof_case_message$;\n" + "return this;\n"); + + // Field.Builder clearField() + WriteFieldDocComment(printer, descriptor_); + PrintNestedBuilderFunction( + printer, "$deprecation$public Builder ${$clear$capitalized_name$$}$()", + + "if ($has_oneof_case_message$) {\n" + " $clear_oneof_case_message$;\n" + " $oneof_name$_ = null;\n" + " $on_changed$\n" + "}\n", + + "if ($has_oneof_case_message$) {\n" + " $clear_oneof_case_message$;\n" + " $oneof_name$_ = null;\n" + "}\n" + "$name$Builder_.clear();\n", + + "return this;\n"); + + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$.Builder " + "${$get$capitalized_name$Builder$}$() {\n" + " return get$capitalized_name$FieldBuilder().getBuilder();\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$public $type$OrBuilder " + "${$get$capitalized_name$OrBuilder$}$() {\n" + " if (($has_oneof_case_message$) && ($name$Builder_ != null)) {\n" + " return $name$Builder_.getMessageOrBuilder();\n" + " } else {\n" + " if ($has_oneof_case_message$) {\n" + " return ($type$) $oneof_name$_;\n" + " }\n" + " return $type$.getDefaultInstance();\n" + " }\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "private com.google.protobuf.SingleFieldBuilder$ver$<\n" + " $type$, $type$.Builder, $type$OrBuilder> \n" + " ${$get$capitalized_name$FieldBuilder$}$() {\n" + " if ($name$Builder_ == null) {\n" + " if (!($has_oneof_case_message$)) {\n" + " $oneof_name$_ = $type$.getDefaultInstance();\n" + " }\n" + " $name$Builder_ = new com.google.protobuf.SingleFieldBuilder$ver$<\n" + " $type$, $type$.Builder, $type$OrBuilder>(\n" + " ($type$) $oneof_name$_,\n" + " getParentForChildren(),\n" + " isClean());\n" + " $oneof_name$_ = null;\n" + " }\n" + " $set_oneof_case_message$;\n" + " $on_changed$;\n" + " return $name$Builder_;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); +} + +void ImmutableMessageOneofFieldGenerator::GenerateBuildingCode( + io::Printer* printer) const { + printer->Print(variables_, "if ($has_oneof_case_message$) {\n"); + printer->Indent(); + + PrintNestedBuilderCondition( + printer, "result.$oneof_name$_ = $oneof_name$_;\n", + + "result.$oneof_name$_ = $name$Builder_.build();\n"); + + printer->Outdent(); + printer->Print("}\n"); +} + +void ImmutableMessageOneofFieldGenerator::GenerateMergingCode( + io::Printer* printer) const { + printer->Print(variables_, + "merge$capitalized_name$(other.get$capitalized_name$());\n"); +} + +void ImmutableMessageOneofFieldGenerator::GenerateParsingCode( + io::Printer* printer) const { + printer->Print(variables_, + "$type$.Builder subBuilder = null;\n" + "if ($has_oneof_case_message$) {\n" + " subBuilder = (($type$) $oneof_name$_).toBuilder();\n" + "}\n"); + + if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) { + printer->Print( + variables_, + "$oneof_name$_ = input.readGroup($number$, $type$.$get_parser$,\n" + " extensionRegistry);\n"); + } else { + printer->Print( + variables_, + "$oneof_name$_ =\n" + " input.readMessage($type$.$get_parser$, extensionRegistry);\n"); + } + + printer->Print(variables_, + "if (subBuilder != null) {\n" + " subBuilder.mergeFrom(($type$) $oneof_name$_);\n" + " $oneof_name$_ = subBuilder.buildPartial();\n" + "}\n"); + printer->Print(variables_, "$set_oneof_case_message$;\n"); +} + +void ImmutableMessageOneofFieldGenerator::GenerateSerializationCode( + io::Printer* printer) const { + printer->Print( + variables_, + "if ($has_oneof_case_message$) {\n" + " output.write$group_or_message$($number$, ($type$) $oneof_name$_);\n" + "}\n"); +} + +void ImmutableMessageOneofFieldGenerator::GenerateSerializedSizeCode( + io::Printer* printer) const { + printer->Print( + variables_, + "if ($has_oneof_case_message$) {\n" + " size += com.google.protobuf.CodedOutputStream\n" + " .compute$group_or_message$Size($number$, ($type$) $oneof_name$_);\n" + "}\n"); +} + +// =================================================================== + +RepeatedImmutableMessageFieldGenerator::RepeatedImmutableMessageFieldGenerator( + const FieldDescriptor* descriptor, int messageBitIndex, int builderBitIndex, + Context* context) + : descriptor_(descriptor), name_resolver_(context->GetNameResolver()) { + SetMessageVariables(descriptor, messageBitIndex, builderBitIndex, + context->GetFieldGeneratorInfo(descriptor), + name_resolver_, &variables_); +} + +RepeatedImmutableMessageFieldGenerator:: + ~RepeatedImmutableMessageFieldGenerator() {} + +int RepeatedImmutableMessageFieldGenerator::GetNumBitsForMessage() const { + return 0; +} + +int RepeatedImmutableMessageFieldGenerator::GetNumBitsForBuilder() const { + return 1; +} + +void RepeatedImmutableMessageFieldGenerator::GenerateInterfaceMembers( + io::Printer* printer) const { + // TODO(jonp): In the future, consider having methods specific to the + // interface so that builders can choose dynamically to either return a + // message or a nested builder, so that asking for the interface doesn't + // cause a message to ever be built. + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$java.util.List<$type$> \n" + " get$capitalized_name$List();\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$$type$ get$capitalized_name$(int index);\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$int get$capitalized_name$Count();\n"); + + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$java.util.List<? extends $type$OrBuilder> \n" + " get$capitalized_name$OrBuilderList();\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$$type$OrBuilder get$capitalized_name$OrBuilder(\n" + " int index);\n"); +} + +void RepeatedImmutableMessageFieldGenerator::GenerateMembers( + io::Printer* printer) const { + printer->Print(variables_, "private java.util.List<$type$> $name$_;\n"); + PrintExtraFieldInfo(variables_, printer); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$public java.util.List<$type$> " + "${$get$capitalized_name$List$}$() {\n" + " return $name$_;\n" // note: unmodifiable list + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$public java.util.List<? extends $type$OrBuilder> \n" + " ${$get$capitalized_name$OrBuilderList$}$() {\n" + " return $name$_;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$public int ${$get$capitalized_name$Count$}$() {\n" + " return $name$_.size();\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$public $type$ ${$get$capitalized_name$$}$(int index) {\n" + " return $name$_.get(index);\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$public $type$OrBuilder " + "${$get$capitalized_name$OrBuilder$}$(\n" + " int index) {\n" + " return $name$_.get(index);\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); +} + +void RepeatedImmutableMessageFieldGenerator::PrintNestedBuilderCondition( + io::Printer* printer, const char* regular_case, + const char* nested_builder_case) const { + printer->Print(variables_, "if ($name$Builder_ == null) {\n"); + printer->Indent(); + printer->Print(variables_, regular_case); + printer->Outdent(); + printer->Print("} else {\n"); + printer->Indent(); + printer->Print(variables_, nested_builder_case); + printer->Outdent(); + printer->Print("}\n"); +} + +void RepeatedImmutableMessageFieldGenerator::PrintNestedBuilderFunction( + io::Printer* printer, const char* method_prototype, + const char* regular_case, const char* nested_builder_case, + const char* trailing_code) const { + printer->Print(variables_, method_prototype); + printer->Annotate("{", "}", descriptor_); + printer->Print(" {\n"); + printer->Indent(); + PrintNestedBuilderCondition(printer, regular_case, nested_builder_case); + if (trailing_code != NULL) { + printer->Print(variables_, trailing_code); + } + printer->Outdent(); + printer->Print("}\n"); +} + +void RepeatedImmutableMessageFieldGenerator::GenerateBuilderMembers( + io::Printer* printer) const { + // When using nested-builders, the code initially works just like the + // non-nested builder case. It only creates a nested builder lazily on + // demand and then forever delegates to it after creation. + + printer->Print( + variables_, + // Used when the builder is null. + // One field is the list and the other field keeps track of whether the + // list is immutable. If it's immutable, the invariant is that it must + // either an instance of Collections.emptyList() or it's an ArrayList + // wrapped in a Collections.unmodifiableList() wrapper and nobody else has + // a reference to the underlying ArrayList. This invariant allows us to + // share instances of lists between protocol buffers avoiding expensive + // memory allocations. Note, immutable is a strong guarantee here -- not + // just that the list cannot be modified via the reference but that the + // list can never be modified. + "private java.util.List<$type$> $name$_ =\n" + " java.util.Collections.emptyList();\n" + + "private void ensure$capitalized_name$IsMutable() {\n" + " if (!$get_mutable_bit_builder$) {\n" + " $name$_ = new java.util.ArrayList<$type$>($name$_);\n" + " $set_mutable_bit_builder$;\n" + " }\n" + "}\n" + "\n"); + + printer->Print( + variables_, + // If this builder is non-null, it is used and the other fields are + // ignored. + "private com.google.protobuf.RepeatedFieldBuilder$ver$<\n" + " $type$, $type$.Builder, $type$OrBuilder> $name$Builder_;\n" + "\n"); + + // The comments above the methods below are based on a hypothetical + // repeated field of type "Field" called "RepeatedField". + + // List<Field> getRepeatedFieldList() + WriteFieldDocComment(printer, descriptor_); + PrintNestedBuilderFunction( + printer, + "$deprecation$public java.util.List<$type$> " + "${$get$capitalized_name$List$}$()", + + "return java.util.Collections.unmodifiableList($name$_);\n", + "return $name$Builder_.getMessageList();\n", + + NULL); + + // int getRepeatedFieldCount() + WriteFieldDocComment(printer, descriptor_); + PrintNestedBuilderFunction( + printer, "$deprecation$public int ${$get$capitalized_name$Count$}$()", + + "return $name$_.size();\n", "return $name$Builder_.getCount();\n", + + NULL); + + // Field getRepeatedField(int index) + WriteFieldDocComment(printer, descriptor_); + PrintNestedBuilderFunction( + printer, + "$deprecation$public $type$ ${$get$capitalized_name$$}$(int index)", + + "return $name$_.get(index);\n", + + "return $name$Builder_.getMessage(index);\n", + + NULL); + + // Builder setRepeatedField(int index, Field value) + WriteFieldDocComment(printer, descriptor_); + PrintNestedBuilderFunction( + printer, + "$deprecation$public Builder ${$set$capitalized_name$$}$(\n" + " int index, $type$ value)", + "if (value == null) {\n" + " throw new NullPointerException();\n" + "}\n" + "ensure$capitalized_name$IsMutable();\n" + "$name$_.set(index, value);\n" + "$on_changed$\n", + "$name$Builder_.setMessage(index, value);\n", "return this;\n"); + + // Builder setRepeatedField(int index, Field.Builder builderForValue) + WriteFieldDocComment(printer, descriptor_); + PrintNestedBuilderFunction( + printer, + "$deprecation$public Builder ${$set$capitalized_name$$}$(\n" + " int index, $type$.Builder builderForValue)", + + "ensure$capitalized_name$IsMutable();\n" + "$name$_.set(index, builderForValue.build());\n" + "$on_changed$\n", + + "$name$Builder_.setMessage(index, builderForValue.build());\n", + + "return this;\n"); + + // Builder addRepeatedField(Field value) + WriteFieldDocComment(printer, descriptor_); + PrintNestedBuilderFunction( + printer, + "$deprecation$public Builder ${$add$capitalized_name$$}$($type$ value)", + + "if (value == null) {\n" + " throw new NullPointerException();\n" + "}\n" + "ensure$capitalized_name$IsMutable();\n" + "$name$_.add(value);\n" + + "$on_changed$\n", + + "$name$Builder_.addMessage(value);\n", + + "return this;\n"); + + // Builder addRepeatedField(int index, Field value) + WriteFieldDocComment(printer, descriptor_); + PrintNestedBuilderFunction( + printer, + "$deprecation$public Builder ${$add$capitalized_name$$}$(\n" + " int index, $type$ value)", + + "if (value == null) {\n" + " throw new NullPointerException();\n" + "}\n" + "ensure$capitalized_name$IsMutable();\n" + "$name$_.add(index, value);\n" + "$on_changed$\n", + + "$name$Builder_.addMessage(index, value);\n", + + "return this;\n"); + + // Builder addRepeatedField(Field.Builder builderForValue) + WriteFieldDocComment(printer, descriptor_); + PrintNestedBuilderFunction( + printer, + "$deprecation$public Builder ${$add$capitalized_name$$}$(\n" + " $type$.Builder builderForValue)", + + "ensure$capitalized_name$IsMutable();\n" + "$name$_.add(builderForValue.build());\n" + "$on_changed$\n", + + "$name$Builder_.addMessage(builderForValue.build());\n", + + "return this;\n"); + + // Builder addRepeatedField(int index, Field.Builder builderForValue) + WriteFieldDocComment(printer, descriptor_); + PrintNestedBuilderFunction( + printer, + "$deprecation$public Builder ${$add$capitalized_name$$}$(\n" + " int index, $type$.Builder builderForValue)", + + "ensure$capitalized_name$IsMutable();\n" + "$name$_.add(index, builderForValue.build());\n" + "$on_changed$\n", + + "$name$Builder_.addMessage(index, builderForValue.build());\n", + + "return this;\n"); + + // Builder addAllRepeatedField(Iterable<Field> values) + WriteFieldDocComment(printer, descriptor_); + PrintNestedBuilderFunction( + printer, + "$deprecation$public Builder ${$addAll$capitalized_name$$}$(\n" + " java.lang.Iterable<? extends $type$> values)", + + "ensure$capitalized_name$IsMutable();\n" + "com.google.protobuf.AbstractMessageLite.Builder.addAll(\n" + " values, $name$_);\n" + "$on_changed$\n", + + "$name$Builder_.addAllMessages(values);\n", + + "return this;\n"); + + // Builder clearAllRepeatedField() + WriteFieldDocComment(printer, descriptor_); + PrintNestedBuilderFunction( + printer, "$deprecation$public Builder ${$clear$capitalized_name$$}$()", + + "$name$_ = java.util.Collections.emptyList();\n" + "$clear_mutable_bit_builder$;\n" + "$on_changed$\n", + + "$name$Builder_.clear();\n", + + "return this;\n"); + + // Builder removeRepeatedField(int index) + WriteFieldDocComment(printer, descriptor_); + PrintNestedBuilderFunction( + printer, + "$deprecation$public Builder ${$remove$capitalized_name$$}$(int index)", + + "ensure$capitalized_name$IsMutable();\n" + "$name$_.remove(index);\n" + "$on_changed$\n", + + "$name$Builder_.remove(index);\n", + + "return this;\n"); + + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$public $type$.Builder ${$get$capitalized_name$Builder$}$(\n" + " int index) {\n" + " return get$capitalized_name$FieldBuilder().getBuilder(index);\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$OrBuilder " + "${$get$capitalized_name$OrBuilder$}$(\n" + " int index) {\n" + " if ($name$Builder_ == null) {\n" + " return $name$_.get(index);" + " } else {\n" + " return $name$Builder_.getMessageOrBuilder(index);\n" + " }\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$public java.util.List<? extends $type$OrBuilder> \n" + " ${$get$capitalized_name$OrBuilderList$}$() {\n" + " if ($name$Builder_ != null) {\n" + " return $name$Builder_.getMessageOrBuilderList();\n" + " } else {\n" + " return java.util.Collections.unmodifiableList($name$_);\n" + " }\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$.Builder " + "${$add$capitalized_name$Builder$}$() {\n" + " return get$capitalized_name$FieldBuilder().addBuilder(\n" + " $type$.getDefaultInstance());\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$public $type$.Builder ${$add$capitalized_name$Builder$}$(\n" + " int index) {\n" + " return get$capitalized_name$FieldBuilder().addBuilder(\n" + " index, $type$.getDefaultInstance());\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$public java.util.List<$type$.Builder> \n" + " ${$get$capitalized_name$BuilderList$}$() {\n" + " return get$capitalized_name$FieldBuilder().getBuilderList();\n" + "}\n" + "private com.google.protobuf.RepeatedFieldBuilder$ver$<\n" + " $type$, $type$.Builder, $type$OrBuilder> \n" + " get$capitalized_name$FieldBuilder() {\n" + " if ($name$Builder_ == null) {\n" + " $name$Builder_ = new " + "com.google.protobuf.RepeatedFieldBuilder$ver$<\n" + " $type$, $type$.Builder, $type$OrBuilder>(\n" + " $name$_,\n" + " $get_mutable_bit_builder$,\n" + " getParentForChildren(),\n" + " isClean());\n" + " $name$_ = null;\n" + " }\n" + " return $name$Builder_;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); +} + +void RepeatedImmutableMessageFieldGenerator:: + GenerateFieldBuilderInitializationCode(io::Printer* printer) const { + printer->Print(variables_, "get$capitalized_name$FieldBuilder();\n"); +} + +void RepeatedImmutableMessageFieldGenerator::GenerateInitializationCode( + io::Printer* printer) const { + printer->Print(variables_, "$name$_ = java.util.Collections.emptyList();\n"); +} + +void RepeatedImmutableMessageFieldGenerator::GenerateBuilderClearCode( + io::Printer* printer) const { + PrintNestedBuilderCondition(printer, + "$name$_ = java.util.Collections.emptyList();\n" + "$clear_mutable_bit_builder$;\n", + + "$name$Builder_.clear();\n"); +} + +void RepeatedImmutableMessageFieldGenerator::GenerateMergingCode( + io::Printer* printer) const { + // The code below does two optimizations (non-nested builder case): + // 1. If the other list is empty, there's nothing to do. This ensures we + // don't allocate a new array if we already have an immutable one. + // 2. If the other list is non-empty and our current list is empty, we can + // reuse the other list which is guaranteed to be immutable. + PrintNestedBuilderCondition( + printer, + "if (!other.$name$_.isEmpty()) {\n" + " if ($name$_.isEmpty()) {\n" + " $name$_ = other.$name$_;\n" + " $clear_mutable_bit_builder$;\n" + " } else {\n" + " ensure$capitalized_name$IsMutable();\n" + " $name$_.addAll(other.$name$_);\n" + " }\n" + " $on_changed$\n" + "}\n", + + "if (!other.$name$_.isEmpty()) {\n" + " if ($name$Builder_.isEmpty()) {\n" + " $name$Builder_.dispose();\n" + " $name$Builder_ = null;\n" + " $name$_ = other.$name$_;\n" + " $clear_mutable_bit_builder$;\n" + " $name$Builder_ = \n" + " com.google.protobuf.GeneratedMessage$ver$.alwaysUseFieldBuilders " + "?\n" + " get$capitalized_name$FieldBuilder() : null;\n" + " } else {\n" + " $name$Builder_.addAllMessages(other.$name$_);\n" + " }\n" + "}\n"); +} + +void RepeatedImmutableMessageFieldGenerator::GenerateBuildingCode( + io::Printer* printer) const { + // The code below (non-nested builder case) ensures that the result has an + // immutable list. If our list is immutable, we can just reuse it. If not, + // we make it immutable. + PrintNestedBuilderCondition( + printer, + "if ($get_mutable_bit_builder$) {\n" + " $name$_ = java.util.Collections.unmodifiableList($name$_);\n" + " $clear_mutable_bit_builder$;\n" + "}\n" + "result.$name$_ = $name$_;\n", + + "result.$name$_ = $name$Builder_.build();\n"); +} + +void RepeatedImmutableMessageFieldGenerator::GenerateParsingCode( + io::Printer* printer) const { + printer->Print(variables_, + "if (!$get_mutable_bit_parser$) {\n" + " $name$_ = new java.util.ArrayList<$type$>();\n" + " $set_mutable_bit_parser$;\n" + "}\n"); + + if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) { + printer->Print( + variables_, + "$name$_.add(input.readGroup($number$, $type$.$get_parser$,\n" + " extensionRegistry));\n"); + } else { + printer->Print( + variables_, + "$name$_.add(\n" + " input.readMessage($type$.$get_parser$, extensionRegistry));\n"); + } +} + +void RepeatedImmutableMessageFieldGenerator::GenerateParsingDoneCode( + io::Printer* printer) const { + printer->Print( + variables_, + "if ($get_mutable_bit_parser$) {\n" + " $name$_ = java.util.Collections.unmodifiableList($name$_);\n" + "}\n"); +} + +void RepeatedImmutableMessageFieldGenerator::GenerateSerializationCode( + io::Printer* printer) const { + printer->Print(variables_, + "for (int i = 0; i < $name$_.size(); i++) {\n" + " output.write$group_or_message$($number$, $name$_.get(i));\n" + "}\n"); +} + +void RepeatedImmutableMessageFieldGenerator::GenerateSerializedSizeCode( + io::Printer* printer) const { + printer->Print( + variables_, + "for (int i = 0; i < $name$_.size(); i++) {\n" + " size += com.google.protobuf.CodedOutputStream\n" + " .compute$group_or_message$Size($number$, $name$_.get(i));\n" + "}\n"); +} + +void RepeatedImmutableMessageFieldGenerator::GenerateEqualsCode( + io::Printer* printer) const { + printer->Print( + variables_, + "if (!get$capitalized_name$List()\n" + " .equals(other.get$capitalized_name$List())) return false;\n"); +} + +void RepeatedImmutableMessageFieldGenerator::GenerateHashCode( + io::Printer* printer) const { + printer->Print( + variables_, + "if (get$capitalized_name$Count() > 0) {\n" + " hash = (37 * hash) + $constant_name$;\n" + " hash = (53 * hash) + get$capitalized_name$List().hashCode();\n" + "}\n"); +} + +std::string RepeatedImmutableMessageFieldGenerator::GetBoxedType() const { + return name_resolver_->GetImmutableClassName(descriptor_->message_type()); +} + +void RepeatedImmutableMessageFieldGenerator::GenerateKotlinDslMembers( + io::Printer* printer) const { + printer->Print( + variables_, + "/**\n" + " * An uninstantiable, behaviorless type to represent the field in\n" + " * generics.\n" + " */\n" + "@kotlin.OptIn" + "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n" + "public class ${$$kt_capitalized_name$Proxy$}$ private constructor()" + " : com.google.protobuf.kotlin.DslProxy()\n"); + + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$kt_deprecation$ public val $kt_name$: " + "com.google.protobuf.kotlin.DslList" + "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>\n" + " @kotlin.jvm.JvmSynthetic\n" + " get() = com.google.protobuf.kotlin.DslList(\n" + " $kt_dsl_builder$.${$get$capitalized_name$List$}$()\n" + " )\n"); + + WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER, + /* builder */ false); + printer->Print(variables_, + "@kotlin.jvm.JvmSynthetic\n" + "@kotlin.jvm.JvmName(\"add$kt_capitalized_name$\")\n" + "public fun com.google.protobuf.kotlin.DslList" + "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." + "add(value: $kt_type$) {\n" + " $kt_dsl_builder$.${$add$capitalized_name$$}$(value)\n" + "}"); + + WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER, + /* builder */ false); + printer->Print(variables_, + "@kotlin.jvm.JvmSynthetic\n" + "@kotlin.jvm.JvmName(\"plusAssign$kt_capitalized_name$\")\n" + "@Suppress(\"NOTHING_TO_INLINE\")\n" + "public inline operator fun com.google.protobuf.kotlin.DslList" + "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." + "plusAssign(value: $kt_type$) {\n" + " add(value)\n" + "}"); + + WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER, + /* builder */ false); + printer->Print(variables_, + "@kotlin.jvm.JvmSynthetic\n" + "@kotlin.jvm.JvmName(\"addAll$kt_capitalized_name$\")\n" + "public fun com.google.protobuf.kotlin.DslList" + "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." + "addAll(values: kotlin.collections.Iterable<$kt_type$>) {\n" + " $kt_dsl_builder$.${$addAll$capitalized_name$$}$(values)\n" + "}"); + + WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER, + /* builder */ false); + printer->Print( + variables_, + "@kotlin.jvm.JvmSynthetic\n" + "@kotlin.jvm.JvmName(\"plusAssignAll$kt_capitalized_name$\")\n" + "@Suppress(\"NOTHING_TO_INLINE\")\n" + "public inline operator fun com.google.protobuf.kotlin.DslList" + "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." + "plusAssign(values: kotlin.collections.Iterable<$kt_type$>) {\n" + " addAll(values)\n" + "}"); + + WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_SETTER, + /* builder */ false); + printer->Print( + variables_, + "@kotlin.jvm.JvmSynthetic\n" + "@kotlin.jvm.JvmName(\"set$kt_capitalized_name$\")\n" + "public operator fun com.google.protobuf.kotlin.DslList" + "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." + "set(index: kotlin.Int, value: $kt_type$) {\n" + " $kt_dsl_builder$.${$set$capitalized_name$$}$(index, value)\n" + "}"); + + WriteFieldAccessorDocComment(printer, descriptor_, CLEARER, + /* builder */ false); + printer->Print(variables_, + "@kotlin.jvm.JvmSynthetic\n" + "@kotlin.jvm.JvmName(\"clear$kt_capitalized_name$\")\n" + "public fun com.google.protobuf.kotlin.DslList" + "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." + "clear() {\n" + " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n" + "}"); +} + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/java/java_message_field.h b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_message_field.h new file mode 100644 index 00000000..2ade2ba8 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_message_field.h @@ -0,0 +1,179 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_FIELD_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_FIELD_H__ + +#include <map> +#include <string> +#include <compiler/java/java_field.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { +class Context; // context.h +class ClassNameResolver; // name_resolver.h +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +class ImmutableMessageFieldGenerator : public ImmutableFieldGenerator { + public: + explicit ImmutableMessageFieldGenerator(const FieldDescriptor* descriptor, + int messageBitIndex, + int builderBitIndex, + Context* context); + ~ImmutableMessageFieldGenerator(); + + // implements ImmutableFieldGenerator + // --------------------------------------- + int GetNumBitsForMessage() const override; + int GetNumBitsForBuilder() const override; + void GenerateInterfaceMembers(io::Printer* printer) const override; + void GenerateMembers(io::Printer* printer) const override; + void GenerateBuilderMembers(io::Printer* printer) const override; + void GenerateInitializationCode(io::Printer* printer) const override; + void GenerateBuilderClearCode(io::Printer* printer) const override; + void GenerateMergingCode(io::Printer* printer) const override; + void GenerateBuildingCode(io::Printer* printer) const override; + void GenerateParsingCode(io::Printer* printer) const override; + void GenerateParsingDoneCode(io::Printer* printer) const override; + void GenerateSerializationCode(io::Printer* printer) const override; + void GenerateSerializedSizeCode(io::Printer* printer) const override; + void GenerateFieldBuilderInitializationCode( + io::Printer* printer) const override; + void GenerateEqualsCode(io::Printer* printer) const override; + void GenerateHashCode(io::Printer* printer) const override; + void GenerateKotlinDslMembers(io::Printer* printer) const override; + + std::string GetBoxedType() const override; + + protected: + const FieldDescriptor* descriptor_; + std::map<std::string, std::string> variables_; + ClassNameResolver* name_resolver_; + + void PrintNestedBuilderCondition(io::Printer* printer, + const char* regular_case, + const char* nested_builder_case) const; + void PrintNestedBuilderFunction(io::Printer* printer, + const char* method_prototype, + const char* regular_case, + const char* nested_builder_case, + const char* trailing_code) const; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableMessageFieldGenerator); +}; + +class ImmutableMessageOneofFieldGenerator + : public ImmutableMessageFieldGenerator { + public: + ImmutableMessageOneofFieldGenerator(const FieldDescriptor* descriptor, + int messageBitIndex, int builderBitIndex, + Context* context); + ~ImmutableMessageOneofFieldGenerator(); + + void GenerateMembers(io::Printer* printer) const override; + void GenerateBuilderMembers(io::Printer* printer) const override; + void GenerateBuildingCode(io::Printer* printer) const override; + void GenerateMergingCode(io::Printer* printer) const override; + void GenerateParsingCode(io::Printer* printer) const override; + void GenerateSerializationCode(io::Printer* printer) const override; + void GenerateSerializedSizeCode(io::Printer* printer) const override; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableMessageOneofFieldGenerator); +}; + +class RepeatedImmutableMessageFieldGenerator : public ImmutableFieldGenerator { + public: + explicit RepeatedImmutableMessageFieldGenerator( + const FieldDescriptor* descriptor, int messageBitIndex, + int builderBitIndex, Context* context); + ~RepeatedImmutableMessageFieldGenerator() override; + + // implements ImmutableFieldGenerator --------------------------------------- + int GetNumBitsForMessage() const override; + int GetNumBitsForBuilder() const override; + void GenerateInterfaceMembers(io::Printer* printer) const override; + void GenerateMembers(io::Printer* printer) const override; + void GenerateBuilderMembers(io::Printer* printer) const override; + void GenerateInitializationCode(io::Printer* printer) const override; + void GenerateBuilderClearCode(io::Printer* printer) const override; + void GenerateMergingCode(io::Printer* printer) const override; + void GenerateBuildingCode(io::Printer* printer) const override; + void GenerateParsingCode(io::Printer* printer) const override; + void GenerateParsingDoneCode(io::Printer* printer) const override; + void GenerateSerializationCode(io::Printer* printer) const override; + void GenerateSerializedSizeCode(io::Printer* printer) const override; + void GenerateFieldBuilderInitializationCode( + io::Printer* printer) const override; + void GenerateEqualsCode(io::Printer* printer) const override; + void GenerateHashCode(io::Printer* printer) const override; + void GenerateKotlinDslMembers(io::Printer* printer) const override; + + std::string GetBoxedType() const override; + + protected: + const FieldDescriptor* descriptor_; + std::map<std::string, std::string> variables_; + ClassNameResolver* name_resolver_; + + void PrintNestedBuilderCondition(io::Printer* printer, + const char* regular_case, + const char* nested_builder_case) const; + void PrintNestedBuilderFunction(io::Printer* printer, + const char* method_prototype, + const char* regular_case, + const char* nested_builder_case, + const char* trailing_code) const; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedImmutableMessageFieldGenerator); +}; + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_FIELD_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/java/java_message_field_lite.cc b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_message_field_lite.cc new file mode 100644 index 00000000..f3050db3 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_message_field_lite.cc @@ -0,0 +1,884 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <compiler/java/java_message_field_lite.h> + +#include <cstdint> +#include <map> +#include <string> + +#include <compiler/java/java_context.h> +#include <compiler/java/java_doc_comment.h> +#include <compiler/java/java_helpers.h> +#include <compiler/java/java_name_resolver.h> +#include <io/printer.h> +#include <wire_format.h> +#include <stubs/strutil.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +namespace { + +void SetMessageVariables(const FieldDescriptor* descriptor, int messageBitIndex, + int builderBitIndex, const FieldGeneratorInfo* info, + ClassNameResolver* name_resolver, + std::map<std::string, std::string>* variables) { + SetCommonFieldVariables(descriptor, info, variables); + + (*variables)["type"] = + name_resolver->GetImmutableClassName(descriptor->message_type()); + (*variables)["kt_type"] = (*variables)["type"]; + (*variables)["mutable_type"] = + name_resolver->GetMutableClassName(descriptor->message_type()); + (*variables)["group_or_message"] = + (GetType(descriptor) == FieldDescriptor::TYPE_GROUP) ? "Group" + : "Message"; + // TODO(birdo): Add @deprecated javadoc when generating javadoc is supported + // by the proto compiler + (*variables)["deprecation"] = + descriptor->options().deprecated() ? "@java.lang.Deprecated " : ""; + (*variables)["kt_deprecation"] = + descriptor->options().deprecated() + ? "@kotlin.Deprecated(message = \"Field " + (*variables)["name"] + + " is deprecated\") " + : ""; + (*variables)["required"] = descriptor->is_required() ? "true" : "false"; + + if (HasHasbit(descriptor)) { + // For singular messages and builders, one bit is used for the hasField bit. + (*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex); + + // Note that these have a trailing ";". + (*variables)["set_has_field_bit_message"] = + GenerateSetBit(messageBitIndex) + ";"; + (*variables)["clear_has_field_bit_message"] = + GenerateClearBit(messageBitIndex) + ";"; + + (*variables)["is_field_present_message"] = GenerateGetBit(messageBitIndex); + } else { + (*variables)["set_has_field_bit_message"] = ""; + (*variables)["clear_has_field_bit_message"] = ""; + + (*variables)["is_field_present_message"] = + (*variables)["name"] + "_ != null"; + } + + (*variables)["get_has_field_bit_from_local"] = + GenerateGetBitFromLocal(builderBitIndex); + (*variables)["set_has_field_bit_to_local"] = + GenerateSetBitToLocal(messageBitIndex); + + // We use `x.getClass()` as a null check because it generates less bytecode + // than an `if (x == null) { throw ... }` statement. + (*variables)["null_check"] = "value.getClass();\n"; +} + +} // namespace + +// =================================================================== + +ImmutableMessageFieldLiteGenerator::ImmutableMessageFieldLiteGenerator( + const FieldDescriptor* descriptor, int messageBitIndex, Context* context) + : descriptor_(descriptor), + messageBitIndex_(messageBitIndex), + name_resolver_(context->GetNameResolver()) { + SetMessageVariables(descriptor, messageBitIndex, 0, + context->GetFieldGeneratorInfo(descriptor), + name_resolver_, &variables_); +} + +ImmutableMessageFieldLiteGenerator::~ImmutableMessageFieldLiteGenerator() {} + +int ImmutableMessageFieldLiteGenerator::GetNumBitsForMessage() const { + // TODO(dweis): We don't need a has bit for messages as they have null + // sentinels and no user should be reflecting on this. We could save some + // bits by setting to 0 and updating the runtimes but this might come at a + // runtime performance cost since we can't memoize has-bit reads. + return HasHasbit(descriptor_) ? 1 : 0; +} + +void ImmutableMessageFieldLiteGenerator::GenerateInterfaceMembers( + io::Printer* printer) const { + WriteFieldAccessorDocComment(printer, descriptor_, HAZZER); + printer->Print(variables_, "$deprecation$boolean has$capitalized_name$();\n"); + WriteFieldAccessorDocComment(printer, descriptor_, GETTER); + printer->Print(variables_, "$deprecation$$type$ get$capitalized_name$();\n"); +} + +void ImmutableMessageFieldLiteGenerator::GenerateMembers( + io::Printer* printer) const { + + printer->Print(variables_, "private $type$ $name$_;\n"); + PrintExtraFieldInfo(variables_, printer); + + if (HasHasbit(descriptor_)) { + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n" + " return $get_has_field_bit_message$;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$public $type$ ${$get$capitalized_name$$}$() {\n" + " return $name$_ == null ? $type$.getDefaultInstance() : $name$_;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + } else { + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n" + " return $name$_ != null;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$public $type$ ${$get$capitalized_name$$}$() {\n" + " return $name$_ == null ? $type$.getDefaultInstance() : $name$_;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + } + + // Field.Builder setField(Field value) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void set$capitalized_name$($type$ value) {\n" + " $null_check$" + " $name$_ = value;\n" + " $set_has_field_bit_message$\n" + " }\n"); + + // Field.Builder mergeField(Field value) + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "@java.lang.SuppressWarnings({\"ReferenceEquality\"})\n" + "private void merge$capitalized_name$($type$ value) {\n" + " $null_check$" + " if ($name$_ != null &&\n" + " $name$_ != $type$.getDefaultInstance()) {\n" + " $name$_ =\n" + " $type$.newBuilder($name$_).mergeFrom(value).buildPartial();\n" + " } else {\n" + " $name$_ = value;\n" + " }\n" + " $set_has_field_bit_message$\n" + "}\n"); + + // Field.Builder clearField() + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void clear$capitalized_name$() {" + " $name$_ = null;\n" + " $clear_has_field_bit_message$\n" + "}\n"); +} + +void ImmutableMessageFieldLiteGenerator::GenerateBuilderMembers( + io::Printer* printer) const { + // The comments above the methods below are based on a hypothetical + // field of type "Field" called "Field". + + // boolean hasField() + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n" + " return instance.has$capitalized_name$();\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + // Field getField() + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$public $type$ ${$get$capitalized_name$$}$() {\n" + " return instance.get$capitalized_name$();\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + // Field.Builder setField(Field value) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder " + "${$set$capitalized_name$$}$($type$ value) {\n" + " copyOnWrite();\n" + " instance.set$capitalized_name$(value);\n" + " return this;\n" + " }\n"); + printer->Annotate("{", "}", descriptor_); + + // Field.Builder setField(Field.Builder builderForValue) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder ${$set$capitalized_name$$}$(\n" + " $type$.Builder builderForValue) {\n" + " copyOnWrite();\n" + " instance.set$capitalized_name$(builderForValue.build());\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + // Field.Builder mergeField(Field value) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder " + "${$merge$capitalized_name$$}$($type$ value) {\n" + " copyOnWrite();\n" + " instance.merge$capitalized_name$(value);\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + // Field.Builder clearField() + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder ${$clear$capitalized_name$$}$() {" + " copyOnWrite();\n" + " instance.clear$capitalized_name$();\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); +} + +void ImmutableMessageFieldLiteGenerator::GenerateKotlinDslMembers( + io::Printer* printer) const { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$kt_deprecation$public var $kt_name$: $kt_type$\n" + " @JvmName(\"${$get$kt_capitalized_name$$}$\")\n" + " get() = $kt_dsl_builder$.${$get$capitalized_name$$}$()\n" + " @JvmName(\"${$set$kt_capitalized_name$$}$\")\n" + " set(value) {\n" + " $kt_dsl_builder$.${$set$capitalized_name$$}$(value)\n" + " }\n"); + + WriteFieldAccessorDocComment(printer, descriptor_, CLEARER, + /* builder */ false); + printer->Print(variables_, + "public fun ${$clear$kt_capitalized_name$$}$() {\n" + " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n" + "}\n"); + + WriteFieldAccessorDocComment(printer, descriptor_, HAZZER); + printer->Print( + variables_, + "public fun ${$has$kt_capitalized_name$$}$(): kotlin.Boolean {\n" + " return $kt_dsl_builder$.${$has$capitalized_name$$}$()\n" + "}\n"); +} + +void ImmutableMessageFieldLiteGenerator::GenerateFieldInfo( + io::Printer* printer, std::vector<uint16_t>* output) const { + WriteIntToUtf16CharSequence(descriptor_->number(), output); + WriteIntToUtf16CharSequence(GetExperimentalJavaFieldType(descriptor_), + output); + if (HasHasbit(descriptor_)) { + WriteIntToUtf16CharSequence(messageBitIndex_, output); + } + printer->Print(variables_, "\"$name$_\",\n"); +} + +void ImmutableMessageFieldLiteGenerator::GenerateInitializationCode( + io::Printer* printer) const {} + +std::string ImmutableMessageFieldLiteGenerator::GetBoxedType() const { + return name_resolver_->GetImmutableClassName(descriptor_->message_type()); +} + +// =================================================================== + +ImmutableMessageOneofFieldLiteGenerator:: + ImmutableMessageOneofFieldLiteGenerator(const FieldDescriptor* descriptor, + int messageBitIndex, + Context* context) + : ImmutableMessageFieldLiteGenerator(descriptor, messageBitIndex, context) { + const OneofGeneratorInfo* info = + context->GetOneofGeneratorInfo(descriptor->containing_oneof()); + SetCommonOneofVariables(descriptor, info, &variables_); +} + +ImmutableMessageOneofFieldLiteGenerator:: + ~ImmutableMessageOneofFieldLiteGenerator() {} + +void ImmutableMessageOneofFieldLiteGenerator::GenerateMembers( + io::Printer* printer) const { + PrintExtraFieldInfo(variables_, printer); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n" + " return $has_oneof_case_message$;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$public $type$ ${$get$capitalized_name$$}$() {\n" + " if ($has_oneof_case_message$) {\n" + " return ($type$) $oneof_name$_;\n" + " }\n" + " return $type$.getDefaultInstance();\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + // Field.Builder setField(Field value) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void set$capitalized_name$($type$ value) {\n" + " $null_check$" + " $oneof_name$_ = value;\n" + " $set_oneof_case_message$;\n" + "}\n"); + + // Field.Builder mergeField(Field value) + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "private void merge$capitalized_name$($type$ value) {\n" + " $null_check$" + " if ($has_oneof_case_message$ &&\n" + " $oneof_name$_ != $type$.getDefaultInstance()) {\n" + " $oneof_name$_ = $type$.newBuilder(($type$) $oneof_name$_)\n" + " .mergeFrom(value).buildPartial();\n" + " } else {\n" + " $oneof_name$_ = value;\n" + " }\n" + " $set_oneof_case_message$;\n" + "}\n"); + + // Field.Builder clearField() + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void clear$capitalized_name$() {\n" + " if ($has_oneof_case_message$) {\n" + " $clear_oneof_case_message$;\n" + " $oneof_name$_ = null;\n" + " }\n" + "}\n"); +} + +void ImmutableMessageOneofFieldLiteGenerator::GenerateFieldInfo( + io::Printer* printer, std::vector<uint16_t>* output) const { + WriteIntToUtf16CharSequence(descriptor_->number(), output); + WriteIntToUtf16CharSequence(GetExperimentalJavaFieldType(descriptor_), + output); + WriteIntToUtf16CharSequence(descriptor_->containing_oneof()->index(), output); + printer->Print(variables_, "$oneof_stored_type$.class,\n"); +} + +void ImmutableMessageOneofFieldLiteGenerator::GenerateBuilderMembers( + io::Printer* printer) const { + // The comments above the methods below are based on a hypothetical + // field of type "Field" called "Field". + + // boolean hasField() + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n" + " return instance.has$capitalized_name$();\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + // Field getField() + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$public $type$ ${$get$capitalized_name$$}$() {\n" + " return instance.get$capitalized_name$();\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + // Field.Builder setField(Field value) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder " + "${$set$capitalized_name$$}$($type$ value) {\n" + " copyOnWrite();\n" + " instance.set$capitalized_name$(value);\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + // Field.Builder setField(Field.Builder builderForValue) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder ${$set$capitalized_name$$}$(\n" + " $type$.Builder builderForValue) {\n" + " copyOnWrite();\n" + " instance.set$capitalized_name$(builderForValue.build());\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + // Field.Builder mergeField(Field value) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder " + "${$merge$capitalized_name$$}$($type$ value) {\n" + " copyOnWrite();\n" + " instance.merge$capitalized_name$(value);\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + // Field.Builder clearField() + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n" + " copyOnWrite();\n" + " instance.clear$capitalized_name$();\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); +} + +// =================================================================== + +RepeatedImmutableMessageFieldLiteGenerator:: + RepeatedImmutableMessageFieldLiteGenerator( + const FieldDescriptor* descriptor, int messageBitIndex, + Context* context) + : descriptor_(descriptor), name_resolver_(context->GetNameResolver()) { + SetMessageVariables(descriptor, messageBitIndex, 0, + context->GetFieldGeneratorInfo(descriptor), + name_resolver_, &variables_); +} + +RepeatedImmutableMessageFieldLiteGenerator:: + ~RepeatedImmutableMessageFieldLiteGenerator() {} + +int RepeatedImmutableMessageFieldLiteGenerator::GetNumBitsForMessage() const { + return 0; +} + +void RepeatedImmutableMessageFieldLiteGenerator::GenerateInterfaceMembers( + io::Printer* printer) const { + // TODO(jonp): In the future, consider having methods specific to the + // interface so that builders can choose dynamically to either return a + // message or a nested builder, so that asking for the interface doesn't + // cause a message to ever be built. + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$java.util.List<$type$> \n" + " get$capitalized_name$List();\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$$type$ get$capitalized_name$(int index);\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$int get$capitalized_name$Count();\n"); +} + +void RepeatedImmutableMessageFieldLiteGenerator::GenerateMembers( + io::Printer* printer) const { + printer->Print( + variables_, + "private com.google.protobuf.Internal.ProtobufList<$type$> $name$_;\n"); + PrintExtraFieldInfo(variables_, printer); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$public java.util.List<$type$> " + "${$get$capitalized_name$List$}$() {\n" + " return $name$_;\n" // note: unmodifiable list + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$public java.util.List<? extends $type$OrBuilder> \n" + " ${$get$capitalized_name$OrBuilderList$}$() {\n" + " return $name$_;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$public int ${$get$capitalized_name$Count$}$() {\n" + " return $name$_.size();\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$public $type$ ${$get$capitalized_name$$}$(int index) {\n" + " return $name$_.get(index);\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$OrBuilder " + "${$get$capitalized_name$OrBuilder$}$(\n" + " int index) {\n" + " return $name$_.get(index);\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + printer->Print( + variables_, + "private void ensure$capitalized_name$IsMutable() {\n" + // Use a temporary to avoid a redundant iget-object. + " com.google.protobuf.Internal.ProtobufList<$type$> tmp = $name$_;\n" + " if (!tmp.isModifiable()) {\n" + " $name$_ =\n" + " com.google.protobuf.GeneratedMessageLite.mutableCopy(tmp);\n" + " }\n" + "}\n" + "\n"); + + // Builder setRepeatedField(int index, Field value) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void set$capitalized_name$(\n" + " int index, $type$ value) {\n" + " $null_check$" + " ensure$capitalized_name$IsMutable();\n" + " $name$_.set(index, value);\n" + "}\n"); + + // Builder addRepeatedField(Field value) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void add$capitalized_name$($type$ value) {\n" + " $null_check$" + " ensure$capitalized_name$IsMutable();\n" + " $name$_.add(value);\n" + "}\n"); + + // Builder addRepeatedField(int index, Field value) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void add$capitalized_name$(\n" + " int index, $type$ value) {\n" + " $null_check$" + " ensure$capitalized_name$IsMutable();\n" + " $name$_.add(index, value);\n" + "}\n"); + + // Builder addAllRepeatedField(Iterable<Field> values) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void addAll$capitalized_name$(\n" + " java.lang.Iterable<? extends $type$> values) {\n" + " ensure$capitalized_name$IsMutable();\n" + " com.google.protobuf.AbstractMessageLite.addAll(\n" + " values, $name$_);\n" + "}\n"); + + // Builder clearAllRepeatedField() + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void clear$capitalized_name$() {\n" + " $name$_ = emptyProtobufList();\n" + "}\n"); + + // Builder removeRepeatedField(int index) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void remove$capitalized_name$(int index) {\n" + " ensure$capitalized_name$IsMutable();\n" + " $name$_.remove(index);\n" + "}\n"); +} + +void RepeatedImmutableMessageFieldLiteGenerator::GenerateBuilderMembers( + io::Printer* printer) const { + // The comments above the methods below are based on a hypothetical + // repeated field of type "Field" called "RepeatedField". + + // List<Field> getRepeatedFieldList() + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$public java.util.List<$type$> " + "${$get$capitalized_name$List$}$() {\n" + " return java.util.Collections.unmodifiableList(\n" + " instance.get$capitalized_name$List());\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + // int getRepeatedFieldCount() + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$public int ${$get$capitalized_name$Count$}$() {\n" + " return instance.get$capitalized_name$Count();\n" + "}"); + printer->Annotate("{", "}", descriptor_); + + // Field getRepeatedField(int index) + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$public $type$ ${$get$capitalized_name$$}$(int index) {\n" + " return instance.get$capitalized_name$(index);\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + // Builder setRepeatedField(int index, Field value) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder ${$set$capitalized_name$$}$(\n" + " int index, $type$ value) {\n" + " copyOnWrite();\n" + " instance.set$capitalized_name$(index, value);\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + // Builder setRepeatedField(int index, Field.Builder builderForValue) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder ${$set$capitalized_name$$}$(\n" + " int index, $type$.Builder builderForValue) {\n" + " copyOnWrite();\n" + " instance.set$capitalized_name$(index,\n" + " builderForValue.build());\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + // Builder addRepeatedField(Field value) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder " + "${$add$capitalized_name$$}$($type$ value) {\n" + " copyOnWrite();\n" + " instance.add$capitalized_name$(value);\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + // Builder addRepeatedField(int index, Field value) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder ${$add$capitalized_name$$}$(\n" + " int index, $type$ value) {\n" + " copyOnWrite();\n" + " instance.add$capitalized_name$(index, value);\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + // Builder addRepeatedField(Field.Builder builderForValue) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder ${$add$capitalized_name$$}$(\n" + " $type$.Builder builderForValue) {\n" + " copyOnWrite();\n" + " instance.add$capitalized_name$(builderForValue.build());\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + // Builder addRepeatedField(int index, Field.Builder builderForValue) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder ${$add$capitalized_name$$}$(\n" + " int index, $type$.Builder builderForValue) {\n" + " copyOnWrite();\n" + " instance.add$capitalized_name$(index,\n" + " builderForValue.build());\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + // Builder addAllRepeatedField(Iterable<Field> values) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder ${$addAll$capitalized_name$$}$(\n" + " java.lang.Iterable<? extends $type$> values) {\n" + " copyOnWrite();\n" + " instance.addAll$capitalized_name$(values);\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + // Builder clearAllRepeatedField() + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n" + " copyOnWrite();\n" + " instance.clear$capitalized_name$();\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + // Builder removeRepeatedField(int index) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder " + "${$remove$capitalized_name$$}$(int index) {\n" + " copyOnWrite();\n" + " instance.remove$capitalized_name$(index);\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); +} + +void RepeatedImmutableMessageFieldLiteGenerator::GenerateFieldInfo( + io::Printer* printer, std::vector<uint16_t>* output) const { + WriteIntToUtf16CharSequence(descriptor_->number(), output); + WriteIntToUtf16CharSequence(GetExperimentalJavaFieldType(descriptor_), + output); + printer->Print(variables_, + "\"$name$_\",\n" + "$type$.class,\n"); +} + +void RepeatedImmutableMessageFieldLiteGenerator::GenerateInitializationCode( + io::Printer* printer) const { + printer->Print(variables_, "$name$_ = emptyProtobufList();\n"); +} + +std::string RepeatedImmutableMessageFieldLiteGenerator::GetBoxedType() const { + return name_resolver_->GetImmutableClassName(descriptor_->message_type()); +} + +void RepeatedImmutableMessageFieldLiteGenerator::GenerateKotlinDslMembers( + io::Printer* printer) const { + printer->Print( + variables_, + "/**\n" + " * An uninstantiable, behaviorless type to represent the field in\n" + " * generics.\n" + " */\n" + "@kotlin.OptIn" + "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n" + "public class ${$$kt_capitalized_name$Proxy$}$ private constructor()" + " : com.google.protobuf.kotlin.DslProxy()\n"); + + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$kt_deprecation$ public val $kt_name$: " + "com.google.protobuf.kotlin.DslList" + "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>\n" + " @kotlin.jvm.JvmSynthetic\n" + " get() = com.google.protobuf.kotlin.DslList(\n" + " $kt_dsl_builder$.${$get$capitalized_name$List$}$()\n" + " )\n"); + + WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER, + /* builder */ false); + printer->Print(variables_, + "@kotlin.jvm.JvmSynthetic\n" + "@kotlin.jvm.JvmName(\"add$kt_capitalized_name$\")\n" + "public fun com.google.protobuf.kotlin.DslList" + "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." + "add(value: $kt_type$) {\n" + " $kt_dsl_builder$.${$add$capitalized_name$$}$(value)\n" + "}"); + + WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER, + /* builder */ false); + printer->Print(variables_, + "@kotlin.jvm.JvmSynthetic\n" + "@kotlin.jvm.JvmName(\"plusAssign$kt_capitalized_name$\")\n" + "@Suppress(\"NOTHING_TO_INLINE\")\n" + "public inline operator fun com.google.protobuf.kotlin.DslList" + "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." + "plusAssign(value: $kt_type$) {\n" + " add(value)\n" + "}"); + + WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER, + /* builder */ false); + printer->Print(variables_, + "@kotlin.jvm.JvmSynthetic\n" + "@kotlin.jvm.JvmName(\"addAll$kt_capitalized_name$\")\n" + "public fun com.google.protobuf.kotlin.DslList" + "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." + "addAll(values: kotlin.collections.Iterable<$kt_type$>) {\n" + " $kt_dsl_builder$.${$addAll$capitalized_name$$}$(values)\n" + "}"); + + WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER, + /* builder */ false); + printer->Print( + variables_, + "@kotlin.jvm.JvmSynthetic\n" + "@kotlin.jvm.JvmName(\"plusAssignAll$kt_capitalized_name$\")\n" + "@Suppress(\"NOTHING_TO_INLINE\")\n" + "public inline operator fun com.google.protobuf.kotlin.DslList" + "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." + "plusAssign(values: kotlin.collections.Iterable<$kt_type$>) {\n" + " addAll(values)\n" + "}"); + + WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_SETTER, + /* builder */ false); + printer->Print( + variables_, + "@kotlin.jvm.JvmSynthetic\n" + "@kotlin.jvm.JvmName(\"set$kt_capitalized_name$\")\n" + "public operator fun com.google.protobuf.kotlin.DslList" + "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." + "set(index: kotlin.Int, value: $kt_type$) {\n" + " $kt_dsl_builder$.${$set$capitalized_name$$}$(index, value)\n" + "}"); + + WriteFieldAccessorDocComment(printer, descriptor_, CLEARER, + /* builder */ false); + printer->Print(variables_, + "@kotlin.jvm.JvmSynthetic\n" + "@kotlin.jvm.JvmName(\"clear$kt_capitalized_name$\")\n" + "public fun com.google.protobuf.kotlin.DslList" + "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." + "clear() {\n" + " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n" + "}"); +} + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/java/java_message_field_lite.h b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_message_field_lite.h new file mode 100644 index 00000000..d34e61a5 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_message_field_lite.h @@ -0,0 +1,140 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_FIELD_LITE_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_FIELD_LITE_H__ + +#include <cstdint> +#include <map> +#include <string> + +#include <compiler/java/java_field.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { +class Context; // context.h +class ClassNameResolver; // name_resolver.h +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +class ImmutableMessageFieldLiteGenerator : public ImmutableFieldLiteGenerator { + public: + explicit ImmutableMessageFieldLiteGenerator(const FieldDescriptor* descriptor, + int messageBitIndex, + Context* context); + ~ImmutableMessageFieldLiteGenerator(); + + // implements ImmutableFieldLiteGenerator + // ------------------------------------ + int GetNumBitsForMessage() const override; + void GenerateInterfaceMembers(io::Printer* printer) const override; + void GenerateMembers(io::Printer* printer) const override; + void GenerateBuilderMembers(io::Printer* printer) const override; + void GenerateInitializationCode(io::Printer* printer) const override; + void GenerateFieldInfo(io::Printer* printer, + std::vector<uint16_t>* output) const override; + void GenerateKotlinDslMembers(io::Printer* printer) const override; + + std::string GetBoxedType() const override; + + protected: + const FieldDescriptor* descriptor_; + std::map<std::string, std::string> variables_; + const int messageBitIndex_; + ClassNameResolver* name_resolver_; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableMessageFieldLiteGenerator); +}; + +class ImmutableMessageOneofFieldLiteGenerator + : public ImmutableMessageFieldLiteGenerator { + public: + ImmutableMessageOneofFieldLiteGenerator(const FieldDescriptor* descriptor, + int messageBitIndex, + Context* context); + ~ImmutableMessageOneofFieldLiteGenerator(); + + void GenerateMembers(io::Printer* printer) const override; + void GenerateBuilderMembers(io::Printer* printer) const override; + void GenerateFieldInfo(io::Printer* printer, + std::vector<uint16_t>* output) const override; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableMessageOneofFieldLiteGenerator); +}; + +class RepeatedImmutableMessageFieldLiteGenerator + : public ImmutableFieldLiteGenerator { + public: + explicit RepeatedImmutableMessageFieldLiteGenerator( + const FieldDescriptor* descriptor, int messageBitIndex, Context* context); + ~RepeatedImmutableMessageFieldLiteGenerator() override; + + // implements ImmutableFieldLiteGenerator ------------------------------------ + int GetNumBitsForMessage() const override; + void GenerateInterfaceMembers(io::Printer* printer) const override; + void GenerateMembers(io::Printer* printer) const override; + void GenerateBuilderMembers(io::Printer* printer) const override; + void GenerateInitializationCode(io::Printer* printer) const override; + void GenerateFieldInfo(io::Printer* printer, + std::vector<uint16_t>* output) const override; + void GenerateKotlinDslMembers(io::Printer* printer) const override; + + std::string GetBoxedType() const override; + + protected: + const FieldDescriptor* descriptor_; + std::map<std::string, std::string> variables_; + ClassNameResolver* name_resolver_; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedImmutableMessageFieldLiteGenerator); +}; + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_FIELD_LITE_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/java/java_message_lite.cc b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_message_lite.cc new file mode 100644 index 00000000..a8196c2d --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_message_lite.cc @@ -0,0 +1,977 @@ +// 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. + +// Author: dweis@google.com (Daniel Weis) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <compiler/java/java_message_lite.h> + +#include <algorithm> +#include <cstdint> +#include <map> +#include <memory> +#include <vector> + +#include <compiler/java/java_context.h> +#include <compiler/java/java_doc_comment.h> +#include <compiler/java/java_enum_lite.h> +#include <compiler/java/java_extension_lite.h> +#include <compiler/java/java_generator_factory.h> +#include <compiler/java/java_helpers.h> +#include <compiler/java/java_message_builder.h> +#include <compiler/java/java_message_builder_lite.h> +#include <compiler/java/java_name_resolver.h> +#include <descriptor.pb.h> +#include <io/coded_stream.h> +#include <io/printer.h> +#include <wire_format.h> +#include <stubs/strutil.h> +#include <stubs/substitute.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +using internal::WireFormat; +using internal::WireFormatLite; + +// =================================================================== +ImmutableMessageLiteGenerator::ImmutableMessageLiteGenerator( + const Descriptor* descriptor, Context* context) + : MessageGenerator(descriptor), + context_(context), + name_resolver_(context->GetNameResolver()), + field_generators_(descriptor, context_) { + GOOGLE_CHECK(!HasDescriptorMethods(descriptor->file(), context->EnforceLite())) + << "Generator factory error: A lite message generator is used to " + "generate non-lite messages."; + for (int i = 0; i < descriptor_->field_count(); i++) { + if (IsRealOneof(descriptor_->field(i))) { + oneofs_.insert(descriptor_->field(i)->containing_oneof()); + } + } +} + +ImmutableMessageLiteGenerator::~ImmutableMessageLiteGenerator() {} + +void ImmutableMessageLiteGenerator::GenerateStaticVariables( + io::Printer* printer, int* bytecode_estimate) { + // Generate static members for all nested types. + for (int i = 0; i < descriptor_->nested_type_count(); i++) { + // TODO(kenton): Reuse MessageGenerator objects? + ImmutableMessageLiteGenerator(descriptor_->nested_type(i), context_) + .GenerateStaticVariables(printer, bytecode_estimate); + } +} + +int ImmutableMessageLiteGenerator::GenerateStaticVariableInitializers( + io::Printer* printer) { + int bytecode_estimate = 0; + // Generate static member initializers for all nested types. + for (int i = 0; i < descriptor_->nested_type_count(); i++) { + // TODO(kenton): Reuse MessageGenerator objects? + bytecode_estimate += + ImmutableMessageLiteGenerator(descriptor_->nested_type(i), context_) + .GenerateStaticVariableInitializers(printer); + } + return bytecode_estimate; +} + +// =================================================================== + +void ImmutableMessageLiteGenerator::GenerateInterface(io::Printer* printer) { + MaybePrintGeneratedAnnotation(context_, printer, descriptor_, + /* immutable = */ true, "OrBuilder"); + if (descriptor_->extension_range_count() > 0) { + printer->Print( + "$deprecation$public interface ${$$classname$OrBuilder$}$ extends \n" + " $extra_interfaces$\n" + " com.google.protobuf.GeneratedMessageLite.\n" + " ExtendableMessageOrBuilder<\n" + " $classname$, $classname$.Builder> {\n", + "deprecation", + descriptor_->options().deprecated() ? "@java.lang.Deprecated " : "", + "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_), + "classname", descriptor_->name(), "{", "", "}", ""); + } else { + printer->Print( + "$deprecation$public interface ${$$classname$OrBuilder$}$ extends\n" + " $extra_interfaces$\n" + " com.google.protobuf.MessageLiteOrBuilder {\n", + "deprecation", + descriptor_->options().deprecated() ? "@java.lang.Deprecated " : "", + "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_), + "classname", descriptor_->name(), "{", "", "}", ""); + } + printer->Annotate("{", "}", descriptor_); + + printer->Indent(); + for (int i = 0; i < descriptor_->field_count(); i++) { + printer->Print("\n"); + field_generators_.get(descriptor_->field(i)) + .GenerateInterfaceMembers(printer); + } + for (auto oneof : oneofs_) { + printer->Print( + "\n" + "public $classname$.$oneof_capitalized_name$Case " + "get$oneof_capitalized_name$Case();\n", + "oneof_capitalized_name", + context_->GetOneofGeneratorInfo(oneof)->capitalized_name, "classname", + context_->GetNameResolver()->GetImmutableClassName(descriptor_)); + } + printer->Outdent(); + + printer->Print("}\n"); +} + +// =================================================================== + +void ImmutableMessageLiteGenerator::Generate(io::Printer* printer) { + bool is_own_file = IsOwnFile(descriptor_, /* immutable = */ true); + + std::map<std::string, std::string> variables; + variables["static"] = is_own_file ? " " : " static "; + variables["classname"] = descriptor_->name(); + variables["extra_interfaces"] = ExtraMessageInterfaces(descriptor_); + variables["deprecation"] = + descriptor_->options().deprecated() ? "@java.lang.Deprecated " : ""; + + WriteMessageDocComment(printer, descriptor_); + MaybePrintGeneratedAnnotation(context_, printer, descriptor_, + /* immutable = */ true); + + + // The builder_type stores the super type name of the nested Builder class. + std::string builder_type; + if (descriptor_->extension_range_count() > 0) { + printer->Print( + variables, + "$deprecation$public $static$final class $classname$ extends\n" + " com.google.protobuf.GeneratedMessageLite.ExtendableMessage<\n" + " $classname$, $classname$.Builder> implements\n" + " $extra_interfaces$\n" + " $classname$OrBuilder {\n"); + builder_type = strings::Substitute( + "com.google.protobuf.GeneratedMessageLite.ExtendableBuilder<$0, ?>", + name_resolver_->GetImmutableClassName(descriptor_)); + } else { + printer->Print( + variables, + "$deprecation$public $static$final class $classname$ extends\n" + " com.google.protobuf.GeneratedMessageLite<\n" + " $classname$, $classname$.Builder> implements\n" + " $extra_interfaces$\n" + " $classname$OrBuilder {\n"); + + builder_type = "com.google.protobuf.GeneratedMessageLite.Builder"; + } + printer->Indent(); + + GenerateConstructor(printer); + + // Nested types + for (int i = 0; i < descriptor_->enum_type_count(); i++) { + EnumLiteGenerator(descriptor_->enum_type(i), true, context_) + .Generate(printer); + } + + for (int i = 0; i < descriptor_->nested_type_count(); i++) { + // Don't generate Java classes for map entry messages. + if (IsMapEntry(descriptor_->nested_type(i))) continue; + ImmutableMessageLiteGenerator messageGenerator(descriptor_->nested_type(i), + context_); + messageGenerator.GenerateInterface(printer); + messageGenerator.Generate(printer); + } + + // Integers for bit fields. + int totalBits = 0; + for (int i = 0; i < descriptor_->field_count(); i++) { + totalBits += + field_generators_.get(descriptor_->field(i)).GetNumBitsForMessage(); + } + int totalInts = (totalBits + 31) / 32; + for (int i = 0; i < totalInts; i++) { + printer->Print("private int $bit_field_name$;\n", "bit_field_name", + GetBitFieldName(i)); + } + + // oneof + std::map<std::string, std::string> vars; + for (auto oneof : oneofs_) { + vars["oneof_name"] = context_->GetOneofGeneratorInfo(oneof)->name; + vars["oneof_capitalized_name"] = + context_->GetOneofGeneratorInfo(oneof)->capitalized_name; + vars["oneof_index"] = StrCat((oneof)->index()); + // oneofCase_ and oneof_ + printer->Print(vars, + "private int $oneof_name$Case_ = 0;\n" + "private java.lang.Object $oneof_name$_;\n"); + // OneofCase enum + printer->Print(vars, "public enum $oneof_capitalized_name$Case {\n"); + printer->Indent(); + for (int j = 0; j < (oneof)->field_count(); j++) { + const FieldDescriptor* field = (oneof)->field(j); + printer->Print("$field_name$($field_number$),\n", "field_name", + ToUpper(field->name()), "field_number", + StrCat(field->number())); + } + printer->Print("$cap_oneof_name$_NOT_SET(0);\n", "cap_oneof_name", + ToUpper(vars["oneof_name"])); + printer->Print(vars, + "private final int value;\n" + "private $oneof_capitalized_name$Case(int value) {\n" + " this.value = value;\n" + "}\n"); + printer->Print( + vars, + "/**\n" + " * @deprecated Use {@link #forNumber(int)} instead.\n" + " */\n" + "@java.lang.Deprecated\n" + "public static $oneof_capitalized_name$Case valueOf(int value) {\n" + " return forNumber(value);\n" + "}\n" + "\n" + "public static $oneof_capitalized_name$Case forNumber(int value) {\n" + " switch (value) {\n"); + for (int j = 0; j < (oneof)->field_count(); j++) { + const FieldDescriptor* field = (oneof)->field(j); + printer->Print(" case $field_number$: return $field_name$;\n", + "field_number", StrCat(field->number()), + "field_name", ToUpper(field->name())); + } + printer->Print( + " case 0: return $cap_oneof_name$_NOT_SET;\n" + " default: return null;\n" + " }\n" + "}\n" + // TODO(b/135620659): Rename this to "getFieldNumber" or something to + // disambiguate it from actual proto enums. + "public int getNumber() {\n" + " return this.value;\n" + "}\n", + "cap_oneof_name", ToUpper(vars["oneof_name"])); + printer->Outdent(); + printer->Print("};\n\n"); + // oneofCase() + printer->Print(vars, + "@java.lang.Override\n" + "public $oneof_capitalized_name$Case\n" + "get$oneof_capitalized_name$Case() {\n" + " return $oneof_capitalized_name$Case.forNumber(\n" + " $oneof_name$Case_);\n" + "}\n" + "\n" + "private void clear$oneof_capitalized_name$() {\n" + " $oneof_name$Case_ = 0;\n" + " $oneof_name$_ = null;\n" + "}\n" + "\n"); + } + + // Fields + for (int i = 0; i < descriptor_->field_count(); i++) { + printer->Print("public static final int $constant_name$ = $number$;\n", + "constant_name", FieldConstantName(descriptor_->field(i)), + "number", StrCat(descriptor_->field(i)->number())); + field_generators_.get(descriptor_->field(i)).GenerateMembers(printer); + printer->Print("\n"); + } + + GenerateParseFromMethods(printer); + GenerateBuilder(printer); + + if (HasRequiredFields(descriptor_)) { + // Memoizes whether the protocol buffer is fully initialized (has all + // required fields). 0 means false, 1 means true, and all other values + // mean not yet computed. + printer->Print("private byte memoizedIsInitialized = 2;\n"); + } + + printer->Print( + "@java.lang.Override\n" + "@java.lang.SuppressWarnings({\"unchecked\", \"fallthrough\"})\n" + "protected final java.lang.Object dynamicMethod(\n" + " com.google.protobuf.GeneratedMessageLite.MethodToInvoke method,\n" + " java.lang.Object arg0, java.lang.Object arg1) {\n" + " switch (method) {\n" + " case NEW_MUTABLE_INSTANCE: {\n" + " return new $classname$();\n" + " }\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_)); + + printer->Indent(); + printer->Indent(); + + printer->Print("case NEW_BUILDER: {\n"); + + printer->Indent(); + GenerateDynamicMethodNewBuilder(printer); + printer->Outdent(); + + printer->Print( + "}\n" + "case BUILD_MESSAGE_INFO: {\n"); + + printer->Indent(); + GenerateDynamicMethodNewBuildMessageInfo(printer); + printer->Outdent(); + + printer->Print( + "}\n" + "// fall through\n" + "case GET_DEFAULT_INSTANCE: {\n" + " return DEFAULT_INSTANCE;\n" + "}\n" + "case GET_PARSER: {\n" + // Generally one would use the lazy initialization holder pattern for + // manipulating static fields but that has exceptional cost on Android as + // it will generate an extra class for every message. Instead, use the + // double-check locking pattern which works just as well. + // + // The "parser" temporary mirrors the "PARSER" field to eliminate a read + // at the final return statement. + " com.google.protobuf.Parser<$classname$> parser = PARSER;\n" + " if (parser == null) {\n" + " synchronized ($classname$.class) {\n" + " parser = PARSER;\n" + " if (parser == null) {\n" + " parser =\n" + " new DefaultInstanceBasedParser<$classname$>(\n" + " DEFAULT_INSTANCE);\n" + " PARSER = parser;\n" + " }\n" + " }\n" + " }\n" + " return parser;\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_)); + + printer->Outdent(); + + if (HasRequiredFields(descriptor_)) { + printer->Print( + "}\n" + "case GET_MEMOIZED_IS_INITIALIZED: {\n" + " return memoizedIsInitialized;\n" + "}\n" + "case SET_MEMOIZED_IS_INITIALIZED: {\n" + " memoizedIsInitialized = (byte) (arg0 == null ? 0 : 1);\n" + " return null;\n" + "}\n"); + } else { + printer->Print( + "}\n" + "case GET_MEMOIZED_IS_INITIALIZED: {\n" + " return (byte) 1;\n" + "}\n" + "case SET_MEMOIZED_IS_INITIALIZED: {\n" + " return null;\n" + "}\n"); + } + + printer->Outdent(); + printer->Print( + " }\n" + " throw new UnsupportedOperationException();\n" + "}\n" + "\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_)); + + printer->Print( + "\n" + "// @@protoc_insertion_point(class_scope:$full_name$)\n", + "full_name", descriptor_->full_name()); + + // Carefully initialize the default instance in such a way that it doesn't + // conflict with other initialization. + printer->Print("private static final $classname$ DEFAULT_INSTANCE;\n", + "classname", + name_resolver_->GetImmutableClassName(descriptor_)); + + printer->Print( + "static {\n" + " $classname$ defaultInstance = new $classname$();\n" + " // New instances are implicitly immutable so no need to make\n" + " // immutable.\n" + " DEFAULT_INSTANCE = defaultInstance;\n" + // Register the default instance in a map. This map will be used by + // experimental runtime to lookup default instance given a class instance + // without using Java reflection. + " com.google.protobuf.GeneratedMessageLite.registerDefaultInstance(\n" + " $classname$.class, defaultInstance);\n" + "}\n" + "\n", + "classname", descriptor_->name()); + + printer->Print( + "public static $classname$ getDefaultInstance() {\n" + " return DEFAULT_INSTANCE;\n" + "}\n" + "\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_)); + + // 'of' method for Wrappers + if (IsWrappersProtoFile(descriptor_->file())) { + printer->Print( + "public static $classname$ of($field_type$ value) {\n" + " return newBuilder().setValue(value).build();\n" + "}\n" + "\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_), + "field_type", PrimitiveTypeName(GetJavaType(descriptor_->field(0)))); + } + + GenerateParser(printer); + + // Extensions must be declared after the DEFAULT_INSTANCE is initialized + // because the DEFAULT_INSTANCE is used by the extension to lazily retrieve + // the outer class's FileDescriptor. + for (int i = 0; i < descriptor_->extension_count(); i++) { + ImmutableExtensionLiteGenerator(descriptor_->extension(i), context_) + .Generate(printer); + } + + printer->Outdent(); + printer->Print("}\n\n"); +} + +void ImmutableMessageLiteGenerator::GenerateDynamicMethodNewBuildMessageInfo( + io::Printer* printer) { + printer->Indent(); + + // Collect field info into a sequence of UTF-16 chars. It will be embedded + // as a Java string in the generated code. + std::vector<uint16_t> chars; + + int flags = 0; + if (IsProto2(descriptor_->file())) { + flags |= 0x1; + } + if (descriptor_->options().message_set_wire_format()) { + flags |= 0x2; + } + WriteIntToUtf16CharSequence(flags, &chars); + WriteIntToUtf16CharSequence(descriptor_->field_count(), &chars); + + if (descriptor_->field_count() == 0) { + printer->Print("java.lang.Object[] objects = null;"); + } else { + // A single array of all fields (including oneof, oneofCase, hasBits). + printer->Print("java.lang.Object[] objects = new java.lang.Object[] {\n"); + printer->Indent(); + + // Record the number of oneofs. + WriteIntToUtf16CharSequence(oneofs_.size(), &chars); + for (auto oneof : oneofs_) { + printer->Print( + "\"$oneof_name$_\",\n" + "\"$oneof_name$Case_\",\n", + "oneof_name", context_->GetOneofGeneratorInfo(oneof)->name); + } + + // Integers for bit fields. + int total_bits = 0; + for (int i = 0; i < descriptor_->field_count(); i++) { + total_bits += + field_generators_.get(descriptor_->field(i)).GetNumBitsForMessage(); + } + int total_ints = (total_bits + 31) / 32; + for (int i = 0; i < total_ints; i++) { + printer->Print("\"$bit_field_name$\",\n", "bit_field_name", + GetBitFieldName(i)); + } + WriteIntToUtf16CharSequence(total_ints, &chars); + + int map_count = 0; + int repeated_count = 0; + std::unique_ptr<const FieldDescriptor*[]> sorted_fields( + SortFieldsByNumber(descriptor_)); + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = sorted_fields[i]; + if (field->is_map()) { + map_count++; + } else if (field->is_repeated()) { + repeated_count++; + } + } + + WriteIntToUtf16CharSequence(sorted_fields[0]->number(), &chars); + WriteIntToUtf16CharSequence( + sorted_fields[descriptor_->field_count() - 1]->number(), &chars); + WriteIntToUtf16CharSequence(descriptor_->field_count(), &chars); + WriteIntToUtf16CharSequence(map_count, &chars); + WriteIntToUtf16CharSequence(repeated_count, &chars); + + std::vector<const FieldDescriptor*> fields_for_is_initialized_check; + for (int i = 0; i < descriptor_->field_count(); i++) { + if (descriptor_->field(i)->is_required() || + (GetJavaType(descriptor_->field(i)) == JAVATYPE_MESSAGE && + HasRequiredFields(descriptor_->field(i)->message_type()))) { + fields_for_is_initialized_check.push_back(descriptor_->field(i)); + } + } + WriteIntToUtf16CharSequence(fields_for_is_initialized_check.size(), &chars); + + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = sorted_fields[i]; + field_generators_.get(field).GenerateFieldInfo(printer, &chars); + } + printer->Outdent(); + printer->Print("};\n"); + } + + printer->Print("java.lang.String info =\n"); + std::string line; + for (size_t i = 0; i < chars.size(); i++) { + uint16_t code = chars[i]; + EscapeUtf16ToString(code, &line); + if (line.size() >= 80) { + printer->Print(" \"$string$\" +\n", "string", line); + line.clear(); + } + } + printer->Print(" \"$string$\";\n", "string", line); + + printer->Print("return newMessageInfo(DEFAULT_INSTANCE, info, objects);\n"); + printer->Outdent(); +} + +// =================================================================== + +void ImmutableMessageLiteGenerator::GenerateParseFromMethods( + io::Printer* printer) { + printer->Print( + "public static $classname$ parseFrom(\n" + " java.nio.ByteBuffer data)\n" + " throws com.google.protobuf.InvalidProtocolBufferException {\n" + " return com.google.protobuf.GeneratedMessageLite.parseFrom(\n" + " DEFAULT_INSTANCE, data);\n" + "}\n" + "public static $classname$ parseFrom(\n" + " java.nio.ByteBuffer data,\n" + " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" + " throws com.google.protobuf.InvalidProtocolBufferException {\n" + " return com.google.protobuf.GeneratedMessageLite.parseFrom(\n" + " DEFAULT_INSTANCE, data, extensionRegistry);\n" + "}\n" + "public static $classname$ parseFrom(\n" + " com.google.protobuf.ByteString data)\n" + " throws com.google.protobuf.InvalidProtocolBufferException {\n" + " return com.google.protobuf.GeneratedMessageLite.parseFrom(\n" + " DEFAULT_INSTANCE, data);\n" + "}\n" + "public static $classname$ parseFrom(\n" + " com.google.protobuf.ByteString data,\n" + " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" + " throws com.google.protobuf.InvalidProtocolBufferException {\n" + " return com.google.protobuf.GeneratedMessageLite.parseFrom(\n" + " DEFAULT_INSTANCE, data, extensionRegistry);\n" + "}\n" + "public static $classname$ parseFrom(byte[] data)\n" + " throws com.google.protobuf.InvalidProtocolBufferException {\n" + " return com.google.protobuf.GeneratedMessageLite.parseFrom(\n" + " DEFAULT_INSTANCE, data);\n" + "}\n" + "public static $classname$ parseFrom(\n" + " byte[] data,\n" + " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" + " throws com.google.protobuf.InvalidProtocolBufferException {\n" + " return com.google.protobuf.GeneratedMessageLite.parseFrom(\n" + " DEFAULT_INSTANCE, data, extensionRegistry);\n" + "}\n" + "public static $classname$ parseFrom(java.io.InputStream input)\n" + " throws java.io.IOException {\n" + " return com.google.protobuf.GeneratedMessageLite.parseFrom(\n" + " DEFAULT_INSTANCE, input);\n" + "}\n" + "public static $classname$ parseFrom(\n" + " java.io.InputStream input,\n" + " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" + " throws java.io.IOException {\n" + " return com.google.protobuf.GeneratedMessageLite.parseFrom(\n" + " DEFAULT_INSTANCE, input, extensionRegistry);\n" + "}\n" + "public static $classname$ parseDelimitedFrom(java.io.InputStream " + "input)\n" + " throws java.io.IOException {\n" + " return parseDelimitedFrom(DEFAULT_INSTANCE, input);\n" + "}\n" + "public static $classname$ parseDelimitedFrom(\n" + " java.io.InputStream input,\n" + " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" + " throws java.io.IOException {\n" + " return parseDelimitedFrom(DEFAULT_INSTANCE, input, " + "extensionRegistry);\n" + "}\n" + "public static $classname$ parseFrom(\n" + " com.google.protobuf.CodedInputStream input)\n" + " throws java.io.IOException {\n" + " return com.google.protobuf.GeneratedMessageLite.parseFrom(\n" + " DEFAULT_INSTANCE, input);\n" + "}\n" + "public static $classname$ parseFrom(\n" + " com.google.protobuf.CodedInputStream input,\n" + " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" + " throws java.io.IOException {\n" + " return com.google.protobuf.GeneratedMessageLite.parseFrom(\n" + " DEFAULT_INSTANCE, input, extensionRegistry);\n" + "}\n" + "\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_)); +} + +// =================================================================== + +void ImmutableMessageLiteGenerator::GenerateBuilder(io::Printer* printer) { + printer->Print( + "public static Builder newBuilder() {\n" + " return (Builder) DEFAULT_INSTANCE.createBuilder();\n" + "}\n" + "public static Builder newBuilder($classname$ prototype) {\n" + " return (Builder) DEFAULT_INSTANCE.createBuilder(prototype);\n" + "}\n" + "\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_)); + + MessageBuilderLiteGenerator builderGenerator(descriptor_, context_); + builderGenerator.Generate(printer); +} + +// =================================================================== + +void ImmutableMessageLiteGenerator::GenerateDynamicMethodNewBuilder( + io::Printer* printer) { + printer->Print("return new Builder();\n"); +} + +// =================================================================== + +void ImmutableMessageLiteGenerator::GenerateExtensionRegistrationCode( + io::Printer* printer) { + for (int i = 0; i < descriptor_->extension_count(); i++) { + ImmutableExtensionLiteGenerator(descriptor_->extension(i), context_) + .GenerateRegistrationCode(printer); + } + + for (int i = 0; i < descriptor_->nested_type_count(); i++) { + ImmutableMessageLiteGenerator(descriptor_->nested_type(i), context_) + .GenerateExtensionRegistrationCode(printer); + } +} + +// =================================================================== +void ImmutableMessageLiteGenerator::GenerateConstructor(io::Printer* printer) { + printer->Print("private $classname$() {\n", "classname", descriptor_->name()); + printer->Indent(); + + // Initialize all fields to default. + GenerateInitializers(printer); + + printer->Outdent(); + printer->Print("}\n"); +} + +// =================================================================== +void ImmutableMessageLiteGenerator::GenerateParser(io::Printer* printer) { + printer->Print( + "private static volatile com.google.protobuf.Parser<$classname$> " + "PARSER;\n" + "\n" + "public static com.google.protobuf.Parser<$classname$> parser() {\n" + " return DEFAULT_INSTANCE.getParserForType();\n" + "}\n", + "classname", descriptor_->name()); +} + +// =================================================================== +void ImmutableMessageLiteGenerator::GenerateInitializers(io::Printer* printer) { + for (int i = 0; i < descriptor_->field_count(); i++) { + if (!IsRealOneof(descriptor_->field(i))) { + field_generators_.get(descriptor_->field(i)) + .GenerateInitializationCode(printer); + } + } +} + +void ImmutableMessageLiteGenerator::GenerateKotlinDsl( + io::Printer* printer) const { + printer->Print( + "@kotlin.OptIn" + "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n" + "@com.google.protobuf.kotlin.ProtoDslMarker\n"); + printer->Print( + "public class Dsl private constructor(\n" + " private val _builder: $message$.Builder\n" + ") {\n" + " public companion object {\n" + " @kotlin.jvm.JvmSynthetic\n" + " @kotlin.PublishedApi\n" + " internal fun _create(builder: $message$.Builder): Dsl = " + "Dsl(builder)\n" + " }\n" + "\n" + " @kotlin.jvm.JvmSynthetic\n" + " @kotlin.PublishedApi\n" + " internal fun _build(): $message$ = _builder.build()\n", + "message", name_resolver_->GetClassName(descriptor_, true)); + + printer->Indent(); + + for (int i = 0; i < descriptor_->field_count(); i++) { + printer->Print("\n"); + field_generators_.get(descriptor_->field(i)) + .GenerateKotlinDslMembers(printer); + } + + for (auto oneof : oneofs_) { + printer->Print( + "public val $oneof_name$Case: $message$.$oneof_capitalized_name$Case\n" + " @JvmName(\"get$oneof_capitalized_name$Case\")\n" + " get() = _builder.get$oneof_capitalized_name$Case()\n\n" + "public fun clear$oneof_capitalized_name$() {\n" + " _builder.clear$oneof_capitalized_name$()\n" + "}\n", + "oneof_name", context_->GetOneofGeneratorInfo(oneof)->name, + "oneof_capitalized_name", + context_->GetOneofGeneratorInfo(oneof)->capitalized_name, "message", + name_resolver_->GetClassName(descriptor_, true)); + } + + if (descriptor_->extension_range_count() > 0) { + GenerateKotlinExtensions(printer); + } + + printer->Outdent(); + printer->Print("}\n"); +} + +void ImmutableMessageLiteGenerator::GenerateKotlinMembers( + io::Printer* printer) const { + printer->Print( + "@kotlin.jvm.JvmSynthetic\n" + "public inline fun $camelcase_name$(block: $message_kt$.Dsl.() -> " + "kotlin.Unit): " + "$message$ =\n" + " $message_kt$.Dsl._create($message$.newBuilder()).apply { block() " + "}._build()\n", + "camelcase_name", name_resolver_->GetKotlinFactoryName(descriptor_), + "message_kt", name_resolver_->GetKotlinExtensionsClassName(descriptor_), + "message", name_resolver_->GetClassName(descriptor_, true)); + + printer->Print("public object $name$Kt {\n", "name", descriptor_->name()); + printer->Indent(); + GenerateKotlinDsl(printer); + for (int i = 0; i < descriptor_->nested_type_count(); i++) { + if (IsMapEntry(descriptor_->nested_type(i))) continue; + ImmutableMessageLiteGenerator(descriptor_->nested_type(i), context_) + .GenerateKotlinMembers(printer); + } + printer->Outdent(); + printer->Print("}\n"); +} + +void ImmutableMessageLiteGenerator::GenerateTopLevelKotlinMembers( + io::Printer* printer) const { + printer->Print( + "public inline fun $message$.copy(block: $message_kt$.Dsl.() -> " + "kotlin.Unit): " + "$message$ =\n" + " $message_kt$.Dsl._create(this.toBuilder()).apply { block() " + "}._build()\n", + "message", name_resolver_->GetClassName(descriptor_, true), "message_kt", + name_resolver_->GetKotlinExtensionsClassName(descriptor_)); + + for (int i = 0; i < descriptor_->nested_type_count(); i++) { + if (IsMapEntry(descriptor_->nested_type(i))) continue; + ImmutableMessageLiteGenerator(descriptor_->nested_type(i), context_) + .GenerateTopLevelKotlinMembers(printer); + } +} + +void ImmutableMessageLiteGenerator::GenerateKotlinExtensions( + io::Printer* printer) const { + std::string message_name = name_resolver_->GetClassName(descriptor_, true); + + printer->Print( + "@Suppress(\"UNCHECKED_CAST\")\n" + "@kotlin.jvm.JvmSynthetic\n" + "public operator fun <T> get(extension: " + "com.google.protobuf.ExtensionLite<$message$, T>): T {\n" + " return if (extension.isRepeated) {\n" + " get(extension as com.google.protobuf.ExtensionLite<$message$, " + "List<*>>) as T\n" + " } else {\n" + " _builder.getExtension(extension)\n" + " }\n" + "}\n\n", + "message", message_name); + + printer->Print( + "@kotlin.jvm.JvmSynthetic\n" + "@kotlin.OptIn" + "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n" + "@kotlin.jvm.JvmName(\"-getRepeatedExtension\")\n" + "public operator fun <E> get(\n" + " extension: com.google.protobuf.ExtensionLite<$message$, List<E>>\n" + "): com.google.protobuf.kotlin.ExtensionList<E, $message$> {\n" + " return com.google.protobuf.kotlin.ExtensionList(extension, " + "_builder.getExtension(extension))\n" + "}\n\n", + "message", message_name); + + printer->Print( + "@kotlin.jvm.JvmSynthetic\n" + "public operator fun contains(extension: " + "com.google.protobuf.ExtensionLite<$message$, *>): " + "Boolean {\n" + " return _builder.hasExtension(extension)\n" + "}\n\n", + "message", message_name); + + printer->Print( + "@kotlin.jvm.JvmSynthetic\n" + "public fun clear(extension: " + "com.google.protobuf.ExtensionLite<$message$, *>) " + "{\n" + " _builder.clearExtension(extension)\n" + "}\n\n", + "message", message_name); + + printer->Print( + "@kotlin.jvm.JvmSynthetic\n" + "@kotlin.PublishedApi\n" + "internal fun <T> setExtension(extension: " + "com.google.protobuf.ExtensionLite<$message$, T>, " + "value: T) {\n" + " _builder.setExtension(extension, value)\n" + "}\n\n", + "message", message_name); + + printer->Print( + "@kotlin.jvm.JvmSynthetic\n" + "@Suppress(\"NOTHING_TO_INLINE\")\n" + "public inline operator fun <T : Comparable<T>> set(\n" + " extension: com.google.protobuf.ExtensionLite<$message$, T>,\n" + " value: T\n" + ") {\n" + " setExtension(extension, value)\n" + "}\n\n", + "message", message_name); + + printer->Print( + "@kotlin.jvm.JvmSynthetic\n" + "@Suppress(\"NOTHING_TO_INLINE\")\n" + "public inline operator fun set(\n" + " extension: com.google.protobuf.ExtensionLite<$message$, " + "com.google.protobuf.ByteString>,\n" + " value: com.google.protobuf.ByteString\n" + ") {\n" + " setExtension(extension, value)\n" + "}\n\n", + "message", message_name); + + printer->Print( + "@kotlin.jvm.JvmSynthetic\n" + "@Suppress(\"NOTHING_TO_INLINE\")\n" + "public inline operator fun <T : com.google.protobuf.MessageLite> set(\n" + " extension: com.google.protobuf.ExtensionLite<$message$, T>,\n" + " value: T\n" + ") {\n" + " setExtension(extension, value)\n" + "}\n\n", + "message", message_name); + + printer->Print( + "@kotlin.jvm.JvmSynthetic\n" + "public fun<E> com.google.protobuf.kotlin.ExtensionList<E, " + "$message$>.add(value: E) {\n" + " _builder.addExtension(this.extension, value)\n" + "}\n\n", + "message", message_name); + + printer->Print( + "@kotlin.jvm.JvmSynthetic\n" + "@Suppress(\"NOTHING_TO_INLINE\")\n" + "public inline operator fun <E> " + "com.google.protobuf.kotlin.ExtensionList<E, " + "$message$>.plusAssign" + "(value: E) {\n" + " add(value)\n" + "}\n\n", + "message", message_name); + + printer->Print( + "@kotlin.jvm.JvmSynthetic\n" + "public fun<E> com.google.protobuf.kotlin.ExtensionList<E, " + "$message$>.addAll(values: Iterable<E>) {\n" + " for (value in values) {\n" + " add(value)\n" + " }\n" + "}\n\n", + "message", message_name); + + printer->Print( + "@kotlin.jvm.JvmSynthetic\n" + "@Suppress(\"NOTHING_TO_INLINE\")\n" + "public inline operator fun <E> " + "com.google.protobuf.kotlin.ExtensionList<E, " + "$message$>.plusAssign(values: " + "Iterable<E>) {\n" + " addAll(values)\n" + "}\n\n", + "message", message_name); + + printer->Print( + "@kotlin.jvm.JvmSynthetic\n" + "public operator fun <E> com.google.protobuf.kotlin.ExtensionList<E, " + "$message$>.set(index: Int, value: " + "E) {\n" + " _builder.setExtension(this.extension, index, value)\n" + "}\n\n", + "message", message_name); + + printer->Print( + "@kotlin.jvm.JvmSynthetic\n" + "@Suppress(\"NOTHING_TO_INLINE\")\n" + "public inline fun com.google.protobuf.kotlin.ExtensionList<*, " + "$message$>.clear() {\n" + " clear(extension)\n" + "}\n\n", + "message", message_name); +} + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/java/java_message_lite.h b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_message_lite.h new file mode 100644 index 00000000..02f144bd --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_message_lite.h @@ -0,0 +1,86 @@ +// 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. + +// Author: dweis@google.com (Daniel Weis) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_LITE_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_LITE_H__ + +#include <map> +#include <string> +#include <compiler/java/java_field.h> +#include <compiler/java/java_message.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +class ImmutableMessageLiteGenerator : public MessageGenerator { + public: + ImmutableMessageLiteGenerator(const Descriptor* descriptor, Context* context); + virtual ~ImmutableMessageLiteGenerator(); + + void Generate(io::Printer* printer) override; + void GenerateInterface(io::Printer* printer) override; + void GenerateExtensionRegistrationCode(io::Printer* printer) override; + void GenerateStaticVariables(io::Printer* printer, + int* bytecode_estimate) override; + int GenerateStaticVariableInitializers(io::Printer* printer) override; + void GenerateKotlinDsl(io::Printer* printer) const override; + void GenerateKotlinMembers(io::Printer* printer) const override; + void GenerateTopLevelKotlinMembers(io::Printer* printer) const override; + + private: + void GenerateParseFromMethods(io::Printer* printer); + + void GenerateBuilder(io::Printer* printer); + void GenerateDynamicMethodNewBuilder(io::Printer* printer); + void GenerateInitializers(io::Printer* printer); + void GenerateParser(io::Printer* printer); + void GenerateConstructor(io::Printer* printer); + void GenerateDynamicMethodNewBuildMessageInfo(io::Printer* printer); + void GenerateKotlinExtensions(io::Printer* printer) const; + + Context* context_; + ClassNameResolver* name_resolver_; + FieldGeneratorMap<ImmutableFieldLiteGenerator> field_generators_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableMessageLiteGenerator); +}; + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_LITE_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/java/java_name_resolver.cc b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_name_resolver.cc new file mode 100644 index 00000000..2d753bc5 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_name_resolver.cc @@ -0,0 +1,380 @@ +// 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 <compiler/java/java_name_resolver.h> + +#include <map> +#include <string> + +#include <compiler/java/java_helpers.h> +#include <compiler/java/java_names.h> +#include <compiler/code_generator.h> +#include <stubs/substitute.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +namespace { +// A suffix that will be appended to the file's outer class name if the name +// conflicts with some other types defined in the file. +const char* kOuterClassNameSuffix = "OuterClass"; + +// Strip package name from a descriptor's full name. +// For example: +// Full name : foo.Bar.Baz +// Package name: foo +// After strip : Bar.Baz +std::string StripPackageName(const std::string& full_name, + const FileDescriptor* file) { + if (file->package().empty()) { + return full_name; + } else { + // Strip package name + return full_name.substr(file->package().size() + 1); + } +} + +// Get the name of a message's Java class without package name prefix. +std::string ClassNameWithoutPackage(const Descriptor* descriptor, + bool immutable) { + return StripPackageName(descriptor->full_name(), descriptor->file()); +} + +std::string ClassNameWithoutPackageKotlin(const Descriptor* descriptor) { + std::string result = descriptor->name(); + const Descriptor* temp = descriptor->containing_type(); + + while (temp) { + result = temp->name() + "Kt." + result; + temp = temp->containing_type(); + } + return result; +} + +// Get the name of an enum's Java class without package name prefix. +std::string ClassNameWithoutPackage(const EnumDescriptor* descriptor, + bool immutable) { + // Doesn't append "Mutable" for enum type's name. + const Descriptor* message_descriptor = descriptor->containing_type(); + if (message_descriptor == NULL) { + return descriptor->name(); + } else { + return ClassNameWithoutPackage(message_descriptor, immutable) + "." + + descriptor->name(); + } +} + +// Get the name of a service's Java class without package name prefix. +std::string ClassNameWithoutPackage(const ServiceDescriptor* descriptor, + bool immutable) { + std::string full_name = + StripPackageName(descriptor->full_name(), descriptor->file()); + // We don't allow nested service definitions. + GOOGLE_CHECK(full_name.find('.') == std::string::npos); + return full_name; +} + +// Return true if a and b are equals (case insensitive). +NameEquality CheckNameEquality(const std::string& a, const std::string& b) { + if (ToUpper(a) == ToUpper(b)) { + if (a == b) { + return NameEquality::EXACT_EQUAL; + } + return NameEquality::EQUAL_IGNORE_CASE; + } + return NameEquality::NO_MATCH; +} + +// Check whether a given message or its nested types has the given class name. +bool MessageHasConflictingClassName(const Descriptor* message, + const std::string& classname, + NameEquality equality_mode) { + if (CheckNameEquality(message->name(), classname) == equality_mode) { + return true; + } + for (int i = 0; i < message->nested_type_count(); ++i) { + if (MessageHasConflictingClassName(message->nested_type(i), classname, + equality_mode)) { + return true; + } + } + for (int i = 0; i < message->enum_type_count(); ++i) { + if (CheckNameEquality(message->enum_type(i)->name(), classname) == + equality_mode) { + return true; + } + } + return false; +} + +} // namespace + +ClassNameResolver::ClassNameResolver() {} + +ClassNameResolver::~ClassNameResolver() {} + +std::string ClassNameResolver::GetFileDefaultImmutableClassName( + const FileDescriptor* file) { + std::string basename; + std::string::size_type last_slash = file->name().find_last_of('/'); + if (last_slash == std::string::npos) { + basename = file->name(); + } else { + basename = file->name().substr(last_slash + 1); + } + return UnderscoresToCamelCase(StripProto(basename), true); +} + +std::string ClassNameResolver::GetFileImmutableClassName( + const FileDescriptor* file) { + std::string& class_name = file_immutable_outer_class_names_[file]; + if (class_name.empty()) { + if (file->options().has_java_outer_classname()) { + class_name = file->options().java_outer_classname(); + } else { + class_name = GetFileDefaultImmutableClassName(file); + if (HasConflictingClassName(file, class_name, + NameEquality::EXACT_EQUAL)) { + class_name += kOuterClassNameSuffix; + } + } + } + return class_name; +} + +std::string ClassNameResolver::GetFileClassName(const FileDescriptor* file, + bool immutable) { + return GetFileClassName(file, immutable, false); +} + +std::string ClassNameResolver::GetFileClassName(const FileDescriptor* file, + bool immutable, bool kotlin) { + if (kotlin) { + return GetFileImmutableClassName(file) + "Kt"; + } else if (immutable) { + return GetFileImmutableClassName(file); + } else { + return "Mutable" + GetFileImmutableClassName(file); + } +} + +// Check whether there is any type defined in the proto file that has +// the given class name. +bool ClassNameResolver::HasConflictingClassName(const FileDescriptor* file, + const std::string& classname, + NameEquality equality_mode) { + for (int i = 0; i < file->enum_type_count(); i++) { + if (CheckNameEquality(file->enum_type(i)->name(), classname) == + equality_mode) { + return true; + } + } + for (int i = 0; i < file->service_count(); i++) { + if (CheckNameEquality(file->service(i)->name(), classname) == + equality_mode) { + return true; + } + } + for (int i = 0; i < file->message_type_count(); i++) { + if (MessageHasConflictingClassName(file->message_type(i), classname, + equality_mode)) { + return true; + } + } + return false; +} + +std::string ClassNameResolver::GetDescriptorClassName( + const FileDescriptor* descriptor) { + return GetFileImmutableClassName(descriptor); +} + +std::string ClassNameResolver::GetClassName(const FileDescriptor* descriptor, + bool immutable) { + return GetClassName(descriptor, immutable, false); +} + +std::string ClassNameResolver::GetClassName(const FileDescriptor* descriptor, + bool immutable, bool kotlin) { + std::string result = FileJavaPackage(descriptor, immutable); + if (!result.empty()) result += '.'; + result += GetFileClassName(descriptor, immutable, kotlin); + return result; +} + +// Get the full name of a Java class by prepending the Java package name +// or outer class name. +std::string ClassNameResolver::GetClassFullName( + const std::string& name_without_package, const FileDescriptor* file, + bool immutable, bool is_own_file) { + return GetClassFullName(name_without_package, file, immutable, is_own_file, + false); +} + +std::string ClassNameResolver::GetClassFullName( + const std::string& name_without_package, const FileDescriptor* file, + bool immutable, bool is_own_file, bool kotlin) { + std::string result; + if (is_own_file) { + result = FileJavaPackage(file, immutable); + } else { + result = GetClassName(file, immutable, kotlin); + } + if (!result.empty()) { + result += '.'; + } + result += name_without_package; + if (kotlin) result += "Kt"; + return result; +} + +std::string ClassNameResolver::GetClassName(const Descriptor* descriptor, + bool immutable) { + return GetClassName(descriptor, immutable, false); +} + +std::string ClassNameResolver::GetClassName(const Descriptor* descriptor, + bool immutable, bool kotlin) { + return GetClassFullName( + ClassNameWithoutPackage(descriptor, immutable), descriptor->file(), + immutable, MultipleJavaFiles(descriptor->file(), immutable), kotlin); +} + +std::string ClassNameResolver::GetClassName(const EnumDescriptor* descriptor, + bool immutable) { + return GetClassName(descriptor, immutable, false); +} + +std::string ClassNameResolver::GetClassName(const EnumDescriptor* descriptor, + bool immutable, bool kotlin) { + return GetClassFullName( + ClassNameWithoutPackage(descriptor, immutable), descriptor->file(), + immutable, MultipleJavaFiles(descriptor->file(), immutable), kotlin); +} + +std::string ClassNameResolver::GetClassName(const ServiceDescriptor* descriptor, + bool immutable) { + return GetClassName(descriptor, immutable, false); +} + +std::string ClassNameResolver::GetClassName(const ServiceDescriptor* descriptor, + bool immutable, bool kotlin) { + return GetClassFullName(ClassNameWithoutPackage(descriptor, immutable), + descriptor->file(), immutable, + IsOwnFile(descriptor, immutable), kotlin); +} + +// Get the Java Class style full name of a message. +std::string ClassNameResolver::GetJavaClassFullName( + const std::string& name_without_package, const FileDescriptor* file, + bool immutable) { + return GetJavaClassFullName(name_without_package, file, immutable, false); +} + +std::string ClassNameResolver::GetJavaClassFullName( + const std::string& name_without_package, const FileDescriptor* file, + bool immutable, bool kotlin) { + std::string result; + if (MultipleJavaFiles(file, immutable)) { + result = FileJavaPackage(file, immutable); + if (!result.empty()) result += '.'; + } else { + result = GetClassName(file, immutable, kotlin); + if (!result.empty()) result += '$'; + } + result += StringReplace(name_without_package, ".", "$", true); + return result; +} + +std::string ClassNameResolver::GetExtensionIdentifierName( + const FieldDescriptor* descriptor, bool immutable) { + return GetExtensionIdentifierName(descriptor, immutable, false); +} + +std::string ClassNameResolver::GetExtensionIdentifierName( + const FieldDescriptor* descriptor, bool immutable, bool kotlin) { + return GetClassName(descriptor->containing_type(), immutable, kotlin) + "." + + descriptor->name(); +} + +std::string ClassNameResolver::GetKotlinFactoryName( + const Descriptor* descriptor) { + std::string name = ToCamelCase(descriptor->name(), /* lower_first = */ true); + return IsForbiddenKotlin(name) ? name + "_" : name; +} + +std::string ClassNameResolver::GetJavaImmutableClassName( + const Descriptor* descriptor) { + return GetJavaClassFullName(ClassNameWithoutPackage(descriptor, true), + descriptor->file(), true); +} + +std::string ClassNameResolver::GetJavaImmutableClassName( + const EnumDescriptor* descriptor) { + return GetJavaClassFullName(ClassNameWithoutPackage(descriptor, true), + descriptor->file(), true); +} + +std::string ClassNameResolver::GetKotlinExtensionsClassName( + const Descriptor* descriptor) { + return GetClassFullName(ClassNameWithoutPackageKotlin(descriptor), + descriptor->file(), true, true, true); +} + +std::string ClassNameResolver::GetJavaMutableClassName( + const Descriptor* descriptor) { + return GetJavaClassFullName(ClassNameWithoutPackage(descriptor, false), + descriptor->file(), false); +} + +std::string ClassNameResolver::GetJavaMutableClassName( + const EnumDescriptor* descriptor) { + return GetJavaClassFullName(ClassNameWithoutPackage(descriptor, false), + descriptor->file(), false); +} + +std::string ClassNameResolver::GetDowngradedFileClassName( + const FileDescriptor* file) { + return "Downgraded" + GetFileClassName(file, false); +} + +std::string ClassNameResolver::GetDowngradedClassName( + const Descriptor* descriptor) { + return FileJavaPackage(descriptor->file()) + "." + + GetDowngradedFileClassName(descriptor->file()) + "." + + ClassNameWithoutPackage(descriptor, false); +} + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/java/java_name_resolver.h b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_name_resolver.h new file mode 100644 index 00000000..4d5a9bf6 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_name_resolver.h @@ -0,0 +1,153 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_NAME_RESOLVER_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVA_NAME_RESOLVER_H__ + +#include <map> +#include <string> + +#include <stubs/common.h> + +namespace google { +namespace protobuf { +class Descriptor; +class EnumDescriptor; +class FieldDescriptor; +class FileDescriptor; +class ServiceDescriptor; + +namespace compiler { +namespace java { + +// Indicates how closely the two class names match. +enum NameEquality { NO_MATCH, EXACT_EQUAL, EQUAL_IGNORE_CASE }; + +// Used to get the Java class related names for a given descriptor. It caches +// the results to avoid redundant calculation across multiple name queries. +// Thread-safety note: This class is *not* thread-safe. +class ClassNameResolver { + public: + ClassNameResolver(); + ~ClassNameResolver(); + + // Gets the unqualified outer class name for the file. + std::string GetFileClassName(const FileDescriptor* file, bool immutable); + std::string GetFileClassName(const FileDescriptor* file, bool immutable, + bool kotlin); + // Gets the unqualified immutable outer class name of a file. + std::string GetFileImmutableClassName(const FileDescriptor* file); + // Gets the unqualified default immutable outer class name of a file + // (converted from the proto file's name). + std::string GetFileDefaultImmutableClassName(const FileDescriptor* file); + + // Check whether there is any type defined in the proto file that has + // the given class name. + bool HasConflictingClassName(const FileDescriptor* file, + const std::string& classname, + NameEquality equality_mode); + + // Gets the name of the outer class that holds descriptor information. + // Descriptors are shared between immutable messages and mutable messages. + // Since both of them are generated optionally, the descriptors need to be + // put in another common place. + std::string GetDescriptorClassName(const FileDescriptor* file); + + // Gets the fully-qualified class name corresponding to the given descriptor. + std::string GetClassName(const Descriptor* descriptor, bool immutable); + std::string GetClassName(const Descriptor* descriptor, bool immutable, + bool kotlin); + std::string GetClassName(const EnumDescriptor* descriptor, bool immutable); + std::string GetClassName(const EnumDescriptor* descriptor, bool immutable, + bool kotlin); + std::string GetClassName(const ServiceDescriptor* descriptor, bool immutable); + std::string GetClassName(const ServiceDescriptor* descriptor, bool immutable, + bool kotlin); + std::string GetClassName(const FileDescriptor* descriptor, bool immutable); + std::string GetClassName(const FileDescriptor* descriptor, bool immutable, + bool kotlin); + + template <class DescriptorType> + std::string GetImmutableClassName(const DescriptorType* descriptor) { + return GetClassName(descriptor, true); + } + template <class DescriptorType> + std::string GetMutableClassName(const DescriptorType* descriptor) { + return GetClassName(descriptor, false); + } + + // Gets the fully qualified name of an extension identifier. + std::string GetExtensionIdentifierName(const FieldDescriptor* descriptor, + bool immutable); + std::string GetExtensionIdentifierName(const FieldDescriptor* descriptor, + bool immutable, bool kotlin); + + // Gets the fully qualified name for generated classes in Java convention. + // Nested classes will be separated using '$' instead of '.' + // For example: + // com.package.OuterClass$OuterMessage$InnerMessage + std::string GetJavaImmutableClassName(const Descriptor* descriptor); + std::string GetJavaImmutableClassName(const EnumDescriptor* descriptor); + std::string GetKotlinFactoryName(const Descriptor* descriptor); + std::string GetKotlinExtensionsClassName(const Descriptor* descriptor); + std::string GetJavaMutableClassName(const Descriptor* descriptor); + std::string GetJavaMutableClassName(const EnumDescriptor* descriptor); + // Gets the outer class and the actual class for downgraded mutable messages. + std::string GetDowngradedFileClassName(const FileDescriptor* file); + std::string GetDowngradedClassName(const Descriptor* descriptor); + + private: + // Get the full name of a Java class by prepending the Java package name + // or outer class name. + std::string GetClassFullName(const std::string& name_without_package, + const FileDescriptor* file, bool immutable, + bool is_own_file); + std::string GetClassFullName(const std::string& name_without_package, + const FileDescriptor* file, bool immutable, + bool is_own_file, bool kotlin); + // Get the Java Class style full name of a message. + std::string GetJavaClassFullName(const std::string& name_without_package, + const FileDescriptor* file, bool immutable); + std::string GetJavaClassFullName(const std::string& name_without_package, + const FileDescriptor* file, bool immutable, + bool kotlin); + // Caches the result to provide better performance. + std::map<const FileDescriptor*, std::string> + file_immutable_outer_class_names_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ClassNameResolver); +}; + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_NAME_RESOLVER_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/java/java_names.h b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_names.h new file mode 100644 index 00000000..313ace4f --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_names.h @@ -0,0 +1,100 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// Provides a mechanism for mapping a descriptor to the +// fully-qualified name of the corresponding Java class. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_NAMES_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVA_NAMES_H__ + +#include <string> + +namespace google { +namespace protobuf { + +class Descriptor; +class EnumDescriptor; +class FileDescriptor; +class FieldDescriptor; +class ServiceDescriptor; + +namespace compiler { +namespace java { + +// Requires: +// descriptor != NULL +// +// Returns: +// The fully-qualified Java class name. +std::string ClassName(const Descriptor* descriptor); + +// Requires: +// descriptor != NULL +// +// Returns: +// The fully-qualified Java class name. +std::string ClassName(const EnumDescriptor* descriptor); + +// Requires: +// descriptor != NULL +// +// Returns: +// The fully-qualified Java class name. +std::string ClassName(const FileDescriptor* descriptor); + +// Requires: +// descriptor != NULL +// +// Returns: +// The fully-qualified Java class name. +std::string ClassName(const ServiceDescriptor* descriptor); + +// Requires: +// descriptor != NULL +// +// Returns: +// Java package name. +std::string FileJavaPackage(const FileDescriptor* descriptor); + +// Requires: +// descriptor != NULL +// Returns: +// Capitalized camel case name field name. +std::string CapitalizedFieldName(const FieldDescriptor* descriptor); + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_NAMES_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/java/java_options.h b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_options.h new file mode 100644 index 00000000..6c29be15 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_options.h @@ -0,0 +1,73 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_OPTIONS_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVA_OPTIONS_H__ + +#include <string> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +// Generator options +struct Options { + Options() + : generate_immutable_code(false), + generate_mutable_code(false), + generate_shared_code(false), + enforce_lite(false), + annotate_code(false) { + } + + bool generate_immutable_code; + bool generate_mutable_code; + bool generate_shared_code; + // When set, the protoc will generate the current files and all the transitive + // dependencies as lite runtime. + bool enforce_lite; + // If true, we should build .meta files and emit @Generated annotations into + // generated code. + bool annotate_code; + // Name of a file where we will write a list of generated .meta file names, + // one per line. + std::string annotation_list_file; + // Name of a file where we will write a list of generated file names, one + // per line. + std::string output_list_file; +}; + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_OPTIONS_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/java/java_plugin_unittest.cc b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_plugin_unittest.cc new file mode 100644 index 00000000..22ae3f24 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_plugin_unittest.cc @@ -0,0 +1,119 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// +// TODO(kenton): Share code with the versions of this test in other languages? +// It seemed like parameterizing it would add more complexity than it is +// worth. + +#include <memory> + +#include <testing/file.h> +#include <testing/file.h> +#include <compiler/java/java_generator.h> +#include <compiler/command_line_interface.h> +#include <io/printer.h> +#include <io/zero_copy_stream.h> +#include <testing/googletest.h> +#include <gtest/gtest.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { +namespace { + +class TestGenerator : public CodeGenerator { + public: + TestGenerator() {} + ~TestGenerator() {} + + virtual bool Generate(const FileDescriptor* file, + const std::string& parameter, GeneratorContext* context, + std::string* error) const { + std::string filename = "Test.java"; + TryInsert(filename, "outer_class_scope", context); + TryInsert(filename, "class_scope:foo.Bar", context); + TryInsert(filename, "class_scope:foo.Bar.Baz", context); + TryInsert(filename, "builder_scope:foo.Bar", context); + TryInsert(filename, "builder_scope:foo.Bar.Baz", context); + TryInsert(filename, "enum_scope:foo.Qux", context); + return true; + } + + void TryInsert(const std::string& filename, + const std::string& insertion_point, + GeneratorContext* context) const { + std::unique_ptr<io::ZeroCopyOutputStream> output( + context->OpenForInsert(filename, insertion_point)); + io::Printer printer(output.get(), '$'); + printer.Print("// inserted $name$\n", "name", insertion_point); + } +}; + +// This test verifies that all the expected insertion points exist. It does +// not verify that they are correctly-placed; that would require actually +// compiling the output which is a bit more than I care to do for this test. +TEST(JavaPluginTest, PluginTest) { + GOOGLE_CHECK_OK(File::SetContents(TestTempDir() + "/test.proto", + "syntax = \"proto2\";\n" + "package foo;\n" + "option java_package = \"\";\n" + "option java_outer_classname = \"Test\";\n" + "message Bar {\n" + " message Baz {}\n" + "}\n" + "enum Qux { BLAH = 1; }\n", + true)); + + CommandLineInterface cli; + cli.SetInputsAreProtoPathRelative(true); + + JavaGenerator java_generator; + TestGenerator test_generator; + cli.RegisterGenerator("--java_out", &java_generator, ""); + cli.RegisterGenerator("--test_out", &test_generator, ""); + + std::string proto_path = "-I" + TestTempDir(); + std::string java_out = "--java_out=" + TestTempDir(); + std::string test_out = "--test_out=" + TestTempDir(); + + const char* argv[] = {"protoc", proto_path.c_str(), java_out.c_str(), + test_out.c_str(), "test.proto"}; + + EXPECT_EQ(0, cli.Run(5, argv)); +} + +} // namespace +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/java/java_primitive_field.cc b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_primitive_field.cc new file mode 100644 index 00000000..23d00b28 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_primitive_field.cc @@ -0,0 +1,1111 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <compiler/java/java_primitive_field.h> + +#include <cstdint> +#include <map> +#include <string> + +#include <stubs/logging.h> +#include <stubs/common.h> +#include <compiler/java/java_context.h> +#include <compiler/java/java_doc_comment.h> +#include <compiler/java/java_helpers.h> +#include <compiler/java/java_name_resolver.h> +#include <io/printer.h> +#include <wire_format.h> +#include <stubs/strutil.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +using internal::WireFormat; + +namespace { + +void SetPrimitiveVariables(const FieldDescriptor* descriptor, + int messageBitIndex, int builderBitIndex, + const FieldGeneratorInfo* info, + ClassNameResolver* name_resolver, + std::map<std::string, std::string>* variables) { + SetCommonFieldVariables(descriptor, info, variables); + JavaType javaType = GetJavaType(descriptor); + + (*variables)["type"] = PrimitiveTypeName(javaType); + (*variables)["boxed_type"] = BoxedPrimitiveTypeName(javaType); + (*variables)["kt_type"] = KotlinTypeName(javaType); + (*variables)["field_type"] = (*variables)["type"]; + + if (javaType == JAVATYPE_BOOLEAN || javaType == JAVATYPE_DOUBLE || + javaType == JAVATYPE_FLOAT || javaType == JAVATYPE_INT || + javaType == JAVATYPE_LONG) { + std::string capitalized_type = UnderscoresToCamelCase( + PrimitiveTypeName(javaType), /*cap_first_letter=*/true); + (*variables)["field_list_type"] = + "com.google.protobuf.Internal." + capitalized_type + "List"; + (*variables)["empty_list"] = "empty" + capitalized_type + "List()"; + (*variables)["create_list"] = "new" + capitalized_type + "List()"; + (*variables)["mutable_copy_list"] = + "mutableCopy(" + (*variables)["name"] + "_)"; + (*variables)["name_make_immutable"] = + (*variables)["name"] + "_.makeImmutable()"; + (*variables)["repeated_get"] = + (*variables)["name"] + "_.get" + capitalized_type; + (*variables)["repeated_add"] = + (*variables)["name"] + "_.add" + capitalized_type; + (*variables)["repeated_set"] = + (*variables)["name"] + "_.set" + capitalized_type; + } else { + (*variables)["field_list_type"] = + "java.util.List<" + (*variables)["boxed_type"] + ">"; + (*variables)["create_list"] = + "new java.util.ArrayList<" + (*variables)["boxed_type"] + ">()"; + (*variables)["mutable_copy_list"] = "new java.util.ArrayList<" + + (*variables)["boxed_type"] + ">(" + + (*variables)["name"] + "_)"; + (*variables)["empty_list"] = "java.util.Collections.emptyList()"; + (*variables)["name_make_immutable"] = + (*variables)["name"] + "_ = java.util.Collections.unmodifiableList(" + + (*variables)["name"] + "_)"; + (*variables)["repeated_get"] = (*variables)["name"] + "_.get"; + (*variables)["repeated_add"] = (*variables)["name"] + "_.add"; + (*variables)["repeated_set"] = (*variables)["name"] + "_.set"; + } + + (*variables)["default"] = ImmutableDefaultValue(descriptor, name_resolver); + (*variables)["default_init"] = + IsDefaultValueJavaDefault(descriptor) + ? "" + : ("= " + ImmutableDefaultValue(descriptor, name_resolver)); + (*variables)["capitalized_type"] = + GetCapitalizedType(descriptor, /* immutable = */ true); + (*variables)["tag"] = + StrCat(static_cast<int32_t>(WireFormat::MakeTag(descriptor))); + (*variables)["tag_size"] = StrCat( + WireFormat::TagSize(descriptor->number(), GetType(descriptor))); + if (IsReferenceType(GetJavaType(descriptor))) { + (*variables)["null_check"] = + " if (value == null) {\n" + " throw new NullPointerException();\n" + " }\n"; + } else { + (*variables)["null_check"] = ""; + } + // TODO(birdo): Add @deprecated javadoc when generating javadoc is supported + // by the proto compiler + (*variables)["deprecation"] = + descriptor->options().deprecated() ? "@java.lang.Deprecated " : ""; + (*variables)["kt_deprecation"] = + descriptor->options().deprecated() + ? "@kotlin.Deprecated(message = \"Field " + (*variables)["name"] + + " is deprecated\") " + : ""; + int fixed_size = FixedSize(GetType(descriptor)); + if (fixed_size != -1) { + (*variables)["fixed_size"] = StrCat(fixed_size); + } + (*variables)["on_changed"] = "onChanged();"; + + if (HasHasbit(descriptor)) { + // For singular messages and builders, one bit is used for the hasField bit. + (*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex); + (*variables)["get_has_field_bit_builder"] = GenerateGetBit(builderBitIndex); + + // Note that these have a trailing ";". + (*variables)["set_has_field_bit_message"] = + GenerateSetBit(messageBitIndex) + ";"; + (*variables)["set_has_field_bit_builder"] = + GenerateSetBit(builderBitIndex) + ";"; + (*variables)["clear_has_field_bit_builder"] = + GenerateClearBit(builderBitIndex) + ";"; + + (*variables)["is_field_present_message"] = GenerateGetBit(messageBitIndex); + } else { + (*variables)["set_has_field_bit_message"] = ""; + (*variables)["set_has_field_bit_builder"] = ""; + (*variables)["clear_has_field_bit_builder"] = ""; + + switch (descriptor->type()) { + case FieldDescriptor::TYPE_BYTES: + (*variables)["is_field_present_message"] = + "!" + (*variables)["name"] + "_.isEmpty()"; + break; + case FieldDescriptor::TYPE_FLOAT: + (*variables)["is_field_present_message"] = + "java.lang.Float.floatToRawIntBits(" + (*variables)["name"] + + "_) != 0"; + break; + case FieldDescriptor::TYPE_DOUBLE: + (*variables)["is_field_present_message"] = + "java.lang.Double.doubleToRawLongBits(" + (*variables)["name"] + + "_) != 0"; + break; + default: + (*variables)["is_field_present_message"] = + (*variables)["name"] + "_ != " + (*variables)["default"]; + break; + } + } + + // For repeated builders, one bit is used for whether the array is immutable. + (*variables)["get_mutable_bit_builder"] = GenerateGetBit(builderBitIndex); + (*variables)["set_mutable_bit_builder"] = GenerateSetBit(builderBitIndex); + (*variables)["clear_mutable_bit_builder"] = GenerateClearBit(builderBitIndex); + + // For repeated fields, one bit is used for whether the array is immutable + // in the parsing constructor. + (*variables)["get_mutable_bit_parser"] = + GenerateGetBitMutableLocal(builderBitIndex); + (*variables)["set_mutable_bit_parser"] = + GenerateSetBitMutableLocal(builderBitIndex); + + (*variables)["get_has_field_bit_from_local"] = + GenerateGetBitFromLocal(builderBitIndex); + (*variables)["set_has_field_bit_to_local"] = + GenerateSetBitToLocal(messageBitIndex); +} + +} // namespace + +// =================================================================== + +ImmutablePrimitiveFieldGenerator::ImmutablePrimitiveFieldGenerator( + const FieldDescriptor* descriptor, int messageBitIndex, int builderBitIndex, + Context* context) + : descriptor_(descriptor), name_resolver_(context->GetNameResolver()) { + SetPrimitiveVariables(descriptor, messageBitIndex, builderBitIndex, + context->GetFieldGeneratorInfo(descriptor), + name_resolver_, &variables_); +} + +ImmutablePrimitiveFieldGenerator::~ImmutablePrimitiveFieldGenerator() {} + +int ImmutablePrimitiveFieldGenerator::GetNumBitsForMessage() const { + return HasHasbit(descriptor_) ? 1 : 0; +} + +int ImmutablePrimitiveFieldGenerator::GetNumBitsForBuilder() const { + return GetNumBitsForMessage(); +} + +void ImmutablePrimitiveFieldGenerator::GenerateInterfaceMembers( + io::Printer* printer) const { + if (HasHazzer(descriptor_)) { + WriteFieldAccessorDocComment(printer, descriptor_, HAZZER); + printer->Print(variables_, + "$deprecation$boolean has$capitalized_name$();\n"); + } + WriteFieldAccessorDocComment(printer, descriptor_, GETTER); + printer->Print(variables_, "$deprecation$$type$ get$capitalized_name$();\n"); +} + +void ImmutablePrimitiveFieldGenerator::GenerateMembers( + io::Printer* printer) const { + printer->Print(variables_, "private $field_type$ $name$_;\n"); + PrintExtraFieldInfo(variables_, printer); + if (HasHazzer(descriptor_)) { + WriteFieldAccessorDocComment(printer, descriptor_, HAZZER); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n" + " return $get_has_field_bit_message$;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + } + + WriteFieldAccessorDocComment(printer, descriptor_, GETTER); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$public $type$ ${$get$capitalized_name$$}$() {\n" + " return $name$_;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); +} + +void ImmutablePrimitiveFieldGenerator::GenerateBuilderMembers( + io::Printer* printer) const { + printer->Print(variables_, "private $field_type$ $name$_ $default_init$;\n"); + + if (HasHazzer(descriptor_)) { + WriteFieldAccessorDocComment(printer, descriptor_, HAZZER); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n" + " return $get_has_field_bit_builder$;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + } + + WriteFieldAccessorDocComment(printer, descriptor_, GETTER); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$public $type$ ${$get$capitalized_name$$}$() {\n" + " return $name$_;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + WriteFieldAccessorDocComment(printer, descriptor_, SETTER, + /* builder */ true); + printer->Print(variables_, + "$deprecation$public Builder " + "${$set$capitalized_name$$}$($type$ value) {\n" + "$null_check$" + " $set_has_field_bit_builder$\n" + " $name$_ = value;\n" + " $on_changed$\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + WriteFieldAccessorDocComment(printer, descriptor_, CLEARER, + /* builder */ true); + printer->Print( + variables_, + "$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n" + " $clear_has_field_bit_builder$\n"); + printer->Annotate("{", "}", descriptor_); + JavaType type = GetJavaType(descriptor_); + if (type == JAVATYPE_STRING || type == JAVATYPE_BYTES) { + // The default value is not a simple literal so we want to avoid executing + // it multiple times. Instead, get the default out of the default instance. + printer->Print( + variables_, + " $name$_ = getDefaultInstance().get$capitalized_name$();\n"); + } else { + printer->Print(variables_, " $name$_ = $default$;\n"); + } + printer->Print(variables_, + " $on_changed$\n" + " return this;\n" + "}\n"); +} + +void ImmutablePrimitiveFieldGenerator::GenerateKotlinDslMembers( + io::Printer* printer) const { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$kt_deprecation$public var $kt_name$: $kt_type$\n" + " @JvmName(\"${$get$kt_capitalized_name$$}$\")\n" + " get() = $kt_dsl_builder$.${$get$capitalized_name$$}$()\n" + " @JvmName(\"${$set$kt_capitalized_name$$}$\")\n" + " set(value) {\n" + " $kt_dsl_builder$.${$set$capitalized_name$$}$(value)\n" + " }\n"); + + WriteFieldAccessorDocComment(printer, descriptor_, CLEARER, + /* builder */ false); + printer->Print(variables_, + "public fun ${$clear$kt_capitalized_name$$}$() {\n" + " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n" + "}\n"); + + if (HasHazzer(descriptor_)) { + WriteFieldAccessorDocComment(printer, descriptor_, HAZZER); + printer->Print( + variables_, + "public fun ${$has$kt_capitalized_name$$}$(): kotlin.Boolean {\n" + " return $kt_dsl_builder$.${$has$capitalized_name$$}$()\n" + "}\n"); + } +} + +void ImmutablePrimitiveFieldGenerator::GenerateFieldBuilderInitializationCode( + io::Printer* printer) const { + // noop for primitives +} + +void ImmutablePrimitiveFieldGenerator::GenerateInitializationCode( + io::Printer* printer) const { + if (!IsDefaultValueJavaDefault(descriptor_)) { + printer->Print(variables_, "$name$_ = $default$;\n"); + } +} + +void ImmutablePrimitiveFieldGenerator::GenerateBuilderClearCode( + io::Printer* printer) const { + printer->Print(variables_, + "$name$_ = $default$;\n" + "$clear_has_field_bit_builder$\n"); +} + +void ImmutablePrimitiveFieldGenerator::GenerateMergingCode( + io::Printer* printer) const { + if (HasHazzer(descriptor_)) { + printer->Print(variables_, + "if (other.has$capitalized_name$()) {\n" + " set$capitalized_name$(other.get$capitalized_name$());\n" + "}\n"); + } else { + printer->Print(variables_, + "if (other.get$capitalized_name$() != $default$) {\n" + " set$capitalized_name$(other.get$capitalized_name$());\n" + "}\n"); + } +} + +void ImmutablePrimitiveFieldGenerator::GenerateBuildingCode( + io::Printer* printer) const { + if (HasHazzer(descriptor_)) { + if (IsDefaultValueJavaDefault(descriptor_)) { + printer->Print(variables_, + "if ($get_has_field_bit_from_local$) {\n" + " result.$name$_ = $name$_;\n" + " $set_has_field_bit_to_local$;\n" + "}\n"); + } else { + printer->Print(variables_, + "if ($get_has_field_bit_from_local$) {\n" + " $set_has_field_bit_to_local$;\n" + "}\n" + "result.$name$_ = $name$_;\n"); + } + } else { + printer->Print(variables_, "result.$name$_ = $name$_;\n"); + } +} + +void ImmutablePrimitiveFieldGenerator::GenerateParsingCode( + io::Printer* printer) const { + printer->Print(variables_, + "$set_has_field_bit_message$\n" + "$name$_ = input.read$capitalized_type$();\n"); +} + +void ImmutablePrimitiveFieldGenerator::GenerateParsingDoneCode( + io::Printer* printer) const { + // noop for primitives. +} + +void ImmutablePrimitiveFieldGenerator::GenerateSerializationCode( + io::Printer* printer) const { + printer->Print(variables_, + "if ($is_field_present_message$) {\n" + " output.write$capitalized_type$($number$, $name$_);\n" + "}\n"); +} + +void ImmutablePrimitiveFieldGenerator::GenerateSerializedSizeCode( + io::Printer* printer) const { + printer->Print(variables_, + "if ($is_field_present_message$) {\n" + " size += com.google.protobuf.CodedOutputStream\n" + " .compute$capitalized_type$Size($number$, $name$_);\n" + "}\n"); +} + +void ImmutablePrimitiveFieldGenerator::GenerateEqualsCode( + io::Printer* printer) const { + switch (GetJavaType(descriptor_)) { + case JAVATYPE_INT: + case JAVATYPE_LONG: + case JAVATYPE_BOOLEAN: + printer->Print(variables_, + "if (get$capitalized_name$()\n" + " != other.get$capitalized_name$()) return false;\n"); + break; + + case JAVATYPE_FLOAT: + printer->Print( + variables_, + "if (java.lang.Float.floatToIntBits(get$capitalized_name$())\n" + " != java.lang.Float.floatToIntBits(\n" + " other.get$capitalized_name$())) return false;\n"); + break; + + case JAVATYPE_DOUBLE: + printer->Print( + variables_, + "if (java.lang.Double.doubleToLongBits(get$capitalized_name$())\n" + " != java.lang.Double.doubleToLongBits(\n" + " other.get$capitalized_name$())) return false;\n"); + break; + + case JAVATYPE_STRING: + case JAVATYPE_BYTES: + printer->Print( + variables_, + "if (!get$capitalized_name$()\n" + " .equals(other.get$capitalized_name$())) return false;\n"); + break; + + case JAVATYPE_ENUM: + case JAVATYPE_MESSAGE: + default: + GOOGLE_LOG(FATAL) << "Can't get here."; + break; + } +} + +void ImmutablePrimitiveFieldGenerator::GenerateHashCode( + io::Printer* printer) const { + printer->Print(variables_, "hash = (37 * hash) + $constant_name$;\n"); + switch (GetJavaType(descriptor_)) { + case JAVATYPE_INT: + printer->Print(variables_, + "hash = (53 * hash) + get$capitalized_name$();\n"); + break; + + case JAVATYPE_LONG: + printer->Print( + variables_, + "hash = (53 * hash) + com.google.protobuf.Internal.hashLong(\n" + " get$capitalized_name$());\n"); + break; + + case JAVATYPE_BOOLEAN: + printer->Print( + variables_, + "hash = (53 * hash) + com.google.protobuf.Internal.hashBoolean(\n" + " get$capitalized_name$());\n"); + break; + + case JAVATYPE_FLOAT: + printer->Print(variables_, + "hash = (53 * hash) + java.lang.Float.floatToIntBits(\n" + " get$capitalized_name$());\n"); + break; + + case JAVATYPE_DOUBLE: + printer->Print( + variables_, + "hash = (53 * hash) + com.google.protobuf.Internal.hashLong(\n" + " java.lang.Double.doubleToLongBits(get$capitalized_name$()));\n"); + break; + + case JAVATYPE_STRING: + case JAVATYPE_BYTES: + printer->Print( + variables_, + "hash = (53 * hash) + get$capitalized_name$().hashCode();\n"); + break; + + case JAVATYPE_ENUM: + case JAVATYPE_MESSAGE: + default: + GOOGLE_LOG(FATAL) << "Can't get here."; + break; + } +} + +std::string ImmutablePrimitiveFieldGenerator::GetBoxedType() const { + return BoxedPrimitiveTypeName(GetJavaType(descriptor_)); +} + +// =================================================================== + +ImmutablePrimitiveOneofFieldGenerator::ImmutablePrimitiveOneofFieldGenerator( + const FieldDescriptor* descriptor, int messageBitIndex, int builderBitIndex, + Context* context) + : ImmutablePrimitiveFieldGenerator(descriptor, messageBitIndex, + builderBitIndex, context) { + const OneofGeneratorInfo* info = + context->GetOneofGeneratorInfo(descriptor->containing_oneof()); + SetCommonOneofVariables(descriptor, info, &variables_); +} + +ImmutablePrimitiveOneofFieldGenerator:: + ~ImmutablePrimitiveOneofFieldGenerator() {} + +void ImmutablePrimitiveOneofFieldGenerator::GenerateMembers( + io::Printer* printer) const { + PrintExtraFieldInfo(variables_, printer); + GOOGLE_DCHECK(HasHazzer(descriptor_)); + WriteFieldAccessorDocComment(printer, descriptor_, HAZZER); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n" + " return $has_oneof_case_message$;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + WriteFieldAccessorDocComment(printer, descriptor_, GETTER); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$public $type$ ${$get$capitalized_name$$}$() {\n" + " if ($has_oneof_case_message$) {\n" + " return ($boxed_type$) $oneof_name$_;\n" + " }\n" + " return $default$;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); +} + +void ImmutablePrimitiveOneofFieldGenerator::GenerateBuilderMembers( + io::Printer* printer) const { + GOOGLE_DCHECK(HasHazzer(descriptor_)); + WriteFieldAccessorDocComment(printer, descriptor_, HAZZER); + printer->Print(variables_, + "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n" + " return $has_oneof_case_message$;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + WriteFieldAccessorDocComment(printer, descriptor_, GETTER); + printer->Print(variables_, + "$deprecation$public $type$ ${$get$capitalized_name$$}$() {\n" + " if ($has_oneof_case_message$) {\n" + " return ($boxed_type$) $oneof_name$_;\n" + " }\n" + " return $default$;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + WriteFieldAccessorDocComment(printer, descriptor_, SETTER, + /* builder */ true); + printer->Print(variables_, + "$deprecation$public Builder " + "${$set$capitalized_name$$}$($type$ value) {\n" + "$null_check$" + " $set_oneof_case_message$;\n" + " $oneof_name$_ = value;\n" + " $on_changed$\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + WriteFieldAccessorDocComment(printer, descriptor_, CLEARER, + /* builder */ true); + printer->Print( + variables_, + "$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n" + " if ($has_oneof_case_message$) {\n" + " $clear_oneof_case_message$;\n" + " $oneof_name$_ = null;\n" + " $on_changed$\n" + " }\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); +} + +void ImmutablePrimitiveOneofFieldGenerator::GenerateBuildingCode( + io::Printer* printer) const { + printer->Print(variables_, + "if ($has_oneof_case_message$) {\n" + " result.$oneof_name$_ = $oneof_name$_;\n" + "}\n"); +} + +void ImmutablePrimitiveOneofFieldGenerator::GenerateMergingCode( + io::Printer* printer) const { + printer->Print(variables_, + "set$capitalized_name$(other.get$capitalized_name$());\n"); +} + +void ImmutablePrimitiveOneofFieldGenerator::GenerateParsingCode( + io::Printer* printer) const { + printer->Print(variables_, + "$oneof_name$_ = input.read$capitalized_type$();\n" + "$set_oneof_case_message$;\n"); +} + +void ImmutablePrimitiveOneofFieldGenerator::GenerateSerializationCode( + io::Printer* printer) const { + printer->Print(variables_, + "if ($has_oneof_case_message$) {\n" + " output.write$capitalized_type$(\n"); + // $type$ and $boxed_type$ is the same for bytes fields so we don't need to + // do redundant casts. + if (GetJavaType(descriptor_) == JAVATYPE_BYTES) { + printer->Print(variables_, " $number$, ($type$) $oneof_name$_);\n"); + } else { + printer->Print( + variables_, + " $number$, ($type$)(($boxed_type$) $oneof_name$_));\n"); + } + printer->Print("}\n"); +} + +void ImmutablePrimitiveOneofFieldGenerator::GenerateSerializedSizeCode( + io::Printer* printer) const { + printer->Print(variables_, + "if ($has_oneof_case_message$) {\n" + " size += com.google.protobuf.CodedOutputStream\n" + " .compute$capitalized_type$Size(\n"); + // $type$ and $boxed_type$ is the same for bytes fields so we don't need to + // do redundant casts. + if (GetJavaType(descriptor_) == JAVATYPE_BYTES) { + printer->Print(variables_, " $number$, ($type$) $oneof_name$_);\n"); + } else { + printer->Print( + variables_, + " $number$, ($type$)(($boxed_type$) $oneof_name$_));\n"); + } + printer->Print("}\n"); +} + +// =================================================================== + +RepeatedImmutablePrimitiveFieldGenerator:: + RepeatedImmutablePrimitiveFieldGenerator(const FieldDescriptor* descriptor, + int messageBitIndex, + int builderBitIndex, + Context* context) + : descriptor_(descriptor), name_resolver_(context->GetNameResolver()) { + SetPrimitiveVariables(descriptor, messageBitIndex, builderBitIndex, + context->GetFieldGeneratorInfo(descriptor), + name_resolver_, &variables_); +} + +RepeatedImmutablePrimitiveFieldGenerator:: + ~RepeatedImmutablePrimitiveFieldGenerator() {} + +int RepeatedImmutablePrimitiveFieldGenerator::GetNumBitsForMessage() const { + return 0; +} + +int RepeatedImmutablePrimitiveFieldGenerator::GetNumBitsForBuilder() const { + return 1; +} + +void RepeatedImmutablePrimitiveFieldGenerator::GenerateInterfaceMembers( + io::Printer* printer) const { + WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER); + printer->Print(variables_, + "$deprecation$java.util.List<$boxed_type$> " + "get$capitalized_name$List();\n"); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_COUNT); + printer->Print(variables_, + "$deprecation$int get$capitalized_name$Count();\n"); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_GETTER); + printer->Print(variables_, + "$deprecation$$type$ get$capitalized_name$(int index);\n"); +} + +void RepeatedImmutablePrimitiveFieldGenerator::GenerateMembers( + io::Printer* printer) const { + printer->Print(variables_, "private $field_list_type$ $name$_;\n"); + PrintExtraFieldInfo(variables_, printer); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$public java.util.List<$boxed_type$>\n" + " ${$get$capitalized_name$List$}$() {\n" + " return $name$_;\n" // note: unmodifiable list + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_COUNT); + printer->Print( + variables_, + "$deprecation$public int ${$get$capitalized_name$Count$}$() {\n" + " return $name$_.size();\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_GETTER); + printer->Print( + variables_, + "$deprecation$public $type$ ${$get$capitalized_name$$}$(int index) {\n" + " return $repeated_get$(index);\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + if (descriptor_->is_packed()) { + printer->Print(variables_, + "private int $name$MemoizedSerializedSize = -1;\n"); + } +} + +void RepeatedImmutablePrimitiveFieldGenerator::GenerateBuilderMembers( + io::Printer* printer) const { + // One field is the list and the bit field keeps track of whether the + // list is immutable. If it's immutable, the invariant is that it must + // either an instance of Collections.emptyList() or it's an ArrayList + // wrapped in a Collections.unmodifiableList() wrapper and nobody else has + // a reference to the underlying ArrayList. This invariant allows us to + // share instances of lists between protocol buffers avoiding expensive + // memory allocations. Note, immutable is a strong guarantee here -- not + // just that the list cannot be modified via the reference but that the + // list can never be modified. + printer->Print(variables_, + "private $field_list_type$ $name$_ = $empty_list$;\n"); + + printer->Print(variables_, + "private void ensure$capitalized_name$IsMutable() {\n" + " if (!$get_mutable_bit_builder$) {\n" + " $name$_ = $mutable_copy_list$;\n" + " $set_mutable_bit_builder$;\n" + " }\n" + "}\n"); + + // Note: We return an unmodifiable list because otherwise the caller + // could hold on to the returned list and modify it after the message + // has been built, thus mutating the message which is supposed to be + // immutable. + WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER); + printer->Print( + variables_, + "$deprecation$public java.util.List<$boxed_type$>\n" + " ${$get$capitalized_name$List$}$() {\n" + " return $get_mutable_bit_builder$ ?\n" + " java.util.Collections.unmodifiableList($name$_) : $name$_;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_COUNT); + printer->Print( + variables_, + "$deprecation$public int ${$get$capitalized_name$Count$}$() {\n" + " return $name$_.size();\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_GETTER); + printer->Print( + variables_, + "$deprecation$public $type$ ${$get$capitalized_name$$}$(int index) {\n" + " return $repeated_get$(index);\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_SETTER, + /* builder */ true); + printer->Print(variables_, + "$deprecation$public Builder ${$set$capitalized_name$$}$(\n" + " int index, $type$ value) {\n" + "$null_check$" + " ensure$capitalized_name$IsMutable();\n" + " $repeated_set$(index, value);\n" + " $on_changed$\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER, + /* builder */ true); + printer->Print(variables_, + "$deprecation$public Builder " + "${$add$capitalized_name$$}$($type$ value) {\n" + "$null_check$" + " ensure$capitalized_name$IsMutable();\n" + " $repeated_add$(value);\n" + " $on_changed$\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER, + /* builder */ true); + printer->Print(variables_, + "$deprecation$public Builder ${$addAll$capitalized_name$$}$(\n" + " java.lang.Iterable<? extends $boxed_type$> values) {\n" + " ensure$capitalized_name$IsMutable();\n" + " com.google.protobuf.AbstractMessageLite.Builder.addAll(\n" + " values, $name$_);\n" + " $on_changed$\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldAccessorDocComment(printer, descriptor_, CLEARER, + /* builder */ true); + printer->Print( + variables_, + "$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n" + " $name$_ = $empty_list$;\n" + " $clear_mutable_bit_builder$;\n" + " $on_changed$\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); +} + +void RepeatedImmutablePrimitiveFieldGenerator::GenerateKotlinDslMembers( + io::Printer* printer) const { + printer->Print( + variables_, + "/**\n" + " * An uninstantiable, behaviorless type to represent the field in\n" + " * generics.\n" + " */\n" + "@kotlin.OptIn" + "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n" + "public class ${$$kt_capitalized_name$Proxy$}$ private constructor()" + " : com.google.protobuf.kotlin.DslProxy()\n"); + + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$kt_deprecation$ public val $kt_name$: " + "com.google.protobuf.kotlin.DslList" + "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>\n" + " @kotlin.jvm.JvmSynthetic\n" + " get() = com.google.protobuf.kotlin.DslList(\n" + " $kt_dsl_builder$.${$get$capitalized_name$List$}$()\n" + " )\n"); + + WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER, + /* builder */ false); + printer->Print(variables_, + "@kotlin.jvm.JvmSynthetic\n" + "@kotlin.jvm.JvmName(\"add$kt_capitalized_name$\")\n" + "public fun com.google.protobuf.kotlin.DslList" + "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." + "add(value: $kt_type$) {\n" + " $kt_dsl_builder$.${$add$capitalized_name$$}$(value)\n" + "}"); + + WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER, + /* builder */ false); + printer->Print(variables_, + "@kotlin.jvm.JvmSynthetic\n" + "@kotlin.jvm.JvmName(\"plusAssign$kt_capitalized_name$\")\n" + "@Suppress(\"NOTHING_TO_INLINE\")\n" + "public inline operator fun com.google.protobuf.kotlin.DslList" + "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." + "plusAssign(value: $kt_type$) {\n" + " add(value)\n" + "}"); + + WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER, + /* builder */ false); + printer->Print(variables_, + "@kotlin.jvm.JvmSynthetic\n" + "@kotlin.jvm.JvmName(\"addAll$kt_capitalized_name$\")\n" + "public fun com.google.protobuf.kotlin.DslList" + "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." + "addAll(values: kotlin.collections.Iterable<$kt_type$>) {\n" + " $kt_dsl_builder$.${$addAll$capitalized_name$$}$(values)\n" + "}"); + + WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER, + /* builder */ false); + printer->Print( + variables_, + "@kotlin.jvm.JvmSynthetic\n" + "@kotlin.jvm.JvmName(\"plusAssignAll$kt_capitalized_name$\")\n" + "@Suppress(\"NOTHING_TO_INLINE\")\n" + "public inline operator fun com.google.protobuf.kotlin.DslList" + "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." + "plusAssign(values: kotlin.collections.Iterable<$kt_type$>) {\n" + " addAll(values)\n" + "}"); + + WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_SETTER, + /* builder */ false); + printer->Print( + variables_, + "@kotlin.jvm.JvmSynthetic\n" + "@kotlin.jvm.JvmName(\"set$kt_capitalized_name$\")\n" + "public operator fun com.google.protobuf.kotlin.DslList" + "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." + "set(index: kotlin.Int, value: $kt_type$) {\n" + " $kt_dsl_builder$.${$set$capitalized_name$$}$(index, value)\n" + "}"); + + WriteFieldAccessorDocComment(printer, descriptor_, CLEARER, + /* builder */ false); + printer->Print(variables_, + "@kotlin.jvm.JvmSynthetic\n" + "@kotlin.jvm.JvmName(\"clear$kt_capitalized_name$\")\n" + "public fun com.google.protobuf.kotlin.DslList" + "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." + "clear() {\n" + " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n" + "}"); +} + +void RepeatedImmutablePrimitiveFieldGenerator:: + GenerateFieldBuilderInitializationCode(io::Printer* printer) const { + // noop for primitives +} + +void RepeatedImmutablePrimitiveFieldGenerator::GenerateInitializationCode( + io::Printer* printer) const { + printer->Print(variables_, "$name$_ = $empty_list$;\n"); +} + +void RepeatedImmutablePrimitiveFieldGenerator::GenerateBuilderClearCode( + io::Printer* printer) const { + printer->Print(variables_, + "$name$_ = $empty_list$;\n" + "$clear_mutable_bit_builder$;\n"); +} + +void RepeatedImmutablePrimitiveFieldGenerator::GenerateMergingCode( + io::Printer* printer) const { + // The code below does two optimizations: + // 1. If the other list is empty, there's nothing to do. This ensures we + // don't allocate a new array if we already have an immutable one. + // 2. If the other list is non-empty and our current list is empty, we can + // reuse the other list which is guaranteed to be immutable. + printer->Print(variables_, + "if (!other.$name$_.isEmpty()) {\n" + " if ($name$_.isEmpty()) {\n" + " $name$_ = other.$name$_;\n" + " $clear_mutable_bit_builder$;\n" + " } else {\n" + " ensure$capitalized_name$IsMutable();\n" + " $name$_.addAll(other.$name$_);\n" + " }\n" + " $on_changed$\n" + "}\n"); +} + +void RepeatedImmutablePrimitiveFieldGenerator::GenerateBuildingCode( + io::Printer* printer) const { + // The code below ensures that the result has an immutable list. If our + // list is immutable, we can just reuse it. If not, we make it immutable. + printer->Print(variables_, + "if ($get_mutable_bit_builder$) {\n" + " $name_make_immutable$;\n" + " $clear_mutable_bit_builder$;\n" + "}\n" + "result.$name$_ = $name$_;\n"); +} + +void RepeatedImmutablePrimitiveFieldGenerator::GenerateParsingCode( + io::Printer* printer) const { + printer->Print(variables_, + "if (!$get_mutable_bit_parser$) {\n" + " $name$_ = $create_list$;\n" + " $set_mutable_bit_parser$;\n" + "}\n" + "$repeated_add$(input.read$capitalized_type$());\n"); +} + +void RepeatedImmutablePrimitiveFieldGenerator::GenerateParsingCodeFromPacked( + io::Printer* printer) const { + printer->Print( + variables_, + "int length = input.readRawVarint32();\n" + "int limit = input.pushLimit(length);\n" + "if (!$get_mutable_bit_parser$ && input.getBytesUntilLimit() > 0) {\n" + " $name$_ = $create_list$;\n" + " $set_mutable_bit_parser$;\n" + "}\n" + "while (input.getBytesUntilLimit() > 0) {\n" + " $repeated_add$(input.read$capitalized_type$());\n" + "}\n" + "input.popLimit(limit);\n"); +} + +void RepeatedImmutablePrimitiveFieldGenerator::GenerateParsingDoneCode( + io::Printer* printer) const { + printer->Print(variables_, + "if ($get_mutable_bit_parser$) {\n" + " $name_make_immutable$; // C\n" + "}\n"); +} + +void RepeatedImmutablePrimitiveFieldGenerator::GenerateSerializationCode( + io::Printer* printer) const { + if (descriptor_->is_packed()) { + // We invoke getSerializedSize in writeTo for messages that have packed + // fields in ImmutableMessageGenerator::GenerateMessageSerializationMethods. + // That makes it safe to rely on the memoized size here. + printer->Print(variables_, + "if (get$capitalized_name$List().size() > 0) {\n" + " output.writeUInt32NoTag($tag$);\n" + " output.writeUInt32NoTag($name$MemoizedSerializedSize);\n" + "}\n" + "for (int i = 0; i < $name$_.size(); i++) {\n" + " output.write$capitalized_type$NoTag($repeated_get$(i));\n" + "}\n"); + } else { + printer->Print( + variables_, + "for (int i = 0; i < $name$_.size(); i++) {\n" + " output.write$capitalized_type$($number$, $repeated_get$(i));\n" + "}\n"); + } +} + +void RepeatedImmutablePrimitiveFieldGenerator::GenerateSerializedSizeCode( + io::Printer* printer) const { + printer->Print(variables_, + "{\n" + " int dataSize = 0;\n"); + printer->Indent(); + + if (FixedSize(GetType(descriptor_)) == -1) { + printer->Print( + variables_, + "for (int i = 0; i < $name$_.size(); i++) {\n" + " dataSize += com.google.protobuf.CodedOutputStream\n" + " .compute$capitalized_type$SizeNoTag($repeated_get$(i));\n" + "}\n"); + } else { + printer->Print( + variables_, + "dataSize = $fixed_size$ * get$capitalized_name$List().size();\n"); + } + + printer->Print("size += dataSize;\n"); + + if (descriptor_->is_packed()) { + printer->Print(variables_, + "if (!get$capitalized_name$List().isEmpty()) {\n" + " size += $tag_size$;\n" + " size += com.google.protobuf.CodedOutputStream\n" + " .computeInt32SizeNoTag(dataSize);\n" + "}\n"); + } else { + printer->Print( + variables_, + "size += $tag_size$ * get$capitalized_name$List().size();\n"); + } + + // cache the data size for packed fields. + if (descriptor_->is_packed()) { + printer->Print(variables_, "$name$MemoizedSerializedSize = dataSize;\n"); + } + + printer->Outdent(); + printer->Print("}\n"); +} + +void RepeatedImmutablePrimitiveFieldGenerator::GenerateEqualsCode( + io::Printer* printer) const { + printer->Print( + variables_, + "if (!get$capitalized_name$List()\n" + " .equals(other.get$capitalized_name$List())) return false;\n"); +} + +void RepeatedImmutablePrimitiveFieldGenerator::GenerateHashCode( + io::Printer* printer) const { + printer->Print( + variables_, + "if (get$capitalized_name$Count() > 0) {\n" + " hash = (37 * hash) + $constant_name$;\n" + " hash = (53 * hash) + get$capitalized_name$List().hashCode();\n" + "}\n"); +} + +std::string RepeatedImmutablePrimitiveFieldGenerator::GetBoxedType() const { + return BoxedPrimitiveTypeName(GetJavaType(descriptor_)); +} + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/java/java_primitive_field.h b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_primitive_field.h new file mode 100644 index 00000000..2291ecb2 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_primitive_field.h @@ -0,0 +1,162 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_PRIMITIVE_FIELD_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVA_PRIMITIVE_FIELD_H__ + +#include <map> +#include <string> +#include <compiler/java/java_field.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { +class Context; // context.h +class ClassNameResolver; // name_resolver.h +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +class ImmutablePrimitiveFieldGenerator : public ImmutableFieldGenerator { + public: + explicit ImmutablePrimitiveFieldGenerator(const FieldDescriptor* descriptor, + int messageBitIndex, + int builderBitIndex, + Context* context); + ~ImmutablePrimitiveFieldGenerator() override; + + // implements ImmutableFieldGenerator + // --------------------------------------- + int GetNumBitsForMessage() const override; + int GetNumBitsForBuilder() const override; + void GenerateInterfaceMembers(io::Printer* printer) const override; + void GenerateMembers(io::Printer* printer) const override; + void GenerateBuilderMembers(io::Printer* printer) const override; + void GenerateInitializationCode(io::Printer* printer) const override; + void GenerateBuilderClearCode(io::Printer* printer) const override; + void GenerateMergingCode(io::Printer* printer) const override; + void GenerateBuildingCode(io::Printer* printer) const override; + void GenerateParsingCode(io::Printer* printer) const override; + void GenerateParsingDoneCode(io::Printer* printer) const override; + void GenerateSerializationCode(io::Printer* printer) const override; + void GenerateSerializedSizeCode(io::Printer* printer) const override; + void GenerateFieldBuilderInitializationCode( + io::Printer* printer) const override; + void GenerateEqualsCode(io::Printer* printer) const override; + void GenerateHashCode(io::Printer* printer) const override; + void GenerateKotlinDslMembers(io::Printer* printer) const override; + + std::string GetBoxedType() const override; + + protected: + const FieldDescriptor* descriptor_; + std::map<std::string, std::string> variables_; + ClassNameResolver* name_resolver_; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutablePrimitiveFieldGenerator); +}; + +class ImmutablePrimitiveOneofFieldGenerator + : public ImmutablePrimitiveFieldGenerator { + public: + ImmutablePrimitiveOneofFieldGenerator(const FieldDescriptor* descriptor, + int messageBitIndex, + int builderBitIndex, Context* context); + ~ImmutablePrimitiveOneofFieldGenerator(); + + void GenerateMembers(io::Printer* printer) const override; + void GenerateBuilderMembers(io::Printer* printer) const override; + void GenerateBuildingCode(io::Printer* printer) const override; + void GenerateMergingCode(io::Printer* printer) const override; + void GenerateParsingCode(io::Printer* printer) const override; + void GenerateSerializationCode(io::Printer* printer) const override; + void GenerateSerializedSizeCode(io::Printer* printer) const override; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutablePrimitiveOneofFieldGenerator); +}; + +class RepeatedImmutablePrimitiveFieldGenerator + : public ImmutableFieldGenerator { + public: + explicit RepeatedImmutablePrimitiveFieldGenerator( + const FieldDescriptor* descriptor, int messageBitIndex, + int builderBitIndex, Context* context); + ~RepeatedImmutablePrimitiveFieldGenerator() override; + + // implements ImmutableFieldGenerator --------------------------------------- + int GetNumBitsForMessage() const override; + int GetNumBitsForBuilder() const override; + void GenerateInterfaceMembers(io::Printer* printer) const override; + void GenerateMembers(io::Printer* printer) const override; + void GenerateBuilderMembers(io::Printer* printer) const override; + void GenerateInitializationCode(io::Printer* printer) const override; + void GenerateBuilderClearCode(io::Printer* printer) const override; + void GenerateMergingCode(io::Printer* printer) const override; + void GenerateBuildingCode(io::Printer* printer) const override; + void GenerateParsingCode(io::Printer* printer) const override; + void GenerateParsingCodeFromPacked(io::Printer* printer) const override; + void GenerateParsingDoneCode(io::Printer* printer) const override; + void GenerateSerializationCode(io::Printer* printer) const override; + void GenerateSerializedSizeCode(io::Printer* printer) const override; + void GenerateFieldBuilderInitializationCode( + io::Printer* printer) const override; + void GenerateEqualsCode(io::Printer* printer) const override; + void GenerateHashCode(io::Printer* printer) const override; + void GenerateKotlinDslMembers(io::Printer* printer) const override; + + std::string GetBoxedType() const override; + + private: + const FieldDescriptor* descriptor_; + std::map<std::string, std::string> variables_; + ClassNameResolver* name_resolver_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedImmutablePrimitiveFieldGenerator); +}; + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_PRIMITIVE_FIELD_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/java/java_primitive_field_lite.cc b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_primitive_field_lite.cc new file mode 100644 index 00000000..7b680a70 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_primitive_field_lite.cc @@ -0,0 +1,779 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <compiler/java/java_primitive_field_lite.h> + +#include <cstdint> +#include <map> +#include <string> + +#include <stubs/logging.h> +#include <stubs/common.h> +#include <compiler/java/java_context.h> +#include <compiler/java/java_doc_comment.h> +#include <compiler/java/java_helpers.h> +#include <compiler/java/java_name_resolver.h> +#include <io/printer.h> +#include <wire_format.h> +#include <stubs/strutil.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +using internal::WireFormat; +using internal::WireFormatLite; + +namespace { +bool EnableExperimentalRuntimeForLite() { +#ifdef PROTOBUF_EXPERIMENT + return PROTOBUF_EXPERIMENT; +#else // PROTOBUF_EXPERIMENT + return false; +#endif // !PROTOBUF_EXPERIMENT +} + +void SetPrimitiveVariables(const FieldDescriptor* descriptor, + int messageBitIndex, int builderBitIndex, + const FieldGeneratorInfo* info, + ClassNameResolver* name_resolver, + std::map<std::string, std::string>* variables) { + SetCommonFieldVariables(descriptor, info, variables); + JavaType javaType = GetJavaType(descriptor); + (*variables)["type"] = PrimitiveTypeName(javaType); + (*variables)["boxed_type"] = BoxedPrimitiveTypeName(javaType); + (*variables)["kt_type"] = KotlinTypeName(javaType); + (*variables)["field_type"] = (*variables)["type"]; + (*variables)["default"] = ImmutableDefaultValue(descriptor, name_resolver); + (*variables)["capitalized_type"] = + GetCapitalizedType(descriptor, /* immutable = */ true); + (*variables)["tag"] = + StrCat(static_cast<int32_t>(WireFormat::MakeTag(descriptor))); + (*variables)["tag_size"] = StrCat( + WireFormat::TagSize(descriptor->number(), GetType(descriptor))); + (*variables)["required"] = descriptor->is_required() ? "true" : "false"; + + std::string capitalized_type = UnderscoresToCamelCase( + PrimitiveTypeName(javaType), true /* cap_next_letter */); + switch (javaType) { + case JAVATYPE_INT: + case JAVATYPE_LONG: + case JAVATYPE_FLOAT: + case JAVATYPE_DOUBLE: + case JAVATYPE_BOOLEAN: + (*variables)["field_list_type"] = + "com.google.protobuf.Internal." + capitalized_type + "List"; + (*variables)["empty_list"] = "empty" + capitalized_type + "List()"; + (*variables)["make_name_unmodifiable"] = + (*variables)["name"] + "_.makeImmutable()"; + (*variables)["repeated_get"] = + (*variables)["name"] + "_.get" + capitalized_type; + (*variables)["repeated_add"] = + (*variables)["name"] + "_.add" + capitalized_type; + (*variables)["repeated_set"] = + (*variables)["name"] + "_.set" + capitalized_type; + (*variables)["visit_type"] = capitalized_type; + (*variables)["visit_type_list"] = "visit" + capitalized_type + "List"; + break; + default: + (*variables)["field_list_type"] = + "com.google.protobuf.Internal.ProtobufList<" + + (*variables)["boxed_type"] + ">"; + (*variables)["empty_list"] = "emptyProtobufList()"; + (*variables)["make_name_unmodifiable"] = + (*variables)["name"] + "_.makeImmutable()"; + (*variables)["repeated_get"] = (*variables)["name"] + "_.get"; + (*variables)["repeated_add"] = (*variables)["name"] + "_.add"; + (*variables)["repeated_set"] = (*variables)["name"] + "_.set"; + (*variables)["visit_type"] = "ByteString"; + (*variables)["visit_type_list"] = "visitList"; + } + + if (javaType == JAVATYPE_BYTES) { + (*variables)["bytes_default"] = + ToUpper((*variables)["name"]) + "_DEFAULT_VALUE"; + } + + if (IsReferenceType(javaType)) { + // We use `x.getClass()` as a null check because it generates less bytecode + // than an `if (x == null) { throw ... }` statement. + (*variables)["null_check"] = + " java.lang.Class<?> valueClass = value.getClass();\n"; + } else { + (*variables)["null_check"] = ""; + } + // TODO(birdo): Add @deprecated javadoc when generating javadoc is supported + // by the proto compiler + (*variables)["deprecation"] = + descriptor->options().deprecated() ? "@java.lang.Deprecated " : ""; + (*variables)["kt_deprecation"] = + descriptor->options().deprecated() + ? "@kotlin.Deprecated(message = \"Field " + (*variables)["name"] + + " is deprecated\") " + : ""; + int fixed_size = FixedSize(GetType(descriptor)); + if (fixed_size != -1) { + (*variables)["fixed_size"] = StrCat(fixed_size); + } + + if (HasHasbit(descriptor)) { + // For singular messages and builders, one bit is used for the hasField bit. + (*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex); + + // Note that these have a trailing ";". + (*variables)["set_has_field_bit_message"] = + GenerateSetBit(messageBitIndex) + ";"; + (*variables)["clear_has_field_bit_message"] = + GenerateClearBit(messageBitIndex) + ";"; + + (*variables)["is_field_present_message"] = GenerateGetBit(messageBitIndex); + } else { + (*variables)["set_has_field_bit_message"] = ""; + (*variables)["set_has_field_bit_message"] = ""; + (*variables)["clear_has_field_bit_message"] = ""; + + switch (descriptor->type()) { + case FieldDescriptor::TYPE_BYTES: + (*variables)["is_field_present_message"] = + "!" + (*variables)["name"] + "_.isEmpty()"; + break; + case FieldDescriptor::TYPE_FLOAT: + (*variables)["is_field_present_message"] = + "java.lang.Float.floatToRawIntBits(" + (*variables)["name"] + + "_) != 0"; + break; + case FieldDescriptor::TYPE_DOUBLE: + (*variables)["is_field_present_message"] = + "java.lang.Double.doubleToRawLongBits(" + (*variables)["name"] + + "_) != 0"; + break; + default: + (*variables)["is_field_present_message"] = + (*variables)["name"] + "_ != " + (*variables)["default"]; + break; + } + } + + (*variables)["get_has_field_bit_from_local"] = + GenerateGetBitFromLocal(builderBitIndex); + (*variables)["set_has_field_bit_to_local"] = + GenerateSetBitToLocal(messageBitIndex); +} + +} // namespace + +// =================================================================== + +ImmutablePrimitiveFieldLiteGenerator::ImmutablePrimitiveFieldLiteGenerator( + const FieldDescriptor* descriptor, int messageBitIndex, Context* context) + : descriptor_(descriptor), + messageBitIndex_(messageBitIndex), + name_resolver_(context->GetNameResolver()) { + SetPrimitiveVariables(descriptor, messageBitIndex, 0, + context->GetFieldGeneratorInfo(descriptor), + name_resolver_, &variables_); +} + +ImmutablePrimitiveFieldLiteGenerator::~ImmutablePrimitiveFieldLiteGenerator() {} + +int ImmutablePrimitiveFieldLiteGenerator::GetNumBitsForMessage() const { + return HasHasbit(descriptor_) ? 1 : 0; +} + +void ImmutablePrimitiveFieldLiteGenerator::GenerateInterfaceMembers( + io::Printer* printer) const { + if (HasHazzer(descriptor_)) { + WriteFieldAccessorDocComment(printer, descriptor_, HAZZER); + printer->Print(variables_, + "$deprecation$boolean has$capitalized_name$();\n"); + } + WriteFieldAccessorDocComment(printer, descriptor_, GETTER); + printer->Print(variables_, "$deprecation$$type$ get$capitalized_name$();\n"); +} + +void ImmutablePrimitiveFieldLiteGenerator::GenerateMembers( + io::Printer* printer) const { + if (IsByteStringWithCustomDefaultValue(descriptor_)) { + // allocate this once statically since we know ByteStrings are immutable + // values that can be reused. + printer->Print( + variables_, + "private static final $field_type$ $bytes_default$ = $default$;\n"); + } + printer->Print(variables_, "private $field_type$ $name$_;\n"); + PrintExtraFieldInfo(variables_, printer); + if (HasHazzer(descriptor_)) { + WriteFieldAccessorDocComment(printer, descriptor_, HAZZER); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n" + " return $get_has_field_bit_message$;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + } + + WriteFieldAccessorDocComment(printer, descriptor_, GETTER); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$public $type$ ${$get$capitalized_name$$}$() {\n" + " return $name$_;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + WriteFieldAccessorDocComment(printer, descriptor_, SETTER); + printer->Print(variables_, + "private void set$capitalized_name$($type$ value) {\n" + "$null_check$" + " $set_has_field_bit_message$\n" + " $name$_ = value;\n" + "}\n"); + + WriteFieldAccessorDocComment(printer, descriptor_, CLEARER); + printer->Print(variables_, + "private void clear$capitalized_name$() {\n" + " $clear_has_field_bit_message$\n"); + JavaType type = GetJavaType(descriptor_); + if (type == JAVATYPE_STRING || type == JAVATYPE_BYTES) { + // The default value is not a simple literal so we want to avoid executing + // it multiple times. Instead, get the default out of the default instance. + printer->Print( + variables_, + " $name$_ = getDefaultInstance().get$capitalized_name$();\n"); + } else { + printer->Print(variables_, " $name$_ = $default$;\n"); + } + printer->Print(variables_, "}\n"); +} + +void ImmutablePrimitiveFieldLiteGenerator::GenerateBuilderMembers( + io::Printer* printer) const { + if (HasHazzer(descriptor_)) { + WriteFieldAccessorDocComment(printer, descriptor_, HAZZER); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n" + " return instance.has$capitalized_name$();\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + } + + WriteFieldAccessorDocComment(printer, descriptor_, GETTER); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$public $type$ ${$get$capitalized_name$$}$() {\n" + " return instance.get$capitalized_name$();\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + WriteFieldAccessorDocComment(printer, descriptor_, SETTER, + /* builder */ true); + printer->Print(variables_, + "$deprecation$public Builder " + "${$set$capitalized_name$$}$($type$ value) {\n" + " copyOnWrite();\n" + " instance.set$capitalized_name$(value);\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + WriteFieldAccessorDocComment(printer, descriptor_, CLEARER, + /* builder */ true); + printer->Print( + variables_, + "$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n" + " copyOnWrite();\n" + " instance.clear$capitalized_name$();\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); +} + +void ImmutablePrimitiveFieldLiteGenerator::GenerateKotlinDslMembers( + io::Printer* printer) const { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$kt_deprecation$public var $kt_name$: $kt_type$\n" + " @JvmName(\"${$get$kt_capitalized_name$$}$\")\n" + " get() = $kt_dsl_builder$.${$get$capitalized_name$$}$()\n" + " @JvmName(\"${$set$kt_capitalized_name$$}$\")\n" + " set(value) {\n" + " $kt_dsl_builder$.${$set$capitalized_name$$}$(value)\n" + " }\n"); + + WriteFieldAccessorDocComment(printer, descriptor_, CLEARER, + /* builder */ false); + printer->Print(variables_, + "public fun ${$clear$kt_capitalized_name$$}$() {\n" + " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n" + "}\n"); + + if (HasHazzer(descriptor_)) { + WriteFieldAccessorDocComment(printer, descriptor_, HAZZER); + printer->Print( + variables_, + "public fun ${$has$kt_capitalized_name$$}$(): kotlin.Boolean {\n" + " return $kt_dsl_builder$.${$has$capitalized_name$$}$()\n" + "}\n"); + } +} + +void ImmutablePrimitiveFieldLiteGenerator::GenerateFieldInfo( + io::Printer* printer, std::vector<uint16_t>* output) const { + WriteIntToUtf16CharSequence(descriptor_->number(), output); + WriteIntToUtf16CharSequence(GetExperimentalJavaFieldType(descriptor_), + output); + if (HasHasbit(descriptor_)) { + WriteIntToUtf16CharSequence(messageBitIndex_, output); + } + printer->Print(variables_, "\"$name$_\",\n"); +} + +void ImmutablePrimitiveFieldLiteGenerator::GenerateInitializationCode( + io::Printer* printer) const { + if (IsByteStringWithCustomDefaultValue(descriptor_)) { + printer->Print(variables_, "$name$_ = $bytes_default$;\n"); + } else if (!IsDefaultValueJavaDefault(descriptor_)) { + printer->Print(variables_, "$name$_ = $default$;\n"); + } +} + +std::string ImmutablePrimitiveFieldLiteGenerator::GetBoxedType() const { + return BoxedPrimitiveTypeName(GetJavaType(descriptor_)); +} + +// =================================================================== + +ImmutablePrimitiveOneofFieldLiteGenerator:: + ImmutablePrimitiveOneofFieldLiteGenerator(const FieldDescriptor* descriptor, + int messageBitIndex, + Context* context) + : ImmutablePrimitiveFieldLiteGenerator(descriptor, messageBitIndex, + context) { + const OneofGeneratorInfo* info = + context->GetOneofGeneratorInfo(descriptor->containing_oneof()); + SetCommonOneofVariables(descriptor, info, &variables_); +} + +ImmutablePrimitiveOneofFieldLiteGenerator:: + ~ImmutablePrimitiveOneofFieldLiteGenerator() {} + +void ImmutablePrimitiveOneofFieldLiteGenerator::GenerateMembers( + io::Printer* printer) const { + PrintExtraFieldInfo(variables_, printer); + GOOGLE_DCHECK(HasHazzer(descriptor_)); + WriteFieldAccessorDocComment(printer, descriptor_, HAZZER); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n" + " return $has_oneof_case_message$;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + WriteFieldAccessorDocComment(printer, descriptor_, GETTER); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$public $type$ ${$get$capitalized_name$$}$() {\n" + " if ($has_oneof_case_message$) {\n" + " return ($boxed_type$) $oneof_name$_;\n" + " }\n" + " return $default$;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + WriteFieldAccessorDocComment(printer, descriptor_, SETTER); + printer->Print(variables_, + "private void set$capitalized_name$($type$ value) {\n" + "$null_check$" + " $set_oneof_case_message$;\n" + " $oneof_name$_ = value;\n" + "}\n"); + + WriteFieldAccessorDocComment(printer, descriptor_, CLEARER); + printer->Print(variables_, + "private void clear$capitalized_name$() {\n" + " if ($has_oneof_case_message$) {\n" + " $clear_oneof_case_message$;\n" + " $oneof_name$_ = null;\n" + " }\n" + "}\n"); +} + +void ImmutablePrimitiveOneofFieldLiteGenerator::GenerateFieldInfo( + io::Printer* printer, std::vector<uint16_t>* output) const { + WriteIntToUtf16CharSequence(descriptor_->number(), output); + WriteIntToUtf16CharSequence(GetExperimentalJavaFieldType(descriptor_), + output); + WriteIntToUtf16CharSequence(descriptor_->containing_oneof()->index(), output); +} + +void ImmutablePrimitiveOneofFieldLiteGenerator::GenerateBuilderMembers( + io::Printer* printer) const { + GOOGLE_DCHECK(HasHazzer(descriptor_)); + WriteFieldAccessorDocComment(printer, descriptor_, HAZZER); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n" + " return instance.has$capitalized_name$();\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + WriteFieldAccessorDocComment(printer, descriptor_, GETTER); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$public $type$ ${$get$capitalized_name$$}$() {\n" + " return instance.get$capitalized_name$();\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + WriteFieldAccessorDocComment(printer, descriptor_, SETTER, + /* builder */ true); + printer->Print(variables_, + "$deprecation$public Builder " + "${$set$capitalized_name$$}$($type$ value) {\n" + " copyOnWrite();\n" + " instance.set$capitalized_name$(value);\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + WriteFieldAccessorDocComment(printer, descriptor_, CLEARER, + /* builder */ true); + printer->Print( + variables_, + "$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n" + " copyOnWrite();\n" + " instance.clear$capitalized_name$();\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); +} + +// =================================================================== + +RepeatedImmutablePrimitiveFieldLiteGenerator:: + RepeatedImmutablePrimitiveFieldLiteGenerator( + const FieldDescriptor* descriptor, int messageBitIndex, + Context* context) + : descriptor_(descriptor), + context_(context), + name_resolver_(context->GetNameResolver()) { + SetPrimitiveVariables(descriptor, messageBitIndex, 0, + context->GetFieldGeneratorInfo(descriptor), + name_resolver_, &variables_); +} + +RepeatedImmutablePrimitiveFieldLiteGenerator:: + ~RepeatedImmutablePrimitiveFieldLiteGenerator() {} + +int RepeatedImmutablePrimitiveFieldLiteGenerator::GetNumBitsForMessage() const { + return 0; +} + +void RepeatedImmutablePrimitiveFieldLiteGenerator::GenerateInterfaceMembers( + io::Printer* printer) const { + WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER); + printer->Print(variables_, + "$deprecation$java.util.List<$boxed_type$> " + "get$capitalized_name$List();\n"); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_COUNT); + printer->Print(variables_, + "$deprecation$int get$capitalized_name$Count();\n"); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_GETTER); + printer->Print(variables_, + "$deprecation$$type$ get$capitalized_name$(int index);\n"); +} + +void RepeatedImmutablePrimitiveFieldLiteGenerator::GenerateMembers( + io::Printer* printer) const { + printer->Print(variables_, "private $field_list_type$ $name$_;\n"); + PrintExtraFieldInfo(variables_, printer); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$public java.util.List<$boxed_type$>\n" + " ${$get$capitalized_name$List$}$() {\n" + " return $name$_;\n" // note: unmodifiable list + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_COUNT); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$public int ${$get$capitalized_name$Count$}$() {\n" + " return $name$_.size();\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_GETTER); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$public $type$ ${$get$capitalized_name$$}$(int index) {\n" + " return $repeated_get$(index);\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + if (!EnableExperimentalRuntimeForLite() && descriptor_->is_packed() && + context_->HasGeneratedMethods(descriptor_->containing_type())) { + printer->Print(variables_, + "private int $name$MemoizedSerializedSize = -1;\n"); + } + + printer->Print( + variables_, + "private void ensure$capitalized_name$IsMutable() {\n" + // Use a temporary to avoid a redundant iget-object. + " $field_list_type$ tmp = $name$_;\n" + " if (!tmp.isModifiable()) {\n" + " $name$_ =\n" + " com.google.protobuf.GeneratedMessageLite.mutableCopy(tmp);\n" + " }\n" + "}\n"); + + WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_SETTER); + printer->Print(variables_, + "private void set$capitalized_name$(\n" + " int index, $type$ value) {\n" + "$null_check$" + " ensure$capitalized_name$IsMutable();\n" + " $repeated_set$(index, value);\n" + "}\n"); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER); + printer->Print(variables_, + "private void add$capitalized_name$($type$ value) {\n" + "$null_check$" + " ensure$capitalized_name$IsMutable();\n" + " $repeated_add$(value);\n" + "}\n"); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER); + printer->Print(variables_, + "private void addAll$capitalized_name$(\n" + " java.lang.Iterable<? extends $boxed_type$> values) {\n" + " ensure$capitalized_name$IsMutable();\n" + " com.google.protobuf.AbstractMessageLite.addAll(\n" + " values, $name$_);\n" + "}\n"); + WriteFieldAccessorDocComment(printer, descriptor_, CLEARER); + printer->Print(variables_, + "private void clear$capitalized_name$() {\n" + " $name$_ = $empty_list$;\n" + "}\n"); +} + +void RepeatedImmutablePrimitiveFieldLiteGenerator::GenerateBuilderMembers( + io::Printer* printer) const { + WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$public java.util.List<$boxed_type$>\n" + " ${$get$capitalized_name$List$}$() {\n" + " return java.util.Collections.unmodifiableList(\n" + " instance.get$capitalized_name$List());\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_COUNT); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$public int ${$get$capitalized_name$Count$}$() {\n" + " return instance.get$capitalized_name$Count();\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_GETTER); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$public $type$ ${$get$capitalized_name$$}$(int index) {\n" + " return instance.get$capitalized_name$(index);\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldAccessorDocComment(printer, descriptor_, SETTER, + /* builder */ true); + printer->Print(variables_, + "$deprecation$public Builder ${$set$capitalized_name$$}$(\n" + " int index, $type$ value) {\n" + " copyOnWrite();\n" + " instance.set$capitalized_name$(index, value);\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER, + /* builder */ true); + printer->Print(variables_, + "$deprecation$public Builder " + "${$add$capitalized_name$$}$($type$ value) {\n" + " copyOnWrite();\n" + " instance.add$capitalized_name$(value);\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER, + /* builder */ true); + printer->Print(variables_, + "$deprecation$public Builder ${$addAll$capitalized_name$$}$(\n" + " java.lang.Iterable<? extends $boxed_type$> values) {\n" + " copyOnWrite();\n" + " instance.addAll$capitalized_name$(values);\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldAccessorDocComment(printer, descriptor_, CLEARER, + /* builder */ true); + printer->Print( + variables_, + "$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n" + " copyOnWrite();\n" + " instance.clear$capitalized_name$();\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); +} + +void RepeatedImmutablePrimitiveFieldLiteGenerator::GenerateKotlinDslMembers( + io::Printer* printer) const { + printer->Print( + variables_, + "/**\n" + " * An uninstantiable, behaviorless type to represent the field in\n" + " * generics.\n" + " */\n" + "@kotlin.OptIn" + "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n" + "public class ${$$kt_capitalized_name$Proxy$}$ private constructor()" + " : com.google.protobuf.kotlin.DslProxy()\n"); + + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$kt_deprecation$ public val $kt_name$: " + "com.google.protobuf.kotlin.DslList" + "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>\n" + " @kotlin.jvm.JvmSynthetic\n" + " get() = com.google.protobuf.kotlin.DslList(\n" + " $kt_dsl_builder$.${$get$capitalized_name$List$}$()\n" + " )\n"); + + WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER, + /* builder */ false); + printer->Print(variables_, + "@kotlin.jvm.JvmSynthetic\n" + "@kotlin.jvm.JvmName(\"add$kt_capitalized_name$\")\n" + "public fun com.google.protobuf.kotlin.DslList" + "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." + "add(value: $kt_type$) {\n" + " $kt_dsl_builder$.${$add$capitalized_name$$}$(value)\n" + "}"); + + WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER, + /* builder */ false); + printer->Print(variables_, + "@kotlin.jvm.JvmSynthetic\n" + "@kotlin.jvm.JvmName(\"plusAssign$kt_capitalized_name$\")\n" + "@Suppress(\"NOTHING_TO_INLINE\")\n" + "public inline operator fun com.google.protobuf.kotlin.DslList" + "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." + "plusAssign(value: $kt_type$) {\n" + " add(value)\n" + "}"); + + WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER, + /* builder */ false); + printer->Print(variables_, + "@kotlin.jvm.JvmSynthetic\n" + "@kotlin.jvm.JvmName(\"addAll$kt_capitalized_name$\")\n" + "public fun com.google.protobuf.kotlin.DslList" + "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." + "addAll(values: kotlin.collections.Iterable<$kt_type$>) {\n" + " $kt_dsl_builder$.${$addAll$capitalized_name$$}$(values)\n" + "}"); + + WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER, + /* builder */ false); + printer->Print( + variables_, + "@kotlin.jvm.JvmSynthetic\n" + "@kotlin.jvm.JvmName(\"plusAssignAll$kt_capitalized_name$\")\n" + "@Suppress(\"NOTHING_TO_INLINE\")\n" + "public inline operator fun com.google.protobuf.kotlin.DslList" + "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." + "plusAssign(values: kotlin.collections.Iterable<$kt_type$>) {\n" + " addAll(values)\n" + "}"); + + WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_SETTER, + /* builder */ false); + printer->Print( + variables_, + "@kotlin.jvm.JvmSynthetic\n" + "@kotlin.jvm.JvmName(\"set$kt_capitalized_name$\")\n" + "public operator fun com.google.protobuf.kotlin.DslList" + "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." + "set(index: kotlin.Int, value: $kt_type$) {\n" + " $kt_dsl_builder$.${$set$capitalized_name$$}$(index, value)\n" + "}"); + + WriteFieldAccessorDocComment(printer, descriptor_, CLEARER, + /* builder */ false); + printer->Print(variables_, + "@kotlin.jvm.JvmSynthetic\n" + "@kotlin.jvm.JvmName(\"clear$kt_capitalized_name$\")\n" + "public fun com.google.protobuf.kotlin.DslList" + "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." + "clear() {\n" + " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n" + "}"); +} + +void RepeatedImmutablePrimitiveFieldLiteGenerator::GenerateFieldInfo( + io::Printer* printer, std::vector<uint16_t>* output) const { + WriteIntToUtf16CharSequence(descriptor_->number(), output); + WriteIntToUtf16CharSequence(GetExperimentalJavaFieldType(descriptor_), + output); + printer->Print(variables_, "\"$name$_\",\n"); +} + +void RepeatedImmutablePrimitiveFieldLiteGenerator::GenerateInitializationCode( + io::Printer* printer) const { + printer->Print(variables_, "$name$_ = $empty_list$;\n"); +} + +std::string RepeatedImmutablePrimitiveFieldLiteGenerator::GetBoxedType() const { + return BoxedPrimitiveTypeName(GetJavaType(descriptor_)); +} + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/java/java_primitive_field_lite.h b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_primitive_field_lite.h new file mode 100644 index 00000000..8bfd7ae2 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_primitive_field_lite.h @@ -0,0 +1,141 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_PRIMITIVE_FIELD_LITE_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVA_PRIMITIVE_FIELD_LITE_H__ + +#include <cstdint> +#include <map> +#include <string> + +#include <compiler/java/java_field.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { +class Context; // context.h +class ClassNameResolver; // name_resolver.h +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +class ImmutablePrimitiveFieldLiteGenerator + : public ImmutableFieldLiteGenerator { + public: + explicit ImmutablePrimitiveFieldLiteGenerator( + const FieldDescriptor* descriptor, int messageBitIndex, Context* context); + ~ImmutablePrimitiveFieldLiteGenerator() override; + + // implements ImmutableFieldLiteGenerator + // ------------------------------------ + int GetNumBitsForMessage() const override; + void GenerateInterfaceMembers(io::Printer* printer) const override; + void GenerateMembers(io::Printer* printer) const override; + void GenerateBuilderMembers(io::Printer* printer) const override; + void GenerateInitializationCode(io::Printer* printer) const override; + void GenerateFieldInfo(io::Printer* printer, + std::vector<uint16_t>* output) const override; + void GenerateKotlinDslMembers(io::Printer* printer) const override; + + std::string GetBoxedType() const override; + + protected: + const FieldDescriptor* descriptor_; + std::map<std::string, std::string> variables_; + const int messageBitIndex_; + ClassNameResolver* name_resolver_; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutablePrimitiveFieldLiteGenerator); +}; + +class ImmutablePrimitiveOneofFieldLiteGenerator + : public ImmutablePrimitiveFieldLiteGenerator { + public: + ImmutablePrimitiveOneofFieldLiteGenerator(const FieldDescriptor* descriptor, + int messageBitIndex, + Context* context); + ~ImmutablePrimitiveOneofFieldLiteGenerator(); + + void GenerateMembers(io::Printer* printer) const override; + void GenerateBuilderMembers(io::Printer* printer) const override; + + void GenerateFieldInfo(io::Printer* printer, + std::vector<uint16_t>* output) const override; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutablePrimitiveOneofFieldLiteGenerator); +}; + +class RepeatedImmutablePrimitiveFieldLiteGenerator + : public ImmutableFieldLiteGenerator { + public: + explicit RepeatedImmutablePrimitiveFieldLiteGenerator( + const FieldDescriptor* descriptor, int messageBitIndex, Context* context); + ~RepeatedImmutablePrimitiveFieldLiteGenerator() override; + + // implements ImmutableFieldLiteGenerator ------------------------------------ + int GetNumBitsForMessage() const override; + void GenerateInterfaceMembers(io::Printer* printer) const override; + void GenerateMembers(io::Printer* printer) const override; + void GenerateBuilderMembers(io::Printer* printer) const override; + void GenerateInitializationCode(io::Printer* printer) const override; + void GenerateFieldInfo(io::Printer* printer, + std::vector<uint16_t>* output) const override; + void GenerateKotlinDslMembers(io::Printer* printer) const override; + + std::string GetBoxedType() const override; + + private: + const FieldDescriptor* descriptor_; + std::map<std::string, std::string> variables_; + Context* context_; + ClassNameResolver* name_resolver_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedImmutablePrimitiveFieldLiteGenerator); +}; + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_PRIMITIVE_FIELD_LITE_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/java/java_service.cc b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_service.cc new file mode 100644 index 00000000..28407660 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_service.cc @@ -0,0 +1,474 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <compiler/java/java_service.h> + +#include <compiler/java/java_context.h> +#include <compiler/java/java_doc_comment.h> +#include <compiler/java/java_helpers.h> +#include <compiler/java/java_name_resolver.h> +#include <io/printer.h> +#include <stubs/strutil.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +ServiceGenerator::ServiceGenerator(const ServiceDescriptor* descriptor) + : descriptor_(descriptor) {} + +ServiceGenerator::~ServiceGenerator() {} + +// =================================================================== +ImmutableServiceGenerator::ImmutableServiceGenerator( + const ServiceDescriptor* descriptor, Context* context) + : ServiceGenerator(descriptor), + context_(context), + name_resolver_(context->GetNameResolver()) {} + +ImmutableServiceGenerator::~ImmutableServiceGenerator() {} + +void ImmutableServiceGenerator::Generate(io::Printer* printer) { + bool is_own_file = IsOwnFile(descriptor_, /* immutable = */ true); + WriteServiceDocComment(printer, descriptor_); + MaybePrintGeneratedAnnotation(context_, printer, descriptor_, + /* immutable = */ true); + printer->Print( + "public $static$ abstract class $classname$\n" + " implements com.google.protobuf.Service {\n", + "static", is_own_file ? "" : "static", "classname", descriptor_->name()); + printer->Indent(); + + printer->Print("protected $classname$() {}\n\n", "classname", + descriptor_->name()); + + GenerateInterface(printer); + + GenerateNewReflectiveServiceMethod(printer); + GenerateNewReflectiveBlockingServiceMethod(printer); + + GenerateAbstractMethods(printer); + + // Generate getDescriptor() and getDescriptorForType(). + printer->Print( + "public static final\n" + " com.google.protobuf.Descriptors.ServiceDescriptor\n" + " getDescriptor() {\n" + " return $file$.getDescriptor().getServices().get($index$);\n" + "}\n", + "file", name_resolver_->GetImmutableClassName(descriptor_->file()), + "index", StrCat(descriptor_->index())); + GenerateGetDescriptorForType(printer); + + // Generate more stuff. + GenerateCallMethod(printer); + GenerateGetPrototype(REQUEST, printer); + GenerateGetPrototype(RESPONSE, printer); + GenerateStub(printer); + GenerateBlockingStub(printer); + + // Add an insertion point. + printer->Print( + "\n" + "// @@protoc_insertion_point(class_scope:$full_name$)\n", + "full_name", descriptor_->full_name()); + + printer->Outdent(); + printer->Print("}\n\n"); +} + +void ImmutableServiceGenerator::GenerateGetDescriptorForType( + io::Printer* printer) { + printer->Print( + "public final com.google.protobuf.Descriptors.ServiceDescriptor\n" + " getDescriptorForType() {\n" + " return getDescriptor();\n" + "}\n"); +} + +void ImmutableServiceGenerator::GenerateInterface(io::Printer* printer) { + printer->Print("public interface Interface {\n"); + printer->Indent(); + GenerateAbstractMethods(printer); + printer->Outdent(); + printer->Print("}\n\n"); +} + +void ImmutableServiceGenerator::GenerateNewReflectiveServiceMethod( + io::Printer* printer) { + printer->Print( + "public static com.google.protobuf.Service newReflectiveService(\n" + " final Interface impl) {\n" + " return new $classname$() {\n", + "classname", descriptor_->name()); + printer->Indent(); + printer->Indent(); + + for (int i = 0; i < descriptor_->method_count(); i++) { + const MethodDescriptor* method = descriptor_->method(i); + printer->Print("@java.lang.Override\n"); + GenerateMethodSignature(printer, method, IS_CONCRETE); + printer->Print( + " {\n" + " impl.$method$(controller, request, done);\n" + "}\n\n", + "method", UnderscoresToCamelCase(method)); + } + + printer->Outdent(); + printer->Print("};\n"); + printer->Outdent(); + printer->Print("}\n\n"); +} + +void ImmutableServiceGenerator::GenerateNewReflectiveBlockingServiceMethod( + io::Printer* printer) { + printer->Print( + "public static com.google.protobuf.BlockingService\n" + " newReflectiveBlockingService(final BlockingInterface impl) {\n" + " return new com.google.protobuf.BlockingService() {\n"); + printer->Indent(); + printer->Indent(); + + GenerateGetDescriptorForType(printer); + + GenerateCallBlockingMethod(printer); + GenerateGetPrototype(REQUEST, printer); + GenerateGetPrototype(RESPONSE, printer); + + printer->Outdent(); + printer->Print("};\n"); + printer->Outdent(); + printer->Print("}\n\n"); +} + +void ImmutableServiceGenerator::GenerateAbstractMethods(io::Printer* printer) { + for (int i = 0; i < descriptor_->method_count(); i++) { + const MethodDescriptor* method = descriptor_->method(i); + WriteMethodDocComment(printer, method); + GenerateMethodSignature(printer, method, IS_ABSTRACT); + printer->Print(";\n\n"); + } +} + +std::string ImmutableServiceGenerator::GetOutput( + const MethodDescriptor* method) { + return name_resolver_->GetImmutableClassName(method->output_type()); +} + +void ImmutableServiceGenerator::GenerateCallMethod(io::Printer* printer) { + printer->Print( + "\n" + "public final void callMethod(\n" + " com.google.protobuf.Descriptors.MethodDescriptor method,\n" + " com.google.protobuf.RpcController controller,\n" + " com.google.protobuf.Message request,\n" + " com.google.protobuf.RpcCallback<\n" + " com.google.protobuf.Message> done) {\n" + " if (method.getService() != getDescriptor()) {\n" + " throw new java.lang.IllegalArgumentException(\n" + " \"Service.callMethod() given method descriptor for wrong \" +\n" + " \"service type.\");\n" + " }\n" + " switch(method.getIndex()) {\n"); + printer->Indent(); + printer->Indent(); + + for (int i = 0; i < descriptor_->method_count(); i++) { + const MethodDescriptor* method = descriptor_->method(i); + std::map<std::string, std::string> vars; + vars["index"] = StrCat(i); + vars["method"] = UnderscoresToCamelCase(method); + vars["input"] = name_resolver_->GetImmutableClassName(method->input_type()); + vars["output"] = GetOutput(method); + printer->Print( + vars, + "case $index$:\n" + " this.$method$(controller, ($input$)request,\n" + " com.google.protobuf.RpcUtil.<$output$>specializeCallback(\n" + " done));\n" + " return;\n"); + } + + printer->Print( + "default:\n" + " throw new java.lang.AssertionError(\"Can't get here.\");\n"); + + printer->Outdent(); + printer->Outdent(); + + printer->Print( + " }\n" + "}\n" + "\n"); +} + +void ImmutableServiceGenerator::GenerateCallBlockingMethod( + io::Printer* printer) { + printer->Print( + "\n" + "public final com.google.protobuf.Message callBlockingMethod(\n" + " com.google.protobuf.Descriptors.MethodDescriptor method,\n" + " com.google.protobuf.RpcController controller,\n" + " com.google.protobuf.Message request)\n" + " throws com.google.protobuf.ServiceException {\n" + " if (method.getService() != getDescriptor()) {\n" + " throw new java.lang.IllegalArgumentException(\n" + " \"Service.callBlockingMethod() given method descriptor for \" +\n" + " \"wrong service type.\");\n" + " }\n" + " switch(method.getIndex()) {\n"); + printer->Indent(); + printer->Indent(); + + for (int i = 0; i < descriptor_->method_count(); i++) { + const MethodDescriptor* method = descriptor_->method(i); + std::map<std::string, std::string> vars; + vars["index"] = StrCat(i); + vars["method"] = UnderscoresToCamelCase(method); + vars["input"] = name_resolver_->GetImmutableClassName(method->input_type()); + vars["output"] = GetOutput(method); + printer->Print(vars, + "case $index$:\n" + " return impl.$method$(controller, ($input$)request);\n"); + } + + printer->Print( + "default:\n" + " throw new java.lang.AssertionError(\"Can't get here.\");\n"); + + printer->Outdent(); + printer->Outdent(); + + printer->Print( + " }\n" + "}\n" + "\n"); +} + +void ImmutableServiceGenerator::GenerateGetPrototype(RequestOrResponse which, + io::Printer* printer) { + /* + * TODO(cpovirk): The exception message says "Service.foo" when it may be + * "BlockingService.foo." Consider fixing. + */ + printer->Print( + "public final com.google.protobuf.Message\n" + " get$request_or_response$Prototype(\n" + " com.google.protobuf.Descriptors.MethodDescriptor method) {\n" + " if (method.getService() != getDescriptor()) {\n" + " throw new java.lang.IllegalArgumentException(\n" + " \"Service.get$request_or_response$Prototype() given method \" +\n" + " \"descriptor for wrong service type.\");\n" + " }\n" + " switch(method.getIndex()) {\n", + "request_or_response", (which == REQUEST) ? "Request" : "Response"); + printer->Indent(); + printer->Indent(); + + for (int i = 0; i < descriptor_->method_count(); i++) { + const MethodDescriptor* method = descriptor_->method(i); + std::map<std::string, std::string> vars; + vars["index"] = StrCat(i); + vars["type"] = + (which == REQUEST) + ? name_resolver_->GetImmutableClassName(method->input_type()) + : GetOutput(method); + printer->Print(vars, + "case $index$:\n" + " return $type$.getDefaultInstance();\n"); + } + + printer->Print( + "default:\n" + " throw new java.lang.AssertionError(\"Can't get here.\");\n"); + + printer->Outdent(); + printer->Outdent(); + + printer->Print( + " }\n" + "}\n" + "\n"); +} + +void ImmutableServiceGenerator::GenerateStub(io::Printer* printer) { + printer->Print( + "public static Stub newStub(\n" + " com.google.protobuf.RpcChannel channel) {\n" + " return new Stub(channel);\n" + "}\n" + "\n" + "public static final class Stub extends $classname$ implements Interface " + "{" + "\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_)); + printer->Indent(); + + printer->Print( + "private Stub(com.google.protobuf.RpcChannel channel) {\n" + " this.channel = channel;\n" + "}\n" + "\n" + "private final com.google.protobuf.RpcChannel channel;\n" + "\n" + "public com.google.protobuf.RpcChannel getChannel() {\n" + " return channel;\n" + "}\n"); + + for (int i = 0; i < descriptor_->method_count(); i++) { + const MethodDescriptor* method = descriptor_->method(i); + printer->Print("\n"); + GenerateMethodSignature(printer, method, IS_CONCRETE); + printer->Print(" {\n"); + printer->Indent(); + + std::map<std::string, std::string> vars; + vars["index"] = StrCat(i); + vars["output"] = GetOutput(method); + printer->Print(vars, + "channel.callMethod(\n" + " getDescriptor().getMethods().get($index$),\n" + " controller,\n" + " request,\n" + " $output$.getDefaultInstance(),\n" + " com.google.protobuf.RpcUtil.generalizeCallback(\n" + " done,\n" + " $output$.class,\n" + " $output$.getDefaultInstance()));\n"); + + printer->Outdent(); + printer->Print("}\n"); + } + + printer->Outdent(); + printer->Print( + "}\n" + "\n"); +} + +void ImmutableServiceGenerator::GenerateBlockingStub(io::Printer* printer) { + printer->Print( + "public static BlockingInterface newBlockingStub(\n" + " com.google.protobuf.BlockingRpcChannel channel) {\n" + " return new BlockingStub(channel);\n" + "}\n" + "\n"); + + printer->Print("public interface BlockingInterface {"); + printer->Indent(); + + for (int i = 0; i < descriptor_->method_count(); i++) { + const MethodDescriptor* method = descriptor_->method(i); + GenerateBlockingMethodSignature(printer, method); + printer->Print(";\n"); + } + + printer->Outdent(); + printer->Print( + "}\n" + "\n"); + + printer->Print( + "private static final class BlockingStub implements BlockingInterface " + "{\n"); + printer->Indent(); + + printer->Print( + "private BlockingStub(com.google.protobuf.BlockingRpcChannel channel) {\n" + " this.channel = channel;\n" + "}\n" + "\n" + "private final com.google.protobuf.BlockingRpcChannel channel;\n"); + + for (int i = 0; i < descriptor_->method_count(); i++) { + const MethodDescriptor* method = descriptor_->method(i); + GenerateBlockingMethodSignature(printer, method); + printer->Print(" {\n"); + printer->Indent(); + + std::map<std::string, std::string> vars; + vars["index"] = StrCat(i); + vars["output"] = GetOutput(method); + printer->Print(vars, + "return ($output$) channel.callBlockingMethod(\n" + " getDescriptor().getMethods().get($index$),\n" + " controller,\n" + " request,\n" + " $output$.getDefaultInstance());\n"); + + printer->Outdent(); + printer->Print( + "}\n" + "\n"); + } + + printer->Outdent(); + printer->Print("}\n"); +} + +void ImmutableServiceGenerator::GenerateMethodSignature( + io::Printer* printer, const MethodDescriptor* method, + IsAbstract is_abstract) { + std::map<std::string, std::string> vars; + vars["name"] = UnderscoresToCamelCase(method); + vars["input"] = name_resolver_->GetImmutableClassName(method->input_type()); + vars["output"] = GetOutput(method); + vars["abstract"] = (is_abstract == IS_ABSTRACT) ? "abstract" : ""; + printer->Print(vars, + "public $abstract$ void $name$(\n" + " com.google.protobuf.RpcController controller,\n" + " $input$ request,\n" + " com.google.protobuf.RpcCallback<$output$> done)"); +} + +void ImmutableServiceGenerator::GenerateBlockingMethodSignature( + io::Printer* printer, const MethodDescriptor* method) { + std::map<std::string, std::string> vars; + vars["method"] = UnderscoresToCamelCase(method); + vars["input"] = name_resolver_->GetImmutableClassName(method->input_type()); + vars["output"] = GetOutput(method); + printer->Print(vars, + "\n" + "public $output$ $method$(\n" + " com.google.protobuf.RpcController controller,\n" + " $input$ request)\n" + " throws com.google.protobuf.ServiceException"); +} + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/java/java_service.h b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_service.h new file mode 100644 index 00000000..f21d5f11 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_service.h @@ -0,0 +1,139 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_SERVICE_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVA_SERVICE_H__ + +#include <map> +#include <descriptor.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { +class Context; // context.h +class ClassNameResolver; // name_resolver.h +} // namespace java +} // namespace compiler +namespace io { +class Printer; // printer.h +} +} // namespace protobuf +} // namespace google + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +class ServiceGenerator { + public: + explicit ServiceGenerator(const ServiceDescriptor* descriptor); + virtual ~ServiceGenerator(); + + virtual void Generate(io::Printer* printer) = 0; + + enum RequestOrResponse { REQUEST, RESPONSE }; + enum IsAbstract { IS_ABSTRACT, IS_CONCRETE }; + + protected: + const ServiceDescriptor* descriptor_; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ServiceGenerator); +}; + +class ImmutableServiceGenerator : public ServiceGenerator { + public: + ImmutableServiceGenerator(const ServiceDescriptor* descriptor, + Context* context); + virtual ~ImmutableServiceGenerator(); + + void Generate(io::Printer* printer) override; + + private: + // Generate the getDescriptorForType() method. + void GenerateGetDescriptorForType(io::Printer* printer); + + // Generate a Java interface for the service. + void GenerateInterface(io::Printer* printer); + + // Generate newReflectiveService() method. + void GenerateNewReflectiveServiceMethod(io::Printer* printer); + + // Generate newReflectiveBlockingService() method. + void GenerateNewReflectiveBlockingServiceMethod(io::Printer* printer); + + // Generate abstract method declarations for all methods. + void GenerateAbstractMethods(io::Printer* printer); + + // Generate the implementation of Service.callMethod(). + void GenerateCallMethod(io::Printer* printer); + + // Generate the implementation of BlockingService.callBlockingMethod(). + void GenerateCallBlockingMethod(io::Printer* printer); + + // Generate the implementations of Service.get{Request,Response}Prototype(). + void GenerateGetPrototype(RequestOrResponse which, io::Printer* printer); + + // Generate a stub implementation of the service. + void GenerateStub(io::Printer* printer); + + // Generate a method signature, possibly abstract, without body or trailing + // semicolon. + void GenerateMethodSignature(io::Printer* printer, + const MethodDescriptor* method, + IsAbstract is_abstract); + + // Generate a blocking stub interface and implementation of the service. + void GenerateBlockingStub(io::Printer* printer); + + // Generate the method signature for one method of a blocking stub. + void GenerateBlockingMethodSignature(io::Printer* printer, + const MethodDescriptor* method); + + // Return the output type of the method. + std::string GetOutput(const MethodDescriptor* method); + + Context* context_; + ClassNameResolver* name_resolver_; + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableServiceGenerator); +}; + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // NET_PROTO2_COMPILER_JAVA_SERVICE_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/java/java_shared_code_generator.cc b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_shared_code_generator.cc new file mode 100644 index 00000000..935ce7bb --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_shared_code_generator.cc @@ -0,0 +1,198 @@ +// 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. + +// Author: xiaofeng@google.com (Feng Xiao) + +#include <compiler/java/java_shared_code_generator.h> + +#include <memory> + +#include <compiler/java/java_helpers.h> +#include <compiler/java/java_name_resolver.h> +#include <compiler/java/java_names.h> +#include <compiler/code_generator.h> +#include <descriptor.pb.h> +#include <io/printer.h> +#include <io/zero_copy_stream.h> +#include <descriptor.h> +#include <stubs/strutil.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +SharedCodeGenerator::SharedCodeGenerator(const FileDescriptor* file, + const Options& options) + : name_resolver_(new ClassNameResolver), file_(file), options_(options) {} + +SharedCodeGenerator::~SharedCodeGenerator() {} + +void SharedCodeGenerator::Generate( + GeneratorContext* context, std::vector<std::string>* file_list, + std::vector<std::string>* annotation_file_list) { + std::string java_package = FileJavaPackage(file_); + std::string package_dir = JavaPackageToDir(java_package); + + if (HasDescriptorMethods(file_, options_.enforce_lite)) { + // Generate descriptors. + std::string classname = name_resolver_->GetDescriptorClassName(file_); + std::string filename = package_dir + classname + ".java"; + file_list->push_back(filename); + std::unique_ptr<io::ZeroCopyOutputStream> output(context->Open(filename)); + GeneratedCodeInfo annotations; + io::AnnotationProtoCollector<GeneratedCodeInfo> annotation_collector( + &annotations); + std::unique_ptr<io::Printer> printer( + new io::Printer(output.get(), '$', + options_.annotate_code ? &annotation_collector : NULL)); + std::string info_relative_path = classname + ".java.pb.meta"; + std::string info_full_path = filename + ".pb.meta"; + printer->Print( + "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" + "// source: $filename$\n" + "\n", + "filename", file_->name()); + if (!java_package.empty()) { + printer->Print( + "package $package$;\n" + "\n", + "package", java_package); + } + PrintGeneratedAnnotation(printer.get(), '$', + options_.annotate_code ? info_relative_path : ""); + printer->Print( + "public final class $classname$ {\n" + " public static com.google.protobuf.Descriptors.FileDescriptor\n" + " descriptor;\n" + " static {\n", + "classname", classname); + printer->Annotate("classname", file_->name()); + printer->Indent(); + printer->Indent(); + GenerateDescriptors(printer.get()); + printer->Outdent(); + printer->Outdent(); + printer->Print( + " }\n" + "}\n"); + + if (options_.annotate_code) { + std::unique_ptr<io::ZeroCopyOutputStream> info_output( + context->Open(info_full_path)); + annotations.SerializeToZeroCopyStream(info_output.get()); + annotation_file_list->push_back(info_full_path); + } + + printer.reset(); + output.reset(); + } +} + +void SharedCodeGenerator::GenerateDescriptors(io::Printer* printer) { + // Embed the descriptor. We simply serialize the entire FileDescriptorProto + // and embed it as a string literal, which is parsed and built into real + // descriptors at initialization time. We unfortunately have to put it in + // a string literal, not a byte array, because apparently using a literal + // byte array causes the Java compiler to generate *instructions* to + // initialize each and every byte of the array, e.g. as if you typed: + // b[0] = 123; b[1] = 456; b[2] = 789; + // This makes huge bytecode files and can easily hit the compiler's internal + // code size limits (error "code to large"). String literals are apparently + // embedded raw, which is what we want. + FileDescriptorProto file_proto; + file_->CopyTo(&file_proto); + + std::string file_data; + file_proto.SerializeToString(&file_data); + + printer->Print("java.lang.String[] descriptorData = {\n"); + printer->Indent(); + + // Limit the number of bytes per line. + static const int kBytesPerLine = 40; + // Limit the number of lines per string part. + static const int kLinesPerPart = 400; + // Every block of bytes, start a new string literal, in order to avoid the + // 64k length limit. Note that this value needs to be <64k. + static const int kBytesPerPart = kBytesPerLine * kLinesPerPart; + for (int i = 0; i < file_data.size(); i += kBytesPerLine) { + if (i > 0) { + if (i % kBytesPerPart == 0) { + printer->Print(",\n"); + } else { + printer->Print(" +\n"); + } + } + printer->Print("\"$data$\"", "data", + CEscape(file_data.substr(i, kBytesPerLine))); + } + + printer->Outdent(); + printer->Print("\n};\n"); + + // ----------------------------------------------------------------- + // Find out all dependencies. + std::vector<std::pair<std::string, std::string> > dependencies; + for (int i = 0; i < file_->dependency_count(); i++) { + std::string filename = file_->dependency(i)->name(); + std::string package = FileJavaPackage(file_->dependency(i)); + std::string classname = + name_resolver_->GetDescriptorClassName(file_->dependency(i)); + std::string full_name; + if (package.empty()) { + full_name = classname; + } else { + full_name = package + "." + classname; + } + dependencies.push_back(std::make_pair(filename, full_name)); + } + + // ----------------------------------------------------------------- + // Invoke internalBuildGeneratedFileFrom() to build the file. + printer->Print( + "descriptor = com.google.protobuf.Descriptors.FileDescriptor\n" + " .internalBuildGeneratedFileFrom(descriptorData,\n"); + printer->Print( + " new com.google.protobuf.Descriptors.FileDescriptor[] {\n"); + + for (int i = 0; i < dependencies.size(); i++) { + const std::string& dependency = dependencies[i].second; + printer->Print(" $dependency$.getDescriptor(),\n", "dependency", + dependency); + } + + printer->Print(" });\n"); +} + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/java/java_shared_code_generator.h b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_shared_code_generator.h new file mode 100644 index 00000000..1e315863 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_shared_code_generator.h @@ -0,0 +1,90 @@ +// 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. + +// Author: xiaofeng@google.com (Feng Xiao) +// +// Generators that generate shared code between immutable API and mutable API. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_SHARED_CODE_GENERATOR_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVA_SHARED_CODE_GENERATOR_H__ + +#include <memory> +#include <string> +#include <vector> + +#include <stubs/common.h> +#include <compiler/java/java_options.h> + +namespace google { +namespace protobuf { +class FileDescriptor; // descriptor.h +namespace compiler { +class GeneratorContext; // code_generator.h +namespace java { +class ClassNameResolver; // name_resolver.h +} +} // namespace compiler +namespace io { +class Printer; // printer.h +} +} // namespace protobuf +} // namespace google + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +// A generator that generates code that are shared between immutable API +// and mutable API. Currently only descriptors are shared. +class SharedCodeGenerator { + public: + SharedCodeGenerator(const FileDescriptor* file, const Options& options); + ~SharedCodeGenerator(); + + void Generate(GeneratorContext* generator_context, + std::vector<std::string>* file_list, + std::vector<std::string>* annotation_file_list); + + void GenerateDescriptors(io::Printer* printer); + + private: + std::unique_ptr<ClassNameResolver> name_resolver_; + const FileDescriptor* file_; + const Options options_; + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(SharedCodeGenerator); +}; + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_SHARED_CODE_GENERATOR_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/java/java_string_field.cc b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_string_field.cc new file mode 100644 index 00000000..454148ca --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_string_field.cc @@ -0,0 +1,1190 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Author: jonp@google.com (Jon Perlow) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <compiler/java/java_string_field.h> + +#include <cstdint> +#include <map> +#include <string> + +#include <stubs/logging.h> +#include <stubs/common.h> +#include <compiler/java/java_context.h> +#include <compiler/java/java_doc_comment.h> +#include <compiler/java/java_helpers.h> +#include <compiler/java/java_name_resolver.h> +#include <io/printer.h> +#include <wire_format.h> +#include <stubs/strutil.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +using internal::WireFormat; +using internal::WireFormatLite; + +namespace { + +void SetPrimitiveVariables(const FieldDescriptor* descriptor, + int messageBitIndex, int builderBitIndex, + const FieldGeneratorInfo* info, + ClassNameResolver* name_resolver, + std::map<std::string, std::string>* variables) { + SetCommonFieldVariables(descriptor, info, variables); + + (*variables)["empty_list"] = "com.google.protobuf.LazyStringArrayList.EMPTY"; + + (*variables)["default"] = ImmutableDefaultValue(descriptor, name_resolver); + (*variables)["default_init"] = + "= " + ImmutableDefaultValue(descriptor, name_resolver); + (*variables)["capitalized_type"] = "String"; + (*variables)["tag"] = + StrCat(static_cast<int32_t>(WireFormat::MakeTag(descriptor))); + (*variables)["tag_size"] = StrCat( + WireFormat::TagSize(descriptor->number(), GetType(descriptor))); + (*variables)["null_check"] = + " if (value == null) {\n" + " throw new NullPointerException();\n" + " }\n"; + (*variables)["isStringEmpty"] = "com.google.protobuf.GeneratedMessage" + + GeneratedCodeVersionSuffix() + + ".isStringEmpty"; + (*variables)["writeString"] = "com.google.protobuf.GeneratedMessage" + + GeneratedCodeVersionSuffix() + ".writeString"; + (*variables)["computeStringSize"] = "com.google.protobuf.GeneratedMessage" + + GeneratedCodeVersionSuffix() + + ".computeStringSize"; + + // TODO(birdo): Add @deprecated javadoc when generating javadoc is supported + // by the proto compiler + (*variables)["deprecation"] = + descriptor->options().deprecated() ? "@java.lang.Deprecated " : ""; + (*variables)["kt_deprecation"] = + descriptor->options().deprecated() + ? "@kotlin.Deprecated(message = \"Field " + (*variables)["name"] + + " is deprecated\") " + : ""; + (*variables)["on_changed"] = "onChanged();"; + + if (HasHasbit(descriptor)) { + // For singular messages and builders, one bit is used for the hasField bit. + (*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex); + (*variables)["get_has_field_bit_builder"] = GenerateGetBit(builderBitIndex); + + // Note that these have a trailing ";". + (*variables)["set_has_field_bit_message"] = + GenerateSetBit(messageBitIndex) + ";"; + (*variables)["set_has_field_bit_builder"] = + GenerateSetBit(builderBitIndex) + ";"; + (*variables)["clear_has_field_bit_builder"] = + GenerateClearBit(builderBitIndex) + ";"; + + (*variables)["is_field_present_message"] = GenerateGetBit(messageBitIndex); + } else { + (*variables)["set_has_field_bit_message"] = ""; + (*variables)["set_has_field_bit_builder"] = ""; + (*variables)["clear_has_field_bit_builder"] = ""; + + (*variables)["is_field_present_message"] = + "!" + (*variables)["isStringEmpty"] + "(" + (*variables)["name"] + "_)"; + } + + // For repeated builders, one bit is used for whether the array is immutable. + (*variables)["get_mutable_bit_builder"] = GenerateGetBit(builderBitIndex); + (*variables)["set_mutable_bit_builder"] = GenerateSetBit(builderBitIndex); + (*variables)["clear_mutable_bit_builder"] = GenerateClearBit(builderBitIndex); + + // For repeated fields, one bit is used for whether the array is immutable + // in the parsing constructor. + (*variables)["get_mutable_bit_parser"] = + GenerateGetBitMutableLocal(builderBitIndex); + (*variables)["set_mutable_bit_parser"] = + GenerateSetBitMutableLocal(builderBitIndex); + + (*variables)["get_has_field_bit_from_local"] = + GenerateGetBitFromLocal(builderBitIndex); + (*variables)["set_has_field_bit_to_local"] = + GenerateSetBitToLocal(messageBitIndex); +} + +} // namespace + +// =================================================================== + +ImmutableStringFieldGenerator::ImmutableStringFieldGenerator( + const FieldDescriptor* descriptor, int messageBitIndex, int builderBitIndex, + Context* context) + : descriptor_(descriptor), name_resolver_(context->GetNameResolver()) { + SetPrimitiveVariables(descriptor, messageBitIndex, builderBitIndex, + context->GetFieldGeneratorInfo(descriptor), + name_resolver_, &variables_); +} + +ImmutableStringFieldGenerator::~ImmutableStringFieldGenerator() {} + +int ImmutableStringFieldGenerator::GetNumBitsForMessage() const { + return HasHasbit(descriptor_) ? 1 : 0; +} + +int ImmutableStringFieldGenerator::GetNumBitsForBuilder() const { + return GetNumBitsForMessage(); +} + +// A note about how strings are handled. This code used to just store a String +// in the Message. This had two issues: +// +// 1. It wouldn't roundtrip byte arrays that were not valid UTF-8 encoded +// strings, but rather fields that were raw bytes incorrectly marked +// as strings in the proto file. This is common because in the proto1 +// syntax, string was the way to indicate bytes and C++ engineers can +// easily make this mistake without affecting the C++ API. By converting to +// strings immediately, some java code might corrupt these byte arrays as +// it passes through a java server even if the field was never accessed by +// application code. +// +// 2. There's a performance hit to converting between bytes and strings and +// it many cases, the field is never even read by the application code. This +// avoids unnecessary conversions in the common use cases. +// +// So now, the field for String is maintained as an Object reference which can +// either store a String or a ByteString. The code uses an instanceof check +// to see which one it has and converts to the other one if needed. It remembers +// the last value requested (in a thread safe manner) as this is most likely +// the one needed next. The thread safety is such that if two threads both +// convert the field because the changes made by each thread were not visible to +// the other, they may cause a conversion to happen more times than would +// otherwise be necessary. This was deemed better than adding synchronization +// overhead. It will not cause any corruption issues or affect the behavior of +// the API. The instanceof check is also highly optimized in the JVM and we +// decided it was better to reduce the memory overhead by not having two +// separate fields but rather use dynamic type checking. +// +// For single fields, the logic for this is done inside the generated code. For +// repeated fields, the logic is done in LazyStringArrayList and +// UnmodifiableLazyStringList. +void ImmutableStringFieldGenerator::GenerateInterfaceMembers( + io::Printer* printer) const { + if (HasHazzer(descriptor_)) { + WriteFieldAccessorDocComment(printer, descriptor_, HAZZER); + printer->Print(variables_, + "$deprecation$boolean has$capitalized_name$();\n"); + } + WriteFieldAccessorDocComment(printer, descriptor_, GETTER); + printer->Print(variables_, + "$deprecation$java.lang.String get$capitalized_name$();\n"); + WriteFieldStringBytesAccessorDocComment(printer, descriptor_, GETTER); + printer->Print(variables_, + "$deprecation$com.google.protobuf.ByteString\n" + " get$capitalized_name$Bytes();\n"); +} + +void ImmutableStringFieldGenerator::GenerateMembers( + io::Printer* printer) const { + printer->Print(variables_, "private volatile java.lang.Object $name$_;\n"); + PrintExtraFieldInfo(variables_, printer); + + if (HasHazzer(descriptor_)) { + WriteFieldAccessorDocComment(printer, descriptor_, HAZZER); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n" + " return $get_has_field_bit_message$;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + } + + WriteFieldAccessorDocComment(printer, descriptor_, GETTER); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$public java.lang.String ${$get$capitalized_name$$}$() {\n" + " java.lang.Object ref = $name$_;\n" + " if (ref instanceof java.lang.String) {\n" + " return (java.lang.String) ref;\n" + " } else {\n" + " com.google.protobuf.ByteString bs = \n" + " (com.google.protobuf.ByteString) ref;\n" + " java.lang.String s = bs.toStringUtf8();\n"); + printer->Annotate("{", "}", descriptor_); + if (CheckUtf8(descriptor_)) { + printer->Print(variables_, " $name$_ = s;\n"); + } else { + printer->Print(variables_, + " if (bs.isValidUtf8()) {\n" + " $name$_ = s;\n" + " }\n"); + } + printer->Print(variables_, + " return s;\n" + " }\n" + "}\n"); + WriteFieldStringBytesAccessorDocComment(printer, descriptor_, GETTER); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$public com.google.protobuf.ByteString\n" + " ${$get$capitalized_name$Bytes$}$() {\n" + " java.lang.Object ref = $name$_;\n" + " if (ref instanceof java.lang.String) {\n" + " com.google.protobuf.ByteString b = \n" + " com.google.protobuf.ByteString.copyFromUtf8(\n" + " (java.lang.String) ref);\n" + " $name$_ = b;\n" + " return b;\n" + " } else {\n" + " return (com.google.protobuf.ByteString) ref;\n" + " }\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); +} + +void ImmutableStringFieldGenerator::GenerateBuilderMembers( + io::Printer* printer) const { + printer->Print(variables_, + "private java.lang.Object $name$_ $default_init$;\n"); + if (HasHazzer(descriptor_)) { + WriteFieldAccessorDocComment(printer, descriptor_, HAZZER); + printer->Print( + variables_, + "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n" + " return $get_has_field_bit_builder$;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + } + + WriteFieldAccessorDocComment(printer, descriptor_, GETTER); + printer->Print( + variables_, + "$deprecation$public java.lang.String ${$get$capitalized_name$$}$() {\n" + " java.lang.Object ref = $name$_;\n" + " if (!(ref instanceof java.lang.String)) {\n" + " com.google.protobuf.ByteString bs =\n" + " (com.google.protobuf.ByteString) ref;\n" + " java.lang.String s = bs.toStringUtf8();\n"); + printer->Annotate("{", "}", descriptor_); + if (CheckUtf8(descriptor_)) { + printer->Print(variables_, " $name$_ = s;\n"); + } else { + printer->Print(variables_, + " if (bs.isValidUtf8()) {\n" + " $name$_ = s;\n" + " }\n"); + } + printer->Print(variables_, + " return s;\n" + " } else {\n" + " return (java.lang.String) ref;\n" + " }\n" + "}\n"); + + WriteFieldStringBytesAccessorDocComment(printer, descriptor_, GETTER); + printer->Print(variables_, + "$deprecation$public com.google.protobuf.ByteString\n" + " ${$get$capitalized_name$Bytes$}$() {\n" + " java.lang.Object ref = $name$_;\n" + " if (ref instanceof String) {\n" + " com.google.protobuf.ByteString b = \n" + " com.google.protobuf.ByteString.copyFromUtf8(\n" + " (java.lang.String) ref);\n" + " $name$_ = b;\n" + " return b;\n" + " } else {\n" + " return (com.google.protobuf.ByteString) ref;\n" + " }\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + WriteFieldAccessorDocComment(printer, descriptor_, SETTER, + /* builder */ true); + printer->Print(variables_, + "$deprecation$public Builder ${$set$capitalized_name$$}$(\n" + " java.lang.String value) {\n" + "$null_check$" + " $set_has_field_bit_builder$\n" + " $name$_ = value;\n" + " $on_changed$\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldAccessorDocComment(printer, descriptor_, CLEARER, + /* builder */ true); + printer->Print( + variables_, + "$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n" + " $clear_has_field_bit_builder$\n"); + printer->Annotate("{", "}", descriptor_); + // The default value is not a simple literal so we want to avoid executing + // it multiple times. Instead, get the default out of the default instance. + printer->Print(variables_, + " $name$_ = getDefaultInstance().get$capitalized_name$();\n"); + printer->Print(variables_, + " $on_changed$\n" + " return this;\n" + "}\n"); + + WriteFieldStringBytesAccessorDocComment(printer, descriptor_, SETTER, + /* builder */ true); + printer->Print( + variables_, + "$deprecation$public Builder ${$set$capitalized_name$Bytes$}$(\n" + " com.google.protobuf.ByteString value) {\n" + "$null_check$"); + printer->Annotate("{", "}", descriptor_); + if (CheckUtf8(descriptor_)) { + printer->Print(variables_, " checkByteStringIsUtf8(value);\n"); + } + printer->Print(variables_, + " $set_has_field_bit_builder$\n" + " $name$_ = value;\n" + " $on_changed$\n" + " return this;\n" + "}\n"); +} + +void ImmutableStringFieldGenerator::GenerateKotlinDslMembers( + io::Printer* printer) const { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$kt_deprecation$public var $kt_name$: kotlin.String\n" + " @JvmName(\"${$get$kt_capitalized_name$$}$\")\n" + " get() = $kt_dsl_builder$.${$get$capitalized_name$$}$()\n" + " @JvmName(\"${$set$kt_capitalized_name$$}$\")\n" + " set(value) {\n" + " $kt_dsl_builder$.${$set$capitalized_name$$}$(value)\n" + " }\n"); + + WriteFieldAccessorDocComment(printer, descriptor_, CLEARER, + /* builder */ false); + printer->Print(variables_, + "public fun ${$clear$kt_capitalized_name$$}$() {\n" + " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n" + "}\n"); + + if (HasHazzer(descriptor_)) { + WriteFieldAccessorDocComment(printer, descriptor_, HAZZER); + printer->Print( + variables_, + "public fun ${$has$kt_capitalized_name$$}$(): kotlin.Boolean {\n" + " return $kt_dsl_builder$.${$has$capitalized_name$$}$()\n" + "}\n"); + } +} + +void ImmutableStringFieldGenerator::GenerateFieldBuilderInitializationCode( + io::Printer* printer) const { + // noop for primitives +} + +void ImmutableStringFieldGenerator::GenerateInitializationCode( + io::Printer* printer) const { + printer->Print(variables_, "$name$_ = $default$;\n"); +} + +void ImmutableStringFieldGenerator::GenerateBuilderClearCode( + io::Printer* printer) const { + printer->Print(variables_, + "$name$_ = $default$;\n" + "$clear_has_field_bit_builder$\n"); +} + +void ImmutableStringFieldGenerator::GenerateMergingCode( + io::Printer* printer) const { + if (HasHazzer(descriptor_)) { + // Allow a slight breach of abstraction here in order to avoid forcing + // all string fields to Strings when copying fields from a Message. + printer->Print(variables_, + "if (other.has$capitalized_name$()) {\n" + " $set_has_field_bit_builder$\n" + " $name$_ = other.$name$_;\n" + " $on_changed$\n" + "}\n"); + } else { + printer->Print(variables_, + "if (!other.get$capitalized_name$().isEmpty()) {\n" + " $name$_ = other.$name$_;\n" + " $on_changed$\n" + "}\n"); + } +} + +void ImmutableStringFieldGenerator::GenerateBuildingCode( + io::Printer* printer) const { + if (HasHazzer(descriptor_)) { + printer->Print(variables_, + "if ($get_has_field_bit_from_local$) {\n" + " $set_has_field_bit_to_local$;\n" + "}\n"); + } + printer->Print(variables_, "result.$name$_ = $name$_;\n"); +} + +void ImmutableStringFieldGenerator::GenerateParsingCode( + io::Printer* printer) const { + if (CheckUtf8(descriptor_)) { + printer->Print(variables_, + "java.lang.String s = input.readStringRequireUtf8();\n" + "$set_has_field_bit_message$\n" + "$name$_ = s;\n"); + } else { + printer->Print(variables_, + "com.google.protobuf.ByteString bs = input.readBytes();\n" + "$set_has_field_bit_message$\n" + "$name$_ = bs;\n"); + } +} + +void ImmutableStringFieldGenerator::GenerateParsingDoneCode( + io::Printer* printer) const { + // noop for strings. +} + +void ImmutableStringFieldGenerator::GenerateSerializationCode( + io::Printer* printer) const { + printer->Print(variables_, + "if ($is_field_present_message$) {\n" + " $writeString$(output, $number$, $name$_);\n" + "}\n"); +} + +void ImmutableStringFieldGenerator::GenerateSerializedSizeCode( + io::Printer* printer) const { + printer->Print(variables_, + "if ($is_field_present_message$) {\n" + " size += $computeStringSize$($number$, $name$_);\n" + "}\n"); +} + +void ImmutableStringFieldGenerator::GenerateEqualsCode( + io::Printer* printer) const { + printer->Print(variables_, + "if (!get$capitalized_name$()\n" + " .equals(other.get$capitalized_name$())) return false;\n"); +} + +void ImmutableStringFieldGenerator::GenerateHashCode( + io::Printer* printer) const { + printer->Print(variables_, "hash = (37 * hash) + $constant_name$;\n"); + printer->Print(variables_, + "hash = (53 * hash) + get$capitalized_name$().hashCode();\n"); +} + +std::string ImmutableStringFieldGenerator::GetBoxedType() const { + return "java.lang.String"; +} + +// =================================================================== + +ImmutableStringOneofFieldGenerator::ImmutableStringOneofFieldGenerator( + const FieldDescriptor* descriptor, int messageBitIndex, int builderBitIndex, + Context* context) + : ImmutableStringFieldGenerator(descriptor, messageBitIndex, + builderBitIndex, context) { + const OneofGeneratorInfo* info = + context->GetOneofGeneratorInfo(descriptor->containing_oneof()); + SetCommonOneofVariables(descriptor, info, &variables_); +} + +ImmutableStringOneofFieldGenerator::~ImmutableStringOneofFieldGenerator() {} + +void ImmutableStringOneofFieldGenerator::GenerateMembers( + io::Printer* printer) const { + PrintExtraFieldInfo(variables_, printer); + GOOGLE_DCHECK(HasHazzer(descriptor_)); + WriteFieldAccessorDocComment(printer, descriptor_, HAZZER); + printer->Print(variables_, + "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n" + " return $has_oneof_case_message$;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + WriteFieldAccessorDocComment(printer, descriptor_, GETTER); + printer->Print( + variables_, + "$deprecation$public java.lang.String ${$get$capitalized_name$$}$() {\n" + " java.lang.Object ref $default_init$;\n" + " if ($has_oneof_case_message$) {\n" + " ref = $oneof_name$_;\n" + " }\n" + " if (ref instanceof java.lang.String) {\n" + " return (java.lang.String) ref;\n" + " } else {\n" + " com.google.protobuf.ByteString bs = \n" + " (com.google.protobuf.ByteString) ref;\n" + " java.lang.String s = bs.toStringUtf8();\n"); + printer->Annotate("{", "}", descriptor_); + if (CheckUtf8(descriptor_)) { + printer->Print(variables_, + " if ($has_oneof_case_message$) {\n" + " $oneof_name$_ = s;\n" + " }\n"); + } else { + printer->Print(variables_, + " if (bs.isValidUtf8() && ($has_oneof_case_message$)) {\n" + " $oneof_name$_ = s;\n" + " }\n"); + } + printer->Print(variables_, + " return s;\n" + " }\n" + "}\n"); + WriteFieldStringBytesAccessorDocComment(printer, descriptor_, GETTER); + + printer->Print(variables_, + "$deprecation$public com.google.protobuf.ByteString\n" + " ${$get$capitalized_name$Bytes$}$() {\n" + " java.lang.Object ref $default_init$;\n" + " if ($has_oneof_case_message$) {\n" + " ref = $oneof_name$_;\n" + " }\n" + " if (ref instanceof java.lang.String) {\n" + " com.google.protobuf.ByteString b = \n" + " com.google.protobuf.ByteString.copyFromUtf8(\n" + " (java.lang.String) ref);\n" + " if ($has_oneof_case_message$) {\n" + " $oneof_name$_ = b;\n" + " }\n" + " return b;\n" + " } else {\n" + " return (com.google.protobuf.ByteString) ref;\n" + " }\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); +} + +void ImmutableStringOneofFieldGenerator::GenerateBuilderMembers( + io::Printer* printer) const { + GOOGLE_DCHECK(HasHazzer(descriptor_)); + WriteFieldAccessorDocComment(printer, descriptor_, HAZZER); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n" + " return $has_oneof_case_message$;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + WriteFieldAccessorDocComment(printer, descriptor_, GETTER); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$public java.lang.String ${$get$capitalized_name$$}$() {\n" + " java.lang.Object ref $default_init$;\n" + " if ($has_oneof_case_message$) {\n" + " ref = $oneof_name$_;\n" + " }\n" + " if (!(ref instanceof java.lang.String)) {\n" + " com.google.protobuf.ByteString bs =\n" + " (com.google.protobuf.ByteString) ref;\n" + " java.lang.String s = bs.toStringUtf8();\n" + " if ($has_oneof_case_message$) {\n"); + printer->Annotate("{", "}", descriptor_); + if (CheckUtf8(descriptor_)) { + printer->Print(variables_, " $oneof_name$_ = s;\n"); + } else { + printer->Print(variables_, + " if (bs.isValidUtf8()) {\n" + " $oneof_name$_ = s;\n" + " }\n"); + } + printer->Print(variables_, + " }\n" + " return s;\n" + " } else {\n" + " return (java.lang.String) ref;\n" + " }\n" + "}\n"); + + WriteFieldStringBytesAccessorDocComment(printer, descriptor_, GETTER); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$public com.google.protobuf.ByteString\n" + " ${$get$capitalized_name$Bytes$}$() {\n" + " java.lang.Object ref $default_init$;\n" + " if ($has_oneof_case_message$) {\n" + " ref = $oneof_name$_;\n" + " }\n" + " if (ref instanceof String) {\n" + " com.google.protobuf.ByteString b = \n" + " com.google.protobuf.ByteString.copyFromUtf8(\n" + " (java.lang.String) ref);\n" + " if ($has_oneof_case_message$) {\n" + " $oneof_name$_ = b;\n" + " }\n" + " return b;\n" + " } else {\n" + " return (com.google.protobuf.ByteString) ref;\n" + " }\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + WriteFieldAccessorDocComment(printer, descriptor_, SETTER, + /* builder */ true); + printer->Print(variables_, + "$deprecation$public Builder ${$set$capitalized_name$$}$(\n" + " java.lang.String value) {\n" + "$null_check$" + " $set_oneof_case_message$;\n" + " $oneof_name$_ = value;\n" + " $on_changed$\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldAccessorDocComment(printer, descriptor_, CLEARER, + /* builder */ true); + printer->Print( + variables_, + "$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n" + " if ($has_oneof_case_message$) {\n" + " $clear_oneof_case_message$;\n" + " $oneof_name$_ = null;\n" + " $on_changed$\n" + " }\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + WriteFieldStringBytesAccessorDocComment(printer, descriptor_, SETTER, + /* builder */ true); + printer->Print( + variables_, + "$deprecation$public Builder ${$set$capitalized_name$Bytes$}$(\n" + " com.google.protobuf.ByteString value) {\n" + "$null_check$"); + printer->Annotate("{", "}", descriptor_); + if (CheckUtf8(descriptor_)) { + printer->Print(variables_, " checkByteStringIsUtf8(value);\n"); + } + printer->Print(variables_, + " $set_oneof_case_message$;\n" + " $oneof_name$_ = value;\n" + " $on_changed$\n" + " return this;\n" + "}\n"); +} + +void ImmutableStringOneofFieldGenerator::GenerateMergingCode( + io::Printer* printer) const { + // Allow a slight breach of abstraction here in order to avoid forcing + // all string fields to Strings when copying fields from a Message. + printer->Print(variables_, + "$set_oneof_case_message$;\n" + "$oneof_name$_ = other.$oneof_name$_;\n" + "$on_changed$\n"); +} + +void ImmutableStringOneofFieldGenerator::GenerateBuildingCode( + io::Printer* printer) const { + printer->Print(variables_, + "if ($has_oneof_case_message$) {\n" + " result.$oneof_name$_ = $oneof_name$_;\n" + "}\n"); +} + +void ImmutableStringOneofFieldGenerator::GenerateParsingCode( + io::Printer* printer) const { + if (CheckUtf8(descriptor_)) { + printer->Print(variables_, + "java.lang.String s = input.readStringRequireUtf8();\n" + "$set_oneof_case_message$;\n" + "$oneof_name$_ = s;\n"); + } else { + printer->Print(variables_, + "com.google.protobuf.ByteString bs = input.readBytes();\n" + "$set_oneof_case_message$;\n" + "$oneof_name$_ = bs;\n"); + } +} + +void ImmutableStringOneofFieldGenerator::GenerateSerializationCode( + io::Printer* printer) const { + printer->Print(variables_, + "if ($has_oneof_case_message$) {\n" + " $writeString$(output, $number$, $oneof_name$_);\n" + "}\n"); +} + +void ImmutableStringOneofFieldGenerator::GenerateSerializedSizeCode( + io::Printer* printer) const { + printer->Print(variables_, + "if ($has_oneof_case_message$) {\n" + " size += $computeStringSize$($number$, $oneof_name$_);\n" + "}\n"); +} + +// =================================================================== + +RepeatedImmutableStringFieldGenerator::RepeatedImmutableStringFieldGenerator( + const FieldDescriptor* descriptor, int messageBitIndex, int builderBitIndex, + Context* context) + : descriptor_(descriptor), name_resolver_(context->GetNameResolver()) { + SetPrimitiveVariables(descriptor, messageBitIndex, builderBitIndex, + context->GetFieldGeneratorInfo(descriptor), + name_resolver_, &variables_); +} + +RepeatedImmutableStringFieldGenerator:: + ~RepeatedImmutableStringFieldGenerator() {} + +int RepeatedImmutableStringFieldGenerator::GetNumBitsForMessage() const { + return 0; +} + +int RepeatedImmutableStringFieldGenerator::GetNumBitsForBuilder() const { + return 1; +} + +void RepeatedImmutableStringFieldGenerator::GenerateInterfaceMembers( + io::Printer* printer) const { + WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER); + printer->Print( + variables_, + // NOTE: the same method in the implementation class actually returns + // com.google.protobuf.ProtocolStringList (a subclass of List). It's + // changed between protobuf 2.5.0 release and protobuf 2.6.1 release. + // To retain binary compatibility with both 2.5.0 and 2.6.1 generated + // code, we make this interface method return List so both methods + // with different return types exist in the compiled byte code. + "$deprecation$java.util.List<java.lang.String>\n" + " get$capitalized_name$List();\n"); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_COUNT); + printer->Print(variables_, + "$deprecation$int get$capitalized_name$Count();\n"); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_GETTER); + printer->Print( + variables_, + "$deprecation$java.lang.String get$capitalized_name$(int index);\n"); + WriteFieldStringBytesAccessorDocComment(printer, descriptor_, + LIST_INDEXED_GETTER); + printer->Print(variables_, + "$deprecation$com.google.protobuf.ByteString\n" + " get$capitalized_name$Bytes(int index);\n"); +} + +void RepeatedImmutableStringFieldGenerator::GenerateMembers( + io::Printer* printer) const { + printer->Print(variables_, + "private com.google.protobuf.LazyStringList $name$_;\n"); + PrintExtraFieldInfo(variables_, printer); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER); + printer->Print(variables_, + "$deprecation$public com.google.protobuf.ProtocolStringList\n" + " ${$get$capitalized_name$List$}$() {\n" + " return $name$_;\n" // note: unmodifiable list + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_COUNT); + printer->Print( + variables_, + "$deprecation$public int ${$get$capitalized_name$Count$}$() {\n" + " return $name$_.size();\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_GETTER); + printer->Print(variables_, + "$deprecation$public java.lang.String " + "${$get$capitalized_name$$}$(int index) {\n" + " return $name$_.get(index);\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldStringBytesAccessorDocComment(printer, descriptor_, + LIST_INDEXED_GETTER); + printer->Print(variables_, + "$deprecation$public com.google.protobuf.ByteString\n" + " ${$get$capitalized_name$Bytes$}$(int index) {\n" + " return $name$_.getByteString(index);\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); +} + +void RepeatedImmutableStringFieldGenerator::GenerateBuilderMembers( + io::Printer* printer) const { + // One field is the list and the bit field keeps track of whether the + // list is immutable. If it's immutable, the invariant is that it must + // either an instance of Collections.emptyList() or it's an ArrayList + // wrapped in a Collections.unmodifiableList() wrapper and nobody else has + // a reference to the underlying ArrayList. This invariant allows us to + // share instances of lists between protocol buffers avoiding expensive + // memory allocations. Note, immutable is a strong guarantee here -- not + // just that the list cannot be modified via the reference but that the + // list can never be modified. + printer->Print( + variables_, + "private com.google.protobuf.LazyStringList $name$_ = $empty_list$;\n"); + + printer->Print( + variables_, + "private void ensure$capitalized_name$IsMutable() {\n" + " if (!$get_mutable_bit_builder$) {\n" + " $name$_ = new com.google.protobuf.LazyStringArrayList($name$_);\n" + " $set_mutable_bit_builder$;\n" + " }\n" + "}\n"); + + // Note: We return an unmodifiable list because otherwise the caller + // could hold on to the returned list and modify it after the message + // has been built, thus mutating the message which is supposed to be + // immutable. + WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER); + printer->Print(variables_, + "$deprecation$public com.google.protobuf.ProtocolStringList\n" + " ${$get$capitalized_name$List$}$() {\n" + " return $name$_.getUnmodifiableView();\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_COUNT); + printer->Print( + variables_, + "$deprecation$public int ${$get$capitalized_name$Count$}$() {\n" + " return $name$_.size();\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_GETTER); + printer->Print(variables_, + "$deprecation$public java.lang.String " + "${$get$capitalized_name$$}$(int index) {\n" + " return $name$_.get(index);\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldStringBytesAccessorDocComment(printer, descriptor_, + LIST_INDEXED_GETTER); + printer->Print(variables_, + "$deprecation$public com.google.protobuf.ByteString\n" + " ${$get$capitalized_name$Bytes$}$(int index) {\n" + " return $name$_.getByteString(index);\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_SETTER, + /* builder */ true); + printer->Print(variables_, + "$deprecation$public Builder ${$set$capitalized_name$$}$(\n" + " int index, java.lang.String value) {\n" + "$null_check$" + " ensure$capitalized_name$IsMutable();\n" + " $name$_.set(index, value);\n" + " $on_changed$\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER, + /* builder */ true); + printer->Print(variables_, + "$deprecation$public Builder ${$add$capitalized_name$$}$(\n" + " java.lang.String value) {\n" + "$null_check$" + " ensure$capitalized_name$IsMutable();\n" + " $name$_.add(value);\n" + " $on_changed$\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER, + /* builder */ true); + printer->Print(variables_, + "$deprecation$public Builder ${$addAll$capitalized_name$$}$(\n" + " java.lang.Iterable<java.lang.String> values) {\n" + " ensure$capitalized_name$IsMutable();\n" + " com.google.protobuf.AbstractMessageLite.Builder.addAll(\n" + " values, $name$_);\n" + " $on_changed$\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldAccessorDocComment(printer, descriptor_, CLEARER, + /* builder */ true); + printer->Print( + variables_, + "$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n" + " $name$_ = $empty_list$;\n" + " $clear_mutable_bit_builder$;\n" + " $on_changed$\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + WriteFieldStringBytesAccessorDocComment(printer, descriptor_, LIST_ADDER, + /* builder */ true); + printer->Print( + variables_, + "$deprecation$public Builder ${$add$capitalized_name$Bytes$}$(\n" + " com.google.protobuf.ByteString value) {\n" + "$null_check$"); + printer->Annotate("{", "}", descriptor_); + if (CheckUtf8(descriptor_)) { + printer->Print(variables_, " checkByteStringIsUtf8(value);\n"); + } + printer->Print(variables_, + " ensure$capitalized_name$IsMutable();\n" + " $name$_.add(value);\n" + " $on_changed$\n" + " return this;\n" + "}\n"); +} + +void RepeatedImmutableStringFieldGenerator::GenerateKotlinDslMembers( + io::Printer* printer) const { + printer->Print( + variables_, + "/**\n" + " * An uninstantiable, behaviorless type to represent the field in\n" + " * generics.\n" + " */\n" + "@kotlin.OptIn" + "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n" + "public class ${$$kt_capitalized_name$Proxy$}$ private constructor()" + " : com.google.protobuf.kotlin.DslProxy()\n"); + + // property for List<String> + WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER); + printer->Print(variables_, + "$kt_deprecation$public val $kt_name$: " + "com.google.protobuf.kotlin.DslList" + "<kotlin.String, ${$$kt_capitalized_name$Proxy$}$>\n" + " @kotlin.jvm.JvmSynthetic\n" + " get() = com.google.protobuf.kotlin.DslList(\n" + " $kt_dsl_builder$.${$get$capitalized_name$List$}$()\n" + " )\n"); + + // List<String>.add(String) + WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER, + /* builder */ false); + printer->Print(variables_, + "@kotlin.jvm.JvmSynthetic\n" + "@kotlin.jvm.JvmName(\"add$kt_capitalized_name$\")\n" + "public fun com.google.protobuf.kotlin.DslList" + "<kotlin.String, ${$$kt_capitalized_name$Proxy$}$>." + "add(value: kotlin.String) {\n" + " $kt_dsl_builder$.${$add$capitalized_name$$}$(value)\n" + "}\n"); + + // List<String> += String + WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER, + /* builder */ false); + printer->Print(variables_, + "@kotlin.jvm.JvmSynthetic\n" + "@kotlin.jvm.JvmName(\"plusAssign$kt_capitalized_name$\")\n" + "@Suppress(\"NOTHING_TO_INLINE\")\n" + "public inline operator fun com.google.protobuf.kotlin.DslList" + "<kotlin.String, ${$$kt_capitalized_name$Proxy$}$>." + "plusAssign(value: kotlin.String) {\n" + " add(value)\n" + "}\n"); + + // List<String>.addAll(Iterable<String>) + WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER, + /* builder */ false); + printer->Print( + variables_, + "@kotlin.jvm.JvmSynthetic\n" + "@kotlin.jvm.JvmName(\"addAll$kt_capitalized_name$\")\n" + "public fun com.google.protobuf.kotlin.DslList" + "<kotlin.String, ${$$kt_capitalized_name$Proxy$}$>." + "addAll(values: kotlin.collections.Iterable<kotlin.String>) {\n" + " $kt_dsl_builder$.${$addAll$capitalized_name$$}$(values)\n" + "}\n"); + + // List<String> += Iterable<String> + WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER, + /* builder */ false); + printer->Print( + variables_, + "@kotlin.jvm.JvmSynthetic\n" + "@kotlin.jvm.JvmName(\"plusAssignAll$kt_capitalized_name$\")\n" + "@Suppress(\"NOTHING_TO_INLINE\")\n" + "public inline operator fun com.google.protobuf.kotlin.DslList" + "<kotlin.String, ${$$kt_capitalized_name$Proxy$}$>." + "plusAssign(values: kotlin.collections.Iterable<kotlin.String>) {\n" + " addAll(values)\n" + "}\n"); + + // List<String>[Int] = String + WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_SETTER, + /* builder */ false); + printer->Print( + variables_, + "@kotlin.jvm.JvmSynthetic\n" + "@kotlin.jvm.JvmName(\"set$kt_capitalized_name$\")\n" + "public operator fun com.google.protobuf.kotlin.DslList" + "<kotlin.String, ${$$kt_capitalized_name$Proxy$}$>." + "set(index: kotlin.Int, value: kotlin.String) {\n" + " $kt_dsl_builder$.${$set$capitalized_name$$}$(index, value)\n" + "}"); + + WriteFieldAccessorDocComment(printer, descriptor_, CLEARER, + /* builder */ false); + printer->Print(variables_, + "@kotlin.jvm.JvmSynthetic\n" + "@kotlin.jvm.JvmName(\"clear$kt_capitalized_name$\")\n" + "public fun com.google.protobuf.kotlin.DslList" + "<kotlin.String, ${$$kt_capitalized_name$Proxy$}$>." + "clear() {\n" + " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n" + "}"); +} + +void RepeatedImmutableStringFieldGenerator:: + GenerateFieldBuilderInitializationCode(io::Printer* printer) const { + // noop for primitives +} + +void RepeatedImmutableStringFieldGenerator::GenerateInitializationCode( + io::Printer* printer) const { + printer->Print(variables_, "$name$_ = $empty_list$;\n"); +} + +void RepeatedImmutableStringFieldGenerator::GenerateBuilderClearCode( + io::Printer* printer) const { + printer->Print(variables_, + "$name$_ = $empty_list$;\n" + "$clear_mutable_bit_builder$;\n"); +} + +void RepeatedImmutableStringFieldGenerator::GenerateMergingCode( + io::Printer* printer) const { + // The code below does two optimizations: + // 1. If the other list is empty, there's nothing to do. This ensures we + // don't allocate a new array if we already have an immutable one. + // 2. If the other list is non-empty and our current list is empty, we can + // reuse the other list which is guaranteed to be immutable. + printer->Print(variables_, + "if (!other.$name$_.isEmpty()) {\n" + " if ($name$_.isEmpty()) {\n" + " $name$_ = other.$name$_;\n" + " $clear_mutable_bit_builder$;\n" + " } else {\n" + " ensure$capitalized_name$IsMutable();\n" + " $name$_.addAll(other.$name$_);\n" + " }\n" + " $on_changed$\n" + "}\n"); +} + +void RepeatedImmutableStringFieldGenerator::GenerateBuildingCode( + io::Printer* printer) const { + // The code below ensures that the result has an immutable list. If our + // list is immutable, we can just reuse it. If not, we make it immutable. + + printer->Print(variables_, + "if ($get_mutable_bit_builder$) {\n" + " $name$_ = $name$_.getUnmodifiableView();\n" + " $clear_mutable_bit_builder$;\n" + "}\n" + "result.$name$_ = $name$_;\n"); +} + +void RepeatedImmutableStringFieldGenerator::GenerateParsingCode( + io::Printer* printer) const { + if (CheckUtf8(descriptor_)) { + printer->Print(variables_, + "java.lang.String s = input.readStringRequireUtf8();\n"); + } else { + printer->Print(variables_, + "com.google.protobuf.ByteString bs = input.readBytes();\n"); + } + printer->Print(variables_, + "if (!$get_mutable_bit_parser$) {\n" + " $name$_ = new com.google.protobuf.LazyStringArrayList();\n" + " $set_mutable_bit_parser$;\n" + "}\n"); + if (CheckUtf8(descriptor_)) { + printer->Print(variables_, "$name$_.add(s);\n"); + } else { + printer->Print(variables_, "$name$_.add(bs);\n"); + } +} + +void RepeatedImmutableStringFieldGenerator::GenerateParsingDoneCode( + io::Printer* printer) const { + printer->Print(variables_, + "if ($get_mutable_bit_parser$) {\n" + " $name$_ = $name$_.getUnmodifiableView();\n" + "}\n"); +} + +void RepeatedImmutableStringFieldGenerator::GenerateSerializationCode( + io::Printer* printer) const { + printer->Print(variables_, + "for (int i = 0; i < $name$_.size(); i++) {\n" + " $writeString$(output, $number$, $name$_.getRaw(i));\n" + "}\n"); +} + +void RepeatedImmutableStringFieldGenerator::GenerateSerializedSizeCode( + io::Printer* printer) const { + printer->Print(variables_, + "{\n" + " int dataSize = 0;\n"); + printer->Indent(); + + printer->Print(variables_, + "for (int i = 0; i < $name$_.size(); i++) {\n" + " dataSize += computeStringSizeNoTag($name$_.getRaw(i));\n" + "}\n"); + + printer->Print("size += dataSize;\n"); + + printer->Print(variables_, + "size += $tag_size$ * get$capitalized_name$List().size();\n"); + + printer->Outdent(); + printer->Print("}\n"); +} + +void RepeatedImmutableStringFieldGenerator::GenerateEqualsCode( + io::Printer* printer) const { + printer->Print( + variables_, + "if (!get$capitalized_name$List()\n" + " .equals(other.get$capitalized_name$List())) return false;\n"); +} + +void RepeatedImmutableStringFieldGenerator::GenerateHashCode( + io::Printer* printer) const { + printer->Print( + variables_, + "if (get$capitalized_name$Count() > 0) {\n" + " hash = (37 * hash) + $constant_name$;\n" + " hash = (53 * hash) + get$capitalized_name$List().hashCode();\n" + "}\n"); +} + +std::string RepeatedImmutableStringFieldGenerator::GetBoxedType() const { + return "String"; +} + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/java/java_string_field.h b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_string_field.h new file mode 100644 index 00000000..03fd43ec --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_string_field.h @@ -0,0 +1,160 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Author: jonp@google.com (Jon Perlow) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_STRING_FIELD_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVA_STRING_FIELD_H__ + +#include <map> +#include <string> +#include <compiler/java/java_field.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { +class Context; // context.h +class ClassNameResolver; // name_resolver.h +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +class ImmutableStringFieldGenerator : public ImmutableFieldGenerator { + public: + explicit ImmutableStringFieldGenerator(const FieldDescriptor* descriptor, + int messageBitIndex, + int builderBitIndex, Context* context); + ~ImmutableStringFieldGenerator(); + + // implements ImmutableFieldGenerator + // --------------------------------------- + int GetNumBitsForMessage() const override; + int GetNumBitsForBuilder() const override; + void GenerateInterfaceMembers(io::Printer* printer) const override; + void GenerateMembers(io::Printer* printer) const override; + void GenerateBuilderMembers(io::Printer* printer) const override; + void GenerateInitializationCode(io::Printer* printer) const override; + void GenerateBuilderClearCode(io::Printer* printer) const override; + void GenerateMergingCode(io::Printer* printer) const override; + void GenerateBuildingCode(io::Printer* printer) const override; + void GenerateParsingCode(io::Printer* printer) const override; + void GenerateParsingDoneCode(io::Printer* printer) const override; + void GenerateSerializationCode(io::Printer* printer) const override; + void GenerateSerializedSizeCode(io::Printer* printer) const override; + void GenerateFieldBuilderInitializationCode( + io::Printer* printer) const override; + void GenerateEqualsCode(io::Printer* printer) const override; + void GenerateHashCode(io::Printer* printer) const override; + void GenerateKotlinDslMembers(io::Printer* printer) const override; + + std::string GetBoxedType() const override; + + protected: + const FieldDescriptor* descriptor_; + std::map<std::string, std::string> variables_; + ClassNameResolver* name_resolver_; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableStringFieldGenerator); +}; + +class ImmutableStringOneofFieldGenerator + : public ImmutableStringFieldGenerator { + public: + ImmutableStringOneofFieldGenerator(const FieldDescriptor* descriptor, + int messageBitIndex, int builderBitIndex, + Context* context); + ~ImmutableStringOneofFieldGenerator(); + + private: + void GenerateMembers(io::Printer* printer) const override; + void GenerateBuilderMembers(io::Printer* printer) const override; + void GenerateMergingCode(io::Printer* printer) const override; + void GenerateBuildingCode(io::Printer* printer) const override; + void GenerateParsingCode(io::Printer* printer) const override; + void GenerateSerializationCode(io::Printer* printer) const override; + void GenerateSerializedSizeCode(io::Printer* printer) const override; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableStringOneofFieldGenerator); +}; + +class RepeatedImmutableStringFieldGenerator : public ImmutableFieldGenerator { + public: + explicit RepeatedImmutableStringFieldGenerator( + const FieldDescriptor* descriptor, int messageBitIndex, + int builderBitIndex, Context* context); + ~RepeatedImmutableStringFieldGenerator() override; + + // implements ImmutableFieldGenerator --------------------------------------- + int GetNumBitsForMessage() const override; + int GetNumBitsForBuilder() const override; + void GenerateInterfaceMembers(io::Printer* printer) const override; + void GenerateMembers(io::Printer* printer) const override; + void GenerateBuilderMembers(io::Printer* printer) const override; + void GenerateInitializationCode(io::Printer* printer) const override; + void GenerateBuilderClearCode(io::Printer* printer) const override; + void GenerateMergingCode(io::Printer* printer) const override; + void GenerateBuildingCode(io::Printer* printer) const override; + void GenerateParsingCode(io::Printer* printer) const override; + void GenerateParsingDoneCode(io::Printer* printer) const override; + void GenerateSerializationCode(io::Printer* printer) const override; + void GenerateSerializedSizeCode(io::Printer* printer) const override; + void GenerateFieldBuilderInitializationCode( + io::Printer* printer) const override; + void GenerateEqualsCode(io::Printer* printer) const override; + void GenerateHashCode(io::Printer* printer) const override; + void GenerateKotlinDslMembers(io::Printer* printer) const override; + + std::string GetBoxedType() const override; + + private: + const FieldDescriptor* descriptor_; + std::map<std::string, std::string> variables_; + ClassNameResolver* name_resolver_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedImmutableStringFieldGenerator); +}; + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_STRING_FIELD_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/java/java_string_field_lite.cc b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_string_field_lite.cc new file mode 100644 index 00000000..6f52fd8f --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_string_field_lite.cc @@ -0,0 +1,864 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Author: jonp@google.com (Jon Perlow) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <compiler/java/java_string_field_lite.h> + +#include <cstdint> +#include <map> +#include <string> + +#include <stubs/logging.h> +#include <stubs/common.h> +#include <compiler/java/java_context.h> +#include <compiler/java/java_doc_comment.h> +#include <compiler/java/java_helpers.h> +#include <compiler/java/java_name_resolver.h> +#include <io/printer.h> +#include <wire_format.h> +#include <stubs/strutil.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +using internal::WireFormat; +using internal::WireFormatLite; + +namespace { + +void SetPrimitiveVariables(const FieldDescriptor* descriptor, + int messageBitIndex, int builderBitIndex, + const FieldGeneratorInfo* info, + ClassNameResolver* name_resolver, + std::map<std::string, std::string>* variables) { + SetCommonFieldVariables(descriptor, info, variables); + + (*variables)["empty_list"] = + "com.google.protobuf.GeneratedMessageLite.emptyProtobufList()"; + + (*variables)["default"] = ImmutableDefaultValue(descriptor, name_resolver); + (*variables)["default_init"] = + "= " + ImmutableDefaultValue(descriptor, name_resolver); + (*variables)["capitalized_type"] = "java.lang.String"; + (*variables)["tag"] = + StrCat(static_cast<int32_t>(WireFormat::MakeTag(descriptor))); + (*variables)["tag_size"] = StrCat( + WireFormat::TagSize(descriptor->number(), GetType(descriptor))); + // We use `x.getClass()` as a null check because it generates less bytecode + // than an `if (x == null) { throw ... }` statement. + (*variables)["null_check"] = + " java.lang.Class<?> valueClass = value.getClass();\n"; + + // TODO(birdo): Add @deprecated javadoc when generating javadoc is supported + // by the proto compiler + (*variables)["deprecation"] = + descriptor->options().deprecated() ? "@java.lang.Deprecated " : ""; + (*variables)["kt_deprecation"] = + descriptor->options().deprecated() + ? "@kotlin.Deprecated(message = \"Field " + (*variables)["name"] + + " is deprecated\") " + : ""; + (*variables)["required"] = descriptor->is_required() ? "true" : "false"; + + if (HasHasbit(descriptor)) { + // For singular messages and builders, one bit is used for the hasField bit. + (*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex); + + // Note that these have a trailing ";". + (*variables)["set_has_field_bit_message"] = + GenerateSetBit(messageBitIndex) + ";"; + (*variables)["clear_has_field_bit_message"] = + GenerateClearBit(messageBitIndex) + ";"; + + (*variables)["is_field_present_message"] = GenerateGetBit(messageBitIndex); + } else { + (*variables)["set_has_field_bit_message"] = ""; + (*variables)["clear_has_field_bit_message"] = ""; + + (*variables)["is_field_present_message"] = + "!" + (*variables)["name"] + "_.isEmpty()"; + } + + (*variables)["get_has_field_bit_from_local"] = + GenerateGetBitFromLocal(builderBitIndex); + (*variables)["set_has_field_bit_to_local"] = + GenerateSetBitToLocal(messageBitIndex); +} + +} // namespace + +// =================================================================== + +ImmutableStringFieldLiteGenerator::ImmutableStringFieldLiteGenerator( + const FieldDescriptor* descriptor, int messageBitIndex, Context* context) + : descriptor_(descriptor), + messageBitIndex_(messageBitIndex), + name_resolver_(context->GetNameResolver()) { + SetPrimitiveVariables(descriptor, messageBitIndex, 0, + context->GetFieldGeneratorInfo(descriptor), + name_resolver_, &variables_); +} + +ImmutableStringFieldLiteGenerator::~ImmutableStringFieldLiteGenerator() {} + +int ImmutableStringFieldLiteGenerator::GetNumBitsForMessage() const { + return HasHasbit(descriptor_) ? 1 : 0; +} + +// A note about how strings are handled. In the SPEED and CODE_SIZE runtimes, +// strings are not stored as java.lang.String in the Message because of two +// issues: +// +// 1. It wouldn't roundtrip byte arrays that were not valid UTF-8 encoded +// strings, but rather fields that were raw bytes incorrectly marked +// as strings in the proto file. This is common because in the proto1 +// syntax, string was the way to indicate bytes and C++ engineers can +// easily make this mistake without affecting the C++ API. By converting to +// strings immediately, some java code might corrupt these byte arrays as +// it passes through a java server even if the field was never accessed by +// application code. +// +// 2. There's a performance hit to converting between bytes and strings and +// it many cases, the field is never even read by the application code. This +// avoids unnecessary conversions in the common use cases. +// +// In the LITE_RUNTIME, we store strings as java.lang.String because we assume +// that the users of this runtime are not subject to proto1 constraints and are +// running code on devices that are user facing. That is, the developers are +// properly incentivized to only fetch the data they need to read and wish to +// reduce the number of allocations incurred when running on a user's device. + +// TODO(dweis): Consider dropping all of the *Bytes() methods. They really +// shouldn't be necessary or used on devices. +void ImmutableStringFieldLiteGenerator::GenerateInterfaceMembers( + io::Printer* printer) const { + if (HasHazzer(descriptor_)) { + WriteFieldAccessorDocComment(printer, descriptor_, HAZZER); + printer->Print(variables_, + "$deprecation$boolean has$capitalized_name$();\n"); + } + WriteFieldAccessorDocComment(printer, descriptor_, GETTER); + printer->Print(variables_, + "$deprecation$java.lang.String get$capitalized_name$();\n"); + WriteFieldStringBytesAccessorDocComment(printer, descriptor_, GETTER); + printer->Print(variables_, + "$deprecation$com.google.protobuf.ByteString\n" + " get$capitalized_name$Bytes();\n"); +} + +void ImmutableStringFieldLiteGenerator::GenerateMembers( + io::Printer* printer) const { + printer->Print(variables_, "private java.lang.String $name$_;\n"); + PrintExtraFieldInfo(variables_, printer); + + if (HasHazzer(descriptor_)) { + WriteFieldAccessorDocComment(printer, descriptor_, HAZZER); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n" + " return $get_has_field_bit_message$;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + } + + WriteFieldAccessorDocComment(printer, descriptor_, GETTER); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$public java.lang.String ${$get$capitalized_name$$}$() {\n" + " return $name$_;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldStringBytesAccessorDocComment(printer, descriptor_, GETTER); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$public com.google.protobuf.ByteString\n" + " ${$get$capitalized_name$Bytes$}$() {\n" + " return com.google.protobuf.ByteString.copyFromUtf8($name$_);\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + WriteFieldAccessorDocComment(printer, descriptor_, SETTER); + printer->Print(variables_, + "private void set$capitalized_name$(\n" + " java.lang.String value) {\n" + "$null_check$" + " $set_has_field_bit_message$\n" + " $name$_ = value;\n" + "}\n"); + WriteFieldAccessorDocComment(printer, descriptor_, CLEARER); + printer->Print(variables_, + "private void clear$capitalized_name$() {\n" + " $clear_has_field_bit_message$\n" + // The default value is not a simple literal so we want to + // avoid executing it multiple times. Instead, get the default + // out of the default instance. + " $name$_ = getDefaultInstance().get$capitalized_name$();\n" + "}\n"); + + WriteFieldStringBytesAccessorDocComment(printer, descriptor_, SETTER); + printer->Print(variables_, + "private void set$capitalized_name$Bytes(\n" + " com.google.protobuf.ByteString value) {\n"); + if (CheckUtf8(descriptor_)) { + printer->Print(variables_, " checkByteStringIsUtf8(value);\n"); + } + printer->Print(variables_, + " $name$_ = value.toStringUtf8();\n" + " $set_has_field_bit_message$\n" + "}\n"); +} + +void ImmutableStringFieldLiteGenerator::GenerateBuilderMembers( + io::Printer* printer) const { + if (HasHazzer(descriptor_)) { + WriteFieldAccessorDocComment(printer, descriptor_, HAZZER); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n" + " return instance.has$capitalized_name$();\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + } + + WriteFieldAccessorDocComment(printer, descriptor_, GETTER); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$public java.lang.String ${$get$capitalized_name$$}$() {\n" + " return instance.get$capitalized_name$();\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + WriteFieldStringBytesAccessorDocComment(printer, descriptor_, GETTER); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$public com.google.protobuf.ByteString\n" + " ${$get$capitalized_name$Bytes$}$() {\n" + " return instance.get$capitalized_name$Bytes();\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + WriteFieldAccessorDocComment(printer, descriptor_, SETTER, + /* builder */ true); + printer->Print(variables_, + "$deprecation$public Builder ${$set$capitalized_name$$}$(\n" + " java.lang.String value) {\n" + " copyOnWrite();\n" + " instance.set$capitalized_name$(value);\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldAccessorDocComment(printer, descriptor_, CLEARER, + /* builder */ true); + printer->Print( + variables_, + "$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n" + " copyOnWrite();\n" + " instance.clear$capitalized_name$();\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + WriteFieldStringBytesAccessorDocComment(printer, descriptor_, SETTER, + /* builder */ true); + printer->Print( + variables_, + "$deprecation$public Builder ${$set$capitalized_name$Bytes$}$(\n" + " com.google.protobuf.ByteString value) {\n" + " copyOnWrite();\n" + " instance.set$capitalized_name$Bytes(value);\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); +} + +void ImmutableStringFieldLiteGenerator::GenerateKotlinDslMembers( + io::Printer* printer) const { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$kt_deprecation$public var $kt_name$: kotlin.String\n" + " @JvmName(\"${$get$kt_capitalized_name$$}$\")\n" + " get() = $kt_dsl_builder$.${$get$capitalized_name$$}$()\n" + " @JvmName(\"${$set$kt_capitalized_name$$}$\")\n" + " set(value) {\n" + " $kt_dsl_builder$.${$set$capitalized_name$$}$(value)\n" + " }\n"); + + WriteFieldAccessorDocComment(printer, descriptor_, CLEARER, + /* builder */ false); + printer->Print(variables_, + "public fun ${$clear$kt_capitalized_name$$}$() {\n" + " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n" + "}\n"); + + if (HasHazzer(descriptor_)) { + WriteFieldAccessorDocComment(printer, descriptor_, HAZZER); + printer->Print( + variables_, + "public fun ${$has$kt_capitalized_name$$}$(): kotlin.Boolean {\n" + " return $kt_dsl_builder$.${$has$capitalized_name$$}$()\n" + "}\n"); + } +} + +void ImmutableStringFieldLiteGenerator::GenerateFieldInfo( + io::Printer* printer, std::vector<uint16_t>* output) const { + WriteIntToUtf16CharSequence(descriptor_->number(), output); + WriteIntToUtf16CharSequence(GetExperimentalJavaFieldType(descriptor_), + output); + if (HasHasbit(descriptor_)) { + WriteIntToUtf16CharSequence(messageBitIndex_, output); + } + printer->Print(variables_, "\"$name$_\",\n"); +} + +void ImmutableStringFieldLiteGenerator::GenerateInitializationCode( + io::Printer* printer) const { + printer->Print(variables_, "$name$_ = $default$;\n"); +} + +std::string ImmutableStringFieldLiteGenerator::GetBoxedType() const { + return "java.lang.String"; +} + +// =================================================================== + +ImmutableStringOneofFieldLiteGenerator::ImmutableStringOneofFieldLiteGenerator( + const FieldDescriptor* descriptor, int messageBitIndex, Context* context) + : ImmutableStringFieldLiteGenerator(descriptor, messageBitIndex, context) { + const OneofGeneratorInfo* info = + context->GetOneofGeneratorInfo(descriptor->containing_oneof()); + SetCommonOneofVariables(descriptor, info, &variables_); +} + +ImmutableStringOneofFieldLiteGenerator:: + ~ImmutableStringOneofFieldLiteGenerator() {} + +void ImmutableStringOneofFieldLiteGenerator::GenerateMembers( + io::Printer* printer) const { + PrintExtraFieldInfo(variables_, printer); + GOOGLE_DCHECK(HasHazzer(descriptor_)); + WriteFieldAccessorDocComment(printer, descriptor_, HAZZER); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n" + " return $has_oneof_case_message$;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + WriteFieldAccessorDocComment(printer, descriptor_, GETTER); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$public java.lang.String ${$get$capitalized_name$$}$() {\n" + " java.lang.String ref $default_init$;\n" + " if ($has_oneof_case_message$) {\n" + " ref = (java.lang.String) $oneof_name$_;\n" + " }\n" + " return ref;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + WriteFieldStringBytesAccessorDocComment(printer, descriptor_, GETTER); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$public com.google.protobuf.ByteString\n" + " ${$get$capitalized_name$Bytes$}$() {\n" + " java.lang.String ref $default_init$;\n" + " if ($has_oneof_case_message$) {\n" + " ref = (java.lang.String) $oneof_name$_;\n" + " }\n" + " return com.google.protobuf.ByteString.copyFromUtf8(ref);\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + WriteFieldAccessorDocComment(printer, descriptor_, SETTER); + printer->Print(variables_, + "private void ${$set$capitalized_name$$}$(\n" + " java.lang.String value) {\n" + "$null_check$" + " $set_oneof_case_message$;\n" + " $oneof_name$_ = value;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldAccessorDocComment(printer, descriptor_, CLEARER); + printer->Print(variables_, + "private void ${$clear$capitalized_name$$}$() {\n" + " if ($has_oneof_case_message$) {\n" + " $clear_oneof_case_message$;\n" + " $oneof_name$_ = null;\n" + " }\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + WriteFieldStringBytesAccessorDocComment(printer, descriptor_, SETTER); + printer->Print(variables_, + "private void ${$set$capitalized_name$Bytes$}$(\n" + " com.google.protobuf.ByteString value) {\n"); + printer->Annotate("{", "}", descriptor_); + if (CheckUtf8(descriptor_)) { + printer->Print(variables_, " checkByteStringIsUtf8(value);\n"); + } + printer->Print(variables_, + " $oneof_name$_ = value.toStringUtf8();\n" + " $set_oneof_case_message$;\n" + "}\n"); +} + +void ImmutableStringOneofFieldLiteGenerator::GenerateFieldInfo( + io::Printer* printer, std::vector<uint16_t>* output) const { + WriteIntToUtf16CharSequence(descriptor_->number(), output); + WriteIntToUtf16CharSequence(GetExperimentalJavaFieldType(descriptor_), + output); + WriteIntToUtf16CharSequence(descriptor_->containing_oneof()->index(), output); +} + +void ImmutableStringOneofFieldLiteGenerator::GenerateBuilderMembers( + io::Printer* printer) const { + GOOGLE_DCHECK(HasHazzer(descriptor_)); + WriteFieldAccessorDocComment(printer, descriptor_, HAZZER); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n" + " return instance.has$capitalized_name$();\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + WriteFieldAccessorDocComment(printer, descriptor_, GETTER); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$public java.lang.String ${$get$capitalized_name$$}$() {\n" + " return instance.get$capitalized_name$();\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + WriteFieldStringBytesAccessorDocComment(printer, descriptor_, GETTER); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$public com.google.protobuf.ByteString\n" + " ${$get$capitalized_name$Bytes$}$() {\n" + " return instance.get$capitalized_name$Bytes();\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + WriteFieldAccessorDocComment(printer, descriptor_, SETTER, + /* builder */ true); + printer->Print(variables_, + "$deprecation$public Builder ${$set$capitalized_name$$}$(\n" + " java.lang.String value) {\n" + " copyOnWrite();\n" + " instance.set$capitalized_name$(value);\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldAccessorDocComment(printer, descriptor_, CLEARER, + /* builder */ true); + printer->Print( + variables_, + "$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n" + " copyOnWrite();\n" + " instance.clear$capitalized_name$();\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + WriteFieldStringBytesAccessorDocComment(printer, descriptor_, SETTER, + /* builder */ true); + printer->Print( + variables_, + "$deprecation$public Builder ${$set$capitalized_name$Bytes$}$(\n" + " com.google.protobuf.ByteString value) {\n" + " copyOnWrite();\n" + " instance.set$capitalized_name$Bytes(value);\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); +} + +// =================================================================== + +RepeatedImmutableStringFieldLiteGenerator:: + RepeatedImmutableStringFieldLiteGenerator(const FieldDescriptor* descriptor, + int messageBitIndex, + Context* context) + : descriptor_(descriptor), name_resolver_(context->GetNameResolver()) { + SetPrimitiveVariables(descriptor, messageBitIndex, 0, + context->GetFieldGeneratorInfo(descriptor), + name_resolver_, &variables_); +} + +RepeatedImmutableStringFieldLiteGenerator:: + ~RepeatedImmutableStringFieldLiteGenerator() {} + +int RepeatedImmutableStringFieldLiteGenerator::GetNumBitsForMessage() const { + return 0; +} + +void RepeatedImmutableStringFieldLiteGenerator::GenerateInterfaceMembers( + io::Printer* printer) const { + WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER); + printer->Print(variables_, + "$deprecation$java.util.List<java.lang.String>\n" + " get$capitalized_name$List();\n"); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_COUNT); + printer->Print(variables_, + "$deprecation$int get$capitalized_name$Count();\n"); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_GETTER); + printer->Print( + variables_, + "$deprecation$java.lang.String get$capitalized_name$(int index);\n"); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_GETTER); + printer->Print(variables_, + "$deprecation$com.google.protobuf.ByteString\n" + " get$capitalized_name$Bytes(int index);\n"); +} + +void RepeatedImmutableStringFieldLiteGenerator::GenerateMembers( + io::Printer* printer) const { + printer->Print( + variables_, + "private com.google.protobuf.Internal.ProtobufList<java.lang.String> " + "$name$_;\n"); + PrintExtraFieldInfo(variables_, printer); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$public java.util.List<java.lang.String> " + "${$get$capitalized_name$List$}$() {\n" + " return $name$_;\n" // note: unmodifiable list + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_COUNT); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$public int ${$get$capitalized_name$Count$}$() {\n" + " return $name$_.size();\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_GETTER); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$public java.lang.String " + "${$get$capitalized_name$$}$(int index) {\n" + " return $name$_.get(index);\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldStringBytesAccessorDocComment(printer, descriptor_, + LIST_INDEXED_GETTER); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$public com.google.protobuf.ByteString\n" + " ${$get$capitalized_name$Bytes$}$(int index) {\n" + " return com.google.protobuf.ByteString.copyFromUtf8(\n" + " $name$_.get(index));\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + printer->Print( + variables_, + "private void ensure$capitalized_name$IsMutable() {\n" + // Use a temporary to avoid a redundant iget-object. + " com.google.protobuf.Internal.ProtobufList<java.lang.String> tmp =\n" + " $name$_;" + " if (!tmp.isModifiable()) {\n" + " $name$_ =\n" + " com.google.protobuf.GeneratedMessageLite.mutableCopy(tmp);\n" + " }\n" + "}\n"); + + WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_SETTER); + printer->Print(variables_, + "private void set$capitalized_name$(\n" + " int index, java.lang.String value) {\n" + "$null_check$" + " ensure$capitalized_name$IsMutable();\n" + " $name$_.set(index, value);\n" + "}\n"); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER); + printer->Print(variables_, + "private void add$capitalized_name$(\n" + " java.lang.String value) {\n" + "$null_check$" + " ensure$capitalized_name$IsMutable();\n" + " $name$_.add(value);\n" + "}\n"); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER); + printer->Print(variables_, + "private void addAll$capitalized_name$(\n" + " java.lang.Iterable<java.lang.String> values) {\n" + " ensure$capitalized_name$IsMutable();\n" + " com.google.protobuf.AbstractMessageLite.addAll(\n" + " values, $name$_);\n" + "}\n"); + WriteFieldAccessorDocComment(printer, descriptor_, CLEARER); + printer->Print(variables_, + "private void clear$capitalized_name$() {\n" + " $name$_ = $empty_list$;\n" + "}\n"); + + WriteFieldStringBytesAccessorDocComment(printer, descriptor_, LIST_ADDER); + printer->Print(variables_, + "private void add$capitalized_name$Bytes(\n" + " com.google.protobuf.ByteString value) {\n"); + if (CheckUtf8(descriptor_)) { + printer->Print(variables_, " checkByteStringIsUtf8(value);\n"); + } + printer->Print(variables_, + " ensure$capitalized_name$IsMutable();\n" + " $name$_.add(value.toStringUtf8());\n" + "}\n"); +} + +void RepeatedImmutableStringFieldLiteGenerator::GenerateBuilderMembers( + io::Printer* printer) const { + WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$public java.util.List<java.lang.String>\n" + " ${$get$capitalized_name$List$}$() {\n" + " return java.util.Collections.unmodifiableList(\n" + " instance.get$capitalized_name$List());\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_COUNT); + printer->Print( + variables_, + "@java.lang.Override\n" + "$deprecation$public int ${$get$capitalized_name$Count$}$() {\n" + " return instance.get$capitalized_name$Count();\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_GETTER); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$public java.lang.String " + "${$get$capitalized_name$$}$(int index) {\n" + " return instance.get$capitalized_name$(index);\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldStringBytesAccessorDocComment(printer, descriptor_, + LIST_INDEXED_GETTER); + printer->Print(variables_, + "@java.lang.Override\n" + "$deprecation$public com.google.protobuf.ByteString\n" + " ${$get$capitalized_name$Bytes$}$(int index) {\n" + " return instance.get$capitalized_name$Bytes(index);\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_SETTER, + /* builder */ true); + printer->Print(variables_, + "$deprecation$public Builder ${$set$capitalized_name$$}$(\n" + " int index, java.lang.String value) {\n" + " copyOnWrite();\n" + " instance.set$capitalized_name$(index, value);\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER, + /* builder */ true); + printer->Print(variables_, + "$deprecation$public Builder ${$add$capitalized_name$$}$(\n" + " java.lang.String value) {\n" + " copyOnWrite();\n" + " instance.add$capitalized_name$(value);\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER, + /* builder */ true); + printer->Print(variables_, + "$deprecation$public Builder ${$addAll$capitalized_name$$}$(\n" + " java.lang.Iterable<java.lang.String> values) {\n" + " copyOnWrite();\n" + " instance.addAll$capitalized_name$(values);\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + WriteFieldAccessorDocComment(printer, descriptor_, CLEARER, + /* builder */ true); + printer->Print( + variables_, + "$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n" + " copyOnWrite();\n" + " instance.clear$capitalized_name$();\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); + + WriteFieldStringBytesAccessorDocComment(printer, descriptor_, LIST_ADDER, + /* builder */ true); + printer->Print( + variables_, + "$deprecation$public Builder ${$add$capitalized_name$Bytes$}$(\n" + " com.google.protobuf.ByteString value) {\n" + " copyOnWrite();\n" + " instance.add$capitalized_name$Bytes(value);\n" + " return this;\n" + "}\n"); + printer->Annotate("{", "}", descriptor_); +} + +void RepeatedImmutableStringFieldLiteGenerator::GenerateKotlinDslMembers( + io::Printer* printer) const { + printer->Print( + variables_, + "/**\n" + " * An uninstantiable, behaviorless type to represent the field in\n" + " * generics.\n" + " */\n" + "@kotlin.OptIn" + "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n" + "public class ${$$kt_capitalized_name$Proxy$}$ private constructor()" + " : com.google.protobuf.kotlin.DslProxy()\n"); + + // property for List<String> + WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER); + printer->Print( + variables_, + "$kt_deprecation$public val $kt_name$: " + "com.google.protobuf.kotlin.DslList" + "<kotlin.String, ${$$kt_capitalized_name$Proxy$}$>\n" + " @kotlin.OptIn" + "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n" + " get() = com.google.protobuf.kotlin.DslList(\n" + " $kt_dsl_builder$.${$get$capitalized_name$List$}$()\n" + " )\n"); + + // List<String>.add(String) + WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER, + /* builder */ false); + printer->Print(variables_, + "@kotlin.jvm.JvmSynthetic\n" + "@kotlin.jvm.JvmName(\"add$kt_capitalized_name$\")\n" + "public fun com.google.protobuf.kotlin.DslList" + "<kotlin.String, ${$$kt_capitalized_name$Proxy$}$>." + "add(value: kotlin.String) {\n" + " $kt_dsl_builder$.${$add$capitalized_name$$}$(value)\n" + "}\n"); + + // List<String> += String + WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER, + /* builder */ false); + printer->Print(variables_, + "@kotlin.jvm.JvmSynthetic\n" + "@kotlin.jvm.JvmName(\"plusAssign$kt_capitalized_name$\")\n" + "@Suppress(\"NOTHING_TO_INLINE\")\n" + "public inline operator fun com.google.protobuf.kotlin.DslList" + "<kotlin.String, ${$$kt_capitalized_name$Proxy$}$>." + "plusAssign(value: kotlin.String) {\n" + " add(value)\n" + "}\n"); + + // List<String>.addAll(Iterable<String>) + WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER, + /* builder */ false); + printer->Print( + variables_, + "@kotlin.jvm.JvmSynthetic\n" + "@kotlin.jvm.JvmName(\"addAll$kt_capitalized_name$\")\n" + "public fun com.google.protobuf.kotlin.DslList" + "<kotlin.String, ${$$kt_capitalized_name$Proxy$}$>." + "addAll(values: kotlin.collections.Iterable<kotlin.String>) {\n" + " $kt_dsl_builder$.${$addAll$capitalized_name$$}$(values)\n" + "}\n"); + + // List<String> += Iterable<String> + WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER, + /* builder */ false); + printer->Print( + variables_, + "@kotlin.jvm.JvmSynthetic\n" + "@kotlin.jvm.JvmName(\"plusAssignAll$kt_capitalized_name$\")\n" + "@Suppress(\"NOTHING_TO_INLINE\")\n" + "public inline operator fun com.google.protobuf.kotlin.DslList" + "<kotlin.String, ${$$kt_capitalized_name$Proxy$}$>." + "plusAssign(values: kotlin.collections.Iterable<kotlin.String>) {\n" + " addAll(values)\n" + "}\n"); + + // List<String>[Int] = String + WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_SETTER, + /* builder */ false); + printer->Print( + variables_, + "@kotlin.jvm.JvmSynthetic\n" + "@kotlin.jvm.JvmName(\"set$kt_capitalized_name$\")\n" + "public operator fun com.google.protobuf.kotlin.DslList" + "<kotlin.String, ${$$kt_capitalized_name$Proxy$}$>." + "set(index: kotlin.Int, value: kotlin.String) {\n" + " $kt_dsl_builder$.${$set$capitalized_name$$}$(index, value)\n" + "}"); + + WriteFieldAccessorDocComment(printer, descriptor_, CLEARER, + /* builder */ false); + printer->Print(variables_, + "@kotlin.jvm.JvmSynthetic\n" + "@kotlin.jvm.JvmName(\"clear$kt_capitalized_name$\")\n" + "public fun com.google.protobuf.kotlin.DslList" + "<kotlin.String, ${$$kt_capitalized_name$Proxy$}$>." + "clear() {\n" + " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n" + "}"); +} + +void RepeatedImmutableStringFieldLiteGenerator::GenerateFieldInfo( + io::Printer* printer, std::vector<uint16_t>* output) const { + WriteIntToUtf16CharSequence(descriptor_->number(), output); + WriteIntToUtf16CharSequence(GetExperimentalJavaFieldType(descriptor_), + output); + printer->Print(variables_, "\"$name$_\",\n"); +} + +void RepeatedImmutableStringFieldLiteGenerator::GenerateInitializationCode( + io::Printer* printer) const { + printer->Print(variables_, "$name$_ = $empty_list$;\n"); +} + +std::string RepeatedImmutableStringFieldLiteGenerator::GetBoxedType() const { + return "java.lang.String"; +} + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/java/java_string_field_lite.h b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_string_field_lite.h new file mode 100644 index 00000000..880d41cc --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/java/java_string_field_lite.h @@ -0,0 +1,139 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Author: jonp@google.com (Jon Perlow) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_STRING_FIELD_LITE_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVA_STRING_FIELD_LITE_H__ + +#include <cstdint> +#include <map> +#include <string> + +#include <compiler/java/java_field.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { +class Context; // context.h +class ClassNameResolver; // name_resolver.h +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +class ImmutableStringFieldLiteGenerator : public ImmutableFieldLiteGenerator { + public: + explicit ImmutableStringFieldLiteGenerator(const FieldDescriptor* descriptor, + int messageBitIndex, + Context* context); + ~ImmutableStringFieldLiteGenerator() override; + + // implements ImmutableFieldLiteGenerator + // ------------------------------------ + int GetNumBitsForMessage() const override; + void GenerateInterfaceMembers(io::Printer* printer) const override; + void GenerateMembers(io::Printer* printer) const override; + void GenerateBuilderMembers(io::Printer* printer) const override; + void GenerateInitializationCode(io::Printer* printer) const override; + void GenerateFieldInfo(io::Printer* printer, + std::vector<uint16_t>* output) const override; + void GenerateKotlinDslMembers(io::Printer* printer) const override; + + std::string GetBoxedType() const override; + + protected: + const FieldDescriptor* descriptor_; + std::map<std::string, std::string> variables_; + const int messageBitIndex_; + ClassNameResolver* name_resolver_; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableStringFieldLiteGenerator); +}; + +class ImmutableStringOneofFieldLiteGenerator + : public ImmutableStringFieldLiteGenerator { + public: + ImmutableStringOneofFieldLiteGenerator(const FieldDescriptor* descriptor, + int messageBitIndex, Context* context); + ~ImmutableStringOneofFieldLiteGenerator() override; + + private: + void GenerateMembers(io::Printer* printer) const override; + void GenerateBuilderMembers(io::Printer* printer) const override; + void GenerateFieldInfo(io::Printer* printer, + std::vector<uint16_t>* output) const override; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableStringOneofFieldLiteGenerator); +}; + +class RepeatedImmutableStringFieldLiteGenerator + : public ImmutableFieldLiteGenerator { + public: + explicit RepeatedImmutableStringFieldLiteGenerator( + const FieldDescriptor* descriptor, int messageBitIndex, Context* context); + ~RepeatedImmutableStringFieldLiteGenerator() override; + + // implements ImmutableFieldLiteGenerator ------------------------------------ + int GetNumBitsForMessage() const override; + void GenerateInterfaceMembers(io::Printer* printer) const override; + void GenerateMembers(io::Printer* printer) const override; + void GenerateBuilderMembers(io::Printer* printer) const override; + void GenerateInitializationCode(io::Printer* printer) const override; + void GenerateFieldInfo(io::Printer* printer, + std::vector<uint16_t>* output) const override; + void GenerateKotlinDslMembers(io::Printer* printer) const override; + + std::string GetBoxedType() const override; + + private: + const FieldDescriptor* descriptor_; + std::map<std::string, std::string> variables_; + ClassNameResolver* name_resolver_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedImmutableStringFieldLiteGenerator); +}; + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_STRING_FIELD_LITE_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/js/js_generator.cc b/NorthstarDedicatedTest/include/protobuf/compiler/js/js_generator.cc new file mode 100644 index 00000000..0a1fbb58 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/js/js_generator.cc @@ -0,0 +1,3941 @@ +// 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 <assert.h> +#include <compiler/js/js_generator.h> +#include <compiler/js/well_known_types_embed.h> +#include <compiler/scc.h> +#include <descriptor.h> +#include <descriptor.pb.h> +#include <io/printer.h> +#include <io/zero_copy_stream.h> +#include <stubs/common.h> +#include <stubs/logging.h> +#include <stubs/stringprintf.h> +#include <stubs/strutil.h> + +#include <algorithm> +#include <limits> +#include <map> +#include <memory> +#include <string> +#include <utility> +#include <vector> + +namespace google { +namespace protobuf { +namespace compiler { +namespace js { + +// Sorted list of JavaScript keywords. These cannot be used as names. If they +// appear, we prefix them with "pb_". +const char* kKeyword[] = { + "abstract", "boolean", "break", "byte", "case", + "catch", "char", "class", "const", "continue", + "debugger", "default", "delete", "do", "double", + "else", "enum", "export", "extends", "false", + "final", "finally", "float", "for", "function", + "goto", "if", "implements", "import", "in", + "instanceof", "int", "interface", "long", "native", + "new", "null", "package", "private", "protected", + "public", "return", "short", "static", "super", + "switch", "synchronized", "this", "throw", "throws", + "transient", "try", "typeof", "var", "void", + "volatile", "while", "with", +}; + +static const int kNumKeyword = sizeof(kKeyword) / sizeof(char*); + +namespace { + +// The mode of operation for bytes fields. Historically JSPB always carried +// bytes as JS {string}, containing base64 content by convention. With binary +// and proto3 serialization the new convention is to represent it as binary +// data in Uint8Array. See b/26173701 for background on the migration. +enum BytesMode { + BYTES_DEFAULT, // Default type for getBytesField to return. + BYTES_B64, // Explicitly coerce to base64 string where needed. + BYTES_U8, // Explicitly coerce to Uint8Array where needed. +}; + +bool IsReserved(const std::string& ident) { + for (int i = 0; i < kNumKeyword; i++) { + if (ident == kKeyword[i]) { + return true; + } + } + return false; +} + +std::string GetSnakeFilename(const std::string& filename) { + std::string snake_name = filename; + ReplaceCharacters(&snake_name, "/", '_'); + return snake_name; +} + +// Given a filename like foo/bar/baz.proto, returns the corresponding JavaScript +// file foo/bar/baz.js. +std::string GetJSFilename(const GeneratorOptions& options, + const std::string& filename) { + return StripProto(filename) + options.GetFileNameExtension(); +} + +// Given a filename like foo/bar/baz.proto, returns the root directory +// path ../../ +std::string GetRootPath(const std::string& from_filename, + const std::string& to_filename) { + if (to_filename.find("google/protobuf") == 0) { + // Well-known types (.proto files in the google/protobuf directory) are + // assumed to come from the 'google-protobuf' npm package. We may want to + // generalize this exception later by letting others put generated code in + // their own npm packages. + return "google-protobuf/"; + } + + size_t slashes = std::count(from_filename.begin(), from_filename.end(), '/'); + if (slashes == 0) { + return "./"; + } + std::string result = ""; + for (size_t i = 0; i < slashes; i++) { + result += "../"; + } + return result; +} + +// Returns the alias we assign to the module of the given .proto filename +// when importing. +std::string ModuleAlias(const std::string& filename) { + // This scheme could technically cause problems if a file includes any 2 of: + // foo/bar_baz.proto + // foo_bar_baz.proto + // foo_bar/baz.proto + // + // We'll worry about this problem if/when we actually see it. This name isn't + // exposed to users so we can change it later if we need to. + std::string basename = StripProto(filename); + ReplaceCharacters(&basename, "-", '$'); + ReplaceCharacters(&basename, "/", '_'); + ReplaceCharacters(&basename, ".", '_'); + return basename + "_pb"; +} + +// Returns the fully normalized JavaScript namespace for the given +// file descriptor's package. +std::string GetNamespace(const GeneratorOptions& options, + const FileDescriptor* file) { + if (!options.namespace_prefix.empty()) { + return options.namespace_prefix; + } else if (!file->package().empty()) { + return "proto." + file->package(); + } else { + return "proto"; + } +} + +// Returns the name of the message with a leading dot and taking into account +// nesting, for example ".OuterMessage.InnerMessage", or returns empty if +// descriptor is null. This function does not handle namespacing, only message +// nesting. +std::string GetNestedMessageName(const Descriptor* descriptor) { + if (descriptor == NULL) { + return ""; + } + std::string result = + StripPrefixString(descriptor->full_name(), descriptor->file()->package()); + // Add a leading dot if one is not already present. + if (!result.empty() && result[0] != '.') { + result = "." + result; + } + return result; +} + +// Returns the path prefix for a message or enumeration that +// lives under the given file and containing type. +std::string GetPrefix(const GeneratorOptions& options, + const FileDescriptor* file_descriptor, + const Descriptor* containing_type) { + std::string prefix = GetNamespace(options, file_descriptor) + + GetNestedMessageName(containing_type); + if (!prefix.empty()) { + prefix += "."; + } + return prefix; +} + +// Returns the fully normalized JavaScript path prefix for the given +// message descriptor. +std::string GetMessagePathPrefix(const GeneratorOptions& options, + const Descriptor* descriptor) { + return GetPrefix(options, descriptor->file(), descriptor->containing_type()); +} + +// Returns the fully normalized JavaScript path for the given +// message descriptor. +std::string GetMessagePath(const GeneratorOptions& options, + const Descriptor* descriptor) { + return GetMessagePathPrefix(options, descriptor) + descriptor->name(); +} + +// Returns the fully normalized JavaScript path prefix for the given +// enumeration descriptor. +std::string GetEnumPathPrefix(const GeneratorOptions& options, + const EnumDescriptor* enum_descriptor) { + return GetPrefix(options, enum_descriptor->file(), + enum_descriptor->containing_type()); +} + +// Returns the fully normalized JavaScript path for the given +// enumeration descriptor. +std::string GetEnumPath(const GeneratorOptions& options, + const EnumDescriptor* enum_descriptor) { + return GetEnumPathPrefix(options, enum_descriptor) + enum_descriptor->name(); +} + +std::string MaybeCrossFileRef(const GeneratorOptions& options, + const FileDescriptor* from_file, + const Descriptor* to_message) { + if ((options.import_style == GeneratorOptions::kImportCommonJs || + options.import_style == GeneratorOptions::kImportCommonJsStrict) && + from_file != to_message->file()) { + // Cross-file ref in CommonJS needs to use the module alias instead of + // the global name. + return ModuleAlias(to_message->file()->name()) + + GetNestedMessageName(to_message->containing_type()) + "." + + to_message->name(); + } else { + // Within a single file we use a full name. + return GetMessagePath(options, to_message); + } +} + +std::string SubmessageTypeRef(const GeneratorOptions& options, + const FieldDescriptor* field) { + GOOGLE_CHECK(field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE); + return MaybeCrossFileRef(options, field->file(), field->message_type()); +} + +// - Object field name: LOWER_UNDERSCORE -> LOWER_CAMEL, except for group fields +// (UPPER_CAMEL -> LOWER_CAMEL), with "List" (or "Map") appended if appropriate, +// and with reserved words triggering a "pb_" prefix. +// - Getters/setters: LOWER_UNDERSCORE -> UPPER_CAMEL, except for group fields +// (use the name directly), then append "List" if appropriate, then append "$" +// if resulting name is equal to a reserved word. +// - Enums: just uppercase. + +// Locale-independent version of ToLower that deals only with ASCII A-Z. +char ToLowerASCII(char c) { + if (c >= 'A' && c <= 'Z') { + return (c - 'A') + 'a'; + } else { + return c; + } +} + +std::vector<std::string> ParseLowerUnderscore(const std::string& input) { + std::vector<std::string> words; + std::string running = ""; + for (int i = 0; i < input.size(); i++) { + if (input[i] == '_') { + if (!running.empty()) { + words.push_back(running); + running.clear(); + } + } else { + running += ToLowerASCII(input[i]); + } + } + if (!running.empty()) { + words.push_back(running); + } + return words; +} + +std::vector<std::string> ParseUpperCamel(const std::string& input) { + std::vector<std::string> words; + std::string running = ""; + for (int i = 0; i < input.size(); i++) { + if (input[i] >= 'A' && input[i] <= 'Z' && !running.empty()) { + words.push_back(running); + running.clear(); + } + running += ToLowerASCII(input[i]); + } + if (!running.empty()) { + words.push_back(running); + } + return words; +} + +std::string ToLowerCamel(const std::vector<std::string>& words) { + std::string result; + for (int i = 0; i < words.size(); i++) { + std::string word = words[i]; + if (i == 0 && (word[0] >= 'A' && word[0] <= 'Z')) { + word[0] = (word[0] - 'A') + 'a'; + } else if (i != 0 && (word[0] >= 'a' && word[0] <= 'z')) { + word[0] = (word[0] - 'a') + 'A'; + } + result += word; + } + return result; +} + +std::string ToUpperCamel(const std::vector<std::string>& words) { + std::string result; + for (int i = 0; i < words.size(); i++) { + std::string word = words[i]; + if (word[0] >= 'a' && word[0] <= 'z') { + word[0] = (word[0] - 'a') + 'A'; + } + result += word; + } + return result; +} + +// Based on code from descriptor.cc (Thanks Kenton!) +// Uppercases the entire string, turning ValueName into +// VALUENAME. +std::string ToEnumCase(const std::string& input) { + std::string result; + result.reserve(input.size()); + + for (int i = 0; i < input.size(); i++) { + if ('a' <= input[i] && input[i] <= 'z') { + result.push_back(input[i] - 'a' + 'A'); + } else { + result.push_back(input[i]); + } + } + + return result; +} + +std::string ToLower(const std::string& input) { + std::string result; + result.reserve(input.size()); + + for (int i = 0; i < input.size(); i++) { + if ('A' <= input[i] && input[i] <= 'Z') { + result.push_back(input[i] - 'A' + 'a'); + } else { + result.push_back(input[i]); + } + } + + return result; +} + +// When we're generating one output file per SCC, this is the filename +// that top-level extensions should go in. +// e.g. one proto file (test.proto): +// package a; +// extends Foo { +// ... +// } +// If "with_filename" equals true, the extension filename will be +// "proto.a_test_extensions.js", otherwise will be "proto.a.js" +std::string GetExtensionFileName(const GeneratorOptions& options, + const FileDescriptor* file, + bool with_filename) { + std::string snake_name = StripProto(GetSnakeFilename(file->name())); + return options.output_dir + "/" + ToLower(GetNamespace(options, file)) + + (with_filename ? ("_" + snake_name + "_extensions") : "") + + options.GetFileNameExtension(); +} +// When we're generating one output file per SCC, this is the filename +// that all messages in the SCC should go in. +// If with_package equals true, filename will have package prefix, +// If the filename length is longer than 200, the filename will be the +// SCC's proto filename with suffix "_long_sccs_(index)" (if with_package equals +// true it still has package prefix) +std::string GetMessagesFileName(const GeneratorOptions& options, const SCC* scc, + bool with_package) { + static std::map<const Descriptor*, std::string>* long_name_dict = + new std::map<const Descriptor*, std::string>(); + std::string package_base = + with_package + ? ToLower(GetNamespace(options, scc->GetRepresentative()->file()) + + "_") + : ""; + std::string filename_base = ""; + std::vector<std::string> all_message_names; + for (auto one_desc : scc->descriptors) { + if (one_desc->containing_type() == nullptr) { + all_message_names.push_back(ToLower(one_desc->name())); + } + } + sort(all_message_names.begin(), all_message_names.end()); + for (auto one_message : all_message_names) { + if (!filename_base.empty()) { + filename_base += "_"; + } + filename_base += one_message; + } + if (filename_base.size() + package_base.size() > 200) { + if ((*long_name_dict).find(scc->GetRepresentative()) == + (*long_name_dict).end()) { + std::string snake_name = StripProto( + GetSnakeFilename(scc->GetRepresentative()->file()->name())); + (*long_name_dict)[scc->GetRepresentative()] = + StrCat(snake_name, "_long_sccs_", + static_cast<uint64>((*long_name_dict).size())); + } + filename_base = (*long_name_dict)[scc->GetRepresentative()]; + } + return options.output_dir + "/" + package_base + filename_base + + options.GetFileNameExtension(); +} + +// When we're generating one output file per type name, this is the filename +// that a top-level enum should go in. +// If with_package equals true, filename will have package prefix. +std::string GetEnumFileName(const GeneratorOptions& options, + const EnumDescriptor* desc, bool with_package) { + return options.output_dir + "/" + + (with_package ? ToLower(GetNamespace(options, desc->file()) + "_") + : "") + + ToLower(desc->name()) + options.GetFileNameExtension(); +} + +// Returns the message/response ID, if set. +std::string GetMessageId(const Descriptor* desc) { return std::string(); } + +bool IgnoreExtensionField(const FieldDescriptor* field) { + // Exclude descriptor extensions from output "to avoid clutter" (from original + // codegen). + if (!field->is_extension()) return false; + const FileDescriptor* file = field->containing_type()->file(); + return file->name() == "net/proto2/proto/descriptor.proto" || + file->name() == "google/protobuf/descriptor.proto"; +} + +// Used inside Google only -- do not remove. +bool IsResponse(const Descriptor* desc) { return false; } + +bool IgnoreField(const FieldDescriptor* field) { + return IgnoreExtensionField(field); +} + +// Do we ignore this message type? +bool IgnoreMessage(const Descriptor* d) { return d->options().map_entry(); } + +// Does JSPB ignore this entire oneof? True only if all fields are ignored. +bool IgnoreOneof(const OneofDescriptor* oneof) { + if (oneof->is_synthetic()) return true; + for (int i = 0; i < oneof->field_count(); i++) { + if (!IgnoreField(oneof->field(i))) { + return false; + } + } + return true; +} + +std::string JSIdent(const GeneratorOptions& options, + const FieldDescriptor* field, bool is_upper_camel, + bool is_map, bool drop_list) { + std::string result; + if (field->type() == FieldDescriptor::TYPE_GROUP) { + result = is_upper_camel + ? ToUpperCamel(ParseUpperCamel(field->message_type()->name())) + : ToLowerCamel(ParseUpperCamel(field->message_type()->name())); + } else { + result = is_upper_camel ? ToUpperCamel(ParseLowerUnderscore(field->name())) + : ToLowerCamel(ParseLowerUnderscore(field->name())); + } + if (is_map || field->is_map()) { + // JSPB-style or proto3-style map. + result += "Map"; + } else if (!drop_list && field->is_repeated()) { + // Repeated field. + result += "List"; + } + return result; +} + +std::string JSObjectFieldName(const GeneratorOptions& options, + const FieldDescriptor* field) { + std::string name = JSIdent(options, field, + /* is_upper_camel = */ false, + /* is_map = */ false, + /* drop_list = */ false); + if (IsReserved(name)) { + name = "pb_" + name; + } + return name; +} + +std::string JSByteGetterSuffix(BytesMode bytes_mode) { + switch (bytes_mode) { + case BYTES_DEFAULT: + return ""; + case BYTES_B64: + return "B64"; + case BYTES_U8: + return "U8"; + default: + assert(false); + } + return ""; +} + +// Returns the field name as a capitalized portion of a getter/setter method +// name, e.g. MyField for .getMyField(). +std::string JSGetterName(const GeneratorOptions& options, + const FieldDescriptor* field, + BytesMode bytes_mode = BYTES_DEFAULT, + bool drop_list = false) { + std::string name = JSIdent(options, field, + /* is_upper_camel = */ true, + /* is_map = */ false, drop_list); + if (field->type() == FieldDescriptor::TYPE_BYTES) { + std::string suffix = JSByteGetterSuffix(bytes_mode); + if (!suffix.empty()) { + name += "_as" + suffix; + } + } + if (name == "Extension" || name == "JsPbMessageId") { + // Avoid conflicts with base-class names. + name += "$"; + } + return name; +} + +std::string JSOneofName(const OneofDescriptor* oneof) { + return ToUpperCamel(ParseLowerUnderscore(oneof->name())); +} + +// Returns the index corresponding to this field in the JSPB array (underlying +// data storage array). +std::string JSFieldIndex(const FieldDescriptor* field) { + // Determine whether this field is a member of a group. Group fields are a bit + // wonky: their "containing type" is a message type created just for the + // group, and that type's parent type has a field with the group-message type + // as its message type and TYPE_GROUP as its field type. For such fields, the + // index we use is relative to the field number of the group submessage field. + // For all other fields, we just use the field number. + const Descriptor* containing_type = field->containing_type(); + const Descriptor* parent_type = containing_type->containing_type(); + if (parent_type != NULL) { + for (int i = 0; i < parent_type->field_count(); i++) { + if (parent_type->field(i)->type() == FieldDescriptor::TYPE_GROUP && + parent_type->field(i)->message_type() == containing_type) { + return StrCat(field->number() - parent_type->field(i)->number()); + } + } + } + return StrCat(field->number()); +} + +std::string JSOneofIndex(const OneofDescriptor* oneof) { + int index = -1; + for (int i = 0; i < oneof->containing_type()->oneof_decl_count(); i++) { + const OneofDescriptor* o = oneof->containing_type()->oneof_decl(i); + if (o->is_synthetic()) continue; + // If at least one field in this oneof is not JSPB-ignored, count the oneof. + for (int j = 0; j < o->field_count(); j++) { + const FieldDescriptor* f = o->field(j); + if (!IgnoreField(f)) { + index++; + break; // inner loop + } + } + if (o == oneof) { + break; + } + } + return StrCat(index); +} + +// Decodes a codepoint in \x0000 -- \xFFFF. +uint16 DecodeUTF8Codepoint(uint8* bytes, size_t* length) { + if (*length == 0) { + return 0; + } + size_t expected = 0; + if ((*bytes & 0x80) == 0) { + expected = 1; + } else if ((*bytes & 0xe0) == 0xc0) { + expected = 2; + } else if ((*bytes & 0xf0) == 0xe0) { + expected = 3; + } else { + // Too long -- don't accept. + *length = 0; + return 0; + } + + if (*length < expected) { + // Not enough bytes -- don't accept. + *length = 0; + return 0; + } + + *length = expected; + switch (expected) { + case 1: + return bytes[0]; + case 2: + return ((bytes[0] & 0x1F) << 6) | ((bytes[1] & 0x3F) << 0); + case 3: + return ((bytes[0] & 0x0F) << 12) | ((bytes[1] & 0x3F) << 6) | + ((bytes[2] & 0x3F) << 0); + default: + return 0; + } +} + +// Escapes the contents of a string to be included within double-quotes ("") in +// JavaScript. The input data should be a UTF-8 encoded C++ string of chars. +// Returns false if |out| was truncated because |in| contained invalid UTF-8 or +// codepoints outside the BMP. +// TODO(b/115551870): Support codepoints outside the BMP. +bool EscapeJSString(const std::string& in, std::string* out) { + size_t decoded = 0; + for (size_t i = 0; i < in.size(); i += decoded) { + uint16 codepoint = 0; + // Decode the next UTF-8 codepoint. + size_t have_bytes = in.size() - i; + uint8 bytes[3] = { + static_cast<uint8>(in[i]), + static_cast<uint8>(((i + 1) < in.size()) ? in[i + 1] : 0), + static_cast<uint8>(((i + 2) < in.size()) ? in[i + 2] : 0), + }; + codepoint = DecodeUTF8Codepoint(bytes, &have_bytes); + if (have_bytes == 0) { + return false; + } + decoded = have_bytes; + + switch (codepoint) { + case '\'': + *out += "\\x27"; + break; + case '"': + *out += "\\x22"; + break; + case '<': + *out += "\\x3c"; + break; + case '=': + *out += "\\x3d"; + break; + case '>': + *out += "\\x3e"; + break; + case '&': + *out += "\\x26"; + break; + case '\b': + *out += "\\b"; + break; + case '\t': + *out += "\\t"; + break; + case '\n': + *out += "\\n"; + break; + case '\f': + *out += "\\f"; + break; + case '\r': + *out += "\\r"; + break; + case '\\': + *out += "\\\\"; + break; + default: + // TODO(b/115551870): Once we're supporting codepoints outside the BMP, + // use a single Unicode codepoint escape if the output language is + // ECMAScript 2015 or above. Otherwise, use a surrogate pair. + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#String_literals + if (codepoint >= 0x20 && codepoint <= 0x7e) { + *out += static_cast<char>(codepoint); + } else if (codepoint >= 0x100) { + *out += StringPrintf("\\u%04x", codepoint); + } else { + *out += StringPrintf("\\x%02x", codepoint); + } + break; + } + } + return true; +} + +std::string EscapeBase64(const std::string& in) { + static const char* kAlphabet = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + std::string result; + + for (size_t i = 0; i < in.size(); i += 3) { + int value = (in[i] << 16) | (((i + 1) < in.size()) ? (in[i + 1] << 8) : 0) | + (((i + 2) < in.size()) ? (in[i + 2] << 0) : 0); + result += kAlphabet[(value >> 18) & 0x3f]; + result += kAlphabet[(value >> 12) & 0x3f]; + if ((i + 1) < in.size()) { + result += kAlphabet[(value >> 6) & 0x3f]; + } else { + result += '='; + } + if ((i + 2) < in.size()) { + result += kAlphabet[(value >> 0) & 0x3f]; + } else { + result += '='; + } + } + + return result; +} + +// Post-process the result of SimpleFtoa/SimpleDtoa to *exactly* match the +// original codegen's formatting (which is just .toString() on java.lang.Double +// or java.lang.Float). +std::string PostProcessFloat(std::string result) { + // If inf, -inf or nan, replace with +Infinity, -Infinity or NaN. + if (result == "inf") { + return "Infinity"; + } else if (result == "-inf") { + return "-Infinity"; + } else if (result == "nan") { + return "NaN"; + } + + // If scientific notation (e.g., "1e10"), (i) capitalize the "e", (ii) + // ensure that the mantissa (portion prior to the "e") has at least one + // fractional digit (after the decimal point), and (iii) strip any unnecessary + // leading zeroes and/or '+' signs from the exponent. + std::string::size_type exp_pos = result.find('e'); + if (exp_pos != std::string::npos) { + std::string mantissa = result.substr(0, exp_pos); + std::string exponent = result.substr(exp_pos + 1); + + // Add ".0" to mantissa if no fractional part exists. + if (mantissa.find('.') == std::string::npos) { + mantissa += ".0"; + } + + // Strip the sign off the exponent and store as |exp_neg|. + bool exp_neg = false; + if (!exponent.empty() && exponent[0] == '+') { + exponent = exponent.substr(1); + } else if (!exponent.empty() && exponent[0] == '-') { + exp_neg = true; + exponent = exponent.substr(1); + } + + // Strip any leading zeroes off the exponent. + while (exponent.size() > 1 && exponent[0] == '0') { + exponent = exponent.substr(1); + } + + return mantissa + "E" + std::string(exp_neg ? "-" : "") + exponent; + } + + // Otherwise, this is an ordinary decimal number. Append ".0" if result has no + // decimal/fractional part in order to match output of original codegen. + if (result.find('.') == std::string::npos) { + result += ".0"; + } + + return result; +} + +std::string FloatToString(float value) { + std::string result = SimpleFtoa(value); + return PostProcessFloat(result); +} + +std::string DoubleToString(double value) { + std::string result = SimpleDtoa(value); + return PostProcessFloat(result); +} + +bool InRealOneof(const FieldDescriptor* field) { + return field->containing_oneof() && + !field->containing_oneof()->is_synthetic(); +} + +// Return true if this is an integral field that should be represented as string +// in JS. +bool IsIntegralFieldWithStringJSType(const FieldDescriptor* field) { + switch (field->cpp_type()) { + case FieldDescriptor::CPPTYPE_INT64: + case FieldDescriptor::CPPTYPE_UINT64: + // The default value of JSType is JS_NORMAL, which behaves the same as + // JS_NUMBER. + return field->options().jstype() == FieldOptions::JS_STRING; + default: + return false; + } +} + +std::string MaybeNumberString(const FieldDescriptor* field, + const std::string& orig) { + return IsIntegralFieldWithStringJSType(field) ? ("\"" + orig + "\"") : orig; +} + +std::string JSFieldDefault(const FieldDescriptor* field) { + if (field->is_repeated()) { + return "[]"; + } + + switch (field->cpp_type()) { + case FieldDescriptor::CPPTYPE_INT32: + return MaybeNumberString(field, StrCat(field->default_value_int32())); + case FieldDescriptor::CPPTYPE_UINT32: + // The original codegen is in Java, and Java protobufs store unsigned + // integer values as signed integer values. In order to exactly match the + // output, we need to reinterpret as base-2 signed. Ugh. + return MaybeNumberString( + field, StrCat(static_cast<int32>(field->default_value_uint32()))); + case FieldDescriptor::CPPTYPE_INT64: + return MaybeNumberString(field, StrCat(field->default_value_int64())); + case FieldDescriptor::CPPTYPE_UINT64: + // See above note for uint32 -- reinterpreting as signed. + return MaybeNumberString( + field, StrCat(static_cast<int64>(field->default_value_uint64()))); + case FieldDescriptor::CPPTYPE_ENUM: + return StrCat(field->default_value_enum()->number()); + case FieldDescriptor::CPPTYPE_BOOL: + return field->default_value_bool() ? "true" : "false"; + case FieldDescriptor::CPPTYPE_FLOAT: + return FloatToString(field->default_value_float()); + case FieldDescriptor::CPPTYPE_DOUBLE: + return DoubleToString(field->default_value_double()); + case FieldDescriptor::CPPTYPE_STRING: + if (field->type() == FieldDescriptor::TYPE_STRING) { + std::string out; + bool is_valid = EscapeJSString(field->default_value_string(), &out); + if (!is_valid) { + // TODO(b/115551870): Decide whether this should be a hard error. + GOOGLE_LOG(WARNING) + << "The default value for field " << field->full_name() + << " was truncated since it contained invalid UTF-8 or" + " codepoints outside the basic multilingual plane."; + } + return "\"" + out + "\""; + } else { // Bytes + return "\"" + EscapeBase64(field->default_value_string()) + "\""; + } + case FieldDescriptor::CPPTYPE_MESSAGE: + return "null"; + } + GOOGLE_LOG(FATAL) << "Shouldn't reach here."; + return ""; +} + +std::string ProtoTypeName(const GeneratorOptions& options, + const FieldDescriptor* field) { + switch (field->type()) { + case FieldDescriptor::TYPE_BOOL: + return "bool"; + 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_STRING: + return "string"; + case FieldDescriptor::TYPE_BYTES: + return "bytes"; + case FieldDescriptor::TYPE_GROUP: + return GetMessagePath(options, field->message_type()); + case FieldDescriptor::TYPE_ENUM: + return GetEnumPath(options, field->enum_type()); + case FieldDescriptor::TYPE_MESSAGE: + return GetMessagePath(options, field->message_type()); + default: + return ""; + } +} + +std::string JSIntegerTypeName(const FieldDescriptor* field) { + return IsIntegralFieldWithStringJSType(field) ? "string" : "number"; +} + +std::string JSStringTypeName(const GeneratorOptions& options, + const FieldDescriptor* field, + BytesMode bytes_mode) { + if (field->type() == FieldDescriptor::TYPE_BYTES) { + switch (bytes_mode) { + case BYTES_DEFAULT: + return "(string|Uint8Array)"; + case BYTES_B64: + return "string"; + case BYTES_U8: + return "Uint8Array"; + default: + assert(false); + } + } + return "string"; +} + +std::string JSTypeName(const GeneratorOptions& options, + const FieldDescriptor* field, BytesMode bytes_mode) { + switch (field->cpp_type()) { + case FieldDescriptor::CPPTYPE_BOOL: + return "boolean"; + case FieldDescriptor::CPPTYPE_INT32: + return JSIntegerTypeName(field); + case FieldDescriptor::CPPTYPE_INT64: + return JSIntegerTypeName(field); + case FieldDescriptor::CPPTYPE_UINT32: + return JSIntegerTypeName(field); + case FieldDescriptor::CPPTYPE_UINT64: + return JSIntegerTypeName(field); + case FieldDescriptor::CPPTYPE_FLOAT: + return "number"; + case FieldDescriptor::CPPTYPE_DOUBLE: + return "number"; + case FieldDescriptor::CPPTYPE_STRING: + return JSStringTypeName(options, field, bytes_mode); + case FieldDescriptor::CPPTYPE_ENUM: + return GetEnumPath(options, field->enum_type()); + case FieldDescriptor::CPPTYPE_MESSAGE: + return GetMessagePath(options, field->message_type()); + default: + return ""; + } +} + +// Used inside Google only -- do not remove. +bool UseBrokenPresenceSemantics(const GeneratorOptions& options, + const FieldDescriptor* field) { + return false; +} + +// Returns true for fields that return "null" from accessors when they are +// unset. This should normally only be true for non-repeated submessages, but we +// have legacy users who relied on old behavior where accessors behaved this +// way. +bool ReturnsNullWhenUnset(const GeneratorOptions& options, + const FieldDescriptor* field) { + if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && + field->is_optional()) { + return true; + } + + // TODO(haberman): remove this case and unconditionally return false. + return UseBrokenPresenceSemantics(options, field) && !field->is_repeated() && + !field->has_default_value(); +} + +// In a sane world, this would be the same as ReturnsNullWhenUnset(). But in +// the status quo, some fields declare that they never return null/undefined +// even though they actually do: +// * required fields +// * optional enum fields +// * proto3 primitive fields. +bool DeclaredReturnTypeIsNullable(const GeneratorOptions& options, + const FieldDescriptor* field) { + if (field->is_required() || field->type() == FieldDescriptor::TYPE_ENUM) { + return false; + } + + if (field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3 && + field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) { + return false; + } + + return ReturnsNullWhenUnset(options, field); +} + +bool SetterAcceptsUndefined(const GeneratorOptions& options, + const FieldDescriptor* field) { + if (ReturnsNullWhenUnset(options, field)) { + return true; + } + + // Broken presence semantics always accepts undefined for setters. + return UseBrokenPresenceSemantics(options, field); +} + +bool SetterAcceptsNull(const GeneratorOptions& options, + const FieldDescriptor* field) { + if (ReturnsNullWhenUnset(options, field)) { + return true; + } + + // With broken presence semantics, fields with defaults accept "null" for + // setters, but other fields do not. This is a strange quirk of the old + // codegen. + return UseBrokenPresenceSemantics(options, field) && + field->has_default_value(); +} + +// Returns types which are known to by non-nullable by default. +// The style guide requires that we omit "!" in this case. +bool IsPrimitive(const std::string& type) { + return type == "undefined" || type == "string" || type == "number" || + type == "boolean"; +} + +std::string JSFieldTypeAnnotation(const GeneratorOptions& options, + const FieldDescriptor* field, + bool is_setter_argument, bool force_present, + bool singular_if_not_packed, + BytesMode bytes_mode = BYTES_DEFAULT, + bool force_singular = false) { + std::string jstype = JSTypeName(options, field, bytes_mode); + + if (!force_singular && field->is_repeated() && + (field->is_packed() || !singular_if_not_packed)) { + if (field->type() == FieldDescriptor::TYPE_BYTES && + bytes_mode == BYTES_DEFAULT) { + jstype = "(Array<!Uint8Array>|Array<string>)"; + } else { + if (!IsPrimitive(jstype)) { + jstype = "!" + jstype; + } + jstype = "Array<" + jstype + ">"; + } + } + + bool is_null_or_undefined = false; + + if (is_setter_argument) { + if (SetterAcceptsNull(options, field)) { + jstype = "?" + jstype; + is_null_or_undefined = true; + } + + if (SetterAcceptsUndefined(options, field)) { + jstype += "|undefined"; + is_null_or_undefined = true; + } + } else if (force_present) { + // Don't add null or undefined. + } else { + if (DeclaredReturnTypeIsNullable(options, field)) { + jstype = "?" + jstype; + is_null_or_undefined = true; + } + } + + if (!is_null_or_undefined && !IsPrimitive(jstype)) { + jstype = "!" + jstype; + } + + return jstype; +} + +std::string JSBinaryReaderMethodType(const FieldDescriptor* field) { + std::string name = field->type_name(); + if (name[0] >= 'a' && name[0] <= 'z') { + name[0] = (name[0] - 'a') + 'A'; + } + return IsIntegralFieldWithStringJSType(field) ? (name + "String") : name; +} + +std::string JSBinaryReadWriteMethodName(const FieldDescriptor* field, + bool is_writer) { + std::string name = JSBinaryReaderMethodType(field); + if (field->is_packed()) { + name = "Packed" + name; + } else if (is_writer && field->is_repeated()) { + name = "Repeated" + name; + } + return name; +} + +std::string JSBinaryReaderMethodName(const GeneratorOptions& options, + const FieldDescriptor* field) { + return "jspb.BinaryReader.prototype.read" + + JSBinaryReadWriteMethodName(field, /* is_writer = */ false); +} + +std::string JSBinaryWriterMethodName(const GeneratorOptions& options, + const FieldDescriptor* field) { + if (field->containing_type() && + field->containing_type()->options().message_set_wire_format()) { + return "jspb.BinaryWriter.prototype.writeMessageSet"; + } + return "jspb.BinaryWriter.prototype.write" + + JSBinaryReadWriteMethodName(field, /* is_writer = */ true); +} + +std::string JSTypeTag(const FieldDescriptor* desc) { + switch (desc->type()) { + case FieldDescriptor::TYPE_DOUBLE: + case FieldDescriptor::TYPE_FLOAT: + return "Float"; + case FieldDescriptor::TYPE_INT32: + case FieldDescriptor::TYPE_UINT32: + case FieldDescriptor::TYPE_INT64: + case FieldDescriptor::TYPE_UINT64: + case FieldDescriptor::TYPE_FIXED32: + case FieldDescriptor::TYPE_FIXED64: + case FieldDescriptor::TYPE_SINT32: + case FieldDescriptor::TYPE_SINT64: + case FieldDescriptor::TYPE_SFIXED32: + case FieldDescriptor::TYPE_SFIXED64: + if (IsIntegralFieldWithStringJSType(desc)) { + return "StringInt"; + } else { + return "Int"; + } + case FieldDescriptor::TYPE_BOOL: + return "Boolean"; + case FieldDescriptor::TYPE_STRING: + return "String"; + case FieldDescriptor::TYPE_BYTES: + return "Bytes"; + case FieldDescriptor::TYPE_ENUM: + return "Enum"; + default: + assert(false); + } + return ""; +} + +bool HasRepeatedFields(const GeneratorOptions& options, + const Descriptor* desc) { + for (int i = 0; i < desc->field_count(); i++) { + if (desc->field(i)->is_repeated() && !desc->field(i)->is_map()) { + return true; + } + } + return false; +} + +static const char* kRepeatedFieldArrayName = ".repeatedFields_"; + +std::string RepeatedFieldsArrayName(const GeneratorOptions& options, + const Descriptor* desc) { + return HasRepeatedFields(options, desc) + ? (GetMessagePath(options, desc) + kRepeatedFieldArrayName) + : "null"; +} + +bool HasOneofFields(const Descriptor* desc) { + for (int i = 0; i < desc->field_count(); i++) { + if (InRealOneof(desc->field(i))) { + return true; + } + } + return false; +} + +static const char* kOneofGroupArrayName = ".oneofGroups_"; + +std::string OneofFieldsArrayName(const GeneratorOptions& options, + const Descriptor* desc) { + return HasOneofFields(desc) + ? (GetMessagePath(options, desc) + kOneofGroupArrayName) + : "null"; +} + +std::string RepeatedFieldNumberList(const GeneratorOptions& options, + const Descriptor* desc) { + std::vector<std::string> numbers; + for (int i = 0; i < desc->field_count(); i++) { + if (desc->field(i)->is_repeated() && !desc->field(i)->is_map()) { + numbers.push_back(JSFieldIndex(desc->field(i))); + } + } + return "[" + Join(numbers, ",") + "]"; +} + +std::string OneofGroupList(const Descriptor* desc) { + // List of arrays (one per oneof), each of which is a list of field indices + std::vector<std::string> oneof_entries; + for (int i = 0; i < desc->oneof_decl_count(); i++) { + const OneofDescriptor* oneof = desc->oneof_decl(i); + if (IgnoreOneof(oneof)) { + continue; + } + + std::vector<std::string> oneof_fields; + for (int j = 0; j < oneof->field_count(); j++) { + if (IgnoreField(oneof->field(j))) { + continue; + } + oneof_fields.push_back(JSFieldIndex(oneof->field(j))); + } + oneof_entries.push_back("[" + Join(oneof_fields, ",") + "]"); + } + return "[" + Join(oneof_entries, ",") + "]"; +} + +std::string JSOneofArray(const GeneratorOptions& options, + const FieldDescriptor* field) { + return OneofFieldsArrayName(options, field->containing_type()) + "[" + + JSOneofIndex(field->containing_oneof()) + "]"; +} + +std::string RelativeTypeName(const FieldDescriptor* field) { + assert(field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM || + field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE); + // For a field with an enum or message type, compute a name relative to the + // path name of the message type containing this field. + std::string package = field->file()->package(); + std::string containing_type = field->containing_type()->full_name() + "."; + std::string type = (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) + ? field->enum_type()->full_name() + : field->message_type()->full_name(); + + // |prefix| is advanced as we find separators '.' past the common package + // prefix that yield common prefixes in the containing type's name and this + // type's name. + int prefix = 0; + for (int i = 0; i < type.size() && i < containing_type.size(); i++) { + if (type[i] != containing_type[i]) { + break; + } + if (type[i] == '.' && i >= package.size()) { + prefix = i + 1; + } + } + + return type.substr(prefix); +} + +std::string JSExtensionsObjectName(const GeneratorOptions& options, + const FileDescriptor* from_file, + const Descriptor* desc) { + if (desc->full_name() == "google.protobuf.bridge.MessageSet") { + // TODO(haberman): fix this for the kImportCommonJs case. + return "jspb.Message.messageSetExtensions"; + } else { + return MaybeCrossFileRef(options, from_file, desc) + ".extensions"; + } +} + +static const int kMapKeyField = 1; +static const int kMapValueField = 2; + +const FieldDescriptor* MapFieldKey(const FieldDescriptor* field) { + assert(field->is_map()); + return field->message_type()->FindFieldByNumber(kMapKeyField); +} + +const FieldDescriptor* MapFieldValue(const FieldDescriptor* field) { + assert(field->is_map()); + return field->message_type()->FindFieldByNumber(kMapValueField); +} + +std::string FieldDefinition(const GeneratorOptions& options, + const FieldDescriptor* field) { + if (field->is_map()) { + const FieldDescriptor* key_field = MapFieldKey(field); + const FieldDescriptor* value_field = MapFieldValue(field); + std::string key_type = ProtoTypeName(options, key_field); + std::string value_type; + if (value_field->type() == FieldDescriptor::TYPE_ENUM || + value_field->type() == FieldDescriptor::TYPE_MESSAGE) { + value_type = RelativeTypeName(value_field); + } else { + value_type = ProtoTypeName(options, value_field); + } + return StringPrintf("map<%s, %s> %s = %d;", key_type.c_str(), + value_type.c_str(), field->name().c_str(), + field->number()); + } else { + std::string qualifier = + field->is_repeated() ? "repeated" + : (field->is_optional() ? "optional" : "required"); + std::string type, name; + if (field->type() == FieldDescriptor::TYPE_ENUM || + field->type() == FieldDescriptor::TYPE_MESSAGE) { + type = RelativeTypeName(field); + name = field->name(); + } else if (field->type() == FieldDescriptor::TYPE_GROUP) { + type = "group"; + name = field->message_type()->name(); + } else { + type = ProtoTypeName(options, field); + name = field->name(); + } + return StringPrintf("%s %s %s = %d;", qualifier.c_str(), type.c_str(), + name.c_str(), field->number()); + } +} + +std::string FieldComments(const FieldDescriptor* field, BytesMode bytes_mode) { + std::string comments; + if (field->type() == FieldDescriptor::TYPE_BYTES && bytes_mode == BYTES_U8) { + comments += + " * Note that Uint8Array is not supported on all browsers.\n" + " * @see http://caniuse.com/Uint8Array\n"; + } + return comments; +} + +bool ShouldGenerateExtension(const FieldDescriptor* field) { + return field->is_extension() && !IgnoreField(field); +} + +bool HasExtensions(const Descriptor* desc) { + for (int i = 0; i < desc->extension_count(); i++) { + if (ShouldGenerateExtension(desc->extension(i))) { + return true; + } + } + for (int i = 0; i < desc->nested_type_count(); i++) { + if (HasExtensions(desc->nested_type(i))) { + return true; + } + } + return false; +} + +bool HasExtensions(const FileDescriptor* file) { + for (int i = 0; i < file->extension_count(); i++) { + if (ShouldGenerateExtension(file->extension(i))) { + return true; + } + } + for (int i = 0; i < file->message_type_count(); i++) { + if (HasExtensions(file->message_type(i))) { + return true; + } + } + return false; +} + +bool HasMap(const GeneratorOptions& options, const Descriptor* desc) { + for (int i = 0; i < desc->field_count(); i++) { + if (desc->field(i)->is_map()) { + return true; + } + } + for (int i = 0; i < desc->nested_type_count(); i++) { + if (HasMap(options, desc->nested_type(i))) { + return true; + } + } + return false; +} + +bool FileHasMap(const GeneratorOptions& options, const FileDescriptor* desc) { + for (int i = 0; i < desc->message_type_count(); i++) { + if (HasMap(options, desc->message_type(i))) { + return true; + } + } + return false; +} + +bool IsExtendable(const Descriptor* desc) { + return desc->extension_range_count() > 0; +} + +// Returns the max index in the underlying data storage array beyond which the +// extension object is used. +std::string GetPivot(const Descriptor* desc) { + static const int kDefaultPivot = 500; + + // Find the max field number + int max_field_number = 0; + for (int i = 0; i < desc->field_count(); i++) { + if (!IgnoreField(desc->field(i)) && + desc->field(i)->number() > max_field_number) { + max_field_number = desc->field(i)->number(); + } + } + + int pivot = -1; + if (IsExtendable(desc) || (max_field_number >= kDefaultPivot)) { + pivot = ((max_field_number + 1) < kDefaultPivot) ? (max_field_number + 1) + : kDefaultPivot; + } + + return StrCat(pivot); +} + +// Whether this field represents presence. For fields with presence, we +// generate extra methods (clearFoo() and hasFoo()) for this field. +bool HasFieldPresence(const GeneratorOptions& options, + const FieldDescriptor* field) { + // This returns false for repeated fields and maps, but we still do + // generate clearFoo() methods for these through a special case elsewhere. + return field->has_presence(); +} + +// We use this to implement the semantics that same file can be generated +// multiple times, but only the last one keep the short name. Others all use +// long name with extra information to distinguish (For message and enum, the +// extra information is package name, for file level extension, the extra +// information is proto's filename). +// We never actually write the files, but we keep a set of which descriptors +// were the final one for a given filename. +class FileDeduplicator { + public: + explicit FileDeduplicator(const GeneratorOptions& options) {} + + // params: + // filenames: a pair of {short filename, full filename} + // (short filename don't have extra information, full filename + // contains extra information) + // desc: The Descriptor or SCC pointer or EnumDescriptor. + bool AddFile(const std::pair<std::string, std::string> filenames, + const void* desc) { + if (descs_by_shortname_.find(filenames.first) != + descs_by_shortname_.end()) { + // Change old pointer's actual name to full name. + auto short_name_desc = descs_by_shortname_[filenames.first]; + allowed_descs_actual_name_[short_name_desc] = + allowed_descs_full_name_[short_name_desc]; + } + descs_by_shortname_[filenames.first] = desc; + allowed_descs_actual_name_[desc] = filenames.first; + allowed_descs_full_name_[desc] = filenames.second; + + return true; + } + + void GetAllowedMap(std::map<const void*, std::string>* allowed_set) { + *allowed_set = allowed_descs_actual_name_; + } + + private: + // The map that restores all the descs that are using short name as filename. + std::map<std::string, const void*> descs_by_shortname_; + // The final actual filename map. + std::map<const void*, std::string> allowed_descs_actual_name_; + // The full name map. + std::map<const void*, std::string> allowed_descs_full_name_; +}; + +void DepthFirstSearch(const FileDescriptor* file, + std::vector<const FileDescriptor*>* list, + std::set<const FileDescriptor*>* seen) { + if (!seen->insert(file).second) { + return; + } + + // Add all dependencies. + for (int i = 0; i < file->dependency_count(); i++) { + DepthFirstSearch(file->dependency(i), list, seen); + } + + // Add this file. + list->push_back(file); +} + +// A functor for the predicate to remove_if() below. Returns true if a given +// FileDescriptor is not in the given set. +class NotInSet { + public: + explicit NotInSet(const std::set<const FileDescriptor*>& file_set) + : file_set_(file_set) {} + + bool operator()(const FileDescriptor* file) { + return file_set_.count(file) == 0; + } + + private: + const std::set<const FileDescriptor*>& file_set_; +}; + +// This function generates an ordering of the input FileDescriptors that matches +// the logic of the old code generator. The order is significant because two +// different input files can generate the same output file, and the last one +// needs to win. +void GenerateJspbFileOrder(const std::vector<const FileDescriptor*>& input, + std::vector<const FileDescriptor*>* ordered) { + // First generate an ordering of all reachable files (including dependencies) + // with depth-first search. This mimics the behavior of --include_imports, + // which is what the old codegen used. + ordered->clear(); + std::set<const FileDescriptor*> seen; + std::set<const FileDescriptor*> input_set; + for (int i = 0; i < input.size(); i++) { + DepthFirstSearch(input[i], ordered, &seen); + input_set.insert(input[i]); + } + + // Now remove the entries that are not actually in our input list. + ordered->erase( + std::remove_if(ordered->begin(), ordered->end(), NotInSet(input_set)), + ordered->end()); +} + +// If we're generating code in file-per-type mode, avoid overwriting files +// by choosing the last descriptor that writes each filename and permitting +// only those to generate code. + +struct DepsGenerator { + std::vector<const Descriptor*> operator()(const Descriptor* desc) const { + std::vector<const Descriptor*> deps; + auto maybe_add = [&](const Descriptor* d) { + if (d) deps.push_back(d); + }; + for (int i = 0; i < desc->field_count(); i++) { + if (!IgnoreField(desc->field(i))) { + maybe_add(desc->field(i)->message_type()); + } + } + for (int i = 0; i < desc->extension_count(); i++) { + maybe_add(desc->extension(i)->message_type()); + maybe_add(desc->extension(i)->containing_type()); + } + for (int i = 0; i < desc->nested_type_count(); i++) { + maybe_add(desc->nested_type(i)); + } + maybe_add(desc->containing_type()); + + return deps; + } +}; + +bool GenerateJspbAllowedMap(const GeneratorOptions& options, + const std::vector<const FileDescriptor*>& files, + std::map<const void*, std::string>* allowed_set, + SCCAnalyzer<DepsGenerator>* analyzer) { + std::vector<const FileDescriptor*> files_ordered; + GenerateJspbFileOrder(files, &files_ordered); + + // Choose the last descriptor for each filename. + FileDeduplicator dedup(options); + std::set<const SCC*> added; + for (int i = 0; i < files_ordered.size(); i++) { + for (int j = 0; j < files_ordered[i]->message_type_count(); j++) { + const Descriptor* desc = files_ordered[i]->message_type(j); + if (added.insert(analyzer->GetSCC(desc)).second && + !dedup.AddFile( + std::make_pair( + GetMessagesFileName(options, analyzer->GetSCC(desc), false), + GetMessagesFileName(options, analyzer->GetSCC(desc), true)), + analyzer->GetSCC(desc))) { + return false; + } + } + for (int j = 0; j < files_ordered[i]->enum_type_count(); j++) { + const EnumDescriptor* desc = files_ordered[i]->enum_type(j); + if (!dedup.AddFile(std::make_pair(GetEnumFileName(options, desc, false), + GetEnumFileName(options, desc, true)), + desc)) { + return false; + } + } + + // Pull out all free-floating extensions and generate files for those too. + bool has_extension = false; + + for (int j = 0; j < files_ordered[i]->extension_count(); j++) { + if (ShouldGenerateExtension(files_ordered[i]->extension(j))) { + has_extension = true; + } + } + + if (has_extension) { + if (!dedup.AddFile( + std::make_pair( + GetExtensionFileName(options, files_ordered[i], false), + GetExtensionFileName(options, files_ordered[i], true)), + files_ordered[i])) { + return false; + } + } + } + + dedup.GetAllowedMap(allowed_set); + + return true; +} + +// Embeds base64 encoded GeneratedCodeInfo proto in a comment at the end of +// file. +void EmbedCodeAnnotations(const GeneratedCodeInfo& annotations, + io::Printer* printer) { + // Serialize annotations proto into base64 string. + std::string meta_content; + annotations.SerializeToString(&meta_content); + std::string meta_64; + Base64Escape(meta_content, &meta_64); + + // Print base64 encoded annotations at the end of output file in + // a comment. + printer->Print("\n// Below is base64 encoded GeneratedCodeInfo proto"); + printer->Print("\n// $encoded_proto$\n", "encoded_proto", meta_64); +} + +bool IsWellKnownTypeFile(const FileDescriptor* file) { + return HasPrefixString(file->name(), "google/protobuf/"); +} + +} // anonymous namespace + +void Generator::GenerateHeader(const GeneratorOptions& options, + const FileDescriptor* file, + io::Printer* printer) const { + if (file != nullptr) { + printer->Print("// source: $filename$\n", "filename", file->name()); + } + printer->Print( + "/**\n" + " * @fileoverview\n" + " * @enhanceable\n" + // TODO(b/152440355): requireType/requires diverged from internal version. + " * @suppress {missingRequire} reports error on implicit type usages.\n" + " * @suppress {messageConventions} JS Compiler reports an " + "error if a variable or\n" + " * field starts with 'MSG_' and isn't a translatable " + "message.\n" + " * @public\n" + " */\n" + "// GENERATED CODE -- DO NOT EDIT!\n" + "/* eslint-disable */\n" + "// @ts-nocheck\n" + "\n"); +} + +void Generator::FindProvidesForFile(const GeneratorOptions& options, + io::Printer* printer, + const FileDescriptor* file, + std::set<std::string>* provided) const { + for (int i = 0; i < file->message_type_count(); i++) { + FindProvidesForMessage(options, printer, file->message_type(i), provided); + } + for (int i = 0; i < file->enum_type_count(); i++) { + FindProvidesForEnum(options, printer, file->enum_type(i), provided); + } +} + +void Generator::FindProvides(const GeneratorOptions& options, + io::Printer* printer, + const std::vector<const FileDescriptor*>& files, + std::set<std::string>* provided) const { + for (int i = 0; i < files.size(); i++) { + FindProvidesForFile(options, printer, files[i], provided); + } + + printer->Print("\n"); +} + +void FindProvidesForOneOfEnum(const GeneratorOptions& options, + const OneofDescriptor* oneof, + std::set<std::string>* provided) { + std::string name = GetMessagePath(options, oneof->containing_type()) + "." + + JSOneofName(oneof) + "Case"; + provided->insert(name); +} + +void FindProvidesForOneOfEnums(const GeneratorOptions& options, + io::Printer* printer, const Descriptor* desc, + std::set<std::string>* provided) { + if (HasOneofFields(desc)) { + for (int i = 0; i < desc->oneof_decl_count(); i++) { + if (IgnoreOneof(desc->oneof_decl(i))) { + continue; + } + FindProvidesForOneOfEnum(options, desc->oneof_decl(i), provided); + } + } +} + +void Generator::FindProvidesForMessage(const GeneratorOptions& options, + io::Printer* printer, + const Descriptor* desc, + std::set<std::string>* provided) const { + if (IgnoreMessage(desc)) { + return; + } + + std::string name = GetMessagePath(options, desc); + provided->insert(name); + + for (int i = 0; i < desc->enum_type_count(); i++) { + FindProvidesForEnum(options, printer, desc->enum_type(i), provided); + } + + FindProvidesForOneOfEnums(options, printer, desc, provided); + + for (int i = 0; i < desc->nested_type_count(); i++) { + FindProvidesForMessage(options, printer, desc->nested_type(i), provided); + } +} +void Generator::FindProvidesForEnum(const GeneratorOptions& options, + io::Printer* printer, + const EnumDescriptor* enumdesc, + std::set<std::string>* provided) const { + std::string name = GetEnumPath(options, enumdesc); + provided->insert(name); +} + +void Generator::FindProvidesForFields( + const GeneratorOptions& options, io::Printer* printer, + const std::vector<const FieldDescriptor*>& fields, + std::set<std::string>* provided) const { + for (int i = 0; i < fields.size(); i++) { + const FieldDescriptor* field = fields[i]; + + if (IgnoreField(field)) { + continue; + } + + std::string name = GetNamespace(options, field->file()) + "." + + JSObjectFieldName(options, field); + provided->insert(name); + } +} + +void Generator::GenerateProvides(const GeneratorOptions& options, + io::Printer* printer, + std::set<std::string>* provided) const { + for (std::set<std::string>::iterator it = provided->begin(); + it != provided->end(); ++it) { + if (options.import_style == GeneratorOptions::kImportClosure) { + printer->Print("goog.provide('$name$');\n", "name", *it); + } else { + // We aren't using Closure's import system, but we use goog.exportSymbol() + // to construct the expected tree of objects, eg. + // + // goog.exportSymbol('foo.bar.Baz', null, this); + // + // // Later generated code expects foo.bar = {} to exist: + // foo.bar.Baz = function() { /* ... */ } + + // Do not use global scope in strict mode + if (options.import_style == GeneratorOptions::kImportCommonJsStrict) { + std::string namespaceObject = *it; + // Remove "proto." from the namespace object + GOOGLE_CHECK_EQ(0, namespaceObject.compare(0, 6, "proto.")); + namespaceObject.erase(0, 6); + printer->Print("goog.exportSymbol('$name$', null, proto);\n", "name", + namespaceObject); + } else { + printer->Print("goog.exportSymbol('$name$', null, global);\n", "name", + *it); + } + } + } +} + +void Generator::GenerateRequiresForSCC(const GeneratorOptions& options, + io::Printer* printer, const SCC* scc, + std::set<std::string>* provided) const { + std::set<std::string> required; + std::set<std::string> forwards; + bool have_message = false; + bool has_extension = false; + bool has_map = false; + for (auto desc : scc->descriptors) { + if (desc->containing_type() == nullptr) { + FindRequiresForMessage(options, desc, &required, &forwards, + &have_message); + has_extension = (has_extension || HasExtensions(desc)); + has_map = (has_map || HasMap(options, desc)); + } + } + + GenerateRequiresImpl(options, printer, &required, &forwards, provided, + /* require_jspb = */ have_message, + /* require_extension = */ has_extension, + /* require_map = */ has_map); +} + +void Generator::GenerateRequiresForLibrary( + const GeneratorOptions& options, io::Printer* printer, + const std::vector<const FileDescriptor*>& files, + std::set<std::string>* provided) const { + GOOGLE_CHECK_EQ(options.import_style, GeneratorOptions::kImportClosure); + // For Closure imports we need to import every message type individually. + std::set<std::string> required; + std::set<std::string> forwards; + bool have_extensions = false; + bool have_map = false; + bool have_message = false; + + for (int i = 0; i < files.size(); i++) { + for (int j = 0; j < files[i]->message_type_count(); j++) { + const Descriptor* desc = files[i]->message_type(j); + if (!IgnoreMessage(desc)) { + FindRequiresForMessage(options, desc, &required, &forwards, + &have_message); + } + } + + if (!have_extensions && HasExtensions(files[i])) { + have_extensions = true; + } + + if (!have_map && FileHasMap(options, files[i])) { + have_map = true; + } + + for (int j = 0; j < files[i]->extension_count(); j++) { + const FieldDescriptor* extension = files[i]->extension(j); + if (IgnoreField(extension)) { + continue; + } + if (extension->containing_type()->full_name() != + "google.protobuf.bridge.MessageSet") { + required.insert(GetMessagePath(options, extension->containing_type())); + } + FindRequiresForField(options, extension, &required, &forwards); + have_extensions = true; + } + } + + GenerateRequiresImpl(options, printer, &required, &forwards, provided, + /* require_jspb = */ have_message, + /* require_extension = */ have_extensions, + /* require_map = */ have_map); +} + +void Generator::GenerateRequiresForExtensions( + const GeneratorOptions& options, io::Printer* printer, + const std::vector<const FieldDescriptor*>& fields, + std::set<std::string>* provided) const { + std::set<std::string> required; + std::set<std::string> forwards; + for (int i = 0; i < fields.size(); i++) { + const FieldDescriptor* field = fields[i]; + if (IgnoreField(field)) { + continue; + } + FindRequiresForExtension(options, field, &required, &forwards); + } + + GenerateRequiresImpl(options, printer, &required, &forwards, provided, + /* require_jspb = */ false, + /* require_extension = */ fields.size() > 0, + /* require_map = */ false); +} + +void Generator::GenerateRequiresImpl(const GeneratorOptions& options, + io::Printer* printer, + std::set<std::string>* required, + std::set<std::string>* forwards, + std::set<std::string>* provided, + bool require_jspb, bool require_extension, + bool require_map) const { + if (require_jspb) { + required->insert("jspb.Message"); + required->insert("jspb.BinaryReader"); + required->insert("jspb.BinaryWriter"); + } + if (require_extension) { + required->insert("jspb.ExtensionFieldBinaryInfo"); + required->insert("jspb.ExtensionFieldInfo"); + } + if (require_map) { + required->insert("jspb.Map"); + } + + std::set<std::string>::iterator it; + for (it = required->begin(); it != required->end(); ++it) { + if (provided->find(*it) != provided->end()) { + continue; + } + printer->Print("goog.require('$name$');\n", "name", *it); + } + + printer->Print("\n"); + + for (it = forwards->begin(); it != forwards->end(); ++it) { + if (provided->find(*it) != provided->end()) { + continue; + } + printer->Print("goog.forwardDeclare('$name$');\n", "name", *it); + } +} + +bool NamespaceOnly(const Descriptor* desc) { return false; } + +void Generator::FindRequiresForMessage(const GeneratorOptions& options, + const Descriptor* desc, + std::set<std::string>* required, + std::set<std::string>* forwards, + bool* have_message) const { + if (!NamespaceOnly(desc)) { + *have_message = true; + for (int i = 0; i < desc->field_count(); i++) { + const FieldDescriptor* field = desc->field(i); + if (IgnoreField(field)) { + continue; + } + FindRequiresForField(options, field, required, forwards); + } + } + + for (int i = 0; i < desc->extension_count(); i++) { + const FieldDescriptor* field = desc->extension(i); + if (IgnoreField(field)) { + continue; + } + FindRequiresForExtension(options, field, required, forwards); + } + + for (int i = 0; i < desc->nested_type_count(); i++) { + FindRequiresForMessage(options, desc->nested_type(i), required, forwards, + have_message); + } +} + +void Generator::FindRequiresForField(const GeneratorOptions& options, + const FieldDescriptor* field, + std::set<std::string>* required, + std::set<std::string>* forwards) const { + if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM && + // N.B.: file-level extensions with enum type do *not* create + // dependencies, as per original codegen. + !(field->is_extension() && field->extension_scope() == nullptr)) { + if (options.add_require_for_enums) { + required->insert(GetEnumPath(options, field->enum_type())); + } else { + forwards->insert(GetEnumPath(options, field->enum_type())); + } + } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + if (!IgnoreMessage(field->message_type())) { + required->insert(GetMessagePath(options, field->message_type())); + } + } +} + +void Generator::FindRequiresForExtension( + const GeneratorOptions& options, const FieldDescriptor* field, + std::set<std::string>* required, std::set<std::string>* forwards) const { + if (field->containing_type()->full_name() != + "google.protobuf.bridge.MessageSet") { + required->insert(GetMessagePath(options, field->containing_type())); + } + FindRequiresForField(options, field, required, forwards); +} + +void Generator::GenerateTestOnly(const GeneratorOptions& options, + io::Printer* printer) const { + if (options.testonly) { + printer->Print("goog.setTestOnly();\n\n"); + } + printer->Print("\n"); +} + +void Generator::GenerateClassesAndEnums(const GeneratorOptions& options, + io::Printer* printer, + const FileDescriptor* file) const { + for (int i = 0; i < file->message_type_count(); i++) { + GenerateClassConstructorAndDeclareExtensionFieldInfo(options, printer, + file->message_type(i)); + } + for (int i = 0; i < file->message_type_count(); i++) { + GenerateClass(options, printer, file->message_type(i)); + } + for (int i = 0; i < file->enum_type_count(); i++) { + GenerateEnum(options, printer, file->enum_type(i)); + } +} + +void Generator::GenerateClass(const GeneratorOptions& options, + io::Printer* printer, + const Descriptor* desc) const { + if (IgnoreMessage(desc)) { + return; + } + + if (!NamespaceOnly(desc)) { + printer->Print("\n"); + GenerateClassFieldInfo(options, printer, desc); + + GenerateClassToObject(options, printer, desc); + // These must come *before* the extension-field info generation in + // GenerateClassRegistration so that references to the binary + // serialization/deserialization functions may be placed in the extension + // objects. + GenerateClassDeserializeBinary(options, printer, desc); + GenerateClassSerializeBinary(options, printer, desc); + } + + // Recurse on nested types. These must come *before* the extension-field + // info generation in GenerateClassRegistration so that extensions that + // reference nested types proceed the definitions of the nested types. + for (int i = 0; i < desc->enum_type_count(); i++) { + GenerateEnum(options, printer, desc->enum_type(i)); + } + for (int i = 0; i < desc->nested_type_count(); i++) { + GenerateClass(options, printer, desc->nested_type(i)); + } + + if (!NamespaceOnly(desc)) { + GenerateClassRegistration(options, printer, desc); + GenerateClassFields(options, printer, desc); + + if (options.import_style != GeneratorOptions::kImportClosure) { + for (int i = 0; i < desc->extension_count(); i++) { + GenerateExtension(options, printer, desc->extension(i)); + } + } + } +} + +void Generator::GenerateClassConstructor(const GeneratorOptions& options, + io::Printer* printer, + const Descriptor* desc) const { + printer->Print( + "/**\n" + " * Generated by JsPbCodeGenerator.\n" + " * @param {Array=} opt_data Optional initial data array, typically " + "from a\n" + " * server response, or constructed directly in Javascript. The array " + "is used\n" + " * in place and becomes part of the constructed object. It is not " + "cloned.\n" + " * If no data is provided, the constructed object will be empty, but " + "still\n" + " * valid.\n" + " * @extends {jspb.Message}\n" + " * @constructor\n" + " */\n" + "$classprefix$$classname$ = function(opt_data) {\n", + "classprefix", GetMessagePathPrefix(options, desc), "classname", + desc->name()); + printer->Annotate("classname", desc); + std::string message_id = GetMessageId(desc); + printer->Print( + " jspb.Message.initialize(this, opt_data, $messageId$, $pivot$, " + "$rptfields$, $oneoffields$);\n", + "messageId", + !message_id.empty() ? ("'" + message_id + "'") + : (IsResponse(desc) ? "''" : "0"), + "pivot", GetPivot(desc), "rptfields", + RepeatedFieldsArrayName(options, desc), "oneoffields", + OneofFieldsArrayName(options, desc)); + printer->Print( + "};\n" + "goog.inherits($classname$, jspb.Message);\n" + "if (goog.DEBUG && !COMPILED) {\n" + // displayName overrides Function.prototype.displayName + // http://google3/javascript/externs/es3.js?l=511 + " /**\n" + " * @public\n" + " * @override\n" + " */\n" + " $classname$.displayName = '$classname$';\n" + "}\n", + "classname", GetMessagePath(options, desc)); +} + +void Generator::GenerateClassConstructorAndDeclareExtensionFieldInfo( + const GeneratorOptions& options, io::Printer* printer, + const Descriptor* desc) const { + if (!NamespaceOnly(desc)) { + GenerateClassConstructor(options, printer, desc); + if (IsExtendable(desc) && + desc->full_name() != "google.protobuf.bridge.MessageSet") { + GenerateClassExtensionFieldInfo(options, printer, desc); + } + } + for (int i = 0; i < desc->nested_type_count(); i++) { + if (!IgnoreMessage(desc->nested_type(i))) { + GenerateClassConstructorAndDeclareExtensionFieldInfo( + options, printer, desc->nested_type(i)); + } + } +} + +void Generator::GenerateClassFieldInfo(const GeneratorOptions& options, + io::Printer* printer, + const Descriptor* desc) const { + if (HasRepeatedFields(options, desc)) { + printer->Print( + "/**\n" + " * List of repeated fields within this message type.\n" + " * @private {!Array<number>}\n" + " * @const\n" + " */\n" + "$classname$$rptfieldarray$ = $rptfields$;\n" + "\n", + "classname", GetMessagePath(options, desc), "rptfieldarray", + kRepeatedFieldArrayName, "rptfields", + RepeatedFieldNumberList(options, desc)); + } + + if (HasOneofFields(desc)) { + printer->Print( + "/**\n" + " * Oneof group definitions for this message. Each group defines the " + "field\n" + " * numbers belonging to that group. When of these fields' value is " + "set, all\n" + " * other fields in the group are cleared. During deserialization, if " + "multiple\n" + " * fields are encountered for a group, only the last value seen will " + "be kept.\n" + " * @private {!Array<!Array<number>>}\n" + " * @const\n" + " */\n" + "$classname$$oneofgrouparray$ = $oneofgroups$;\n" + "\n", + "classname", GetMessagePath(options, desc), "oneofgrouparray", + kOneofGroupArrayName, "oneofgroups", OneofGroupList(desc)); + + for (int i = 0; i < desc->oneof_decl_count(); i++) { + if (IgnoreOneof(desc->oneof_decl(i))) { + continue; + } + GenerateOneofCaseDefinition(options, printer, desc->oneof_decl(i)); + } + } +} + +void Generator::GenerateClassXid(const GeneratorOptions& options, + io::Printer* printer, + const Descriptor* desc) const { + printer->Print( + "\n" + "\n" + "$class$.prototype.messageXid = xid('$class$');\n", + "class", GetMessagePath(options, desc)); +} + +void Generator::GenerateOneofCaseDefinition( + const GeneratorOptions& options, io::Printer* printer, + const OneofDescriptor* oneof) const { + printer->Print( + "/**\n" + " * @enum {number}\n" + " */\n" + "$classname$.$oneof$Case = {\n" + " $upcase$_NOT_SET: 0", + "classname", GetMessagePath(options, oneof->containing_type()), "oneof", + JSOneofName(oneof), "upcase", ToEnumCase(oneof->name())); + + for (int i = 0; i < oneof->field_count(); i++) { + if (IgnoreField(oneof->field(i))) { + continue; + } + + printer->Print( + ",\n" + " $upcase$: $number$", + "upcase", ToEnumCase(oneof->field(i)->name()), "number", + JSFieldIndex(oneof->field(i))); + printer->Annotate("upcase", oneof->field(i)); + } + + printer->Print( + "\n" + "};\n" + "\n" + "/**\n" + " * @return {$class$.$oneof$Case}\n" + " */\n" + "$class$.prototype.get$oneof$Case = function() {\n" + " return /** @type {$class$.$oneof$Case} */(jspb.Message." + "computeOneofCase(this, $class$.oneofGroups_[$oneofindex$]));\n" + "};\n" + "\n", + "class", GetMessagePath(options, oneof->containing_type()), "oneof", + JSOneofName(oneof), "oneofindex", JSOneofIndex(oneof)); +} + +void Generator::GenerateClassToObject(const GeneratorOptions& options, + io::Printer* printer, + const Descriptor* desc) const { + printer->Print( + "\n" + "\n" + "if (jspb.Message.GENERATE_TO_OBJECT) {\n" + "/**\n" + " * Creates an object representation of this proto.\n" + " * Field names that are reserved in JavaScript and will be renamed to " + "pb_name.\n" + " * Optional fields that are not set will be set to undefined.\n" + " * To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.\n" + " * For the list of reserved names please see:\n" + " * net/proto2/compiler/js/internal/generator.cc#kKeyword.\n" + " * @param {boolean=} opt_includeInstance Deprecated. whether to include " + "the\n" + " * JSPB instance for transitional soy proto support:\n" + " * http://goto/soy-param-migration\n" + " * @return {!Object}\n" + " */\n" + "$classname$.prototype.toObject = function(opt_includeInstance) {\n" + " return $classname$.toObject(opt_includeInstance, this);\n" + "};\n" + "\n" + "\n" + "/**\n" + " * Static version of the {@see toObject} method.\n" + " * @param {boolean|undefined} includeInstance Deprecated. Whether to " + "include\n" + " * the JSPB instance for transitional soy proto support:\n" + " * http://goto/soy-param-migration\n" + " * @param {!$classname$} msg The msg instance to transform.\n" + " * @return {!Object}\n" + " * @suppress {unusedLocalVariables} f is only used for nested messages\n" + " */\n" + "$classname$.toObject = function(includeInstance, msg) {\n" + " var f, obj = {", + "classname", GetMessagePath(options, desc)); + + bool first = true; + for (int i = 0; i < desc->field_count(); i++) { + const FieldDescriptor* field = desc->field(i); + if (IgnoreField(field)) { + continue; + } + + if (!first) { + printer->Print(",\n "); + } else { + printer->Print("\n "); + first = false; + } + + GenerateClassFieldToObject(options, printer, field); + } + + if (!first) { + printer->Print("\n };\n\n"); + } else { + printer->Print("\n\n };\n\n"); + } + + if (IsExtendable(desc)) { + printer->Print( + " jspb.Message.toObjectExtension(/** @type {!jspb.Message} */ (msg), " + "obj,\n" + " $extObject$, $class$.prototype.getExtension,\n" + " includeInstance);\n", + "extObject", JSExtensionsObjectName(options, desc->file(), desc), + "class", GetMessagePath(options, desc)); + } + + printer->Print( + " if (includeInstance) {\n" + " obj.$$jspbMessageInstance = msg;\n" + " }\n" + " return obj;\n" + "};\n" + "}\n" + "\n" + "\n", + "classname", GetMessagePath(options, desc)); +} + +void Generator::GenerateFieldValueExpression(io::Printer* printer, + const char* obj_reference, + const FieldDescriptor* field, + bool use_default) const { + const bool is_float_or_double = + field->cpp_type() == FieldDescriptor::CPPTYPE_FLOAT || + field->cpp_type() == FieldDescriptor::CPPTYPE_DOUBLE; + const bool is_boolean = field->cpp_type() == FieldDescriptor::CPPTYPE_BOOL; + + const std::string with_default = use_default ? "WithDefault" : ""; + const std::string default_arg = + use_default ? StrCat(", ", JSFieldDefault(field)) : ""; + const std::string cardinality = field->is_repeated() ? "Repeated" : ""; + std::string type = ""; + if (is_float_or_double) { + type = "FloatingPoint"; + } + if (is_boolean) { + type = "Boolean"; + } + + // Prints the appropriate function, among: + // - getField + // - getBooleanField + // - getFloatingPointField => Replaced by getOptionalFloatingPointField to + // preserve backward compatibility. + // - getFieldWithDefault + // - getBooleanFieldWithDefault + // - getFloatingPointFieldWithDefault + // - getRepeatedField + // - getRepeatedBooleanField + // - getRepeatedFloatingPointField + if (is_float_or_double && !field->is_repeated() && !use_default) { + printer->Print( + "jspb.Message.getOptionalFloatingPointField($obj$, " + "$index$$default$)", + "obj", obj_reference, "index", JSFieldIndex(field), "default", + default_arg); + } else { + printer->Print( + "jspb.Message.get$cardinality$$type$Field$with_default$($obj$, " + "$index$$default$)", + "cardinality", cardinality, "type", type, "with_default", with_default, + "obj", obj_reference, "index", JSFieldIndex(field), "default", + default_arg); + } +} + +void Generator::GenerateClassFieldToObject(const GeneratorOptions& options, + io::Printer* printer, + const FieldDescriptor* field) const { + printer->Print("$fieldname$: ", "fieldname", + JSObjectFieldName(options, field)); + + if (field->is_map()) { + const FieldDescriptor* value_field = MapFieldValue(field); + // If the map values are of a message type, we must provide their static + // toObject() method; otherwise we pass undefined for that argument. + std::string value_to_object; + if (value_field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + value_to_object = + GetMessagePath(options, value_field->message_type()) + ".toObject"; + } else { + value_to_object = "undefined"; + } + printer->Print( + "(f = msg.get$name$()) ? f.toObject(includeInstance, $valuetoobject$) " + ": []", + "name", JSGetterName(options, field), "valuetoobject", value_to_object); + } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + // Message field. + if (field->is_repeated()) { + { + printer->Print( + "jspb.Message.toObjectList(msg.get$getter$(),\n" + " $type$.toObject, includeInstance)", + "getter", JSGetterName(options, field), "type", + SubmessageTypeRef(options, field)); + } + } else { + printer->Print( + "(f = msg.get$getter$()) && " + "$type$.toObject(includeInstance, f)", + "getter", JSGetterName(options, field), "type", + SubmessageTypeRef(options, field)); + } + } else if (field->type() == FieldDescriptor::TYPE_BYTES) { + // For bytes fields we want to always return the B64 data. + printer->Print("msg.get$getter$()", "getter", + JSGetterName(options, field, BYTES_B64)); + } else { + bool use_default = field->has_default_value(); + + if (field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3 && + // Repeated fields get initialized to their default in the constructor + // (why?), so we emit a plain getField() call for them. + !field->is_repeated()) { + // Proto3 puts all defaults (including implicit defaults) in toObject(). + // But for proto2 we leave the existing semantics unchanged: unset fields + // without default are unset. + use_default = true; + } + + // We don't implement this by calling the accessors, because the semantics + // of the accessors are changing independently of the toObject() semantics. + // We are migrating the accessors to return defaults instead of null, but + // it may take longer to migrate toObject (or we might not want to do it at + // all). So we want to generate independent code. + // The accessor for unset optional values without default should return + // null. Those are converted to undefined in the generated object. + if (!use_default) { + printer->Print("(f = "); + } + GenerateFieldValueExpression(printer, "msg", field, use_default); + if (!use_default) { + printer->Print(") == null ? undefined : f"); + } + } +} + +void Generator::GenerateObjectTypedef(const GeneratorOptions& options, + io::Printer* printer, + const Descriptor* desc) const { + // TODO(b/122687752): Consider renaming nested messages called ObjectFormat + // to prevent collisions. + const std::string type_name = GetMessagePath(options, desc) + ".ObjectFormat"; + + printer->Print( + "/**\n" + " * The raw object form of $messageName$ as accepted by the `fromObject` " + "method.\n" + " * @record\n" + " */\n" + "$typeName$ = function() {\n", + "messageName", desc->name(), "typeName", type_name); + + for (int i = 0; i < desc->field_count(); i++) { + if (i > 0) { + printer->Print("\n"); + } + printer->Print( + " /** @type {$fieldType$|undefined} */\n" + " this.$fieldName$;\n", + "fieldName", JSObjectFieldName(options, desc->field(i)), + // TODO(b/121097361): Add type checking for field values. + "fieldType", "?"); + } + + printer->Print("};\n\n"); +} + +void Generator::GenerateClassFromObject(const GeneratorOptions& options, + io::Printer* printer, + const Descriptor* desc) const { + printer->Print("if (jspb.Message.GENERATE_FROM_OBJECT) {\n\n"); + + GenerateObjectTypedef(options, printer, desc); + + printer->Print( + "/**\n" + " * Loads data from an object into a new instance of this proto.\n" + " * @param {!$classname$.ObjectFormat} obj\n" + " * The object representation of this proto to load the data from.\n" + " * @return {!$classname$}\n" + " */\n" + "$classname$.fromObject = function(obj) {\n" + " var msg = new $classname$();\n", + "classname", GetMessagePath(options, desc)); + + for (int i = 0; i < desc->field_count(); i++) { + const FieldDescriptor* field = desc->field(i); + if (!IgnoreField(field)) { + GenerateClassFieldFromObject(options, printer, field); + } + } + + printer->Print( + " return msg;\n" + "};\n" + "}\n\n"); +} + +void Generator::GenerateClassFieldFromObject( + const GeneratorOptions& options, io::Printer* printer, + const FieldDescriptor* field) const { + if (field->is_map()) { + const FieldDescriptor* value_field = MapFieldValue(field); + if (value_field->type() == FieldDescriptor::TYPE_MESSAGE) { + // Since the map values are of message type, we have to do some extra work + // to recursively call fromObject() on them before setting the map field. + printer->Print( + " obj.$name$ && jspb.Message.setWrapperField(\n" + " msg, $index$, jspb.Map.fromObject(obj.$name$, $fieldclass$, " + "$fieldclass$.fromObject));\n", + "name", JSObjectFieldName(options, field), "index", + JSFieldIndex(field), "fieldclass", + GetMessagePath(options, value_field->message_type())); + } else { + // `msg` is a newly-constructed message object that has not yet built any + // map containers wrapping underlying arrays, so we can simply directly + // set the array here without fear of a stale wrapper. + printer->Print( + " obj.$name$ && " + "jspb.Message.setField(msg, $index$, obj.$name$);\n", + "name", JSObjectFieldName(options, field), "index", + JSFieldIndex(field)); + } + } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + // Message field (singular or repeated) + if (field->is_repeated()) { + { + printer->Print( + " obj.$name$ && " + "jspb.Message.setRepeatedWrapperField(\n" + " msg, $index$, obj.$name$.map(\n" + " $fieldclass$.fromObject));\n", + "name", JSObjectFieldName(options, field), "index", + JSFieldIndex(field), "fieldclass", + SubmessageTypeRef(options, field)); + } + } else { + printer->Print( + " obj.$name$ && jspb.Message.setWrapperField(\n" + " msg, $index$, $fieldclass$.fromObject(obj.$name$));\n", + "name", JSObjectFieldName(options, field), "index", + JSFieldIndex(field), "fieldclass", SubmessageTypeRef(options, field)); + } + } else { + // Simple (primitive) field. + printer->Print( + " obj.$name$ != null && jspb.Message.setField(msg, $index$, " + "obj.$name$);\n", + "name", JSObjectFieldName(options, field), "index", + JSFieldIndex(field)); + } +} + +void Generator::GenerateClassRegistration(const GeneratorOptions& options, + io::Printer* printer, + const Descriptor* desc) const { + // Register any extensions defined inside this message type. + for (int i = 0; i < desc->extension_count(); i++) { + const FieldDescriptor* extension = desc->extension(i); + if (ShouldGenerateExtension(extension)) { + GenerateExtension(options, printer, extension); + } + } +} + +void Generator::GenerateClassFields(const GeneratorOptions& options, + io::Printer* printer, + const Descriptor* desc) const { + for (int i = 0; i < desc->field_count(); i++) { + if (!IgnoreField(desc->field(i))) { + GenerateClassField(options, printer, desc->field(i)); + } + } +} + +void GenerateBytesWrapper(const GeneratorOptions& options, io::Printer* printer, + const FieldDescriptor* field, BytesMode bytes_mode) { + std::string type = + JSFieldTypeAnnotation(options, field, + /* is_setter_argument = */ false, + /* force_present = */ false, + /* singular_if_not_packed = */ false, bytes_mode); + printer->Print( + "/**\n" + " * $fielddef$\n" + "$comment$" + " * This is a type-conversion wrapper around `get$defname$()`\n" + " * @return {$type$}\n" + " */\n" + "$class$.prototype.get$name$ = function() {\n" + " return /** @type {$type$} */ (jspb.Message.bytes$list$As$suffix$(\n" + " this.get$defname$()));\n" + "};\n" + "\n" + "\n", + "fielddef", FieldDefinition(options, field), "comment", + FieldComments(field, bytes_mode), "type", type, "class", + GetMessagePath(options, field->containing_type()), "name", + JSGetterName(options, field, bytes_mode), "list", + field->is_repeated() ? "List" : "", "suffix", + JSByteGetterSuffix(bytes_mode), "defname", + JSGetterName(options, field, BYTES_DEFAULT)); +} + +void Generator::GenerateClassField(const GeneratorOptions& options, + io::Printer* printer, + const FieldDescriptor* field) const { + if (field->is_map()) { + const FieldDescriptor* key_field = MapFieldKey(field); + const FieldDescriptor* value_field = MapFieldValue(field); + // Map field: special handling to instantiate the map object on demand. + std::string key_type = + JSFieldTypeAnnotation(options, key_field, + /* is_setter_argument = */ false, + /* force_present = */ true, + /* singular_if_not_packed = */ false); + std::string value_type = + JSFieldTypeAnnotation(options, value_field, + /* is_setter_argument = */ false, + /* force_present = */ true, + /* singular_if_not_packed = */ false); + + printer->Print( + "/**\n" + " * $fielddef$\n" + " * @param {boolean=} opt_noLazyCreate Do not create the map if\n" + " * empty, instead returning `undefined`\n" + " * @return {!jspb.Map<$keytype$,$valuetype$>}\n" + " */\n", + "fielddef", FieldDefinition(options, field), "keytype", key_type, + "valuetype", value_type); + printer->Print( + "$class$.prototype.$gettername$ = function(opt_noLazyCreate) {\n" + " return /** @type {!jspb.Map<$keytype$,$valuetype$>} */ (\n", + "class", GetMessagePath(options, field->containing_type()), + "gettername", "get" + JSGetterName(options, field), "keytype", key_type, + "valuetype", value_type); + printer->Annotate("gettername", field); + printer->Print( + " jspb.Message.getMapField(this, $index$, opt_noLazyCreate", + "index", JSFieldIndex(field)); + + if (value_field->type() == FieldDescriptor::TYPE_MESSAGE) { + printer->Print( + ",\n" + " $messageType$", + "messageType", GetMessagePath(options, value_field->message_type())); + } else { + printer->Print( + ",\n" + " null"); + } + + printer->Print("));\n"); + + printer->Print( + "};\n" + "\n" + "\n"); + } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + // Message field: special handling in order to wrap the underlying data + // array with a message object. + + printer->Print( + "/**\n" + " * $fielddef$\n" + "$comment$" + " * @return {$type$}\n" + " */\n", + "fielddef", FieldDefinition(options, field), "comment", + FieldComments(field, BYTES_DEFAULT), "type", + JSFieldTypeAnnotation(options, field, + /* is_setter_argument = */ false, + /* force_present = */ false, + /* singular_if_not_packed = */ false)); + printer->Print( + "$class$.prototype.$gettername$ = function() {\n" + " return /** @type{$type$} */ (\n" + " jspb.Message.get$rpt$WrapperField(this, $wrapperclass$, " + "$index$$required$));\n" + "};\n" + "\n" + "\n", + "class", GetMessagePath(options, field->containing_type()), + "gettername", "get" + JSGetterName(options, field), "type", + JSFieldTypeAnnotation(options, field, + /* is_setter_argument = */ false, + /* force_present = */ false, + /* singular_if_not_packed = */ false), + "rpt", (field->is_repeated() ? "Repeated" : ""), "index", + JSFieldIndex(field), "wrapperclass", SubmessageTypeRef(options, field), + "required", + (field->label() == FieldDescriptor::LABEL_REQUIRED ? ", 1" : "")); + printer->Annotate("gettername", field); + printer->Print( + "/**\n" + " * @param {$optionaltype$} value\n" + " * @return {!$class$} returns this\n" + "*/\n" + "$class$.prototype.$settername$ = function(value) {\n" + " return jspb.Message.set$oneoftag$$repeatedtag$WrapperField(", + "optionaltype", + JSFieldTypeAnnotation(options, field, + /* is_setter_argument = */ true, + /* force_present = */ false, + /* singular_if_not_packed = */ false), + "class", GetMessagePath(options, field->containing_type()), + "settername", "set" + JSGetterName(options, field), "oneoftag", + (InRealOneof(field) ? "Oneof" : ""), "repeatedtag", + (field->is_repeated() ? "Repeated" : "")); + printer->Annotate("settername", field); + + printer->Print( + "this, $index$$oneofgroup$, value);\n" + "};\n" + "\n" + "\n", + "index", JSFieldIndex(field), "oneofgroup", + (InRealOneof(field) ? (", " + JSOneofArray(options, field)) : "")); + + if (field->is_repeated()) { + GenerateRepeatedMessageHelperMethods(options, printer, field); + } + + } else { + bool untyped = false; + + // Simple (primitive) field, either singular or repeated. + + // TODO(b/26173701): Always use BYTES_DEFAULT for the getter return type; + // at this point we "lie" to non-binary users and tell the return + // type is always base64 string, pending a LSC to migrate to typed getters. + BytesMode bytes_mode = + field->type() == FieldDescriptor::TYPE_BYTES && !options.binary + ? BYTES_B64 + : BYTES_DEFAULT; + std::string typed_annotation = + JSFieldTypeAnnotation(options, field, + /* is_setter_argument = */ false, + /* force_present = */ false, + /* singular_if_not_packed = */ false, + /* bytes_mode = */ bytes_mode); + if (untyped) { + printer->Print( + "/**\n" + " * @return {?} Raw field, untyped.\n" + " */\n"); + } else { + printer->Print( + "/**\n" + " * $fielddef$\n" + "$comment$" + " * @return {$type$}\n" + " */\n", + "fielddef", FieldDefinition(options, field), "comment", + FieldComments(field, bytes_mode), "type", typed_annotation); + } + + printer->Print("$class$.prototype.$gettername$ = function() {\n", "class", + GetMessagePath(options, field->containing_type()), + "gettername", "get" + JSGetterName(options, field)); + printer->Annotate("gettername", field); + + if (untyped) { + printer->Print(" return "); + } else { + printer->Print(" return /** @type {$type$} */ (", "type", + typed_annotation); + } + + bool use_default = !ReturnsNullWhenUnset(options, field); + + // Raw fields with no default set should just return undefined. + if (untyped && !field->has_default_value()) { + use_default = false; + } + + // Repeated fields get initialized to their default in the constructor + // (why?), so we emit a plain getField() call for them. + if (field->is_repeated()) { + use_default = false; + } + + GenerateFieldValueExpression(printer, "this", field, use_default); + + if (untyped) { + printer->Print( + ";\n" + "};\n" + "\n" + "\n"); + } else { + printer->Print( + ");\n" + "};\n" + "\n" + "\n"); + } + + if (field->type() == FieldDescriptor::TYPE_BYTES && !untyped) { + GenerateBytesWrapper(options, printer, field, BYTES_B64); + GenerateBytesWrapper(options, printer, field, BYTES_U8); + } + + printer->Print( + "/**\n" + " * @param {$optionaltype$} value\n" + " * @return {!$class$} returns this\n" + " */\n", + "class", GetMessagePath(options, field->containing_type()), + "optionaltype", + untyped ? "*" + : JSFieldTypeAnnotation(options, field, + /* is_setter_argument = */ true, + /* force_present = */ false, + /* singular_if_not_packed = */ false)); + + if (field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3 && + !field->is_repeated() && !field->is_map() && + !HasFieldPresence(options, field)) { + // Proto3 non-repeated and non-map fields without presence use the + // setProto3*Field function. + printer->Print( + "$class$.prototype.$settername$ = function(value) {\n" + " return jspb.Message.setProto3$typetag$Field(this, $index$, " + "value);" + "\n" + "};\n" + "\n" + "\n", + "class", GetMessagePath(options, field->containing_type()), + "settername", "set" + JSGetterName(options, field), "typetag", + JSTypeTag(field), "index", JSFieldIndex(field)); + printer->Annotate("settername", field); + } else { + // Otherwise, use the regular setField function. + printer->Print( + "$class$.prototype.$settername$ = function(value) {\n" + " return jspb.Message.set$oneoftag$Field(this, $index$", + "class", GetMessagePath(options, field->containing_type()), + "settername", "set" + JSGetterName(options, field), "oneoftag", + (InRealOneof(field) ? "Oneof" : ""), "index", JSFieldIndex(field)); + printer->Annotate("settername", field); + printer->Print( + "$oneofgroup$, $type$value$rptvalueinit$$typeclose$);\n" + "};\n" + "\n" + "\n", + "type", + untyped ? "/** @type{string|number|boolean|Array|undefined} */(" : "", + "typeclose", untyped ? ")" : "", "oneofgroup", + (InRealOneof(field) ? (", " + JSOneofArray(options, field)) : ""), + "rptvalueinit", (field->is_repeated() ? " || []" : "")); + } + + if (untyped) { + printer->Print( + "/**\n" + " * Clears the value.\n" + " * @return {!$class$} returns this\n" + " */\n", + "class", GetMessagePath(options, field->containing_type())); + } + + if (field->is_repeated()) { + GenerateRepeatedPrimitiveHelperMethods(options, printer, field, untyped); + } + } + + // Generate clearFoo() method for map fields, repeated fields, and other + // fields with presence. + if (field->is_map()) { + // clang-format off + printer->Print( + "/**\n" + " * Clears values from the map. The map will be non-null.\n" + " * @return {!$class$} returns this\n" + " */\n" + "$class$.prototype.$clearername$ = function() {\n" + " this.$gettername$().clear();\n" + " return this;" + "};\n" + "\n" + "\n", + "class", GetMessagePath(options, field->containing_type()), + "clearername", "clear" + JSGetterName(options, field), + "gettername", "get" + JSGetterName(options, field)); + // clang-format on + printer->Annotate("clearername", field); + } else if (field->is_repeated() || + (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && + !field->is_required())) { + // Fields where we can delegate to the regular setter. + // clang-format off + printer->Print( + "/**\n" + " * $jsdoc$\n" + " * @return {!$class$} returns this\n" + " */\n" + "$class$.prototype.$clearername$ = function() {\n" + " return this.$settername$($clearedvalue$);\n" + "};\n" + "\n" + "\n", + "jsdoc", field->is_repeated() + ? "Clears the list making it empty but non-null." + : "Clears the message field making it undefined.", + "class", GetMessagePath(options, field->containing_type()), + "clearername", "clear" + JSGetterName(options, field), + "settername", "set" + JSGetterName(options, field), + "clearedvalue", (field->is_repeated() ? "[]" : "undefined")); + // clang-format on + printer->Annotate("clearername", field); + } else if (HasFieldPresence(options, field)) { + // Fields where we can't delegate to the regular setter because it doesn't + // accept "undefined" as an argument. + // clang-format off + printer->Print( + "/**\n" + " * Clears the field making it undefined.\n" + " * @return {!$class$} returns this\n" + " */\n" + "$class$.prototype.$clearername$ = function() {\n" + " return jspb.Message.set$maybeoneof$Field(this, " + "$index$$maybeoneofgroup$, ", + "class", GetMessagePath(options, field->containing_type()), + "clearername", "clear" + JSGetterName(options, field), + "maybeoneof", (InRealOneof(field) ? "Oneof" : ""), + "maybeoneofgroup", (InRealOneof(field) + ? (", " + JSOneofArray(options, field)) + : ""), + "index", JSFieldIndex(field)); + // clang-format on + printer->Annotate("clearername", field); + printer->Print( + "$clearedvalue$);\n" + "};\n" + "\n" + "\n", + "clearedvalue", (field->is_repeated() ? "[]" : "undefined")); + } + + if (HasFieldPresence(options, field)) { + printer->Print( + "/**\n" + " * Returns whether this field is set.\n" + " * @return {boolean}\n" + " */\n" + "$class$.prototype.$hasername$ = function() {\n" + " return jspb.Message.getField(this, $index$) != null;\n" + "};\n" + "\n" + "\n", + "class", GetMessagePath(options, field->containing_type()), "hasername", + "has" + JSGetterName(options, field), "index", JSFieldIndex(field)); + printer->Annotate("hasername", field); + } +} + +void Generator::GenerateRepeatedPrimitiveHelperMethods( + const GeneratorOptions& options, io::Printer* printer, + const FieldDescriptor* field, bool untyped) const { + // clang-format off + printer->Print( + "/**\n" + " * @param {$optionaltype$} value\n" + " * @param {number=} opt_index\n" + " * @return {!$class$} returns this\n" + " */\n" + "$class$.prototype.$addername$ = function(value, opt_index) {\n" + " return jspb.Message.addToRepeatedField(this, " + "$index$", + "class", GetMessagePath(options, field->containing_type()), "addername", + "add" + JSGetterName(options, field, BYTES_DEFAULT, + /* drop_list = */ true), + "optionaltype", + JSFieldTypeAnnotation( + options, field, + /* is_setter_argument = */ false, + /* force_present = */ true, + /* singular_if_not_packed = */ false, + BYTES_DEFAULT, + /* force_singular = */ true), + "index", JSFieldIndex(field)); + printer->Annotate("addername", field); + printer->Print( + "$oneofgroup$, $type$value$rptvalueinit$$typeclose$, " + "opt_index);\n" + "};\n" + "\n" + "\n", + "type", untyped ? "/** @type{string|number|boolean|!Uint8Array} */(" : "", + "typeclose", untyped ? ")" : "", "oneofgroup", + (InRealOneof(field) ? (", " + JSOneofArray(options, field)) : ""), + "rptvalueinit", ""); + // clang-format on +} + +void Generator::GenerateRepeatedMessageHelperMethods( + const GeneratorOptions& options, io::Printer* printer, + const FieldDescriptor* field) const { + printer->Print( + "/**\n" + " * @param {!$optionaltype$=} opt_value\n" + " * @param {number=} opt_index\n" + " * @return {!$optionaltype$}\n" + " */\n" + "$class$.prototype.$addername$ = function(opt_value, opt_index) {\n" + " return jspb.Message.addTo$repeatedtag$WrapperField(", + "optionaltype", JSTypeName(options, field, BYTES_DEFAULT), "class", + GetMessagePath(options, field->containing_type()), "addername", + "add" + JSGetterName(options, field, BYTES_DEFAULT, + /* drop_list = */ true), + "repeatedtag", (field->is_repeated() ? "Repeated" : "")); + + printer->Annotate("addername", field); + printer->Print( + "this, $index$$oneofgroup$, opt_value, $ctor$, opt_index);\n" + "};\n" + "\n" + "\n", + "index", JSFieldIndex(field), "oneofgroup", + (InRealOneof(field) ? (", " + JSOneofArray(options, field)) : ""), "ctor", + GetMessagePath(options, field->message_type())); +} + +void Generator::GenerateClassExtensionFieldInfo(const GeneratorOptions& options, + io::Printer* printer, + const Descriptor* desc) const { + if (IsExtendable(desc)) { + printer->Print( + "\n" + "/**\n" + " * The extensions registered with this message class. This is a " + "map of\n" + " * extension field number to fieldInfo object.\n" + " *\n" + " * For example:\n" + " * { 123: {fieldIndex: 123, fieldName: {my_field_name: 0}, " + "ctor: proto.example.MyMessage} }\n" + " *\n" + " * fieldName contains the JsCompiler renamed field name property " + "so that it\n" + " * works in OPTIMIZED mode.\n" + " *\n" + " * @type {!Object<number, jspb.ExtensionFieldInfo>}\n" + " */\n" + "$class$.extensions = {};\n" + "\n", + "class", GetMessagePath(options, desc)); + + printer->Print( + "\n" + "/**\n" + " * The extensions registered with this message class. This is a " + "map of\n" + " * extension field number to fieldInfo object.\n" + " *\n" + " * For example:\n" + " * { 123: {fieldIndex: 123, fieldName: {my_field_name: 0}, " + "ctor: proto.example.MyMessage} }\n" + " *\n" + " * fieldName contains the JsCompiler renamed field name property " + "so that it\n" + " * works in OPTIMIZED mode.\n" + " *\n" + " * @type {!Object<number, jspb.ExtensionFieldBinaryInfo>}\n" + " */\n" + "$class$.extensionsBinary = {};\n" + "\n", + "class", GetMessagePath(options, desc)); + } +} + +void Generator::GenerateClassDeserializeBinary(const GeneratorOptions& options, + io::Printer* printer, + const Descriptor* desc) const { + // TODO(cfallin): Handle lazy decoding when requested by field option and/or + // by default for 'bytes' fields and packed repeated fields. + + printer->Print( + "/**\n" + " * Deserializes binary data (in protobuf wire format).\n" + " * @param {jspb.ByteSource} bytes The bytes to deserialize.\n" + " * @return {!$class$}\n" + " */\n" + "$class$.deserializeBinary = function(bytes) {\n" + " var reader = new jspb.BinaryReader(bytes);\n" + " var msg = new $class$;\n" + " return $class$.deserializeBinaryFromReader(msg, reader);\n" + "};\n" + "\n" + "\n" + "/**\n" + " * Deserializes binary data (in protobuf wire format) from the\n" + " * given reader into the given message object.\n" + " * @param {!$class$} msg The message object to deserialize into.\n" + " * @param {!jspb.BinaryReader} reader The BinaryReader to use.\n" + " * @return {!$class$}\n" + " */\n" + "$class$.deserializeBinaryFromReader = function(msg, reader) {\n" + " while (reader.nextField()) {\n", + "class", GetMessagePath(options, desc)); + printer->Print( + " if (reader.isEndGroup()) {\n" + " break;\n" + " }\n" + " var field = reader.getFieldNumber();\n" + " switch (field) {\n"); + + for (int i = 0; i < desc->field_count(); i++) { + if (!IgnoreField(desc->field(i))) { + GenerateClassDeserializeBinaryField(options, printer, desc->field(i)); + } + } + + printer->Print(" default:\n"); + if (IsExtendable(desc)) { + printer->Print( + " jspb.Message.readBinaryExtension(msg, reader,\n" + " $extobj$Binary,\n" + " $class$.prototype.getExtension,\n" + " $class$.prototype.setExtension);\n" + " break;\n" + " }\n", + "extobj", JSExtensionsObjectName(options, desc->file(), desc), "class", + GetMessagePath(options, desc)); + } else { + printer->Print( + " reader.skipField();\n" + " break;\n" + " }\n"); + } + + printer->Print( + " }\n" + " return msg;\n" + "};\n" + "\n" + "\n"); +} + +void Generator::GenerateClassDeserializeBinaryField( + const GeneratorOptions& options, io::Printer* printer, + const FieldDescriptor* field) const { + printer->Print(" case $num$:\n", "num", StrCat(field->number())); + + if (field->is_map()) { + const FieldDescriptor* key_field = MapFieldKey(field); + const FieldDescriptor* value_field = MapFieldValue(field); + printer->Print( + " var value = msg.get$name$();\n" + " reader.readMessage(value, function(message, reader) {\n", + "name", JSGetterName(options, field)); + + printer->Print( + " jspb.Map.deserializeBinary(message, reader, " + "$keyReaderFn$, $valueReaderFn$", + "keyReaderFn", JSBinaryReaderMethodName(options, key_field), + "valueReaderFn", JSBinaryReaderMethodName(options, value_field)); + + if (value_field->type() == FieldDescriptor::TYPE_MESSAGE) { + printer->Print(", $messageType$.deserializeBinaryFromReader", + "messageType", + GetMessagePath(options, value_field->message_type())); + } else { + printer->Print(", null"); + } + printer->Print(", $defaultKey$", "defaultKey", JSFieldDefault(key_field)); + if (value_field->type() == FieldDescriptor::TYPE_MESSAGE) { + printer->Print(", new $messageType$()", "messageType", + GetMessagePath(options, value_field->message_type())); + } else { + printer->Print(", $defaultValue$", "defaultValue", + JSFieldDefault(value_field)); + } + printer->Print(");\n"); + printer->Print(" });\n"); + } else { + if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + printer->Print( + " var value = new $fieldclass$;\n" + " reader.read$msgOrGroup$($grpfield$value," + "$fieldclass$.deserializeBinaryFromReader);\n", + "fieldclass", SubmessageTypeRef(options, field), "msgOrGroup", + (field->type() == FieldDescriptor::TYPE_GROUP) ? "Group" : "Message", + "grpfield", + (field->type() == FieldDescriptor::TYPE_GROUP) + ? (StrCat(field->number()) + ", ") + : ""); + } else if (field->is_packable()) { + printer->Print( + " var values = /** @type {$fieldtype$} */ " + "(reader.isDelimited() " + "? reader.readPacked$reader$() : [reader.read$reader$()]);\n", + "fieldtype", + JSFieldTypeAnnotation(options, field, false, true, + /* singular_if_not_packed */ false, BYTES_U8), + "reader", JSBinaryReaderMethodType(field)); + } else { + printer->Print( + " var value = /** @type {$fieldtype$} */ " + "(reader.read$reader$());\n", + "fieldtype", + JSFieldTypeAnnotation(options, field, false, true, + /* singular_if_not_packed */ true, BYTES_U8), + "reader", + JSBinaryReadWriteMethodName(field, /* is_writer = */ false)); + } + + if (field->is_packable()) { + printer->Print( + " for (var i = 0; i < values.length; i++) {\n" + " msg.add$name$(values[i]);\n" + " }\n", + "name", + JSGetterName(options, field, BYTES_DEFAULT, /* drop_list = */ true)); + } else if (field->is_repeated()) { + printer->Print( + " msg.add$name$(value);\n", "name", + JSGetterName(options, field, BYTES_DEFAULT, /* drop_list = */ true)); + } else { + // Singular fields, and packed repeated fields, receive a |value| either + // as the field's value or as the array of all the field's values; set + // this as the field's value directly. + printer->Print(" msg.set$name$(value);\n", "name", + JSGetterName(options, field)); + } + } + + printer->Print(" break;\n"); +} + +void Generator::GenerateClassSerializeBinary(const GeneratorOptions& options, + io::Printer* printer, + const Descriptor* desc) const { + printer->Print( + "/**\n" + " * Serializes the message to binary data (in protobuf wire format).\n" + " * @return {!Uint8Array}\n" + " */\n" + "$class$.prototype.serializeBinary = function() {\n" + " var writer = new jspb.BinaryWriter();\n" + " $class$.serializeBinaryToWriter(this, writer);\n" + " return writer.getResultBuffer();\n" + "};\n" + "\n" + "\n" + "/**\n" + " * Serializes the given message to binary data (in protobuf wire\n" + " * format), writing to the given BinaryWriter.\n" + " * @param {!$class$} message\n" + " * @param {!jspb.BinaryWriter} writer\n" + " * @suppress {unusedLocalVariables} f is only used for nested messages\n" + " */\n" + "$class$.serializeBinaryToWriter = function(message, " + "writer) {\n" + " var f = undefined;\n", + "class", GetMessagePath(options, desc)); + + for (int i = 0; i < desc->field_count(); i++) { + if (!IgnoreField(desc->field(i))) { + GenerateClassSerializeBinaryField(options, printer, desc->field(i)); + } + } + + if (IsExtendable(desc)) { + printer->Print( + " jspb.Message.serializeBinaryExtensions(message, writer,\n" + " $extobj$Binary, $class$.prototype.getExtension);\n", + "extobj", JSExtensionsObjectName(options, desc->file(), desc), "class", + GetMessagePath(options, desc)); + } + + printer->Print( + "};\n" + "\n" + "\n"); +} + +void Generator::GenerateClassSerializeBinaryField( + const GeneratorOptions& options, io::Printer* printer, + const FieldDescriptor* field) const { + if (HasFieldPresence(options, field) && + field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) { + std::string typed_annotation = + JSFieldTypeAnnotation(options, field, + /* is_setter_argument = */ false, + /* force_present = */ false, + /* singular_if_not_packed = */ false, + /* bytes_mode = */ BYTES_DEFAULT); + printer->Print( + " f = /** @type {$type$} */ " + "(jspb.Message.getField(message, $index$));\n", + "index", JSFieldIndex(field), "type", typed_annotation); + } else { + printer->Print( + " f = message.get$name$($nolazy$);\n", "name", + JSGetterName(options, field, BYTES_U8), + // No lazy creation for maps containers -- fastpath the empty case. + "nolazy", field->is_map() ? "true" : ""); + } + + // Print an `if (condition)` statement that evaluates to true if the field + // goes on the wire. + if (field->is_map()) { + printer->Print(" if (f && f.getLength() > 0) {\n"); + } else if (field->is_repeated()) { + printer->Print(" if (f.length > 0) {\n"); + } else { + if (HasFieldPresence(options, field)) { + printer->Print(" if (f != null) {\n"); + } else { + // No field presence: serialize onto the wire only if value is + // non-default. Defaults are documented here: + // https://goto.google.com/lhdfm + switch (field->cpp_type()) { + case FieldDescriptor::CPPTYPE_INT32: + case FieldDescriptor::CPPTYPE_INT64: + case FieldDescriptor::CPPTYPE_UINT32: + case FieldDescriptor::CPPTYPE_UINT64: { + if (IsIntegralFieldWithStringJSType(field)) { + // We can use `parseInt` here even though it will not be precise for + // 64-bit quantities because we are only testing for zero/nonzero, + // and JS numbers (64-bit floating point values, i.e., doubles) are + // integer-precise in the range that includes zero. + printer->Print(" if (parseInt(f, 10) !== 0) {\n"); + } else { + printer->Print(" if (f !== 0) {\n"); + } + break; + } + + case FieldDescriptor::CPPTYPE_ENUM: + case FieldDescriptor::CPPTYPE_FLOAT: + case FieldDescriptor::CPPTYPE_DOUBLE: + printer->Print(" if (f !== 0.0) {\n"); + break; + case FieldDescriptor::CPPTYPE_BOOL: + printer->Print(" if (f) {\n"); + break; + case FieldDescriptor::CPPTYPE_STRING: + printer->Print(" if (f.length > 0) {\n"); + break; + default: + assert(false); + break; + } + } + } + + // Write the field on the wire. + if (field->is_map()) { + const FieldDescriptor* key_field = MapFieldKey(field); + const FieldDescriptor* value_field = MapFieldValue(field); + printer->Print( + " f.serializeBinary($index$, writer, " + "$keyWriterFn$, $valueWriterFn$", + "index", StrCat(field->number()), "keyWriterFn", + JSBinaryWriterMethodName(options, key_field), "valueWriterFn", + JSBinaryWriterMethodName(options, value_field)); + + if (value_field->type() == FieldDescriptor::TYPE_MESSAGE) { + printer->Print(", $messageType$.serializeBinaryToWriter", "messageType", + GetMessagePath(options, value_field->message_type())); + } + + printer->Print(");\n"); + } else { + printer->Print( + " writer.write$method$(\n" + " $index$,\n" + " f", + "method", JSBinaryReadWriteMethodName(field, /* is_writer = */ true), + "index", StrCat(field->number())); + + if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && + !field->is_map()) { + printer->Print( + ",\n" + " $submsg$.serializeBinaryToWriter\n", + "submsg", SubmessageTypeRef(options, field)); + } else { + printer->Print("\n"); + } + + printer->Print(" );\n"); + } + + // Close the `if`. + printer->Print(" }\n"); +} + +void Generator::GenerateEnum(const GeneratorOptions& options, + io::Printer* printer, + const EnumDescriptor* enumdesc) const { + printer->Print( + "/**\n" + " * @enum {number}\n" + " */\n" + "$enumprefix$$name$ = {\n", + "enumprefix", GetEnumPathPrefix(options, enumdesc), "name", + enumdesc->name()); + printer->Annotate("name", enumdesc); + + std::set<std::string> used_name; + std::vector<int> valid_index; + for (int i = 0; i < enumdesc->value_count(); i++) { + if (enumdesc->options().allow_alias() && + !used_name.insert(ToEnumCase(enumdesc->value(i)->name())).second) { + continue; + } + valid_index.push_back(i); + } + for (auto i : valid_index) { + const EnumValueDescriptor* value = enumdesc->value(i); + printer->Print(" $name$: $value$$comma$\n", "name", + ToEnumCase(value->name()), "value", StrCat(value->number()), + "comma", (i == valid_index.back()) ? "" : ","); + printer->Annotate("name", value); + } + + printer->Print( + "};\n" + "\n"); +} + +void Generator::GenerateExtension(const GeneratorOptions& options, + io::Printer* printer, + const FieldDescriptor* field) const { + std::string extension_scope = + (field->extension_scope() + ? GetMessagePath(options, field->extension_scope()) + : GetNamespace(options, field->file())); + + const std::string extension_object_name = JSObjectFieldName(options, field); + printer->Print( + "\n" + "/**\n" + " * A tuple of {field number, class constructor} for the extension\n" + " * field named `$nameInComment$`.\n" + " * @type {!jspb.ExtensionFieldInfo<$extensionType$>}\n" + " */\n" + "$class$.$name$ = new jspb.ExtensionFieldInfo(\n", + "nameInComment", extension_object_name, "name", extension_object_name, + "class", extension_scope, "extensionType", + JSFieldTypeAnnotation(options, field, + /* is_setter_argument = */ false, + /* force_present = */ true, + /* singular_if_not_packed = */ false)); + printer->Annotate("name", field); + printer->Print( + " $index$,\n" + " {$name$: 0},\n" + " $ctor$,\n" + " /** @type {?function((boolean|undefined),!jspb.Message=): " + "!Object} */ (\n" + " $toObject$),\n" + " $repeated$);\n", + "index", StrCat(field->number()), "name", extension_object_name, "ctor", + (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE + ? SubmessageTypeRef(options, field) + : std::string("null")), + "toObject", + (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE + ? (SubmessageTypeRef(options, field) + ".toObject") + : std::string("null")), + "repeated", (field->is_repeated() ? "1" : "0")); + + printer->Print( + "\n" + "$extendName$Binary[$index$] = new jspb.ExtensionFieldBinaryInfo(\n" + " $class$.$name$,\n" + " $binaryReaderFn$,\n" + " $binaryWriterFn$,\n" + " $binaryMessageSerializeFn$,\n" + " $binaryMessageDeserializeFn$,\n", + "extendName", + JSExtensionsObjectName(options, field->file(), field->containing_type()), + "index", StrCat(field->number()), "class", extension_scope, "name", + extension_object_name, "binaryReaderFn", + JSBinaryReaderMethodName(options, field), "binaryWriterFn", + JSBinaryWriterMethodName(options, field), "binaryMessageSerializeFn", + (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) + ? (SubmessageTypeRef(options, field) + ".serializeBinaryToWriter") + : "undefined", + "binaryMessageDeserializeFn", + (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) + ? (SubmessageTypeRef(options, field) + ".deserializeBinaryFromReader") + : "undefined"); + + printer->Print(" $isPacked$);\n", "isPacked", + (field->is_packed() ? "true" : "false")); + + printer->Print( + "// This registers the extension field with the extended class, so that\n" + "// toObject() will function correctly.\n" + "$extendName$[$index$] = $class$.$name$;\n" + "\n", + "extendName", + JSExtensionsObjectName(options, field->file(), field->containing_type()), + "index", StrCat(field->number()), "class", extension_scope, "name", + extension_object_name); +} + +bool GeneratorOptions::ParseFromOptions( + const std::vector<std::pair<std::string, std::string> >& options, + std::string* error) { + for (int i = 0; i < options.size(); i++) { + if (options[i].first == "add_require_for_enums") { + if (options[i].second != "") { + *error = "Unexpected option value for add_require_for_enums"; + return false; + } + add_require_for_enums = true; + } else if (options[i].first == "binary") { + if (options[i].second != "") { + *error = "Unexpected option value for binary"; + return false; + } + binary = true; + } else if (options[i].first == "testonly") { + if (options[i].second != "") { + *error = "Unexpected option value for testonly"; + return false; + } + testonly = true; + + } else if (options[i].first == "error_on_name_conflict") { + GOOGLE_LOG(WARNING) << "Ignoring error_on_name_conflict option, this " + "will be removed in a future release"; + } else if (options[i].first == "output_dir") { + output_dir = options[i].second; + } else if (options[i].first == "namespace_prefix") { + namespace_prefix = options[i].second; + } else if (options[i].first == "library") { + library = options[i].second; + } else if (options[i].first == "import_style") { + if (options[i].second == "closure") { + import_style = kImportClosure; + } else if (options[i].second == "commonjs") { + import_style = kImportCommonJs; + } else if (options[i].second == "commonjs_strict") { + import_style = kImportCommonJsStrict; + } else if (options[i].second == "browser") { + import_style = kImportBrowser; + } else if (options[i].second == "es6") { + import_style = kImportEs6; + } else { + *error = "Unknown import style " + options[i].second + ", expected " + + "one of: closure, commonjs, browser, es6."; + } + } else if (options[i].first == "extension") { + extension = options[i].second; + } else if (options[i].first == "one_output_file_per_input_file") { + if (!options[i].second.empty()) { + *error = "Unexpected option value for one_output_file_per_input_file"; + return false; + } + one_output_file_per_input_file = true; + } else if (options[i].first == "annotate_code") { + if (!options[i].second.empty()) { + *error = "Unexpected option value for annotate_code"; + return false; + } + annotate_code = true; + } else { + // Assume any other option is an output directory, as long as it is a bare + // `key` rather than a `key=value` option. + if (options[i].second != "") { + *error = "Unknown option: " + options[i].first; + return false; + } + output_dir = options[i].first; + } + } + + if (import_style != kImportClosure && + (add_require_for_enums || testonly || !library.empty() || + extension != ".js" || one_output_file_per_input_file)) { + *error = + "The add_require_for_enums, testonly, library, extension, and " + "one_output_file_per_input_file options should only be " + "used for import_style=closure"; + return false; + } + + return true; +} + +GeneratorOptions::OutputMode GeneratorOptions::output_mode() const { + // We use one output file per input file if we are not using Closure or if + // this is explicitly requested. + if (import_style != kImportClosure || one_output_file_per_input_file) { + return kOneOutputFilePerInputFile; + } + + // If a library name is provided, we put everything in that one file. + if (!library.empty()) { + return kEverythingInOneFile; + } + + // Otherwise, we create one output file per SCC. + return kOneOutputFilePerSCC; +} + +void Generator::GenerateFilesInDepOrder( + const GeneratorOptions& options, io::Printer* printer, + const std::vector<const FileDescriptor*>& files) const { + // Build a std::set over all files so that the DFS can detect when it recurses + // into a dep not specified in the user's command line. + std::set<const FileDescriptor*> all_files(files.begin(), files.end()); + // Track the in-progress set of files that have been generated already. + std::set<const FileDescriptor*> generated; + for (int i = 0; i < files.size(); i++) { + GenerateFileAndDeps(options, printer, files[i], &all_files, &generated); + } +} + +void Generator::GenerateFileAndDeps( + const GeneratorOptions& options, io::Printer* printer, + const FileDescriptor* root, std::set<const FileDescriptor*>* all_files, + std::set<const FileDescriptor*>* generated) const { + // Skip if already generated. + if (generated->find(root) != generated->end()) { + return; + } + generated->insert(root); + + // Generate all dependencies before this file's content. + for (int i = 0; i < root->dependency_count(); i++) { + const FileDescriptor* dep = root->dependency(i); + GenerateFileAndDeps(options, printer, dep, all_files, generated); + } + + // Generate this file's content. Only generate if the file is part of the + // original set requested to be generated; i.e., don't take all transitive + // deps down to the roots. + if (all_files->find(root) != all_files->end()) { + GenerateClassesAndEnums(options, printer, root); + } +} + +bool Generator::GenerateFile(const FileDescriptor* file, + const GeneratorOptions& options, + GeneratorContext* context, + bool use_short_name) const { + std::string filename = + options.output_dir + "/" + + GetJSFilename(options, use_short_name + ? file->name().substr(file->name().rfind('/')) + : file->name()); + std::unique_ptr<io::ZeroCopyOutputStream> output(context->Open(filename)); + GOOGLE_CHECK(output); + GeneratedCodeInfo annotations; + io::AnnotationProtoCollector<GeneratedCodeInfo> annotation_collector( + &annotations); + io::Printer printer(output.get(), '$', + options.annotate_code ? &annotation_collector : nullptr); + + GenerateFile(options, &printer, file); + + if (printer.failed()) { + return false; + } + + if (options.annotate_code) { + EmbedCodeAnnotations(annotations, &printer); + } + + return true; +} + +void Generator::GenerateFile(const GeneratorOptions& options, + io::Printer* printer, + const FileDescriptor* file) const { + GenerateHeader(options, file, printer); + + // Generate "require" statements. + if ((options.import_style == GeneratorOptions::kImportCommonJs || + options.import_style == GeneratorOptions::kImportCommonJsStrict)) { + printer->Print("var jspb = require('google-protobuf');\n"); + printer->Print("var goog = jspb;\n"); + + // Do not use global scope in strict mode + if (options.import_style == GeneratorOptions::kImportCommonJsStrict) { + printer->Print("var proto = {};\n\n"); + } else { + // To get the global object we call a function with .call(null), this will set "this" inside the + // function to the global object. + // This does not work if we are running in strict mode ("use strict"), + // so we fallback to the following things (in order from first to last): + // - window: defined in browsers + // - global: defined in most server side environments like NodeJS + // - self: defined inside Web Workers (WorkerGlobalScope) + // - Function('return this')(): this will work on most platforms, but it may be blocked by things like CSP. + // Function('') is almost the same as eval('') + printer->Print( + "var global = (function() {\n" + " if (this) { return this; }\n" + " if (typeof window !== 'undefined') { return window; }\n" + " if (typeof global !== 'undefined') { return global; }\n" + " if (typeof self !== 'undefined') { return self; }\n" + " return Function('return this')();\n" + "}.call(null));\n\n"); + } + + for (int i = 0; i < file->dependency_count(); i++) { + const std::string& name = file->dependency(i)->name(); + printer->Print( + "var $alias$ = require('$file$');\n" + "goog.object.extend(proto, $alias$);\n", + "alias", ModuleAlias(name), "file", + GetRootPath(file->name(), name) + GetJSFilename(options, name)); + } + } + + std::set<std::string> provided; + std::set<const FieldDescriptor*> extensions; + for (int i = 0; i < file->extension_count(); i++) { + // We honor the jspb::ignore option here only when working with + // Closure-style imports. Use of this option is discouraged and so we want + // to avoid adding new support for it. + if (options.import_style == GeneratorOptions::kImportClosure && + IgnoreField(file->extension(i))) { + continue; + } + provided.insert(GetNamespace(options, file) + "." + + JSObjectFieldName(options, file->extension(i))); + extensions.insert(file->extension(i)); + } + + FindProvidesForFile(options, printer, file, &provided); + GenerateProvides(options, printer, &provided); + std::vector<const FileDescriptor*> files; + files.push_back(file); + if (options.import_style == GeneratorOptions::kImportClosure) { + GenerateRequiresForLibrary(options, printer, files, &provided); + } + + GenerateClassesAndEnums(options, printer, file); + + // Generate code for top-level extensions. Extensions nested inside messages + // are emitted inside GenerateClassesAndEnums(). + for (std::set<const FieldDescriptor*>::const_iterator it = extensions.begin(); + it != extensions.end(); ++it) { + GenerateExtension(options, printer, *it); + } + + // if provided is empty, do not export anything + if (options.import_style == GeneratorOptions::kImportCommonJs && + !provided.empty()) { + printer->Print("goog.object.extend(exports, $package$);\n", "package", + GetNamespace(options, file)); + } else if (options.import_style == GeneratorOptions::kImportCommonJsStrict) { + printer->Print("goog.object.extend(exports, proto);\n", "package", + GetNamespace(options, file)); + } + + // Emit well-known type methods. + for (FileToc* toc = well_known_types_js; toc->name != NULL; toc++) { + std::string name = std::string("google/protobuf/") + toc->name; + if (name == StripProto(file->name()) + ".js") { + printer->Print(toc->data); + } + } +} + +bool Generator::GenerateAll(const std::vector<const FileDescriptor*>& files, + const std::string& parameter, + GeneratorContext* context, + std::string* error) const { + std::vector<std::pair<std::string, std::string> > option_pairs; + ParseGeneratorParameter(parameter, &option_pairs); + GeneratorOptions options; + if (!options.ParseFromOptions(option_pairs, error)) { + return false; + } + + if (options.output_mode() == GeneratorOptions::kEverythingInOneFile) { + // All output should go in a single file. + std::string filename = options.output_dir + "/" + options.library + + options.GetFileNameExtension(); + std::unique_ptr<io::ZeroCopyOutputStream> output(context->Open(filename)); + GOOGLE_CHECK(output.get()); + GeneratedCodeInfo annotations; + io::AnnotationProtoCollector<GeneratedCodeInfo> annotation_collector( + &annotations); + io::Printer printer( + output.get(), '$', + options.annotate_code ? &annotation_collector : nullptr); + + // Pull out all extensions -- we need these to generate all + // provides/requires. + std::vector<const FieldDescriptor*> extensions; + for (int i = 0; i < files.size(); i++) { + for (int j = 0; j < files[i]->extension_count(); j++) { + const FieldDescriptor* extension = files[i]->extension(j); + extensions.push_back(extension); + } + } + + if (files.size() == 1) { + GenerateHeader(options, files[0], &printer); + } else { + GenerateHeader(options, nullptr, &printer); + } + + std::set<std::string> provided; + FindProvides(options, &printer, files, &provided); + FindProvidesForFields(options, &printer, extensions, &provided); + GenerateProvides(options, &printer, &provided); + GenerateTestOnly(options, &printer); + GenerateRequiresForLibrary(options, &printer, files, &provided); + + GenerateFilesInDepOrder(options, &printer, files); + + for (int i = 0; i < extensions.size(); i++) { + if (ShouldGenerateExtension(extensions[i])) { + GenerateExtension(options, &printer, extensions[i]); + } + } + + if (printer.failed()) { + return false; + } + if (options.annotate_code) { + EmbedCodeAnnotations(annotations, &printer); + } + } else if (options.output_mode() == GeneratorOptions::kOneOutputFilePerSCC) { + std::set<const Descriptor*> have_printed; + SCCAnalyzer<DepsGenerator> analyzer; + std::map<const void*, std::string> allowed_map; + if (!GenerateJspbAllowedMap(options, files, &allowed_map, &analyzer)) { + return false; + } + + bool generated = false; + for (int i = 0; i < files.size(); i++) { + const FileDescriptor* file = files[i]; + // Force well known type to generate in a whole file. + if (IsWellKnownTypeFile(file)) { + if (!GenerateFile(file, options, context, true)) { + return false; + } + generated = true; + continue; + } + for (int j = 0; j < file->message_type_count(); j++) { + const Descriptor* desc = file->message_type(j); + if (have_printed.count(desc) || + allowed_map.count(analyzer.GetSCC(desc)) == 0) { + continue; + } + + generated = true; + const SCC* scc = analyzer.GetSCC(desc); + const std::string& filename = allowed_map[scc]; + std::unique_ptr<io::ZeroCopyOutputStream> output( + context->Open(filename)); + GOOGLE_CHECK(output.get()); + GeneratedCodeInfo annotations; + io::AnnotationProtoCollector<GeneratedCodeInfo> annotation_collector( + &annotations); + io::Printer printer( + output.get(), '$', + options.annotate_code ? &annotation_collector : nullptr); + + GenerateHeader(options, file, &printer); + + std::set<std::string> provided; + for (auto one_desc : scc->descriptors) { + if (one_desc->containing_type() == nullptr) { + FindProvidesForMessage(options, &printer, one_desc, &provided); + } + } + GenerateProvides(options, &printer, &provided); + GenerateTestOnly(options, &printer); + GenerateRequiresForSCC(options, &printer, scc, &provided); + + for (auto one_desc : scc->descriptors) { + if (one_desc->containing_type() == nullptr) { + GenerateClassConstructorAndDeclareExtensionFieldInfo( + options, &printer, one_desc); + } + } + for (auto one_desc : scc->descriptors) { + if (one_desc->containing_type() == nullptr) { + GenerateClass(options, &printer, one_desc); + } + } + + for (auto one_desc : scc->descriptors) { + have_printed.insert(one_desc); + } + + if (printer.failed()) { + return false; + } + if (options.annotate_code) { + EmbedCodeAnnotations(annotations, &printer); + } + } + for (int j = 0; j < file->enum_type_count(); j++) { + const EnumDescriptor* enumdesc = file->enum_type(j); + if (allowed_map.count(enumdesc) == 0) { + continue; + } + + generated = true; + const std::string& filename = allowed_map[enumdesc]; + std::unique_ptr<io::ZeroCopyOutputStream> output( + context->Open(filename)); + GOOGLE_CHECK(output.get()); + GeneratedCodeInfo annotations; + io::AnnotationProtoCollector<GeneratedCodeInfo> annotation_collector( + &annotations); + io::Printer printer( + output.get(), '$', + options.annotate_code ? &annotation_collector : nullptr); + + GenerateHeader(options, file, &printer); + + std::set<std::string> provided; + FindProvidesForEnum(options, &printer, enumdesc, &provided); + GenerateProvides(options, &printer, &provided); + GenerateTestOnly(options, &printer); + + GenerateEnum(options, &printer, enumdesc); + + if (printer.failed()) { + return false; + } + if (options.annotate_code) { + EmbedCodeAnnotations(annotations, &printer); + } + } + // File-level extensions (message-level extensions are generated under + // the enclosing message). + if (allowed_map.count(file) == 1) { + generated = true; + const std::string& filename = allowed_map[file]; + + std::unique_ptr<io::ZeroCopyOutputStream> output( + context->Open(filename)); + GOOGLE_CHECK(output.get()); + GeneratedCodeInfo annotations; + io::AnnotationProtoCollector<GeneratedCodeInfo> annotation_collector( + &annotations); + io::Printer printer( + output.get(), '$', + options.annotate_code ? &annotation_collector : nullptr); + + GenerateHeader(options, file, &printer); + + std::set<std::string> provided; + std::vector<const FieldDescriptor*> fields; + + for (int j = 0; j < files[i]->extension_count(); j++) { + if (ShouldGenerateExtension(files[i]->extension(j))) { + fields.push_back(files[i]->extension(j)); + } + } + + FindProvidesForFields(options, &printer, fields, &provided); + GenerateProvides(options, &printer, &provided); + GenerateTestOnly(options, &printer); + GenerateRequiresForExtensions(options, &printer, fields, &provided); + + for (int j = 0; j < files[i]->extension_count(); j++) { + if (ShouldGenerateExtension(files[i]->extension(j))) { + GenerateExtension(options, &printer, files[i]->extension(j)); + } + } + if (options.annotate_code) { + EmbedCodeAnnotations(annotations, &printer); + } + } + } + if (!generated) { + std::string filename = options.output_dir + "/" + + "empty_no_content_void_file" + + options.GetFileNameExtension(); + std::unique_ptr<io::ZeroCopyOutputStream> output(context->Open(filename)); + } + } else /* options.output_mode() == kOneOutputFilePerInputFile */ { + // Generate one output file per input (.proto) file. + + for (int i = 0; i < files.size(); i++) { + const FileDescriptor* file = files[i]; + if (!GenerateFile(file, options, context, false)) { + return false; + } + } + } + return true; +} + +} // namespace js +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/js/js_generator.h b/NorthstarDedicatedTest/include/protobuf/compiler/js/js_generator.h new file mode 100644 index 00000000..b01b15e8 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/js/js_generator.h @@ -0,0 +1,336 @@ +// 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. + +// Generates JavaScript code for a given .proto file. +// +#ifndef GOOGLE_PROTOBUF_COMPILER_JS_GENERATOR_H__ +#define GOOGLE_PROTOBUF_COMPILER_JS_GENERATOR_H__ + +#include <set> +#include <string> + +#include <stubs/logging.h> +#include <stubs/common.h> +#include <compiler/scc.h> +#include <compiler/code_generator.h> + +#include <port_def.inc> + +namespace google { +namespace protobuf { + +class Descriptor; +class EnumDescriptor; +class FieldDescriptor; +class OneofDescriptor; +class FileDescriptor; + +namespace io { +class Printer; +} + +namespace compiler { +namespace js { + +struct GeneratorOptions { + // Output path. + std::string output_dir; + // Namespace prefix. + std::string namespace_prefix; + // Enable binary-format support? + bool binary; + // What style of imports should be used. + enum ImportStyle { + kImportClosure, // goog.require() + kImportCommonJs, // require() + kImportCommonJsStrict, // require() with no global export + kImportBrowser, // no import statements + kImportEs6, // import { member } from '' + } import_style; + + GeneratorOptions() + : output_dir("."), + namespace_prefix(""), + binary(false), + import_style(kImportClosure), + add_require_for_enums(false), + testonly(false), + library(""), + extension(".js"), + one_output_file_per_input_file(false), + annotate_code(false) {} + + bool ParseFromOptions( + const std::vector<std::pair<std::string, std::string> >& options, + std::string* error); + + // Returns the file name extension to use for generated code. + std::string GetFileNameExtension() const { + return import_style == kImportClosure ? extension : "_pb.js"; + } + + enum OutputMode { + // Create an output file for each input .proto file. + kOneOutputFilePerInputFile, + // Create an output file for each type. + kOneOutputFilePerSCC, + // Put everything in a single file named by the library option. + kEverythingInOneFile, + }; + + // Indicates how to output the generated code based on the provided options. + OutputMode output_mode() const; + + // The remaining options are only relevant when we are using kImportClosure. + + // Add a `goog.requires()` call for each enum type used. If not set, a + // forward declaration with `goog.forwardDeclare` is produced instead. + bool add_require_for_enums; + // Set this as a test-only module via `goog.setTestOnly();`. + bool testonly; + // Create a library with name <name>_lib.js rather than a separate .js file + // per type? + std::string library; + // The extension to use for output file names. + std::string extension; + // Create a separate output file for each input file? + bool one_output_file_per_input_file; + // If true, we should append annotations as comments on the last line for + // generated .js file. Annotations used by tools like https://kythe.io + // to provide cross-references between .js and .proto files. Annotations + // are encoded as base64 proto of GeneratedCodeInfo message (see + // descriptor.proto). + bool annotate_code; +}; + +// CodeGenerator implementation which generates a JavaScript source file and +// header. If you create your own protocol compiler binary and you want it to +// support JavaScript output, you can do so by registering an instance of this +// CodeGenerator with the CommandLineInterface in your main() function. +class PROTOC_EXPORT Generator : public CodeGenerator { + public: + Generator() {} + virtual ~Generator() {} + + bool Generate(const FileDescriptor* file, const std::string& parameter, + GeneratorContext* context, std::string* error) const override { + *error = "Unimplemented Generate() method. Call GenerateAll() instead."; + return false; + } + + bool HasGenerateAll() const override { return true; } + + bool GenerateAll(const std::vector<const FileDescriptor*>& files, + const std::string& parameter, GeneratorContext* context, + std::string* error) const override; + + uint64 GetSupportedFeatures() const override { + return FEATURE_PROTO3_OPTIONAL; + } + + private: + void GenerateHeader(const GeneratorOptions& options, + const FileDescriptor* file, io::Printer* printer) const; + + // Generate goog.provides() calls. + void FindProvides(const GeneratorOptions& options, io::Printer* printer, + const std::vector<const FileDescriptor*>& file, + std::set<std::string>* provided) const; + void FindProvidesForFile(const GeneratorOptions& options, + io::Printer* printer, const FileDescriptor* file, + std::set<std::string>* provided) const; + void FindProvidesForMessage(const GeneratorOptions& options, + io::Printer* printer, const Descriptor* desc, + std::set<std::string>* provided) const; + void FindProvidesForEnum(const GeneratorOptions& options, + io::Printer* printer, const EnumDescriptor* enumdesc, + std::set<std::string>* provided) const; + // For extension fields at file scope. + void FindProvidesForFields(const GeneratorOptions& options, + io::Printer* printer, + const std::vector<const FieldDescriptor*>& fields, + std::set<std::string>* provided) const; + // Print the goog.provides() found by the methods above. + void GenerateProvides(const GeneratorOptions& options, io::Printer* printer, + std::set<std::string>* provided) const; + + // Generate goog.setTestOnly() if indicated. + void GenerateTestOnly(const GeneratorOptions& options, + io::Printer* printer) const; + + // Generate goog.requires() calls. + void GenerateRequiresForLibrary( + const GeneratorOptions& options, io::Printer* printer, + const std::vector<const FileDescriptor*>& files, + std::set<std::string>* provided) const; + void GenerateRequiresForSCC(const GeneratorOptions& options, + io::Printer* printer, const SCC* scc, + std::set<std::string>* provided) const; + // For extension fields at file scope. + void GenerateRequiresForExtensions( + const GeneratorOptions& options, io::Printer* printer, + const std::vector<const FieldDescriptor*>& fields, + std::set<std::string>* provided) const; + void GenerateRequiresImpl(const GeneratorOptions& options, + io::Printer* printer, + std::set<std::string>* required, + std::set<std::string>* forwards, + std::set<std::string>* provided, bool require_jspb, + bool require_extension, bool require_map) const; + void FindRequiresForMessage(const GeneratorOptions& options, + const Descriptor* desc, + std::set<std::string>* required, + std::set<std::string>* forwards, + bool* have_message) const; + void FindRequiresForField(const GeneratorOptions& options, + const FieldDescriptor* field, + std::set<std::string>* required, + std::set<std::string>* forwards) const; + void FindRequiresForExtension(const GeneratorOptions& options, + const FieldDescriptor* field, + std::set<std::string>* required, + std::set<std::string>* forwards) const; + // Generate all things in a proto file into one file. + // If use_short_name is true, the generated file's name will only be short + // name that without directory, otherwise filename equals file->name() + bool GenerateFile(const FileDescriptor* file, const GeneratorOptions& options, + GeneratorContext* context, bool use_short_name) const; + void GenerateFile(const GeneratorOptions& options, io::Printer* printer, + const FileDescriptor* file) const; + + // Generate definitions for all message classes and enums in all files, + // processing the files in dependence order. + void GenerateFilesInDepOrder( + const GeneratorOptions& options, io::Printer* printer, + const std::vector<const FileDescriptor*>& file) const; + // Helper for above. + void GenerateFileAndDeps(const GeneratorOptions& options, + io::Printer* printer, const FileDescriptor* root, + std::set<const FileDescriptor*>* all_files, + std::set<const FileDescriptor*>* generated) const; + + // Generate definitions for all message classes and enums. + void GenerateClassesAndEnums(const GeneratorOptions& options, + io::Printer* printer, + const FileDescriptor* file) const; + + void GenerateFieldValueExpression(io::Printer* printer, + const char* obj_reference, + const FieldDescriptor* field, + bool use_default) const; + + // Generate definition for one class. + void GenerateClass(const GeneratorOptions& options, io::Printer* printer, + const Descriptor* desc) const; + void GenerateClassConstructor(const GeneratorOptions& options, + io::Printer* printer, + const Descriptor* desc) const; + void GenerateClassFieldInfo(const GeneratorOptions& options, + io::Printer* printer, + const Descriptor* desc) const; + void GenerateClassConstructorAndDeclareExtensionFieldInfo( + const GeneratorOptions& options, io::Printer* printer, + const Descriptor* desc) const; + void GenerateClassXid(const GeneratorOptions& options, io::Printer* printer, + const Descriptor* desc) const; + void GenerateOneofCaseDefinition(const GeneratorOptions& options, + io::Printer* printer, + const OneofDescriptor* oneof) const; + void GenerateObjectTypedef(const GeneratorOptions& options, + io::Printer* printer, + const Descriptor* desc) const; + void GenerateClassToObject(const GeneratorOptions& options, + io::Printer* printer, + const Descriptor* desc) const; + void GenerateClassFieldToObject(const GeneratorOptions& options, + io::Printer* printer, + const FieldDescriptor* field) const; + void GenerateClassFromObject(const GeneratorOptions& options, + io::Printer* printer, + const Descriptor* desc) const; + void GenerateClassFieldFromObject(const GeneratorOptions& options, + io::Printer* printer, + const FieldDescriptor* field) const; + void GenerateClassRegistration(const GeneratorOptions& options, + io::Printer* printer, + const Descriptor* desc) const; + void GenerateClassFields(const GeneratorOptions& options, + io::Printer* printer, const Descriptor* desc) const; + void GenerateClassField(const GeneratorOptions& options, io::Printer* printer, + const FieldDescriptor* desc) const; + void GenerateClassExtensionFieldInfo(const GeneratorOptions& options, + io::Printer* printer, + const Descriptor* desc) const; + void GenerateClassDeserialize(const GeneratorOptions& options, + io::Printer* printer, + const Descriptor* desc) const; + void GenerateClassDeserializeBinary(const GeneratorOptions& options, + io::Printer* printer, + const Descriptor* desc) const; + void GenerateClassDeserializeBinaryField(const GeneratorOptions& options, + io::Printer* printer, + const FieldDescriptor* field) const; + void GenerateClassSerializeBinary(const GeneratorOptions& options, + io::Printer* printer, + const Descriptor* desc) const; + void GenerateClassSerializeBinaryField(const GeneratorOptions& options, + io::Printer* printer, + const FieldDescriptor* field) const; + + // Generate definition for one enum. + void GenerateEnum(const GeneratorOptions& options, io::Printer* printer, + const EnumDescriptor* enumdesc) const; + + // Generate an extension definition. + void GenerateExtension(const GeneratorOptions& options, io::Printer* printer, + const FieldDescriptor* field) const; + + // Generate addFoo() method for repeated primitive fields. + void GenerateRepeatedPrimitiveHelperMethods(const GeneratorOptions& options, + io::Printer* printer, + const FieldDescriptor* field, + bool untyped) const; + + // Generate addFoo() method for repeated message fields. + void GenerateRepeatedMessageHelperMethods(const GeneratorOptions& options, + io::Printer* printer, + const FieldDescriptor* field) const; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Generator); +}; + +} // namespace js +} // namespace compiler +} // namespace protobuf +} // namespace google + +#include <port_undef.inc> + +#endif // GOOGLE_PROTOBUF_COMPILER_JS_GENERATOR_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/js/well_known_types_embed.cc b/NorthstarDedicatedTest/include/protobuf/compiler/js/well_known_types_embed.cc new file mode 100644 index 00000000..eaccdcf5 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/js/well_known_types_embed.cc @@ -0,0 +1,270 @@ +// 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 <compiler/js/well_known_types_embed.h> + +struct FileToc well_known_types_js[] = { + {"any.js", + "/* This code will be inserted into generated code for\n" + " * google/protobuf/any.proto. */\n" + "\n" + "/**\n" + " * Returns the type name contained in this instance, if any.\n" + " * @return {string|undefined}\n" + " */\n" + "proto.google.protobuf.Any.prototype.getTypeName = function() {\n" + " return this.getTypeUrl().split('/').pop();\n" + "};\n" + "\n" + "\n" + "/**\n" + " * Packs the given message instance into this Any.\n" + " * For binary format usage only.\n" + " * @param {!Uint8Array} serialized The serialized data to pack.\n" + " * @param {string} name The type name of this message object.\n" + " * @param {string=} opt_typeUrlPrefix the type URL prefix.\n" + " */\n" + "proto.google.protobuf.Any.prototype.pack = function(serialized, name,\n" + " opt_typeUrlPrefix) " + "{\n" + " if (!opt_typeUrlPrefix) {\n" + " opt_typeUrlPrefix = 'type.googleapis.com/';\n" + " }\n" + "\n" + " if (opt_typeUrlPrefix.substr(-1) != '/') {\n" + " this.setTypeUrl(opt_typeUrlPrefix + '/' + name);\n" + " } else {\n" + " this.setTypeUrl(opt_typeUrlPrefix + name);\n" + " }\n" + "\n" + " this.setValue(serialized);\n" + "};\n" + "\n" + "\n" + "/**\n" + " * @template T\n" + " * Unpacks this Any into the given message object.\n" + " * @param {function(Uint8Array):T} deserialize Function that will " + "deserialize\n" + " * the binary data properly.\n" + " * @param {string} name The expected type name of this message object.\n" + " * @return {?T} If the name matched the expected name, returns the " + "deserialized\n" + " * object, otherwise returns null.\n" + " */\n" + "proto.google.protobuf.Any.prototype.unpack = function(deserialize, name) " + "{\n" + " if (this.getTypeName() == name) {\n" + " return deserialize(this.getValue_asU8());\n" + " } else {\n" + " return null;\n" + " }\n" + "};\n" + }, + {"timestamp.js", + "/* This code will be inserted into generated code for\n" + " * google/protobuf/timestamp.proto. */\n" + "\n" + "/**\n" + " * Returns a JavaScript 'Date' object corresponding to this Timestamp.\n" + " * @return {!Date}\n" + " */\n" + "proto.google.protobuf.Timestamp.prototype.toDate = function() {\n" + " var seconds = this.getSeconds();\n" + " var nanos = this.getNanos();\n" + "\n" + " return new Date((seconds * 1000) + (nanos / 1000000));\n" + "};\n" + "\n" + "\n" + "/**\n" + " * Sets the value of this Timestamp object to be the given Date.\n" + " * @param {!Date} value The value to set.\n" + " */\n" + "proto.google.protobuf.Timestamp.prototype.fromDate = function(value) {\n" + " this.setSeconds(Math.floor(value.getTime() / 1000));\n" + " this.setNanos(value.getMilliseconds() * 1000000);\n" + "};\n" + "\n" + "\n" + "/**\n" + " * Factory method that returns a Timestamp object with value equal to\n" + " * the given Date.\n" + " * @param {!Date} value The value to set.\n" + " * @return {!proto.google.protobuf.Timestamp}\n" + " */\n" + "proto.google.protobuf.Timestamp.fromDate = function(value) {\n" + " var timestamp = new proto.google.protobuf.Timestamp();\n" + " timestamp.fromDate(value);\n" + " return timestamp;\n" + "};\n"}, + {"struct.js", + "/* This code will be inserted into generated code for\n" + " * google/protobuf/struct.proto. */\n" + "\n" + "/**\n" + " * Typedef representing plain JavaScript values that can go into a\n" + " * Struct.\n" + " * @typedef {null|number|string|boolean|Array|Object}\n" + " */\n" + "proto.google.protobuf.JavaScriptValue;\n" + "\n" + "\n" + "/**\n" + " * Converts this Value object to a plain JavaScript value.\n" + " * @return {?proto.google.protobuf.JavaScriptValue} a plain JavaScript\n" + " * value representing this Struct.\n" + " */\n" + "proto.google.protobuf.Value.prototype.toJavaScript = function() {\n" + " var kindCase = proto.google.protobuf.Value.KindCase;\n" + " switch (this.getKindCase()) {\n" + " case kindCase.NULL_VALUE:\n" + " return null;\n" + " case kindCase.NUMBER_VALUE:\n" + " return this.getNumberValue();\n" + " case kindCase.STRING_VALUE:\n" + " return this.getStringValue();\n" + " case kindCase.BOOL_VALUE:\n" + " return this.getBoolValue();\n" + " case kindCase.STRUCT_VALUE:\n" + " return this.getStructValue().toJavaScript();\n" + " case kindCase.LIST_VALUE:\n" + " return this.getListValue().toJavaScript();\n" + " default:\n" + " throw new Error('Unexpected struct type');\n" + " }\n" + "};\n" + "\n" + "\n" + "/**\n" + " * Converts this JavaScript value to a new Value proto.\n" + " * @param {!proto.google.protobuf.JavaScriptValue} value The value to\n" + " * convert.\n" + " * @return {!proto.google.protobuf.Value} The newly constructed value.\n" + " */\n" + "proto.google.protobuf.Value.fromJavaScript = function(value) {\n" + " var ret = new proto.google.protobuf.Value();\n" + " switch (goog.typeOf(value)) {\n" + " case 'string':\n" + " ret.setStringValue(/** @type {string} */ (value));\n" + " break;\n" + " case 'number':\n" + " ret.setNumberValue(/** @type {number} */ (value));\n" + " break;\n" + " case 'boolean':\n" + " ret.setBoolValue(/** @type {boolean} */ (value));\n" + " break;\n" + " case 'null':\n" + " ret.setNullValue(proto.google.protobuf.NullValue.NULL_VALUE);\n" + " break;\n" + " case 'array':\n" + " ret.setListValue(proto.google.protobuf.ListValue.fromJavaScript(\n" + " /** @type{!Array} */ (value)));\n" + " break;\n" + " case 'object':\n" + " ret.setStructValue(proto.google.protobuf.Struct.fromJavaScript(\n" + " /** @type{!Object} */ (value)));\n" + " break;\n" + " default:\n" + " throw new Error('Unexpected struct type.');\n" + " }\n" + "\n" + " return ret;\n" + "};\n" + "\n" + "\n" + "/**\n" + " * Converts this ListValue object to a plain JavaScript array.\n" + " * @return {!Array} a plain JavaScript array representing this List.\n" + " */\n" + "proto.google.protobuf.ListValue.prototype.toJavaScript = function() {\n" + " var ret = [];\n" + " var values = this.getValuesList();\n" + "\n" + " for (var i = 0; i < values.length; i++) {\n" + " ret[i] = values[i].toJavaScript();\n" + " }\n" + "\n" + " return ret;\n" + "};\n" + "\n" + "\n" + "/**\n" + " * Constructs a ListValue protobuf from this plain JavaScript array.\n" + " * @param {!Array} array a plain JavaScript array\n" + " * @return {proto.google.protobuf.ListValue} a new ListValue object\n" + " */\n" + "proto.google.protobuf.ListValue.fromJavaScript = function(array) {\n" + " var ret = new proto.google.protobuf.ListValue();\n" + "\n" + " for (var i = 0; i < array.length; i++) {\n" + " " + "ret.addValues(proto.google.protobuf.Value.fromJavaScript(array[i]));\n" + " }\n" + "\n" + " return ret;\n" + "};\n" + "\n" + "\n" + "/**\n" + " * Converts this Struct object to a plain JavaScript object.\n" + " * @return {!Object<string, !proto.google.protobuf.JavaScriptValue>} a " + "plain\n" + " * JavaScript object representing this Struct.\n" + " */\n" + "proto.google.protobuf.Struct.prototype.toJavaScript = function() {\n" + " var ret = {};\n" + "\n" + " this.getFieldsMap().forEach(function(value, key) {\n" + " ret[key] = value.toJavaScript();\n" + " });\n" + "\n" + " return ret;\n" + "};\n" + "\n" + "\n" + "/**\n" + " * Constructs a Struct protobuf from this plain JavaScript object.\n" + " * @param {!Object} obj a plain JavaScript object\n" + " * @return {proto.google.protobuf.Struct} a new Struct object\n" + " */\n" + "proto.google.protobuf.Struct.fromJavaScript = function(obj) {\n" + " var ret = new proto.google.protobuf.Struct();\n" + " var map = ret.getFieldsMap();\n" + "\n" + " for (var property in obj) {\n" + " var val = obj[property];\n" + " map.set(property, proto.google.protobuf.Value.fromJavaScript(val));\n" + " }\n" + "\n" + " return ret;\n" + "};\n"}, + {NULL, NULL} // Terminate the list. +}; diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/js/well_known_types_embed.h b/NorthstarDedicatedTest/include/protobuf/compiler/js/well_known_types_embed.h new file mode 100644 index 00000000..174c665e --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/js/well_known_types_embed.h @@ -0,0 +1,43 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JS_WELL_KNOWN_TYPES_EMBED_H__ +#define GOOGLE_PROTOBUF_COMPILER_JS_WELL_KNOWN_TYPES_EMBED_H__ + +#include <stddef.h> + +struct FileToc { + const char* name; + const char* data; +}; + +extern struct FileToc well_known_types_js[]; + +#endif // GOOGLE_PROTOBUF_COMPILER_JS_WELL_KNOWN_TYPES_EMBED_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/main.cc b/NorthstarDedicatedTest/include/protobuf/compiler/main.cc new file mode 100644 index 00000000..2a5a2267 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/main.cc @@ -0,0 +1,113 @@ +// 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 <compiler/cpp/cpp_generator.h> +#include <compiler/java/java_generator.h> +#include <compiler/java/java_kotlin_generator.h> +#include <compiler/js/js_generator.h> +#include <compiler/command_line_interface.h> +#include <compiler/python/python_generator.h> +#include <compiler/csharp/csharp_generator.h> +#include <compiler/objectivec/objectivec_generator.h> +#include <compiler/php/php_generator.h> +#include <compiler/ruby/ruby_generator.h> + +#include <port_def.inc> + +namespace google { +namespace protobuf { +namespace compiler { + +int ProtobufMain(int argc, char* argv[]) { + + CommandLineInterface cli; + cli.AllowPlugins("protoc-"); + + // Proto2 C++ + cpp::CppGenerator cpp_generator; + cli.RegisterGenerator("--cpp_out", "--cpp_opt", &cpp_generator, + "Generate C++ header and source."); + +#ifdef GOOGLE_PROTOBUF_RUNTIME_INCLUDE_BASE + cpp_generator.set_opensource_runtime(true); + cpp_generator.set_runtime_include_base(GOOGLE_PROTOBUF_RUNTIME_INCLUDE_BASE); +#endif + + // Proto2 Java + java::JavaGenerator java_generator; + cli.RegisterGenerator("--java_out", "--java_opt", &java_generator, + "Generate Java source file."); + + // Proto2 Kotlin + java::KotlinGenerator kt_generator; + cli.RegisterGenerator("--kotlin_out", "--kotlin_opt", &kt_generator, + "Generate Kotlin file."); + + + // Proto2 Python + python::Generator py_generator; + cli.RegisterGenerator("--python_out", "--python_opt", &py_generator, + "Generate Python source file."); + + // PHP + php::Generator php_generator; + cli.RegisterGenerator("--php_out", "--php_opt", &php_generator, + "Generate PHP source file."); + + // Ruby + ruby::Generator rb_generator; + cli.RegisterGenerator("--ruby_out", "--ruby_opt", &rb_generator, + "Generate Ruby source file."); + + // CSharp + csharp::Generator csharp_generator; + cli.RegisterGenerator("--csharp_out", "--csharp_opt", &csharp_generator, + "Generate C# source file."); + + // Objective-C + objectivec::ObjectiveCGenerator objc_generator; + cli.RegisterGenerator("--objc_out", "--objc_opt", &objc_generator, + "Generate Objective-C header and source."); + + // JavaScript + js::Generator js_generator; + cli.RegisterGenerator("--js_out", "--js_opt", &js_generator, + "Generate JavaScript source."); + + return cli.Run(argc, argv); +} + +} // namespace compiler +} // namespace protobuf +} // namespace google + +int main(int argc, char* argv[]) { + return PROTOBUF_NAMESPACE_ID::compiler::ProtobufMain(argc, argv); +} diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/mock_code_generator.cc b/NorthstarDedicatedTest/include/protobuf/compiler/mock_code_generator.cc new file mode 100644 index 00000000..9de6b5b0 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/mock_code_generator.cc @@ -0,0 +1,384 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) + +#include <compiler/mock_code_generator.h> + +#include <stdlib.h> + +#include <cstdint> +#include <iostream> +#include <memory> +#include <vector> + +#include <stubs/strutil.h> + +#include <stubs/logging.h> +#include <stubs/common.h> +#include <testing/file.h> +#include <testing/file.h> +#include <testing/file.h> +#include <compiler/plugin.pb.h> +#include <io/printer.h> +#include <io/zero_copy_stream.h> +#include <descriptor.pb.h> +#include <descriptor.h> +#include <text_format.h> +#include <gtest/gtest.h> +#include <stubs/substitute.h> + +#ifdef major +#undef major +#endif +#ifdef minor +#undef minor +#endif + +namespace google { +namespace protobuf { +namespace compiler { + +// Returns the list of the names of files in all_files in the form of a +// comma-separated string. +std::string CommaSeparatedList( + const std::vector<const FileDescriptor*>& all_files) { + std::vector<std::string> names; + for (size_t i = 0; i < all_files.size(); i++) { + names.push_back(all_files[i]->name()); + } + return Join(names, ","); +} + +static const char* kFirstInsertionPointName = "first_mock_insertion_point"; +static const char* kSecondInsertionPointName = "second_mock_insertion_point"; +static const char* kFirstInsertionPoint = + "# @@protoc_insertion_point(first_mock_insertion_point) is here\n"; +static const char* kSecondInsertionPoint = + " # @@protoc_insertion_point(second_mock_insertion_point) is here\n"; + +MockCodeGenerator::MockCodeGenerator(const std::string& name) : name_(name) {} + +MockCodeGenerator::~MockCodeGenerator() {} + +uint64_t MockCodeGenerator::GetSupportedFeatures() const { + uint64_t all_features = CodeGenerator::FEATURE_PROTO3_OPTIONAL; + return all_features & ~suppressed_features_; +} + +void MockCodeGenerator::SuppressFeatures(uint64_t features) { + suppressed_features_ = features; +} + +void MockCodeGenerator::ExpectGenerated( + const std::string& name, const std::string& parameter, + const std::string& insertions, const std::string& file, + const std::string& first_message_name, + const std::string& first_parsed_file_name, + const std::string& output_directory) { + std::string content; + GOOGLE_CHECK_OK( + File::GetContents(output_directory + "/" + GetOutputFileName(name, file), + &content, true)); + + std::vector<std::string> lines = + Split(content, "\n", true); + + while (!lines.empty() && lines.back().empty()) { + lines.pop_back(); + } + for (size_t i = 0; i < lines.size(); i++) { + lines[i] += "\n"; + } + + std::vector<std::string> insertion_list; + if (!insertions.empty()) { + insertion_list = Split(insertions, ",", true); + } + + EXPECT_EQ(lines.size(), 3 + insertion_list.size() * 2); + EXPECT_EQ(GetOutputFileContent(name, parameter, file, first_parsed_file_name, + first_message_name), + lines[0]); + + EXPECT_EQ(kFirstInsertionPoint, lines[1 + insertion_list.size()]); + EXPECT_EQ(kSecondInsertionPoint, lines[2 + insertion_list.size() * 2]); + + for (size_t i = 0; i < insertion_list.size(); i++) { + EXPECT_EQ(GetOutputFileContent(insertion_list[i], "first_insert", file, + file, first_message_name), + lines[1 + i]); + // Second insertion point is indented, so the inserted text should + // automatically be indented too. + EXPECT_EQ(" " + GetOutputFileContent(insertion_list[i], "second_insert", + file, file, first_message_name), + lines[2 + insertion_list.size() + i]); + } +} + +namespace { +void CheckSingleAnnotation(const std::string& expected_file, + const std::string& expected_text, + const std::string& file_content, + const GeneratedCodeInfo::Annotation& annotation) { + EXPECT_EQ(expected_file, annotation.source_file()); + ASSERT_GE(file_content.size(), annotation.begin()); + ASSERT_GE(file_content.size(), annotation.end()); + ASSERT_LE(annotation.begin(), annotation.end()); + EXPECT_EQ(expected_text.size(), annotation.end() - annotation.begin()); + EXPECT_EQ(expected_text, + file_content.substr(annotation.begin(), expected_text.size())); +} +} // anonymous namespace + +void MockCodeGenerator::CheckGeneratedAnnotations( + const std::string& name, const std::string& file, + const std::string& output_directory) { + std::string file_content; + GOOGLE_CHECK_OK( + File::GetContents(output_directory + "/" + GetOutputFileName(name, file), + &file_content, true)); + std::string meta_content; + GOOGLE_CHECK_OK(File::GetContents( + output_directory + "/" + GetOutputFileName(name, file) + ".pb.meta", + &meta_content, true)); + GeneratedCodeInfo annotations; + GOOGLE_CHECK(TextFormat::ParseFromString(meta_content, &annotations)); + ASSERT_EQ(7, annotations.annotation_size()); + + CheckSingleAnnotation("first_annotation", "first", file_content, + annotations.annotation(0)); + CheckSingleAnnotation("first_path", + "test_generator: first_insert,\n foo.proto,\n " + "MockCodeGenerator_Annotate,\n foo.proto\n", + file_content, annotations.annotation(1)); + CheckSingleAnnotation("first_path", + "test_plugin: first_insert,\n foo.proto,\n " + "MockCodeGenerator_Annotate,\n foo.proto\n", + file_content, annotations.annotation(2)); + CheckSingleAnnotation("second_annotation", "second", file_content, + annotations.annotation(3)); + // This annotated text has changed because it was inserted at an indented + // insertion point. + CheckSingleAnnotation("second_path", + "test_generator: second_insert,\n foo.proto,\n " + "MockCodeGenerator_Annotate,\n foo.proto\n", + file_content, annotations.annotation(4)); + CheckSingleAnnotation("second_path", + "test_plugin: second_insert,\n foo.proto,\n " + "MockCodeGenerator_Annotate,\n foo.proto\n", + file_content, annotations.annotation(5)); + CheckSingleAnnotation("third_annotation", "third", file_content, + annotations.annotation(6)); +} + +bool MockCodeGenerator::Generate(const FileDescriptor* file, + const std::string& parameter, + GeneratorContext* context, + std::string* error) const { + bool annotate = false; + for (int i = 0; i < file->message_type_count(); i++) { + if (HasPrefixString(file->message_type(i)->name(), "MockCodeGenerator_")) { + std::string command = StripPrefixString( + file->message_type(i)->name(), "MockCodeGenerator_"); + if (command == "Error") { + *error = "Saw message type MockCodeGenerator_Error."; + return false; + } else if (command == "Exit") { + std::cerr << "Saw message type MockCodeGenerator_Exit." << std::endl; + exit(123); + } else if (command == "Abort") { + std::cerr << "Saw message type MockCodeGenerator_Abort." << std::endl; + abort(); + } else if (command == "HasSourceCodeInfo") { + FileDescriptorProto file_descriptor_proto; + file->CopySourceCodeInfoTo(&file_descriptor_proto); + bool has_source_code_info = + file_descriptor_proto.has_source_code_info() && + file_descriptor_proto.source_code_info().location_size() > 0; + std::cerr << "Saw message type MockCodeGenerator_HasSourceCodeInfo: " + << has_source_code_info << "." << std::endl; + abort(); + } else if (command == "HasJsonName") { + FieldDescriptorProto field_descriptor_proto; + file->message_type(i)->field(0)->CopyTo(&field_descriptor_proto); + std::cerr << "Saw json_name: " << field_descriptor_proto.has_json_name() + << std::endl; + abort(); + } else if (command == "Annotate") { + annotate = true; + } else if (command == "ShowVersionNumber") { + Version compiler_version; + context->GetCompilerVersion(&compiler_version); + std::cerr << "Saw compiler_version: " + << compiler_version.major() * 1000000 + + compiler_version.minor() * 1000 + + compiler_version.patch() + << " " << compiler_version.suffix() << std::endl; + abort(); + } else { + GOOGLE_LOG(FATAL) << "Unknown MockCodeGenerator command: " << command; + } + } + } + + bool insert_endlines = HasPrefixString(parameter, "insert_endlines="); + if (insert_endlines || HasPrefixString(parameter, "insert=")) { + std::vector<std::string> insert_into = Split( + StripPrefixString( + parameter, insert_endlines ? "insert_endlines=" : "insert="), + ",", true); + + for (size_t i = 0; i < insert_into.size(); i++) { + { + google::protobuf::GeneratedCodeInfo info; + std::string content = + GetOutputFileContent(name_, "first_insert", file, context); + if (insert_endlines) { + GlobalReplaceSubstring(",", ",\n", &content); + } + if (annotate) { + auto* annotation = info.add_annotation(); + annotation->set_begin(0); + annotation->set_end(content.size()); + annotation->set_source_file("first_path"); + } + std::unique_ptr<io::ZeroCopyOutputStream> output( + context->OpenForInsertWithGeneratedCodeInfo( + GetOutputFileName(insert_into[i], file), + kFirstInsertionPointName, info)); + io::Printer printer(output.get(), '$'); + printer.PrintRaw(content); + if (printer.failed()) { + *error = "MockCodeGenerator detected write error."; + return false; + } + } + + { + google::protobuf::GeneratedCodeInfo info; + std::string content = + GetOutputFileContent(name_, "second_insert", file, context); + if (insert_endlines) { + GlobalReplaceSubstring(",", ",\n", &content); + } + if (annotate) { + auto* annotation = info.add_annotation(); + annotation->set_begin(0); + annotation->set_end(content.size()); + annotation->set_source_file("second_path"); + } + std::unique_ptr<io::ZeroCopyOutputStream> output( + context->OpenForInsertWithGeneratedCodeInfo( + GetOutputFileName(insert_into[i], file), + kSecondInsertionPointName, info)); + io::Printer printer(output.get(), '$'); + printer.PrintRaw(content); + if (printer.failed()) { + *error = "MockCodeGenerator detected write error."; + return false; + } + } + } + } else { + std::unique_ptr<io::ZeroCopyOutputStream> output( + context->Open(GetOutputFileName(name_, file))); + + GeneratedCodeInfo annotations; + io::AnnotationProtoCollector<GeneratedCodeInfo> annotation_collector( + &annotations); + io::Printer printer(output.get(), '$', + annotate ? &annotation_collector : NULL); + printer.PrintRaw(GetOutputFileContent(name_, parameter, file, context)); + std::string annotate_suffix = "_annotation"; + if (annotate) { + printer.Print("$p$\n", "p", "first"); + printer.Annotate("p", "first" + annotate_suffix); + } + printer.PrintRaw(kFirstInsertionPoint); + if (annotate) { + printer.Print("$p$\n", "p", "second"); + printer.Annotate("p", "second" + annotate_suffix); + } + printer.PrintRaw(kSecondInsertionPoint); + if (annotate) { + printer.Print("$p$\n", "p", "third"); + printer.Annotate("p", "third" + annotate_suffix); + } + + if (printer.failed()) { + *error = "MockCodeGenerator detected write error."; + return false; + } + if (annotate) { + std::unique_ptr<io::ZeroCopyOutputStream> meta_output( + context->Open(GetOutputFileName(name_, file) + ".pb.meta")); + if (!TextFormat::Print(annotations, meta_output.get())) { + *error = "MockCodeGenerator couldn't write .pb.meta"; + return false; + } + } + } + + return true; +} + +std::string MockCodeGenerator::GetOutputFileName( + const std::string& generator_name, const FileDescriptor* file) { + return GetOutputFileName(generator_name, file->name()); +} + +std::string MockCodeGenerator::GetOutputFileName( + const std::string& generator_name, const std::string& file) { + return file + ".MockCodeGenerator." + generator_name; +} + +std::string MockCodeGenerator::GetOutputFileContent( + const std::string& generator_name, const std::string& parameter, + const FileDescriptor* file, GeneratorContext* context) { + std::vector<const FileDescriptor*> all_files; + context->ListParsedFiles(&all_files); + return GetOutputFileContent( + generator_name, parameter, file->name(), CommaSeparatedList(all_files), + file->message_type_count() > 0 ? file->message_type(0)->name() + : "(none)"); +} + +std::string MockCodeGenerator::GetOutputFileContent( + const std::string& generator_name, const std::string& parameter, + const std::string& file, const std::string& parsed_file_list, + const std::string& first_message_name) { + return strings::Substitute("$0: $1, $2, $3, $4\n", generator_name, parameter, + file, first_message_name, parsed_file_list); +} + +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/mock_code_generator.h b/NorthstarDedicatedTest/include/protobuf/compiler/mock_code_generator.h new file mode 100644 index 00000000..4b7c4dd1 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/mock_code_generator.h @@ -0,0 +1,136 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) + +#ifndef GOOGLE_PROTOBUF_COMPILER_MOCK_CODE_GENERATOR_H__ +#define GOOGLE_PROTOBUF_COMPILER_MOCK_CODE_GENERATOR_H__ + +#include <cstdint> +#include <string> + +#include <compiler/code_generator.h> + +namespace google { +namespace protobuf { +class FileDescriptor; +} // namespace protobuf +} // namespace google + +namespace google { +namespace protobuf { +namespace compiler { + +// A mock CodeGenerator, used by command_line_interface_unittest. This is in +// its own file so that it can be used both directly and as a plugin. +// +// Generate() produces some output which can be checked by ExpectCalled(). The +// generator can run in a different process (e.g. a plugin). +// +// If the parameter is "insert=NAMES", the MockCodeGenerator will insert lines +// into the files generated by other MockCodeGenerators instead of creating +// its own file. NAMES is a comma-separated list of the names of those other +// MockCodeGenerators. If the parameter is "insert_endlines=NAMES", the +// MockCodeGenerator will insert data guaranteed to contain more than one +// endline into the files generated by NAMES. +// +// MockCodeGenerator will also modify its behavior slightly if the input file +// contains a message type with one of the following names: +// MockCodeGenerator_Error: Causes Generate() to return false and set the +// error message to "Saw message type MockCodeGenerator_Error." +// MockCodeGenerator_Exit: Generate() prints "Saw message type +// MockCodeGenerator_Exit." to stderr and then calls exit(123). +// MockCodeGenerator_Abort: Generate() prints "Saw message type +// MockCodeGenerator_Abort." to stderr and then calls abort(). +// MockCodeGenerator_HasSourceCodeInfo: Causes Generate() to abort after +// printing "Saw message type MockCodeGenerator_HasSourceCodeInfo: FOO." to +// stderr, where FOO is "1" if the supplied FileDescriptorProto has source +// code info, and "0" otherwise. +// MockCodeGenerator_Annotate: Generate() will add annotations to its output +// that can later be verified with CheckGeneratedAnnotations. +class MockCodeGenerator : public CodeGenerator { + public: + MockCodeGenerator(const std::string& name); + virtual ~MockCodeGenerator(); + + // Expect (via gTest) that a MockCodeGenerator with the given name was called + // with the given parameters by inspecting the output location. + // + // |insertions| is a comma-separated list of names of MockCodeGenerators which + // should have inserted lines into this file. + // |parsed_file_list| is a comma-separated list of names of the files + // that are being compiled together in this run. + static void ExpectGenerated(const std::string& name, + const std::string& parameter, + const std::string& insertions, + const std::string& file, + const std::string& first_message_name, + const std::string& parsed_file_list, + const std::string& output_directory); + + // Checks that the correct text ranges were annotated by the + // MockCodeGenerator_Annotate directive. + static void CheckGeneratedAnnotations(const std::string& name, + const std::string& file, + const std::string& output_directory); + + // Get the name of the file which would be written by the given generator. + static std::string GetOutputFileName(const std::string& generator_name, + const FileDescriptor* file); + static std::string GetOutputFileName(const std::string& generator_name, + const std::string& file); + + // implements CodeGenerator ---------------------------------------- + + bool Generate(const FileDescriptor* file, const std::string& parameter, + GeneratorContext* context, std::string* error) const override; + + uint64_t GetSupportedFeatures() const override; + void SuppressFeatures(uint64_t features); + + private: + std::string name_; + uint64_t suppressed_features_ = 0; + + static std::string GetOutputFileContent(const std::string& generator_name, + const std::string& parameter, + const FileDescriptor* file, + GeneratorContext* context); + static std::string GetOutputFileContent( + const std::string& generator_name, const std::string& parameter, + const std::string& file, const std::string& parsed_file_list, + const std::string& first_message_name); +}; + +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_MOCK_CODE_GENERATOR_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_enum.cc b/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_enum.cc new file mode 100644 index 00000000..5510750a --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_enum.cc @@ -0,0 +1,260 @@ +// 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 <map> +#include <string> + +#include <compiler/objectivec/objectivec_enum.h> +#include <compiler/objectivec/objectivec_helpers.h> +#include <io/printer.h> +#include <stubs/strutil.h> +#include <algorithm> // std::find() + +namespace google { +namespace protobuf { +namespace compiler { +namespace objectivec { + +EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor) + : descriptor_(descriptor), + name_(EnumName(descriptor_)) { + // Track the names for the enum values, and if an alias overlaps a base + // value, skip making a name for it. Likewise if two alias overlap, the + // first one wins. + // The one gap in this logic is if two base values overlap, but for that + // to happen you have to have "Foo" and "FOO" or "FOO_BAR" and "FooBar", + // and if an enum has that, it is already going to be confusing and a + // compile error is just fine. + // The values are still tracked to support the reflection apis and + // TextFormat handing since they are different there. + std::set<std::string> value_names; + + for (int i = 0; i < descriptor_->value_count(); i++) { + const EnumValueDescriptor* value = descriptor_->value(i); + const EnumValueDescriptor* canonical_value = + descriptor_->FindValueByNumber(value->number()); + + if (value == canonical_value) { + base_values_.push_back(value); + value_names.insert(EnumValueName(value)); + } else { + std::string value_name(EnumValueName(value)); + if (value_names.find(value_name) != value_names.end()) { + alias_values_to_skip_.insert(value); + } else { + value_names.insert(value_name); + } + } + all_values_.push_back(value); + } +} + +EnumGenerator::~EnumGenerator() {} + +void EnumGenerator::GenerateHeader(io::Printer* printer) { + std::string enum_comments; + SourceLocation location; + if (descriptor_->GetSourceLocation(&location)) { + enum_comments = BuildCommentsString(location, true); + } else { + enum_comments = ""; + } + + printer->Print( + "#pragma mark - Enum $name$\n" + "\n", + "name", name_); + + // Swift 5 included SE0192 "Handling Future Enum Cases" + // https://github.com/apple/swift-evolution/blob/master/proposals/0192-non-exhaustive-enums.md + // Since a .proto file can get new values added to an enum at any time, they + // are effectively "non-frozen". Even in a proto3 syntax file where there is + // support for the unknown value, an edit to the file can always add a new + // value moving something from unknown to known. Since Swift is now ABI + // stable, it also means a binary could contain Swift compiled against one + // version of the .pbobjc.h file, but finally linked against an enum with + // more cases. So the Swift code will always have to treat ObjC Proto Enums + // as "non-frozen". The default behavior in SE0192 is for all objc enums to + // be "non-frozen" unless marked as otherwise, so this means this generation + // doesn't have to bother with the `enum_extensibility` attribute, as the + // default will be what is needed. + + printer->Print("$comments$typedef$deprecated_attribute$ GPB_ENUM($name$) {\n", + "comments", enum_comments, + "deprecated_attribute", GetOptionalDeprecatedAttribute(descriptor_, descriptor_->file()), + "name", name_); + printer->Indent(); + + if (HasPreservingUnknownEnumSemantics(descriptor_->file())) { + // Include the unknown value. + printer->Print( + "/**\n" + " * Value used if any message's field encounters a value that is not defined\n" + " * by this enum. The message will also have C functions to get/set the rawValue\n" + " * of the field.\n" + " **/\n" + "$name$_GPBUnrecognizedEnumeratorValue = kGPBUnrecognizedEnumeratorValue,\n", + "name", name_); + } + for (int i = 0; i < all_values_.size(); i++) { + if (alias_values_to_skip_.find(all_values_[i]) != alias_values_to_skip_.end()) { + continue; + } + if (all_values_[i]->GetSourceLocation(&location)) { + std::string comments = BuildCommentsString(location, true).c_str(); + if (comments.length() > 0) { + if (i > 0) { + printer->Print("\n"); + } + printer->Print(comments.c_str()); + } + } + + printer->Print( + "$name$$deprecated_attribute$ = $value$,\n", + "name", EnumValueName(all_values_[i]), + "deprecated_attribute", GetOptionalDeprecatedAttribute(all_values_[i]), + "value", StrCat(all_values_[i]->number())); + } + printer->Outdent(); + printer->Print( + "};\n" + "\n" + "GPBEnumDescriptor *$name$_EnumDescriptor(void);\n" + "\n" + "/**\n" + " * Checks to see if the given value is defined by the enum or was not known at\n" + " * the time this source was generated.\n" + " **/\n" + "BOOL $name$_IsValidValue(int32_t value);\n" + "\n", + "name", name_); +} + +void EnumGenerator::GenerateSource(io::Printer* printer) { + printer->Print( + "#pragma mark - Enum $name$\n" + "\n", + "name", name_); + + // Note: For the TextFormat decode info, we can't use the enum value as + // the key because protocol buffer enums have 'allow_alias', which lets + // a value be used more than once. Instead, the index into the list of + // enum value descriptions is used. Note: start with -1 so the first one + // will be zero. + TextFormatDecodeData text_format_decode_data; + int enum_value_description_key = -1; + std::string text_blob; + + for (int i = 0; i < all_values_.size(); i++) { + ++enum_value_description_key; + std::string short_name(EnumValueShortName(all_values_[i])); + text_blob += short_name + '\0'; + if (UnCamelCaseEnumShortName(short_name) != all_values_[i]->name()) { + text_format_decode_data.AddString(enum_value_description_key, short_name, + all_values_[i]->name()); + } + } + + printer->Print( + "GPBEnumDescriptor *$name$_EnumDescriptor(void) {\n" + " static _Atomic(GPBEnumDescriptor*) descriptor = nil;\n" + " if (!descriptor) {\n", + "name", name_); + + static const int kBytesPerLine = 40; // allow for escaping + printer->Print( + " static const char *valueNames ="); + for (int i = 0; i < text_blob.size(); i += kBytesPerLine) { + printer->Print( + "\n \"$data$\"", + "data", EscapeTrigraphs(CEscape(text_blob.substr(i, kBytesPerLine)))); + } + printer->Print( + ";\n" + " static const int32_t values[] = {\n"); + for (int i = 0; i < all_values_.size(); i++) { + printer->Print(" $name$,\n", "name", EnumValueName(all_values_[i])); + } + printer->Print(" };\n"); + + if (text_format_decode_data.num_entries() == 0) { + printer->Print( + " GPBEnumDescriptor *worker =\n" + " [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol($name$)\n" + " valueNames:valueNames\n" + " values:values\n" + " count:(uint32_t)(sizeof(values) / sizeof(int32_t))\n" + " enumVerifier:$name$_IsValidValue];\n", + "name", name_); + } else { + printer->Print( + " static const char *extraTextFormatInfo = \"$extraTextFormatInfo$\";\n" + " GPBEnumDescriptor *worker =\n" + " [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol($name$)\n" + " valueNames:valueNames\n" + " values:values\n" + " count:(uint32_t)(sizeof(values) / sizeof(int32_t))\n" + " enumVerifier:$name$_IsValidValue\n" + " extraTextFormatInfo:extraTextFormatInfo];\n", + "name", name_, + "extraTextFormatInfo", CEscape(text_format_decode_data.Data())); + } + printer->Print( + " GPBEnumDescriptor *expected = nil;\n" + " if (!atomic_compare_exchange_strong(&descriptor, &expected, worker)) {\n" + " [worker release];\n" + " }\n" + " }\n" + " return descriptor;\n" + "}\n\n"); + + printer->Print( + "BOOL $name$_IsValidValue(int32_t value__) {\n" + " switch (value__) {\n", + "name", name_); + + for (int i = 0; i < base_values_.size(); i++) { + printer->Print( + " case $name$:\n", + "name", EnumValueName(base_values_[i])); + } + + printer->Print( + " return YES;\n" + " default:\n" + " return NO;\n" + " }\n" + "}\n\n"); +} +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_enum.h b/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_enum.h new file mode 100644 index 00000000..51560dd1 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_enum.h @@ -0,0 +1,71 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_ENUM_H__ +#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_ENUM_H__ + +#include <string> +#include <set> +#include <vector> +#include <descriptor.h> +#include <io/printer.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace objectivec { + +class EnumGenerator { + public: + explicit EnumGenerator(const EnumDescriptor* descriptor); + ~EnumGenerator(); + + EnumGenerator(const EnumGenerator&) = delete; + EnumGenerator& operator=(const EnumGenerator&) = delete; + + void GenerateHeader(io::Printer* printer); + void GenerateSource(io::Printer* printer); + + const std::string& name() const { return name_; } + + private: + const EnumDescriptor* descriptor_; + std::vector<const EnumValueDescriptor*> base_values_; + std::vector<const EnumValueDescriptor*> all_values_; + std::set<const EnumValueDescriptor*> alias_values_to_skip_; + const std::string name_; +}; + +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_ENUM_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_enum_field.cc b/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_enum_field.cc new file mode 100644 index 00000000..66877afb --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_enum_field.cc @@ -0,0 +1,149 @@ +// 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 <map> +#include <string> + +#include <compiler/objectivec/objectivec_enum_field.h> +#include <compiler/objectivec/objectivec_helpers.h> +#include <io/printer.h> +#include <wire_format.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace objectivec { + +namespace { + +void SetEnumVariables(const FieldDescriptor* descriptor, + std::map<std::string, std::string>* variables) { + std::string type = EnumName(descriptor->enum_type()); + (*variables)["storage_type"] = type; + // For non repeated fields, if it was defined in a different file, the + // property decls need to use "enum NAME" rather than just "NAME" to support + // the forward declaration of the enums. + if (!descriptor->is_repeated() && + (descriptor->file() != descriptor->enum_type()->file())) { + (*variables)["property_type"] = "enum " + type; + } + (*variables)["enum_verifier"] = type + "_IsValidValue"; + (*variables)["enum_desc_func"] = type + "_EnumDescriptor"; + + (*variables)["dataTypeSpecific_name"] = "enumDescFunc"; + (*variables)["dataTypeSpecific_value"] = (*variables)["enum_desc_func"]; + + const Descriptor* msg_descriptor = descriptor->containing_type(); + (*variables)["owning_message_class"] = ClassName(msg_descriptor); +} +} // namespace + +EnumFieldGenerator::EnumFieldGenerator(const FieldDescriptor* descriptor, + const Options& options) + : SingleFieldGenerator(descriptor, options) { + SetEnumVariables(descriptor, &variables_); +} + +EnumFieldGenerator::~EnumFieldGenerator() {} + +void EnumFieldGenerator::GenerateCFunctionDeclarations( + io::Printer* printer) const { + if (!HasPreservingUnknownEnumSemantics(descriptor_->file())) { + return; + } + + printer->Print( + variables_, + "/**\n" + " * Fetches the raw value of a @c $owning_message_class$'s @c $name$ property, even\n" + " * if the value was not defined by the enum at the time the code was generated.\n" + " **/\n" + "int32_t $owning_message_class$_$capitalized_name$_RawValue($owning_message_class$ *message);\n" + "/**\n" + " * Sets the raw value of an @c $owning_message_class$'s @c $name$ property, allowing\n" + " * it to be set to a value that was not defined by the enum at the time the code\n" + " * was generated.\n" + " **/\n" + "void Set$owning_message_class$_$capitalized_name$_RawValue($owning_message_class$ *message, int32_t value);\n" + "\n"); +} + +void EnumFieldGenerator::GenerateCFunctionImplementations( + io::Printer* printer) const { + if (!HasPreservingUnknownEnumSemantics(descriptor_->file())) return; + + printer->Print( + variables_, + "int32_t $owning_message_class$_$capitalized_name$_RawValue($owning_message_class$ *message) {\n" + " GPBDescriptor *descriptor = [$owning_message_class$ descriptor];\n" + " GPBFieldDescriptor *field = [descriptor fieldWithNumber:$field_number_name$];\n" + " return GPBGetMessageRawEnumField(message, field);\n" + "}\n" + "\n" + "void Set$owning_message_class$_$capitalized_name$_RawValue($owning_message_class$ *message, int32_t value) {\n" + " GPBDescriptor *descriptor = [$owning_message_class$ descriptor];\n" + " GPBFieldDescriptor *field = [descriptor fieldWithNumber:$field_number_name$];\n" + " GPBSetMessageRawEnumField(message, field, value);\n" + "}\n" + "\n"); +} + +void EnumFieldGenerator::DetermineForwardDeclarations( + std::set<std::string>* fwd_decls) const { + SingleFieldGenerator::DetermineForwardDeclarations(fwd_decls); + // If it is an enum defined in a different file, then we'll need a forward + // declaration for it. When it is in our file, all the enums are output + // before the message, so it will be declared before it is needed. + if (descriptor_->file() != descriptor_->enum_type()->file()) { + // Enum name is already in "storage_type". + const std::string& name = variable("storage_type"); + fwd_decls->insert("GPB_ENUM_FWD_DECLARE(" + name + ")"); + } +} + +RepeatedEnumFieldGenerator::RepeatedEnumFieldGenerator( + const FieldDescriptor* descriptor, const Options& options) + : RepeatedFieldGenerator(descriptor, options) { + SetEnumVariables(descriptor, &variables_); + variables_["array_storage_type"] = "GPBEnumArray"; +} + +RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() {} + +void RepeatedEnumFieldGenerator::FinishInitialization(void) { + RepeatedFieldGenerator::FinishInitialization(); + variables_["array_comment"] = + "// |" + variables_["name"] + "| contains |" + variables_["storage_type"] + "|\n"; +} + +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_enum_field.h b/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_enum_field.h new file mode 100644 index 00000000..1f11abcb --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_enum_field.h @@ -0,0 +1,80 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_ENUM_FIELD_H__ +#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_ENUM_FIELD_H__ + +#include <map> +#include <string> +#include <compiler/objectivec/objectivec_field.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace objectivec { + +class EnumFieldGenerator : public SingleFieldGenerator { + friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field, + const Options& options); + + EnumFieldGenerator(const EnumFieldGenerator&) = delete; + EnumFieldGenerator& operator=(const EnumFieldGenerator&) = delete; + + public: + virtual void GenerateCFunctionDeclarations( + io::Printer* printer) const override; + virtual void GenerateCFunctionImplementations( + io::Printer* printer) const override; + virtual void DetermineForwardDeclarations( + std::set<std::string>* fwd_decls) const override; + + protected: + EnumFieldGenerator(const FieldDescriptor* descriptor, const Options& options); + virtual ~EnumFieldGenerator(); +}; + +class RepeatedEnumFieldGenerator : public RepeatedFieldGenerator { + friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field, + const Options& options); + + public: + virtual void FinishInitialization() override; + + protected: + RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor, + const Options& options); + virtual ~RepeatedEnumFieldGenerator(); +}; + +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_ENUM_FIELD_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_extension.cc b/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_extension.cc new file mode 100644 index 00000000..7ec80bc9 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_extension.cc @@ -0,0 +1,156 @@ +// 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 <iostream> + +#include <compiler/objectivec/objectivec_extension.h> +#include <compiler/objectivec/objectivec_helpers.h> +#include <descriptor.pb.h> +#include <stubs/strutil.h> +#include <io/printer.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace objectivec { + +ExtensionGenerator::ExtensionGenerator(const std::string& root_class_name, + const FieldDescriptor* descriptor) + : method_name_(ExtensionMethodName(descriptor)), + root_class_and_method_name_(root_class_name + "_" + method_name_), + descriptor_(descriptor) { + if (descriptor->is_map()) { + // 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. + std::cerr << "error: Extension is a map<>!" + << " That used to be blocked by the compiler." << std::endl; + std::cerr.flush(); + abort(); + } +} + +ExtensionGenerator::~ExtensionGenerator() {} + +void ExtensionGenerator::GenerateMembersHeader(io::Printer* printer) { + std::map<std::string, std::string> vars; + vars["method_name"] = method_name_; + if (IsRetainedName(method_name_)) { + vars["storage_attribute"] = " NS_RETURNS_NOT_RETAINED"; + } else { + vars["storage_attribute"] = ""; + } + SourceLocation location; + if (descriptor_->GetSourceLocation(&location)) { + vars["comments"] = BuildCommentsString(location, true); + } else { + vars["comments"] = ""; + } + // Unlike normal message fields, check if the file for the extension was + // deprecated. + vars["deprecated_attribute"] = GetOptionalDeprecatedAttribute(descriptor_, descriptor_->file()); + printer->Print(vars, + "$comments$" + "+ (GPBExtensionDescriptor *)$method_name$$storage_attribute$$deprecated_attribute$;\n"); +} + +void ExtensionGenerator::GenerateStaticVariablesInitialization( + io::Printer* printer) { + std::map<std::string, std::string> vars; + vars["root_class_and_method_name"] = root_class_and_method_name_; + const std::string containing_type = ClassName(descriptor_->containing_type()); + vars["extended_type"] = ObjCClass(containing_type); + vars["number"] = StrCat(descriptor_->number()); + + std::vector<std::string> options; + if (descriptor_->is_repeated()) options.push_back("GPBExtensionRepeated"); + if (descriptor_->is_packed()) options.push_back("GPBExtensionPacked"); + if (descriptor_->containing_type()->options().message_set_wire_format()) { + options.push_back("GPBExtensionSetWireFormat"); + } + vars["options"] = BuildFlagsString(FLAGTYPE_EXTENSION, options); + + ObjectiveCType objc_type = GetObjectiveCType(descriptor_); + if (objc_type == OBJECTIVECTYPE_MESSAGE) { + std::string message_type = ClassName(descriptor_->message_type()); + vars["type"] = ObjCClass(message_type); + } else { + vars["type"] = "Nil"; + } + + vars["default_name"] = GPBGenericValueFieldName(descriptor_); + if (descriptor_->is_repeated()) { + vars["default"] = "nil"; + } else { + vars["default"] = DefaultValue(descriptor_); + } + std::string type = GetCapitalizedType(descriptor_); + vars["extension_type"] = std::string("GPBDataType") + type; + + if (objc_type == OBJECTIVECTYPE_ENUM) { + vars["enum_desc_func_name"] = + EnumName(descriptor_->enum_type()) + "_EnumDescriptor"; + } else { + vars["enum_desc_func_name"] = "NULL"; + } + + printer->Print(vars, + "{\n" + " .defaultValue.$default_name$ = $default$,\n" + " .singletonName = GPBStringifySymbol($root_class_and_method_name$),\n" + " .extendedClass.clazz = $extended_type$,\n" + " .messageOrGroupClass.clazz = $type$,\n" + " .enumDescriptorFunc = $enum_desc_func_name$,\n" + " .fieldNumber = $number$,\n" + " .dataType = $extension_type$,\n" + " .options = $options$,\n" + "},\n"); +} + +void ExtensionGenerator::DetermineObjectiveCClassDefinitions( + std::set<std::string>* fwd_decls) { + std::string extended_type = ClassName(descriptor_->containing_type()); + fwd_decls->insert(ObjCClassDeclaration(extended_type)); + ObjectiveCType objc_type = GetObjectiveCType(descriptor_); + if (objc_type == OBJECTIVECTYPE_MESSAGE) { + std::string message_type = ClassName(descriptor_->message_type()); + fwd_decls->insert(ObjCClassDeclaration(message_type)); + } +} + +void ExtensionGenerator::GenerateRegistrationSource(io::Printer* printer) { + printer->Print( + "[registry addExtension:$root_class_and_method_name$];\n", + "root_class_and_method_name", root_class_and_method_name_); +} + +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_extension.h b/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_extension.h new file mode 100644 index 00000000..b985d831 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_extension.h @@ -0,0 +1,67 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_EXTENSION_H__ +#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_EXTENSION_H__ + +#include <descriptor.h> +#include <io/printer.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace objectivec { + +class ExtensionGenerator { + public: + ExtensionGenerator(const std::string& root_class_name, + const FieldDescriptor* descriptor); + ~ExtensionGenerator(); + + ExtensionGenerator(const ExtensionGenerator&) = delete; + ExtensionGenerator& operator=(const ExtensionGenerator&) = delete; + + void GenerateMembersHeader(io::Printer* printer); + void GenerateStaticVariablesInitialization(io::Printer* printer); + void GenerateRegistrationSource(io::Printer* printer); + void DetermineObjectiveCClassDefinitions(std::set<std::string>* fwd_decls); + + private: + std::string method_name_; + std::string root_class_and_method_name_; + const FieldDescriptor* descriptor_; +}; + +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_MESSAGE_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_field.cc b/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_field.cc new file mode 100644 index 00000000..29f434b5 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_field.cc @@ -0,0 +1,475 @@ +// 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 <iostream> + +#include <compiler/objectivec/objectivec_field.h> +#include <compiler/objectivec/objectivec_helpers.h> +#include <compiler/objectivec/objectivec_enum_field.h> +#include <compiler/objectivec/objectivec_map_field.h> +#include <compiler/objectivec/objectivec_message_field.h> +#include <compiler/objectivec/objectivec_primitive_field.h> +#include <io/printer.h> +#include <wire_format.h> +#include <stubs/strutil.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace objectivec { + +namespace { + +void SetCommonFieldVariables(const FieldDescriptor* descriptor, + std::map<std::string, std::string>* variables) { + std::string camel_case_name = FieldName(descriptor); + std::string raw_field_name; + if (descriptor->type() == FieldDescriptor::TYPE_GROUP) { + raw_field_name = descriptor->message_type()->name(); + } else { + raw_field_name = descriptor->name(); + } + // The logic here has to match -[GGPBFieldDescriptor textFormatName]. + const std::string un_camel_case_name( + UnCamelCaseFieldName(camel_case_name, descriptor)); + const bool needs_custom_name = (raw_field_name != un_camel_case_name); + + SourceLocation location; + if (descriptor->GetSourceLocation(&location)) { + (*variables)["comments"] = BuildCommentsString(location, true); + } else { + (*variables)["comments"] = "\n"; + } + const std::string& classname = ClassName(descriptor->containing_type()); + (*variables)["classname"] = classname; + (*variables)["name"] = camel_case_name; + const std::string& capitalized_name = FieldNameCapitalized(descriptor); + (*variables)["capitalized_name"] = capitalized_name; + (*variables)["raw_field_name"] = raw_field_name; + (*variables)["field_number_name"] = + classname + "_FieldNumber_" + capitalized_name; + (*variables)["field_number"] = StrCat(descriptor->number()); + (*variables)["field_type"] = GetCapitalizedType(descriptor); + (*variables)["deprecated_attribute"] = GetOptionalDeprecatedAttribute(descriptor); + std::vector<std::string> field_flags; + if (descriptor->is_repeated()) field_flags.push_back("GPBFieldRepeated"); + if (descriptor->is_required()) field_flags.push_back("GPBFieldRequired"); + if (descriptor->is_optional()) field_flags.push_back("GPBFieldOptional"); + if (descriptor->is_packed()) field_flags.push_back("GPBFieldPacked"); + + // ObjC custom flags. + if (descriptor->has_default_value()) + field_flags.push_back("GPBFieldHasDefaultValue"); + if (needs_custom_name) field_flags.push_back("GPBFieldTextFormatNameCustom"); + if (descriptor->type() == FieldDescriptor::TYPE_ENUM) { + field_flags.push_back("GPBFieldHasEnumDescriptor"); + } + // It will clear on a zero value if... + // - not repeated/map + // - doesn't have presence + bool clear_on_zero = + (!descriptor->is_repeated() && !descriptor->has_presence()); + if (clear_on_zero) { + field_flags.push_back("GPBFieldClearHasIvarOnZero"); + } + + (*variables)["fieldflags"] = BuildFlagsString(FLAGTYPE_FIELD, field_flags); + + (*variables)["default"] = DefaultValue(descriptor); + (*variables)["default_name"] = GPBGenericValueFieldName(descriptor); + + (*variables)["dataTypeSpecific_name"] = "clazz"; + (*variables)["dataTypeSpecific_value"] = "Nil"; + + (*variables)["storage_offset_value"] = + "(uint32_t)offsetof(" + classname + "__storage_, " + camel_case_name + ")"; + (*variables)["storage_offset_comment"] = ""; + + // Clear some common things so they can be set just when needed. + (*variables)["storage_attribute"] = ""; +} + +} // namespace + +FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field, + const Options& options) { + FieldGenerator* result = NULL; + if (field->is_repeated()) { + switch (GetObjectiveCType(field)) { + case OBJECTIVECTYPE_MESSAGE: { + if (field->is_map()) { + result = new MapFieldGenerator(field, options); + } else { + result = new RepeatedMessageFieldGenerator(field, options); + } + break; + } + case OBJECTIVECTYPE_ENUM: + result = new RepeatedEnumFieldGenerator(field, options); + break; + default: + result = new RepeatedPrimitiveFieldGenerator(field, options); + break; + } + } else { + switch (GetObjectiveCType(field)) { + case OBJECTIVECTYPE_MESSAGE: { + result = new MessageFieldGenerator(field, options); + break; + } + case OBJECTIVECTYPE_ENUM: + result = new EnumFieldGenerator(field, options); + break; + default: + if (IsReferenceType(field)) { + result = new PrimitiveObjFieldGenerator(field, options); + } else { + result = new PrimitiveFieldGenerator(field, options); + } + break; + } + } + result->FinishInitialization(); + return result; +} + +FieldGenerator::FieldGenerator(const FieldDescriptor* descriptor, + const Options& options) + : descriptor_(descriptor) { + SetCommonFieldVariables(descriptor, &variables_); +} + +FieldGenerator::~FieldGenerator() {} + +void FieldGenerator::GenerateFieldNumberConstant(io::Printer* printer) const { + printer->Print( + variables_, + "$field_number_name$ = $field_number$,\n"); +} + +void FieldGenerator::GenerateCFunctionDeclarations( + io::Printer* printer) const { + // Nothing +} + +void FieldGenerator::GenerateCFunctionImplementations( + io::Printer* printer) const { + // Nothing +} + +void FieldGenerator::DetermineForwardDeclarations( + std::set<std::string>* fwd_decls) const { + // Nothing +} + +void FieldGenerator::DetermineObjectiveCClassDefinitions( + std::set<std::string>* fwd_decls) const { + // Nothing +} + +void FieldGenerator::GenerateFieldDescription( + io::Printer* printer, bool include_default) const { + // Printed in the same order as the structure decl. + if (include_default) { + printer->Print( + variables_, + "{\n" + " .defaultValue.$default_name$ = $default$,\n" + " .core.name = \"$name$\",\n" + " .core.dataTypeSpecific.$dataTypeSpecific_name$ = $dataTypeSpecific_value$,\n" + " .core.number = $field_number_name$,\n" + " .core.hasIndex = $has_index$,\n" + " .core.offset = $storage_offset_value$,$storage_offset_comment$\n" + " .core.flags = $fieldflags$,\n" + " .core.dataType = GPBDataType$field_type$,\n" + "},\n"); + } else { + printer->Print( + variables_, + "{\n" + " .name = \"$name$\",\n" + " .dataTypeSpecific.$dataTypeSpecific_name$ = $dataTypeSpecific_value$,\n" + " .number = $field_number_name$,\n" + " .hasIndex = $has_index$,\n" + " .offset = $storage_offset_value$,$storage_offset_comment$\n" + " .flags = $fieldflags$,\n" + " .dataType = GPBDataType$field_type$,\n" + "},\n"); + } +} + +void FieldGenerator::SetRuntimeHasBit(int has_index) { + variables_["has_index"] = StrCat(has_index); +} + +void FieldGenerator::SetNoHasBit(void) { + variables_["has_index"] = "GPBNoHasBit"; +} + +int FieldGenerator::ExtraRuntimeHasBitsNeeded(void) const { + return 0; +} + +void FieldGenerator::SetExtraRuntimeHasBitsBase(int index_base) { + // 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. + std::cerr << "Error: should have overridden SetExtraRuntimeHasBitsBase()." << std::endl; + std::cerr.flush(); + abort(); +} + +void FieldGenerator::SetOneofIndexBase(int index_base) { + const OneofDescriptor* oneof = descriptor_->real_containing_oneof(); + if (oneof != NULL) { + int index = oneof->index() + index_base; + // Flip the sign to mark it as a oneof. + variables_["has_index"] = StrCat(-index); + } +} + +bool FieldGenerator::WantsHasProperty(void) const { + return descriptor_->has_presence() && !descriptor_->real_containing_oneof(); +} + +void FieldGenerator::FinishInitialization(void) { + // If "property_type" wasn't set, make it "storage_type". + if ((variables_.find("property_type") == variables_.end()) && + (variables_.find("storage_type") != variables_.end())) { + variables_["property_type"] = variable("storage_type"); + } +} + +SingleFieldGenerator::SingleFieldGenerator(const FieldDescriptor* descriptor, + const Options& options) + : FieldGenerator(descriptor, options) { + // Nothing +} + +SingleFieldGenerator::~SingleFieldGenerator() {} + +void SingleFieldGenerator::GenerateFieldStorageDeclaration( + io::Printer* printer) const { + printer->Print(variables_, "$storage_type$ $name$;\n"); +} + +void SingleFieldGenerator::GeneratePropertyDeclaration( + io::Printer* printer) const { + printer->Print(variables_, "$comments$"); + printer->Print( + variables_, + "@property(nonatomic, readwrite) $property_type$ $name$$deprecated_attribute$;\n" + "\n"); + if (WantsHasProperty()) { + printer->Print( + variables_, + "@property(nonatomic, readwrite) BOOL has$capitalized_name$$deprecated_attribute$;\n"); + } +} + +void SingleFieldGenerator::GeneratePropertyImplementation( + io::Printer* printer) const { + if (WantsHasProperty()) { + printer->Print(variables_, "@dynamic has$capitalized_name$, $name$;\n"); + } else { + printer->Print(variables_, "@dynamic $name$;\n"); + } +} + +bool SingleFieldGenerator::RuntimeUsesHasBit(void) const { + if (descriptor_->real_containing_oneof()) { + // The oneof tracks what is set instead. + return false; + } + return true; +} + +ObjCObjFieldGenerator::ObjCObjFieldGenerator(const FieldDescriptor* descriptor, + const Options& options) + : SingleFieldGenerator(descriptor, options) { + variables_["property_storage_attribute"] = "strong"; + if (IsRetainedName(variables_["name"])) { + variables_["storage_attribute"] = " NS_RETURNS_NOT_RETAINED"; + } +} + +ObjCObjFieldGenerator::~ObjCObjFieldGenerator() {} + +void ObjCObjFieldGenerator::GenerateFieldStorageDeclaration( + io::Printer* printer) const { + printer->Print(variables_, "$storage_type$ *$name$;\n"); +} + +void ObjCObjFieldGenerator::GeneratePropertyDeclaration( + io::Printer* printer) const { + + // Differs from SingleFieldGenerator::GeneratePropertyDeclaration() in that + // it uses pointers and deals with Objective C's rules around storage name + // conventions (init*, new*, etc.) + + printer->Print(variables_, "$comments$"); + printer->Print( + variables_, + "@property(nonatomic, readwrite, $property_storage_attribute$, null_resettable) $property_type$ *$name$$storage_attribute$$deprecated_attribute$;\n"); + if (WantsHasProperty()) { + printer->Print( + variables_, + "/** Test to see if @c $name$ has been set. */\n" + "@property(nonatomic, readwrite) BOOL has$capitalized_name$$deprecated_attribute$;\n"); + } + if (IsInitName(variables_.find("name")->second)) { + // If property name starts with init we need to annotate it to get past ARC. + // http://stackoverflow.com/questions/18723226/how-do-i-annotate-an-objective-c-property-with-an-objc-method-family/18723227#18723227 + printer->Print(variables_, + "- ($property_type$ *)$name$ GPB_METHOD_FAMILY_NONE$deprecated_attribute$;\n"); + } + printer->Print("\n"); +} + +RepeatedFieldGenerator::RepeatedFieldGenerator( + const FieldDescriptor* descriptor, const Options& options) + : ObjCObjFieldGenerator(descriptor, options) { + // Default to no comment and let the cases needing it fill it in. + variables_["array_comment"] = ""; +} + +RepeatedFieldGenerator::~RepeatedFieldGenerator() {} + +void RepeatedFieldGenerator::FinishInitialization(void) { + FieldGenerator::FinishInitialization(); + if (variables_.find("array_property_type") == variables_.end()) { + variables_["array_property_type"] = variable("array_storage_type"); + } +} + +void RepeatedFieldGenerator::GenerateFieldStorageDeclaration( + io::Printer* printer) const { + printer->Print(variables_, "$array_storage_type$ *$name$;\n"); +} + +void RepeatedFieldGenerator::GeneratePropertyImplementation( + io::Printer* printer) const { + printer->Print(variables_, "@dynamic $name$, $name$_Count;\n"); +} + +void RepeatedFieldGenerator::GeneratePropertyDeclaration( + io::Printer* printer) const { + + // Repeated fields don't need the has* properties, but they do expose a + // *Count (to check without autocreation). So for the field property we need + // the same logic as ObjCObjFieldGenerator::GeneratePropertyDeclaration() for + // dealing with needing Objective C's rules around storage name conventions + // (init*, new*, etc.) + + printer->Print( + variables_, + "$comments$" + "$array_comment$" + "@property(nonatomic, readwrite, strong, null_resettable) $array_property_type$ *$name$$storage_attribute$$deprecated_attribute$;\n" + "/** The number of items in @c $name$ without causing the array to be created. */\n" + "@property(nonatomic, readonly) NSUInteger $name$_Count$deprecated_attribute$;\n"); + if (IsInitName(variables_.find("name")->second)) { + // If property name starts with init we need to annotate it to get past ARC. + // http://stackoverflow.com/questions/18723226/how-do-i-annotate-an-objective-c-property-with-an-objc-method-family/18723227#18723227 + printer->Print(variables_, + "- ($array_property_type$ *)$name$ GPB_METHOD_FAMILY_NONE$deprecated_attribute$;\n"); + } + printer->Print("\n"); +} + +bool RepeatedFieldGenerator::RuntimeUsesHasBit(void) const { + return false; // The array (or map/dict) having anything is what is used. +} + +FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor, + const Options& options) + : descriptor_(descriptor), + field_generators_(descriptor->field_count()), + extension_generators_(descriptor->extension_count()) { + // Construct all the FieldGenerators. + for (int i = 0; i < descriptor->field_count(); i++) { + field_generators_[i].reset( + FieldGenerator::Make(descriptor->field(i), options)); + } + for (int i = 0; i < descriptor->extension_count(); i++) { + extension_generators_[i].reset( + FieldGenerator::Make(descriptor->extension(i), options)); + } +} + +FieldGeneratorMap::~FieldGeneratorMap() {} + +const FieldGenerator& FieldGeneratorMap::get( + const FieldDescriptor* field) const { + GOOGLE_CHECK_EQ(field->containing_type(), descriptor_); + return *field_generators_[field->index()]; +} + +const FieldGenerator& FieldGeneratorMap::get_extension(int index) const { + return *extension_generators_[index]; +} + +int FieldGeneratorMap::CalculateHasBits(void) { + int total_bits = 0; + for (int i = 0; i < descriptor_->field_count(); i++) { + if (field_generators_[i]->RuntimeUsesHasBit()) { + field_generators_[i]->SetRuntimeHasBit(total_bits); + ++total_bits; + } else { + field_generators_[i]->SetNoHasBit(); + } + int extra_bits = field_generators_[i]->ExtraRuntimeHasBitsNeeded(); + if (extra_bits) { + field_generators_[i]->SetExtraRuntimeHasBitsBase(total_bits); + total_bits += extra_bits; + } + } + return total_bits; +} + +void FieldGeneratorMap::SetOneofIndexBase(int index_base) { + for (int i = 0; i < descriptor_->field_count(); i++) { + field_generators_[i]->SetOneofIndexBase(index_base); + } +} + +bool FieldGeneratorMap::DoesAnyFieldHaveNonZeroDefault(void) const { + for (int i = 0; i < descriptor_->field_count(); i++) { + if (HasNonZeroDefaultValue(descriptor_->field(i))) { + return true; + } + } + + return false; +} + +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_field.h b/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_field.h new file mode 100644 index 00000000..ee213ff4 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_field.h @@ -0,0 +1,194 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_FIELD_H__ +#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_FIELD_H__ + +#include <map> +#include <string> +#include <compiler/objectivec/objectivec_helpers.h> +#include <descriptor.h> +#include <io/printer.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace objectivec { + +class FieldGenerator { + public: + static FieldGenerator* Make(const FieldDescriptor* field, + const Options& options); + + virtual ~FieldGenerator(); + + FieldGenerator(const FieldGenerator&) = delete; + FieldGenerator& operator=(const FieldGenerator&) = delete; + + // Exposed for subclasses to fill in. + virtual void GenerateFieldStorageDeclaration(io::Printer* printer) const = 0; + virtual void GeneratePropertyDeclaration(io::Printer* printer) const = 0; + virtual void GeneratePropertyImplementation(io::Printer* printer) const = 0; + + // Called by GenerateFieldDescription, exposed for classes that need custom + // generation. + + // Exposed for subclasses to extend, base does nothing. + virtual void GenerateCFunctionDeclarations(io::Printer* printer) const; + virtual void GenerateCFunctionImplementations(io::Printer* printer) const; + + // Exposed for subclasses, should always call it on the parent class also. + virtual void DetermineForwardDeclarations( + std::set<std::string>* fwd_decls) const; + virtual void DetermineObjectiveCClassDefinitions( + std::set<std::string>* fwd_decls) const; + + // Used during generation, not intended to be extended by subclasses. + void GenerateFieldDescription( + io::Printer* printer, bool include_default) const; + void GenerateFieldNumberConstant(io::Printer* printer) const; + + // Exposed to get and set the has bits information. + virtual bool RuntimeUsesHasBit(void) const = 0; + void SetRuntimeHasBit(int has_index); + void SetNoHasBit(void); + virtual int ExtraRuntimeHasBitsNeeded(void) const; + virtual void SetExtraRuntimeHasBitsBase(int index_base); + void SetOneofIndexBase(int index_base); + + std::string variable(const char* key) const { + return variables_.find(key)->second; + } + + bool needs_textformat_name_support() const { + const std::string& field_flags = variable("fieldflags"); + return field_flags.find("GPBFieldTextFormatNameCustom") != + std::string::npos; + } + std::string generated_objc_name() const { return variable("name"); } + std::string raw_field_name() const { return variable("raw_field_name"); } + + protected: + FieldGenerator(const FieldDescriptor* descriptor, const Options& options); + + virtual void FinishInitialization(void); + bool WantsHasProperty(void) const; + + const FieldDescriptor* descriptor_; + std::map<std::string, std::string> variables_; +}; + +class SingleFieldGenerator : public FieldGenerator { + public: + virtual ~SingleFieldGenerator(); + + SingleFieldGenerator(const SingleFieldGenerator&) = delete; + SingleFieldGenerator& operator=(const SingleFieldGenerator&) = delete; + + virtual void GenerateFieldStorageDeclaration(io::Printer* printer) const override; + virtual void GeneratePropertyDeclaration(io::Printer* printer) const override; + + virtual void GeneratePropertyImplementation(io::Printer* printer) const override; + + virtual bool RuntimeUsesHasBit(void) const override; + + protected: + SingleFieldGenerator(const FieldDescriptor* descriptor, + const Options& options); +}; + +// Subclass with common support for when the field ends up as an ObjC Object. +class ObjCObjFieldGenerator : public SingleFieldGenerator { + public: + virtual ~ObjCObjFieldGenerator(); + + ObjCObjFieldGenerator(const ObjCObjFieldGenerator&) = delete; + ObjCObjFieldGenerator& operator=(const ObjCObjFieldGenerator&) = delete; + + virtual void GenerateFieldStorageDeclaration(io::Printer* printer) const override; + virtual void GeneratePropertyDeclaration(io::Printer* printer) const override; + + protected: + ObjCObjFieldGenerator(const FieldDescriptor* descriptor, + const Options& options); +}; + +class RepeatedFieldGenerator : public ObjCObjFieldGenerator { + public: + virtual ~RepeatedFieldGenerator(); + + RepeatedFieldGenerator(const RepeatedFieldGenerator&) = delete; + RepeatedFieldGenerator& operator=(const RepeatedFieldGenerator&) = delete; + + virtual void GenerateFieldStorageDeclaration(io::Printer* printer) const override; + virtual void GeneratePropertyDeclaration(io::Printer* printer) const override; + + virtual void GeneratePropertyImplementation(io::Printer* printer) const override; + + virtual bool RuntimeUsesHasBit(void) const override; + + protected: + RepeatedFieldGenerator(const FieldDescriptor* descriptor, + const Options& options); + virtual void FinishInitialization(void) override; +}; + +// Convenience class which constructs FieldGenerators for a Descriptor. +class FieldGeneratorMap { + public: + FieldGeneratorMap(const Descriptor* descriptor, const Options& options); + ~FieldGeneratorMap(); + + FieldGeneratorMap(const FieldGeneratorMap&) = delete; + FieldGeneratorMap& operator=(const FieldGeneratorMap&) = delete; + + const FieldGenerator& get(const FieldDescriptor* field) const; + const FieldGenerator& get_extension(int index) const; + + // Assigns the has bits and returns the number of bits needed. + int CalculateHasBits(void); + + void SetOneofIndexBase(int index_base); + + // Check if any field of this message has a non zero default. + bool DoesAnyFieldHaveNonZeroDefault(void) const; + + private: + const Descriptor* descriptor_; + std::vector<std::unique_ptr<FieldGenerator>> field_generators_; + std::vector<std::unique_ptr<FieldGenerator>> extension_generators_; +}; + +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_FIELD_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_file.cc b/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_file.cc new file mode 100644 index 00000000..e98a8985 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_file.cc @@ -0,0 +1,610 @@ +// 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 <compiler/objectivec/objectivec_file.h> +#include <compiler/objectivec/objectivec_enum.h> +#include <compiler/objectivec/objectivec_extension.h> +#include <compiler/objectivec/objectivec_message.h> +#include <compiler/code_generator.h> +#include <io/printer.h> +#include <io/zero_copy_stream_impl.h> +#include <stubs/stl_util.h> +#include <stubs/strutil.h> +#include <algorithm> // std::find() +#include <iostream> +#include <sstream> + +// 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 { + +namespace { + +// This is also found in GPBBootstrap.h, and needs to be kept in sync. +const int32_t GOOGLE_PROTOBUF_OBJC_VERSION = 30004; + +const char* kHeaderExtension = ".pbobjc.h"; + +// Checks if a message contains any enums definitions (on the message or +// a nested message under it). +bool MessageContainsEnums(const Descriptor* message) { + if (message->enum_type_count() > 0) { + return true; + } + for (int i = 0; i < message->nested_type_count(); i++) { + if (MessageContainsEnums(message->nested_type(i))) { + return true; + } + } + return false; +} + +// Checks if a message contains any extension definitions (on the message or +// a nested message under it). +bool MessageContainsExtensions(const Descriptor* message) { + if (message->extension_count() > 0) { + return true; + } + for (int i = 0; i < message->nested_type_count(); i++) { + if (MessageContainsExtensions(message->nested_type(i))) { + return true; + } + } + return false; +} + +// Checks if the file contains any enum definitions (at the root or +// nested under a message). +bool FileContainsEnums(const FileDescriptor* file) { + if (file->enum_type_count() > 0) { + return true; + } + for (int i = 0; i < file->message_type_count(); i++) { + if (MessageContainsEnums(file->message_type(i))) { + return true; + } + } + return false; +} + +// Checks if the file contains any extensions definitions (at the root or +// nested under a message). +bool FileContainsExtensions(const FileDescriptor* file) { + if (file->extension_count() > 0) { + return true; + } + for (int i = 0; i < file->message_type_count(); i++) { + if (MessageContainsExtensions(file->message_type(i))) { + return true; + } + } + return false; +} + +// Helper for CollectMinimalFileDepsContainingExtensionsWorker that marks all +// deps as visited and prunes them from the needed files list. +void PruneFileAndDepsMarkingAsVisited( + const FileDescriptor* file, + std::vector<const FileDescriptor*>* files, + std::set<const FileDescriptor*>* files_visited) { + std::vector<const FileDescriptor*>::iterator iter = + std::find(files->begin(), files->end(), file); + if (iter != files->end()) { + files->erase(iter); + } + files_visited->insert(file); + for (int i = 0; i < file->dependency_count(); i++) { + PruneFileAndDepsMarkingAsVisited(file->dependency(i), files, files_visited); + } +} + +// Helper for CollectMinimalFileDepsContainingExtensions. +void CollectMinimalFileDepsContainingExtensionsWorker( + const FileDescriptor* file, + std::vector<const FileDescriptor*>* files, + std::set<const FileDescriptor*>* files_visited) { + if (files_visited->find(file) != files_visited->end()) { + return; + } + files_visited->insert(file); + + if (FileContainsExtensions(file)) { + files->push_back(file); + for (int i = 0; i < file->dependency_count(); i++) { + const FileDescriptor* dep = file->dependency(i); + PruneFileAndDepsMarkingAsVisited(dep, files, files_visited); + } + } else { + for (int i = 0; i < file->dependency_count(); i++) { + const FileDescriptor* dep = file->dependency(i); + CollectMinimalFileDepsContainingExtensionsWorker(dep, files, + files_visited); + } + } +} + +// Collect the deps of the given file that contain extensions. This can be used to +// create the chain of roots that need to be wired together. +// +// NOTE: If any changes are made to this and the supporting functions, you will +// need to manually validate what the generated code is for the test files: +// objectivec/Tests/unittest_extension_chain_*.proto +// There are comments about what the expected code should be line and limited +// testing objectivec/Tests/GPBUnittestProtos2.m around compilation (#imports +// specifically). +void CollectMinimalFileDepsContainingExtensions( + const FileDescriptor* file, + std::vector<const FileDescriptor*>* files) { + std::set<const FileDescriptor*> files_visited; + for (int i = 0; i < file->dependency_count(); i++) { + const FileDescriptor* dep = file->dependency(i); + CollectMinimalFileDepsContainingExtensionsWorker(dep, files, + &files_visited); + } +} + +bool IsDirectDependency(const FileDescriptor* dep, const FileDescriptor* file) { + for (int i = 0; i < file->dependency_count(); i++) { + if (dep == file->dependency(i)) { + return true; + } + } + return false; +} + +} // namespace + +FileGenerator::FileGenerator(const FileDescriptor* file, const Options& options) + : file_(file), + root_class_name_(FileClassName(file)), + is_bundled_proto_(IsProtobufLibraryBundledProtoFile(file)), + options_(options) { + for (int i = 0; i < file_->enum_type_count(); i++) { + EnumGenerator* generator = new EnumGenerator(file_->enum_type(i)); + enum_generators_.emplace_back(generator); + } + for (int i = 0; i < file_->message_type_count(); i++) { + MessageGenerator* generator = + new MessageGenerator(root_class_name_, file_->message_type(i), options_); + message_generators_.emplace_back(generator); + } + for (int i = 0; i < file_->extension_count(); i++) { + ExtensionGenerator* generator = + new ExtensionGenerator(root_class_name_, file_->extension(i)); + extension_generators_.emplace_back(generator); + } +} + +FileGenerator::~FileGenerator() {} + +void FileGenerator::GenerateHeader(io::Printer* printer) { + std::vector<std::string> headers; + // Generated files bundled with the library get minimal imports, everything + // else gets the wrapper so everything is usable. + if (is_bundled_proto_) { + headers.push_back("GPBDescriptor.h"); + headers.push_back("GPBMessage.h"); + headers.push_back("GPBRootObject.h"); + } else { + headers.push_back("GPBProtocolBuffers.h"); + } + PrintFileRuntimePreamble(printer, headers); + + // Add some verification that the generated code matches the source the + // code is being compiled with. + // NOTE: This captures the raw numeric values at the time the generator was + // compiled, since that will be the versions for the ObjC runtime at that + // time. The constants in the generated code will then get their values at + // at compile time (so checking against the headers being used to compile). + printer->Print( + "#if GOOGLE_PROTOBUF_OBJC_VERSION < $google_protobuf_objc_version$\n" + "#error This file was generated by a newer version of protoc which is incompatible with your Protocol Buffer library sources.\n" + "#endif\n" + "#if $google_protobuf_objc_version$ < GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION\n" + "#error This file was generated by an older version of protoc which is incompatible with your Protocol Buffer library sources.\n" + "#endif\n" + "\n", + "google_protobuf_objc_version", StrCat(GOOGLE_PROTOBUF_OBJC_VERSION)); + + // #import any headers for "public imports" in the proto file. + { + ImportWriter import_writer( + options_.generate_for_named_framework, + options_.named_framework_to_proto_path_mappings_path, + options_.runtime_import_prefix, + is_bundled_proto_); + const std::string header_extension(kHeaderExtension); + for (int i = 0; i < file_->public_dependency_count(); i++) { + import_writer.AddFile(file_->public_dependency(i), header_extension); + } + import_writer.Print(printer); + } + + // Note: + // deprecated-declarations suppression is only needed if some place in this + // proto file is something deprecated or if it references something from + // another file that is deprecated. + printer->Print( + "// @@protoc_insertion_point(imports)\n" + "\n" + "#pragma clang diagnostic push\n" + "#pragma clang diagnostic ignored \"-Wdeprecated-declarations\"\n" + "\n" + "CF_EXTERN_C_BEGIN\n" + "\n"); + + std::set<std::string> fwd_decls; + for (const auto& generator : message_generators_) { + generator->DetermineForwardDeclarations(&fwd_decls); + } + for (std::set<std::string>::const_iterator i(fwd_decls.begin()); + i != fwd_decls.end(); ++i) { + printer->Print("$value$;\n", "value", *i); + } + if (fwd_decls.begin() != fwd_decls.end()) { + printer->Print("\n"); + } + + printer->Print( + "NS_ASSUME_NONNULL_BEGIN\n" + "\n"); + + // need to write out all enums first + for (const auto& generator : enum_generators_) { + generator->GenerateHeader(printer); + } + + for (const auto& generator : message_generators_) { + generator->GenerateEnumHeader(printer); + } + + // For extensions to chain together, the Root gets created even if there + // are no extensions. + printer->Print( + "#pragma mark - $root_class_name$\n" + "\n" + "/**\n" + " * Exposes the extension registry for this file.\n" + " *\n" + " * The base class provides:\n" + " * @code\n" + " * + (GPBExtensionRegistry *)extensionRegistry;\n" + " * @endcode\n" + " * which is a @c GPBExtensionRegistry that includes all the extensions defined by\n" + " * this file and all files that it depends on.\n" + " **/\n" + "GPB_FINAL @interface $root_class_name$ : GPBRootObject\n" + "@end\n" + "\n", + "root_class_name", root_class_name_); + + if (!extension_generators_.empty()) { + // The dynamic methods block is only needed if there are extensions. + printer->Print( + "@interface $root_class_name$ (DynamicMethods)\n", + "root_class_name", root_class_name_); + + for (const auto& generator : extension_generators_) { + generator->GenerateMembersHeader(printer); + } + + printer->Print("@end\n\n"); + } // !extension_generators_.empty() + + for (const auto& generator : message_generators_) { + generator->GenerateMessageHeader(printer); + } + + printer->Print( + "NS_ASSUME_NONNULL_END\n" + "\n" + "CF_EXTERN_C_END\n" + "\n" + "#pragma clang diagnostic pop\n" + "\n" + "// @@protoc_insertion_point(global_scope)\n"); +} + +void FileGenerator::GenerateSource(io::Printer* printer) { + // #import the runtime support. + std::vector<std::string> headers; + headers.push_back("GPBProtocolBuffers_RuntimeSupport.h"); + PrintFileRuntimePreamble(printer, headers); + + // Enums use atomic in the generated code, so add the system import as needed. + if (FileContainsEnums(file_)) { + printer->Print( + "#import <stdatomic.h>\n" + "\n"); + } + + std::vector<const FileDescriptor*> deps_with_extensions; + CollectMinimalFileDepsContainingExtensions(file_, &deps_with_extensions); + + { + ImportWriter import_writer( + options_.generate_for_named_framework, + options_.named_framework_to_proto_path_mappings_path, + options_.runtime_import_prefix, + is_bundled_proto_); + const std::string header_extension(kHeaderExtension); + + // #import the header for this proto file. + import_writer.AddFile(file_, header_extension); + + // #import the headers for anything that a plain dependency of this proto + // file (that means they were just an include, not a "public" include). + std::set<std::string> public_import_names; + for (int i = 0; i < file_->public_dependency_count(); i++) { + public_import_names.insert(file_->public_dependency(i)->name()); + } + for (int i = 0; i < file_->dependency_count(); i++) { + const FileDescriptor *dep = file_->dependency(i); + bool public_import = (public_import_names.count(dep->name()) != 0); + if (!public_import) { + import_writer.AddFile(dep, header_extension); + } + } + + // If any indirect dependency provided extensions, it needs to be directly + // imported so it can get merged into the root's extensions registry. + // See the Note by CollectMinimalFileDepsContainingExtensions before + // changing this. + for (std::vector<const FileDescriptor*>::iterator iter = + deps_with_extensions.begin(); + iter != deps_with_extensions.end(); ++iter) { + if (!IsDirectDependency(*iter, file_)) { + import_writer.AddFile(*iter, header_extension); + } + } + + import_writer.Print(printer); + } + + bool includes_oneof = false; + for (const auto& generator : message_generators_) { + if (generator->IncludesOneOfDefinition()) { + includes_oneof = true; + break; + } + } + + std::set<std::string> fwd_decls; + for (const auto& generator : message_generators_) { + generator->DetermineObjectiveCClassDefinitions(&fwd_decls); + } + for (const auto& generator : extension_generators_) { + generator->DetermineObjectiveCClassDefinitions(&fwd_decls); + } + + // Note: + // deprecated-declarations suppression is only needed if some place in this + // proto file is something deprecated or if it references something from + // another file that is deprecated. + // dollar-in-identifier-extension is needed because we use references to + // objc class names that have $ in identifiers. + printer->Print( + "// @@protoc_insertion_point(imports)\n" + "\n" + "#pragma clang diagnostic push\n" + "#pragma clang diagnostic ignored \"-Wdeprecated-declarations\"\n"); + if (includes_oneof) { + // The generated code for oneof's uses direct ivar access, suppress the + // warning in case developer turn that on in the context they compile the + // generated code. + printer->Print( + "#pragma clang diagnostic ignored \"-Wdirect-ivar-access\"\n"); + } + if (!fwd_decls.empty()) { + printer->Print( + "#pragma clang diagnostic ignored \"-Wdollar-in-identifier-extension\"\n"); + } + printer->Print( + "\n"); + if (!fwd_decls.empty()) { + printer->Print( + "#pragma mark - Objective C Class declarations\n" + "// Forward declarations of Objective C classes that we can use as\n" + "// static values in struct initializers.\n" + "// We don't use [Foo class] because it is not a static value.\n"); + } + for (const auto& i : fwd_decls) { + printer->Print("$value$\n", "value", i); + } + if (!fwd_decls.empty()) { + printer->Print("\n"); + } + printer->Print( + "#pragma mark - $root_class_name$\n" + "\n" + "@implementation $root_class_name$\n\n", + "root_class_name", root_class_name_); + + const bool file_contains_extensions = FileContainsExtensions(file_); + + // If there were any extensions or this file has any dependencies, output + // a registry to override to create the file specific registry. + if (file_contains_extensions || !deps_with_extensions.empty()) { + printer->Print( + "+ (GPBExtensionRegistry*)extensionRegistry {\n" + " // This is called by +initialize so there is no need to worry\n" + " // about thread safety and initialization of registry.\n" + " static GPBExtensionRegistry* registry = nil;\n" + " if (!registry) {\n" + " GPB_DEBUG_CHECK_RUNTIME_VERSIONS();\n" + " registry = [[GPBExtensionRegistry alloc] init];\n"); + + printer->Indent(); + printer->Indent(); + + if (file_contains_extensions) { + printer->Print( + "static GPBExtensionDescription descriptions[] = {\n"); + printer->Indent(); + for (const auto& generator : extension_generators_) { + generator->GenerateStaticVariablesInitialization(printer); + } + for (const auto& generator : message_generators_) { + generator->GenerateStaticVariablesInitialization(printer); + } + printer->Outdent(); + printer->Print( + "};\n" + "for (size_t i = 0; i < sizeof(descriptions) / sizeof(descriptions[0]); ++i) {\n" + " GPBExtensionDescriptor *extension =\n" + " [[GPBExtensionDescriptor alloc] initWithExtensionDescription:&descriptions[i]\n" + " usesClassRefs:YES];\n" + " [registry addExtension:extension];\n" + " [self globallyRegisterExtension:extension];\n" + " [extension release];\n" + "}\n"); + } + + if (deps_with_extensions.empty()) { + printer->Print( + "// None of the imports (direct or indirect) defined extensions, so no need to add\n" + "// them to this registry.\n"); + } else { + printer->Print( + "// Merge in the imports (direct or indirect) that defined extensions.\n"); + for (std::vector<const FileDescriptor*>::iterator iter = + deps_with_extensions.begin(); + iter != deps_with_extensions.end(); ++iter) { + const std::string root_class_name(FileClassName((*iter))); + printer->Print( + "[registry addExtensions:[$dependency$ extensionRegistry]];\n", + "dependency", root_class_name); + } + } + + printer->Outdent(); + printer->Outdent(); + + printer->Print( + " }\n" + " return registry;\n" + "}\n"); + } else { + if (file_->dependency_count() > 0) { + printer->Print( + "// No extensions in the file and none of the imports (direct or indirect)\n" + "// defined extensions, so no need to generate +extensionRegistry.\n"); + } else { + printer->Print( + "// No extensions in the file and no imports, so no need to generate\n" + "// +extensionRegistry.\n"); + } + } + + printer->Print("\n@end\n\n"); + + // File descriptor only needed if there are messages to use it. + if (!message_generators_.empty()) { + std::map<std::string, std::string> vars; + vars["root_class_name"] = root_class_name_; + vars["package"] = file_->package(); + vars["objc_prefix"] = FileClassPrefix(file_); + switch (file_->syntax()) { + case FileDescriptor::SYNTAX_UNKNOWN: + vars["syntax"] = "GPBFileSyntaxUnknown"; + break; + case FileDescriptor::SYNTAX_PROTO2: + vars["syntax"] = "GPBFileSyntaxProto2"; + break; + case FileDescriptor::SYNTAX_PROTO3: + vars["syntax"] = "GPBFileSyntaxProto3"; + break; + } + printer->Print(vars, + "#pragma mark - $root_class_name$_FileDescriptor\n" + "\n" + "static GPBFileDescriptor *$root_class_name$_FileDescriptor(void) {\n" + " // This is called by +initialize so there is no need to worry\n" + " // about thread safety of the singleton.\n" + " static GPBFileDescriptor *descriptor = NULL;\n" + " if (!descriptor) {\n" + " GPB_DEBUG_CHECK_RUNTIME_VERSIONS();\n"); + if (!vars["objc_prefix"].empty()) { + printer->Print( + vars, + " descriptor = [[GPBFileDescriptor alloc] initWithPackage:@\"$package$\"\n" + " objcPrefix:@\"$objc_prefix$\"\n" + " syntax:$syntax$];\n"); + } else { + printer->Print( + vars, + " descriptor = [[GPBFileDescriptor alloc] initWithPackage:@\"$package$\"\n" + " syntax:$syntax$];\n"); + } + printer->Print( + " }\n" + " return descriptor;\n" + "}\n" + "\n"); + } + + for (const auto& generator : enum_generators_) { + generator->GenerateSource(printer); + } + for (const auto& generator : message_generators_) { + generator->GenerateSource(printer); + } + + printer->Print( + "\n" + "#pragma clang diagnostic pop\n" + "\n" + "// @@protoc_insertion_point(global_scope)\n"); +} + +// Helper to print the import of the runtime support at the top of generated +// files. This currently only supports the runtime coming from a framework +// as defined by the official CocoaPod. +void FileGenerator::PrintFileRuntimePreamble( + io::Printer* printer, + const std::vector<std::string>& headers_to_import) const { + printer->Print( + "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" + "// source: $filename$\n" + "\n", + "filename", file_->name()); + ImportWriter::PrintRuntimeImports( + printer, headers_to_import, options_.runtime_import_prefix, true); + printer->Print("\n"); +} + +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_file.h b/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_file.h new file mode 100644 index 00000000..61572802 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_file.h @@ -0,0 +1,82 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_FILE_H__ +#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_FILE_H__ + +#include <string> +#include <set> +#include <vector> +#include <compiler/objectivec/objectivec_helpers.h> +#include <descriptor.h> +#include <io/printer.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace objectivec { + +class EnumGenerator; +class ExtensionGenerator; +class MessageGenerator; + +class FileGenerator { + public: + FileGenerator(const FileDescriptor* file, const Options& options); + ~FileGenerator(); + + FileGenerator(const FileGenerator&) = delete; + FileGenerator& operator=(const FileGenerator&) = delete; + + void GenerateSource(io::Printer* printer); + void GenerateHeader(io::Printer* printer); + + private: + const FileDescriptor* file_; + std::string root_class_name_; + bool is_bundled_proto_; + + std::vector<std::unique_ptr<EnumGenerator>> enum_generators_; + std::vector<std::unique_ptr<MessageGenerator>> message_generators_; + std::vector<std::unique_ptr<ExtensionGenerator>> extension_generators_; + + const Options options_; + + void PrintFileRuntimePreamble( + io::Printer* printer, + const std::vector<std::string>& headers_to_import) const; +}; + +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_FILE_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_generator.cc b/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_generator.cc new file mode 100644 index 00000000..3dbd1d43 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_generator.cc @@ -0,0 +1,276 @@ +// 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 <fstream> +#include <iostream> +#include <string> +#include <unordered_set> +#include <compiler/objectivec/objectivec_generator.h> +#include <compiler/objectivec/objectivec_file.h> +#include <compiler/objectivec/objectivec_helpers.h> +#include <io/printer.h> +#include <io/zero_copy_stream.h> +#include <stubs/strutil.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace objectivec { + +namespace { + +// Convert a string with "yes"/"no" (case insensitive) to a boolean, returning +// true/false for if the input string was a valid value. If the input string is +// invalid, `result` is unchanged. +bool StringToBool(const std::string& value, bool* result) { + std::string upper_value(value); + UpperString(&upper_value); + if (upper_value == "NO") { + *result = false; + return true; + } + if (upper_value == "YES") { + *result = true; + return true; + } + + return false; +} + +} // namespace + +ObjectiveCGenerator::ObjectiveCGenerator() {} + +ObjectiveCGenerator::~ObjectiveCGenerator() {} + +bool ObjectiveCGenerator::HasGenerateAll() const { + return true; +} + +bool ObjectiveCGenerator::Generate(const FileDescriptor* file, + const std::string& parameter, + GeneratorContext* context, + std::string* error) const { + *error = "Unimplemented Generate() method. Call GenerateAll() instead."; + return false; +} + +bool ObjectiveCGenerator::GenerateAll( + const std::vector<const FileDescriptor*>& files, + const std::string& parameter, GeneratorContext* context, + std::string* error) const { + // ----------------------------------------------------------------- + // Parse generator options. These options are passed to the compiler using the + // --objc_opt flag. The options are passed as a comma separated list of + // options along with their values. If the option appears multiple times, only + // the last value will be considered. + // + // e.g. protoc ... --objc_opt=expected_prefixes=file.txt,generate_for_named_framework=MyFramework + + Options generation_options; + + std::vector<std::pair<std::string, std::string> > options; + ParseGeneratorParameter(parameter, &options); + for (int i = 0; i < options.size(); i++) { + if (options[i].first == "expected_prefixes_path") { + // Path to find a file containing the expected prefixes + // (objc_class_prefix "PREFIX") for proto packages (package NAME). The + // generator will then issue warnings/errors if in the proto files being + // generated the option is not listed/wrong/etc in the file. + // + // The format of the file is: + // - An entry is a line of "package=prefix". + // - Comments start with "#". + // - A comment can go on a line after a expected package/prefix pair. + // (i.e. - "package=prefix # comment") + // + // There is no validation that the prefixes are good prefixes, it is + // assumed that they are when you create the file. + generation_options.expected_prefixes_path = options[i].second; + } else if (options[i].first == "expected_prefixes_suppressions") { + // A semicolon delimited string that lists the paths of .proto files to + // exclude from the package prefix validations (expected_prefixes_path). + // This is provided as an "out", to skip some files being checked. + for (StringPiece split_piece : Split( + options[i].second, ";", true)) { + generation_options.expected_prefixes_suppressions.push_back( + std::string(split_piece)); + } + } else if (options[i].first == "prefixes_must_be_registered") { + // If objc prefix file option value must be registered to be used. This + // option has no meaning if an "expected_prefixes_path" isn't set. The + // available options are: + // "no": They don't have to be registered. + // "yes": They must be registered and an error will be raised if a files + // tried to use a prefix that isn't registered. + // Default is "no". + if (!StringToBool(options[i].second, + &generation_options.prefixes_must_be_registered)) { + *error = "error: Unknown value for prefixes_must_be_registered: " + options[i].second; + return false; + } + } else if (options[i].first == "require_prefixes") { + // If every file must have an objc prefix file option to be used. The + // available options are: + // "no": Files can be generated without the prefix option. + // "yes": Files must have the objc prefix option, and an error will be + // raised if a files doesn't have one. + // Default is "no". + if (!StringToBool(options[i].second, + &generation_options.require_prefixes)) { + *error = "error: Unknown value for require_prefixes: " + options[i].second; + return false; + } + } else if (options[i].first == "generate_for_named_framework") { + // The name of the framework that protos are being generated for. This + // will cause the #import statements to be framework based using this + // name (i.e. - "#import <NAME/proto.pbobjc.h>). + // + // NOTE: If this option is used with + // named_framework_to_proto_path_mappings_path, then this is effectively + // the "default" framework name used for everything that wasn't mapped by + // the mapping file. + generation_options.generate_for_named_framework = options[i].second; + } else if (options[i].first == "named_framework_to_proto_path_mappings_path") { + // Path to find a file containing the list of framework names and proto + // files. The generator uses this to decide if a proto file + // referenced should use a framework style import vs. a user level import + // (#import <FRAMEWORK/file.pbobjc.h> vs #import "dir/file.pbobjc.h"). + // + // The format of the file is: + // - An entry is a line of "frameworkName: file.proto, dir/file2.proto". + // - Comments start with "#". + // - A comment can go on a line after a expected package/prefix pair. + // (i.e. - "frameworkName: file.proto # comment") + // + // Any number of files can be listed for a framework, just separate them + // with commas. + // + // There can be multiple lines listing the same frameworkName in case it + // has a lot of proto files included in it; having multiple lines makes + // things easier to read. If a proto file is not configured in the + // mappings file, it will use the default framework name if one was passed + // with generate_for_named_framework, or the relative path to it's include + // path otherwise. + generation_options.named_framework_to_proto_path_mappings_path = options[i].second; + } else if (options[i].first == "runtime_import_prefix") { + // Path to use as a prefix on #imports of runtime provided headers in the + // generated files. When integrating ObjC protos into a build system, + // this can be used to avoid having to add the runtime directory to the + // header search path since the generate #import will be more complete. + generation_options.runtime_import_prefix = + StripSuffixString(options[i].second, "/"); + } else if (options[i].first == "use_package_as_prefix") { + // Controls how the symbols should be prefixed to avoid symbols + // collisions. The objc_class_prefix file option is always honored, this + // is just what to do if that isn't set. The available options are: + // "no": Not prefixed (the existing mode). + // "yes": Make a prefix out of the proto package. + bool value = false; + if (StringToBool(options[i].second, &value)) { + SetUseProtoPackageAsDefaultPrefix(value); + } else { + *error = "error: Unknown use_package_as_prefix: " + options[i].second; + return false; + } + } else if (options[i].first == "proto_package_prefix_exceptions_path") { + // Path to find a file containing the list of proto package names that are + // exceptions when use_package_as_prefix is enabled. This can be used to + // migrate packages one at a time to use_package_as_prefix since there + // are likely code updates needed with each one. + // + // The format of the file is: + // - An entry is a line of "proto.package.name". + // - Comments start with "#". + // - A comment can go on a line after a expected package/prefix pair. + // (i.e. - "some.proto.package # comment") + SetProtoPackagePrefixExceptionList(options[i].second); + } else { + *error = "error: Unknown generator option: " + options[i].first; + return false; + } + } + + // ----------------------------------------------------------------- + + // These are not official generation options and could be removed/changed in + // the future and doing that won't count as a breaking change. + bool headers_only = getenv("GPB_OBJC_HEADERS_ONLY") != NULL; + std::unordered_set<std::string> skip_impls; + if (getenv("GPB_OBJC_SKIP_IMPLS_FILE") != NULL) { + std::ifstream skip_file(getenv("GPB_OBJC_SKIP_IMPLS_FILE")); + if (skip_file.is_open()) { + std::string line; + while (std::getline(skip_file, line)) { + skip_impls.insert(line); + } + } else { + *error = "error: Failed to open GPB_OBJC_SKIP_IMPLS_FILE file"; + return false; + } + } + + // ----------------------------------------------------------------- + + // Validate the objc prefix/package pairings. + if (!ValidateObjCClassPrefixes(files, generation_options, error)) { + // *error will have been filled in. + return false; + } + + for (int i = 0; i < files.size(); i++) { + const FileDescriptor* file = files[i]; + FileGenerator file_generator(file, generation_options); + std::string filepath = FilePath(file); + + // Generate header. + { + std::unique_ptr<io::ZeroCopyOutputStream> output( + context->Open(filepath + ".pbobjc.h")); + io::Printer printer(output.get(), '$'); + file_generator.GenerateHeader(&printer); + } + + // Generate m file. + if (!headers_only && skip_impls.count(file->name()) == 0) { + std::unique_ptr<io::ZeroCopyOutputStream> output( + context->Open(filepath + ".pbobjc.m")); + io::Printer printer(output.get(), '$'); + file_generator.GenerateSource(&printer); + } + } + + return true; +} + +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_generator.h b/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_generator.h new file mode 100644 index 00000000..c7cfe8d3 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_generator.h @@ -0,0 +1,79 @@ +// 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. + +// Generates ObjectiveC code for a given .proto file. + +#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_GENERATOR_H__ +#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_GENERATOR_H__ + +#include <string> +#include <compiler/code_generator.h> +#include <descriptor.h> + +#include <port_def.inc> + +namespace google { +namespace protobuf { +namespace compiler { +namespace objectivec { + +// CodeGenerator implementation which generates a ObjectiveC source file and +// header. If you create your own protocol compiler binary and you want it to +// support ObjectiveC output, you can do so by registering an instance of this +// CodeGenerator with the CommandLineInterface in your main() function. +class PROTOC_EXPORT ObjectiveCGenerator : public CodeGenerator { + public: + ObjectiveCGenerator(); + ~ObjectiveCGenerator(); + + ObjectiveCGenerator(const ObjectiveCGenerator&) = delete; + ObjectiveCGenerator& operator=(const ObjectiveCGenerator&) = delete; + + // implements CodeGenerator ---------------------------------------- + bool HasGenerateAll() const override; + bool Generate(const FileDescriptor* file, const std::string& parameter, + GeneratorContext* context, std::string* error) const override; + bool GenerateAll(const std::vector<const FileDescriptor*>& files, + const std::string& parameter, GeneratorContext* context, + std::string* error) const override; + + uint64_t GetSupportedFeatures() const override { + return FEATURE_PROTO3_OPTIONAL; + } +}; + +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google + +#include <port_undef.inc> + +#endif // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_GENERATOR_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_helpers.cc b/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_helpers.cc new file mode 100644 index 00000000..014edb9e --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_helpers.cc @@ -0,0 +1,1960 @@ +// 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. + +#ifndef _MSC_VER +#include <unistd.h> +#endif +#include <climits> +#include <errno.h> +#include <fcntl.h> +#include <fstream> +#include <iostream> +#include <sstream> +#include <stdlib.h> +#include <unordered_set> +#include <vector> + +#include <compiler/code_generator.h> +#include <compiler/objectivec/objectivec_helpers.h> +#include <compiler/objectivec/objectivec_nsobject_methods.h> +#include <descriptor.pb.h> +#include <io/coded_stream.h> +#include <io/printer.h> +#include <io/zero_copy_stream_impl.h> +#include <io/io_win32.h> +#include <port.h> +#include <stubs/common.h> +#include <stubs/strutil.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 { + +// <io.h> is transitively included in this file. Import the functions explicitly +// in this port namespace to avoid ambiguous definition. +namespace posix { +#ifdef _WIN32 +using ::google::protobuf::io::win32::open; +#else +using ::open; +#endif +} // namespace port + +namespace { + +class SimpleLineCollector : public LineConsumer { + public: + SimpleLineCollector(std::unordered_set<std::string>* inout_set) + : set_(inout_set) {} + + virtual bool ConsumeLine(const StringPiece& line, std::string* out_error) override { + set_->insert(std::string(line)); + return true; + } + + private: + std::unordered_set<std::string>* set_; +}; + +class PrefixModeStorage { + public: + PrefixModeStorage(); + + bool use_package_name() const { return use_package_name_; } + void set_use_package_name(bool on_or_off) { use_package_name_ = on_or_off; } + + const std::string exception_path() const { return exception_path_; } + void set_exception_path(const std::string& path) { + exception_path_ = path; + exceptions_.clear(); + } + + bool is_package_exempted(const std::string& package); + + private: + bool use_package_name_; + std::string exception_path_; + std::unordered_set<std::string> exceptions_; +}; + +PrefixModeStorage::PrefixModeStorage() { + // Even thought there are generation options, have an env back door since some + // of these helpers could be used in other plugins. + + const char* use_package_cstr = getenv("GPB_OBJC_USE_PACKAGE_AS_PREFIX"); + use_package_name_ = + (use_package_cstr && (std::string("YES") == ToUpper(use_package_cstr))); + + const char* exception_path = getenv("GPB_OBJC_PACKAGE_PREFIX_EXCEPTIONS_PATH"); + if (exception_path) { + exception_path_ = exception_path; + } +} + +bool PrefixModeStorage::is_package_exempted(const std::string& package) { + if (exceptions_.empty() && !exception_path_.empty()) { + std::string error_str; + SimpleLineCollector collector(&exceptions_); + if (!ParseSimpleFile(exception_path_, &collector, &error_str)) { + if (error_str.empty()) { + error_str = std::string("protoc:0: warning: Failed to parse") + + std::string(" package prefix exceptions file: ") + + exception_path_; + } + std::cerr << error_str << std::endl; + std::cerr.flush(); + exceptions_.clear(); + } + + // If the file was empty put something in it so it doesn't get reloaded over + // and over. + if (exceptions_.empty()) { + exceptions_.insert("<not a real package>"); + } + } + + return exceptions_.count(package) != 0; +} + +PrefixModeStorage g_prefix_mode; + +} // namespace + +bool UseProtoPackageAsDefaultPrefix() { + return g_prefix_mode.use_package_name(); +} + +void SetUseProtoPackageAsDefaultPrefix(bool on_or_off) { + g_prefix_mode.set_use_package_name(on_or_off); +} + +std::string GetProtoPackagePrefixExceptionList() { + return g_prefix_mode.exception_path(); +} + +void SetProtoPackagePrefixExceptionList(const std::string& file_path) { + g_prefix_mode.set_exception_path(file_path); +} + +Options::Options() { + // Default is the value of the env for the package prefixes. + 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 = + Split(suppressions, ";", true); + } + prefixes_must_be_registered = false; + require_prefixes = false; +} + +namespace { + +std::unordered_set<std::string> MakeWordsMap(const char* const words[], + size_t num_words) { + std::unordered_set<std::string> result; + for (int i = 0; i < num_words; i++) { + result.insert(words[i]); + } + return result; +} + +const char* const kUpperSegmentsList[] = {"url", "http", "https"}; + +std::unordered_set<std::string> kUpperSegments = + MakeWordsMap(kUpperSegmentsList, GOOGLE_ARRAYSIZE(kUpperSegmentsList)); + +bool ascii_isnewline(char c) { + return c == '\n' || c == '\r'; +} + +// Internal helper for name handing. +// Do not expose this outside of helpers, stick to having functions for specific +// cases (ClassName(), FieldName()), so there is always consistent suffix rules. +std::string UnderscoresToCamelCase(const std::string& input, + bool first_capitalized) { + std::vector<std::string> values; + std::string current; + + bool last_char_was_number = false; + bool last_char_was_lower = false; + bool last_char_was_upper = false; + for (int i = 0; i < input.size(); i++) { + char c = input[i]; + if (ascii_isdigit(c)) { + if (!last_char_was_number) { + values.push_back(current); + current = ""; + } + current += c; + last_char_was_number = last_char_was_lower = last_char_was_upper = false; + last_char_was_number = true; + } else if (ascii_islower(c)) { + // lowercase letter can follow a lowercase or uppercase letter + if (!last_char_was_lower && !last_char_was_upper) { + values.push_back(current); + current = ""; + } + current += c; // already lower + last_char_was_number = last_char_was_lower = last_char_was_upper = false; + last_char_was_lower = true; + } else if (ascii_isupper(c)) { + if (!last_char_was_upper) { + values.push_back(current); + current = ""; + } + current += ascii_tolower(c); + last_char_was_number = last_char_was_lower = last_char_was_upper = false; + last_char_was_upper = true; + } else { + last_char_was_number = last_char_was_lower = last_char_was_upper = false; + } + } + values.push_back(current); + + std::string result; + bool first_segment_forces_upper = false; + for (std::vector<std::string>::iterator i = values.begin(); i != values.end(); + ++i) { + std::string value = *i; + bool all_upper = (kUpperSegments.count(value) > 0); + if (all_upper && (result.length() == 0)) { + first_segment_forces_upper = true; + } + for (int j = 0; j < value.length(); j++) { + if (j == 0 || all_upper) { + value[j] = ascii_toupper(value[j]); + } else { + // Nothing, already in lower. + } + } + result += value; + } + if ((result.length() != 0) && + !first_capitalized && + !first_segment_forces_upper) { + result[0] = ascii_tolower(result[0]); + } + return result; +} + +const char* const kReservedWordList[] = { + // Note NSObject Methods: + // These are brought in from objectivec_nsobject_methods.h that is generated + // using method_dump.sh. See kNSObjectMethods below. + + // Objective C "keywords" that aren't in C + // From + // http://stackoverflow.com/questions/1873630/reserved-keywords-in-objective-c + // with some others added on. + "id", "_cmd", "super", "in", "out", "inout", "bycopy", "byref", "oneway", + "self", "instancetype", "nullable", "nonnull", "nil", "Nil", + "YES", "NO", "weak", + + // C/C++ keywords (Incl C++ 0x11) + // From http://en.cppreference.com/w/cpp/keywords + "and", "and_eq", "alignas", "alignof", "asm", "auto", "bitand", "bitor", + "bool", "break", "case", "catch", "char", "char16_t", "char32_t", "class", + "compl", "const", "constexpr", "const_cast", "continue", "decltype", + "default", "delete", "double", "dynamic_cast", "else", "enum", "explicit", + "export", "extern ", "false", "float", "for", "friend", "goto", "if", + "inline", "int", "long", "mutable", "namespace", "new", "noexcept", "not", + "not_eq", "nullptr", "operator", "or", "or_eq", "private", "protected", + "public", "register", "reinterpret_cast", "return", "short", "signed", + "sizeof", "static", "static_assert", "static_cast", "struct", "switch", + "template", "this", "thread_local", "throw", "true", "try", "typedef", + "typeid", "typename", "union", "unsigned", "using", "virtual", "void", + "volatile", "wchar_t", "while", "xor", "xor_eq", + + // C99 keywords + // From + // http://publib.boulder.ibm.com/infocenter/lnxpcomp/v8v101/index.jsp?topic=%2Fcom.ibm.xlcpp8l.doc%2Flanguage%2Fref%2Fkeyw.htm + "restrict", + + // GCC/Clang extension + "typeof", + + // Not a keyword, but will break you + "NULL", + + // C88+ specs call for these to be macros, so depending on what they are + // defined to be it can lead to odd errors for some Xcode/SDK versions. + "stdin", "stdout", "stderr", + + // Objective-C Runtime typedefs + // From <obc/runtime.h> + "Category", "Ivar", "Method", "Protocol", + + // GPBMessage Methods + // Only need to add instance methods that may conflict with + // method declared in protos. The main cases are methods + // that take no arguments, or setFoo:/hasFoo: type methods. + "clear", "data", "delimitedData", "descriptor", "extensionRegistry", + "extensionsCurrentlySet", "initialized", "isInitialized", "serializedSize", + "sortedExtensionsInUse", "unknownFields", + + // MacTypes.h names + "Fixed", "Fract", "Size", "LogicalAddress", "PhysicalAddress", "ByteCount", + "ByteOffset", "Duration", "AbsoluteTime", "OptionBits", "ItemCount", + "PBVersion", "ScriptCode", "LangCode", "RegionCode", "OSType", + "ProcessSerialNumber", "Point", "Rect", "FixedPoint", "FixedRect", "Style", + "StyleParameter", "StyleField", "TimeScale", "TimeBase", "TimeRecord", +}; + +// returns true is input starts with __ or _[A-Z] which are reserved identifiers +// in C/ C++. All calls should go through UnderscoresToCamelCase before getting here +// but this verifies and allows for future expansion if we decide to redefine what a +// reserved C identifier is (for example the GNU list +// https://www.gnu.org/software/libc/manual/html_node/Reserved-Names.html ) +bool IsReservedCIdentifier(const std::string& input) { + if (input.length() > 2) { + if (input.at(0) == '_') { + if (isupper(input.at(1)) || input.at(1) == '_') { + return true; + } + } + } + return false; +} + +std::string SanitizeNameForObjC(const std::string& prefix, + const std::string& input, + const std::string& extension, + std::string* out_suffix_added) { + static const std::unordered_set<std::string> kReservedWords = + MakeWordsMap(kReservedWordList, GOOGLE_ARRAYSIZE(kReservedWordList)); + static const std::unordered_set<std::string> kNSObjectMethods = + MakeWordsMap(kNSObjectMethodsList, GOOGLE_ARRAYSIZE(kNSObjectMethodsList)); + std::string sanitized; + // We add the prefix in the cases where the string is missing a prefix. + // We define "missing a prefix" as where 'input': + // a) Doesn't start with the prefix or + // b) Isn't equivalent to the prefix or + // c) Has the prefix, but the letter after the prefix is lowercase + if (HasPrefixString(input, prefix)) { + if (input.length() == prefix.length() || !ascii_isupper(input[prefix.length()])) { + sanitized = prefix + input; + } else { + sanitized = input; + } + } else { + sanitized = prefix + input; + } + if (IsReservedCIdentifier(sanitized) || + (kReservedWords.count(sanitized) > 0) || + (kNSObjectMethods.count(sanitized) > 0)) { + if (out_suffix_added) *out_suffix_added = extension; + return sanitized + extension; + } + if (out_suffix_added) out_suffix_added->clear(); + return sanitized; +} + +std::string NameFromFieldDescriptor(const FieldDescriptor* field) { + if (field->type() == FieldDescriptor::TYPE_GROUP) { + return field->message_type()->name(); + } else { + return field->name(); + } +} + +void PathSplit(const std::string& path, std::string* directory, + std::string* basename) { + std::string::size_type last_slash = path.rfind('/'); + if (last_slash == std::string::npos) { + if (directory) { + *directory = ""; + } + if (basename) { + *basename = path; + } + } else { + if (directory) { + *directory = path.substr(0, last_slash); + } + if (basename) { + *basename = path.substr(last_slash + 1); + } + } +} + +bool IsSpecialName(const std::string& name, const std::string* special_names, + size_t count) { + for (size_t i = 0; i < count; ++i) { + size_t length = special_names[i].length(); + if (name.compare(0, length, special_names[i]) == 0) { + if (name.length() > length) { + // If name is longer than the retained_name[i] that it matches + // the next character must be not lower case (newton vs newTon vs + // new_ton). + return !ascii_islower(name[length]); + } else { + return true; + } + } + } + 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(StringPiece* input) { + if ((input->length() >= 2) && + ((*input->data() == '\'' || *input->data() == '"')) && + ((*input)[input->length() - 1] == *input->data())) { + input->remove_prefix(1); + input->remove_suffix(1); + } +} + +} // namespace + +// Escape C++ trigraphs by escaping question marks to \? +std::string EscapeTrigraphs(const std::string& to_escape) { + return StringReplace(to_escape, "?", "\\?", true); +} + +void TrimWhitespace(StringPiece* input) { + while (!input->empty() && ascii_isspace(*input->data())) { + input->remove_prefix(1); + } + while (!input->empty() && ascii_isspace((*input)[input->length() - 1])) { + input->remove_suffix(1); + } +} + +bool IsRetainedName(const std::string& name) { + // List of prefixes from + // http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html + static const std::string retained_names[] = {"new", "alloc", "copy", + "mutableCopy"}; + return IsSpecialName(name, retained_names, + sizeof(retained_names) / sizeof(retained_names[0])); +} + +bool IsInitName(const std::string& name) { + static const std::string init_names[] = {"init"}; + return IsSpecialName(name, init_names, + sizeof(init_names) / sizeof(init_names[0])); +} + +std::string BaseFileName(const FileDescriptor* file) { + std::string basename; + PathSplit(file->name(), NULL, &basename); + return basename; +} + +std::string FileClassPrefix(const FileDescriptor* file) { + // Always honor the file option. + if (file->options().has_objc_class_prefix()) { + return file->options().objc_class_prefix(); + } + + // If package prefix isn't enabled or no package, done. + if (!g_prefix_mode.use_package_name() || file->package().empty()) { + return ""; + } + + // If the package is in the exceptions list, done. + if (g_prefix_mode.is_package_exempted(file->package())) { + return ""; + } + + // Transform the package into a prefix: use the dot segments as part, + // camelcase each one and then join them with underscores, and add an + // underscore at the end. + std::string result; + const std::vector<std::string> segments = Split(file->package(), ".", true); + for (const auto& segment : segments) { + const std::string part = UnderscoresToCamelCase(segment, true); + if (part.empty()) { + continue; + } + if (!result.empty()) { + result.append("_"); + } + result.append(part); + } + if (!result.empty()) { + result.append("_"); + } + return result; +} + +std::string FilePath(const FileDescriptor* file) { + std::string output; + std::string basename; + std::string directory; + PathSplit(file->name(), &directory, &basename); + if (directory.length() > 0) { + output = directory + "/"; + } + basename = StripProto(basename); + + // CamelCase to be more ObjC friendly. + basename = UnderscoresToCamelCase(basename, true); + + output += basename; + return output; +} + +std::string FilePathBasename(const FileDescriptor* file) { + std::string output; + std::string basename; + std::string directory; + PathSplit(file->name(), &directory, &basename); + basename = StripProto(basename); + + // CamelCase to be more ObjC friendly. + output = UnderscoresToCamelCase(basename, true); + + return output; +} + +std::string FileClassName(const FileDescriptor* file) { + const std::string prefix = FileClassPrefix(file); + const std::string name = + UnderscoresToCamelCase(StripProto(BaseFileName(file)), true) + "Root"; + // There aren't really any reserved words that end in "Root", but playing + // it safe and checking. + return SanitizeNameForObjC(prefix, name, "_RootClass", NULL); +} + +std::string ClassNameWorker(const Descriptor* descriptor) { + std::string name; + if (descriptor->containing_type() != NULL) { + name = ClassNameWorker(descriptor->containing_type()); + name += "_"; + } + return name + descriptor->name(); +} + +std::string ClassNameWorker(const EnumDescriptor* descriptor) { + std::string name; + if (descriptor->containing_type() != NULL) { + name = ClassNameWorker(descriptor->containing_type()); + name += "_"; + } + return name + descriptor->name(); +} + +std::string ClassName(const Descriptor* descriptor) { + return ClassName(descriptor, NULL); +} + +std::string ClassName(const Descriptor* descriptor, + std::string* out_suffix_added) { + // 1. Message names are used as is (style calls for CamelCase, trust it). + // 2. Check for reserved word at the very end and then suffix things. + const std::string prefix = FileClassPrefix(descriptor->file()); + const std::string name = ClassNameWorker(descriptor); + return SanitizeNameForObjC(prefix, name, "_Class", out_suffix_added); +} + +std::string EnumName(const EnumDescriptor* descriptor) { + // 1. Enum names are used as is (style calls for CamelCase, trust it). + // 2. Check for reserved word at the every end and then suffix things. + // message Fixed { + // message Size {...} + // enum Mumble {...} + // ... + // } + // yields Fixed_Class, Fixed_Size. + const std::string prefix = FileClassPrefix(descriptor->file()); + const std::string name = ClassNameWorker(descriptor); + return SanitizeNameForObjC(prefix, name, "_Enum", NULL); +} + +std::string EnumValueName(const EnumValueDescriptor* descriptor) { + // Because of the Switch enum compatibility, the name on the enum has to have + // the suffix handing, so it slightly diverges from how nested classes work. + // enum Fixed { + // FOO = 1 + // } + // yields Fixed_Enum and Fixed_Enum_Foo (not Fixed_Foo). + const std::string class_name = EnumName(descriptor->type()); + const std::string value_str = + UnderscoresToCamelCase(descriptor->name(), true); + const std::string name = class_name + "_" + value_str; + // There aren't really any reserved words with an underscore and a leading + // capital letter, but playing it safe and checking. + return SanitizeNameForObjC("", name, "_Value", NULL); +} + +std::string EnumValueShortName(const EnumValueDescriptor* descriptor) { + // Enum value names (EnumValueName above) are the enum name turned into + // a class name and then the value name is CamelCased and concatenated; the + // whole thing then gets sanitized for reserved words. + // The "short name" is intended to be the final leaf, the value name; but + // you can't simply send that off to sanitize as that could result in it + // getting modified when the full name didn't. For example enum + // "StorageModes" has a value "retain". So the full name is + // "StorageModes_Retain", but if we sanitize "retain" it would become + // "RetainValue". + // So the right way to get the short name is to take the full enum name + // and then strip off the enum name (leaving the value name and anything + // done by sanitize). + const std::string class_name = EnumName(descriptor->type()); + const std::string long_name_prefix = class_name + "_"; + const std::string long_name = EnumValueName(descriptor); + return StripPrefixString(long_name, long_name_prefix); +} + +std::string UnCamelCaseEnumShortName(const std::string& name) { + std::string result; + for (int i = 0; i < name.size(); i++) { + char c = name[i]; + if (i > 0 && ascii_isupper(c)) { + result += '_'; + } + result += ascii_toupper(c); + } + return result; +} + +std::string ExtensionMethodName(const FieldDescriptor* descriptor) { + const std::string name = NameFromFieldDescriptor(descriptor); + const std::string result = UnderscoresToCamelCase(name, false); + return SanitizeNameForObjC("", result, "_Extension", NULL); +} + +std::string FieldName(const FieldDescriptor* field) { + const std::string name = NameFromFieldDescriptor(field); + std::string result = UnderscoresToCamelCase(name, false); + if (field->is_repeated() && !field->is_map()) { + // Add "Array" before do check for reserved worlds. + result += "Array"; + } else { + // If it wasn't repeated, but ends in "Array", force on the _p suffix. + if (HasSuffixString(result, "Array")) { + result += "_p"; + } + } + return SanitizeNameForObjC("", result, "_p", NULL); +} + +std::string FieldNameCapitalized(const FieldDescriptor* field) { + // Want the same suffix handling, so upcase the first letter of the other + // name. + std::string result = FieldName(field); + if (result.length() > 0) { + result[0] = ascii_toupper(result[0]); + } + return result; +} + +std::string OneofEnumName(const OneofDescriptor* descriptor) { + const Descriptor* fieldDescriptor = descriptor->containing_type(); + std::string name = ClassName(fieldDescriptor); + name += "_" + UnderscoresToCamelCase(descriptor->name(), true) + "_OneOfCase"; + // No sanitize needed because the OS never has names that end in _OneOfCase. + return name; +} + +std::string OneofName(const OneofDescriptor* descriptor) { + std::string name = UnderscoresToCamelCase(descriptor->name(), false); + // No sanitize needed because it gets OneOfCase added and that shouldn't + // ever conflict. + return name; +} + +std::string OneofNameCapitalized(const OneofDescriptor* descriptor) { + // Use the common handling and then up-case the first letter. + std::string result = OneofName(descriptor); + if (result.length() > 0) { + result[0] = ascii_toupper(result[0]); + } + 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) { + std::string worker(name); + if (HasSuffixString(worker, "_p")) { + worker = StripSuffixString(worker, "_p"); + } + if (field->is_repeated() && HasSuffixString(worker, "Array")) { + worker = StripSuffixString(worker, "Array"); + } + if (field->type() == FieldDescriptor::TYPE_GROUP) { + if (worker.length() > 0) { + if (ascii_islower(worker[0])) { + worker[0] = ascii_toupper(worker[0]); + } + } + return worker; + } else { + std::string result; + for (int i = 0; i < worker.size(); i++) { + char c = worker[i]; + if (ascii_isupper(c)) { + if (i > 0) { + result += '_'; + } + result += ascii_tolower(c); + } else { + result += c; + } + } + return result; + } +} + +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 StrCat(field->default_value_int32()); + case FieldDescriptor::CPPTYPE_UINT32: + return 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 StrCat(field->default_value_int64()) + "LL"; + case FieldDescriptor::CPPTYPE_UINT64: + return 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(CEscape(bytes)) + "\""; + } else { + return "@\"" + EscapeTrigraphs(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 = Split(comments, "\n", false); + 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 (int i = 0; i < lines.size(); i++) { + std::string line = StripPrefixString(lines[i], " "); + // HeaderDoc and appledoc use '\' and '@' for markers; escape them. + line = StringReplace(line, "\\", "\\\\", true); + line = StringReplace(line, "@", "\\@", true); + // Decouple / from * to not have inline comments inside comments. + line = StringReplace(line, "/*", "/\\*", true); + line = StringReplace(line, "*/", "*\\/", true); + line = prefix + line; + StripWhitespace(&line); + // If not a one line, need to add the first space before *, as + // StripWhitespace 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 +// use a different value; so it isn't as simple as a option. +const char* const ProtobufLibraryFrameworkName = "Protobuf"; + +std::string ProtobufFrameworkImportSymbol(const std::string& framework_name) { + // GPB_USE_[framework_name]_FRAMEWORK_IMPORTS + std::string result = std::string("GPB_USE_"); + result += ToUpper(framework_name); + result += "_FRAMEWORK_IMPORTS"; + return result; +} + +bool IsProtobufLibraryBundledProtoFile(const FileDescriptor* file) { + // We don't check the name prefix or proto package because some files + // (descriptor.proto), aren't shipped generated by the library, so this + // seems to be the safest way to only catch the ones shipped. + const std::string name = file->name(); + if (name == "google/protobuf/any.proto" || + name == "google/protobuf/api.proto" || + name == "google/protobuf/duration.proto" || + name == "google/protobuf/empty.proto" || + name == "google/protobuf/field_mask.proto" || + name == "google/protobuf/source_context.proto" || + name == "google/protobuf/struct.proto" || + name == "google/protobuf/timestamp.proto" || + name == "google/protobuf/type.proto" || + name == "google/protobuf/wrappers.proto") { + return true; + } + return false; +} + +bool ReadLine(StringPiece* input, StringPiece* line) { + for (int len = 0; len < input->size(); ++len) { + if (ascii_isnewline((*input)[len])) { + *line = StringPiece(input->data(), len); + ++len; // advance over the newline + *input = StringPiece(input->data() + len, input->size() - len); + return true; + } + } + return false; // Ran out of input with no newline. +} + +void RemoveComment(StringPiece* input) { + int offset = input->find('#'); + if (offset != StringPiece::npos) { + input->remove_suffix(input->length() - offset); + } +} + +namespace { + +class ExpectedPrefixesCollector : public LineConsumer { + public: + ExpectedPrefixesCollector(std::map<std::string, std::string>* inout_package_to_prefix_map) + : prefix_map_(inout_package_to_prefix_map) {} + + virtual bool ConsumeLine(const StringPiece& line, std::string* out_error) override; + + private: + std::map<std::string, std::string>* prefix_map_; +}; + +bool ExpectedPrefixesCollector::ConsumeLine( + const StringPiece& line, std::string* out_error) { + int offset = line.find('='); + if (offset == StringPiece::npos) { + *out_error = std::string("Expected prefixes file line without equal sign: '") + + std::string(line) + "'."; + return false; + } + StringPiece package = line.substr(0, offset); + StringPiece prefix = line.substr(offset + 1); + TrimWhitespace(&package); + TrimWhitespace(&prefix); + MaybeUnQuote(&prefix); + // Don't really worry about error checking the package/prefix for + // being valid. Assume the file is validated when it is created/edited. + (*prefix_map_)[std::string(package)] = std::string(prefix); + return true; +} + +bool LoadExpectedPackagePrefixes(const Options& generation_options, + std::map<std::string, std::string>* prefix_map, + std::string* out_error) { + if (generation_options.expected_prefixes_path.empty()) { + return true; + } + + ExpectedPrefixesCollector collector(prefix_map); + return ParseSimpleFile( + generation_options.expected_prefixes_path, &collector, out_error); +} + +bool ValidateObjCClassPrefix( + const FileDescriptor* file, const std::string& expected_prefixes_path, + const std::map<std::string, std::string>& expected_package_prefixes, + bool prefixes_must_be_registered, bool require_prefixes, + std::string* out_error) { + // Reminder: An explicit prefix option of "" is valid in case the default + // prefixing is set to use the proto package and a file needs to be generated + // without any prefix at all (for legacy reasons). + + bool has_prefix = file->options().has_objc_class_prefix(); + bool have_expected_prefix_file = !expected_prefixes_path.empty(); + + const std::string prefix = file->options().objc_class_prefix(); + const std::string package = file->package(); + + // 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 warnings. + + // Check: Error - See if there was an expected prefix for the package and + // report if it doesn't match (wrong or missing). + std::map<std::string, std::string>::const_iterator package_match = + expected_package_prefixes.find(package); + if (package_match != expected_package_prefixes.end()) { + // There was an entry, and... + if (has_prefix && package_match->second == prefix) { + // ...it matches. All good, out of here! + return true; + } else { + // ...it didn't match! + *out_error = "error: Expected 'option objc_class_prefix = \"" + + package_match->second + "\";' for package '" + package + + "' in '" + file->name() + "'"; + if (has_prefix) { + *out_error += "; but found '" + prefix + "' instead"; + } + *out_error += "."; + return false; + } + } + + // If there was no prefix option, we're done at this point. + if (!has_prefix) { + if (require_prefixes) { + *out_error = + "error: '" + file->name() + "' does not have a required 'option" + + " objc_class_prefix'."; + return false; + } + return true; + } + + // When the prefix is non empty, check it against the expected entries. + if (!prefix.empty() && have_expected_prefix_file) { + // For a non empty prefix, look for any other package that uses the prefix. + std::string other_package_for_prefix; + for (std::map<std::string, std::string>::const_iterator i = + expected_package_prefixes.begin(); + i != expected_package_prefixes.end(); ++i) { + if (i->second == prefix) { + other_package_for_prefix = i->first; + break; + } + } + + // Check: Warning - If the file does not have a package, check whether the + // prefix was declared is being used by another package or not. This is + // a special case for empty packages. + if (package.empty()) { + // The file does not have a package and ... + if (other_package_for_prefix.empty()) { + // ... no other package has declared that prefix. + std::cerr + << "protoc:0: warning: File '" << file->name() << "' has no " + << "package. Consider adding a new package to the proto and adding '" + << "new.package = " << prefix << "' to the expected prefixes file (" + << expected_prefixes_path << ")." << std::endl; + std::cerr.flush(); + } else { + // ... another package has declared the same prefix. + std::cerr + << "protoc:0: warning: File '" << file->name() << "' has no package " + << "and package '" << other_package_for_prefix << "' already uses '" + << prefix << "' as its prefix. Consider either adding a new package " + << "to the proto, or reusing one of the packages already using this " + << "prefix in the expected prefixes file (" + << expected_prefixes_path << ")." << std::endl; + std::cerr.flush(); + } + return true; + } + + // Check: Error - Make sure the prefix wasn't expected for a different + // package (overlap is allowed, but it has to be listed as an expected + // overlap). + if (!other_package_for_prefix.empty()) { + *out_error = + "error: Found 'option objc_class_prefix = \"" + prefix + + "\";' in '" + file->name() + + "'; that prefix is already used for 'package " + + other_package_for_prefix + ";'. It can only be reused by listing " + + "it in the expected file (" + + expected_prefixes_path + ")."; + return false; // Only report first usage of the prefix. + } + } // !prefix.empty() + + // Check: Warning - Make sure the prefix is is a reasonable value according + // to Apple's rules (the checks above implicitly whitelist anything that + // doesn't meet these rules). + if (!prefix.empty() && !ascii_isupper(prefix[0])) { + std::cerr + << "protoc:0: warning: Invalid 'option objc_class_prefix = \"" + << prefix << "\";' in '" << file->name() << "';" + << " it should start with a capital letter." << std::endl; + std::cerr.flush(); + } + if (!prefix.empty() && prefix.length() < 3) { + // Apple reserves 2 character prefixes for themselves. They do use some + // 3 character prefixes, but they haven't updated the rules/docs. + std::cerr + << "protoc:0: warning: Invalid 'option objc_class_prefix = \"" + << prefix << "\";' in '" << file->name() << "';" + << " Apple recommends they should be at least 3 characters long." + << std::endl; + std::cerr.flush(); + } + + // Check: Error/Warning - If the given package/prefix pair wasn't expected, + // issue a error/warning to added to the file. + if (have_expected_prefix_file) { + if (prefixes_must_be_registered) { + *out_error = + "error: '" + file->name() + "' has 'option objc_class_prefix = \"" + + prefix + "\";', but it is not registered; add it to the expected " + + "prefixes file (" + expected_prefixes_path + ") for the package '" + + package + "'."; + return false; + } + + std::cerr + << "protoc:0: warning: Found unexpected 'option objc_class_prefix = \"" + << prefix << "\";' in '" << file->name() << "';" + << " consider adding it to the expected prefixes file (" + << expected_prefixes_path << ")." << std::endl; + std::cerr.flush(); + } + + return true; +} + +} // namespace + +bool ValidateObjCClassPrefixes(const std::vector<const FileDescriptor*>& files, + const Options& generation_options, + std::string* out_error) { + // Allow a '-' as the path for the expected prefixes to completely disable + // even the most basic of checks. + if (generation_options.expected_prefixes_path == "-") { + return true; + } + + // Load the expected package prefixes, if available, to validate against. + std::map<std::string, std::string> expected_package_prefixes; + if (!LoadExpectedPackagePrefixes(generation_options, + &expected_package_prefixes, + out_error)) { + return false; + } + + for (int i = 0; i < files.size(); i++) { + bool should_skip = + (std::find(generation_options.expected_prefixes_suppressions.begin(), + generation_options.expected_prefixes_suppressions.end(), + files[i]->name()) + != generation_options.expected_prefixes_suppressions.end()); + if (should_skip) { + continue; + } + + bool is_valid = + ValidateObjCClassPrefix(files[i], + generation_options.expected_prefixes_path, + expected_package_prefixes, + generation_options.prefixes_must_be_registered, + generation_options.require_prefixes, + out_error); + if (!is_valid) { + return false; + } + } + 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 { + +// 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_ &= 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 == ascii_toupper(input)) { + op_ = kOpFirstUpper; + } else if (desired == 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) || 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 == 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: \"" << CEscape(input_for_decode) << "\", desired: \"" + << 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 { + public: + Parser(LineConsumer* line_consumer) + : line_consumer_(line_consumer), line_(0) {} + + // Feeds in some input, parse what it can, returning success/failure. Calling + // again after an error is undefined. + bool ParseChunk(StringPiece chunk, std::string* out_error); + + // Should be called to finish parsing (after all input has been provided via + // successful calls to ParseChunk(), calling after a ParseChunk() failure is + // undefined). Returns success/failure. + bool Finish(std::string* out_error); + + int last_line() const { return line_; } + + private: + LineConsumer* line_consumer_; + int line_; + std::string leftover_; +}; + +bool Parser::ParseChunk(StringPiece chunk, std::string* out_error) { + StringPiece full_chunk; + if (!leftover_.empty()) { + leftover_ += std::string(chunk); + full_chunk = StringPiece(leftover_); + } else { + full_chunk = chunk; + } + + StringPiece line; + while (ReadLine(&full_chunk, &line)) { + ++line_; + RemoveComment(&line); + TrimWhitespace(&line); + if (!line.empty() && !line_consumer_->ConsumeLine(line, out_error)) { + if (out_error->empty()) { + *out_error = "ConsumeLine failed without setting an error."; + } + leftover_.clear(); + return false; + } + } + + if (full_chunk.empty()) { + leftover_.clear(); + } else { + leftover_ = std::string(full_chunk); + } + return true; +} + +bool Parser::Finish(std::string* out_error) { + // If there is still something to go, flush it with a newline. + if (!leftover_.empty() && !ParseChunk("\n", out_error)) { + return false; + } + // This really should never fail if ParseChunk succeeded, but check to be sure. + if (!leftover_.empty()) { + *out_error = "ParseSimple Internal error: finished with pending data."; + return false; + } + return true; +} + +std::string FullErrorString(const std::string& name, int line_num, const std::string& msg) { + return std::string("error: ") + name + " Line " + StrCat(line_num) + ", " + msg; +} + +} // namespace + +LineConsumer::LineConsumer() {} + +LineConsumer::~LineConsumer() {} + +bool ParseSimpleFile(const std::string& path, LineConsumer* line_consumer, + std::string* out_error) { + int fd; + do { + fd = posix::open(path.c_str(), O_RDONLY); + } while (fd < 0 && errno == EINTR); + if (fd < 0) { + *out_error = std::string("error: Unable to open \"") + path + "\", " + + strerror(errno); + return false; + } + io::FileInputStream file_stream(fd); + file_stream.SetCloseOnDelete(true); + + return ParseSimpleStream(file_stream, path, line_consumer, out_error); +} + +bool ParseSimpleStream(io::ZeroCopyInputStream& input_stream, + const std::string& stream_name, + LineConsumer* line_consumer, + std::string* out_error) { + std::string local_error; + Parser parser(line_consumer); + const void* buf; + int buf_len; + while (input_stream.Next(&buf, &buf_len)) { + if (buf_len == 0) { + continue; + } + + if (!parser.ParseChunk(StringPiece(static_cast<const char*>(buf), buf_len), + &local_error)) { + *out_error = FullErrorString(stream_name, parser.last_line(), local_error); + return false; + } + } + if (!parser.Finish(&local_error)) { + *out_error = FullErrorString(stream_name, parser.last_line(), local_error); + return false; + } + 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 StringPiece& line, std::string* out_error) { + int offset = line.find(':'); + if (offset == StringPiece::npos) { + *out_error = + std::string("Framework/proto file mapping line without colon sign: '") + + std::string(line) + "'."; + return false; + } + StringPiece framework_name = line.substr(0, offset); + StringPiece 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 == StringPiece::npos) { + offset = proto_file_list.length(); + } + + StringPiece 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(' ') != StringPiece::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 +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_helpers.h b/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_helpers.h new file mode 100644 index 00000000..e6a3e436 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_helpers.h @@ -0,0 +1,347 @@ +// 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. + +// Helper functions for generating ObjectiveC code. + +#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_HELPERS_H__ +#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_HELPERS_H__ + +#include <string> +#include <vector> + +#include <descriptor.h> +#include <descriptor.pb.h> +#include <io/zero_copy_stream.h> + +#include <port_def.inc> + +namespace google { +namespace protobuf { +namespace compiler { +namespace objectivec { + +// Get/Set if the proto package should be used to make the default prefix for +// symbols. This will then impact most of the type naming apis below. It is done +// as a global to not break any other generator reusing the methods since they +// are exported. +bool PROTOC_EXPORT UseProtoPackageAsDefaultPrefix(); +void PROTOC_EXPORT SetUseProtoPackageAsDefaultPrefix(bool on_or_off); +// Get/Set the path to a file to load as exceptions when +// `UseProtoPackageAsDefaultPrefixUseProtoPackageAsDefaultPrefix()` is `true`. +// And empty string means there should be no exceptions loaded. +std::string PROTOC_EXPORT GetProtoPackagePrefixExceptionList(); +void PROTOC_EXPORT SetProtoPackagePrefixExceptionList( + const std::string& file_path); + +// Generator options (see objectivec_generator.cc for a description of each): +struct Options { + Options(); + std::string expected_prefixes_path; + std::vector<std::string> expected_prefixes_suppressions; + std::string generate_for_named_framework; + std::string named_framework_to_proto_path_mappings_path; + std::string runtime_import_prefix; + bool prefixes_must_be_registered; + bool require_prefixes; +}; + +// Escape C++ trigraphs by escaping question marks to "\?". +std::string PROTOC_EXPORT EscapeTrigraphs(const std::string& to_escape); + +// Remove white space from either end of a StringPiece. +void PROTOC_EXPORT TrimWhitespace(StringPiece* input); + +// Returns true if the name requires a ns_returns_not_retained attribute applied +// to it. +bool PROTOC_EXPORT IsRetainedName(const std::string& name); + +// Returns true if the name starts with "init" and will need to have special +// handling under ARC. +bool PROTOC_EXPORT IsInitName(const std::string& name); + +// Gets the objc_class_prefix or the prefix made from the proto package. +std::string PROTOC_EXPORT FileClassPrefix(const FileDescriptor* file); + +// Gets the path of the file we're going to generate (sans the .pb.h +// extension). The path will be dependent on the objectivec package +// declared in the proto package. +std::string PROTOC_EXPORT FilePath(const FileDescriptor* file); + +// Just like FilePath(), but without the directory part. +std::string PROTOC_EXPORT FilePathBasename(const FileDescriptor* file); + +// Gets the name of the root class we'll generate in the file. This class +// is not meant for external consumption, but instead contains helpers that +// the rest of the classes need +std::string PROTOC_EXPORT FileClassName(const FileDescriptor* file); + +// These return the fully-qualified class name corresponding to the given +// descriptor. +std::string PROTOC_EXPORT ClassName(const Descriptor* descriptor); +std::string PROTOC_EXPORT ClassName(const Descriptor* descriptor, + std::string* out_suffix_added); +std::string PROTOC_EXPORT EnumName(const EnumDescriptor* descriptor); + +// Returns the fully-qualified name of the enum value corresponding to the +// the descriptor. +std::string PROTOC_EXPORT EnumValueName(const EnumValueDescriptor* descriptor); + +// Returns the name of the enum value corresponding to the descriptor. +std::string PROTOC_EXPORT EnumValueShortName(const EnumValueDescriptor* descriptor); + +// Reverse what an enum does. +std::string PROTOC_EXPORT UnCamelCaseEnumShortName(const std::string& name); + +// Returns the name to use for the extension (used as the method off the file's +// Root class). +std::string PROTOC_EXPORT ExtensionMethodName(const FieldDescriptor* descriptor); + +// Returns the transformed field name. +std::string PROTOC_EXPORT FieldName(const FieldDescriptor* field); +std::string PROTOC_EXPORT FieldNameCapitalized(const FieldDescriptor* field); + +// Returns the transformed oneof name. +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; +// Returns the CPP symbol name to use as the gate for framework style imports +// for the given framework name to use. +std::string PROTOC_EXPORT +ProtobufFrameworkImportSymbol(const std::string& framework_name); + +// Checks if the file is one of the proto's bundled with the library. +bool PROTOC_EXPORT +IsProtobufLibraryBundledProtoFile(const FileDescriptor* file); + +// 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. +bool PROTOC_EXPORT ValidateObjCClassPrefixes( + const std::vector<const FileDescriptor*>& files, + const Options& generation_options, 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: + LineConsumer(); + virtual ~LineConsumer(); + virtual bool ConsumeLine(const StringPiece& line, std::string* out_error) = 0; +}; + +bool PROTOC_EXPORT ParseSimpleFile(const std::string& path, + LineConsumer* line_consumer, + std::string* out_error); + +bool PROTOC_EXPORT ParseSimpleStream(io::ZeroCopyInputStream& input_stream, + const std::string& stream_name, + 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 StringPiece& 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 +} // namespace google + +#include <port_undef.inc> + +#endif // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_HELPERS_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_helpers_unittest.cc b/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_helpers_unittest.cc new file mode 100644 index 00000000..85f150b9 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_helpers_unittest.cc @@ -0,0 +1,385 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2014 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 <compiler/objectivec/objectivec_helpers.h> +#include <io/zero_copy_stream_impl_lite.h> +#include <testing/googletest.h> +#include <gtest/gtest.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace objectivec { +namespace { + +TEST(ObjCHelper, TextFormatDecodeData_DecodeDataForString_RawStrings) { + std::string input_for_decode("abcdefghIJ"); + std::string desired_output_for_decode; + std::string expected; + std::string result; + + // Different data, can't transform. + + desired_output_for_decode = "zbcdefghIJ"; + expected = std::string("\0zbcdefghIJ\0", 12); + result = TextFormatDecodeData::DecodeDataForString(input_for_decode, + desired_output_for_decode); + EXPECT_EQ(expected, result); + + desired_output_for_decode = "abcdezghIJ"; + expected = std::string("\0abcdezghIJ\0", 12); + result = TextFormatDecodeData::DecodeDataForString(input_for_decode, + desired_output_for_decode); + EXPECT_EQ(expected, result); + + // Shortened data, can't transform. + + desired_output_for_decode = "abcdefghI"; + expected = std::string("\0abcdefghI\0", 11); + result = TextFormatDecodeData::DecodeDataForString(input_for_decode, + desired_output_for_decode); + EXPECT_EQ(expected, result); + + // Extra data, can't transform. + + desired_output_for_decode = "abcdefghIJz"; + expected = std::string("\0abcdefghIJz\0", 13); + result = TextFormatDecodeData::DecodeDataForString(input_for_decode, + desired_output_for_decode); + EXPECT_EQ(expected, result); +} + +TEST(ObjCHelper, TextFormatDecodeData_DecodeDataForString_ByteCodes) { + std::string input_for_decode("abcdefghIJ"); + std::string desired_output_for_decode; + std::string expected; + std::string result; + + desired_output_for_decode = "abcdefghIJ"; + expected = std::string("\x0A\x0", 2); + result = TextFormatDecodeData::DecodeDataForString(input_for_decode, + desired_output_for_decode); + EXPECT_EQ(expected, result); + + desired_output_for_decode = "_AbcdefghIJ"; + expected = std::string("\xCA\x0", 2); + result = TextFormatDecodeData::DecodeDataForString(input_for_decode, + desired_output_for_decode); + EXPECT_EQ(expected, result); + + desired_output_for_decode = "ABCD__EfghI_j"; + expected = std::string("\x64\x80\xC5\xA1\x0", 5); + result = TextFormatDecodeData::DecodeDataForString(input_for_decode, + desired_output_for_decode); + EXPECT_EQ(expected, result); + + // Long name so multiple decode ops are needed. + + input_for_decode = + "longFieldNameIsLooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong1000"; + desired_output_for_decode = + "long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_1000"; + expected = std::string("\x04\xA5\xA4\xA2\xBF\x1F\x0E\x84\x0", 9); + result = TextFormatDecodeData::DecodeDataForString(input_for_decode, + desired_output_for_decode); + EXPECT_EQ(expected, result); +} + +// Death tests do not work on Windows as of yet. +#ifdef PROTOBUF_HAS_DEATH_TEST +TEST(ObjCHelperDeathTest, TextFormatDecodeData_DecodeDataForString_Failures) { + // Empty inputs. + + EXPECT_EXIT(TextFormatDecodeData::DecodeDataForString("", ""), + ::testing::KilledBySignal(SIGABRT), + "error: got empty string for making TextFormat data, input:"); + EXPECT_EXIT(TextFormatDecodeData::DecodeDataForString("a", ""), + ::testing::KilledBySignal(SIGABRT), + "error: got empty string for making TextFormat data, input:"); + EXPECT_EXIT(TextFormatDecodeData::DecodeDataForString("", "a"), + ::testing::KilledBySignal(SIGABRT), + "error: got empty string for making TextFormat data, input:"); + + // Null char in the string. + + std::string str_with_null_char("ab\0c", 4); + EXPECT_EXIT( + TextFormatDecodeData::DecodeDataForString(str_with_null_char, "def"), + ::testing::KilledBySignal(SIGABRT), + "error: got a null char in a string for making TextFormat data, input:"); + EXPECT_EXIT( + TextFormatDecodeData::DecodeDataForString("def", str_with_null_char), + ::testing::KilledBySignal(SIGABRT), + "error: got a null char in a string for making TextFormat data, input:"); +} +#endif // PROTOBUF_HAS_DEATH_TEST + +TEST(ObjCHelper, TextFormatDecodeData_RawStrings) { + TextFormatDecodeData decode_data; + + // Different data, can't transform. + decode_data.AddString(1, "abcdefghIJ", "zbcdefghIJ"); + decode_data.AddString(3, "abcdefghIJ", "abcdezghIJ"); + // Shortened data, can't transform. + decode_data.AddString(2, "abcdefghIJ", "abcdefghI"); + // Extra data, can't transform. + decode_data.AddString(4, "abcdefghIJ", "abcdefghIJz"); + + EXPECT_EQ(4, decode_data.num_entries()); + + uint8 expected_data[] = { + 0x4, + 0x1, 0x0, 'z', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'I', 'J', 0x0, + 0x3, 0x0, 'a', 'b', 'c', 'd', 'e', 'z', 'g', 'h', 'I', 'J', 0x0, + 0x2, 0x0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'I', 0x0, + 0x4, 0x0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'I', 'J', 'z', 0x0, + }; + std::string expected((const char*)expected_data, sizeof(expected_data)); + + EXPECT_EQ(expected, decode_data.Data()); +} + +TEST(ObjCHelper, TextFormatDecodeData_ByteCodes) { + TextFormatDecodeData decode_data; + + decode_data.AddString(1, "abcdefghIJ", "abcdefghIJ"); + decode_data.AddString(3, "abcdefghIJ", "_AbcdefghIJ"); + decode_data.AddString(2, "abcdefghIJ", "Abcd_EfghIJ"); + decode_data.AddString(4, "abcdefghIJ", "ABCD__EfghI_j"); + decode_data.AddString(1000, + "longFieldNameIsLooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong1000", + "long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_1000"); + + EXPECT_EQ(5, decode_data.num_entries()); + + uint8 expected_data[] = { + 0x5, + // All as is (00 op) + 0x1, 0x0A, 0x0, + // Underscore, upper + 9 (10 op) + 0x3, 0xCA, 0x0, + // Upper + 3 (10 op), underscore, upper + 5 (10 op) + 0x2, 0x44, 0xC6, 0x0, + // All Upper for 4 (11 op), underscore, underscore, upper + 5 (10 op), + // underscore, lower + 0 (01 op) + 0x4, 0x64, 0x80, 0xC5, 0xA1, 0x0, + // 2 byte key: as is + 3 (00 op), underscore, lower + 4 (01 op), + // underscore, lower + 3 (01 op), underscore, lower + 1 (01 op), + // underscore, lower + 30 (01 op), as is + 30 (00 op), as is + 13 (00 + // op), + // underscore, as is + 3 (00 op) + 0xE8, 0x07, 0x04, 0xA5, 0xA4, 0xA2, 0xBF, 0x1F, 0x0E, 0x84, 0x0, + }; + std::string expected((const char*)expected_data, sizeof(expected_data)); + + EXPECT_EQ(expected, decode_data.Data()); +} + + +// Death tests do not work on Windows as of yet. +#ifdef PROTOBUF_HAS_DEATH_TEST +TEST(ObjCHelperDeathTest, TextFormatDecodeData_Failures) { + TextFormatDecodeData decode_data; + + // Empty inputs. + + EXPECT_EXIT(decode_data.AddString(1, "", ""), + ::testing::KilledBySignal(SIGABRT), + "error: got empty string for making TextFormat data, input:"); + EXPECT_EXIT(decode_data.AddString(1, "a", ""), + ::testing::KilledBySignal(SIGABRT), + "error: got empty string for making TextFormat data, input:"); + EXPECT_EXIT(decode_data.AddString(1, "", "a"), + ::testing::KilledBySignal(SIGABRT), + "error: got empty string for making TextFormat data, input:"); + + // Null char in the string. + + std::string str_with_null_char("ab\0c", 4); + EXPECT_EXIT( + decode_data.AddString(1, str_with_null_char, "def"), + ::testing::KilledBySignal(SIGABRT), + "error: got a null char in a string for making TextFormat data, input:"); + EXPECT_EXIT( + decode_data.AddString(1, "def", str_with_null_char), + ::testing::KilledBySignal(SIGABRT), + "error: got a null char in a string for making TextFormat data, input:"); + + // Duplicate keys + + decode_data.AddString(1, "abcdefghIJ", "abcdefghIJ"); + decode_data.AddString(3, "abcdefghIJ", "_AbcdefghIJ"); + decode_data.AddString(2, "abcdefghIJ", "Abcd_EfghIJ"); + EXPECT_EXIT(decode_data.AddString(2, "xyz", "x_yz"), + ::testing::KilledBySignal(SIGABRT), + "error: duplicate key \\(2\\) making TextFormat data, input:"); +} +#endif // PROTOBUF_HAS_DEATH_TEST + +class TestLineCollector : public LineConsumer { + public: + TestLineCollector(std::vector<std::string>* inout_lines, + const std::string* reject_line = nullptr, + bool skip_msg = false) + : lines_(inout_lines), reject_(reject_line), skip_msg_(skip_msg) {} + + bool ConsumeLine(const StringPiece& line, std::string* out_error) override { + if (reject_ && *reject_ == line) { + if (!skip_msg_) { + *out_error = std::string("Rejected '") + *reject_ + "'"; + } + return false; + } + if (lines_) { + lines_->emplace_back(line); + } + return true; + } + + private: + std::vector<std::string>* lines_; + const std::string* reject_; + bool skip_msg_; +}; + +const int kBlockSizes[] = {-1, 1, 2, 5, 64}; +const int kBlockSizeCount = GOOGLE_ARRAYSIZE(kBlockSizes); + +TEST(ObjCHelper, ParseSimple_BasicsSuccess) { + const std::vector<std::pair<std::string, std::vector<std::string>>> tests = { + {"", {}}, + {"a", {"a"}}, + {"a c", {"a c"}}, + {" a c ", {"a c"}}, + {"\ta c ", {"a c"}}, + {"abc\n", {"abc"}}, + {"abc\nd f", {"abc", "d f"}}, + {"\n abc \n def \n\n", {"abc", "def"}}, + }; + + for (const auto& test : tests) { + for (int i = 0; i < kBlockSizeCount; i++) { + io::ArrayInputStream input(test.first.data(), test.first.size(), kBlockSizes[i]); + std::string err_str; + std::vector<std::string> lines; + TestLineCollector collector(&lines); + EXPECT_TRUE(ParseSimpleStream(input, "dummy", &collector, &err_str)); + EXPECT_EQ(lines, test.second); + EXPECT_TRUE(err_str.empty()); + } + } +} + +TEST(ObjCHelper, ParseSimple_DropsComments) { + const std::vector<std::pair<std::string, std::vector<std::string>>> tests = { + {"# nothing", {}}, + {"#", {}}, + {"##", {}}, + {"\n# nothing\n", {}}, + {"a # same line", {"a"}}, + {"a # same line\n", {"a"}}, + {"a\n# line\nc", {"a", "c"}}, + {"# n o t # h i n g #", {}}, + {"## n o # t h i n g #", {}}, + {"a# n o t # h i n g #", {"a"}}, + {"a\n## n o # t h i n g #", {"a"}}, + }; + + for (const auto& test : tests) { + for (int i = 0; i < kBlockSizeCount; i++) { + io::ArrayInputStream input(test.first.data(), test.first.size(), kBlockSizes[i]); + std::string err_str; + std::vector<std::string> lines; + TestLineCollector collector(&lines); + EXPECT_TRUE(ParseSimpleStream(input, "dummy", &collector, &err_str)); + EXPECT_EQ(lines, test.second); + EXPECT_TRUE(err_str.empty()); + } + } +} + +TEST(ObjCHelper, ParseSimple_RejectLines) { + const std::vector<std::tuple<std::string, std::string, int>> tests = { + std::make_tuple("a\nb\nc", "a", 1), + std::make_tuple("a\nb\nc", "b", 2), + std::make_tuple("a\nb\nc", "c", 3), + std::make_tuple("a\nb\nc\n", "c", 3), + }; + + for (const auto& test : tests) { + for (int i = 0; i < kBlockSizeCount; i++) { + io::ArrayInputStream input(std::get<0>(test).data(), std::get<0>(test).size(), + kBlockSizes[i]); + std::string err_str; + TestLineCollector collector(nullptr, &std::get<1>(test)); + EXPECT_FALSE(ParseSimpleStream(input, "dummy", &collector, &err_str)); + std::string expected_err = + StrCat("error: dummy Line ", std::get<2>(test), ", Rejected '", std::get<1>(test), "'"); + EXPECT_EQ(err_str, expected_err); + } + } +} + +TEST(ObjCHelper, ParseSimple_RejectLinesNoMessage) { + const std::vector<std::tuple<std::string, std::string, int>> tests = { + std::make_tuple("a\nb\nc", "a", 1), + std::make_tuple("a\nb\nc", "b", 2), + std::make_tuple("a\nb\nc", "c", 3), + std::make_tuple("a\nb\nc\n", "c", 3), + }; + + for (const auto& test : tests) { + for (int i = 0; i < kBlockSizeCount; i++) { + io::ArrayInputStream input(std::get<0>(test).data(), std::get<0>(test).size(), + kBlockSizes[i]); + std::string err_str; + TestLineCollector collector(nullptr, &std::get<1>(test), true /* skip msg */); + EXPECT_FALSE(ParseSimpleStream(input, "dummy", &collector, &err_str)); + std::string expected_err = + StrCat("error: dummy Line ", std::get<2>(test), + ", ConsumeLine failed without setting an error."); + EXPECT_EQ(err_str, expected_err); + } + } +} + +// TODO(thomasvl): Should probably add some unittests for all the special cases +// of name mangling (class name, field name, enum names). Rather than doing +// this with an ObjC test in the objectivec directory, we should be able to +// use src/google/protobuf/compiler/importer* (like other tests) to support a +// virtual file system to feed in protos, once we have the Descriptor tree, the +// tests could use the helper methods for generating names and validate the +// right things are happening. + +} // namespace +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_map_field.cc b/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_map_field.cc new file mode 100644 index 00000000..58681ae4 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_map_field.cc @@ -0,0 +1,189 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2015 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 <map> +#include <string> + +#include <compiler/objectivec/objectivec_map_field.h> +#include <compiler/objectivec/objectivec_helpers.h> +#include <io/printer.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace objectivec { + +// MapFieldGenerator uses RepeatedFieldGenerator as the parent because it +// provides a bunch of things (no has* methods, comments for contained type, +// etc.). + +namespace { + +const char* MapEntryTypeName(const FieldDescriptor* descriptor, bool isKey) { + ObjectiveCType type = GetObjectiveCType(descriptor); + switch (type) { + case OBJECTIVECTYPE_INT32: + return "Int32"; + case OBJECTIVECTYPE_UINT32: + return "UInt32"; + case OBJECTIVECTYPE_INT64: + return "Int64"; + case OBJECTIVECTYPE_UINT64: + return "UInt64"; + case OBJECTIVECTYPE_FLOAT: + return "Float"; + case OBJECTIVECTYPE_DOUBLE: + return "Double"; + case OBJECTIVECTYPE_BOOLEAN: + return "Bool"; + case OBJECTIVECTYPE_STRING: + return (isKey ? "String" : "Object"); + case OBJECTIVECTYPE_DATA: + return "Object"; + case OBJECTIVECTYPE_ENUM: + return "Enum"; + case OBJECTIVECTYPE_MESSAGE: + return "Object"; + } + + // 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 NULL; +} + +} // namespace + +MapFieldGenerator::MapFieldGenerator(const FieldDescriptor* descriptor, + const Options& options) + : RepeatedFieldGenerator(descriptor, options) { + const FieldDescriptor* key_descriptor = + descriptor->message_type()->map_key(); + const FieldDescriptor* value_descriptor = + descriptor->message_type()->map_value(); + value_field_generator_.reset(FieldGenerator::Make(value_descriptor, options)); + + // Pull over some variables_ from the value. + variables_["field_type"] = value_field_generator_->variable("field_type"); + variables_["default"] = value_field_generator_->variable("default"); + variables_["default_name"] = value_field_generator_->variable("default_name"); + + // Build custom field flags. + std::vector<std::string> field_flags; + field_flags.push_back("GPBFieldMapKey" + GetCapitalizedType(key_descriptor)); + // Pull over the current text format custom name values that was calculated. + if (variables_["fieldflags"].find("GPBFieldTextFormatNameCustom") != + std::string::npos) { + field_flags.push_back("GPBFieldTextFormatNameCustom"); + } + // Pull over some info from the value's flags. + const std::string& value_field_flags = + value_field_generator_->variable("fieldflags"); + if (value_field_flags.find("GPBFieldHasDefaultValue") != std::string::npos) { + field_flags.push_back("GPBFieldHasDefaultValue"); + } + if (value_field_flags.find("GPBFieldHasEnumDescriptor") != + std::string::npos) { + field_flags.push_back("GPBFieldHasEnumDescriptor"); + } + + variables_["fieldflags"] = BuildFlagsString(FLAGTYPE_FIELD, field_flags); + + ObjectiveCType value_objc_type = GetObjectiveCType(value_descriptor); + const bool value_is_object_type = + ((value_objc_type == OBJECTIVECTYPE_STRING) || + (value_objc_type == OBJECTIVECTYPE_DATA) || + (value_objc_type == OBJECTIVECTYPE_MESSAGE)); + if ((GetObjectiveCType(key_descriptor) == OBJECTIVECTYPE_STRING) && + value_is_object_type) { + variables_["array_storage_type"] = "NSMutableDictionary"; + variables_["array_property_type"] = + "NSMutableDictionary<NSString*, " + + value_field_generator_->variable("storage_type") + "*>"; + } else { + std::string class_name("GPB"); + class_name += MapEntryTypeName(key_descriptor, true); + class_name += MapEntryTypeName(value_descriptor, false); + class_name += "Dictionary"; + variables_["array_storage_type"] = class_name; + if (value_is_object_type) { + variables_["array_property_type"] = + class_name + "<" + + value_field_generator_->variable("storage_type") + "*>"; + } + } + + variables_["dataTypeSpecific_name"] = + value_field_generator_->variable("dataTypeSpecific_name"); + variables_["dataTypeSpecific_value"] = + value_field_generator_->variable("dataTypeSpecific_value"); +} + +MapFieldGenerator::~MapFieldGenerator() {} + +void MapFieldGenerator::FinishInitialization(void) { + RepeatedFieldGenerator::FinishInitialization(); + // Use the array_comment support in RepeatedFieldGenerator to output what the + // values in the map are. + const FieldDescriptor* value_descriptor = + descriptor_->message_type()->FindFieldByName("value"); + if (GetObjectiveCType(value_descriptor) == OBJECTIVECTYPE_ENUM) { + variables_["array_comment"] = + "// |" + variables_["name"] + "| values are |" + value_field_generator_->variable("storage_type") + "|\n"; + } +} + +void MapFieldGenerator::DetermineForwardDeclarations( + std::set<std::string>* fwd_decls) const { + RepeatedFieldGenerator::DetermineForwardDeclarations(fwd_decls); + const FieldDescriptor* value_descriptor = + descriptor_->message_type()->FindFieldByName("value"); + if (GetObjectiveCType(value_descriptor) == OBJECTIVECTYPE_MESSAGE) { + const std::string& value_storage_type = + value_field_generator_->variable("storage_type"); + fwd_decls->insert("@class " + value_storage_type); + } +} + +void MapFieldGenerator::DetermineObjectiveCClassDefinitions( + std::set<std::string>* fwd_decls) const { + // Class name is already in "storage_type". + const FieldDescriptor* value_descriptor = + descriptor_->message_type()->FindFieldByName("value"); + if (GetObjectiveCType(value_descriptor) == OBJECTIVECTYPE_MESSAGE) { + fwd_decls->insert(ObjCClassDeclaration( + value_field_generator_->variable("storage_type"))); + } +} + +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_map_field.h b/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_map_field.h new file mode 100644 index 00000000..32371123 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_map_field.h @@ -0,0 +1,71 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2015 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_MAP_FIELD_H__ +#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_MAP_FIELD_H__ + +#include <map> +#include <string> +#include <compiler/objectivec/objectivec_field.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace objectivec { + +class MapFieldGenerator : public RepeatedFieldGenerator { + friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field, + const Options& options); + + public: + virtual void FinishInitialization(void) override; + + MapFieldGenerator(const MapFieldGenerator&) = delete; + MapFieldGenerator& operator=(const MapFieldGenerator&) = delete; + + protected: + MapFieldGenerator(const FieldDescriptor* descriptor, const Options& options); + virtual ~MapFieldGenerator(); + + virtual void DetermineObjectiveCClassDefinitions( + std::set<std::string>* fwd_decls) const override; + virtual void DetermineForwardDeclarations( + std::set<std::string>* fwd_decls) const override; + + private: + std::unique_ptr<FieldGenerator> value_field_generator_; +}; + +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_MAP_FIELD_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_message.cc b/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_message.cc new file mode 100644 index 00000000..0e8bfec9 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_message.cc @@ -0,0 +1,636 @@ +// 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 <algorithm> +#include <iostream> +#include <sstream> + +#include <compiler/objectivec/objectivec_message.h> +#include <compiler/objectivec/objectivec_enum.h> +#include <compiler/objectivec/objectivec_extension.h> +#include <compiler/objectivec/objectivec_helpers.h> +#include <stubs/stl_util.h> +#include <stubs/strutil.h> +#include <io/printer.h> +#include <io/coded_stream.h> +#include <io/zero_copy_stream_impl.h> +#include <wire_format.h> +#include <wire_format_lite.h> +#include <descriptor.pb.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace objectivec { + +namespace { +struct FieldOrderingByNumber { + inline bool operator()(const FieldDescriptor* a, + const FieldDescriptor* b) const { + return a->number() < b->number(); + } +}; + +int OrderGroupForFieldDescriptor(const FieldDescriptor* descriptor) { + // The first item in the object structure is our uint32[] for has bits. + // We then want to order things to make the instances as small as + // possible. So we follow the has bits with: + // 1. Anything always 4 bytes - float, *32, enums + // 2. Anything that is always a pointer (they will be 8 bytes on 64 bit + // builds and 4 bytes on 32bit builds. + // 3. Anything always 8 bytes - double, *64 + // + // NOTE: Bools aren't listed, they were stored in the has bits. + // + // Why? Using 64bit builds as an example, this means worse case, we have + // enough bools that we overflow 1 byte from 4 byte alignment, so 3 bytes + // are wasted before the 4 byte values. Then if we have an odd number of + // those 4 byte values, the 8 byte values will be pushed down by 32bits to + // keep them aligned. But the structure will end 8 byte aligned, so no + // waste on the end. If you did the reverse order, you could waste 4 bytes + // before the first 8 byte value (after the has array), then a single + // bool on the end would need 7 bytes of padding to make the overall + // structure 8 byte aligned; so 11 bytes, wasted total. + + // Anything repeated is a GPB*Array/NSArray, so pointer. + if (descriptor->is_repeated()) { + return 3; + } + + switch (descriptor->type()) { + // All always 8 bytes. + case FieldDescriptor::TYPE_DOUBLE: + case FieldDescriptor::TYPE_INT64: + case FieldDescriptor::TYPE_SINT64: + case FieldDescriptor::TYPE_UINT64: + case FieldDescriptor::TYPE_SFIXED64: + case FieldDescriptor::TYPE_FIXED64: + return 4; + + // Pointers (string and bytes are NSString and NSData); 8 or 4 bytes + // depending on the build architecture. + case FieldDescriptor::TYPE_GROUP: + case FieldDescriptor::TYPE_MESSAGE: + case FieldDescriptor::TYPE_STRING: + case FieldDescriptor::TYPE_BYTES: + return 3; + + // All always 4 bytes (enums are int32s). + case FieldDescriptor::TYPE_FLOAT: + case FieldDescriptor::TYPE_INT32: + case FieldDescriptor::TYPE_SINT32: + case FieldDescriptor::TYPE_UINT32: + case FieldDescriptor::TYPE_SFIXED32: + case FieldDescriptor::TYPE_FIXED32: + case FieldDescriptor::TYPE_ENUM: + return 2; + + // 0 bytes. Stored in the has bits. + case FieldDescriptor::TYPE_BOOL: + return 99; // End of the list (doesn't really matter). + } + + // 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 0; +} + +struct FieldOrderingByStorageSize { + inline bool operator()(const FieldDescriptor* a, + const FieldDescriptor* b) const { + // Order by grouping. + const int order_group_a = OrderGroupForFieldDescriptor(a); + const int order_group_b = OrderGroupForFieldDescriptor(b); + if (order_group_a != order_group_b) { + return order_group_a < order_group_b; + } + // Within the group, order by field number (provides stable ordering). + return a->number() < b->number(); + } +}; + +struct ExtensionRangeOrdering { + bool operator()(const Descriptor::ExtensionRange* a, + const Descriptor::ExtensionRange* b) const { + return a->start < b->start; + } +}; + +// Sort the fields of the given Descriptor by number into a new[]'d array +// and return it. +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; +} + +// Sort the fields of the given Descriptor by storage size into a new[]'d +// array and return it. +const FieldDescriptor** SortFieldsByStorageSize(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(), + FieldOrderingByStorageSize()); + return fields; +} +} // namespace + +MessageGenerator::MessageGenerator(const std::string& root_classname, + const Descriptor* descriptor, + const Options& options) + : root_classname_(root_classname), + descriptor_(descriptor), + field_generators_(descriptor, options), + class_name_(ClassName(descriptor_)), + deprecated_attribute_(GetOptionalDeprecatedAttribute( + descriptor, descriptor->file(), false, true)) { + for (int i = 0; i < descriptor_->extension_count(); i++) { + extension_generators_.emplace_back( + new ExtensionGenerator(class_name_, descriptor_->extension(i))); + } + + for (int i = 0; i < descriptor_->real_oneof_decl_count(); i++) { + OneofGenerator* generator = new OneofGenerator(descriptor_->oneof_decl(i)); + oneof_generators_.emplace_back(generator); + } + + for (int i = 0; i < descriptor_->enum_type_count(); i++) { + EnumGenerator* generator = new EnumGenerator(descriptor_->enum_type(i)); + enum_generators_.emplace_back(generator); + } + + for (int i = 0; i < descriptor_->nested_type_count(); i++) { + MessageGenerator* generator = + new MessageGenerator(root_classname_, + descriptor_->nested_type(i), + options); + nested_message_generators_.emplace_back(generator); + } +} + +MessageGenerator::~MessageGenerator() {} + +void MessageGenerator::GenerateStaticVariablesInitialization( + io::Printer* printer) { + for (const auto& generator : extension_generators_) { + generator->GenerateStaticVariablesInitialization(printer); + } + + for (const auto& generator : nested_message_generators_) { + generator->GenerateStaticVariablesInitialization(printer); + } +} + +void MessageGenerator::DetermineForwardDeclarations( + std::set<std::string>* fwd_decls) { + if (!IsMapEntryMessage(descriptor_)) { + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* fieldDescriptor = descriptor_->field(i); + field_generators_.get(fieldDescriptor) + .DetermineForwardDeclarations(fwd_decls); + } + } + + for (const auto& generator : nested_message_generators_) { + generator->DetermineForwardDeclarations(fwd_decls); + } +} + +void MessageGenerator::DetermineObjectiveCClassDefinitions( + std::set<std::string>* fwd_decls) { + if (!IsMapEntryMessage(descriptor_)) { + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* fieldDescriptor = descriptor_->field(i); + field_generators_.get(fieldDescriptor) + .DetermineObjectiveCClassDefinitions(fwd_decls); + } + } + + for (const auto& generator : extension_generators_) { + generator->DetermineObjectiveCClassDefinitions(fwd_decls); + } + + for (const auto& generator : nested_message_generators_) { + generator->DetermineObjectiveCClassDefinitions(fwd_decls); + } + + const Descriptor* containing_descriptor = descriptor_->containing_type(); + if (containing_descriptor != NULL) { + std::string containing_class = ClassName(containing_descriptor); + fwd_decls->insert(ObjCClassDeclaration(containing_class)); + } +} + +bool MessageGenerator::IncludesOneOfDefinition() const { + if (!oneof_generators_.empty()) { + return true; + } + + for (const auto& generator : nested_message_generators_) { + if (generator->IncludesOneOfDefinition()) { + return true; + } + } + + return false; +} + +void MessageGenerator::GenerateEnumHeader(io::Printer* printer) { + for (const auto& generator : enum_generators_) { + generator->GenerateHeader(printer); + } + + for (const auto& generator : nested_message_generators_) { + generator->GenerateEnumHeader(printer); + } +} + +void MessageGenerator::GenerateExtensionRegistrationSource( + io::Printer* printer) { + for (const auto& generator : extension_generators_) { + generator->GenerateRegistrationSource(printer); + } + + for (const auto& generator : nested_message_generators_) { + generator->GenerateExtensionRegistrationSource(printer); + } +} + +void MessageGenerator::GenerateMessageHeader(io::Printer* printer) { + // This a a map entry message, just recurse and do nothing directly. + if (IsMapEntryMessage(descriptor_)) { + for (const auto& generator : nested_message_generators_) { + generator->GenerateMessageHeader(printer); + } + return; + } + + printer->Print( + "#pragma mark - $classname$\n" + "\n", + "classname", class_name_); + + if (descriptor_->field_count()) { + std::unique_ptr<const FieldDescriptor*[]> sorted_fields( + SortFieldsByNumber(descriptor_)); + + printer->Print("typedef GPB_ENUM($classname$_FieldNumber) {\n", + "classname", class_name_); + printer->Indent(); + + for (int i = 0; i < descriptor_->field_count(); i++) { + field_generators_.get(sorted_fields[i]) + .GenerateFieldNumberConstant(printer); + } + + printer->Outdent(); + printer->Print("};\n\n"); + } + + for (const auto& generator : oneof_generators_) { + generator->GenerateCaseEnum(printer); + } + + std::string message_comments; + SourceLocation location; + if (descriptor_->GetSourceLocation(&location)) { + message_comments = BuildCommentsString(location, false); + } else { + message_comments = ""; + } + + printer->Print( + "$comments$$deprecated_attribute$GPB_FINAL @interface $classname$ : GPBMessage\n\n", + "classname", class_name_, + "deprecated_attribute", deprecated_attribute_, + "comments", message_comments); + + std::vector<char> seen_oneofs(oneof_generators_.size(), 0); + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = descriptor_->field(i); + const OneofDescriptor* oneof = field->real_containing_oneof(); + if (oneof) { + const int oneof_index = oneof->index(); + if (!seen_oneofs[oneof_index]) { + seen_oneofs[oneof_index] = 1; + oneof_generators_[oneof_index]->GeneratePublicCasePropertyDeclaration( + printer); + } + } + field_generators_.get(field).GeneratePropertyDeclaration(printer); + } + + printer->Print("@end\n\n"); + + for (int i = 0; i < descriptor_->field_count(); i++) { + field_generators_.get(descriptor_->field(i)) + .GenerateCFunctionDeclarations(printer); + } + + if (!oneof_generators_.empty()) { + for (const auto& generator : oneof_generators_) { + generator->GenerateClearFunctionDeclaration(printer); + } + printer->Print("\n"); + } + + if (descriptor_->extension_count() > 0) { + printer->Print("@interface $classname$ (DynamicMethods)\n\n", + "classname", class_name_); + for (const auto& generator : extension_generators_) { + generator->GenerateMembersHeader(printer); + } + printer->Print("@end\n\n"); + } + + for (const auto& generator : nested_message_generators_) { + generator->GenerateMessageHeader(printer); + } +} + +void MessageGenerator::GenerateSource(io::Printer* printer) { + if (!IsMapEntryMessage(descriptor_)) { + printer->Print( + "#pragma mark - $classname$\n" + "\n", + "classname", class_name_); + + if (!deprecated_attribute_.empty()) { + // No warnings when compiling the impl of this deprecated class. + printer->Print( + "#pragma clang diagnostic push\n" + "#pragma clang diagnostic ignored \"-Wdeprecated-implementations\"\n" + "\n"); + } + + printer->Print("@implementation $classname$\n\n", + "classname", class_name_); + + for (const auto& generator : oneof_generators_) { + generator->GeneratePropertyImplementation(printer); + } + + for (int i = 0; i < descriptor_->field_count(); i++) { + field_generators_.get(descriptor_->field(i)) + .GeneratePropertyImplementation(printer); + } + + std::unique_ptr<const FieldDescriptor*[]> sorted_fields( + SortFieldsByNumber(descriptor_)); + std::unique_ptr<const FieldDescriptor*[]> size_order_fields( + SortFieldsByStorageSize(descriptor_)); + + std::vector<const Descriptor::ExtensionRange*> sorted_extensions; + sorted_extensions.reserve(descriptor_->extension_range_count()); + for (int i = 0; i < descriptor_->extension_range_count(); ++i) { + sorted_extensions.push_back(descriptor_->extension_range(i)); + } + + std::sort(sorted_extensions.begin(), sorted_extensions.end(), + ExtensionRangeOrdering()); + + // Assign has bits: + // 1. FieldGeneratorMap::CalculateHasBits() loops through the fields seeing + // who needs has bits and assigning them. + // 2. FieldGenerator::SetOneofIndexBase() overrides has_bit with a negative + // index that groups all the elements in the oneof. + size_t num_has_bits = field_generators_.CalculateHasBits(); + size_t sizeof_has_storage = (num_has_bits + 31) / 32; + if (sizeof_has_storage == 0) { + // In the case where no field needs has bits, don't let the _has_storage_ + // end up as zero length (zero length arrays are sort of a grey area + // since it has to be at the start of the struct). This also ensures a + // field with only oneofs keeps the required negative indices they need. + sizeof_has_storage = 1; + } + // Tell all the fields the oneof base. + for (const auto& generator : oneof_generators_) { + generator->SetOneofIndexBase(sizeof_has_storage); + } + field_generators_.SetOneofIndexBase(sizeof_has_storage); + // sizeof_has_storage needs enough bits for the single fields that aren't in + // any oneof, and then one int32 for each oneof (to store the field number). + sizeof_has_storage += oneof_generators_.size(); + + printer->Print( + "\n" + "typedef struct $classname$__storage_ {\n" + " uint32_t _has_storage_[$sizeof_has_storage$];\n", + "classname", class_name_, + "sizeof_has_storage", StrCat(sizeof_has_storage)); + printer->Indent(); + + for (int i = 0; i < descriptor_->field_count(); i++) { + field_generators_.get(size_order_fields[i]) + .GenerateFieldStorageDeclaration(printer); + } + printer->Outdent(); + + printer->Print("} $classname$__storage_;\n\n", "classname", class_name_); + + + printer->Print( + "// This method is threadsafe because it is initially called\n" + "// in +initialize for each subclass.\n" + "+ (GPBDescriptor *)descriptor {\n" + " static GPBDescriptor *descriptor = nil;\n" + " if (!descriptor) {\n"); + + TextFormatDecodeData text_format_decode_data; + bool has_fields = descriptor_->field_count() > 0; + bool need_defaults = field_generators_.DoesAnyFieldHaveNonZeroDefault(); + std::string field_description_type; + if (need_defaults) { + field_description_type = "GPBMessageFieldDescriptionWithDefault"; + } else { + field_description_type = "GPBMessageFieldDescription"; + } + if (has_fields) { + printer->Indent(); + printer->Indent(); + printer->Print( + "static $field_description_type$ fields[] = {\n", + "field_description_type", field_description_type); + printer->Indent(); + for (int i = 0; i < descriptor_->field_count(); ++i) { + const FieldGenerator& field_generator = + field_generators_.get(sorted_fields[i]); + field_generator.GenerateFieldDescription(printer, need_defaults); + if (field_generator.needs_textformat_name_support()) { + text_format_decode_data.AddString(sorted_fields[i]->number(), + field_generator.generated_objc_name(), + field_generator.raw_field_name()); + } + } + printer->Outdent(); + printer->Print( + "};\n"); + printer->Outdent(); + printer->Outdent(); + } + + std::map<std::string, std::string> vars; + vars["classname"] = class_name_; + vars["rootclassname"] = root_classname_; + vars["fields"] = has_fields ? "fields" : "NULL"; + if (has_fields) { + vars["fields_count"] = + "(uint32_t)(sizeof(fields) / sizeof(" + field_description_type + "))"; + } else { + vars["fields_count"] = "0"; + } + + std::vector<std::string> init_flags; + init_flags.push_back("GPBDescriptorInitializationFlag_UsesClassRefs"); + init_flags.push_back("GPBDescriptorInitializationFlag_Proto3OptionalKnown"); + if (need_defaults) { + init_flags.push_back("GPBDescriptorInitializationFlag_FieldsWithDefault"); + } + if (descriptor_->options().message_set_wire_format()) { + init_flags.push_back("GPBDescriptorInitializationFlag_WireFormat"); + } + vars["init_flags"] = BuildFlagsString(FLAGTYPE_DESCRIPTOR_INITIALIZATION, + init_flags); + + printer->Print( + vars, + " GPBDescriptor *localDescriptor =\n" + " [GPBDescriptor allocDescriptorForClass:[$classname$ class]\n" + " rootClass:[$rootclassname$ class]\n" + " file:$rootclassname$_FileDescriptor()\n" + " fields:$fields$\n" + " fieldCount:$fields_count$\n" + " storageSize:sizeof($classname$__storage_)\n" + " flags:$init_flags$];\n"); + if (!oneof_generators_.empty()) { + printer->Print( + " static const char *oneofs[] = {\n"); + for (const auto& generator : oneof_generators_) { + printer->Print(" \"$name$\",\n", "name", + generator->DescriptorName()); + } + printer->Print( + " };\n" + " [localDescriptor setupOneofs:oneofs\n" + " count:(uint32_t)(sizeof(oneofs) / sizeof(char*))\n" + " firstHasIndex:$first_has_index$];\n", + "first_has_index", oneof_generators_[0]->HasIndexAsString()); + } + if (text_format_decode_data.num_entries() != 0) { + const std::string text_format_data_str(text_format_decode_data.Data()); + printer->Print( + "#if !GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS\n" + " static const char *extraTextFormatInfo ="); + static const int kBytesPerLine = 40; // allow for escaping + for (int i = 0; i < text_format_data_str.size(); i += kBytesPerLine) { + printer->Print( + "\n \"$data$\"", + "data", EscapeTrigraphs( + CEscape(text_format_data_str.substr(i, kBytesPerLine)))); + } + printer->Print( + ";\n" + " [localDescriptor setupExtraTextInfo:extraTextFormatInfo];\n" + "#endif // !GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS\n"); + } + if (!sorted_extensions.empty()) { + printer->Print( + " static const GPBExtensionRange ranges[] = {\n"); + for (int i = 0; i < sorted_extensions.size(); i++) { + printer->Print(" { .start = $start$, .end = $end$ },\n", + "start", StrCat(sorted_extensions[i]->start), + "end", StrCat(sorted_extensions[i]->end)); + } + printer->Print( + " };\n" + " [localDescriptor setupExtensionRanges:ranges\n" + " count:(uint32_t)(sizeof(ranges) / sizeof(GPBExtensionRange))];\n"); + } + if (descriptor_->containing_type() != NULL) { + std::string containing_class = ClassName(descriptor_->containing_type()); + std::string parent_class_ref = ObjCClass(containing_class); + printer->Print( + " [localDescriptor setupContainingMessageClass:$parent_class_ref$];\n", + "parent_class_ref", parent_class_ref); + } + std::string suffix_added; + ClassName(descriptor_, &suffix_added); + if (!suffix_added.empty()) { + printer->Print( + " [localDescriptor setupMessageClassNameSuffix:@\"$suffix$\"];\n", + "suffix", suffix_added); + } + printer->Print( + " #if defined(DEBUG) && DEBUG\n" + " NSAssert(descriptor == nil, @\"Startup recursed!\");\n" + " #endif // DEBUG\n" + " descriptor = localDescriptor;\n" + " }\n" + " return descriptor;\n" + "}\n\n" + "@end\n\n"); + + if (!deprecated_attribute_.empty()) { + printer->Print( + "#pragma clang diagnostic pop\n" + "\n"); + } + + for (int i = 0; i < descriptor_->field_count(); i++) { + field_generators_.get(descriptor_->field(i)) + .GenerateCFunctionImplementations(printer); + } + + for (const auto& generator : oneof_generators_) { + generator->GenerateClearFunctionImplementation(printer); + } + } + + for (const auto& generator : enum_generators_) { + generator->GenerateSource(printer); + } + + for (const auto& generator : nested_message_generators_) { + generator->GenerateSource(printer); + } +} + +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_message.h b/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_message.h new file mode 100644 index 00000000..64c7b49f --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_message.h @@ -0,0 +1,99 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_MESSAGE_H__ +#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_MESSAGE_H__ + +#include <string> +#include <set> +#include <vector> +#include <compiler/objectivec/objectivec_field.h> +#include <compiler/objectivec/objectivec_helpers.h> +#include <compiler/objectivec/objectivec_oneof.h> +#include <descriptor.h> +#include <io/printer.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace objectivec { + +class ExtensionGenerator; +class EnumGenerator; + +class MessageGenerator { + public: + MessageGenerator(const std::string& root_classname, + const Descriptor* descriptor, const Options& options); + ~MessageGenerator(); + + MessageGenerator(const MessageGenerator&) = delete; + MessageGenerator& operator=(const MessageGenerator&) = delete; + + void GenerateStaticVariablesInitialization(io::Printer* printer); + void GenerateEnumHeader(io::Printer* printer); + void GenerateMessageHeader(io::Printer* printer); + void GenerateSource(io::Printer* printer); + void GenerateExtensionRegistrationSource(io::Printer* printer); + void DetermineObjectiveCClassDefinitions(std::set<std::string>* fwd_decls); + void DetermineForwardDeclarations(std::set<std::string>* fwd_decls); + + // Checks if the message or a nested message includes a oneof definition. + bool IncludesOneOfDefinition() const; + + private: + void GenerateParseFromMethodsHeader(io::Printer* printer); + + void GenerateSerializeOneFieldSource(io::Printer* printer, + const FieldDescriptor* field); + void GenerateSerializeOneExtensionRangeSource( + io::Printer* printer, const Descriptor::ExtensionRange* range); + + void GenerateMessageDescriptionSource(io::Printer* printer); + void GenerateDescriptionOneFieldSource(io::Printer* printer, + const FieldDescriptor* field); + + const std::string root_classname_; + const Descriptor* descriptor_; + FieldGeneratorMap field_generators_; + const std::string class_name_; + const std::string deprecated_attribute_; + std::vector<std::unique_ptr<ExtensionGenerator>> extension_generators_; + std::vector<std::unique_ptr<EnumGenerator>> enum_generators_; + std::vector<std::unique_ptr<MessageGenerator>> nested_message_generators_; + std::vector<std::unique_ptr<OneofGenerator>> oneof_generators_; +}; + +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_MESSAGE_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_message_field.cc b/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_message_field.cc new file mode 100644 index 00000000..241ae0fa --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_message_field.cc @@ -0,0 +1,107 @@ +// 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 <map> +#include <string> + +#include <compiler/objectivec/objectivec_message_field.h> +#include <compiler/objectivec/objectivec_helpers.h> +#include <io/printer.h> +#include <wire_format.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace objectivec { + +namespace { + +void SetMessageVariables(const FieldDescriptor* descriptor, + std::map<std::string, std::string>* variables) { + const std::string& message_type = ClassName(descriptor->message_type()); + const std::string& containing_class = + ClassName(descriptor->containing_type()); + (*variables)["type"] = message_type; + (*variables)["containing_class"] = containing_class; + (*variables)["storage_type"] = message_type; + (*variables)["group_or_message"] = + (descriptor->type() == FieldDescriptor::TYPE_GROUP) ? "Group" : "Message"; + (*variables)["dataTypeSpecific_value"] = ObjCClass(message_type); +} + +} // namespace + +MessageFieldGenerator::MessageFieldGenerator(const FieldDescriptor* descriptor, + const Options& options) + : ObjCObjFieldGenerator(descriptor, options) { + SetMessageVariables(descriptor, &variables_); +} + +MessageFieldGenerator::~MessageFieldGenerator() {} + +void MessageFieldGenerator::DetermineForwardDeclarations( + std::set<std::string>* fwd_decls) const { + ObjCObjFieldGenerator::DetermineForwardDeclarations(fwd_decls); + // Class name is already in "storage_type". + fwd_decls->insert("@class " + variable("storage_type")); +} + +void MessageFieldGenerator::DetermineObjectiveCClassDefinitions( + std::set<std::string>* fwd_decls) const { + fwd_decls->insert(ObjCClassDeclaration(variable("storage_type"))); +} + +RepeatedMessageFieldGenerator::RepeatedMessageFieldGenerator( + const FieldDescriptor* descriptor, const Options& options) + : RepeatedFieldGenerator(descriptor, options) { + SetMessageVariables(descriptor, &variables_); + variables_["array_storage_type"] = "NSMutableArray"; + variables_["array_property_type"] = + "NSMutableArray<" + variables_["storage_type"] + "*>"; +} + +RepeatedMessageFieldGenerator::~RepeatedMessageFieldGenerator() {} + +void RepeatedMessageFieldGenerator::DetermineForwardDeclarations( + std::set<std::string>* fwd_decls) const { + RepeatedFieldGenerator::DetermineForwardDeclarations(fwd_decls); + // Class name is already in "storage_type". + fwd_decls->insert("@class " + variable("storage_type")); +} + +void RepeatedMessageFieldGenerator::DetermineObjectiveCClassDefinitions( + std::set<std::string>* fwd_decls) const { + fwd_decls->insert(ObjCClassDeclaration(variable("storage_type"))); +} + +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_message_field.h b/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_message_field.h new file mode 100644 index 00000000..7ea99c37 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_message_field.h @@ -0,0 +1,87 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_MESSAGE_FIELD_H__ +#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_MESSAGE_FIELD_H__ + +#include <map> +#include <string> +#include <compiler/objectivec/objectivec_field.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace objectivec { + +class MessageFieldGenerator : public ObjCObjFieldGenerator { + friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field, + const Options& options); + + protected: + MessageFieldGenerator(const FieldDescriptor* descriptor, + const Options& options); + + MessageFieldGenerator(const MessageFieldGenerator&) = delete; + MessageFieldGenerator& operator=(const MessageFieldGenerator&) = delete; + + virtual ~MessageFieldGenerator(); + + public: + virtual void DetermineForwardDeclarations( + std::set<std::string>* fwd_decls) const override; + virtual void DetermineObjectiveCClassDefinitions( + std::set<std::string>* fwd_decls) const override; +}; + +class RepeatedMessageFieldGenerator : public RepeatedFieldGenerator { + friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field, + const Options& options); + + protected: + RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor, + const Options& options); + virtual ~RepeatedMessageFieldGenerator(); + + RepeatedMessageFieldGenerator(const RepeatedMessageFieldGenerator&) = delete; + RepeatedMessageFieldGenerator operator=(const RepeatedMessageFieldGenerator&) = delete; + + public: + virtual void DetermineForwardDeclarations( + std::set<std::string>* fwd_decls) const override; + virtual void DetermineObjectiveCClassDefinitions( + std::set<std::string>* fwd_decls) const override; +}; + +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_MESSAGE_FIELD_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_nsobject_methods.h b/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_nsobject_methods.h new file mode 100644 index 00000000..16330466 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_nsobject_methods.h @@ -0,0 +1,197 @@ +// NSObject methods +// Autogenerated by method_dump.sh. Do not edit by hand. +// Date: Thu Nov 1 14:12:16 PDT 2018 +// macOS: MacOSX10.14.sdk +// iOS: iPhoneSimulator12.1.sdk + +const char* const kNSObjectMethodsList[] = { + "CAMLType", + "CA_copyRenderValue", + "CA_prepareRenderValue", + "NS_copyCGImage", + "NS_tiledLayerVisibleRect", + "___tryRetain_OA", + "__autorelease_OA", + "__dealloc_zombie", + "__release_OA", + "__retain_OA", + "_accessibilityFinalize", + "_accessibilityIsTableViewDescendant", + "_accessibilityUIElementSpecifier", + "_accessibilityUseConvenienceAPI", + "_allowsDirectEncoding", + "_asScriptTerminologyNameArray", + "_asScriptTerminologyNameString", + "_bindingAdaptor", + "_cfTypeID", + "_copyDescription", + "_destroyObserverList", + "_didEndKeyValueObserving", + "_implicitObservationInfo", + "_internalAccessibilityAttributedHint", + "_internalAccessibilityAttributedLabel", + "_internalAccessibilityAttributedValue", + "_isAXConnector", + "_isAccessibilityContainerSectionCandidate", + "_isAccessibilityContentNavigatorSectionCandidate", + "_isAccessibilityContentSectionCandidate", + "_isAccessibilityTopLevelNavigatorSectionCandidate", + "_isDeallocating", + "_isKVOA", + "_isToManyChangeInformation", + "_ivarDescription", + "_localClassNameForClass", + "_methodDescription", + "_observerStorage", + "_overrideUseFastBlockObservers", + "_propertyDescription", + "_releaseBindingAdaptor", + "_scriptingCount", + "_scriptingCountNonrecursively", + "_scriptingDebugDescription", + "_scriptingExists", + "_scriptingShouldCheckObjectIndexes", + "_shortMethodDescription", + "_shouldSearchChildrenForSection", + "_traitStorageList", + "_tryRetain", + "_ui_descriptionBuilder", + "_uikit_variesByTraitCollections", + "_web_description", + "_webkit_invokeOnMainThread", + "_willBeginKeyValueObserving", + "accessibilityActivate", + "accessibilityActivationPoint", + "accessibilityAllowsOverriddenAttributesWhenIgnored", + "accessibilityAssistiveTechnologyFocusedIdentifiers", + "accessibilityAttributedHint", + "accessibilityAttributedLabel", + "accessibilityAttributedValue", + "accessibilityContainer", + "accessibilityContainerType", + "accessibilityCustomActions", + "accessibilityCustomRotors", + "accessibilityDecrement", + "accessibilityDragSourceDescriptors", + "accessibilityDropPointDescriptors", + "accessibilityElementCount", + "accessibilityElementDidBecomeFocused", + "accessibilityElementDidLoseFocus", + "accessibilityElementIsFocused", + "accessibilityElements", + "accessibilityElementsHidden", + "accessibilityFrame", + "accessibilityHeaderElements", + "accessibilityHint", + "accessibilityIdentification", + "accessibilityIdentifier", + "accessibilityIncrement", + "accessibilityLabel", + "accessibilityLanguage", + "accessibilityLocalizedStringKey", + "accessibilityNavigationStyle", + "accessibilityOverriddenAttributes", + "accessibilityParameterizedAttributeNames", + "accessibilityPath", + "accessibilityPerformEscape", + "accessibilityPerformMagicTap", + "accessibilityPresenterProcessIdentifier", + "accessibilityShouldUseUniqueId", + "accessibilitySupportsNotifications", + "accessibilitySupportsOverriddenAttributes", + "accessibilityTemporaryChildren", + "accessibilityTraits", + "accessibilityValue", + "accessibilityViewIsModal", + "accessibilityVisibleArea", + "allPropertyKeys", + "allowsWeakReference", + "attributeKeys", + "autoContentAccessingProxy", + "autorelease", + "awakeFromNib", + "boolValueSafe", + "bs_encoded", + "bs_isPlistableType", + "bs_secureEncoded", + "cl_json_serializeKey", + "class", + "classCode", + "classDescription", + "classForArchiver", + "classForCoder", + "classForKeyedArchiver", + "classForPortCoder", + "className", + "clearProperties", + "copy", + "dealloc", + "debugDescription", + "defaultAccessibilityTraits", + "description", + "doubleValueSafe", + "entityName", + "exposedBindings", + "finalize", + "finishObserving", + "flushKeyBindings", + "hash", + "init", + "int64ValueSafe", + "isAccessibilityElement", + "isAccessibilityElementByDefault", + "isElementAccessibilityExposedToInterfaceBuilder", + "isFault", + "isNSArray__", + "isNSCFConstantString__", + "isNSData__", + "isNSDate__", + "isNSDictionary__", + "isNSNumber__", + "isNSObject__", + "isNSOrderedSet__", + "isNSSet__", + "isNSString__", + "isNSTimeZone__", + "isNSValue__", + "isProxy", + "mutableCopy", + "nilValueForKey", + "objectSpecifier", + "observationInfo", + "pep_onDetachedThread", + "pep_onMainThread", + "pep_onMainThreadIfNecessary", + "prepareForInterfaceBuilder", + "release", + "releaseOnMainThread", + "retain", + "retainCount", + "retainWeakReference", + "scriptingProperties", + "self", + "shouldGroupAccessibilityChildren", + "storedAccessibilityActivationPoint", + "storedAccessibilityContainerType", + "storedAccessibilityElementsHidden", + "storedAccessibilityFrame", + "storedAccessibilityNavigationStyle", + "storedAccessibilityTraits", + "storedAccessibilityViewIsModal", + "storedIsAccessibilityElement", + "storedShouldGroupAccessibilityChildren", + "stringValueSafe", + "superclass", + "toManyRelationshipKeys", + "toOneRelationshipKeys", + "traitStorageList", + "un_safeBoolValue", + "userInterfaceItemIdentifier", + "utf8ValueSafe", + "valuesForKeysWithDictionary", + "zone", +// Protocol: CAAnimatableValue +// Protocol: CARenderValue +// Protocol: NSObject +// Protocol: ROCKRemoteInvocationInterface +}; diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_oneof.cc b/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_oneof.cc new file mode 100644 index 00000000..de00a1f4 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_oneof.cc @@ -0,0 +1,140 @@ +// 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 <map> +#include <string> + +#include <compiler/objectivec/objectivec_oneof.h> +#include <compiler/objectivec/objectivec_helpers.h> +#include <io/printer.h> +#include <stubs/strutil.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace objectivec { + +OneofGenerator::OneofGenerator(const OneofDescriptor* descriptor) + : descriptor_(descriptor) { + variables_["enum_name"] = OneofEnumName(descriptor_); + variables_["name"] = OneofName(descriptor_); + variables_["capitalized_name"] = OneofNameCapitalized(descriptor_); + variables_["raw_index"] = StrCat(descriptor_->index()); + const Descriptor* msg_descriptor = descriptor_->containing_type(); + variables_["owning_message_class"] = ClassName(msg_descriptor); + + std::string comments; + SourceLocation location; + if (descriptor_->GetSourceLocation(&location)) { + comments = BuildCommentsString(location, true); + } else { + comments = ""; + } + variables_["comments"] = comments; +} + +OneofGenerator::~OneofGenerator() {} + +void OneofGenerator::SetOneofIndexBase(int index_base) { + int index = descriptor_->index() + index_base; + // Flip the sign to mark it as a oneof. + variables_["index"] = StrCat(-index); +} + +void OneofGenerator::GenerateCaseEnum(io::Printer* printer) { + printer->Print( + variables_, + "typedef GPB_ENUM($enum_name$) {\n"); + printer->Indent(); + printer->Print( + variables_, + "$enum_name$_GPBUnsetOneOfCase = 0,\n"); + std::string enum_name = variables_["enum_name"]; + for (int j = 0; j < descriptor_->field_count(); j++) { + const FieldDescriptor* field = descriptor_->field(j); + std::string field_name = FieldNameCapitalized(field); + printer->Print( + "$enum_name$_$field_name$ = $field_number$,\n", + "enum_name", enum_name, + "field_name", field_name, + "field_number", StrCat(field->number())); + } + printer->Outdent(); + printer->Print( + "};\n" + "\n"); +} + +void OneofGenerator::GeneratePublicCasePropertyDeclaration( + io::Printer* printer) { + printer->Print( + variables_, + "$comments$" + "@property(nonatomic, readonly) $enum_name$ $name$OneOfCase;\n" + "\n"); +} + +void OneofGenerator::GenerateClearFunctionDeclaration(io::Printer* printer) { + printer->Print( + variables_, + "/**\n" + " * Clears whatever value was set for the oneof '$name$'.\n" + " **/\n" + "void $owning_message_class$_Clear$capitalized_name$OneOfCase($owning_message_class$ *message);\n"); +} + +void OneofGenerator::GeneratePropertyImplementation(io::Printer* printer) { + printer->Print( + variables_, + "@dynamic $name$OneOfCase;\n"); +} + +void OneofGenerator::GenerateClearFunctionImplementation(io::Printer* printer) { + printer->Print( + variables_, + "void $owning_message_class$_Clear$capitalized_name$OneOfCase($owning_message_class$ *message) {\n" + " GPBDescriptor *descriptor = [$owning_message_class$ descriptor];\n" + " GPBOneofDescriptor *oneof = [descriptor.oneofs objectAtIndex:$raw_index$];\n" + " GPBClearOneof(message, oneof);\n" + "}\n"); +} + +std::string OneofGenerator::DescriptorName(void) const { + return variables_.find("name")->second; +} + +std::string OneofGenerator::HasIndexAsString(void) const { + return variables_.find("index")->second; +} + +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_oneof.h b/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_oneof.h new file mode 100644 index 00000000..3d59f4ff --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_oneof.h @@ -0,0 +1,76 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_ONEOF_H__ +#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_ONEOF_H__ + +#include <string> +#include <set> +#include <vector> +#include <descriptor.h> +#include <io/printer.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace objectivec { + +class OneofGenerator { + public: + explicit OneofGenerator(const OneofDescriptor* descriptor); + ~OneofGenerator(); + + OneofGenerator(const OneofGenerator&) = delete; + OneofGenerator& operator=(const OneofGenerator&) = delete; + + void SetOneofIndexBase(int index_base); + + void GenerateCaseEnum(io::Printer* printer); + + void GeneratePublicCasePropertyDeclaration(io::Printer* printer); + void GenerateClearFunctionDeclaration(io::Printer* printer); + + void GeneratePropertyImplementation(io::Printer* printer); + void GenerateClearFunctionImplementation(io::Printer* printer); + + std::string DescriptorName(void) const; + std::string HasIndexAsString(void) const; + + private: + const OneofDescriptor* descriptor_; + std::map<std::string, std::string> variables_; +}; + +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_ONEOF_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_primitive_field.cc b/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_primitive_field.cc new file mode 100644 index 00000000..7b5eec0c --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_primitive_field.cc @@ -0,0 +1,190 @@ +// 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 <map> +#include <string> + +#include <compiler/objectivec/objectivec_helpers.h> +#include <compiler/objectivec/objectivec_primitive_field.h> +#include <io/printer.h> +#include <stubs/strutil.h> +#include <wire_format.h> +#include <wire_format_lite.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace objectivec { + +using internal::WireFormat; +using internal::WireFormatLite; + +namespace { + +const char* PrimitiveTypeName(const FieldDescriptor* descriptor) { + ObjectiveCType type = GetObjectiveCType(descriptor); + switch (type) { + case OBJECTIVECTYPE_INT32: + return "int32_t"; + case OBJECTIVECTYPE_UINT32: + return "uint32_t"; + case OBJECTIVECTYPE_INT64: + return "int64_t"; + case OBJECTIVECTYPE_UINT64: + return "uint64_t"; + case OBJECTIVECTYPE_FLOAT: + return "float"; + case OBJECTIVECTYPE_DOUBLE: + return "double"; + case OBJECTIVECTYPE_BOOLEAN: + return "BOOL"; + case OBJECTIVECTYPE_STRING: + return "NSString"; + case OBJECTIVECTYPE_DATA: + return "NSData"; + case OBJECTIVECTYPE_ENUM: + return "int32_t"; + case OBJECTIVECTYPE_MESSAGE: + return NULL; // Messages go through objectivec_message_field.cc|h. + } + + // 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 NULL; +} + +const char* PrimitiveArrayTypeName(const FieldDescriptor* descriptor) { + ObjectiveCType type = GetObjectiveCType(descriptor); + switch (type) { + case OBJECTIVECTYPE_INT32: + return "Int32"; + case OBJECTIVECTYPE_UINT32: + return "UInt32"; + case OBJECTIVECTYPE_INT64: + return "Int64"; + case OBJECTIVECTYPE_UINT64: + return "UInt64"; + case OBJECTIVECTYPE_FLOAT: + return "Float"; + case OBJECTIVECTYPE_DOUBLE: + return "Double"; + case OBJECTIVECTYPE_BOOLEAN: + return "Bool"; + case OBJECTIVECTYPE_STRING: + return ""; // Want NSArray + case OBJECTIVECTYPE_DATA: + return ""; // Want NSArray + case OBJECTIVECTYPE_ENUM: + return "Enum"; + case OBJECTIVECTYPE_MESSAGE: + // Want NSArray (but goes through objectivec_message_field.cc|h). + return ""; + } + + // 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 NULL; +} + +void SetPrimitiveVariables(const FieldDescriptor* descriptor, + std::map<std::string, std::string>* variables) { + std::string primitive_name = PrimitiveTypeName(descriptor); + (*variables)["type"] = primitive_name; + (*variables)["storage_type"] = primitive_name; +} + +} // namespace + +PrimitiveFieldGenerator::PrimitiveFieldGenerator( + const FieldDescriptor* descriptor, const Options& options) + : SingleFieldGenerator(descriptor, options) { + SetPrimitiveVariables(descriptor, &variables_); +} + +PrimitiveFieldGenerator::~PrimitiveFieldGenerator() {} + +void PrimitiveFieldGenerator::GenerateFieldStorageDeclaration( + io::Printer* printer) const { + if (GetObjectiveCType(descriptor_) == OBJECTIVECTYPE_BOOLEAN) { + // Nothing, BOOLs are stored in the has bits. + } else { + SingleFieldGenerator::GenerateFieldStorageDeclaration(printer); + } +} + +int PrimitiveFieldGenerator::ExtraRuntimeHasBitsNeeded(void) const { + if (GetObjectiveCType(descriptor_) == OBJECTIVECTYPE_BOOLEAN) { + // Reserve a bit for the storage of the boolean. + return 1; + } + return 0; +} + +void PrimitiveFieldGenerator::SetExtraRuntimeHasBitsBase(int has_base) { + if (GetObjectiveCType(descriptor_) == OBJECTIVECTYPE_BOOLEAN) { + // Set into the offset the has bit to use for the actual value. + variables_["storage_offset_value"] = StrCat(has_base); + variables_["storage_offset_comment"] = + " // Stored in _has_storage_ to save space."; + } +} + +PrimitiveObjFieldGenerator::PrimitiveObjFieldGenerator( + const FieldDescriptor* descriptor, const Options& options) + : ObjCObjFieldGenerator(descriptor, options) { + SetPrimitiveVariables(descriptor, &variables_); + variables_["property_storage_attribute"] = "copy"; +} + +PrimitiveObjFieldGenerator::~PrimitiveObjFieldGenerator() {} + +RepeatedPrimitiveFieldGenerator::RepeatedPrimitiveFieldGenerator( + const FieldDescriptor* descriptor, const Options& options) + : RepeatedFieldGenerator(descriptor, options) { + SetPrimitiveVariables(descriptor, &variables_); + + std::string base_name = PrimitiveArrayTypeName(descriptor); + if (base_name.length()) { + variables_["array_storage_type"] = "GPB" + base_name + "Array"; + } else { + variables_["array_storage_type"] = "NSMutableArray"; + variables_["array_property_type"] = + "NSMutableArray<" + variables_["storage_type"] + "*>"; + } +} + +RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() {} + +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_primitive_field.h b/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_primitive_field.h new file mode 100644 index 00000000..88e91ba8 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/objectivec/objectivec_primitive_field.h @@ -0,0 +1,95 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_PRIMITIVE_FIELD_H__ +#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_PRIMITIVE_FIELD_H__ + +#include <map> +#include <string> +#include <compiler/objectivec/objectivec_field.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace objectivec { + +class PrimitiveFieldGenerator : public SingleFieldGenerator { + friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field, + const Options& options); + + protected: + PrimitiveFieldGenerator(const FieldDescriptor* descriptor, + const Options& options); + virtual ~PrimitiveFieldGenerator(); + + PrimitiveFieldGenerator(const PrimitiveFieldGenerator&) = delete; + PrimitiveFieldGenerator& operator=(const PrimitiveFieldGenerator&) = delete; + + virtual void GenerateFieldStorageDeclaration(io::Printer* printer) const override; + + virtual int ExtraRuntimeHasBitsNeeded(void) const override; + virtual void SetExtraRuntimeHasBitsBase(int index_base) override; +}; + +class PrimitiveObjFieldGenerator : public ObjCObjFieldGenerator { + friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field, + const Options& options); + + protected: + PrimitiveObjFieldGenerator(const FieldDescriptor* descriptor, + const Options& options); + virtual ~PrimitiveObjFieldGenerator(); + + PrimitiveObjFieldGenerator(const PrimitiveObjFieldGenerator&) = delete; + PrimitiveObjFieldGenerator& operator=(const PrimitiveObjFieldGenerator&) = + delete; +}; + +class RepeatedPrimitiveFieldGenerator : public RepeatedFieldGenerator { + friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field, + const Options& options); + + protected: + RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor, + const Options& options); + virtual ~RepeatedPrimitiveFieldGenerator(); + + RepeatedPrimitiveFieldGenerator(const RepeatedPrimitiveFieldGenerator&) = + delete; + RepeatedPrimitiveFieldGenerator& operator=( + const RepeatedPrimitiveFieldGenerator&) = delete; +}; + +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_PRIMITIVE_FIELD_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/package_info.h b/NorthstarDedicatedTest/include/protobuf/compiler/package_info.h new file mode 100644 index 00000000..105ef601 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/package_info.h @@ -0,0 +1,63 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// This file exists solely to document the google::protobuf::compiler namespace. +// It is not compiled into anything, but it may be read by an automated +// documentation generator. + +namespace google { +namespace protobuf { + +// Implementation of the Protocol Buffer compiler. +// +// This package contains code for parsing .proto files and generating code +// based on them. There are two reasons you might be interested in this +// package: +// - You want to parse .proto files at runtime. In this case, you should +// look at importer.h. Since this functionality is widely useful, it is +// included in the libprotobuf base library; you do not have to link against +// libprotoc. +// - You want to write a custom protocol compiler which generates different +// kinds of code, e.g. code in a different language which is not supported +// by the official compiler. For this purpose, command_line_interface.h +// provides you with a complete compiler front-end, so all you need to do +// is write a custom implementation of CodeGenerator and a trivial main() +// function. You can even make your compiler support the official languages +// in addition to your own. Since this functionality is only useful to those +// writing custom compilers, it is in a separate library called "libprotoc" +// which you will have to link against. +namespace compiler {} + +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/parser.cc b/NorthstarDedicatedTest/include/protobuf/compiler/parser.cc new file mode 100644 index 00000000..6d84ac9f --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/parser.cc @@ -0,0 +1,2445 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// Recursive descent FTW. + +#include <compiler/parser.h> + +#include <float.h> + +#include <cstdint> +#include <limits> +#include <unordered_map> +#include <unordered_set> + +#include <stubs/casts.h> +#include <stubs/logging.h> +#include <stubs/common.h> +#include <descriptor.pb.h> +#include <io/tokenizer.h> +#include <descriptor.h> +#include <wire_format.h> +#include <stubs/strutil.h> +#include <stubs/map_util.h> +#include <stubs/hash.h> + +namespace google { +namespace protobuf { +namespace compiler { + +using internal::WireFormat; + +namespace { + +typedef std::unordered_map<std::string, FieldDescriptorProto::Type> TypeNameMap; + +TypeNameMap MakeTypeNameTable() { + TypeNameMap result; + + result["double"] = FieldDescriptorProto::TYPE_DOUBLE; + result["float"] = FieldDescriptorProto::TYPE_FLOAT; + result["uint64"] = FieldDescriptorProto::TYPE_UINT64; + result["fixed64"] = FieldDescriptorProto::TYPE_FIXED64; + result["fixed32"] = FieldDescriptorProto::TYPE_FIXED32; + result["bool"] = FieldDescriptorProto::TYPE_BOOL; + result["string"] = FieldDescriptorProto::TYPE_STRING; + result["group"] = FieldDescriptorProto::TYPE_GROUP; + + result["bytes"] = FieldDescriptorProto::TYPE_BYTES; + result["uint32"] = FieldDescriptorProto::TYPE_UINT32; + result["sfixed32"] = FieldDescriptorProto::TYPE_SFIXED32; + result["sfixed64"] = FieldDescriptorProto::TYPE_SFIXED64; + result["int32"] = FieldDescriptorProto::TYPE_INT32; + result["int64"] = FieldDescriptorProto::TYPE_INT64; + result["sint32"] = FieldDescriptorProto::TYPE_SINT32; + result["sint64"] = FieldDescriptorProto::TYPE_SINT64; + + return result; +} + +const TypeNameMap kTypeNames = MakeTypeNameTable(); + +// Camel-case the field name and append "Entry" for generated map entry name. +// e.g. map<KeyType, ValueType> foo_map => FooMapEntry +std::string MapEntryName(const std::string& field_name) { + std::string result; + static const char kSuffix[] = "Entry"; + result.reserve(field_name.size() + sizeof(kSuffix)); + bool cap_next = true; + for (const char field_name_char : field_name) { + if (field_name_char == '_') { + cap_next = true; + } else if (cap_next) { + // Note: Do not use ctype.h due to locales. + if ('a' <= field_name_char && field_name_char <= 'z') { + result.push_back(field_name_char - 'a' + 'A'); + } else { + result.push_back(field_name_char); + } + cap_next = false; + } else { + result.push_back(field_name_char); + } + } + result.append(kSuffix); + return result; +} + +bool IsUppercase(char c) { return c >= 'A' && c <= 'Z'; } + +bool IsLowercase(char c) { return c >= 'a' && c <= 'z'; } + +bool IsNumber(char c) { return c >= '0' && c <= '9'; } + +bool IsUpperCamelCase(const std::string& name) { + if (name.empty()) { + return true; + } + // Name must start with an upper case character. + if (!IsUppercase(name[0])) { + return false; + } + // Must not contains underscore. + for (const char c : name) { + if (c == '_') { + return false; + } + } + return true; +} + +bool IsUpperUnderscore(const std::string& name) { + for (const char c : name) { + if (!IsUppercase(c) && c != '_' && !IsNumber(c)) { + return false; + } + } + return true; +} + +bool IsLowerUnderscore(const std::string& name) { + for (const char c : name) { + if (!IsLowercase(c) && c != '_' && !IsNumber(c)) { + return false; + } + } + return true; +} + +bool IsNumberFollowUnderscore(const std::string& name) { + for (int i = 1; i < name.length(); i++) { + const char c = name[i]; + if (IsNumber(c) && name[i - 1] == '_') { + return true; + } + } + return false; +} + +} // anonymous namespace + +// Makes code slightly more readable. The meaning of "DO(foo)" is +// "Execute foo and fail if it fails.", where failure is indicated by +// returning false. +#define DO(STATEMENT) \ + if (STATEMENT) { \ + } else \ + return false + +// =================================================================== + +Parser::Parser() + : input_(NULL), + error_collector_(NULL), + source_location_table_(NULL), + had_errors_(false), + require_syntax_identifier_(false), + stop_after_syntax_identifier_(false) { +} + +Parser::~Parser() {} + +// =================================================================== + +inline bool Parser::LookingAt(const char* text) { + return input_->current().text == text; +} + +inline bool Parser::LookingAtType(io::Tokenizer::TokenType token_type) { + return input_->current().type == token_type; +} + +inline bool Parser::AtEnd() { return LookingAtType(io::Tokenizer::TYPE_END); } + +bool Parser::TryConsume(const char* text) { + if (LookingAt(text)) { + input_->Next(); + return true; + } else { + return false; + } +} + +bool Parser::Consume(const char* text, const char* error) { + if (TryConsume(text)) { + return true; + } else { + AddError(error); + return false; + } +} + +bool Parser::Consume(const char* text) { + if (TryConsume(text)) { + return true; + } else { + AddError("Expected \"" + std::string(text) + "\"."); + return false; + } +} + +bool Parser::ConsumeIdentifier(std::string* output, const char* error) { + if (LookingAtType(io::Tokenizer::TYPE_IDENTIFIER)) { + *output = input_->current().text; + input_->Next(); + return true; + } else { + AddError(error); + return false; + } +} + +bool Parser::ConsumeInteger(int* output, const char* error) { + if (LookingAtType(io::Tokenizer::TYPE_INTEGER)) { + uint64_t value = 0; + if (!io::Tokenizer::ParseInteger(input_->current().text, + std::numeric_limits<int32_t>::max(), + &value)) { + AddError("Integer out of range."); + // We still return true because we did, in fact, parse an integer. + } + *output = value; + input_->Next(); + return true; + } else { + AddError(error); + return false; + } +} + +bool Parser::ConsumeSignedInteger(int* output, const char* error) { + bool is_negative = false; + uint64_t max_value = std::numeric_limits<int32_t>::max(); + if (TryConsume("-")) { + is_negative = true; + max_value += 1; + } + uint64_t value = 0; + DO(ConsumeInteger64(max_value, &value, error)); + if (is_negative) value *= -1; + *output = value; + return true; +} + +bool Parser::ConsumeInteger64(uint64_t max_value, uint64_t* output, + const char* error) { + if (LookingAtType(io::Tokenizer::TYPE_INTEGER)) { + if (!io::Tokenizer::ParseInteger(input_->current().text, max_value, + output)) { + AddError("Integer out of range."); + // We still return true because we did, in fact, parse an integer. + *output = 0; + } + input_->Next(); + return true; + } else { + AddError(error); + return false; + } +} + +bool Parser::ConsumeNumber(double* output, const char* error) { + if (LookingAtType(io::Tokenizer::TYPE_FLOAT)) { + *output = io::Tokenizer::ParseFloat(input_->current().text); + input_->Next(); + return true; + } else if (LookingAtType(io::Tokenizer::TYPE_INTEGER)) { + // Also accept integers. + uint64_t value = 0; + if (!io::Tokenizer::ParseInteger(input_->current().text, + std::numeric_limits<uint64_t>::max(), + &value)) { + AddError("Integer out of range."); + // We still return true because we did, in fact, parse a number. + } + *output = value; + input_->Next(); + return true; + } else if (LookingAt("inf")) { + *output = std::numeric_limits<double>::infinity(); + input_->Next(); + return true; + } else if (LookingAt("nan")) { + *output = std::numeric_limits<double>::quiet_NaN(); + input_->Next(); + return true; + } else { + AddError(error); + return false; + } +} + +bool Parser::ConsumeString(std::string* output, const char* error) { + if (LookingAtType(io::Tokenizer::TYPE_STRING)) { + io::Tokenizer::ParseString(input_->current().text, output); + input_->Next(); + // Allow C++ like concatenation of adjacent string tokens. + while (LookingAtType(io::Tokenizer::TYPE_STRING)) { + io::Tokenizer::ParseStringAppend(input_->current().text, output); + input_->Next(); + } + return true; + } else { + AddError(error); + return false; + } +} + +bool Parser::TryConsumeEndOfDeclaration(const char* text, + const LocationRecorder* location) { + if (LookingAt(text)) { + std::string leading, trailing; + std::vector<std::string> detached; + input_->NextWithComments(&trailing, &detached, &leading); + + // Save the leading comments for next time, and recall the leading comments + // from last time. + leading.swap(upcoming_doc_comments_); + + if (location != NULL) { + upcoming_detached_comments_.swap(detached); + location->AttachComments(&leading, &trailing, &detached); + } else if (strcmp(text, "}") == 0) { + // If the current location is null and we are finishing the current scope, + // drop pending upcoming detached comments. + upcoming_detached_comments_.swap(detached); + } else { + // Otherwise, append the new detached comments to the existing upcoming + // detached comments. + upcoming_detached_comments_.insert(upcoming_detached_comments_.end(), + detached.begin(), detached.end()); + } + + return true; + } else { + return false; + } +} + +bool Parser::ConsumeEndOfDeclaration(const char* text, + const LocationRecorder* location) { + if (TryConsumeEndOfDeclaration(text, location)) { + return true; + } else { + AddError("Expected \"" + std::string(text) + "\"."); + return false; + } +} + +// ------------------------------------------------------------------- + +void Parser::AddError(int line, int column, const std::string& error) { + if (error_collector_ != NULL) { + error_collector_->AddError(line, column, error); + } + had_errors_ = true; +} + +void Parser::AddError(const std::string& error) { + AddError(input_->current().line, input_->current().column, error); +} + +void Parser::AddWarning(const std::string& warning) { + if (error_collector_ != nullptr) { + error_collector_->AddWarning(input_->current().line, + input_->current().column, warning); + } +} + +// ------------------------------------------------------------------- + +Parser::LocationRecorder::LocationRecorder(Parser* parser) + : parser_(parser), + source_code_info_(parser->source_code_info_), + location_(parser_->source_code_info_->add_location()) { + location_->add_span(parser_->input_->current().line); + location_->add_span(parser_->input_->current().column); +} + +Parser::LocationRecorder::LocationRecorder(const LocationRecorder& parent) { + Init(parent, parent.source_code_info_); +} + +Parser::LocationRecorder::LocationRecorder(const LocationRecorder& parent, + int path1, + SourceCodeInfo* source_code_info) { + Init(parent, source_code_info); + AddPath(path1); +} + +Parser::LocationRecorder::LocationRecorder(const LocationRecorder& parent, + int path1) { + Init(parent, parent.source_code_info_); + AddPath(path1); +} + +Parser::LocationRecorder::LocationRecorder(const LocationRecorder& parent, + int path1, int path2) { + Init(parent, parent.source_code_info_); + AddPath(path1); + AddPath(path2); +} + +void Parser::LocationRecorder::Init(const LocationRecorder& parent, + SourceCodeInfo* source_code_info) { + parser_ = parent.parser_; + source_code_info_ = source_code_info; + + location_ = source_code_info_->add_location(); + location_->mutable_path()->CopyFrom(parent.location_->path()); + + location_->add_span(parser_->input_->current().line); + location_->add_span(parser_->input_->current().column); +} + +Parser::LocationRecorder::~LocationRecorder() { + if (location_->span_size() <= 2) { + EndAt(parser_->input_->previous()); + } +} + +void Parser::LocationRecorder::AddPath(int path_component) { + location_->add_path(path_component); +} + +void Parser::LocationRecorder::StartAt(const io::Tokenizer::Token& token) { + location_->set_span(0, token.line); + location_->set_span(1, token.column); +} + +void Parser::LocationRecorder::StartAt(const LocationRecorder& other) { + location_->set_span(0, other.location_->span(0)); + location_->set_span(1, other.location_->span(1)); +} + +void Parser::LocationRecorder::EndAt(const io::Tokenizer::Token& token) { + if (token.line != location_->span(0)) { + location_->add_span(token.line); + } + location_->add_span(token.end_column); +} + +void Parser::LocationRecorder::RecordLegacyLocation( + const Message* descriptor, + DescriptorPool::ErrorCollector::ErrorLocation location) { + if (parser_->source_location_table_ != NULL) { + parser_->source_location_table_->Add( + descriptor, location, location_->span(0), location_->span(1)); + } +} + +void Parser::LocationRecorder::RecordLegacyImportLocation( + const Message* descriptor, const std::string& name) { + if (parser_->source_location_table_ != nullptr) { + parser_->source_location_table_->AddImport( + descriptor, name, location_->span(0), location_->span(1)); + } +} + +int Parser::LocationRecorder::CurrentPathSize() const { + return location_->path_size(); +} + +void Parser::LocationRecorder::AttachComments( + std::string* leading, std::string* trailing, + std::vector<std::string>* detached_comments) const { + GOOGLE_CHECK(!location_->has_leading_comments()); + GOOGLE_CHECK(!location_->has_trailing_comments()); + + if (!leading->empty()) { + location_->mutable_leading_comments()->swap(*leading); + } + if (!trailing->empty()) { + location_->mutable_trailing_comments()->swap(*trailing); + } + for (int i = 0; i < detached_comments->size(); ++i) { + location_->add_leading_detached_comments()->swap((*detached_comments)[i]); + } + detached_comments->clear(); +} + +// ------------------------------------------------------------------- + +void Parser::SkipStatement() { + while (true) { + if (AtEnd()) { + return; + } else if (LookingAtType(io::Tokenizer::TYPE_SYMBOL)) { + if (TryConsumeEndOfDeclaration(";", NULL)) { + return; + } else if (TryConsume("{")) { + SkipRestOfBlock(); + return; + } else if (LookingAt("}")) { + return; + } + } + input_->Next(); + } +} + +void Parser::SkipRestOfBlock() { + while (true) { + if (AtEnd()) { + return; + } else if (LookingAtType(io::Tokenizer::TYPE_SYMBOL)) { + if (TryConsumeEndOfDeclaration("}", NULL)) { + return; + } else if (TryConsume("{")) { + SkipRestOfBlock(); + } + } + input_->Next(); + } +} + +// =================================================================== + +bool Parser::ValidateEnum(const EnumDescriptorProto* proto) { + bool has_allow_alias = false; + bool allow_alias = false; + + for (int i = 0; i < proto->options().uninterpreted_option_size(); i++) { + const UninterpretedOption option = proto->options().uninterpreted_option(i); + if (option.name_size() > 1) { + continue; + } + if (!option.name(0).is_extension() && + option.name(0).name_part() == "allow_alias") { + has_allow_alias = true; + if (option.identifier_value() == "true") { + allow_alias = true; + } + break; + } + } + + if (has_allow_alias && !allow_alias) { + std::string error = + "\"" + proto->name() + + "\" declares 'option allow_alias = false;' which has no effect. " + "Please remove the declaration."; + // This needlessly clutters declarations with nops. + AddError(error); + return false; + } + + std::set<int> used_values; + bool has_duplicates = false; + for (int i = 0; i < proto->value_size(); ++i) { + const EnumValueDescriptorProto& enum_value = proto->value(i); + if (used_values.find(enum_value.number()) != used_values.end()) { + has_duplicates = true; + break; + } else { + used_values.insert(enum_value.number()); + } + } + if (allow_alias && !has_duplicates) { + std::string error = + "\"" + proto->name() + + "\" declares support for enum aliases but no enum values share field " + "numbers. Please remove the unnecessary 'option allow_alias = true;' " + "declaration."; + // Generate an error if an enum declares support for duplicate enum values + // and does not use it protect future authors. + AddError(error); + return false; + } + + // Enforce that enum constants must be UPPER_CASE except in case of + // enum_alias. + if (!allow_alias) { + for (const auto& enum_value : proto->value()) { + if (!IsUpperUnderscore(enum_value.name())) { + AddWarning( + "Enum constant should be in UPPER_CASE. Found: " + + enum_value.name() + + ". See https://developers.google.com/protocol-buffers/docs/style"); + } + } + } + + return true; +} + +bool Parser::Parse(io::Tokenizer* input, FileDescriptorProto* file) { + input_ = input; + had_errors_ = false; + syntax_identifier_.clear(); + + // Note that |file| could be NULL at this point if + // stop_after_syntax_identifier_ is true. So, we conservatively allocate + // SourceCodeInfo on the stack, then swap it into the FileDescriptorProto + // later on. + SourceCodeInfo source_code_info; + source_code_info_ = &source_code_info; + + if (LookingAtType(io::Tokenizer::TYPE_START)) { + // Advance to first token. + input_->NextWithComments(NULL, &upcoming_detached_comments_, + &upcoming_doc_comments_); + } + + { + LocationRecorder root_location(this); + root_location.RecordLegacyLocation(file, + DescriptorPool::ErrorCollector::OTHER); + + if (require_syntax_identifier_ || LookingAt("syntax")) { + if (!ParseSyntaxIdentifier(root_location)) { + // Don't attempt to parse the file if we didn't recognize the syntax + // identifier. + return false; + } + // Store the syntax into the file. + if (file != NULL) file->set_syntax(syntax_identifier_); + } else if (!stop_after_syntax_identifier_) { + GOOGLE_LOG(WARNING) << "No syntax specified for the proto file: " << file->name() + << ". Please use 'syntax = \"proto2\";' " + << "or 'syntax = \"proto3\";' to specify a syntax " + << "version. (Defaulted to proto2 syntax.)"; + syntax_identifier_ = "proto2"; + } + + if (stop_after_syntax_identifier_) return !had_errors_; + + // Repeatedly parse statements until we reach the end of the file. + while (!AtEnd()) { + if (!ParseTopLevelStatement(file, root_location)) { + // This statement failed to parse. Skip it, but keep looping to parse + // other statements. + SkipStatement(); + + if (LookingAt("}")) { + AddError("Unmatched \"}\"."); + input_->NextWithComments(NULL, &upcoming_detached_comments_, + &upcoming_doc_comments_); + } + } + } + } + + input_ = NULL; + source_code_info_ = NULL; + assert(file != NULL); + source_code_info.Swap(file->mutable_source_code_info()); + return !had_errors_; +} + +bool Parser::ParseSyntaxIdentifier(const LocationRecorder& parent) { + LocationRecorder syntax_location(parent, + FileDescriptorProto::kSyntaxFieldNumber); + DO(Consume( + "syntax", + "File must begin with a syntax statement, e.g. 'syntax = \"proto2\";'.")); + DO(Consume("=")); + io::Tokenizer::Token syntax_token = input_->current(); + std::string syntax; + DO(ConsumeString(&syntax, "Expected syntax identifier.")); + DO(ConsumeEndOfDeclaration(";", &syntax_location)); + + syntax_identifier_ = syntax; + + if (syntax != "proto2" && syntax != "proto3" && + !stop_after_syntax_identifier_) { + AddError(syntax_token.line, syntax_token.column, + "Unrecognized syntax identifier \"" + syntax + + "\". This parser " + "only recognizes \"proto2\" and \"proto3\"."); + return false; + } + + return true; +} + +bool Parser::ParseTopLevelStatement(FileDescriptorProto* file, + const LocationRecorder& root_location) { + if (TryConsumeEndOfDeclaration(";", NULL)) { + // empty statement; ignore + return true; + } else if (LookingAt("message")) { + LocationRecorder location(root_location, + FileDescriptorProto::kMessageTypeFieldNumber, + file->message_type_size()); + return ParseMessageDefinition(file->add_message_type(), location, file); + } else if (LookingAt("enum")) { + LocationRecorder location(root_location, + FileDescriptorProto::kEnumTypeFieldNumber, + file->enum_type_size()); + return ParseEnumDefinition(file->add_enum_type(), location, file); + } else if (LookingAt("service")) { + LocationRecorder location(root_location, + FileDescriptorProto::kServiceFieldNumber, + file->service_size()); + return ParseServiceDefinition(file->add_service(), location, file); + } else if (LookingAt("extend")) { + LocationRecorder location(root_location, + FileDescriptorProto::kExtensionFieldNumber); + return ParseExtend( + file->mutable_extension(), file->mutable_message_type(), root_location, + FileDescriptorProto::kMessageTypeFieldNumber, location, file); + } else if (LookingAt("import")) { + return ParseImport(file->mutable_dependency(), + file->mutable_public_dependency(), + file->mutable_weak_dependency(), root_location, file); + } else if (LookingAt("package")) { + return ParsePackage(file, root_location, file); + } else if (LookingAt("option")) { + LocationRecorder location(root_location, + FileDescriptorProto::kOptionsFieldNumber); + return ParseOption(file->mutable_options(), location, file, + OPTION_STATEMENT); + } else { + AddError("Expected top-level statement (e.g. \"message\")."); + return false; + } +} + +// ------------------------------------------------------------------- +// Messages + +bool Parser::ParseMessageDefinition( + DescriptorProto* message, const LocationRecorder& message_location, + const FileDescriptorProto* containing_file) { + DO(Consume("message")); + { + LocationRecorder location(message_location, + DescriptorProto::kNameFieldNumber); + location.RecordLegacyLocation(message, + DescriptorPool::ErrorCollector::NAME); + DO(ConsumeIdentifier(message->mutable_name(), "Expected message name.")); + if (!IsUpperCamelCase(message->name())) { + AddWarning( + "Message name should be in UpperCamelCase. Found: " + + message->name() + + ". See https://developers.google.com/protocol-buffers/docs/style"); + } + } + DO(ParseMessageBlock(message, message_location, containing_file)); + + if (syntax_identifier_ == "proto3") { + // Add synthetic one-field oneofs for optional fields, except messages which + // already have presence in proto3. + // + // We have to make sure the oneof names don't conflict with any other + // field or oneof. + std::unordered_set<std::string> names; + for (const auto& field : message->field()) { + names.insert(field.name()); + } + for (const auto& oneof : message->oneof_decl()) { + names.insert(oneof.name()); + } + + for (auto& field : *message->mutable_field()) { + if (field.proto3_optional()) { + std::string oneof_name = field.name(); + + // Prepend 'XXXXX_' until we are no longer conflicting. + // Avoid prepending a double-underscore because such names are + // reserved in C++. + if (oneof_name.empty() || oneof_name[0] != '_') { + oneof_name = '_' + oneof_name; + } + while (names.count(oneof_name) > 0) { + oneof_name = 'X' + oneof_name; + } + + names.insert(oneof_name); + field.set_oneof_index(message->oneof_decl_size()); + OneofDescriptorProto* oneof = message->add_oneof_decl(); + oneof->set_name(oneof_name); + } + } + } + + return true; +} + +namespace { + +const int kMaxRangeSentinel = -1; + +bool IsMessageSetWireFormatMessage(const DescriptorProto& message) { + const MessageOptions& options = message.options(); + for (int i = 0; i < options.uninterpreted_option_size(); ++i) { + const UninterpretedOption& uninterpreted = options.uninterpreted_option(i); + if (uninterpreted.name_size() == 1 && + uninterpreted.name(0).name_part() == "message_set_wire_format" && + uninterpreted.identifier_value() == "true") { + return true; + } + } + return false; +} + +// Modifies any extension ranges that specified 'max' as the end of the +// extension range, and sets them to the type-specific maximum. The actual max +// tag number can only be determined after all options have been parsed. +void AdjustExtensionRangesWithMaxEndNumber(DescriptorProto* message) { + const bool is_message_set = IsMessageSetWireFormatMessage(*message); + const int max_extension_number = is_message_set + ? std::numeric_limits<int32_t>::max() + : FieldDescriptor::kMaxNumber + 1; + for (int i = 0; i < message->extension_range_size(); ++i) { + if (message->extension_range(i).end() == kMaxRangeSentinel) { + message->mutable_extension_range(i)->set_end(max_extension_number); + } + } +} + +// Modifies any reserved ranges that specified 'max' as the end of the +// reserved range, and sets them to the type-specific maximum. The actual max +// tag number can only be determined after all options have been parsed. +void AdjustReservedRangesWithMaxEndNumber(DescriptorProto* message) { + const bool is_message_set = IsMessageSetWireFormatMessage(*message); + const int max_field_number = is_message_set + ? std::numeric_limits<int32_t>::max() + : FieldDescriptor::kMaxNumber + 1; + for (int i = 0; i < message->reserved_range_size(); ++i) { + if (message->reserved_range(i).end() == kMaxRangeSentinel) { + message->mutable_reserved_range(i)->set_end(max_field_number); + } + } +} + +} // namespace + +bool Parser::ParseMessageBlock(DescriptorProto* message, + const LocationRecorder& message_location, + const FileDescriptorProto* containing_file) { + DO(ConsumeEndOfDeclaration("{", &message_location)); + + while (!TryConsumeEndOfDeclaration("}", NULL)) { + if (AtEnd()) { + AddError("Reached end of input in message definition (missing '}')."); + return false; + } + + if (!ParseMessageStatement(message, message_location, containing_file)) { + // This statement failed to parse. Skip it, but keep looping to parse + // other statements. + SkipStatement(); + } + } + + if (message->extension_range_size() > 0) { + AdjustExtensionRangesWithMaxEndNumber(message); + } + if (message->reserved_range_size() > 0) { + AdjustReservedRangesWithMaxEndNumber(message); + } + return true; +} + +bool Parser::ParseMessageStatement(DescriptorProto* message, + const LocationRecorder& message_location, + const FileDescriptorProto* containing_file) { + if (TryConsumeEndOfDeclaration(";", NULL)) { + // empty statement; ignore + return true; + } else if (LookingAt("message")) { + LocationRecorder location(message_location, + DescriptorProto::kNestedTypeFieldNumber, + message->nested_type_size()); + return ParseMessageDefinition(message->add_nested_type(), location, + containing_file); + } else if (LookingAt("enum")) { + LocationRecorder location(message_location, + DescriptorProto::kEnumTypeFieldNumber, + message->enum_type_size()); + return ParseEnumDefinition(message->add_enum_type(), location, + containing_file); + } else if (LookingAt("extensions")) { + LocationRecorder location(message_location, + DescriptorProto::kExtensionRangeFieldNumber); + return ParseExtensions(message, location, containing_file); + } else if (LookingAt("reserved")) { + return ParseReserved(message, message_location); + } else if (LookingAt("extend")) { + LocationRecorder location(message_location, + DescriptorProto::kExtensionFieldNumber); + return ParseExtend(message->mutable_extension(), + message->mutable_nested_type(), message_location, + DescriptorProto::kNestedTypeFieldNumber, location, + containing_file); + } else if (LookingAt("option")) { + LocationRecorder location(message_location, + DescriptorProto::kOptionsFieldNumber); + return ParseOption(message->mutable_options(), location, containing_file, + OPTION_STATEMENT); + } else if (LookingAt("oneof")) { + int oneof_index = message->oneof_decl_size(); + LocationRecorder oneof_location( + message_location, DescriptorProto::kOneofDeclFieldNumber, oneof_index); + + return ParseOneof(message->add_oneof_decl(), message, oneof_index, + oneof_location, message_location, containing_file); + } else { + LocationRecorder location(message_location, + DescriptorProto::kFieldFieldNumber, + message->field_size()); + return ParseMessageField( + message->add_field(), message->mutable_nested_type(), message_location, + DescriptorProto::kNestedTypeFieldNumber, location, containing_file); + } +} + +bool Parser::ParseMessageField(FieldDescriptorProto* field, + RepeatedPtrField<DescriptorProto>* messages, + const LocationRecorder& parent_location, + int location_field_number_for_nested_type, + const LocationRecorder& field_location, + const FileDescriptorProto* containing_file) { + { + FieldDescriptorProto::Label label; + if (ParseLabel(&label, field_location, containing_file)) { + field->set_label(label); + if (label == FieldDescriptorProto::LABEL_OPTIONAL && + syntax_identifier_ == "proto3") { + field->set_proto3_optional(true); + } + } + } + + return ParseMessageFieldNoLabel(field, messages, parent_location, + location_field_number_for_nested_type, + field_location, containing_file); +} + +bool Parser::ParseMessageFieldNoLabel( + FieldDescriptorProto* field, RepeatedPtrField<DescriptorProto>* messages, + const LocationRecorder& parent_location, + int location_field_number_for_nested_type, + const LocationRecorder& field_location, + const FileDescriptorProto* containing_file) { + MapField map_field; + // Parse type. + { + LocationRecorder location(field_location); // add path later + location.RecordLegacyLocation(field, DescriptorPool::ErrorCollector::TYPE); + + bool type_parsed = false; + FieldDescriptorProto::Type type = FieldDescriptorProto::TYPE_INT32; + std::string type_name; + + // Special case map field. We only treat the field as a map field if the + // field type name starts with the word "map" with a following "<". + if (TryConsume("map")) { + if (LookingAt("<")) { + map_field.is_map_field = true; + } else { + // False positive + type_parsed = true; + type_name = "map"; + } + } + if (map_field.is_map_field) { + if (field->has_oneof_index()) { + AddError("Map fields are not allowed in oneofs."); + return false; + } + if (field->has_label()) { + AddError( + "Field labels (required/optional/repeated) are not allowed on " + "map fields."); + return false; + } + if (field->has_extendee()) { + AddError("Map fields are not allowed to be extensions."); + return false; + } + field->set_label(FieldDescriptorProto::LABEL_REPEATED); + DO(Consume("<")); + DO(ParseType(&map_field.key_type, &map_field.key_type_name)); + DO(Consume(",")); + DO(ParseType(&map_field.value_type, &map_field.value_type_name)); + DO(Consume(">")); + // Defer setting of the type name of the map field until the + // field name is parsed. Add the source location though. + location.AddPath(FieldDescriptorProto::kTypeNameFieldNumber); + } else { + // Handle the case where no explicit label is given for a non-map field. + if (!field->has_label() && DefaultToOptionalFields()) { + field->set_label(FieldDescriptorProto::LABEL_OPTIONAL); + } + if (!field->has_label()) { + AddError("Expected \"required\", \"optional\", or \"repeated\"."); + // We can actually reasonably recover here by just assuming the user + // forgot the label altogether. + field->set_label(FieldDescriptorProto::LABEL_OPTIONAL); + } + + // Handle the case where the actual type is a message or enum named "map", + // which we already consumed in the code above. + if (!type_parsed) { + DO(ParseType(&type, &type_name)); + } + if (type_name.empty()) { + location.AddPath(FieldDescriptorProto::kTypeFieldNumber); + field->set_type(type); + } else { + location.AddPath(FieldDescriptorProto::kTypeNameFieldNumber); + field->set_type_name(type_name); + } + } + } + + // Parse name and '='. + io::Tokenizer::Token name_token = input_->current(); + { + LocationRecorder location(field_location, + FieldDescriptorProto::kNameFieldNumber); + location.RecordLegacyLocation(field, DescriptorPool::ErrorCollector::NAME); + DO(ConsumeIdentifier(field->mutable_name(), "Expected field name.")); + + if (!IsLowerUnderscore(field->name())) { + AddWarning( + "Field name should be lowercase. Found: " + field->name() + + ". See: https://developers.google.com/protocol-buffers/docs/style"); + } + if (IsNumberFollowUnderscore(field->name())) { + AddWarning( + "Number should not come right after an underscore. Found: " + + field->name() + + ". See: https://developers.google.com/protocol-buffers/docs/style"); + } + } + DO(Consume("=", "Missing field number.")); + + // Parse field number. + { + LocationRecorder location(field_location, + FieldDescriptorProto::kNumberFieldNumber); + location.RecordLegacyLocation(field, + DescriptorPool::ErrorCollector::NUMBER); + int number; + DO(ConsumeInteger(&number, "Expected field number.")); + field->set_number(number); + } + + // Parse options. + DO(ParseFieldOptions(field, field_location, containing_file)); + + // Deal with groups. + if (field->has_type() && field->type() == FieldDescriptorProto::TYPE_GROUP) { + // Awkward: Since a group declares both a message type and a field, we + // have to create overlapping locations. + LocationRecorder group_location(parent_location); + group_location.StartAt(field_location); + group_location.AddPath(location_field_number_for_nested_type); + group_location.AddPath(messages->size()); + + DescriptorProto* group = messages->Add(); + group->set_name(field->name()); + + // Record name location to match the field name's location. + { + LocationRecorder location(group_location, + DescriptorProto::kNameFieldNumber); + location.StartAt(name_token); + location.EndAt(name_token); + location.RecordLegacyLocation(group, + DescriptorPool::ErrorCollector::NAME); + } + + // The field's type_name also comes from the name. Confusing! + { + LocationRecorder location(field_location, + FieldDescriptorProto::kTypeNameFieldNumber); + location.StartAt(name_token); + location.EndAt(name_token); + } + + // As a hack for backwards-compatibility, we force the group name to start + // with a capital letter and lower-case the field name. New code should + // not use groups; it should use nested messages. + if (group->name()[0] < 'A' || 'Z' < group->name()[0]) { + AddError(name_token.line, name_token.column, + "Group names must start with a capital letter."); + } + LowerString(field->mutable_name()); + + field->set_type_name(group->name()); + if (LookingAt("{")) { + DO(ParseMessageBlock(group, group_location, containing_file)); + } else { + AddError("Missing group body."); + return false; + } + } else { + DO(ConsumeEndOfDeclaration(";", &field_location)); + } + + // Create a map entry type if this is a map field. + if (map_field.is_map_field) { + GenerateMapEntry(map_field, field, messages); + } + + return true; +} + +void Parser::GenerateMapEntry(const MapField& map_field, + FieldDescriptorProto* field, + RepeatedPtrField<DescriptorProto>* messages) { + DescriptorProto* entry = messages->Add(); + std::string entry_name = MapEntryName(field->name()); + field->set_type_name(entry_name); + entry->set_name(entry_name); + entry->mutable_options()->set_map_entry(true); + FieldDescriptorProto* key_field = entry->add_field(); + key_field->set_name("key"); + key_field->set_label(FieldDescriptorProto::LABEL_OPTIONAL); + key_field->set_number(1); + if (map_field.key_type_name.empty()) { + key_field->set_type(map_field.key_type); + } else { + key_field->set_type_name(map_field.key_type_name); + } + FieldDescriptorProto* value_field = entry->add_field(); + value_field->set_name("value"); + value_field->set_label(FieldDescriptorProto::LABEL_OPTIONAL); + value_field->set_number(2); + if (map_field.value_type_name.empty()) { + value_field->set_type(map_field.value_type); + } else { + value_field->set_type_name(map_field.value_type_name); + } + // Propagate the "enforce_utf8" option to key and value fields if they + // are strings. This helps simplify the implementation of code generators + // and also reflection-based parsing code. + // + // The following definition: + // message Foo { + // map<string, string> value = 1 [enforce_utf8 = false]; + // } + // will be interpreted as: + // message Foo { + // message ValueEntry { + // option map_entry = true; + // string key = 1 [enforce_utf8 = false]; + // string value = 2 [enforce_utf8 = false]; + // } + // repeated ValueEntry value = 1 [enforce_utf8 = false]; + // } + // + // TODO(xiaofeng): Remove this when the "enforce_utf8" option is removed + // from protocol compiler. + for (int i = 0; i < field->options().uninterpreted_option_size(); ++i) { + const UninterpretedOption& option = + field->options().uninterpreted_option(i); + if (option.name_size() == 1 && + option.name(0).name_part() == "enforce_utf8" && + !option.name(0).is_extension()) { + if (key_field->type() == FieldDescriptorProto::TYPE_STRING) { + key_field->mutable_options()->add_uninterpreted_option()->CopyFrom( + option); + } + if (value_field->type() == FieldDescriptorProto::TYPE_STRING) { + value_field->mutable_options()->add_uninterpreted_option()->CopyFrom( + option); + } + } + } +} + +bool Parser::ParseFieldOptions(FieldDescriptorProto* field, + const LocationRecorder& field_location, + const FileDescriptorProto* containing_file) { + if (!LookingAt("[")) return true; + + LocationRecorder location(field_location, + FieldDescriptorProto::kOptionsFieldNumber); + + DO(Consume("[")); + + // Parse field options. + do { + if (LookingAt("default")) { + // We intentionally pass field_location rather than location here, since + // the default value is not actually an option. + DO(ParseDefaultAssignment(field, field_location, containing_file)); + } else if (LookingAt("json_name")) { + // Like default value, this "json_name" is not an actual option. + DO(ParseJsonName(field, field_location, containing_file)); + } else { + DO(ParseOption(field->mutable_options(), location, containing_file, + OPTION_ASSIGNMENT)); + } + } while (TryConsume(",")); + + DO(Consume("]")); + return true; +} + +bool Parser::ParseDefaultAssignment( + FieldDescriptorProto* field, const LocationRecorder& field_location, + const FileDescriptorProto* containing_file) { + if (field->has_default_value()) { + AddError("Already set option \"default\"."); + field->clear_default_value(); + } + + DO(Consume("default")); + DO(Consume("=")); + + LocationRecorder location(field_location, + FieldDescriptorProto::kDefaultValueFieldNumber); + location.RecordLegacyLocation(field, + DescriptorPool::ErrorCollector::DEFAULT_VALUE); + std::string* default_value = field->mutable_default_value(); + + if (!field->has_type()) { + // The field has a type name, but we don't know if it is a message or an + // enum yet. (If it were a primitive type, |field| would have a type set + // already.) In this case, simply take the current string as the default + // value; we will catch the error later if it is not a valid enum value. + // (N.B. that we do not check whether the current token is an identifier: + // doing so throws strange errors when the user mistypes a primitive + // typename and we assume it's an enum. E.g.: "optional int foo = 1 [default + // = 42]". In such a case the fundamental error is really that "int" is not + // a type, not that "42" is not an identifier. See b/12533582.) + *default_value = input_->current().text; + input_->Next(); + return true; + } + + switch (field->type()) { + case FieldDescriptorProto::TYPE_INT32: + case FieldDescriptorProto::TYPE_INT64: + case FieldDescriptorProto::TYPE_SINT32: + case FieldDescriptorProto::TYPE_SINT64: + case FieldDescriptorProto::TYPE_SFIXED32: + case FieldDescriptorProto::TYPE_SFIXED64: { + uint64_t max_value = std::numeric_limits<int64_t>::max(); + if (field->type() == FieldDescriptorProto::TYPE_INT32 || + field->type() == FieldDescriptorProto::TYPE_SINT32 || + field->type() == FieldDescriptorProto::TYPE_SFIXED32) { + max_value = std::numeric_limits<int32_t>::max(); + } + + // These types can be negative. + if (TryConsume("-")) { + default_value->append("-"); + // Two's complement always has one more negative value than positive. + ++max_value; + } + // Parse the integer to verify that it is not out-of-range. + uint64_t value; + DO(ConsumeInteger64(max_value, &value, + "Expected integer for field default value.")); + // And stringify it again. + default_value->append(StrCat(value)); + break; + } + + case FieldDescriptorProto::TYPE_UINT32: + case FieldDescriptorProto::TYPE_UINT64: + case FieldDescriptorProto::TYPE_FIXED32: + case FieldDescriptorProto::TYPE_FIXED64: { + uint64_t max_value = std::numeric_limits<uint64_t>::max(); + if (field->type() == FieldDescriptorProto::TYPE_UINT32 || + field->type() == FieldDescriptorProto::TYPE_FIXED32) { + max_value = std::numeric_limits<uint32_t>::max(); + } + + // Numeric, not negative. + if (TryConsume("-")) { + AddError("Unsigned field can't have negative default value."); + } + // Parse the integer to verify that it is not out-of-range. + uint64_t value; + DO(ConsumeInteger64(max_value, &value, + "Expected integer for field default value.")); + // And stringify it again. + default_value->append(StrCat(value)); + break; + } + + case FieldDescriptorProto::TYPE_FLOAT: + case FieldDescriptorProto::TYPE_DOUBLE: + // These types can be negative. + if (TryConsume("-")) { + default_value->append("-"); + } + // Parse the integer because we have to convert hex integers to decimal + // floats. + double value; + DO(ConsumeNumber(&value, "Expected number.")); + // And stringify it again. + default_value->append(SimpleDtoa(value)); + break; + + case FieldDescriptorProto::TYPE_BOOL: + if (TryConsume("true")) { + default_value->assign("true"); + } else if (TryConsume("false")) { + default_value->assign("false"); + } else { + AddError("Expected \"true\" or \"false\"."); + return false; + } + break; + + case FieldDescriptorProto::TYPE_STRING: + // Note: When file option java_string_check_utf8 is true, if a + // non-string representation (eg byte[]) is later supported, it must + // be checked for UTF-8-ness. + DO(ConsumeString(default_value, + "Expected string for field default " + "value.")); + break; + + case FieldDescriptorProto::TYPE_BYTES: + DO(ConsumeString(default_value, "Expected string.")); + *default_value = CEscape(*default_value); + break; + + case FieldDescriptorProto::TYPE_ENUM: + DO(ConsumeIdentifier(default_value, + "Expected enum identifier for field " + "default value.")); + break; + + case FieldDescriptorProto::TYPE_MESSAGE: + case FieldDescriptorProto::TYPE_GROUP: + AddError("Messages can't have default values."); + return false; + } + + return true; +} + +bool Parser::ParseJsonName(FieldDescriptorProto* field, + const LocationRecorder& field_location, + const FileDescriptorProto* containing_file) { + if (field->has_json_name()) { + AddError("Already set option \"json_name\"."); + field->clear_json_name(); + } + + LocationRecorder location(field_location, + FieldDescriptorProto::kJsonNameFieldNumber); + location.RecordLegacyLocation(field, + DescriptorPool::ErrorCollector::OPTION_NAME); + + DO(Consume("json_name")); + DO(Consume("=")); + + LocationRecorder value_location(location); + value_location.RecordLegacyLocation( + field, DescriptorPool::ErrorCollector::OPTION_VALUE); + + DO(ConsumeString(field->mutable_json_name(), + "Expected string for JSON name.")); + return true; +} + +bool Parser::ParseOptionNamePart(UninterpretedOption* uninterpreted_option, + const LocationRecorder& part_location, + const FileDescriptorProto* containing_file) { + UninterpretedOption::NamePart* name = uninterpreted_option->add_name(); + std::string identifier; // We parse identifiers into this string. + if (LookingAt("(")) { // This is an extension. + DO(Consume("(")); + + { + LocationRecorder location( + part_location, UninterpretedOption::NamePart::kNamePartFieldNumber); + // An extension name consists of dot-separated identifiers, and may begin + // with a dot. + if (LookingAtType(io::Tokenizer::TYPE_IDENTIFIER)) { + DO(ConsumeIdentifier(&identifier, "Expected identifier.")); + name->mutable_name_part()->append(identifier); + } + while (LookingAt(".")) { + DO(Consume(".")); + name->mutable_name_part()->append("."); + DO(ConsumeIdentifier(&identifier, "Expected identifier.")); + name->mutable_name_part()->append(identifier); + } + } + + DO(Consume(")")); + name->set_is_extension(true); + } else { // This is a regular field. + LocationRecorder location( + part_location, UninterpretedOption::NamePart::kNamePartFieldNumber); + DO(ConsumeIdentifier(&identifier, "Expected identifier.")); + name->mutable_name_part()->append(identifier); + name->set_is_extension(false); + } + return true; +} + +bool Parser::ParseUninterpretedBlock(std::string* value) { + // Note that enclosing braces are not added to *value. + // We do NOT use ConsumeEndOfStatement for this brace because it's delimiting + // an expression, not a block of statements. + DO(Consume("{")); + int brace_depth = 1; + while (!AtEnd()) { + if (LookingAt("{")) { + brace_depth++; + } else if (LookingAt("}")) { + brace_depth--; + if (brace_depth == 0) { + input_->Next(); + return true; + } + } + // TODO(sanjay): Interpret line/column numbers to preserve formatting + if (!value->empty()) value->push_back(' '); + value->append(input_->current().text); + input_->Next(); + } + AddError("Unexpected end of stream while parsing aggregate value."); + return false; +} + +// We don't interpret the option here. Instead we store it in an +// UninterpretedOption, to be interpreted later. +bool Parser::ParseOption(Message* options, + const LocationRecorder& options_location, + const FileDescriptorProto* containing_file, + OptionStyle style) { + // Create an entry in the uninterpreted_option field. + const FieldDescriptor* uninterpreted_option_field = + options->GetDescriptor()->FindFieldByName("uninterpreted_option"); + GOOGLE_CHECK(uninterpreted_option_field != NULL) + << "No field named \"uninterpreted_option\" in the Options proto."; + + const Reflection* reflection = options->GetReflection(); + + LocationRecorder location( + options_location, uninterpreted_option_field->number(), + reflection->FieldSize(*options, uninterpreted_option_field)); + + if (style == OPTION_STATEMENT) { + DO(Consume("option")); + } + + UninterpretedOption* uninterpreted_option = + down_cast<UninterpretedOption*>(options->GetReflection()->AddMessage( + options, uninterpreted_option_field)); + + // Parse dot-separated name. + { + LocationRecorder name_location(location, + UninterpretedOption::kNameFieldNumber); + name_location.RecordLegacyLocation( + uninterpreted_option, DescriptorPool::ErrorCollector::OPTION_NAME); + + { + LocationRecorder part_location(name_location, + uninterpreted_option->name_size()); + DO(ParseOptionNamePart(uninterpreted_option, part_location, + containing_file)); + } + + while (LookingAt(".")) { + DO(Consume(".")); + LocationRecorder part_location(name_location, + uninterpreted_option->name_size()); + DO(ParseOptionNamePart(uninterpreted_option, part_location, + containing_file)); + } + } + + DO(Consume("=")); + + { + LocationRecorder value_location(location); + value_location.RecordLegacyLocation( + uninterpreted_option, DescriptorPool::ErrorCollector::OPTION_VALUE); + + // All values are a single token, except for negative numbers, which consist + // of a single '-' symbol, followed by a positive number. + bool is_negative = TryConsume("-"); + + switch (input_->current().type) { + case io::Tokenizer::TYPE_START: + GOOGLE_LOG(FATAL) << "Trying to read value before any tokens have been read."; + return false; + + case io::Tokenizer::TYPE_END: + AddError("Unexpected end of stream while parsing option value."); + return false; + + case io::Tokenizer::TYPE_WHITESPACE: + case io::Tokenizer::TYPE_NEWLINE: + GOOGLE_CHECK(!input_->report_whitespace() && !input_->report_newlines()) + << "Whitespace tokens were not requested."; + GOOGLE_LOG(FATAL) << "Tokenizer reported whitespace."; + return false; + + case io::Tokenizer::TYPE_IDENTIFIER: { + value_location.AddPath( + UninterpretedOption::kIdentifierValueFieldNumber); + if (is_negative) { + AddError("Invalid '-' symbol before identifier."); + return false; + } + std::string value; + DO(ConsumeIdentifier(&value, "Expected identifier.")); + uninterpreted_option->set_identifier_value(value); + break; + } + + case io::Tokenizer::TYPE_INTEGER: { + uint64_t value; + uint64_t max_value = + is_negative + ? static_cast<uint64_t>(std::numeric_limits<int64_t>::max()) + 1 + : std::numeric_limits<uint64_t>::max(); + DO(ConsumeInteger64(max_value, &value, "Expected integer.")); + if (is_negative) { + value_location.AddPath( + UninterpretedOption::kNegativeIntValueFieldNumber); + uninterpreted_option->set_negative_int_value( + static_cast<int64_t>(0 - value)); + } else { + value_location.AddPath( + UninterpretedOption::kPositiveIntValueFieldNumber); + uninterpreted_option->set_positive_int_value(value); + } + break; + } + + case io::Tokenizer::TYPE_FLOAT: { + value_location.AddPath(UninterpretedOption::kDoubleValueFieldNumber); + double value; + DO(ConsumeNumber(&value, "Expected number.")); + uninterpreted_option->set_double_value(is_negative ? -value : value); + break; + } + + case io::Tokenizer::TYPE_STRING: { + value_location.AddPath(UninterpretedOption::kStringValueFieldNumber); + if (is_negative) { + AddError("Invalid '-' symbol before string."); + return false; + } + std::string value; + DO(ConsumeString(&value, "Expected string.")); + uninterpreted_option->set_string_value(value); + break; + } + + case io::Tokenizer::TYPE_SYMBOL: + if (LookingAt("{")) { + value_location.AddPath( + UninterpretedOption::kAggregateValueFieldNumber); + DO(ParseUninterpretedBlock( + uninterpreted_option->mutable_aggregate_value())); + } else { + AddError("Expected option value."); + return false; + } + break; + } + } + + if (style == OPTION_STATEMENT) { + DO(ConsumeEndOfDeclaration(";", &location)); + } + + return true; +} + +bool Parser::ParseExtensions(DescriptorProto* message, + const LocationRecorder& extensions_location, + const FileDescriptorProto* containing_file) { + // Parse the declaration. + DO(Consume("extensions")); + + int old_range_size = message->extension_range_size(); + + do { + // Note that kExtensionRangeFieldNumber was already pushed by the parent. + LocationRecorder location(extensions_location, + message->extension_range_size()); + + DescriptorProto::ExtensionRange* range = message->add_extension_range(); + location.RecordLegacyLocation(range, + DescriptorPool::ErrorCollector::NUMBER); + + int start, end; + io::Tokenizer::Token start_token; + + { + LocationRecorder start_location( + location, DescriptorProto::ExtensionRange::kStartFieldNumber); + start_token = input_->current(); + DO(ConsumeInteger(&start, "Expected field number range.")); + } + + if (TryConsume("to")) { + LocationRecorder end_location( + location, DescriptorProto::ExtensionRange::kEndFieldNumber); + if (TryConsume("max")) { + // Set to the sentinel value - 1 since we increment the value below. + // The actual value of the end of the range should be set with + // AdjustExtensionRangesWithMaxEndNumber. + end = kMaxRangeSentinel - 1; + } else { + DO(ConsumeInteger(&end, "Expected integer.")); + } + } else { + LocationRecorder end_location( + location, DescriptorProto::ExtensionRange::kEndFieldNumber); + end_location.StartAt(start_token); + end_location.EndAt(start_token); + end = start; + } + + // Users like to specify inclusive ranges, but in code we like the end + // number to be exclusive. + ++end; + + range->set_start(start); + range->set_end(end); + } while (TryConsume(",")); + + if (LookingAt("[")) { + int range_number_index = extensions_location.CurrentPathSize(); + SourceCodeInfo info; + + // Parse extension range options in the first range. + ExtensionRangeOptions* options = + message->mutable_extension_range(old_range_size)->mutable_options(); + + { + LocationRecorder index_location( + extensions_location, 0 /* we fill this in w/ actual index below */, + &info); + LocationRecorder location( + index_location, DescriptorProto::ExtensionRange::kOptionsFieldNumber); + DO(Consume("[")); + + do { + DO(ParseOption(options, location, containing_file, OPTION_ASSIGNMENT)); + } while (TryConsume(",")); + + DO(Consume("]")); + } + + // Then copy the extension range options to all of the other ranges we've + // parsed. + for (int i = old_range_size + 1; i < message->extension_range_size(); i++) { + message->mutable_extension_range(i)->mutable_options()->CopyFrom( + *options); + } + // and copy source locations to the other ranges, too + for (int i = old_range_size; i < message->extension_range_size(); i++) { + for (int j = 0; j < info.location_size(); j++) { + if (info.location(j).path_size() == range_number_index + 1) { + // this location's path is up to the extension range index, but + // doesn't include options; so it's redundant with location above + continue; + } + SourceCodeInfo_Location* dest = source_code_info_->add_location(); + *dest = info.location(j); + dest->set_path(range_number_index, i); + } + } + } + + DO(ConsumeEndOfDeclaration(";", &extensions_location)); + return true; +} + +// This is similar to extension range parsing, except that it accepts field +// name literals. +bool Parser::ParseReserved(DescriptorProto* message, + const LocationRecorder& message_location) { + io::Tokenizer::Token start_token = input_->current(); + // Parse the declaration. + DO(Consume("reserved")); + if (LookingAtType(io::Tokenizer::TYPE_STRING)) { + LocationRecorder location(message_location, + DescriptorProto::kReservedNameFieldNumber); + location.StartAt(start_token); + return ParseReservedNames(message, location); + } else { + LocationRecorder location(message_location, + DescriptorProto::kReservedRangeFieldNumber); + location.StartAt(start_token); + return ParseReservedNumbers(message, location); + } +} + +bool Parser::ParseReservedNames(DescriptorProto* message, + const LocationRecorder& parent_location) { + do { + LocationRecorder location(parent_location, message->reserved_name_size()); + DO(ConsumeString(message->add_reserved_name(), "Expected field name.")); + } while (TryConsume(",")); + DO(ConsumeEndOfDeclaration(";", &parent_location)); + return true; +} + +bool Parser::ParseReservedNumbers(DescriptorProto* message, + const LocationRecorder& parent_location) { + bool first = true; + do { + LocationRecorder location(parent_location, message->reserved_range_size()); + + DescriptorProto::ReservedRange* range = message->add_reserved_range(); + int start, end; + io::Tokenizer::Token start_token; + { + LocationRecorder start_location( + location, DescriptorProto::ReservedRange::kStartFieldNumber); + start_token = input_->current(); + DO(ConsumeInteger(&start, (first ? "Expected field name or number range." + : "Expected field number range."))); + } + + if (TryConsume("to")) { + LocationRecorder end_location( + location, DescriptorProto::ReservedRange::kEndFieldNumber); + if (TryConsume("max")) { + // Set to the sentinel value - 1 since we increment the value below. + // The actual value of the end of the range should be set with + // AdjustExtensionRangesWithMaxEndNumber. + end = kMaxRangeSentinel - 1; + } else { + DO(ConsumeInteger(&end, "Expected integer.")); + } + } else { + LocationRecorder end_location( + location, DescriptorProto::ReservedRange::kEndFieldNumber); + end_location.StartAt(start_token); + end_location.EndAt(start_token); + end = start; + } + + // Users like to specify inclusive ranges, but in code we like the end + // number to be exclusive. + ++end; + + range->set_start(start); + range->set_end(end); + first = false; + } while (TryConsume(",")); + + DO(ConsumeEndOfDeclaration(";", &parent_location)); + return true; +} + +bool Parser::ParseReserved(EnumDescriptorProto* message, + const LocationRecorder& message_location) { + io::Tokenizer::Token start_token = input_->current(); + // Parse the declaration. + DO(Consume("reserved")); + if (LookingAtType(io::Tokenizer::TYPE_STRING)) { + LocationRecorder location(message_location, + EnumDescriptorProto::kReservedNameFieldNumber); + location.StartAt(start_token); + return ParseReservedNames(message, location); + } else { + LocationRecorder location(message_location, + EnumDescriptorProto::kReservedRangeFieldNumber); + location.StartAt(start_token); + return ParseReservedNumbers(message, location); + } +} + +bool Parser::ParseReservedNames(EnumDescriptorProto* message, + const LocationRecorder& parent_location) { + do { + LocationRecorder location(parent_location, message->reserved_name_size()); + DO(ConsumeString(message->add_reserved_name(), "Expected enum value.")); + } while (TryConsume(",")); + DO(ConsumeEndOfDeclaration(";", &parent_location)); + return true; +} + +bool Parser::ParseReservedNumbers(EnumDescriptorProto* message, + const LocationRecorder& parent_location) { + bool first = true; + do { + LocationRecorder location(parent_location, message->reserved_range_size()); + + EnumDescriptorProto::EnumReservedRange* range = + message->add_reserved_range(); + int start, end; + io::Tokenizer::Token start_token; + { + LocationRecorder start_location( + location, EnumDescriptorProto::EnumReservedRange::kStartFieldNumber); + start_token = input_->current(); + DO(ConsumeSignedInteger(&start, + (first ? "Expected enum value or number range." + : "Expected enum number range."))); + } + + if (TryConsume("to")) { + LocationRecorder end_location( + location, EnumDescriptorProto::EnumReservedRange::kEndFieldNumber); + if (TryConsume("max")) { + // This is in the enum descriptor path, which doesn't have the message + // set duality to fix up, so it doesn't integrate with the sentinel. + end = INT_MAX; + } else { + DO(ConsumeSignedInteger(&end, "Expected integer.")); + } + } else { + LocationRecorder end_location( + location, EnumDescriptorProto::EnumReservedRange::kEndFieldNumber); + end_location.StartAt(start_token); + end_location.EndAt(start_token); + end = start; + } + + range->set_start(start); + range->set_end(end); + first = false; + } while (TryConsume(",")); + + DO(ConsumeEndOfDeclaration(";", &parent_location)); + return true; +} + +bool Parser::ParseExtend(RepeatedPtrField<FieldDescriptorProto>* extensions, + RepeatedPtrField<DescriptorProto>* messages, + const LocationRecorder& parent_location, + int location_field_number_for_nested_type, + const LocationRecorder& extend_location, + const FileDescriptorProto* containing_file) { + DO(Consume("extend")); + + // Parse the extendee type. + io::Tokenizer::Token extendee_start = input_->current(); + std::string extendee; + DO(ParseUserDefinedType(&extendee)); + io::Tokenizer::Token extendee_end = input_->previous(); + + // Parse the block. + DO(ConsumeEndOfDeclaration("{", &extend_location)); + + bool is_first = true; + + do { + if (AtEnd()) { + AddError("Reached end of input in extend definition (missing '}')."); + return false; + } + + // Note that kExtensionFieldNumber was already pushed by the parent. + LocationRecorder location(extend_location, extensions->size()); + + FieldDescriptorProto* field = extensions->Add(); + + { + LocationRecorder extendee_location( + location, FieldDescriptorProto::kExtendeeFieldNumber); + extendee_location.StartAt(extendee_start); + extendee_location.EndAt(extendee_end); + + if (is_first) { + extendee_location.RecordLegacyLocation( + field, DescriptorPool::ErrorCollector::EXTENDEE); + is_first = false; + } + } + + field->set_extendee(extendee); + + if (!ParseMessageField(field, messages, parent_location, + location_field_number_for_nested_type, location, + containing_file)) { + // This statement failed to parse. Skip it, but keep looping to parse + // other statements. + SkipStatement(); + } + } while (!TryConsumeEndOfDeclaration("}", NULL)); + + return true; +} + +bool Parser::ParseOneof(OneofDescriptorProto* oneof_decl, + DescriptorProto* containing_type, int oneof_index, + const LocationRecorder& oneof_location, + const LocationRecorder& containing_type_location, + const FileDescriptorProto* containing_file) { + DO(Consume("oneof")); + + { + LocationRecorder name_location(oneof_location, + OneofDescriptorProto::kNameFieldNumber); + DO(ConsumeIdentifier(oneof_decl->mutable_name(), "Expected oneof name.")); + } + + DO(ConsumeEndOfDeclaration("{", &oneof_location)); + + do { + if (AtEnd()) { + AddError("Reached end of input in oneof definition (missing '}')."); + return false; + } + + if (LookingAt("option")) { + LocationRecorder option_location( + oneof_location, OneofDescriptorProto::kOptionsFieldNumber); + if (!ParseOption(oneof_decl->mutable_options(), option_location, + containing_file, OPTION_STATEMENT)) { + return false; + } + continue; + } + + // Print a nice error if the user accidentally tries to place a label + // on an individual member of a oneof. + if (LookingAt("required") || LookingAt("optional") || + LookingAt("repeated")) { + AddError( + "Fields in oneofs must not have labels (required / optional " + "/ repeated)."); + // We can continue parsing here because we understand what the user + // meant. The error report will still make parsing fail overall. + input_->Next(); + } + + LocationRecorder field_location(containing_type_location, + DescriptorProto::kFieldFieldNumber, + containing_type->field_size()); + + FieldDescriptorProto* field = containing_type->add_field(); + field->set_label(FieldDescriptorProto::LABEL_OPTIONAL); + field->set_oneof_index(oneof_index); + + if (!ParseMessageFieldNoLabel(field, containing_type->mutable_nested_type(), + containing_type_location, + DescriptorProto::kNestedTypeFieldNumber, + field_location, containing_file)) { + // This statement failed to parse. Skip it, but keep looping to parse + // other statements. + SkipStatement(); + } + } while (!TryConsumeEndOfDeclaration("}", NULL)); + + return true; +} + +// ------------------------------------------------------------------- +// Enums + +bool Parser::ParseEnumDefinition(EnumDescriptorProto* enum_type, + const LocationRecorder& enum_location, + const FileDescriptorProto* containing_file) { + DO(Consume("enum")); + + { + LocationRecorder location(enum_location, + EnumDescriptorProto::kNameFieldNumber); + location.RecordLegacyLocation(enum_type, + DescriptorPool::ErrorCollector::NAME); + DO(ConsumeIdentifier(enum_type->mutable_name(), "Expected enum name.")); + } + + DO(ParseEnumBlock(enum_type, enum_location, containing_file)); + + DO(ValidateEnum(enum_type)); + + return true; +} + +bool Parser::ParseEnumBlock(EnumDescriptorProto* enum_type, + const LocationRecorder& enum_location, + const FileDescriptorProto* containing_file) { + DO(ConsumeEndOfDeclaration("{", &enum_location)); + + while (!TryConsumeEndOfDeclaration("}", NULL)) { + if (AtEnd()) { + AddError("Reached end of input in enum definition (missing '}')."); + return false; + } + + if (!ParseEnumStatement(enum_type, enum_location, containing_file)) { + // This statement failed to parse. Skip it, but keep looping to parse + // other statements. + SkipStatement(); + } + } + + return true; +} + +bool Parser::ParseEnumStatement(EnumDescriptorProto* enum_type, + const LocationRecorder& enum_location, + const FileDescriptorProto* containing_file) { + if (TryConsumeEndOfDeclaration(";", NULL)) { + // empty statement; ignore + return true; + } else if (LookingAt("option")) { + LocationRecorder location(enum_location, + EnumDescriptorProto::kOptionsFieldNumber); + return ParseOption(enum_type->mutable_options(), location, containing_file, + OPTION_STATEMENT); + } else if (LookingAt("reserved")) { + return ParseReserved(enum_type, enum_location); + } else { + LocationRecorder location(enum_location, + EnumDescriptorProto::kValueFieldNumber, + enum_type->value_size()); + return ParseEnumConstant(enum_type->add_value(), location, containing_file); + } +} + +bool Parser::ParseEnumConstant(EnumValueDescriptorProto* enum_value, + const LocationRecorder& enum_value_location, + const FileDescriptorProto* containing_file) { + // Parse name. + { + LocationRecorder location(enum_value_location, + EnumValueDescriptorProto::kNameFieldNumber); + location.RecordLegacyLocation(enum_value, + DescriptorPool::ErrorCollector::NAME); + DO(ConsumeIdentifier(enum_value->mutable_name(), + "Expected enum constant name.")); + } + + DO(Consume("=", "Missing numeric value for enum constant.")); + + // Parse value. + { + LocationRecorder location(enum_value_location, + EnumValueDescriptorProto::kNumberFieldNumber); + location.RecordLegacyLocation(enum_value, + DescriptorPool::ErrorCollector::NUMBER); + + int number; + DO(ConsumeSignedInteger(&number, "Expected integer.")); + enum_value->set_number(number); + } + + DO(ParseEnumConstantOptions(enum_value, enum_value_location, + containing_file)); + + DO(ConsumeEndOfDeclaration(";", &enum_value_location)); + + return true; +} + +bool Parser::ParseEnumConstantOptions( + EnumValueDescriptorProto* value, + const LocationRecorder& enum_value_location, + const FileDescriptorProto* containing_file) { + if (!LookingAt("[")) return true; + + LocationRecorder location(enum_value_location, + EnumValueDescriptorProto::kOptionsFieldNumber); + + DO(Consume("[")); + + do { + DO(ParseOption(value->mutable_options(), location, containing_file, + OPTION_ASSIGNMENT)); + } while (TryConsume(",")); + + DO(Consume("]")); + return true; +} + +// ------------------------------------------------------------------- +// Services + +bool Parser::ParseServiceDefinition( + ServiceDescriptorProto* service, const LocationRecorder& service_location, + const FileDescriptorProto* containing_file) { + DO(Consume("service")); + + { + LocationRecorder location(service_location, + ServiceDescriptorProto::kNameFieldNumber); + location.RecordLegacyLocation(service, + DescriptorPool::ErrorCollector::NAME); + DO(ConsumeIdentifier(service->mutable_name(), "Expected service name.")); + } + + DO(ParseServiceBlock(service, service_location, containing_file)); + return true; +} + +bool Parser::ParseServiceBlock(ServiceDescriptorProto* service, + const LocationRecorder& service_location, + const FileDescriptorProto* containing_file) { + DO(ConsumeEndOfDeclaration("{", &service_location)); + + while (!TryConsumeEndOfDeclaration("}", NULL)) { + if (AtEnd()) { + AddError("Reached end of input in service definition (missing '}')."); + return false; + } + + if (!ParseServiceStatement(service, service_location, containing_file)) { + // This statement failed to parse. Skip it, but keep looping to parse + // other statements. + SkipStatement(); + } + } + + return true; +} + +bool Parser::ParseServiceStatement(ServiceDescriptorProto* service, + const LocationRecorder& service_location, + const FileDescriptorProto* containing_file) { + if (TryConsumeEndOfDeclaration(";", NULL)) { + // empty statement; ignore + return true; + } else if (LookingAt("option")) { + LocationRecorder location(service_location, + ServiceDescriptorProto::kOptionsFieldNumber); + return ParseOption(service->mutable_options(), location, containing_file, + OPTION_STATEMENT); + } else { + LocationRecorder location(service_location, + ServiceDescriptorProto::kMethodFieldNumber, + service->method_size()); + return ParseServiceMethod(service->add_method(), location, containing_file); + } +} + +bool Parser::ParseServiceMethod(MethodDescriptorProto* method, + const LocationRecorder& method_location, + const FileDescriptorProto* containing_file) { + DO(Consume("rpc")); + + { + LocationRecorder location(method_location, + MethodDescriptorProto::kNameFieldNumber); + location.RecordLegacyLocation(method, DescriptorPool::ErrorCollector::NAME); + DO(ConsumeIdentifier(method->mutable_name(), "Expected method name.")); + } + + // Parse input type. + DO(Consume("(")); + { + if (LookingAt("stream")) { + LocationRecorder location( + method_location, MethodDescriptorProto::kClientStreamingFieldNumber); + location.RecordLegacyLocation(method, + DescriptorPool::ErrorCollector::OTHER); + method->set_client_streaming(true); + DO(Consume("stream")); + + } + LocationRecorder location(method_location, + MethodDescriptorProto::kInputTypeFieldNumber); + location.RecordLegacyLocation(method, + DescriptorPool::ErrorCollector::INPUT_TYPE); + DO(ParseUserDefinedType(method->mutable_input_type())); + } + DO(Consume(")")); + + // Parse output type. + DO(Consume("returns")); + DO(Consume("(")); + { + if (LookingAt("stream")) { + LocationRecorder location( + method_location, MethodDescriptorProto::kServerStreamingFieldNumber); + location.RecordLegacyLocation(method, + DescriptorPool::ErrorCollector::OTHER); + DO(Consume("stream")); + method->set_server_streaming(true); + + } + LocationRecorder location(method_location, + MethodDescriptorProto::kOutputTypeFieldNumber); + location.RecordLegacyLocation(method, + DescriptorPool::ErrorCollector::OUTPUT_TYPE); + DO(ParseUserDefinedType(method->mutable_output_type())); + } + DO(Consume(")")); + + if (LookingAt("{")) { + // Options! + DO(ParseMethodOptions(method_location, containing_file, + MethodDescriptorProto::kOptionsFieldNumber, + method->mutable_options())); + } else { + DO(ConsumeEndOfDeclaration(";", &method_location)); + } + + return true; +} + +bool Parser::ParseMethodOptions(const LocationRecorder& parent_location, + const FileDescriptorProto* containing_file, + const int optionsFieldNumber, + Message* mutable_options) { + // Options! + ConsumeEndOfDeclaration("{", &parent_location); + while (!TryConsumeEndOfDeclaration("}", NULL)) { + if (AtEnd()) { + AddError("Reached end of input in method options (missing '}')."); + return false; + } + + if (TryConsumeEndOfDeclaration(";", NULL)) { + // empty statement; ignore + } else { + LocationRecorder location(parent_location, optionsFieldNumber); + if (!ParseOption(mutable_options, location, containing_file, + OPTION_STATEMENT)) { + // This statement failed to parse. Skip it, but keep looping to + // parse other statements. + SkipStatement(); + } + } + } + + return true; +} + +// ------------------------------------------------------------------- + +bool Parser::ParseLabel(FieldDescriptorProto::Label* label, + const LocationRecorder& field_location, + const FileDescriptorProto* containing_file) { + if (!LookingAt("optional") && !LookingAt("repeated") && + !LookingAt("required")) { + return false; + } + LocationRecorder location(field_location, + FieldDescriptorProto::kLabelFieldNumber); + if (TryConsume("optional")) { + *label = FieldDescriptorProto::LABEL_OPTIONAL; + } else if (TryConsume("repeated")) { + *label = FieldDescriptorProto::LABEL_REPEATED; + } else { + Consume("required"); + *label = FieldDescriptorProto::LABEL_REQUIRED; + } + return true; +} + +bool Parser::ParseType(FieldDescriptorProto::Type* type, + std::string* type_name) { + TypeNameMap::const_iterator iter = kTypeNames.find(input_->current().text); + if (iter != kTypeNames.end()) { + *type = iter->second; + input_->Next(); + } else { + DO(ParseUserDefinedType(type_name)); + } + return true; +} + +bool Parser::ParseUserDefinedType(std::string* type_name) { + type_name->clear(); + + TypeNameMap::const_iterator iter = kTypeNames.find(input_->current().text); + if (iter != kTypeNames.end()) { + // Note: The only place enum types are allowed is for field types, but + // if we are parsing a field type then we would not get here because + // primitives are allowed there as well. So this error message doesn't + // need to account for enums. + AddError("Expected message type."); + + // Pretend to accept this type so that we can go on parsing. + *type_name = input_->current().text; + input_->Next(); + return true; + } + + // A leading "." means the name is fully-qualified. + if (TryConsume(".")) type_name->append("."); + + // Consume the first part of the name. + std::string identifier; + DO(ConsumeIdentifier(&identifier, "Expected type name.")); + type_name->append(identifier); + + // Consume more parts. + while (TryConsume(".")) { + type_name->append("."); + DO(ConsumeIdentifier(&identifier, "Expected identifier.")); + type_name->append(identifier); + } + + return true; +} + +// =================================================================== + +bool Parser::ParsePackage(FileDescriptorProto* file, + const LocationRecorder& root_location, + const FileDescriptorProto* containing_file) { + if (file->has_package()) { + AddError("Multiple package definitions."); + // Don't append the new package to the old one. Just replace it. Not + // that it really matters since this is an error anyway. + file->clear_package(); + } + + LocationRecorder location(root_location, + FileDescriptorProto::kPackageFieldNumber); + location.RecordLegacyLocation(file, DescriptorPool::ErrorCollector::NAME); + + DO(Consume("package")); + + while (true) { + std::string identifier; + DO(ConsumeIdentifier(&identifier, "Expected identifier.")); + file->mutable_package()->append(identifier); + if (!TryConsume(".")) break; + file->mutable_package()->append("."); + } + + DO(ConsumeEndOfDeclaration(";", &location)); + + return true; +} + +bool Parser::ParseImport(RepeatedPtrField<std::string>* dependency, + RepeatedField<int32_t>* public_dependency, + RepeatedField<int32_t>* weak_dependency, + const LocationRecorder& root_location, + const FileDescriptorProto* containing_file) { + LocationRecorder location(root_location, + FileDescriptorProto::kDependencyFieldNumber, + dependency->size()); + + DO(Consume("import")); + + if (LookingAt("public")) { + LocationRecorder public_location( + root_location, FileDescriptorProto::kPublicDependencyFieldNumber, + public_dependency->size()); + DO(Consume("public")); + *public_dependency->Add() = dependency->size(); + } else if (LookingAt("weak")) { + LocationRecorder weak_location( + root_location, FileDescriptorProto::kWeakDependencyFieldNumber, + weak_dependency->size()); + weak_location.RecordLegacyImportLocation(containing_file, "weak"); + DO(Consume("weak")); + *weak_dependency->Add() = dependency->size(); + } + + std::string import_file; + DO(ConsumeString(&import_file, + "Expected a string naming the file to import.")); + *dependency->Add() = import_file; + location.RecordLegacyImportLocation(containing_file, import_file); + + DO(ConsumeEndOfDeclaration(";", &location)); + + return true; +} + +// =================================================================== + +SourceLocationTable::SourceLocationTable() {} +SourceLocationTable::~SourceLocationTable() {} + +bool SourceLocationTable::Find( + const Message* descriptor, + DescriptorPool::ErrorCollector::ErrorLocation location, int* line, + int* column) const { + const std::pair<int, int>* result = + FindOrNull(location_map_, std::make_pair(descriptor, location)); + if (result == NULL) { + *line = -1; + *column = 0; + return false; + } else { + *line = result->first; + *column = result->second; + return true; + } +} + +bool SourceLocationTable::FindImport(const Message* descriptor, + const std::string& name, int* line, + int* column) const { + const std::pair<int, int>* result = + FindOrNull(import_location_map_, std::make_pair(descriptor, name)); + if (result == nullptr) { + *line = -1; + *column = 0; + return false; + } else { + *line = result->first; + *column = result->second; + return true; + } +} + +void SourceLocationTable::Add( + const Message* descriptor, + DescriptorPool::ErrorCollector::ErrorLocation location, int line, + int column) { + location_map_[std::make_pair(descriptor, location)] = + std::make_pair(line, column); +} + +void SourceLocationTable::AddImport(const Message* descriptor, + const std::string& name, int line, + int column) { + import_location_map_[std::make_pair(descriptor, name)] = + std::make_pair(line, column); +} + +void SourceLocationTable::Clear() { location_map_.clear(); } + +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/parser.h b/NorthstarDedicatedTest/include/protobuf/compiler/parser.h new file mode 100644 index 00000000..37055bd3 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/parser.h @@ -0,0 +1,603 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// Implements parsing of .proto files to FileDescriptorProtos. + +#ifndef GOOGLE_PROTOBUF_COMPILER_PARSER_H__ +#define GOOGLE_PROTOBUF_COMPILER_PARSER_H__ + +#include <cstdint> +#include <map> +#include <string> +#include <utility> + +#include <descriptor.pb.h> +#include <io/tokenizer.h> +#include <descriptor.h> +#include <repeated_field.h> + +// Must be included last. +#include <port_def.inc> + +namespace google { +namespace protobuf { + +class Message; + +namespace compiler { + +// Defined in this file. +class Parser; +class SourceLocationTable; + +// Implements parsing of protocol definitions (such as .proto files). +// +// Note that most users will be more interested in the Importer class. +// Parser is a lower-level class which simply converts a single .proto file +// to a FileDescriptorProto. It does not resolve import directives or perform +// many other kinds of validation needed to construct a complete +// FileDescriptor. +class PROTOBUF_EXPORT Parser { + public: + Parser(); + ~Parser(); + + // Parse the entire input and construct a FileDescriptorProto representing + // it. Returns true if no errors occurred, false otherwise. + bool Parse(io::Tokenizer* input, FileDescriptorProto* file); + + // Optional features: + + // DEPRECATED: New code should use the SourceCodeInfo embedded in the + // FileDescriptorProto. + // + // Requests that locations of certain definitions be recorded to the given + // SourceLocationTable while parsing. This can be used to look up exact line + // and column numbers for errors reported by DescriptorPool during validation. + // Set to NULL (the default) to discard source location information. + void RecordSourceLocationsTo(SourceLocationTable* location_table) { + source_location_table_ = location_table; + } + + // Requests that errors be recorded to the given ErrorCollector while + // parsing. Set to NULL (the default) to discard error messages. + void RecordErrorsTo(io::ErrorCollector* error_collector) { + error_collector_ = error_collector; + } + + // Returns the identifier used in the "syntax = " declaration, if one was + // seen during the last call to Parse(), or the empty string otherwise. + const std::string& GetSyntaxIdentifier() { return syntax_identifier_; } + + // If set true, input files will be required to begin with a syntax + // identifier. Otherwise, files may omit this. If a syntax identifier + // is provided, it must be 'syntax = "proto2";' and must appear at the + // top of this file regardless of whether or not it was required. + void SetRequireSyntaxIdentifier(bool value) { + require_syntax_identifier_ = value; + } + + // Call SetStopAfterSyntaxIdentifier(true) to tell the parser to stop + // parsing as soon as it has seen the syntax identifier, or lack thereof. + // This is useful for quickly identifying the syntax of the file without + // parsing the whole thing. If this is enabled, no error will be recorded + // if the syntax identifier is something other than "proto2" (since + // presumably the caller intends to deal with that), but other kinds of + // errors (e.g. parse errors) will still be reported. When this is enabled, + // you may pass a NULL FileDescriptorProto to Parse(). + void SetStopAfterSyntaxIdentifier(bool value) { + stop_after_syntax_identifier_ = value; + } + + private: + class LocationRecorder; + + // ================================================================= + // Error recovery helpers + + // Consume the rest of the current statement. This consumes tokens + // until it sees one of: + // ';' Consumes the token and returns. + // '{' Consumes the brace then calls SkipRestOfBlock(). + // '}' Returns without consuming. + // EOF Returns (can't consume). + // The Parser often calls SkipStatement() after encountering a syntax + // error. This allows it to go on parsing the following lines, allowing + // it to report more than just one error in the file. + void SkipStatement(); + + // Consume the rest of the current block, including nested blocks, + // ending after the closing '}' is encountered and consumed, or at EOF. + void SkipRestOfBlock(); + + // ----------------------------------------------------------------- + // Single-token consuming helpers + // + // These make parsing code more readable. + + // True if the current token is TYPE_END. + inline bool AtEnd(); + + // True if the next token matches the given text. + inline bool LookingAt(const char* text); + // True if the next token is of the given type. + inline bool LookingAtType(io::Tokenizer::TokenType token_type); + + // If the next token exactly matches the text given, consume it and return + // true. Otherwise, return false without logging an error. + bool TryConsume(const char* text); + + // These attempt to read some kind of token from the input. If successful, + // they return true. Otherwise they return false and add the given error + // to the error list. + + // Consume a token with the exact text given. + bool Consume(const char* text, const char* error); + // Same as above, but automatically generates the error "Expected \"text\".", + // where "text" is the expected token text. + bool Consume(const char* text); + // Consume a token of type IDENTIFIER and store its text in "output". + bool ConsumeIdentifier(std::string* output, const char* error); + // Consume an integer and store its value in "output". + bool ConsumeInteger(int* output, const char* error); + // Consume a signed integer and store its value in "output". + bool ConsumeSignedInteger(int* output, const char* error); + // Consume a 64-bit integer and store its value in "output". If the value + // is greater than max_value, an error will be reported. + bool ConsumeInteger64(uint64_t max_value, uint64_t* output, + const char* error); + // Consume a number and store its value in "output". This will accept + // tokens of either INTEGER or FLOAT type. + bool ConsumeNumber(double* output, const char* error); + // Consume a string literal and store its (unescaped) value in "output". + bool ConsumeString(std::string* output, const char* error); + + // Consume a token representing the end of the statement. Comments between + // this token and the next will be harvested for documentation. The given + // LocationRecorder should refer to the declaration that was just parsed; + // it will be populated with these comments. + // + // TODO(kenton): The LocationRecorder is const because historically locations + // have been passed around by const reference, for no particularly good + // reason. We should probably go through and change them all to mutable + // pointer to make this more intuitive. + bool TryConsumeEndOfDeclaration(const char* text, + const LocationRecorder* location); + bool TryConsumeEndOfDeclarationFinishScope(const char* text, + const LocationRecorder* location); + + bool ConsumeEndOfDeclaration(const char* text, + const LocationRecorder* location); + + // ----------------------------------------------------------------- + // Error logging helpers + + // Invokes error_collector_->AddError(), if error_collector_ is not NULL. + void AddError(int line, int column, const std::string& error); + + // Invokes error_collector_->AddError() with the line and column number + // of the current token. + void AddError(const std::string& error); + + // Invokes error_collector_->AddWarning() with the line and column number + // of the current token. + void AddWarning(const std::string& warning); + + // Records a location in the SourceCodeInfo.location table (see + // descriptor.proto). We use RAII to ensure that the start and end locations + // are recorded -- the constructor records the start location and the + // destructor records the end location. Since the parser is + // recursive-descent, this works out beautifully. + class PROTOBUF_EXPORT LocationRecorder { + public: + // Construct the file's "root" location. + LocationRecorder(Parser* parser); + + // Construct a location that represents a declaration nested within the + // given parent. E.g. a field's location is nested within the location + // for a message type. The parent's path will be copied, so you should + // call AddPath() only to add the path components leading from the parent + // to the child (as opposed to leading from the root to the child). + LocationRecorder(const LocationRecorder& parent); + + // Convenience constructors that call AddPath() one or two times. + LocationRecorder(const LocationRecorder& parent, int path1); + LocationRecorder(const LocationRecorder& parent, int path1, int path2); + + // Creates a recorder that generates locations into given source code info. + LocationRecorder(const LocationRecorder& parent, int path1, + SourceCodeInfo* source_code_info); + + ~LocationRecorder(); + + // Add a path component. See SourceCodeInfo.Location.path in + // descriptor.proto. + void AddPath(int path_component); + + // By default the location is considered to start at the current token at + // the time the LocationRecorder is created. StartAt() sets the start + // location to the given token instead. + void StartAt(const io::Tokenizer::Token& token); + + // Start at the same location as some other LocationRecorder. + void StartAt(const LocationRecorder& other); + + // By default the location is considered to end at the previous token at + // the time the LocationRecorder is destroyed. EndAt() sets the end + // location to the given token instead. + void EndAt(const io::Tokenizer::Token& token); + + // Records the start point of this location to the SourceLocationTable that + // was passed to RecordSourceLocationsTo(), if any. SourceLocationTable + // is an older way of keeping track of source locations which is still + // used in some places. + void RecordLegacyLocation( + const Message* descriptor, + DescriptorPool::ErrorCollector::ErrorLocation location); + void RecordLegacyImportLocation(const Message* descriptor, + const std::string& name); + + // Returns the number of path components in the recorder's current location. + int CurrentPathSize() const; + + // Attaches leading and trailing comments to the location. The two strings + // will be swapped into place, so after this is called *leading and + // *trailing will be empty. + // + // TODO(kenton): See comment on TryConsumeEndOfDeclaration(), above, for + // why this is const. + void AttachComments(std::string* leading, std::string* trailing, + std::vector<std::string>* detached_comments) const; + + private: + // Indexes of parent and current location in the parent + // SourceCodeInfo.location repeated field. For top-level elements, + // parent_index_ is -1. + Parser* parser_; + SourceCodeInfo* source_code_info_; + SourceCodeInfo::Location* location_; + + void Init(const LocationRecorder& parent, SourceCodeInfo* source_code_info); + }; + + // ================================================================= + // Parsers for various language constructs + + // Parses the "syntax = \"proto2\";" line at the top of the file. Returns + // false if it failed to parse or if the syntax identifier was not + // recognized. + bool ParseSyntaxIdentifier(const LocationRecorder& parent); + + // These methods parse various individual bits of code. They return + // false if they completely fail to parse the construct. In this case, + // it is probably necessary to skip the rest of the statement to recover. + // However, if these methods return true, it does NOT mean that there + // were no errors; only that there were no *syntax* errors. For instance, + // if a service method is defined using proper syntax but uses a primitive + // type as its input or output, ParseMethodField() still returns true + // and only reports the error by calling AddError(). In practice, this + // makes logic much simpler for the caller. + + // Parse a top-level message, enum, service, etc. + bool ParseTopLevelStatement(FileDescriptorProto* file, + const LocationRecorder& root_location); + + // Parse various language high-level language construrcts. + bool ParseMessageDefinition(DescriptorProto* message, + const LocationRecorder& message_location, + const FileDescriptorProto* containing_file); + bool ParseEnumDefinition(EnumDescriptorProto* enum_type, + const LocationRecorder& enum_location, + const FileDescriptorProto* containing_file); + bool ParseServiceDefinition(ServiceDescriptorProto* service, + const LocationRecorder& service_location, + const FileDescriptorProto* containing_file); + bool ParsePackage(FileDescriptorProto* file, + const LocationRecorder& root_location, + const FileDescriptorProto* containing_file); + bool ParseImport(RepeatedPtrField<std::string>* dependency, + RepeatedField<int32_t>* public_dependency, + RepeatedField<int32_t>* weak_dependency, + const LocationRecorder& root_location, + const FileDescriptorProto* containing_file); + + // These methods parse the contents of a message, enum, or service type and + // add them to the given object. They consume the entire block including + // the beginning and ending brace. + bool ParseMessageBlock(DescriptorProto* message, + const LocationRecorder& message_location, + const FileDescriptorProto* containing_file); + bool ParseEnumBlock(EnumDescriptorProto* enum_type, + const LocationRecorder& enum_location, + const FileDescriptorProto* containing_file); + bool ParseServiceBlock(ServiceDescriptorProto* service, + const LocationRecorder& service_location, + const FileDescriptorProto* containing_file); + + // Parse one statement within a message, enum, or service block, including + // final semicolon. + bool ParseMessageStatement(DescriptorProto* message, + const LocationRecorder& message_location, + const FileDescriptorProto* containing_file); + bool ParseEnumStatement(EnumDescriptorProto* message, + const LocationRecorder& enum_location, + const FileDescriptorProto* containing_file); + bool ParseServiceStatement(ServiceDescriptorProto* message, + const LocationRecorder& service_location, + const FileDescriptorProto* containing_file); + + // Parse a field of a message. If the field is a group, its type will be + // added to "messages". + // + // parent_location and location_field_number_for_nested_type are needed when + // parsing groups -- we need to generate a nested message type within the + // parent and record its location accordingly. Since the parent could be + // either a FileDescriptorProto or a DescriptorProto, we must pass in the + // correct field number to use. + bool ParseMessageField(FieldDescriptorProto* field, + RepeatedPtrField<DescriptorProto>* messages, + const LocationRecorder& parent_location, + int location_field_number_for_nested_type, + const LocationRecorder& field_location, + const FileDescriptorProto* containing_file); + + // Like ParseMessageField() but expects the label has already been filled in + // by the caller. + bool ParseMessageFieldNoLabel(FieldDescriptorProto* field, + RepeatedPtrField<DescriptorProto>* messages, + const LocationRecorder& parent_location, + int location_field_number_for_nested_type, + const LocationRecorder& field_location, + const FileDescriptorProto* containing_file); + + // Parse an "extensions" declaration. + bool ParseExtensions(DescriptorProto* message, + const LocationRecorder& extensions_location, + const FileDescriptorProto* containing_file); + + // Parse a "reserved" declaration. + bool ParseReserved(DescriptorProto* message, + const LocationRecorder& message_location); + bool ParseReservedNames(DescriptorProto* message, + const LocationRecorder& parent_location); + bool ParseReservedNumbers(DescriptorProto* message, + const LocationRecorder& parent_location); + bool ParseReserved(EnumDescriptorProto* message, + const LocationRecorder& message_location); + bool ParseReservedNames(EnumDescriptorProto* message, + const LocationRecorder& parent_location); + bool ParseReservedNumbers(EnumDescriptorProto* message, + const LocationRecorder& parent_location); + + // Parse an "extend" declaration. (See also comments for + // ParseMessageField().) + bool ParseExtend(RepeatedPtrField<FieldDescriptorProto>* extensions, + RepeatedPtrField<DescriptorProto>* messages, + const LocationRecorder& parent_location, + int location_field_number_for_nested_type, + const LocationRecorder& extend_location, + const FileDescriptorProto* containing_file); + + // Parse a "oneof" declaration. The caller is responsible for setting + // oneof_decl->label() since it will have had to parse the label before it + // knew it was parsing a oneof. + bool ParseOneof(OneofDescriptorProto* oneof_decl, + DescriptorProto* containing_type, int oneof_index, + const LocationRecorder& oneof_location, + const LocationRecorder& containing_type_location, + const FileDescriptorProto* containing_file); + + // Parse a single enum value within an enum block. + bool ParseEnumConstant(EnumValueDescriptorProto* enum_value, + const LocationRecorder& enum_value_location, + const FileDescriptorProto* containing_file); + + // Parse enum constant options, i.e. the list in square brackets at the end + // of the enum constant value definition. + bool ParseEnumConstantOptions(EnumValueDescriptorProto* value, + const LocationRecorder& enum_value_location, + const FileDescriptorProto* containing_file); + + // Parse a single method within a service definition. + bool ParseServiceMethod(MethodDescriptorProto* method, + const LocationRecorder& method_location, + const FileDescriptorProto* containing_file); + + + // Parse options of a single method or stream. + bool ParseMethodOptions(const LocationRecorder& parent_location, + const FileDescriptorProto* containing_file, + const int optionsFieldNumber, + Message* mutable_options); + + // Parse "required", "optional", or "repeated" and fill in "label" + // with the value. Returns true if such a label is consumed. + bool ParseLabel(FieldDescriptorProto::Label* label, + const LocationRecorder& field_location, + const FileDescriptorProto* containing_file); + + // Parse a type name and fill in "type" (if it is a primitive) or + // "type_name" (if it is not) with the type parsed. + bool ParseType(FieldDescriptorProto::Type* type, std::string* type_name); + // Parse a user-defined type and fill in "type_name" with the name. + // If a primitive type is named, it is treated as an error. + bool ParseUserDefinedType(std::string* type_name); + + // Parses field options, i.e. the stuff in square brackets at the end + // of a field definition. Also parses default value. + bool ParseFieldOptions(FieldDescriptorProto* field, + const LocationRecorder& field_location, + const FileDescriptorProto* containing_file); + + // Parse the "default" option. This needs special handling because its + // type is the field's type. + bool ParseDefaultAssignment(FieldDescriptorProto* field, + const LocationRecorder& field_location, + const FileDescriptorProto* containing_file); + + bool ParseJsonName(FieldDescriptorProto* field, + const LocationRecorder& field_location, + const FileDescriptorProto* containing_file); + + enum OptionStyle { + OPTION_ASSIGNMENT, // just "name = value" + OPTION_STATEMENT // "option name = value;" + }; + + // Parse a single option name/value pair, e.g. "ctype = CORD". The name + // identifies a field of the given Message, and the value of that field + // is set to the parsed value. + bool ParseOption(Message* options, const LocationRecorder& options_location, + const FileDescriptorProto* containing_file, + OptionStyle style); + + // Parses a single part of a multipart option name. A multipart name consists + // of names separated by dots. Each name is either an identifier or a series + // of identifiers separated by dots and enclosed in parentheses. E.g., + // "foo.(bar.baz).qux". + bool ParseOptionNamePart(UninterpretedOption* uninterpreted_option, + const LocationRecorder& part_location, + const FileDescriptorProto* containing_file); + + // Parses a string surrounded by balanced braces. Strips off the outer + // braces and stores the enclosed string in *value. + // E.g., + // { foo } *value gets 'foo' + // { foo { bar: box } } *value gets 'foo { bar: box }' + // {} *value gets '' + // + // REQUIRES: LookingAt("{") + // When finished successfully, we are looking at the first token past + // the ending brace. + bool ParseUninterpretedBlock(std::string* value); + + struct MapField { + // Whether the field is a map field. + bool is_map_field; + // The types of the key and value if they are primitive types. + FieldDescriptorProto::Type key_type; + FieldDescriptorProto::Type value_type; + // Or the type names string if the types are customized types. + std::string key_type_name; + std::string value_type_name; + + MapField() : is_map_field(false) {} + }; + // Desugar the map syntax to generate a nested map entry message. + void GenerateMapEntry(const MapField& map_field, FieldDescriptorProto* field, + RepeatedPtrField<DescriptorProto>* messages); + + // Whether fields without label default to optional fields. + bool DefaultToOptionalFields() const { + return syntax_identifier_ == "proto3"; + } + + bool ValidateEnum(const EnumDescriptorProto* proto); + + // ================================================================= + + io::Tokenizer* input_; + io::ErrorCollector* error_collector_; + SourceCodeInfo* source_code_info_; + SourceLocationTable* source_location_table_; // legacy + bool had_errors_; + bool require_syntax_identifier_; + bool stop_after_syntax_identifier_; + std::string syntax_identifier_; + + // Leading doc comments for the next declaration. These are not complete + // yet; use ConsumeEndOfDeclaration() to get the complete comments. + std::string upcoming_doc_comments_; + + // Detached comments are not connected to any syntax entities. Elements in + // this vector are paragraphs of comments separated by empty lines. The + // detached comments will be put into the leading_detached_comments field for + // the next element (See SourceCodeInfo.Location in descriptor.proto), when + // ConsumeEndOfDeclaration() is called. + std::vector<std::string> upcoming_detached_comments_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Parser); +}; + +// A table mapping (descriptor, ErrorLocation) pairs -- as reported by +// DescriptorPool when validating descriptors -- to line and column numbers +// within the original source code. +// +// This is semi-obsolete: FileDescriptorProto.source_code_info now contains +// far more complete information about source locations. However, as of this +// writing you still need to use SourceLocationTable when integrating with +// DescriptorPool. +class PROTOBUF_EXPORT SourceLocationTable { + public: + SourceLocationTable(); + ~SourceLocationTable(); + + // Finds the precise location of the given error and fills in *line and + // *column with the line and column numbers. If not found, sets *line to + // -1 and *column to 0 (since line = -1 is used to mean "error has no exact + // location" in the ErrorCollector interface). Returns true if found, false + // otherwise. + bool Find(const Message* descriptor, + DescriptorPool::ErrorCollector::ErrorLocation location, int* line, + int* column) const; + bool FindImport(const Message* descriptor, const std::string& name, int* line, + int* column) const; + + // Adds a location to the table. + void Add(const Message* descriptor, + DescriptorPool::ErrorCollector::ErrorLocation location, int line, + int column); + void AddImport(const Message* descriptor, const std::string& name, int line, + int column); + + // Clears the contents of the table. + void Clear(); + + private: + typedef std::map< + std::pair<const Message*, DescriptorPool::ErrorCollector::ErrorLocation>, + std::pair<int, int> > + LocationMap; + LocationMap location_map_; + std::map<std::pair<const Message*, std::string>, std::pair<int, int> > + import_location_map_; +}; + +} // namespace compiler +} // namespace protobuf +} // namespace google + +#include <port_undef.inc> + +#endif // GOOGLE_PROTOBUF_COMPILER_PARSER_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/parser_unittest.cc b/NorthstarDedicatedTest/include/protobuf/compiler/parser_unittest.cc new file mode 100644 index 00000000..0b175117 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/parser_unittest.cc @@ -0,0 +1,3681 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <compiler/parser.h> + +#include <algorithm> +#include <map> +#include <memory> +#include <vector> + +#include <test_util2.h> +#include <unittest.pb.h> +#include <any.pb.h> +#include <unittest_custom_options.pb.h> +#include <io/tokenizer.h> +#include <io/zero_copy_stream_impl.h> +#include <descriptor.pb.h> +#include <text_format.h> +#include <wire_format.h> +#include <testing/googletest.h> +#include <gtest/gtest.h> +#include <stubs/substitute.h> +#include <stubs/map_util.h> + +namespace google { +namespace protobuf { +namespace compiler { + +namespace { + +class MockErrorCollector : public io::ErrorCollector { + public: + MockErrorCollector() = default; + ~MockErrorCollector() override = default; + + std::string warning_; + std::string text_; + + // implements ErrorCollector --------------------------------------- + void AddWarning(int line, int column, const std::string& message) override { + strings::SubstituteAndAppend(&warning_, "$0:$1: $2\n", line, column, message); + } + + void AddError(int line, int column, const std::string& message) override { + strings::SubstituteAndAppend(&text_, "$0:$1: $2\n", line, column, message); + } +}; + +class MockValidationErrorCollector : public DescriptorPool::ErrorCollector { + public: + MockValidationErrorCollector(const SourceLocationTable& source_locations, + io::ErrorCollector* wrapped_collector) + : source_locations_(source_locations), + wrapped_collector_(wrapped_collector) {} + ~MockValidationErrorCollector() {} + + // implements ErrorCollector --------------------------------------- + void AddError(const std::string& filename, const std::string& element_name, + const Message* descriptor, ErrorLocation location, + const std::string& message) override { + int line, column; + if (location == DescriptorPool::ErrorCollector::IMPORT) { + source_locations_.FindImport(descriptor, element_name, &line, &column); + } else { + source_locations_.Find(descriptor, location, &line, &column); + } + wrapped_collector_->AddError(line, column, message); + } + + private: + const SourceLocationTable& source_locations_; + io::ErrorCollector* wrapped_collector_; +}; + +class ParserTest : public testing::Test { + protected: + ParserTest() : require_syntax_identifier_(false) {} + + // Set up the parser to parse the given text. + void SetupParser(const char* text) { + raw_input_.reset(new io::ArrayInputStream(text, strlen(text))); + input_.reset(new io::Tokenizer(raw_input_.get(), &error_collector_)); + parser_.reset(new Parser()); + parser_->RecordErrorsTo(&error_collector_); + parser_->SetRequireSyntaxIdentifier(require_syntax_identifier_); + } + + // Parse the input and expect that the resulting FileDescriptorProto matches + // the given output. The output is a FileDescriptorProto in protocol buffer + // text format. + void ExpectParsesTo(const char* input, const char* output) { + SetupParser(input); + FileDescriptorProto actual, expected; + + parser_->Parse(input_.get(), &actual); + EXPECT_EQ(io::Tokenizer::TYPE_END, input_->current().type); + ASSERT_EQ("", error_collector_.text_); + + // We don't cover SourceCodeInfo in these tests. + actual.clear_source_code_info(); + + // Parse the ASCII representation in order to canonicalize it. We could + // just compare directly to actual.DebugString(), but that would require + // that the caller precisely match the formatting that DebugString() + // produces. + ASSERT_TRUE(TextFormat::ParseFromString(output, &expected)); + + // Compare by comparing debug strings. + // TODO(kenton): Use differencer, once it is available. + EXPECT_EQ(expected.DebugString(), actual.DebugString()); + } + + // Parse the text and expect that the given errors are reported. + void ExpectHasErrors(const char* text, const char* expected_errors) { + ExpectHasEarlyExitErrors(text, expected_errors); + EXPECT_EQ(io::Tokenizer::TYPE_END, input_->current().type); + } + + // Same as above but does not expect that the parser parses the complete + // input. + void ExpectHasEarlyExitErrors(const char* text, const char* expected_errors) { + SetupParser(text); + FileDescriptorProto file; + parser_->Parse(input_.get(), &file); + EXPECT_EQ(expected_errors, error_collector_.text_); + } + + // Parse the text as a file and validate it (with a DescriptorPool), and + // expect that the validation step reports the given errors. + void ExpectHasValidationErrors(const char* text, + const char* expected_errors) { + SetupParser(text); + SourceLocationTable source_locations; + parser_->RecordSourceLocationsTo(&source_locations); + + FileDescriptorProto file; + file.set_name("foo.proto"); + parser_->Parse(input_.get(), &file); + EXPECT_EQ(io::Tokenizer::TYPE_END, input_->current().type); + ASSERT_EQ("", error_collector_.text_); + + MockValidationErrorCollector validation_error_collector(source_locations, + &error_collector_); + EXPECT_TRUE(pool_.BuildFileCollectingErrors( + file, &validation_error_collector) == NULL); + EXPECT_EQ(expected_errors, error_collector_.text_); + } + + MockErrorCollector error_collector_; + DescriptorPool pool_; + + std::unique_ptr<io::ZeroCopyInputStream> raw_input_; + std::unique_ptr<io::Tokenizer> input_; + std::unique_ptr<Parser> parser_; + bool require_syntax_identifier_; +}; + +// =================================================================== + +TEST_F(ParserTest, StopAfterSyntaxIdentifier) { + SetupParser( + "// blah\n" + "syntax = \"foobar\";\n" + "this line will not be parsed\n"); + parser_->SetStopAfterSyntaxIdentifier(true); + EXPECT_TRUE(parser_->Parse(input_.get(), NULL)); + EXPECT_EQ("", error_collector_.text_); + EXPECT_EQ("foobar", parser_->GetSyntaxIdentifier()); +} + +TEST_F(ParserTest, StopAfterOmittedSyntaxIdentifier) { + SetupParser( + "// blah\n" + "this line will not be parsed\n"); + parser_->SetStopAfterSyntaxIdentifier(true); + EXPECT_TRUE(parser_->Parse(input_.get(), NULL)); + EXPECT_EQ("", error_collector_.text_); + EXPECT_EQ("", parser_->GetSyntaxIdentifier()); +} + +TEST_F(ParserTest, StopAfterSyntaxIdentifierWithErrors) { + SetupParser( + "// blah\n" + "syntax = error;\n"); + parser_->SetStopAfterSyntaxIdentifier(true); + EXPECT_FALSE(parser_->Parse(input_.get(), NULL)); + EXPECT_EQ("1:9: Expected syntax identifier.\n", error_collector_.text_); +} + +TEST_F(ParserTest, WarnIfSyntaxIdentifierOmmitted) { + SetupParser("message A {}"); + FileDescriptorProto file; + CaptureTestStderr(); + EXPECT_TRUE(parser_->Parse(input_.get(), &file)); + EXPECT_TRUE(GetCapturedTestStderr().find("No syntax specified") != + std::string::npos); +} + +TEST_F(ParserTest, WarnIfFieldNameIsNotUpperCamel) { + SetupParser( + "syntax = \"proto2\";" + "message abc {}"); + FileDescriptorProto file; + EXPECT_TRUE(parser_->Parse(input_.get(), &file)); + EXPECT_TRUE(error_collector_.warning_.find( + "Message name should be in UpperCamelCase. Found: abc.") != + std::string::npos); +} + +TEST_F(ParserTest, WarnIfFieldNameIsNotLowerUnderscore) { + SetupParser( + "syntax = \"proto2\";" + "message A {" + " optional string SongName = 1;" + "}"); + FileDescriptorProto file; + EXPECT_TRUE(parser_->Parse(input_.get(), &file)); + EXPECT_TRUE(error_collector_.warning_.find( + "Field name should be lowercase. Found: SongName") != + std::string::npos); +} + +TEST_F(ParserTest, WarnIfFieldNameContainsNumberImmediatelyFollowUnderscore) { + SetupParser( + "syntax = \"proto2\";" + "message A {" + " optional string song_name_1 = 1;" + "}"); + FileDescriptorProto file; + EXPECT_TRUE(parser_->Parse(input_.get(), &file)); + EXPECT_TRUE(error_collector_.warning_.find( + "Number should not come right after an underscore. Found: " + "song_name_1.") != std::string::npos); +} + +// =================================================================== + +typedef ParserTest ParseMessageTest; + +TEST_F(ParseMessageTest, IgnoreBOM) { + char input[] = + " message TestMessage {\n" + " required int32 foo = 1;\n" + "}\n"; + // Set UTF-8 BOM. + input[0] = (char)0xEF; + input[1] = (char)0xBB; + input[2] = (char)0xBF; + ExpectParsesTo( + input, + "message_type {" + " name: \"TestMessage\"" + " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:1 }" + "}"); +} + +TEST_F(ParseMessageTest, BOMError) { + char input[] = + " message TestMessage {\n" + " required int32 foo = 1;\n" + "}\n"; + input[0] = (char)0xEF; + ExpectHasErrors(input, + "0:1: Proto file starts with 0xEF but not UTF-8 BOM. " + "Only UTF-8 is accepted for proto file.\n" + "0:0: Expected top-level statement (e.g. \"message\").\n"); +} + +TEST_F(ParseMessageTest, SimpleMessage) { + ExpectParsesTo( + "message TestMessage {\n" + " required int32 foo = 1;\n" + "}\n", + + "message_type {" + " name: \"TestMessage\"" + " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:1 }" + "}"); +} + +TEST_F(ParseMessageTest, ImplicitSyntaxIdentifier) { + require_syntax_identifier_ = false; + ExpectParsesTo( + "message TestMessage {\n" + " required int32 foo = 1;\n" + "}\n", + + "message_type {" + " name: \"TestMessage\"" + " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:1 }" + "}"); + EXPECT_EQ("proto2", parser_->GetSyntaxIdentifier()); +} + +TEST_F(ParseMessageTest, ExplicitSyntaxIdentifier) { + ExpectParsesTo( + "syntax = \"proto2\";\n" + "message TestMessage {\n" + " required int32 foo = 1;\n" + "}\n", + + "syntax: 'proto2' " + "message_type {" + " name: \"TestMessage\"" + " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:1 }" + "}"); + EXPECT_EQ("proto2", parser_->GetSyntaxIdentifier()); +} + +TEST_F(ParseMessageTest, ExplicitRequiredSyntaxIdentifier) { + require_syntax_identifier_ = true; + ExpectParsesTo( + "syntax = \"proto2\";\n" + "message TestMessage {\n" + " required int32 foo = 1;\n" + "}\n", + + "syntax: 'proto2' " + "message_type {" + " name: \"TestMessage\"" + " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:1 }" + "}"); + EXPECT_EQ("proto2", parser_->GetSyntaxIdentifier()); +} + +TEST_F(ParseMessageTest, SimpleFields) { + ExpectParsesTo( + "message TestMessage {\n" + " required int32 foo = 15;\n" + " optional int32 bar = 34;\n" + " repeated int32 baz = 3;\n" + "}\n", + + "message_type {" + " name: \"TestMessage\"" + " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:15 }" + " field { name:\"bar\" label:LABEL_OPTIONAL type:TYPE_INT32 number:34 }" + " field { name:\"baz\" label:LABEL_REPEATED type:TYPE_INT32 number:3 }" + "}"); +} + +TEST_F(ParseMessageTest, PrimitiveFieldTypes) { + ExpectParsesTo( + "message TestMessage {\n" + " required int32 foo = 1;\n" + " required int64 foo = 1;\n" + " required uint32 foo = 1;\n" + " required uint64 foo = 1;\n" + " required sint32 foo = 1;\n" + " required sint64 foo = 1;\n" + " required fixed32 foo = 1;\n" + " required fixed64 foo = 1;\n" + " required sfixed32 foo = 1;\n" + " required sfixed64 foo = 1;\n" + " required float foo = 1;\n" + " required double foo = 1;\n" + " required string foo = 1;\n" + " required bytes foo = 1;\n" + " required bool foo = 1;\n" + "}\n", + + "message_type {" + " name: \"TestMessage\"" + " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:1 " + "}" + " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT64 number:1 " + "}" + " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_UINT32 number:1 " + "}" + " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_UINT64 number:1 " + "}" + " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_SINT32 number:1 " + "}" + " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_SINT64 number:1 " + "}" + " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_FIXED32 number:1 " + "}" + " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_FIXED64 number:1 " + "}" + " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_SFIXED32 number:1 " + "}" + " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_SFIXED64 number:1 " + "}" + " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_FLOAT number:1 " + "}" + " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_DOUBLE number:1 " + "}" + " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_STRING number:1 " + "}" + " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_BYTES number:1 " + "}" + " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_BOOL number:1 " + "}" + "}"); +} + +TEST_F(ParseMessageTest, FieldDefaults) { + ExpectParsesTo( + "message TestMessage {\n" + " required int32 foo = 1 [default= 1 ];\n" + " required int32 foo = 1 [default= -2 ];\n" + " required int64 foo = 1 [default= 3 ];\n" + " required int64 foo = 1 [default= -4 ];\n" + " required uint32 foo = 1 [default= 5 ];\n" + " required uint64 foo = 1 [default= 6 ];\n" + " required float foo = 1 [default= 7.5];\n" + " required float foo = 1 [default= -8.5];\n" + " required float foo = 1 [default= 9 ];\n" + " required double foo = 1 [default= 10.5];\n" + " required double foo = 1 [default=-11.5];\n" + " required double foo = 1 [default= 12 ];\n" + " required double foo = 1 [default= inf ];\n" + " required double foo = 1 [default=-inf ];\n" + " required double foo = 1 [default= nan ];\n" + " required string foo = 1 [default='13\\001'];\n" + " required string foo = 1 [default='a' \"b\" \n \"c\"];\n" + " required bytes foo = 1 [default='14\\002'];\n" + " required bytes foo = 1 [default='a' \"b\" \n 'c'];\n" + " required bool foo = 1 [default=true ];\n" + " required Foo foo = 1 [default=FOO ];\n" + + " required int32 foo = 1 [default= 0x7FFFFFFF];\n" + " required int32 foo = 1 [default=-0x80000000];\n" + " required uint32 foo = 1 [default= 0xFFFFFFFF];\n" + " required int64 foo = 1 [default= 0x7FFFFFFFFFFFFFFF];\n" + " required int64 foo = 1 [default=-0x8000000000000000];\n" + " required uint64 foo = 1 [default= 0xFFFFFFFFFFFFFFFF];\n" + " required double foo = 1 [default= 0xabcd];\n" + "}\n", + +#define ETC "name:\"foo\" label:LABEL_REQUIRED number:1" + "message_type {" + " name: \"TestMessage\"" + " field { type:TYPE_INT32 default_value:\"1\" " ETC + " }" + " field { type:TYPE_INT32 default_value:\"-2\" " ETC + " }" + " field { type:TYPE_INT64 default_value:\"3\" " ETC + " }" + " field { type:TYPE_INT64 default_value:\"-4\" " ETC + " }" + " field { type:TYPE_UINT32 default_value:\"5\" " ETC + " }" + " field { type:TYPE_UINT64 default_value:\"6\" " ETC + " }" + " field { type:TYPE_FLOAT default_value:\"7.5\" " ETC + " }" + " field { type:TYPE_FLOAT default_value:\"-8.5\" " ETC + " }" + " field { type:TYPE_FLOAT default_value:\"9\" " ETC + " }" + " field { type:TYPE_DOUBLE default_value:\"10.5\" " ETC + " }" + " field { type:TYPE_DOUBLE default_value:\"-11.5\" " ETC + " }" + " field { type:TYPE_DOUBLE default_value:\"12\" " ETC + " }" + " field { type:TYPE_DOUBLE default_value:\"inf\" " ETC + " }" + " field { type:TYPE_DOUBLE default_value:\"-inf\" " ETC + " }" + " field { type:TYPE_DOUBLE default_value:\"nan\" " ETC + " }" + " field { type:TYPE_STRING default_value:\"13\\001\" " ETC + " }" + " field { type:TYPE_STRING default_value:\"abc\" " ETC + " }" + " field { type:TYPE_BYTES default_value:\"14\\\\002\" " ETC + " }" + " field { type:TYPE_BYTES default_value:\"abc\" " ETC + " }" + " field { type:TYPE_BOOL default_value:\"true\" " ETC + " }" + " field { type_name:\"Foo\" default_value:\"FOO\" " ETC + " }" + + " field {" + " type:TYPE_INT32 default_value:\"2147483647\" " ETC + " }" + " field {" + " type:TYPE_INT32 default_value:\"-2147483648\" " ETC + " }" + " field {" + " type:TYPE_UINT32 default_value:\"4294967295\" " ETC + " }" + " field {" + " type:TYPE_INT64 default_value:\"9223372036854775807\" " ETC + " }" + " field {" + " type:TYPE_INT64 default_value:\"-9223372036854775808\" " ETC + " }" + " field {" + " type:TYPE_UINT64 default_value:\"18446744073709551615\" " ETC + " }" + " field {" + " type:TYPE_DOUBLE default_value:\"43981\" " ETC + " }" + "}"); +#undef ETC +} + +TEST_F(ParseMessageTest, FieldJsonName) { + ExpectParsesTo( + "message TestMessage {\n" + " optional string foo = 1 [json_name = \"@type\"];\n" + "}\n", + "message_type {" + " name: \"TestMessage\"" + " field {\n" + " name: \"foo\" label: LABEL_OPTIONAL type: TYPE_STRING number: 1" + " json_name: \"@type\"\n" + " }\n" + "}\n"); +} + +TEST_F(ParseMessageTest, FieldOptions) { + ExpectParsesTo( + "message TestMessage {\n" + " optional string foo = 1\n" + " [ctype=CORD, (foo)=7, foo.(.bar.baz).qux.quux.(corge)=-33, \n" + " (quux)=\"x\040y\", (baz.qux)=hey];\n" + "}\n", + + "message_type {" + " name: \"TestMessage\"" + " field { name: \"foo\" label: LABEL_OPTIONAL type: TYPE_STRING number: " + "1" + " options { uninterpreted_option: { name { name_part: \"ctype\" " + " is_extension: false " + "} " + " identifier_value: \"CORD\" " + "}" + " uninterpreted_option: { name { name_part: \"foo\" " + " is_extension: true } " + " positive_int_value: 7 }" + " uninterpreted_option: { name { name_part: \"foo\" " + " is_extension: false " + "} " + " name { name_part: " + "\".bar.baz\"" + " is_extension: true } " + " name { name_part: \"qux\" " + " is_extension: false " + "} " + " name { name_part: \"quux\" " + " is_extension: false " + "} " + " name { name_part: \"corge\" " + " is_extension: true } " + " negative_int_value: -33 }" + " uninterpreted_option: { name { name_part: \"quux\" " + " is_extension: true } " + " string_value: \"x y\" }" + " uninterpreted_option: { name { name_part: " + "\"baz.qux\" " + " is_extension: true } " + " identifier_value: \"hey\" }" + " }" + " }" + "}"); +} + +TEST_F(ParseMessageTest, Oneof) { + ExpectParsesTo( + "message TestMessage {\n" + " oneof foo {\n" + " int32 a = 1;\n" + " string b = 2;\n" + " TestMessage c = 3;\n" + " group D = 4 { optional int32 i = 5; }\n" + " }\n" + "}\n", + + "message_type {" + " name: \"TestMessage\"" + " field { name:\"a\" label:LABEL_OPTIONAL type:TYPE_INT32 number:1 " + " oneof_index:0 }" + " field { name:\"b\" label:LABEL_OPTIONAL type:TYPE_STRING number:2 " + " oneof_index:0 }" + " field { name:\"c\" label:LABEL_OPTIONAL type_name:\"TestMessage\" " + " number:3 oneof_index:0 }" + " field { name:\"d\" label:LABEL_OPTIONAL type:TYPE_GROUP " + " type_name:\"D\" number:4 oneof_index:0 }" + " oneof_decl {" + " name: \"foo\"" + " }" + " nested_type {" + " name: \"D\"" + " field { name:\"i\" label:LABEL_OPTIONAL type:TYPE_INT32 number:5 }" + " }" + "}"); +} + +TEST_F(ParseMessageTest, MultipleOneofs) { + ExpectParsesTo( + "message TestMessage {\n" + " oneof foo {\n" + " int32 a = 1;\n" + " string b = 2;\n" + " }\n" + " oneof bar {\n" + " int32 c = 3;\n" + " string d = 4;\n" + " }\n" + "}\n", + + "message_type {" + " name: \"TestMessage\"" + " field { name:\"a\" label:LABEL_OPTIONAL type:TYPE_INT32 number:1 " + " oneof_index:0 }" + " field { name:\"b\" label:LABEL_OPTIONAL type:TYPE_STRING number:2 " + " oneof_index:0 }" + " field { name:\"c\" label:LABEL_OPTIONAL type:TYPE_INT32 number:3 " + " oneof_index:1 }" + " field { name:\"d\" label:LABEL_OPTIONAL type:TYPE_STRING number:4 " + " oneof_index:1 }" + " oneof_decl {" + " name: \"foo\"" + " }" + " oneof_decl {" + " name: \"bar\"" + " }" + "}"); +} + +TEST_F(ParseMessageTest, Maps) { + ExpectParsesTo( + "message TestMessage {\n" + " map<int32, string> primitive_type_map = 1;\n" + " map<KeyType, ValueType> composite_type_map = 2;\n" + "}\n", + + "message_type {" + " name: \"TestMessage\"" + " nested_type {" + " name: \"PrimitiveTypeMapEntry\"" + " field { " + " name: \"key\" number: 1 label:LABEL_OPTIONAL" + " type:TYPE_INT32" + " }" + " field { " + " name: \"value\" number: 2 label:LABEL_OPTIONAL" + " type:TYPE_STRING" + " }" + " options { map_entry: true }" + " }" + " nested_type {" + " name: \"CompositeTypeMapEntry\"" + " field { " + " name: \"key\" number: 1 label:LABEL_OPTIONAL" + " type_name: \"KeyType\"" + " }" + " field { " + " name: \"value\" number: 2 label:LABEL_OPTIONAL" + " type_name: \"ValueType\"" + " }" + " options { map_entry: true }" + " }" + " field {" + " name: \"primitive_type_map\"" + " label: LABEL_REPEATED" + " type_name: \"PrimitiveTypeMapEntry\"" + " number: 1" + " }" + " field {" + " name: \"composite_type_map\"" + " label: LABEL_REPEATED" + " type_name: \"CompositeTypeMapEntry\"" + " number: 2" + " }" + "}"); +} + +TEST_F(ParseMessageTest, Group) { + ExpectParsesTo( + "message TestMessage {\n" + " optional group TestGroup = 1 {};\n" + "}\n", + + "message_type {" + " name: \"TestMessage\"" + " nested_type { name: \"TestGroup\" }" + " field { name:\"testgroup\" label:LABEL_OPTIONAL number:1" + " type:TYPE_GROUP type_name: \"TestGroup\" }" + "}"); +} + +TEST_F(ParseMessageTest, NestedMessage) { + ExpectParsesTo( + "message TestMessage {\n" + " message Nested {}\n" + " optional Nested test_nested = 1;\n" + "}\n", + + "message_type {" + " name: \"TestMessage\"" + " nested_type { name: \"Nested\" }" + " field { name:\"test_nested\" label:LABEL_OPTIONAL number:1" + " type_name: \"Nested\" }" + "}"); +} + +TEST_F(ParseMessageTest, NestedEnum) { + ExpectParsesTo( + "message TestMessage {\n" + " enum NestedEnum {}\n" + " optional NestedEnum test_enum = 1;\n" + "}\n", + + "message_type {" + " name: \"TestMessage\"" + " enum_type { name: \"NestedEnum\" }" + " field { name:\"test_enum\" label:LABEL_OPTIONAL number:1" + " type_name: \"NestedEnum\" }" + "}"); +} + +TEST_F(ParseMessageTest, ReservedRange) { + ExpectParsesTo( + "message TestMessage {\n" + " required int32 foo = 1;\n" + " reserved 2, 15, 9 to 11, 3, 20 to max;\n" + "}\n", + + "message_type {" + " name: \"TestMessage\"" + " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:1 }" + " reserved_range { start:2 end:3 }" + " reserved_range { start:15 end:16 }" + " reserved_range { start:9 end:12 }" + " reserved_range { start:3 end:4 }" + " reserved_range { start:20 end:536870912 }" + "}"); +} + +TEST_F(ParseMessageTest, ReservedRangeOnMessageSet) { + ExpectParsesTo( + "message TestMessage {\n" + " option message_set_wire_format = true;\n" + " reserved 20 to max;\n" + "}\n", + + "message_type {" + " name: \"TestMessage\"" + " options {" + " uninterpreted_option {" + " name {" + " name_part: \"message_set_wire_format\"" + " is_extension: false" + " }" + " identifier_value: \"true\"" + " }" + " }" + " reserved_range { start:20 end:2147483647 }" + "}"); +} + +TEST_F(ParseMessageTest, ReservedNames) { + ExpectParsesTo( + "message TestMessage {\n" + " reserved \"foo\", \"bar\";\n" + "}\n", + + "message_type {" + " name: \"TestMessage\"" + " reserved_name: \"foo\"" + " reserved_name: \"bar\"" + "}"); +} + +TEST_F(ParseMessageTest, ExtensionRange) { + ExpectParsesTo( + "message TestMessage {\n" + " extensions 10 to 19;\n" + " extensions 30 to max;\n" + "}\n", + + "message_type {" + " name: \"TestMessage\"" + " extension_range { start:10 end:20 }" + " extension_range { start:30 end:536870912 }" + "}"); +} + +TEST_F(ParseMessageTest, ExtensionRangeWithOptions) { + ExpectParsesTo( + "message TestMessage {\n" + " extensions 10 to 19 [(i) = 5];\n" + "}\n", + + "message_type {" + " name: \"TestMessage\"" + " extension_range {" + " start:10" + " end:20" + " options {" + " uninterpreted_option {" + " name {" + " name_part: \"i\"" + " is_extension: true" + " }" + " positive_int_value: 5" + " }" + " }" + " }" + "}"); +} + +TEST_F(ParseMessageTest, CompoundExtensionRange) { + ExpectParsesTo( + "message TestMessage {\n" + " extensions 2, 15, 9 to 11, 100 to max, 3;\n" + "}\n", + + "message_type {" + " name: \"TestMessage\"" + " extension_range { start:2 end:3 }" + " extension_range { start:15 end:16 }" + " extension_range { start:9 end:12 }" + " extension_range { start:100 end:536870912 }" + " extension_range { start:3 end:4 }" + "}"); +} + +TEST_F(ParseMessageTest, CompoundExtensionRangeWithOptions) { + ExpectParsesTo( + "message TestMessage {\n" + " extensions 2, 15, 9 to 11, 100 to max, 3 [(i) = 5];\n" + "}\n", + + "message_type {" + " name: \"TestMessage\"" + " extension_range {" + " start:2" + " end:3" + " options {" + " uninterpreted_option {" + " name {" + " name_part: \"i\"" + " is_extension: true" + " }" + " positive_int_value: 5" + " }" + " }" + " }" + " extension_range {" + " start:15" + " end:16" + " options {" + " uninterpreted_option {" + " name {" + " name_part: \"i\"" + " is_extension: true" + " }" + " positive_int_value: 5" + " }" + " }" + " }" + " extension_range {" + " start:9" + " end:12" + " options {" + " uninterpreted_option {" + " name {" + " name_part: \"i\"" + " is_extension: true" + " }" + " positive_int_value: 5" + " }" + " }" + " }" + " extension_range {" + " start:100" + " end:536870912" + " options {" + " uninterpreted_option {" + " name {" + " name_part: \"i\"" + " is_extension: true" + " }" + " positive_int_value: 5" + " }" + " }" + " }" + " extension_range {" + " start:3" + " end:4" + " options {" + " uninterpreted_option {" + " name {" + " name_part: \"i\"" + " is_extension: true" + " }" + " positive_int_value: 5" + " }" + " }" + " }" + "}"); +} + +TEST_F(ParseMessageTest, LargerMaxForMessageSetWireFormatMessages) { + // Messages using the message_set_wire_format option can accept larger + // extension numbers, as the numbers are not encoded as int32 field values + // rather than tags. + ExpectParsesTo( + "message TestMessage {\n" + " extensions 4 to max;\n" + " option message_set_wire_format = true;\n" + "}\n", + + "message_type {" + " name: \"TestMessage\"" + " extension_range { start:4 end: 0x7fffffff }" + " options {\n" + " uninterpreted_option { \n" + " name {\n" + " name_part: \"message_set_wire_format\"\n" + " is_extension: false\n" + " }\n" + " identifier_value: \"true\"\n" + " }\n" + " }\n" + "}"); +} + +TEST_F(ParseMessageTest, Extensions) { + ExpectParsesTo( + "extend Extendee1 { optional int32 foo = 12; }\n" + "extend Extendee2 { repeated TestMessage bar = 22; }\n", + + "extension { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:12" + " extendee: \"Extendee1\" } " + "extension { name:\"bar\" label:LABEL_REPEATED number:22" + " type_name:\"TestMessage\" extendee: \"Extendee2\" }"); +} + +TEST_F(ParseMessageTest, ExtensionsInMessageScope) { + ExpectParsesTo( + "message TestMessage {\n" + " extend Extendee1 { optional int32 foo = 12; }\n" + " extend Extendee2 { repeated TestMessage bar = 22; }\n" + "}\n", + + "message_type {" + " name: \"TestMessage\"" + " extension { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 " + "number:12" + " extendee: \"Extendee1\" }" + " extension { name:\"bar\" label:LABEL_REPEATED number:22" + " type_name:\"TestMessage\" extendee: \"Extendee2\" }" + "}"); +} + +TEST_F(ParseMessageTest, MultipleExtensionsOneExtendee) { + ExpectParsesTo( + "extend Extendee1 {\n" + " optional int32 foo = 12;\n" + " repeated TestMessage bar = 22;\n" + "}\n", + + "extension { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:12" + " extendee: \"Extendee1\" } " + "extension { name:\"bar\" label:LABEL_REPEATED number:22" + " type_name:\"TestMessage\" extendee: \"Extendee1\" }"); +} + +TEST_F(ParseMessageTest, OptionalLabelProto3) { + ExpectParsesTo( + "syntax = \"proto3\";\n" + "message TestMessage {\n" + " int32 foo = 1;\n" + "}\n", + + "syntax: \"proto3\" " + "message_type {" + " name: \"TestMessage\"" + " field { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:1 } " + "}"); +} + +TEST_F(ParseMessageTest, ExplicitOptionalLabelProto3) { + ExpectParsesTo( + "syntax = 'proto3';\n" + "message TestMessage {\n" + " optional int32 foo = 1;\n" + "}\n", + + "syntax: \"proto3\" " + "message_type {" + " name: \"TestMessage\"" + " field { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:1 " + " proto3_optional: true oneof_index: 0 } " + " oneof_decl { name:\"_foo\" } " + "}"); + + // Handle collisions in the synthetic oneof name. + ExpectParsesTo( + "syntax = 'proto3';\n" + "message TestMessage {\n" + " optional int32 foo = 1;\n" + " oneof _foo {\n" + " int32 __foo = 2;\n" + " }\n" + "}\n", + + "syntax: \"proto3\" " + "message_type {" + " name: \"TestMessage\"" + " field { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:1 " + " proto3_optional: true oneof_index: 1 } " + " field { name:\"__foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:2 " + " oneof_index: 0 } " + " oneof_decl { name:\"_foo\" } " + " oneof_decl { name:\"X_foo\" } " + "}"); +} + +// =================================================================== + +typedef ParserTest ParseEnumTest; + +TEST_F(ParseEnumTest, SimpleEnum) { + ExpectParsesTo( + "enum TestEnum {\n" + " FOO = 0;\n" + "}\n", + + "enum_type {" + " name: \"TestEnum\"" + " value { name:\"FOO\" number:0 }" + "}"); +} + +TEST_F(ParseEnumTest, Values) { + ExpectParsesTo( + "enum TestEnum {\n" + " FOO = 13;\n" + " BAR = -10;\n" + " BAZ = 500;\n" + " HEX_MAX = 0x7FFFFFFF;\n" + " HEX_MIN = -0x80000000;\n" + " INT_MAX = 2147483647;\n" + " INT_MIN = -2147483648;\n" + "}\n", + + "enum_type {" + " name: \"TestEnum\"" + " value { name:\"FOO\" number:13 }" + " value { name:\"BAR\" number:-10 }" + " value { name:\"BAZ\" number:500 }" + " value { name:\"HEX_MAX\" number:2147483647 }" + " value { name:\"HEX_MIN\" number:-2147483648 }" + " value { name:\"INT_MAX\" number:2147483647 }" + " value { name:\"INT_MIN\" number:-2147483648 }" + "}"); +} + +TEST_F(ParseEnumTest, ValueOptions) { + ExpectParsesTo( + "enum TestEnum {\n" + " FOO = 13;\n" + " BAR = -10 [ (something.text) = 'abc' ];\n" + " BAZ = 500 [ (something.text) = 'def', other = 1 ];\n" + "}\n", + + "enum_type {" + " name: \"TestEnum\"" + " value { name: \"FOO\" number: 13 }" + " value { name: \"BAR\" number: -10 " + " options { " + " uninterpreted_option { " + " name { name_part: \"something.text\" is_extension: true } " + " string_value: \"abc\" " + " } " + " } " + " } " + " value { name: \"BAZ\" number: 500 " + " options { " + " uninterpreted_option { " + " name { name_part: \"something.text\" is_extension: true } " + " string_value: \"def\" " + " } " + " uninterpreted_option { " + " name { name_part: \"other\" is_extension: false } " + " positive_int_value: 1 " + " } " + " } " + " } " + "}"); +} + +TEST_F(ParseEnumTest, ReservedRange) { + ExpectParsesTo( + "enum TestEnum {\n" + " FOO = 0;\n" + " reserved -2147483648, -6 to -4, -1 to 1, 2, 15, 9 to 11, 3, 20 to " + "max;\n" + "}\n", + + "enum_type {" + " name: \"TestEnum\"" + " value { name:\"FOO\" number:0 }" + " reserved_range { start:-2147483648 end:-2147483648 }" + " reserved_range { start:-6 end:-4 }" + " reserved_range { start:-1 end:1 }" + " reserved_range { start:2 end:2 }" + " reserved_range { start:15 end:15 }" + " reserved_range { start:9 end:11 }" + " reserved_range { start:3 end:3 }" + " reserved_range { start:20 end:2147483647 }" + "}"); +} + +TEST_F(ParseEnumTest, ReservedNames) { + ExpectParsesTo( + "enum TestEnum {\n" + " FOO = 0;\n" + " reserved \"foo\", \"bar\";\n" + "}\n", + + "enum_type {" + " name: \"TestEnum\"" + " value { name:\"FOO\" number:0 }" + " reserved_name: \"foo\"" + " reserved_name: \"bar\"" + "}"); +} + +// =================================================================== + +typedef ParserTest ParseServiceTest; + +TEST_F(ParseServiceTest, SimpleService) { + ExpectParsesTo( + "service TestService {\n" + " rpc Foo(In) returns (Out);\n" + "}\n", + + "service {" + " name: \"TestService\"" + " method { name:\"Foo\" input_type:\"In\" output_type:\"Out\" }" + "}"); +} + +TEST_F(ParseServiceTest, MethodsAndStreams) { + ExpectParsesTo( + "service TestService {\n" + " rpc Foo(In1) returns (Out1);\n" + " rpc Bar(In2) returns (Out2);\n" + " rpc Baz(In3) returns (Out3);\n" + "}\n", + + "service {" + " name: \"TestService\"" + " method { name:\"Foo\" input_type:\"In1\" output_type:\"Out1\" }" + " method { name:\"Bar\" input_type:\"In2\" output_type:\"Out2\" }" + " method { name:\"Baz\" input_type:\"In3\" output_type:\"Out3\" }" + "}"); +} + + +// =================================================================== +// imports and packages + +typedef ParserTest ParseMiscTest; + +TEST_F(ParseMiscTest, ParseImport) { + ExpectParsesTo("import \"foo/bar/baz.proto\";\n", + "dependency: \"foo/bar/baz.proto\""); +} + +TEST_F(ParseMiscTest, ParseMultipleImports) { + ExpectParsesTo( + "import \"foo.proto\";\n" + "import \"bar.proto\";\n" + "import \"baz.proto\";\n", + "dependency: \"foo.proto\"" + "dependency: \"bar.proto\"" + "dependency: \"baz.proto\""); +} + +TEST_F(ParseMiscTest, ParsePublicImports) { + ExpectParsesTo( + "import \"foo.proto\";\n" + "import public \"bar.proto\";\n" + "import \"baz.proto\";\n" + "import public \"qux.proto\";\n", + "dependency: \"foo.proto\"" + "dependency: \"bar.proto\"" + "dependency: \"baz.proto\"" + "dependency: \"qux.proto\"" + "public_dependency: 1 " + "public_dependency: 3 "); +} + +TEST_F(ParseMiscTest, ParsePackage) { + ExpectParsesTo("package foo.bar.baz;\n", "package: \"foo.bar.baz\""); +} + +TEST_F(ParseMiscTest, ParsePackageWithSpaces) { + ExpectParsesTo( + "package foo . bar. \n" + " baz;\n", + "package: \"foo.bar.baz\""); +} + +// =================================================================== +// options + +TEST_F(ParseMiscTest, ParseFileOptions) { + ExpectParsesTo( + "option java_package = \"com.google.foo\";\n" + "option optimize_for = CODE_SIZE;", + + "options {" + "uninterpreted_option { name { name_part: \"java_package\" " + " is_extension: false }" + " string_value: \"com.google.foo\"} " + "uninterpreted_option { name { name_part: \"optimize_for\" " + " is_extension: false }" + " identifier_value: \"CODE_SIZE\" } " + "}"); +} + +// =================================================================== +// Error tests +// +// There are a very large number of possible errors that the parser could +// report, so it's infeasible to test every single one of them. Instead, +// we test each unique call to AddError() in parser.h. This does not mean +// we are testing every possible error that Parser can generate because +// each variant of the Consume() helper only counts as one unique call to +// AddError(). + +typedef ParserTest ParseErrorTest; + +TEST_F(ParseErrorTest, MissingSyntaxIdentifier) { + require_syntax_identifier_ = true; + ExpectHasEarlyExitErrors("message TestMessage {}", + "0:0: File must begin with a syntax statement, e.g. " + "'syntax = \"proto2\";'.\n"); + EXPECT_EQ("", parser_->GetSyntaxIdentifier()); +} + +TEST_F(ParseErrorTest, UnknownSyntaxIdentifier) { + ExpectHasEarlyExitErrors( + "syntax = \"no_such_syntax\";", + "0:9: Unrecognized syntax identifier \"no_such_syntax\". This parser " + "only recognizes \"proto2\" and \"proto3\".\n"); + EXPECT_EQ("no_such_syntax", parser_->GetSyntaxIdentifier()); +} + +TEST_F(ParseErrorTest, SimpleSyntaxError) { + ExpectHasErrors("message TestMessage @#$ { blah }", + "0:20: Expected \"{\".\n"); + EXPECT_EQ("proto2", parser_->GetSyntaxIdentifier()); +} + +TEST_F(ParseErrorTest, ExpectedTopLevel) { + ExpectHasErrors("blah;", + "0:0: Expected top-level statement (e.g. \"message\").\n"); +} + +TEST_F(ParseErrorTest, UnmatchedCloseBrace) { + // This used to cause an infinite loop. Doh. + ExpectHasErrors("}", + "0:0: Expected top-level statement (e.g. \"message\").\n" + "0:0: Unmatched \"}\".\n"); +} + +// ------------------------------------------------------------------- +// Message errors + +TEST_F(ParseErrorTest, MessageMissingName) { + ExpectHasErrors("message {}", "0:8: Expected message name.\n"); +} + +TEST_F(ParseErrorTest, MessageMissingBody) { + ExpectHasErrors("message TestMessage;", "0:19: Expected \"{\".\n"); +} + +TEST_F(ParseErrorTest, EofInMessage) { + ExpectHasErrors( + "message TestMessage {", + "0:21: Reached end of input in message definition (missing '}').\n"); +} + +TEST_F(ParseErrorTest, MissingFieldNumber) { + ExpectHasErrors( + "message TestMessage {\n" + " optional int32 foo;\n" + "}\n", + "1:20: Missing field number.\n"); +} + +TEST_F(ParseErrorTest, ExpectedFieldNumber) { + ExpectHasErrors( + "message TestMessage {\n" + " optional int32 foo = ;\n" + "}\n", + "1:23: Expected field number.\n"); +} + +TEST_F(ParseErrorTest, FieldNumberOutOfRange) { + ExpectHasErrors( + "message TestMessage {\n" + " optional int32 foo = 0x100000000;\n" + "}\n", + "1:23: Integer out of range.\n"); +} + +TEST_F(ParseErrorTest, MissingLabel) { + ExpectHasErrors( + "message TestMessage {\n" + " int32 foo = 1;\n" + "}\n", + "1:2: Expected \"required\", \"optional\", or \"repeated\".\n"); +} + +TEST_F(ParseErrorTest, ExpectedOptionName) { + ExpectHasErrors( + "message TestMessage {\n" + " optional uint32 foo = 1 [];\n" + "}\n", + "1:27: Expected identifier.\n"); +} + +TEST_F(ParseErrorTest, NonExtensionOptionNameBeginningWithDot) { + ExpectHasErrors( + "message TestMessage {\n" + " optional uint32 foo = 1 [.foo=1];\n" + "}\n", + "1:27: Expected identifier.\n"); +} + +TEST_F(ParseErrorTest, DefaultValueTypeMismatch) { + ExpectHasErrors( + "message TestMessage {\n" + " optional uint32 foo = 1 [default=true];\n" + "}\n", + "1:35: Expected integer for field default value.\n"); +} + +TEST_F(ParseErrorTest, DefaultValueNotBoolean) { + ExpectHasErrors( + "message TestMessage {\n" + " optional bool foo = 1 [default=blah];\n" + "}\n", + "1:33: Expected \"true\" or \"false\".\n"); +} + +TEST_F(ParseErrorTest, DefaultValueNotString) { + ExpectHasErrors( + "message TestMessage {\n" + " optional string foo = 1 [default=1];\n" + "}\n", + "1:35: Expected string for field default value.\n"); +} + +TEST_F(ParseErrorTest, DefaultValueUnsignedNegative) { + ExpectHasErrors( + "message TestMessage {\n" + " optional uint32 foo = 1 [default=-1];\n" + "}\n", + "1:36: Unsigned field can't have negative default value.\n"); +} + +TEST_F(ParseErrorTest, DefaultValueTooLarge) { + ExpectHasErrors( + "message TestMessage {\n" + " optional int32 foo = 1 [default= 0x80000000];\n" + " optional int32 foo = 1 [default=-0x80000001];\n" + " optional uint32 foo = 1 [default= 0x100000000];\n" + " optional int64 foo = 1 [default= 0x80000000000000000];\n" + " optional int64 foo = 1 [default=-0x80000000000000001];\n" + " optional uint64 foo = 1 [default= 0x100000000000000000];\n" + "}\n", + "1:36: Integer out of range.\n" + "2:36: Integer out of range.\n" + "3:36: Integer out of range.\n" + "4:36: Integer out of range.\n" + "5:36: Integer out of range.\n" + "6:36: Integer out of range.\n"); +} + +TEST_F(ParseErrorTest, JsonNameNotString) { + ExpectHasErrors( + "message TestMessage {\n" + " optional string foo = 1 [json_name=1];\n" + "}\n", + "1:37: Expected string for JSON name.\n"); +} + +TEST_F(ParseErrorTest, DuplicateJsonName) { + ExpectHasErrors( + "message TestMessage {\n" + " optional uint32 foo = 1 [json_name=\"a\",json_name=\"b\"];\n" + "}\n", + "1:41: Already set option \"json_name\".\n"); +} + +TEST_F(ParseErrorTest, EnumValueOutOfRange) { + ExpectHasErrors( + "enum TestEnum {\n" + " HEX_TOO_BIG = 0x80000000;\n" + " HEX_TOO_SMALL = -0x80000001;\n" + " INT_TOO_BIG = 2147483648;\n" + " INT_TOO_SMALL = -2147483649;\n" + "}\n", + "1:19: Integer out of range.\n" + "2:19: Integer out of range.\n" + "3:19: Integer out of range.\n" + "4:19: Integer out of range.\n"); +} + +TEST_F(ParseErrorTest, EnumAllowAliasFalse) { + ExpectHasErrors( + "enum Foo {\n" + " option allow_alias = false;\n" + " BAR = 1;\n" + " BAZ = 2;\n" + "}\n", + "5:0: \"Foo\" declares 'option allow_alias = false;' which has no " + "effect. " + "Please remove the declaration.\n"); +} + +TEST_F(ParseErrorTest, UnnecessaryEnumAllowAlias) { + ExpectHasErrors( + "enum Foo {\n" + " option allow_alias = true;\n" + " BAR = 1;\n" + " BAZ = 2;\n" + "}\n", + "5:0: \"Foo\" declares support for enum aliases but no enum values share " + "field numbers. Please remove the unnecessary 'option allow_alias = " + "true;' " + "declaration.\n"); +} + +TEST_F(ParseErrorTest, DefaultValueMissing) { + ExpectHasErrors( + "message TestMessage {\n" + " optional uint32 foo = 1 [default=];\n" + "}\n", + "1:35: Expected integer for field default value.\n"); +} + +TEST_F(ParseErrorTest, DefaultValueForGroup) { + ExpectHasErrors( + "message TestMessage {\n" + " optional group Foo = 1 [default=blah] {}\n" + "}\n", + "1:34: Messages can't have default values.\n"); +} + +TEST_F(ParseErrorTest, DuplicateDefaultValue) { + ExpectHasErrors( + "message TestMessage {\n" + " optional uint32 foo = 1 [default=1,default=2];\n" + "}\n", + "1:37: Already set option \"default\".\n"); +} + +TEST_F(ParseErrorTest, MissingOneofName) { + ExpectHasErrors( + "message TestMessage {\n" + " oneof {\n" + " int32 bar = 1;\n" + " }\n" + "}\n", + "1:8: Expected oneof name.\n"); +} + +TEST_F(ParseErrorTest, LabelInOneof) { + ExpectHasErrors( + "message TestMessage {\n" + " oneof foo {\n" + " optional int32 bar = 1;\n" + " }\n" + "}\n", + "2:4: Fields in oneofs must not have labels (required / optional " + "/ repeated).\n"); +} + +TEST_F(ParseErrorTest, MapInOneof) { + ExpectHasErrors( + "message TestMessage {\n" + " oneof foo {\n" + " map<int32, int32> foo_map = 1;\n" + " map message_field = 2;\n" // a normal message field is OK + " }\n" + "}\n", + "2:7: Map fields are not allowed in oneofs.\n"); +} + +TEST_F(ParseErrorTest, LabelForMap) { + ExpectHasErrors( + "message TestMessage {\n" + " optional map<int32, int32> int_map = 1;\n" + " required map<int32, int32> int_map2 = 2;\n" + " repeated map<int32, int32> int_map3 = 3;\n" + " optional map map_message = 4;\n" // a normal message field is OK + "}\n", + "1:14: Field labels (required/optional/repeated) are not allowed on map " + "fields.\n" + "2:14: Field labels (required/optional/repeated) are not allowed on map " + "fields.\n" + "3:14: Field labels (required/optional/repeated) are not allowed on map " + "fields.\n"); +} + +TEST_F(ParseErrorTest, MalformedMaps) { + ExpectHasErrors( + "message TestMessage {\n" + " map map_message = 1;\n" // a normal message field lacking label + " map<string> str_map = 2;\n" + " map<string,> str_map2 = 3;\n" + " map<,string> str_map3 = 4;\n" + " map<> empty_map = 5;\n" + " map<string,string str_map6 = 6;\n" + "}" + "extend SomeMessage {\n" + " map<int32, int32> int_map = 1;\n" + "}", + "1:6: Expected \"required\", \"optional\", or \"repeated\".\n" + "2:12: Expected \",\".\n" + "3:13: Expected type name.\n" + "4:6: Expected type name.\n" + "5:6: Expected type name.\n" + "6:20: Expected \">\".\n" + "8:5: Map fields are not allowed to be extensions.\n"); +} + +TEST_F(ParseErrorTest, GroupNotCapitalized) { + ExpectHasErrors( + "message TestMessage {\n" + " optional group foo = 1 {}\n" + "}\n", + "1:17: Group names must start with a capital letter.\n"); +} + +TEST_F(ParseErrorTest, GroupMissingBody) { + ExpectHasErrors( + "message TestMessage {\n" + " optional group Foo = 1;\n" + "}\n", + "1:24: Missing group body.\n"); +} + +TEST_F(ParseErrorTest, ExtendingPrimitive) { + ExpectHasErrors("extend int32 { optional string foo = 4; }\n", + "0:7: Expected message type.\n"); +} + +TEST_F(ParseErrorTest, ErrorInExtension) { + ExpectHasErrors( + "message Foo { extensions 100 to 199; }\n" + "extend Foo { optional string foo; }\n", + "1:32: Missing field number.\n"); +} + +TEST_F(ParseErrorTest, MultipleParseErrors) { + // When a statement has a parse error, the parser should be able to continue + // parsing at the next statement. + ExpectHasErrors( + "message TestMessage {\n" + " optional int32 foo;\n" + " !invalid statement ending in a block { blah blah { blah } blah }\n" + " optional int32 bar = 3 {}\n" + "}\n", + "1:20: Missing field number.\n" + "2:2: Expected \"required\", \"optional\", or \"repeated\".\n" + "2:2: Expected type name.\n" + "3:25: Expected \";\".\n"); +} + +TEST_F(ParseErrorTest, EofInAggregateValue) { + ExpectHasErrors( + "option (fileopt) = { i:100\n", + "1:0: Unexpected end of stream while parsing aggregate value.\n"); +} + +// ------------------------------------------------------------------- +// Enum errors + +TEST_F(ParseErrorTest, EofInEnum) { + ExpectHasErrors( + "enum TestEnum {", + "0:15: Reached end of input in enum definition (missing '}').\n"); +} + +TEST_F(ParseErrorTest, EnumValueMissingNumber) { + ExpectHasErrors( + "enum TestEnum {\n" + " FOO;\n" + "}\n", + "1:5: Missing numeric value for enum constant.\n"); +} + +TEST_F(ParseErrorTest, EnumReservedStandaloneMaxNotAllowed) { + ExpectHasErrors( + "enum TestEnum {\n" + " FOO = 1;\n" + " reserved max;\n" + "}\n", + "2:11: Expected enum value or number range.\n"); +} + +TEST_F(ParseErrorTest, EnumReservedMixNameAndNumber) { + ExpectHasErrors( + "enum TestEnum {\n" + " FOO = 1;\n" + " reserved 10, \"foo\";\n" + "}\n", + "2:15: Expected enum number range.\n"); +} + +TEST_F(ParseErrorTest, EnumReservedPositiveNumberOutOfRange) { + ExpectHasErrors( + "enum TestEnum {\n" + "FOO = 1;\n" + " reserved 2147483648;\n" + "}\n", + "2:11: Integer out of range.\n"); +} + +TEST_F(ParseErrorTest, EnumReservedNegativeNumberOutOfRange) { + ExpectHasErrors( + "enum TestEnum {\n" + "FOO = 1;\n" + " reserved -2147483649;\n" + "}\n", + "2:12: Integer out of range.\n"); +} + +TEST_F(ParseErrorTest, EnumReservedMissingQuotes) { + ExpectHasErrors( + "enum TestEnum {\n" + " FOO = 1;\n" + " reserved foo;\n" + "}\n", + "2:11: Expected enum value or number range.\n"); +} + +// ------------------------------------------------------------------- +// Reserved field number errors + +TEST_F(ParseErrorTest, ReservedStandaloneMaxNotAllowed) { + ExpectHasErrors( + "message Foo {\n" + " reserved max;\n" + "}\n", + "1:11: Expected field name or number range.\n"); +} + +TEST_F(ParseErrorTest, ReservedMixNameAndNumber) { + ExpectHasErrors( + "message Foo {\n" + " reserved 10, \"foo\";\n" + "}\n", + "1:15: Expected field number range.\n"); +} + +TEST_F(ParseErrorTest, ReservedMissingQuotes) { + ExpectHasErrors( + "message Foo {\n" + " reserved foo;\n" + "}\n", + "1:11: Expected field name or number range.\n"); +} + +TEST_F(ParseErrorTest, ReservedNegativeNumber) { + ExpectHasErrors( + "message Foo {\n" + " reserved -10;\n" + "}\n", + "1:11: Expected field name or number range.\n"); +} + +TEST_F(ParseErrorTest, ReservedNumberOutOfRange) { + ExpectHasErrors( + "message Foo {\n" + " reserved 2147483648;\n" + "}\n", + "1:11: Integer out of range.\n"); +} + +// ------------------------------------------------------------------- +// Service errors + +TEST_F(ParseErrorTest, EofInService) { + ExpectHasErrors( + "service TestService {", + "0:21: Reached end of input in service definition (missing '}').\n"); +} + +TEST_F(ParseErrorTest, ServiceMethodPrimitiveParams) { + ExpectHasErrors( + "service TestService {\n" + " rpc Foo(int32) returns (string);\n" + "}\n", + "1:10: Expected message type.\n" + "1:26: Expected message type.\n"); +} + + +TEST_F(ParseErrorTest, EofInMethodOptions) { + ExpectHasErrors( + "service TestService {\n" + " rpc Foo(Bar) returns(Bar) {", + "1:29: Reached end of input in method options (missing '}').\n" + "1:29: Reached end of input in service definition (missing '}').\n"); +} + + +TEST_F(ParseErrorTest, PrimitiveMethodInput) { + ExpectHasErrors( + "service TestService {\n" + " rpc Foo(int32) returns(Bar);\n" + "}\n", + "1:10: Expected message type.\n"); +} + + +TEST_F(ParseErrorTest, MethodOptionTypeError) { + // This used to cause an infinite loop. + ExpectHasErrors( + "message Baz {}\n" + "service Foo {\n" + " rpc Bar(Baz) returns(Baz) { option invalid syntax; }\n" + "}\n", + "2:45: Expected \"=\".\n"); +} + + +// ------------------------------------------------------------------- +// Import and package errors + +TEST_F(ParseErrorTest, ImportNotQuoted) { + ExpectHasErrors("import foo;\n", + "0:7: Expected a string naming the file to import.\n"); +} + +TEST_F(ParseErrorTest, MultiplePackagesInFile) { + ExpectHasErrors( + "package foo;\n" + "package bar;\n", + "1:0: Multiple package definitions.\n"); +} + +// =================================================================== +// Test that errors detected by DescriptorPool correctly report line and +// column numbers. We have one test for every call to RecordLocation() in +// parser.cc. + +typedef ParserTest ParserValidationErrorTest; + +TEST_F(ParserValidationErrorTest, PackageNameError) { + // Create another file which defines symbol "foo". + FileDescriptorProto other_file; + other_file.set_name("bar.proto"); + other_file.add_message_type()->set_name("foo"); + EXPECT_TRUE(pool_.BuildFile(other_file) != NULL); + + // Now try to define it as a package. + ExpectHasValidationErrors( + "package foo.bar;", + "0:0: \"foo\" is already defined (as something other than a package) " + "in file \"bar.proto\".\n"); +} + +TEST_F(ParserValidationErrorTest, ImportUnloadedError) { + ExpectHasValidationErrors( + "package test;\n" + "\n" + "import \"unloaded.proto\";", + "2:0: Import \"unloaded.proto\" has not been loaded.\n"); +} + +TEST_F(ParserValidationErrorTest, ImportTwice) { + FileDescriptorProto other_file; + other_file.set_name("bar.proto"); + other_file.add_message_type()->set_name("foo"); + EXPECT_TRUE(pool_.BuildFile(other_file) != nullptr); + + ExpectHasValidationErrors( + "package test;\n" + "\n" + "import \"bar.proto\";\n" + " import \"bar.proto\";", + "3:2: Import \"bar.proto\" was listed twice.\n"); +} + +TEST_F(ParserValidationErrorTest, DuplicateFileError) { + FileDescriptorProto other_file; + other_file.set_name("foo.proto"); + EXPECT_TRUE(pool_.BuildFile(other_file) != nullptr); + + ExpectHasValidationErrors( + "package test;", "0:0: A file with this name is already in the pool.\n"); +} + +TEST_F(ParserValidationErrorTest, MessageNameError) { + ExpectHasValidationErrors( + "message Foo {}\n" + "message Foo {}\n", + "1:8: \"Foo\" is already defined.\n"); +} + +TEST_F(ParserValidationErrorTest, FieldNameError) { + ExpectHasValidationErrors( + "message Foo {\n" + " optional int32 bar = 1;\n" + " optional int32 bar = 2;\n" + "}\n", + "2:17: \"bar\" is already defined in \"Foo\".\n"); +} + +TEST_F(ParserValidationErrorTest, FieldTypeError) { + ExpectHasValidationErrors( + "message Foo {\n" + " optional Baz bar = 1;\n" + "}\n", + "1:11: \"Baz\" is not defined.\n"); +} + +TEST_F(ParserValidationErrorTest, FieldNumberError) { + ExpectHasValidationErrors( + "message Foo {\n" + " optional int32 bar = 0;\n" + "}\n", + "1:23: Field numbers must be positive integers.\n"); +} + +TEST_F(ParserValidationErrorTest, FieldExtendeeError) { + ExpectHasValidationErrors("extend Baz { optional int32 bar = 1; }\n", + "0:7: \"Baz\" is not defined.\n"); +} + +TEST_F(ParserValidationErrorTest, ExtensionJsonNameError) { + ExpectHasValidationErrors( + "message TestMessage {\n" + " extensions 1 to 100;\n" + "}\n" + "extend TestMessage {\n" + " optional int32 foo = 12 [json_name = \"bar\"];\n" + "}", + "4:27: option json_name is not allowed on extension fields.\n"); +} + +TEST_F(ParserValidationErrorTest, FieldDefaultValueError) { + ExpectHasValidationErrors( + "enum Baz { QUX = 1; }\n" + "message Foo {\n" + " optional Baz bar = 1 [default=NO_SUCH_VALUE];\n" + "}\n", + "2:32: Enum type \"Baz\" has no value named \"NO_SUCH_VALUE\".\n"); +} + +TEST_F(ParserValidationErrorTest, FileOptionNameError) { + ExpectHasValidationErrors( + "option foo = 5;", + "0:7: Option \"foo\" unknown. Ensure that your proto definition file " + "imports the proto which defines the option.\n"); +} + +TEST_F(ParserValidationErrorTest, FileOptionValueError) { + ExpectHasValidationErrors( + "option java_outer_classname = 5;", + "0:30: Value must be quoted string for string option " + "\"google.protobuf.FileOptions.java_outer_classname\".\n"); +} + +TEST_F(ParserValidationErrorTest, FieldOptionNameError) { + ExpectHasValidationErrors( + "message Foo {\n" + " optional bool bar = 1 [foo=1];\n" + "}\n", + "1:25: Option \"foo\" unknown. Ensure that your proto definition file " + "imports the proto which defines the option.\n"); +} + +TEST_F(ParserValidationErrorTest, FieldOptionValueError) { + ExpectHasValidationErrors( + "message Foo {\n" + " optional int32 bar = 1 [ctype=1];\n" + "}\n", + "1:32: Value must be identifier for enum-valued option " + "\"google.protobuf.FieldOptions.ctype\".\n"); +} + +TEST_F(ParserValidationErrorTest, ExtensionRangeNumberError) { + ExpectHasValidationErrors( + "message Foo {\n" + " extensions 0;\n" + "}\n", + "1:13: Extension numbers must be positive integers.\n"); +} + +TEST_F(ParserValidationErrorTest, Proto3ExtensionError) { + ExpectHasValidationErrors( + "syntax = 'proto3';\n" + "message Foo { \n" + " extensions 100 to 199;\n" + "}\n" + "extend Foo { string foo = 101; }\n", + "4:7: Extensions in proto3 are only allowed for defining options.\n" + "2:13: Extension ranges are not allowed in proto3.\n"); +} + +TEST_F(ParserValidationErrorTest, Proto3MessageSet) { + ExpectHasValidationErrors( + "syntax = 'proto3';\n" + "message Foo { \n" + " option message_set_wire_format = true;\n" + "}\n", + "1:8: MessageSet is not supported in proto3.\n"); +} + +TEST_F(ParserValidationErrorTest, Proto3Required) { + ExpectHasValidationErrors( + "syntax = 'proto3';\n" + "message Foo { \n" + " required int32 field = 1;" + "}\n", + "2:11: Required fields are not allowed in proto3.\n"); +} + +TEST_F(ParserValidationErrorTest, Proto3Default) { + ExpectHasValidationErrors( + "syntax = 'proto3';\n" + "message Foo { \n" + " int32 field = 1 [default = 12];" + "}\n", + "2:29: Explicit default values are not allowed in proto3.\n"); +} + +TEST_F(ParserValidationErrorTest, Proto3JsonConflictError) { + ExpectHasValidationErrors( + "syntax = 'proto3';\n" + "message TestMessage {\n" + " uint32 foo = 1;\n" + " uint32 Foo = 2;\n" + "}\n", + "3:9: The JSON camel-case name of field \"Foo\" conflicts with field " + "\"foo\". This is not allowed in proto3.\n"); +} + +TEST_F(ParserValidationErrorTest, EnumNameError) { + ExpectHasValidationErrors( + "enum Foo {A = 1;}\n" + "enum Foo {B = 1;}\n", + "1:5: \"Foo\" is already defined.\n"); +} + +TEST_F(ParserValidationErrorTest, Proto3EnumError) { + ExpectHasValidationErrors( + "syntax = 'proto3';\n" + "enum Foo {A = 1;}\n", + "1:14: The first enum value must be zero in proto3.\n"); +} + +TEST_F(ParserValidationErrorTest, EnumValueNameError) { + ExpectHasValidationErrors( + "enum Foo {\n" + " BAR = 1;\n" + " BAR = 1;\n" + "}\n", + "2:2: \"BAR\" is already defined.\n"); +} + +TEST_F(ParserValidationErrorTest, EnumValueAliasError) { + ExpectHasValidationErrors( + "enum Foo {\n" + " BAR = 1;\n" + " BAZ = 1;\n" + "}\n", + "2:8: \"BAZ\" uses the same enum value as \"BAR\". If this is " + "intended, set 'option allow_alias = true;' to the enum " + "definition.\n"); +} + +TEST_F(ParserValidationErrorTest, ExplicitlyMapEntryError) { + ExpectHasValidationErrors( + "message Foo {\n" + " message ValueEntry {\n" + " option map_entry = true;\n" + " optional int32 key = 1;\n" + " optional int32 value = 2;\n" + " extensions 99 to 999;\n" + " }\n" + " repeated ValueEntry value = 1;\n" + "}", + "7:11: map_entry should not be set explicitly. Use " + "map<KeyType, ValueType> instead.\n"); +} + +TEST_F(ParserValidationErrorTest, ServiceNameError) { + ExpectHasValidationErrors( + "service Foo {}\n" + "service Foo {}\n", + "1:8: \"Foo\" is already defined.\n"); +} + +TEST_F(ParserValidationErrorTest, MethodNameError) { + ExpectHasValidationErrors( + "message Baz {}\n" + "service Foo {\n" + " rpc Bar(Baz) returns(Baz);\n" + " rpc Bar(Baz) returns(Baz);\n" + "}\n", + "3:6: \"Bar\" is already defined in \"Foo\".\n"); +} + + +TEST_F(ParserValidationErrorTest, MethodInputTypeError) { + ExpectHasValidationErrors( + "message Baz {}\n" + "service Foo {\n" + " rpc Bar(Qux) returns(Baz);\n" + "}\n", + "2:10: \"Qux\" is not defined.\n"); +} + + +TEST_F(ParserValidationErrorTest, MethodOutputTypeError) { + ExpectHasValidationErrors( + "message Baz {}\n" + "service Foo {\n" + " rpc Bar(Baz) returns(Qux);\n" + "}\n", + "2:23: \"Qux\" is not defined.\n"); +} + + +TEST_F(ParserValidationErrorTest, ResolvedUndefinedError) { + // Create another file which defines symbol ".base.bar". + FileDescriptorProto other_file; + other_file.set_name("base.proto"); + other_file.set_package("base"); + other_file.add_message_type()->set_name("bar"); + EXPECT_TRUE(pool_.BuildFile(other_file) != NULL); + + // Define "foo.base" and try "base.bar". + // "base.bar" is resolved to "foo.base.bar" which is not defined. + ExpectHasValidationErrors( + "package foo.base;\n" + "import \"base.proto\";\n" + "message qux {\n" + " optional base.bar baz = 1;\n" + " optional .base.bar quz = 2;\n" + "}\n", + "3:11: \"base.bar\" is resolved to \"foo.base.bar\"," + " which is not defined. The innermost scope is searched first " + "in name resolution. Consider using a leading '.'(i.e., \".base.bar\")" + " to start from the outermost scope.\n"); +} + +TEST_F(ParserValidationErrorTest, ResovledUndefinedOptionError) { + // Build descriptor message in test pool + FileDescriptorProto descriptor_proto; + DescriptorProto::descriptor()->file()->CopyTo(&descriptor_proto); + ASSERT_TRUE(pool_.BuildFile(descriptor_proto) != NULL); + + // base2.proto: + // package baz + // import net/proto2/proto/descriptor.proto + // message Bar { optional int32 foo = 1; } + // extend FileOptions { optional Bar bar = 7672757; } + FileDescriptorProto other_file; + other_file.set_name("base2.proto"); + other_file.set_package("baz"); + other_file.add_dependency(); + other_file.set_dependency(0, descriptor_proto.name()); + + DescriptorProto* message(other_file.add_message_type()); + message->set_name("Bar"); + FieldDescriptorProto* field(message->add_field()); + field->set_name("foo"); + field->set_number(1); + field->set_label(FieldDescriptorProto::LABEL_OPTIONAL); + field->set_type(FieldDescriptorProto::TYPE_INT32); + + FieldDescriptorProto* extension(other_file.add_extension()); + extension->set_name("bar"); + extension->set_number(7672757); + extension->set_label(FieldDescriptorProto::LABEL_OPTIONAL); + extension->set_type(FieldDescriptorProto::TYPE_MESSAGE); + extension->set_type_name("Bar"); + extension->set_extendee("google.protobuf.FileOptions"); + + EXPECT_TRUE(pool_.BuildFile(other_file) != NULL); + + // qux.proto: + // package qux.baz + // option (baz.bar).foo = 1; + // + // Although "baz.bar" is already defined, the lookup code will try + // "qux.baz.bar", since it's the match from the innermost scope, + // which will cause a symbol not defined error. + ExpectHasValidationErrors( + "package qux.baz;\n" + "import \"base2.proto\";\n" + "option (baz.bar).foo = 1;\n", + "2:7: Option \"(baz.bar)\" is resolved to \"(qux.baz.bar)\"," + " which is not defined. The innermost scope is searched first " + "in name resolution. Consider using a leading '.'(i.e., \"(.baz.bar)\")" + " to start from the outermost scope.\n"); +} + +// =================================================================== +// Test that the output from FileDescriptor::DebugString() (and all other +// descriptor types) is parseable, and results in the same Descriptor +// definitions again afoter parsing (note, however, that the order of messages +// cannot be guaranteed to be the same) + +typedef ParserTest ParseDescriptorDebugTest; + +class CompareDescriptorNames { + public: + bool operator()(const DescriptorProto* left, + const DescriptorProto* right) const { + return left->name() < right->name(); + } +}; + +// Sorts nested DescriptorProtos of a DescriptoProto, by name. +void SortMessages(DescriptorProto* descriptor_proto) { + int size = descriptor_proto->nested_type_size(); + // recursively sort; we can't guarantee the order of nested messages either + for (int i = 0; i < size; ++i) { + SortMessages(descriptor_proto->mutable_nested_type(i)); + } + DescriptorProto** data = + descriptor_proto->mutable_nested_type()->mutable_data(); + std::sort(data, data + size, CompareDescriptorNames()); +} + +// Sorts DescriptorProtos belonging to a FileDescriptorProto, by name. +void SortMessages(FileDescriptorProto* file_descriptor_proto) { + int size = file_descriptor_proto->message_type_size(); + // recursively sort; we can't guarantee the order of nested messages either + for (int i = 0; i < size; ++i) { + SortMessages(file_descriptor_proto->mutable_message_type(i)); + } + DescriptorProto** data = + file_descriptor_proto->mutable_message_type()->mutable_data(); + std::sort(data, data + size, CompareDescriptorNames()); +} + +// Strips the message and enum field type names for comparison purpose only. +void StripFieldTypeName(DescriptorProto* proto) { + for (int i = 0; i < proto->field_size(); ++i) { + std::string type_name = proto->field(i).type_name(); + std::string::size_type pos = type_name.find_last_of('.'); + if (pos != std::string::npos) { + proto->mutable_field(i)->mutable_type_name()->assign( + type_name.begin() + pos + 1, type_name.end()); + } + } + for (int i = 0; i < proto->nested_type_size(); ++i) { + StripFieldTypeName(proto->mutable_nested_type(i)); + } +} + +void StripFieldTypeName(FileDescriptorProto* file_proto) { + for (int i = 0; i < file_proto->message_type_size(); ++i) { + StripFieldTypeName(file_proto->mutable_message_type(i)); + } +} + +TEST_F(ParseDescriptorDebugTest, TestAllDescriptorTypes) { + const FileDescriptor* original_file = + protobuf_unittest::TestAllTypes::descriptor()->file(); + FileDescriptorProto expected; + original_file->CopyTo(&expected); + + // Get the DebugString of the unittest.proto FileDecriptor, which includes + // all other descriptor types + std::string debug_string = original_file->DebugString(); + + // Parse the debug string + SetupParser(debug_string.c_str()); + FileDescriptorProto parsed; + parser_->Parse(input_.get(), &parsed); + EXPECT_EQ(io::Tokenizer::TYPE_END, input_->current().type); + ASSERT_EQ("", error_collector_.text_) << "Failed to parse:\n" << debug_string; + + // We now have a FileDescriptorProto, but to compare with the expected we + // need to link to a FileDecriptor, then output back to a proto. We'll + // also need to give it the same name as the original. + parsed.set_name( + TestUtil::MaybeTranslatePath("net/proto2/internal/unittest.proto")); + // We need the imported dependency before we can build our parsed proto + const FileDescriptor* public_import = + protobuf_unittest_import::PublicImportMessage::descriptor()->file(); + FileDescriptorProto public_import_proto; + public_import->CopyTo(&public_import_proto); + ASSERT_TRUE(pool_.BuildFile(public_import_proto) != NULL); + const FileDescriptor* import = + protobuf_unittest_import::ImportMessage::descriptor()->file(); + FileDescriptorProto import_proto; + import->CopyTo(&import_proto); + ASSERT_TRUE(pool_.BuildFile(import_proto) != NULL); + const FileDescriptor* actual = pool_.BuildFile(parsed); + parsed.Clear(); + ASSERT_TRUE(actual != NULL) << "Failed to validate:\n" << debug_string; + actual->CopyTo(&parsed); + ASSERT_TRUE(actual != NULL); + + // The messages might be in different orders, making them hard to compare. + // So, sort the messages in the descriptor protos (including nested messages, + // recursively). + SortMessages(&expected); + SortMessages(&parsed); + + // I really wanted to use StringDiff here for the debug output on fail, + // but the strings are too long for it, and if I increase its max size, + // we get a memory allocation failure :( + EXPECT_EQ(expected.DebugString(), parsed.DebugString()); +} + +TEST_F(ParseDescriptorDebugTest, TestCustomOptions) { + const FileDescriptor* original_file = + protobuf_unittest::AggregateMessage::descriptor()->file(); + FileDescriptorProto expected; + original_file->CopyTo(&expected); + + std::string debug_string = original_file->DebugString(); + + // Parse the debug string + SetupParser(debug_string.c_str()); + FileDescriptorProto parsed; + parser_->Parse(input_.get(), &parsed); + EXPECT_EQ(io::Tokenizer::TYPE_END, input_->current().type); + ASSERT_EQ("", error_collector_.text_); + + // We now have a FileDescriptorProto, but to compare with the expected we + // need to link to a FileDecriptor, then output back to a proto. We'll + // also need to give it the same name as the original. + parsed.set_name(original_file->name()); + + // unittest_custom_options.proto depends on descriptor.proto. + const FileDescriptor* import = FileDescriptorProto::descriptor()->file(); + FileDescriptorProto import_proto; + import->CopyTo(&import_proto); + ASSERT_TRUE(pool_.BuildFile(import_proto) != NULL); + + FileDescriptorProto any_import; + google::protobuf::Any::descriptor()->file()->CopyTo(&any_import); + ASSERT_TRUE(pool_.BuildFile(any_import) != nullptr); + + const FileDescriptor* actual = pool_.BuildFile(parsed); + ASSERT_TRUE(actual != NULL); + parsed.Clear(); + actual->CopyTo(&parsed); + + // The messages might be in different orders, making them hard to compare. + // So, sort the messages in the descriptor protos (including nested messages, + // recursively). + SortMessages(&expected); + SortMessages(&parsed); + + EXPECT_EQ(expected.DebugString(), parsed.DebugString()); +} + +// Ensure that DebugStringWithOptions(), with |include_comments| set to true, +// includes comments from the original parser input in all of the appropriate +// places. +TEST_F(ParseDescriptorDebugTest, TestCommentsInDebugString) { + SetupParser( + "// Detached comment before syntax.\n" + "\n" + "// Syntax comment.\n" + "syntax = \"proto2\";\n" + "\n" + "// Detached comment before package.\n" + "\n" + "// Package comment.\n" + "package comment_test;\n" + "\n" + "// Detached comment before TestMessage1.\n" + "\n" + "// Message comment.\n" + "//\n" + "// More detail in message comment.\n" + "message TestMessage1 {\n" + "\n" + " // Detached comment before foo.\n" + "\n" + " // Field comment.\n" + " optional int32 foo = 1;\n" + "\n" + " // Detached comment before NestedMessage.\n" + "\n" + " // Nested-message comment.\n" + " message NestedMessage {\n" + " optional int32 bar = 1;\n" + " }\n" + "}\n" + "\n" + "// Detached comment before MyEnumType.\n" + "\n" + "// Enum comment.\n" + "enum MyEnumType {\n" + "\n" + " // Detached comment before ASDF.\n" + "\n" + " // Enum-value comment.\n" + " ASDF = 1;\n" + "}\n" + "\n" + "// Detached comment before MyService.\n" + "\n" + "// Service comment.\n" + "service MyService {\n" + "\n" + " // Detached comment before MyRPCCall.\n" + "\n" + " // RPC comment.\n" + " rpc MyRPCCall(TestMessage1) returns (TestMessage1) { }\n" + "}\n"); + + FileDescriptorProto parsed_desc; + parsed_desc.set_name("foo.proto"); + SourceLocationTable source_locations; + parser_->RecordSourceLocationsTo(&source_locations); + parser_->Parse(input_.get(), &parsed_desc); + EXPECT_EQ(io::Tokenizer::TYPE_END, input_->current().type); + ASSERT_EQ("", error_collector_.text_); + + // We need to import the FileDescriptorProto to get a FileDescriptor. + MockValidationErrorCollector collector(source_locations, &error_collector_); + const FileDescriptor* descriptor = + pool_.BuildFileCollectingErrors(parsed_desc, &collector); + ASSERT_TRUE(descriptor != NULL); + + // Ensure that each of the comments appears somewhere in the DebugString(). + // We don't test the exact comment placement or formatting, because we do not + // want to be too fragile here. + const char* expected_comments[] = { + "Detached comment before syntax.", + "Syntax comment.", + "Detached comment before package.", + "Package comment.", + "Detached comment before TestMessage1.", + "Message comment.", + "More detail in message comment.", + "Detached comment before foo.", + "Field comment", + "Detached comment before NestedMessage.", + "Nested-message comment", + "Detached comment before MyEnumType.", + "Enum comment", + "Detached comment before ASDF.", + "Enum-value comment", + "Detached comment before MyService.", + "Service comment", + "Detached comment before MyRPCCall.", + "RPC comment", + }; + + DebugStringOptions debug_string_options; + debug_string_options.include_comments = true; + + { + const std::string debug_string = + descriptor->DebugStringWithOptions(debug_string_options); + + for (int i = 0; i < GOOGLE_ARRAYSIZE(expected_comments); ++i) { + std::string::size_type found_pos = + debug_string.find(expected_comments[i]); + EXPECT_TRUE(found_pos != std::string::npos) + << "\"" << expected_comments[i] << "\" not found."; + } + + // Result of DebugStringWithOptions should be parseable. + SetupParser(debug_string.c_str()); + FileDescriptorProto parsed; + parser_->Parse(input_.get(), &parsed); + EXPECT_EQ(io::Tokenizer::TYPE_END, input_->current().type); + ASSERT_EQ("", error_collector_.text_) << "Failed to parse:\n" + << debug_string; + } + +} + +TEST_F(ParseDescriptorDebugTest, TestMaps) { + SetupParser( + "syntax = \"proto3\"; " + "message Foo { " + " message Bar { } " + " map<int32, Bar> enum_message_map = 1; " + " map<string, float> primitive_map = 2; " + "} "); + FileDescriptorProto original; + EXPECT_TRUE(parser_->Parse(input_.get(), &original)); + original.set_name("foo.proto"); + const FileDescriptor* file = pool_.BuildFile(original); + ASSERT_TRUE(file != NULL); + + // Make sure the debug string uses map syntax and does not have the auto + // generated entry. + std::string debug_string = file->DebugString(); + EXPECT_TRUE(debug_string.find("map<") != std::string::npos); + EXPECT_TRUE(debug_string.find("option map_entry") == std::string::npos); + EXPECT_TRUE(debug_string.find("MapEntry") == std::string::npos); + + // Make sure the descriptor debug string is parsable. + FileDescriptorProto parsed; + SetupParser(debug_string.c_str()); + parsed.set_name("foo.proto"); + ASSERT_TRUE(parser_->Parse(input_.get(), &parsed)); + + original.clear_source_code_info(); + parsed.clear_source_code_info(); + StripFieldTypeName(&original); + StripFieldTypeName(&parsed); + EXPECT_EQ(original.DebugString(), parsed.DebugString()); +} + +// =================================================================== +// SourceCodeInfo tests. + +// Follows a path -- as defined by SourceCodeInfo.Location.path -- from a +// message to a particular sub-field. +// * If the target is itself a message, sets *output_message to point at it, +// *output_field to NULL, and *output_index to -1. +// * Otherwise, if the target is an element of a repeated field, sets +// *output_message to the containing message, *output_field to the descriptor +// of the field, and *output_index to the index of the element. +// * Otherwise, the target is a field (possibly a repeated field, but not any +// one element). Sets *output_message to the containing message, +// *output_field to the descriptor of the field, and *output_index to -1. +// Returns true if the path was valid, false otherwise. A gTest failure is +// recorded before returning false. +bool FollowPath(const Message& root, const int* path_begin, const int* path_end, + const Message** output_message, + const FieldDescriptor** output_field, int* output_index) { + if (path_begin == path_end) { + // Path refers to this whole message. + *output_message = &root; + *output_field = NULL; + *output_index = -1; + return true; + } + + const Descriptor* descriptor = root.GetDescriptor(); + const Reflection* reflection = root.GetReflection(); + + const FieldDescriptor* field = descriptor->FindFieldByNumber(*path_begin); + + if (field == NULL) { + ADD_FAILURE() << descriptor->name() + << " has no field number: " << *path_begin; + return false; + } + + ++path_begin; + + if (field->is_repeated()) { + if (path_begin == path_end) { + // Path refers to the whole repeated field. + *output_message = &root; + *output_field = field; + *output_index = -1; + return true; + } + + int index = *path_begin++; + int size = reflection->FieldSize(root, field); + + if (index >= size) { + ADD_FAILURE() << descriptor->name() << "." << field->name() + << " has size " << size + << ", but path contained index: " << index; + return false; + } + + if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + // Descend into child message. + const Message& child = reflection->GetRepeatedMessage(root, field, index); + return FollowPath(child, path_begin, path_end, output_message, + output_field, output_index); + } else if (path_begin == path_end) { + // Path refers to this element. + *output_message = &root; + *output_field = field; + *output_index = index; + return true; + } else { + ADD_FAILURE() << descriptor->name() << "." << field->name() + << " is not a message; cannot descend into it."; + return false; + } + } else { + if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + const Message& child = reflection->GetMessage(root, field); + return FollowPath(child, path_begin, path_end, output_message, + output_field, output_index); + } else if (path_begin == path_end) { + // Path refers to this field. + *output_message = &root; + *output_field = field; + *output_index = -1; + return true; + } else { + ADD_FAILURE() << descriptor->name() << "." << field->name() + << " is not a message; cannot descend into it."; + return false; + } + } +} + +// Check if two spans are equal. +bool CompareSpans(const RepeatedField<int>& span1, + const RepeatedField<int>& span2) { + if (span1.size() != span2.size()) return false; + for (int i = 0; i < span1.size(); i++) { + if (span1.Get(i) != span2.Get(i)) return false; + } + return true; +} + +// Test fixture for source info tests, which check that source locations are +// recorded correctly in FileDescriptorProto.source_code_info.location. +class SourceInfoTest : public ParserTest { + protected: + // The parsed file (initialized by Parse()). + FileDescriptorProto file_; + + // Parse the given text as a .proto file and populate the spans_ map with + // all the source location spans in its SourceCodeInfo table. + bool Parse(const char* text) { + ExtractMarkers(text); + SetupParser(text_without_markers_.c_str()); + if (!parser_->Parse(input_.get(), &file_)) { + return false; + } + + const SourceCodeInfo& source_info = file_.source_code_info(); + for (int i = 0; i < source_info.location_size(); i++) { + const SourceCodeInfo::Location& location = source_info.location(i); + const Message* descriptor_proto = NULL; + const FieldDescriptor* field = NULL; + int index = 0; + if (!FollowPath(file_, location.path().begin(), location.path().end(), + &descriptor_proto, &field, &index)) { + return false; + } + + spans_.insert( + std::make_pair(SpanKey(*descriptor_proto, field, index), &location)); + } + + return true; + } + + void TearDown() override { + EXPECT_TRUE(spans_.empty()) << "Forgot to call HasSpan() for:\n" + << spans_.begin()->second->DebugString(); + } + + // ----------------------------------------------------------------- + // HasSpan() checks that the span of source code delimited by the given + // tags (comments) correspond via the SourceCodeInfo table to the given + // part of the FileDescriptorProto. (If unclear, look at the actual tests; + // it should quickly become obvious.) + + bool HasSpan(char start_marker, char end_marker, + const Message& descriptor_proto) { + return HasSpanWithComment(start_marker, end_marker, descriptor_proto, NULL, + -1, NULL, NULL, NULL); + } + + bool HasSpanWithComment(char start_marker, char end_marker, + const Message& descriptor_proto, + const char* expected_leading_comments, + const char* expected_trailing_comments, + const char* expected_leading_detached_comments) { + return HasSpanWithComment(start_marker, end_marker, descriptor_proto, NULL, + -1, expected_leading_comments, + expected_trailing_comments, + expected_leading_detached_comments); + } + + bool HasSpan(char start_marker, char end_marker, + const Message& descriptor_proto, const std::string& field_name) { + return HasSpan(start_marker, end_marker, descriptor_proto, field_name, -1); + } + + bool HasSpan(char start_marker, char end_marker, + const Message& descriptor_proto, const std::string& field_name, + int index) { + return HasSpan(start_marker, end_marker, descriptor_proto, field_name, + index, NULL, NULL, NULL); + } + + bool HasSpan(char start_marker, char end_marker, + const Message& descriptor_proto, const std::string& field_name, + int index, const char* expected_leading_comments, + const char* expected_trailing_comments, + const char* expected_leading_detached_comments) { + const FieldDescriptor* field = + descriptor_proto.GetDescriptor()->FindFieldByName(field_name); + if (field == NULL) { + ADD_FAILURE() << descriptor_proto.GetDescriptor()->name() + << " has no such field: " << field_name; + return false; + } + + return HasSpanWithComment(start_marker, end_marker, descriptor_proto, field, + index, expected_leading_comments, + expected_trailing_comments, + expected_leading_detached_comments); + } + + bool HasSpan(const Message& descriptor_proto) { + return HasSpanWithComment('\0', '\0', descriptor_proto, NULL, -1, NULL, + NULL, NULL); + } + + bool HasSpan(const Message& descriptor_proto, const std::string& field_name) { + return HasSpan('\0', '\0', descriptor_proto, field_name, -1); + } + + bool HasSpanWithComment(char start_marker, char end_marker, + const Message& descriptor_proto, + const FieldDescriptor* field, int index, + const char* expected_leading_comments, + const char* expected_trailing_comments, + const char* expected_leading_detached_comments) { + std::pair<SpanMap::iterator, SpanMap::iterator> range = + spans_.equal_range(SpanKey(descriptor_proto, field, index)); + + if (start_marker == '\0') { + if (range.first == range.second) { + return false; + } else { + spans_.erase(range.first); + return true; + } + } else { + std::pair<int, int> start_pos = FindOrDie(markers_, start_marker); + std::pair<int, int> end_pos = FindOrDie(markers_, end_marker); + + RepeatedField<int> expected_span; + expected_span.Add(start_pos.first); + expected_span.Add(start_pos.second); + if (end_pos.first != start_pos.first) { + expected_span.Add(end_pos.first); + } + expected_span.Add(end_pos.second); + + for (SpanMap::iterator iter = range.first; iter != range.second; ++iter) { + if (CompareSpans(expected_span, iter->second->span())) { + if (expected_leading_comments == NULL) { + EXPECT_FALSE(iter->second->has_leading_comments()); + } else { + EXPECT_TRUE(iter->second->has_leading_comments()); + EXPECT_EQ(expected_leading_comments, + iter->second->leading_comments()); + } + if (expected_trailing_comments == NULL) { + EXPECT_FALSE(iter->second->has_trailing_comments()); + } else { + EXPECT_TRUE(iter->second->has_trailing_comments()); + EXPECT_EQ(expected_trailing_comments, + iter->second->trailing_comments()); + } + if (expected_leading_detached_comments == NULL) { + EXPECT_EQ(0, iter->second->leading_detached_comments_size()); + } else { + EXPECT_EQ( + expected_leading_detached_comments, + Join(iter->second->leading_detached_comments(), "\n")); + } + + spans_.erase(iter); + return true; + } + } + + return false; + } + } + + private: + struct SpanKey { + const Message* descriptor_proto; + const FieldDescriptor* field; + int index; + + inline SpanKey() {} + inline SpanKey(const Message& descriptor_proto_param, + const FieldDescriptor* field_param, int index_param) + : descriptor_proto(&descriptor_proto_param), + field(field_param), + index(index_param) {} + + inline bool operator<(const SpanKey& other) const { + if (descriptor_proto < other.descriptor_proto) return true; + if (descriptor_proto > other.descriptor_proto) return false; + if (field < other.field) return true; + if (field > other.field) return false; + return index < other.index; + } + }; + + typedef std::multimap<SpanKey, const SourceCodeInfo::Location*> SpanMap; + SpanMap spans_; + std::map<char, std::pair<int, int> > markers_; + std::string text_without_markers_; + + void ExtractMarkers(const char* text) { + markers_.clear(); + text_without_markers_.clear(); + int line = 0; + int column = 0; + while (*text != '\0') { + if (*text == '$') { + ++text; + GOOGLE_CHECK_NE('\0', *text); + if (*text == '$') { + text_without_markers_ += '$'; + ++column; + } else { + markers_[*text] = std::make_pair(line, column); + ++text; + GOOGLE_CHECK_EQ('$', *text); + } + } else if (*text == '\n') { + ++line; + column = 0; + text_without_markers_ += *text; + } else { + text_without_markers_ += *text; + ++column; + } + ++text; + } + } +}; + +TEST_F(SourceInfoTest, BasicFileDecls) { + EXPECT_TRUE( + Parse("$a$syntax = \"proto2\";$i$\n" + "$b$package foo.bar;$c$\n" + "$d$import \"baz.proto\";$e$\n" + "$f$import\"qux.proto\";$h$\n" + "$j$import $k$public$l$ \"bar.proto\";$m$\n" + "$n$import $o$weak$p$ \"bar.proto\";$q$\n" + "\n" + "// comment ignored\n")); + + EXPECT_TRUE(HasSpan('a', 'q', file_)); + EXPECT_TRUE(HasSpan('b', 'c', file_, "package")); + EXPECT_TRUE(HasSpan('d', 'e', file_, "dependency", 0)); + EXPECT_TRUE(HasSpan('f', 'h', file_, "dependency", 1)); + EXPECT_TRUE(HasSpan('j', 'm', file_, "dependency", 2)); + EXPECT_TRUE(HasSpan('k', 'l', file_, "public_dependency", 0)); + EXPECT_TRUE(HasSpan('n', 'q', file_, "dependency", 3)); + EXPECT_TRUE(HasSpan('o', 'p', file_, "weak_dependency", 0)); + EXPECT_TRUE(HasSpan('a', 'i', file_, "syntax")); +} + +TEST_F(SourceInfoTest, Messages) { + EXPECT_TRUE( + Parse("$a$message $b$Foo$c$ {}$d$\n" + "$e$message $f$Bar$g$ {}$h$\n")); + + EXPECT_TRUE(HasSpan('a', 'd', file_.message_type(0))); + EXPECT_TRUE(HasSpan('b', 'c', file_.message_type(0), "name")); + EXPECT_TRUE(HasSpan('e', 'h', file_.message_type(1))); + EXPECT_TRUE(HasSpan('f', 'g', file_.message_type(1), "name")); + + // Ignore these. + EXPECT_TRUE(HasSpan(file_)); +} + +TEST_F(SourceInfoTest, Fields) { + EXPECT_TRUE( + Parse("message Foo {\n" + " $a$optional$b$ $c$int32$d$ $e$bar$f$ = $g$1$h$;$i$\n" + " $j$repeated$k$ $l$X.Y$m$ $n$baz$o$ = $p$2$q$;$r$\n" + "}\n")); + + const FieldDescriptorProto& field1 = file_.message_type(0).field(0); + const FieldDescriptorProto& field2 = file_.message_type(0).field(1); + + EXPECT_TRUE(HasSpan('a', 'i', field1)); + EXPECT_TRUE(HasSpan('a', 'b', field1, "label")); + EXPECT_TRUE(HasSpan('c', 'd', field1, "type")); + EXPECT_TRUE(HasSpan('e', 'f', field1, "name")); + EXPECT_TRUE(HasSpan('g', 'h', field1, "number")); + + EXPECT_TRUE(HasSpan('j', 'r', field2)); + EXPECT_TRUE(HasSpan('j', 'k', field2, "label")); + EXPECT_TRUE(HasSpan('l', 'm', field2, "type_name")); + EXPECT_TRUE(HasSpan('n', 'o', field2, "name")); + EXPECT_TRUE(HasSpan('p', 'q', field2, "number")); + + // Ignore these. + EXPECT_TRUE(HasSpan(file_)); + EXPECT_TRUE(HasSpan(file_.message_type(0))); + EXPECT_TRUE(HasSpan(file_.message_type(0), "name")); +} + +TEST_F(SourceInfoTest, Proto3Fields) { + EXPECT_TRUE( + Parse("syntax = \"proto3\";\n" + "message Foo {\n" + " $a$int32$b$ $c$bar$d$ = $e$1$f$;$g$\n" + " $h$repeated$i$ $j$X.Y$k$ $l$baz$m$ = $n$2$o$;$p$\n" + "}\n")); + + const FieldDescriptorProto& field1 = file_.message_type(0).field(0); + const FieldDescriptorProto& field2 = file_.message_type(0).field(1); + + EXPECT_TRUE(HasSpan('a', 'g', field1)); + EXPECT_TRUE(HasSpan('a', 'b', field1, "type")); + EXPECT_TRUE(HasSpan('c', 'd', field1, "name")); + EXPECT_TRUE(HasSpan('e', 'f', field1, "number")); + + EXPECT_TRUE(HasSpan('h', 'p', field2)); + EXPECT_TRUE(HasSpan('h', 'i', field2, "label")); + EXPECT_TRUE(HasSpan('j', 'k', field2, "type_name")); + EXPECT_TRUE(HasSpan('l', 'm', field2, "name")); + EXPECT_TRUE(HasSpan('n', 'o', field2, "number")); + + // Ignore these. + EXPECT_TRUE(HasSpan(file_)); + EXPECT_TRUE(HasSpan(file_, "syntax")); + EXPECT_TRUE(HasSpan(file_.message_type(0))); + EXPECT_TRUE(HasSpan(file_.message_type(0), "name")); +} + +TEST_F(SourceInfoTest, Extensions) { + EXPECT_TRUE( + Parse("$a$extend $b$Foo$c$ {\n" + " $d$optional$e$ int32 bar = 1;$f$\n" + " $g$repeated$h$ X.Y baz = 2;$i$\n" + "}$j$\n" + "$k$extend $l$Bar$m$ {\n" + " $n$optional int32 qux = 1;$o$\n" + "}$p$\n")); + + const FieldDescriptorProto& field1 = file_.extension(0); + const FieldDescriptorProto& field2 = file_.extension(1); + const FieldDescriptorProto& field3 = file_.extension(2); + + EXPECT_TRUE(HasSpan('a', 'j', file_, "extension")); + EXPECT_TRUE(HasSpan('k', 'p', file_, "extension")); + + EXPECT_TRUE(HasSpan('d', 'f', field1)); + EXPECT_TRUE(HasSpan('d', 'e', field1, "label")); + EXPECT_TRUE(HasSpan('b', 'c', field1, "extendee")); + + EXPECT_TRUE(HasSpan('g', 'i', field2)); + EXPECT_TRUE(HasSpan('g', 'h', field2, "label")); + EXPECT_TRUE(HasSpan('b', 'c', field2, "extendee")); + + EXPECT_TRUE(HasSpan('n', 'o', field3)); + EXPECT_TRUE(HasSpan('l', 'm', field3, "extendee")); + + // Ignore these. + EXPECT_TRUE(HasSpan(file_)); + EXPECT_TRUE(HasSpan(field1, "type")); + EXPECT_TRUE(HasSpan(field1, "name")); + EXPECT_TRUE(HasSpan(field1, "number")); + EXPECT_TRUE(HasSpan(field2, "type_name")); + EXPECT_TRUE(HasSpan(field2, "name")); + EXPECT_TRUE(HasSpan(field2, "number")); + EXPECT_TRUE(HasSpan(field3, "label")); + EXPECT_TRUE(HasSpan(field3, "type")); + EXPECT_TRUE(HasSpan(field3, "name")); + EXPECT_TRUE(HasSpan(field3, "number")); +} + +TEST_F(SourceInfoTest, NestedExtensions) { + EXPECT_TRUE( + Parse("message Message {\n" + " $a$extend $b$Foo$c$ {\n" + " $d$optional$e$ int32 bar = 1;$f$\n" + " $g$repeated$h$ X.Y baz = 2;$i$\n" + " }$j$\n" + " $k$extend $l$Bar$m$ {\n" + " $n$optional int32 qux = 1;$o$\n" + " }$p$\n" + "}\n")); + + const FieldDescriptorProto& field1 = file_.message_type(0).extension(0); + const FieldDescriptorProto& field2 = file_.message_type(0).extension(1); + const FieldDescriptorProto& field3 = file_.message_type(0).extension(2); + + EXPECT_TRUE(HasSpan('a', 'j', file_.message_type(0), "extension")); + EXPECT_TRUE(HasSpan('k', 'p', file_.message_type(0), "extension")); + + EXPECT_TRUE(HasSpan('d', 'f', field1)); + EXPECT_TRUE(HasSpan('d', 'e', field1, "label")); + EXPECT_TRUE(HasSpan('b', 'c', field1, "extendee")); + + EXPECT_TRUE(HasSpan('g', 'i', field2)); + EXPECT_TRUE(HasSpan('g', 'h', field2, "label")); + EXPECT_TRUE(HasSpan('b', 'c', field2, "extendee")); + + EXPECT_TRUE(HasSpan('n', 'o', field3)); + EXPECT_TRUE(HasSpan('l', 'm', field3, "extendee")); + + // Ignore these. + EXPECT_TRUE(HasSpan(file_)); + EXPECT_TRUE(HasSpan(file_.message_type(0))); + EXPECT_TRUE(HasSpan(file_.message_type(0), "name")); + EXPECT_TRUE(HasSpan(field1, "type")); + EXPECT_TRUE(HasSpan(field1, "name")); + EXPECT_TRUE(HasSpan(field1, "number")); + EXPECT_TRUE(HasSpan(field2, "type_name")); + EXPECT_TRUE(HasSpan(field2, "name")); + EXPECT_TRUE(HasSpan(field2, "number")); + EXPECT_TRUE(HasSpan(field3, "label")); + EXPECT_TRUE(HasSpan(field3, "type")); + EXPECT_TRUE(HasSpan(field3, "name")); + EXPECT_TRUE(HasSpan(field3, "number")); +} + +TEST_F(SourceInfoTest, ExtensionRanges) { + EXPECT_TRUE( + Parse("message Message {\n" + " $a$extensions $b$1$c$ to $d$4$e$, $f$6$g$;$h$\n" + " $i$extensions $j$8$k$ to $l$max$m$;$n$\n" + "}\n")); + + const DescriptorProto::ExtensionRange& range1 = + file_.message_type(0).extension_range(0); + const DescriptorProto::ExtensionRange& range2 = + file_.message_type(0).extension_range(1); + const DescriptorProto::ExtensionRange& range3 = + file_.message_type(0).extension_range(2); + + EXPECT_TRUE(HasSpan('a', 'h', file_.message_type(0), "extension_range")); + EXPECT_TRUE(HasSpan('i', 'n', file_.message_type(0), "extension_range")); + + EXPECT_TRUE(HasSpan('b', 'e', range1)); + EXPECT_TRUE(HasSpan('b', 'c', range1, "start")); + EXPECT_TRUE(HasSpan('d', 'e', range1, "end")); + + EXPECT_TRUE(HasSpan('f', 'g', range2)); + EXPECT_TRUE(HasSpan('f', 'g', range2, "start")); + EXPECT_TRUE(HasSpan('f', 'g', range2, "end")); + + EXPECT_TRUE(HasSpan('j', 'm', range3)); + EXPECT_TRUE(HasSpan('j', 'k', range3, "start")); + EXPECT_TRUE(HasSpan('l', 'm', range3, "end")); + + // Ignore these. + EXPECT_TRUE(HasSpan(file_)); + EXPECT_TRUE(HasSpan(file_.message_type(0))); + EXPECT_TRUE(HasSpan(file_.message_type(0), "name")); +} + +TEST_F(SourceInfoTest, ReservedRanges) { + EXPECT_TRUE( + Parse("message Message {\n" + " $a$reserved $b$1$c$ to $d$4$e$, $f$6$g$;$h$\n" + "}\n")); + + const DescriptorProto::ReservedRange& range1 = + file_.message_type(0).reserved_range(0); + const DescriptorProto::ReservedRange& range2 = + file_.message_type(0).reserved_range(1); + + EXPECT_TRUE(HasSpan('a', 'h', file_.message_type(0), "reserved_range")); + + EXPECT_TRUE(HasSpan('b', 'e', range1)); + EXPECT_TRUE(HasSpan('b', 'c', range1, "start")); + EXPECT_TRUE(HasSpan('d', 'e', range1, "end")); + + EXPECT_TRUE(HasSpan('f', 'g', range2)); + EXPECT_TRUE(HasSpan('f', 'g', range2, "start")); + EXPECT_TRUE(HasSpan('f', 'g', range2, "end")); + + // Ignore these. + EXPECT_TRUE(HasSpan(file_)); + EXPECT_TRUE(HasSpan(file_.message_type(0))); + EXPECT_TRUE(HasSpan(file_.message_type(0), "name")); +} + +TEST_F(SourceInfoTest, Oneofs) { + EXPECT_TRUE( + Parse("message Foo {\n" + " $a$oneof $c$foo$d$ {\n" + " $e$int32$f$ $g$a$h$ = $i$1$j$;$k$\n" + " }$r$\n" + "}\n")); + + const OneofDescriptorProto& oneof_decl = file_.message_type(0).oneof_decl(0); + const FieldDescriptorProto& field = file_.message_type(0).field(0); + + EXPECT_TRUE(HasSpan('a', 'r', oneof_decl)); + EXPECT_TRUE(HasSpan('c', 'd', oneof_decl, "name")); + + EXPECT_TRUE(HasSpan('e', 'k', field)); + EXPECT_TRUE(HasSpan('e', 'f', field, "type")); + EXPECT_TRUE(HasSpan('g', 'h', field, "name")); + EXPECT_TRUE(HasSpan('i', 'j', field, "number")); + + // Ignore these. + EXPECT_TRUE(HasSpan(file_)); + EXPECT_TRUE(HasSpan(file_.message_type(0))); + EXPECT_TRUE(HasSpan(file_.message_type(0), "name")); +} + +TEST_F(SourceInfoTest, NestedMessages) { + EXPECT_TRUE( + Parse("message Foo {\n" + " $a$message $b$Bar$c$ {\n" + " $d$message $e$Baz$f$ {}$g$\n" + " }$h$\n" + " $i$message $j$Qux$k$ {}$l$\n" + "}\n")); + + const DescriptorProto& bar = file_.message_type(0).nested_type(0); + const DescriptorProto& baz = bar.nested_type(0); + const DescriptorProto& qux = file_.message_type(0).nested_type(1); + + EXPECT_TRUE(HasSpan('a', 'h', bar)); + EXPECT_TRUE(HasSpan('b', 'c', bar, "name")); + EXPECT_TRUE(HasSpan('d', 'g', baz)); + EXPECT_TRUE(HasSpan('e', 'f', baz, "name")); + EXPECT_TRUE(HasSpan('i', 'l', qux)); + EXPECT_TRUE(HasSpan('j', 'k', qux, "name")); + + // Ignore these. + EXPECT_TRUE(HasSpan(file_)); + EXPECT_TRUE(HasSpan(file_.message_type(0))); + EXPECT_TRUE(HasSpan(file_.message_type(0), "name")); +} + +TEST_F(SourceInfoTest, Groups) { + EXPECT_TRUE( + Parse("message Foo {\n" + " message Bar {}\n" + " $a$optional$b$ $c$group$d$ $e$Baz$f$ = $g$1$h$ {\n" + " $i$message Qux {}$j$\n" + " }$k$\n" + "}\n")); + + const DescriptorProto& bar = file_.message_type(0).nested_type(0); + const DescriptorProto& baz = file_.message_type(0).nested_type(1); + const DescriptorProto& qux = baz.nested_type(0); + const FieldDescriptorProto& field = file_.message_type(0).field(0); + + EXPECT_TRUE(HasSpan('a', 'k', field)); + EXPECT_TRUE(HasSpan('a', 'b', field, "label")); + EXPECT_TRUE(HasSpan('c', 'd', field, "type")); + EXPECT_TRUE(HasSpan('e', 'f', field, "name")); + EXPECT_TRUE(HasSpan('e', 'f', field, "type_name")); + EXPECT_TRUE(HasSpan('g', 'h', field, "number")); + + EXPECT_TRUE(HasSpan('a', 'k', baz)); + EXPECT_TRUE(HasSpan('e', 'f', baz, "name")); + EXPECT_TRUE(HasSpan('i', 'j', qux)); + + // Ignore these. + EXPECT_TRUE(HasSpan(file_)); + EXPECT_TRUE(HasSpan(file_.message_type(0))); + EXPECT_TRUE(HasSpan(file_.message_type(0), "name")); + EXPECT_TRUE(HasSpan(bar)); + EXPECT_TRUE(HasSpan(bar, "name")); + EXPECT_TRUE(HasSpan(qux, "name")); +} + +TEST_F(SourceInfoTest, Enums) { + EXPECT_TRUE( + Parse("$a$enum $b$Foo$c$ {}$d$\n" + "$e$enum $f$Bar$g$ {}$h$\n")); + + EXPECT_TRUE(HasSpan('a', 'd', file_.enum_type(0))); + EXPECT_TRUE(HasSpan('b', 'c', file_.enum_type(0), "name")); + EXPECT_TRUE(HasSpan('e', 'h', file_.enum_type(1))); + EXPECT_TRUE(HasSpan('f', 'g', file_.enum_type(1), "name")); + + // Ignore these. + EXPECT_TRUE(HasSpan(file_)); +} + +TEST_F(SourceInfoTest, EnumValues) { + EXPECT_TRUE( + Parse("enum Foo {\n" + " $a$BAR$b$ = $c$1$d$;$e$\n" + " $f$BAZ$g$ = $h$2$i$;$j$\n" + "}")); + + const EnumValueDescriptorProto& bar = file_.enum_type(0).value(0); + const EnumValueDescriptorProto& baz = file_.enum_type(0).value(1); + + EXPECT_TRUE(HasSpan('a', 'e', bar)); + EXPECT_TRUE(HasSpan('a', 'b', bar, "name")); + EXPECT_TRUE(HasSpan('c', 'd', bar, "number")); + EXPECT_TRUE(HasSpan('f', 'j', baz)); + EXPECT_TRUE(HasSpan('f', 'g', baz, "name")); + EXPECT_TRUE(HasSpan('h', 'i', baz, "number")); + + // Ignore these. + EXPECT_TRUE(HasSpan(file_)); + EXPECT_TRUE(HasSpan(file_.enum_type(0))); + EXPECT_TRUE(HasSpan(file_.enum_type(0), "name")); +} + +TEST_F(SourceInfoTest, EnumReservedRange) { + EXPECT_TRUE( + Parse("enum TestEnum {\n" + " $a$reserved $b$1$c$ to $d$10$e$;$f$\n" + "}")); + + const EnumDescriptorProto::EnumReservedRange& bar = + file_.enum_type(0).reserved_range(0); + + EXPECT_TRUE(HasSpan('a', 'f', file_.enum_type(0), "reserved_range")); + EXPECT_TRUE(HasSpan('b', 'e', bar)); + EXPECT_TRUE(HasSpan('b', 'c', bar, "start")); + EXPECT_TRUE(HasSpan('d', 'e', bar, "end")); + + // Ignore these. + EXPECT_TRUE(HasSpan(file_)); + EXPECT_TRUE(HasSpan(file_.enum_type(0))); + EXPECT_TRUE(HasSpan(file_.enum_type(0), "name")); +} + +TEST_F(SourceInfoTest, EnumReservedName) { + EXPECT_TRUE( + Parse("enum TestEnum {\n" + " $a$reserved $b$'foo'$c$;$d$\n" + "}")); + + const EnumDescriptorProto& bar = file_.enum_type(0); + + EXPECT_TRUE(HasSpan('a', 'd', bar, "reserved_name")); + EXPECT_TRUE(HasSpan('b', 'c', bar, "reserved_name", 0)); + + // Ignore these. + EXPECT_TRUE(HasSpan(file_)); + EXPECT_TRUE(HasSpan(file_.enum_type(0))); + EXPECT_TRUE(HasSpan(file_.enum_type(0), "name")); +} + +TEST_F(SourceInfoTest, NestedEnums) { + EXPECT_TRUE( + Parse("message Foo {\n" + " $a$enum $b$Bar$c$ {}$d$\n" + " $e$enum $f$Baz$g$ {}$h$\n" + "}\n")); + + const EnumDescriptorProto& bar = file_.message_type(0).enum_type(0); + const EnumDescriptorProto& baz = file_.message_type(0).enum_type(1); + + EXPECT_TRUE(HasSpan('a', 'd', bar)); + EXPECT_TRUE(HasSpan('b', 'c', bar, "name")); + EXPECT_TRUE(HasSpan('e', 'h', baz)); + EXPECT_TRUE(HasSpan('f', 'g', baz, "name")); + + // Ignore these. + EXPECT_TRUE(HasSpan(file_)); + EXPECT_TRUE(HasSpan(file_.message_type(0))); + EXPECT_TRUE(HasSpan(file_.message_type(0), "name")); +} + +TEST_F(SourceInfoTest, Services) { + EXPECT_TRUE( + Parse("$a$service $b$Foo$c$ {}$d$\n" + "$e$service $f$Bar$g$ {}$h$\n")); + + EXPECT_TRUE(HasSpan('a', 'd', file_.service(0))); + EXPECT_TRUE(HasSpan('b', 'c', file_.service(0), "name")); + EXPECT_TRUE(HasSpan('e', 'h', file_.service(1))); + EXPECT_TRUE(HasSpan('f', 'g', file_.service(1), "name")); + + // Ignore these. + EXPECT_TRUE(HasSpan(file_)); +} + +TEST_F(SourceInfoTest, MethodsAndStreams) { + EXPECT_TRUE( + Parse("service Foo {\n" + " $a$rpc $b$Bar$c$($d$X$e$) returns($f$Y$g$);$h$" + " $i$rpc $j$Baz$k$($l$Z$m$) returns($n$W$o$);$p$" + "}")); + + const MethodDescriptorProto& bar = file_.service(0).method(0); + const MethodDescriptorProto& baz = file_.service(0).method(1); + + EXPECT_TRUE(HasSpan('a', 'h', bar)); + EXPECT_TRUE(HasSpan('b', 'c', bar, "name")); + EXPECT_TRUE(HasSpan('d', 'e', bar, "input_type")); + EXPECT_TRUE(HasSpan('f', 'g', bar, "output_type")); + + EXPECT_TRUE(HasSpan('i', 'p', baz)); + EXPECT_TRUE(HasSpan('j', 'k', baz, "name")); + EXPECT_TRUE(HasSpan('l', 'm', baz, "input_type")); + EXPECT_TRUE(HasSpan('n', 'o', baz, "output_type")); + + // Ignore these. + EXPECT_TRUE(HasSpan(file_)); + EXPECT_TRUE(HasSpan(file_.service(0))); + EXPECT_TRUE(HasSpan(file_.service(0), "name")); +} + + +TEST_F(SourceInfoTest, Options) { + EXPECT_TRUE( + Parse("$a$option $b$foo$c$.$d$($e$bar.baz$f$)$g$ = " + "$h$123$i$;$j$\n" + "$k$option qux = $l$-123$m$;$n$\n" + "$o$option corge = $p$abc$q$;$r$\n" + "$s$option grault = $t$'blah'$u$;$v$\n" + "$w$option garply = $x${ yadda yadda }$y$;$z$\n" + "$0$option waldo = $1$123.0$2$;$3$\n")); + + const UninterpretedOption& option1 = file_.options().uninterpreted_option(0); + const UninterpretedOption& option2 = file_.options().uninterpreted_option(1); + const UninterpretedOption& option3 = file_.options().uninterpreted_option(2); + const UninterpretedOption& option4 = file_.options().uninterpreted_option(3); + const UninterpretedOption& option5 = file_.options().uninterpreted_option(4); + const UninterpretedOption& option6 = file_.options().uninterpreted_option(5); + + EXPECT_TRUE(HasSpan('a', 'j', file_.options())); + EXPECT_TRUE(HasSpan('a', 'j', option1)); + EXPECT_TRUE(HasSpan('b', 'g', option1, "name")); + EXPECT_TRUE(HasSpan('b', 'c', option1.name(0))); + EXPECT_TRUE(HasSpan('b', 'c', option1.name(0), "name_part")); + EXPECT_TRUE(HasSpan('d', 'g', option1.name(1))); + EXPECT_TRUE(HasSpan('e', 'f', option1.name(1), "name_part")); + EXPECT_TRUE(HasSpan('h', 'i', option1, "positive_int_value")); + + EXPECT_TRUE(HasSpan('k', 'n', file_.options())); + EXPECT_TRUE(HasSpan('l', 'm', option2, "negative_int_value")); + + EXPECT_TRUE(HasSpan('o', 'r', file_.options())); + EXPECT_TRUE(HasSpan('p', 'q', option3, "identifier_value")); + + EXPECT_TRUE(HasSpan('s', 'v', file_.options())); + EXPECT_TRUE(HasSpan('t', 'u', option4, "string_value")); + + EXPECT_TRUE(HasSpan('w', 'z', file_.options())); + EXPECT_TRUE(HasSpan('x', 'y', option5, "aggregate_value")); + + EXPECT_TRUE(HasSpan('0', '3', file_.options())); + EXPECT_TRUE(HasSpan('1', '2', option6, "double_value")); + + // Ignore these. + EXPECT_TRUE(HasSpan(file_)); + EXPECT_TRUE(HasSpan(option2)); + EXPECT_TRUE(HasSpan(option3)); + EXPECT_TRUE(HasSpan(option4)); + EXPECT_TRUE(HasSpan(option5)); + EXPECT_TRUE(HasSpan(option6)); + EXPECT_TRUE(HasSpan(option2, "name")); + EXPECT_TRUE(HasSpan(option3, "name")); + EXPECT_TRUE(HasSpan(option4, "name")); + EXPECT_TRUE(HasSpan(option5, "name")); + EXPECT_TRUE(HasSpan(option6, "name")); + EXPECT_TRUE(HasSpan(option2.name(0))); + EXPECT_TRUE(HasSpan(option3.name(0))); + EXPECT_TRUE(HasSpan(option4.name(0))); + EXPECT_TRUE(HasSpan(option5.name(0))); + EXPECT_TRUE(HasSpan(option6.name(0))); + EXPECT_TRUE(HasSpan(option2.name(0), "name_part")); + EXPECT_TRUE(HasSpan(option3.name(0), "name_part")); + EXPECT_TRUE(HasSpan(option4.name(0), "name_part")); + EXPECT_TRUE(HasSpan(option5.name(0), "name_part")); + EXPECT_TRUE(HasSpan(option6.name(0), "name_part")); +} + +TEST_F(SourceInfoTest, ScopedOptions) { + EXPECT_TRUE( + Parse("message Foo {\n" + " $a$option mopt = 1;$b$\n" + "}\n" + "enum Bar {\n" + " $c$option eopt = 1;$d$\n" + "}\n" + "service Baz {\n" + " $e$option sopt = 1;$f$\n" + " rpc M(X) returns(Y) {\n" + " $g$option mopt = 1;$h$\n" + " }\n" + " rpc MS4($1$stream$2$ X) returns($3$stream$4$ Y) {\n" + " $k$option mopt = 1;$l$\n" + " }\n" + "}\n")); + + EXPECT_TRUE(HasSpan('a', 'b', file_.message_type(0).options())); + EXPECT_TRUE(HasSpan('c', 'd', file_.enum_type(0).options())); + EXPECT_TRUE(HasSpan('e', 'f', file_.service(0).options())); + EXPECT_TRUE(HasSpan('g', 'h', file_.service(0).method(0).options())); + + // Ignore these. + EXPECT_TRUE(HasSpan(file_)); + EXPECT_TRUE(HasSpan(file_.message_type(0))); + EXPECT_TRUE(HasSpan(file_.message_type(0), "name")); + EXPECT_TRUE(HasSpan(file_.message_type(0).options().uninterpreted_option(0))); + EXPECT_TRUE( + HasSpan(file_.message_type(0).options().uninterpreted_option(0), "name")); + EXPECT_TRUE( + HasSpan(file_.message_type(0).options().uninterpreted_option(0).name(0))); + EXPECT_TRUE( + HasSpan(file_.message_type(0).options().uninterpreted_option(0).name(0), + "name_part")); + EXPECT_TRUE(HasSpan(file_.message_type(0).options().uninterpreted_option(0), + "positive_int_value")); + EXPECT_TRUE(HasSpan(file_.enum_type(0))); + EXPECT_TRUE(HasSpan(file_.enum_type(0), "name")); + EXPECT_TRUE(HasSpan(file_.enum_type(0).options().uninterpreted_option(0))); + EXPECT_TRUE( + HasSpan(file_.enum_type(0).options().uninterpreted_option(0), "name")); + EXPECT_TRUE( + HasSpan(file_.enum_type(0).options().uninterpreted_option(0).name(0))); + EXPECT_TRUE( + HasSpan(file_.enum_type(0).options().uninterpreted_option(0).name(0), + "name_part")); + EXPECT_TRUE(HasSpan(file_.enum_type(0).options().uninterpreted_option(0), + "positive_int_value")); + EXPECT_TRUE(HasSpan(file_.service(0))); + EXPECT_TRUE(HasSpan(file_.service(0), "name")); + EXPECT_TRUE(HasSpan(file_.service(0).method(0))); + EXPECT_TRUE(HasSpan(file_.service(0).options().uninterpreted_option(0))); + EXPECT_TRUE( + HasSpan(file_.service(0).options().uninterpreted_option(0), "name")); + EXPECT_TRUE( + HasSpan(file_.service(0).options().uninterpreted_option(0).name(0))); + EXPECT_TRUE(HasSpan( + file_.service(0).options().uninterpreted_option(0).name(0), "name_part")); + EXPECT_TRUE(HasSpan(file_.service(0).options().uninterpreted_option(0), + "positive_int_value")); + EXPECT_TRUE(HasSpan(file_.service(0).method(0), "name")); + EXPECT_TRUE(HasSpan(file_.service(0).method(0), "input_type")); + EXPECT_TRUE(HasSpan(file_.service(0).method(0), "output_type")); + EXPECT_TRUE( + HasSpan(file_.service(0).method(0).options().uninterpreted_option(0))); + EXPECT_TRUE(HasSpan( + file_.service(0).method(0).options().uninterpreted_option(0), "name")); + EXPECT_TRUE(HasSpan( + file_.service(0).method(0).options().uninterpreted_option(0).name(0))); + EXPECT_TRUE(HasSpan( + file_.service(0).method(0).options().uninterpreted_option(0).name(0), + "name_part")); + EXPECT_TRUE( + HasSpan(file_.service(0).method(0).options().uninterpreted_option(0), + "positive_int_value")); + + EXPECT_TRUE(HasSpan('k', 'l', file_.service(0).method(1).options())); + EXPECT_TRUE(HasSpan(file_.service(0).method(1))); + EXPECT_TRUE(HasSpan(file_.service(0).method(1), "name")); + EXPECT_TRUE(HasSpan(file_.service(0).method(1), "input_type")); + EXPECT_TRUE(HasSpan(file_.service(0).method(1), "output_type")); + EXPECT_TRUE( + HasSpan(file_.service(0).method(1).options().uninterpreted_option(0))); + EXPECT_TRUE(HasSpan( + file_.service(0).method(1).options().uninterpreted_option(0), "name")); + EXPECT_TRUE(HasSpan( + file_.service(0).method(1).options().uninterpreted_option(0).name(0))); + EXPECT_TRUE(HasSpan( + file_.service(0).method(1).options().uninterpreted_option(0).name(0), + "name_part")); + EXPECT_TRUE( + HasSpan(file_.service(0).method(1).options().uninterpreted_option(0), + "positive_int_value")); + EXPECT_TRUE( + HasSpan('1', '2', file_.service(0).method(1), "client_streaming")); + EXPECT_TRUE( + HasSpan('3', '4', file_.service(0).method(1), "server_streaming")); +} + +TEST_F(SourceInfoTest, FieldOptions) { + // The actual "name = value" pairs are parsed by the same code as for + // top-level options so we won't re-test that -- just make sure that the + // syntax used for field options is understood. + EXPECT_TRUE( + Parse("message Foo {" + " optional int32 bar = 1 " + "$a$[default=$b$123$c$,$d$opt1=123$e$," + "$f$opt2='hi'$g$]$h$;" + "}\n")); + + const FieldDescriptorProto& field = file_.message_type(0).field(0); + const UninterpretedOption& option1 = field.options().uninterpreted_option(0); + const UninterpretedOption& option2 = field.options().uninterpreted_option(1); + + EXPECT_TRUE(HasSpan('a', 'h', field.options())); + EXPECT_TRUE(HasSpan('b', 'c', field, "default_value")); + EXPECT_TRUE(HasSpan('d', 'e', option1)); + EXPECT_TRUE(HasSpan('f', 'g', option2)); + + // Ignore these. + EXPECT_TRUE(HasSpan(file_)); + EXPECT_TRUE(HasSpan(file_.message_type(0))); + EXPECT_TRUE(HasSpan(file_.message_type(0), "name")); + EXPECT_TRUE(HasSpan(field)); + EXPECT_TRUE(HasSpan(field, "label")); + EXPECT_TRUE(HasSpan(field, "type")); + EXPECT_TRUE(HasSpan(field, "name")); + EXPECT_TRUE(HasSpan(field, "number")); + EXPECT_TRUE(HasSpan(option1, "name")); + EXPECT_TRUE(HasSpan(option2, "name")); + EXPECT_TRUE(HasSpan(option1.name(0))); + EXPECT_TRUE(HasSpan(option2.name(0))); + EXPECT_TRUE(HasSpan(option1.name(0), "name_part")); + EXPECT_TRUE(HasSpan(option2.name(0), "name_part")); + EXPECT_TRUE(HasSpan(option1, "positive_int_value")); + EXPECT_TRUE(HasSpan(option2, "string_value")); +} + +TEST_F(SourceInfoTest, EnumValueOptions) { + // The actual "name = value" pairs are parsed by the same code as for + // top-level options so we won't re-test that -- just make sure that the + // syntax used for enum options is understood. + EXPECT_TRUE( + Parse("enum Foo {" + " BAR = 1 $a$[$b$opt1=123$c$,$d$opt2='hi'$e$]$f$;" + "}\n")); + + const EnumValueDescriptorProto& value = file_.enum_type(0).value(0); + const UninterpretedOption& option1 = value.options().uninterpreted_option(0); + const UninterpretedOption& option2 = value.options().uninterpreted_option(1); + + EXPECT_TRUE(HasSpan('a', 'f', value.options())); + EXPECT_TRUE(HasSpan('b', 'c', option1)); + EXPECT_TRUE(HasSpan('d', 'e', option2)); + + // Ignore these. + EXPECT_TRUE(HasSpan(file_)); + EXPECT_TRUE(HasSpan(file_.enum_type(0))); + EXPECT_TRUE(HasSpan(file_.enum_type(0), "name")); + EXPECT_TRUE(HasSpan(value)); + EXPECT_TRUE(HasSpan(value, "name")); + EXPECT_TRUE(HasSpan(value, "number")); + EXPECT_TRUE(HasSpan(option1, "name")); + EXPECT_TRUE(HasSpan(option2, "name")); + EXPECT_TRUE(HasSpan(option1.name(0))); + EXPECT_TRUE(HasSpan(option2.name(0))); + EXPECT_TRUE(HasSpan(option1.name(0), "name_part")); + EXPECT_TRUE(HasSpan(option2.name(0), "name_part")); + EXPECT_TRUE(HasSpan(option1, "positive_int_value")); + EXPECT_TRUE(HasSpan(option2, "string_value")); +} + +TEST_F(SourceInfoTest, DocComments) { + EXPECT_TRUE( + Parse("// Foo leading\n" + "// line 2\n" + "$a$message Foo {\n" + " // Foo trailing\n" + " // line 2\n" + "\n" + " // detached\n" + "\n" + " // bar leading\n" + " $b$optional int32 bar = 1;$c$\n" + " // bar trailing\n" + "}$d$\n" + "// ignored\n")); + + const DescriptorProto& foo = file_.message_type(0); + const FieldDescriptorProto& bar = foo.field(0); + + EXPECT_TRUE(HasSpanWithComment('a', 'd', foo, " Foo leading\n line 2\n", + " Foo trailing\n line 2\n", NULL)); + EXPECT_TRUE(HasSpanWithComment('b', 'c', bar, " bar leading\n", + " bar trailing\n", " detached\n")); + + // Ignore these. + EXPECT_TRUE(HasSpan(file_)); + EXPECT_TRUE(HasSpan(foo, "name")); + EXPECT_TRUE(HasSpan(bar, "label")); + EXPECT_TRUE(HasSpan(bar, "type")); + EXPECT_TRUE(HasSpan(bar, "name")); + EXPECT_TRUE(HasSpan(bar, "number")); +} + +TEST_F(SourceInfoTest, DocComments2) { + EXPECT_TRUE( + Parse("// detached before message.\n" + "\n" + "// Foo leading\n" + "// line 2\n" + "$a$message Foo {\n" + " /* Foo trailing\n" + " * line 2 */\n" + " // detached\n" + " /* bar leading\n" + " */" + " $b$optional int32 bar = 1;$c$ // bar trailing\n" + " // ignored detached\n" + "}$d$\n" + "// ignored\n" + "\n" + "// detached before option\n" + "\n" + "// option leading\n" + "$e$option baz = 123;$f$\n" + "// option trailing\n")); + + const DescriptorProto& foo = file_.message_type(0); + const FieldDescriptorProto& bar = foo.field(0); + const UninterpretedOption& baz = file_.options().uninterpreted_option(0); + + EXPECT_TRUE(HasSpanWithComment('a', 'd', foo, " Foo leading\n line 2\n", + " Foo trailing\n line 2 ", + " detached before message.\n")); + EXPECT_TRUE(HasSpanWithComment('b', 'c', bar, " bar leading\n", + " bar trailing\n", " detached\n")); + EXPECT_TRUE(HasSpanWithComment('e', 'f', baz, " option leading\n", + " option trailing\n", + " detached before option\n")); + + // Ignore these. + EXPECT_TRUE(HasSpan(file_)); + EXPECT_TRUE(HasSpan(foo, "name")); + EXPECT_TRUE(HasSpan(bar, "label")); + EXPECT_TRUE(HasSpan(bar, "type")); + EXPECT_TRUE(HasSpan(bar, "name")); + EXPECT_TRUE(HasSpan(bar, "number")); + EXPECT_TRUE(HasSpan(file_.options())); + EXPECT_TRUE(HasSpan(baz, "name")); + EXPECT_TRUE(HasSpan(baz.name(0))); + EXPECT_TRUE(HasSpan(baz.name(0), "name_part")); + EXPECT_TRUE(HasSpan(baz, "positive_int_value")); +} + +TEST_F(SourceInfoTest, DocComments3) { + EXPECT_TRUE( + Parse("$a$message Foo {\n" + " // bar leading\n" + " $b$optional int32 bar = 1 [(baz.qux) = {}];$c$\n" + " // bar trailing\n" + "}$d$\n" + "// ignored\n")); + + const DescriptorProto& foo = file_.message_type(0); + const FieldDescriptorProto& bar = foo.field(0); + + EXPECT_TRUE(HasSpanWithComment('b', 'c', bar, " bar leading\n", + " bar trailing\n", NULL)); + + // Ignore these. + EXPECT_TRUE(HasSpan(file_)); + EXPECT_TRUE(HasSpan(foo)); + EXPECT_TRUE(HasSpan(foo, "name")); + EXPECT_TRUE(HasSpan(bar, "label")); + EXPECT_TRUE(HasSpan(bar, "type")); + EXPECT_TRUE(HasSpan(bar, "name")); + EXPECT_TRUE(HasSpan(bar, "number")); + EXPECT_TRUE(HasSpan(bar.options())); + EXPECT_TRUE(HasSpan(bar.options().uninterpreted_option(0))); + EXPECT_TRUE(HasSpan(bar.options().uninterpreted_option(0), "name")); + EXPECT_TRUE(HasSpan(bar.options().uninterpreted_option(0).name(0))); + EXPECT_TRUE( + HasSpan(bar.options().uninterpreted_option(0).name(0), "name_part")); + EXPECT_TRUE( + HasSpan(bar.options().uninterpreted_option(0), "aggregate_value")); +} + +TEST_F(SourceInfoTest, DocCommentsTopLevel) { + EXPECT_TRUE( + Parse("// detached before syntax paragraph 1\n" + "\n" + "// detached before syntax paragraph 2\n" + "\n" + "// syntax leading\n" + "$a$syntax = \"proto2\";$b$\n" + "// syntax trailing\n" + "\n" + "// syntax-package detached comments\n" + "\n" + ";\n" + "\n" + "// detached after empty before package\n" + "\n" + "// package leading\n" + "$c$package foo;$d$\n" + "// package trailing\n" + "\n" + "// ignored detach\n" + "\n")); + + EXPECT_TRUE(HasSpan('a', 'b', file_, "syntax", -1, " syntax leading\n", + " syntax trailing\n", + " detached before syntax paragraph 1\n" + "\n" + " detached before syntax paragraph 2\n")); + EXPECT_TRUE(HasSpan('c', 'd', file_, "package", -1, " package leading\n", + " package trailing\n", + " syntax-package detached comments\n" + "\n" + " detached after empty before package\n")); + + // ignore these. + EXPECT_TRUE(HasSpan(file_)); +} + +TEST_F(SourceInfoTest, DocCommentsOneof) { + EXPECT_TRUE( + Parse("// Foo leading\n" + "$a$message Foo {\n" + " /* Foo trailing\n" + " */\n" + " // detached before oneof\n" + " /* bar leading\n" + " * line 2 */\n" + " $b$oneof bar {\n" + " /* bar trailing\n" + " * line 2 */\n" + " // detached before bar_int\n" + " /* bar_int leading\n" + " */\n" + " $c$int32 bar_int = 1;$d$ // bar_int trailing\n" + " // detach comment ignored\n" + " }$e$\n" + "}$f$\n")); + + const DescriptorProto& foo = file_.message_type(0); + const OneofDescriptorProto& bar = foo.oneof_decl(0); + const FieldDescriptorProto& bar_int = foo.field(0); + + EXPECT_TRUE(HasSpanWithComment('a', 'f', foo, " Foo leading\n", + " Foo trailing\n", NULL)); + EXPECT_TRUE(HasSpanWithComment('b', 'e', bar, " bar leading\n line 2 ", + " bar trailing\n line 2 ", + " detached before oneof\n")); + EXPECT_TRUE(HasSpanWithComment('c', 'd', bar_int, " bar_int leading\n", + " bar_int trailing\n", + " detached before bar_int\n")); + + // Ignore these. + EXPECT_TRUE(HasSpan(file_)); + EXPECT_TRUE(HasSpan(foo, "name")); + EXPECT_TRUE(HasSpan(bar, "name")); + EXPECT_TRUE(HasSpan(bar_int, "type")); + EXPECT_TRUE(HasSpan(bar_int, "name")); + EXPECT_TRUE(HasSpan(bar_int, "number")); +} + +// =================================================================== + +} // anonymous namespace + +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/php/php_generator.cc b/NorthstarDedicatedTest/include/protobuf/compiler/php/php_generator.cc new file mode 100644 index 00000000..31914f38 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/php/php_generator.cc @@ -0,0 +1,2325 @@ +// 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 <compiler/php/php_generator.h> + +#include <compiler/code_generator.h> +#include <compiler/plugin.h> +#include <descriptor.h> +#include <descriptor.pb.h> +#include <io/printer.h> +#include <io/zero_copy_stream.h> +#include <stubs/strutil.h> + +#include <sstream> + +const std::string kDescriptorFile = "google/protobuf/descriptor.proto"; +const std::string kEmptyFile = "google/protobuf/empty.proto"; +const std::string kEmptyMetadataFile = "GPBMetadata/Google/Protobuf/GPBEmpty.php"; +const std::string kDescriptorMetadataFile = + "GPBMetadata/Google/Protobuf/Internal/Descriptor.php"; +const std::string kDescriptorDirName = "Google/Protobuf/Internal"; +const std::string kDescriptorPackageName = "Google\\Protobuf\\Internal"; +const char* const kReservedNames[] = { + "abstract", "and", "array", "as", "break", + "callable", "case", "catch", "class", "clone", + "const", "continue", "declare", "default", "die", + "do", "echo", "else", "elseif", "empty", + "enddeclare", "endfor", "endforeach", "endif", "endswitch", + "endwhile", "eval", "exit", "extends", "final", + "finally", "fn", "for", "foreach", "function", + "global", "goto", "if", "implements", "include", + "include_once", "instanceof", "insteadof", "interface", "isset", + "list", "match", "namespace", "new", "or", + "print", "private", "protected", "public", "require", + "require_once", "return", "static", "switch", "throw", + "trait", "try", "unset", "use", "var", + "while", "xor", "yield", "int", "float", + "bool", "string", "true", "false", "null", + "void", "iterable"}; +const char* const kValidConstantNames[] = { + "int", "float", "bool", "string", "true", + "false", "null", "void", "iterable", +}; +const int kReservedNamesSize = 77; +const int kValidConstantNamesSize = 9; +const int kFieldSetter = 1; +const int kFieldGetter = 2; +const int kFieldProperty = 3; + +namespace google { +namespace protobuf { +namespace compiler { +namespace php { + +struct Options { + bool is_descriptor = false; + bool aggregate_metadata = false; + bool gen_c_wkt = false; + std::set<string> aggregate_metadata_prefixes; +}; + +namespace { + +// Forward decls. +std::string PhpName(const std::string& full_name, const Options& options); +std::string IntToString(int32 value); +std::string FilenameToClassname(const std::string& filename); +std::string GeneratedMetadataFileName(const FileDescriptor* file, + const Options& options); +std::string UnderscoresToCamelCase(const std::string& name, + bool cap_first_letter); +void Indent(io::Printer* printer); +void Outdent(io::Printer* printer); +void GenerateAddFilesToPool(const FileDescriptor* file, const Options& options, + io::Printer* printer); +void GenerateMessageDocComment(io::Printer* printer, const Descriptor* message, + const Options& options); +void GenerateMessageConstructorDocComment(io::Printer* printer, + const Descriptor* message, + const Options& options); +void GenerateFieldDocComment(io::Printer* printer, const FieldDescriptor* field, + const Options& options, int function_type); +void GenerateWrapperFieldGetterDocComment(io::Printer* printer, + const FieldDescriptor* field); +void GenerateWrapperFieldSetterDocComment(io::Printer* printer, + const FieldDescriptor* field); +void GenerateEnumDocComment(io::Printer* printer, const EnumDescriptor* enum_, + const Options& options); +void GenerateEnumValueDocComment(io::Printer* printer, + const EnumValueDescriptor* value); +void GenerateServiceDocComment(io::Printer* printer, + const ServiceDescriptor* service); +void GenerateServiceMethodDocComment(io::Printer* printer, + const MethodDescriptor* method); + +std::string ReservedNamePrefix(const std::string& classname, + const FileDescriptor* file) { + bool is_reserved = false; + + std::string lower = classname; + std::transform(lower.begin(), lower.end(), lower.begin(), ::tolower); + + for (int i = 0; i < kReservedNamesSize; i++) { + if (lower == kReservedNames[i]) { + is_reserved = true; + break; + } + } + + if (is_reserved) { + if (file->package() == "google.protobuf") { + return "GPB"; + } else { + return "PB"; + } + } + + return ""; +} + +template <typename DescriptorType> +std::string DescriptorFullName(const DescriptorType* desc, bool is_internal) { + if (is_internal) { + return StringReplace(desc->full_name(), + "google.protobuf", + "google.protobuf.internal", false); + } else { + return desc->full_name(); + } +} + +template <typename DescriptorType> +std::string ClassNamePrefix(const std::string& classname, + const DescriptorType* desc) { + const std::string& prefix = (desc->file()->options()).php_class_prefix(); + if (!prefix.empty()) { + return prefix; + } + + return ReservedNamePrefix(classname, desc->file()); +} + +template <typename DescriptorType> +std::string GeneratedClassNameImpl(const DescriptorType* desc) { + std::string classname = ClassNamePrefix(desc->name(), desc) + desc->name(); + const Descriptor* containing = desc->containing_type(); + while (containing != NULL) { + classname = ClassNamePrefix(containing->name(), desc) + containing->name() + + '\\' + classname; + containing = containing->containing_type(); + } + return classname; +} + +std::string GeneratedClassNameImpl(const ServiceDescriptor* desc) { + std::string classname = desc->name(); + return ClassNamePrefix(classname, desc) + classname; +} + +template <typename DescriptorType> +std::string LegacyGeneratedClassName(const DescriptorType* desc) { + std::string classname = desc->name(); + const Descriptor* containing = desc->containing_type(); + while (containing != NULL) { + classname = containing->name() + '_' + classname; + containing = containing->containing_type(); + } + return ClassNamePrefix(classname, desc) + classname; +} + +std::string ClassNamePrefix(const std::string& classname) { + std::string lower = classname; + std::transform(lower.begin(), lower.end(), lower.begin(), ::tolower); + + for (int i = 0; i < kReservedNamesSize; i++) { + if (lower == kReservedNames[i]) { + return "PB"; + } + } + + return ""; +} + +std::string ConstantNamePrefix(const std::string& classname) { + bool is_reserved = false; + + std::string lower = classname; + std::transform(lower.begin(), lower.end(), lower.begin(), ::tolower); + + for (int i = 0; i < kReservedNamesSize; i++) { + if (lower == kReservedNames[i]) { + is_reserved = true; + break; + } + } + + for (int i = 0; i < kValidConstantNamesSize; i++) { + if (lower == kValidConstantNames[i]) { + is_reserved = false; + break; + } + } + + if (is_reserved) { + return "PB"; + } + + return ""; +} + +template <typename DescriptorType> +std::string RootPhpNamespace(const DescriptorType* desc, + const Options& options) { + if (desc->file()->options().has_php_namespace()) { + const std::string& php_namespace = desc->file()->options().php_namespace(); + if (!php_namespace.empty()) { + return php_namespace; + } + return ""; + } + + if (!desc->file()->package().empty()) { + return PhpName(desc->file()->package(), options); + } + return ""; +} + +template <typename DescriptorType> +std::string FullClassName(const DescriptorType* desc, const Options& options) { + std::string classname = GeneratedClassNameImpl(desc); + std::string php_namespace = RootPhpNamespace(desc, options); + if (!php_namespace.empty()) { + return php_namespace + "\\" + classname; + } + return classname; +} + +template <typename DescriptorType> +std::string FullClassName(const DescriptorType* desc, bool is_descriptor) { + Options options; + options.is_descriptor = is_descriptor; + return FullClassName(desc, options); +} + +template <typename DescriptorType> +std::string LegacyFullClassName(const DescriptorType* desc, + const Options& options) { + std::string classname = LegacyGeneratedClassName(desc); + std::string php_namespace = RootPhpNamespace(desc, options); + if (!php_namespace.empty()) { + return php_namespace + "\\" + classname; + } + return classname; +} + +std::string PhpName(const std::string& full_name, const Options& options) { + if (options.is_descriptor) { + return kDescriptorPackageName; + } + + std::string segment; + std::string result; + bool cap_next_letter = true; + for (int i = 0; i < full_name.size(); i++) { + if ('a' <= full_name[i] && full_name[i] <= 'z' && cap_next_letter) { + segment += full_name[i] + ('A' - 'a'); + cap_next_letter = false; + } else if (full_name[i] == '.') { + result += ClassNamePrefix(segment) + segment + '\\'; + segment = ""; + cap_next_letter = true; + } else { + segment += full_name[i]; + cap_next_letter = false; + } + } + result += ClassNamePrefix(segment) + segment; + return result; +} + +std::string DefaultForField(const FieldDescriptor* field) { + switch (field->type()) { + case FieldDescriptor::TYPE_INT32: + case FieldDescriptor::TYPE_INT64: + case FieldDescriptor::TYPE_UINT32: + case FieldDescriptor::TYPE_UINT64: + case FieldDescriptor::TYPE_SINT32: + case FieldDescriptor::TYPE_SINT64: + case FieldDescriptor::TYPE_FIXED32: + case FieldDescriptor::TYPE_FIXED64: + case FieldDescriptor::TYPE_SFIXED32: + case FieldDescriptor::TYPE_SFIXED64: + case FieldDescriptor::TYPE_ENUM: return "0"; + case FieldDescriptor::TYPE_DOUBLE: + case FieldDescriptor::TYPE_FLOAT: return "0.0"; + case FieldDescriptor::TYPE_BOOL: return "false"; + case FieldDescriptor::TYPE_STRING: + case FieldDescriptor::TYPE_BYTES: return "''"; + case FieldDescriptor::TYPE_MESSAGE: + case FieldDescriptor::TYPE_GROUP: return "null"; + default: assert(false); return ""; + } +} + +std::string GeneratedMetadataFileName(const FileDescriptor* file, + const Options& options) { + const std::string& proto_file = file->name(); + int start_index = 0; + int first_index = proto_file.find_first_of("/", start_index); + std::string result = ""; + std::string segment = ""; + + if (proto_file == kEmptyFile) { + return kEmptyMetadataFile; + } + if (options.is_descriptor) { + return kDescriptorMetadataFile; + } + + // Append directory name. + std::string file_no_suffix; + int lastindex = proto_file.find_last_of("."); + if (proto_file == kEmptyFile) { + return kEmptyMetadataFile; + } else { + file_no_suffix = proto_file.substr(0, lastindex); + } + + if (file->options().has_php_metadata_namespace()) { + const std::string& php_metadata_namespace = + file->options().php_metadata_namespace(); + if (!php_metadata_namespace.empty() && php_metadata_namespace != "\\") { + result += php_metadata_namespace; + std::replace(result.begin(), result.end(), '\\', '/'); + if (result.at(result.size() - 1) != '/') { + result += "/"; + } + } + } else { + result += "GPBMetadata/"; + while (first_index != std::string::npos) { + segment = UnderscoresToCamelCase( + file_no_suffix.substr(start_index, first_index - start_index), true); + result += ReservedNamePrefix(segment, file) + segment + "/"; + start_index = first_index + 1; + first_index = file_no_suffix.find_first_of("/", start_index); + } + } + + // Append file name. + int file_name_start = file_no_suffix.find_last_of("/"); + if (file_name_start == std::string::npos) { + file_name_start = 0; + } else { + file_name_start += 1; + } + segment = UnderscoresToCamelCase( + file_no_suffix.substr(file_name_start, first_index - file_name_start), true); + + return result + ReservedNamePrefix(segment, file) + segment + ".php"; +} + +std::string GeneratedMetadataFileName(const FileDescriptor* file, + bool is_descriptor) { + Options options; + options.is_descriptor = is_descriptor; + return GeneratedMetadataFileName(file, options); +} + +template <typename DescriptorType> +std::string GeneratedClassFileName(const DescriptorType* desc, + const Options& options) { + std::string result = FullClassName(desc, options); + for (int i = 0; i < result.size(); i++) { + if (result[i] == '\\') { + result[i] = '/'; + } + } + return result + ".php"; +} + +template <typename DescriptorType> +std::string LegacyGeneratedClassFileName(const DescriptorType* desc, + const Options& options) { + std::string result = LegacyFullClassName(desc, options); + + for (int i = 0; i < result.size(); i++) { + if (result[i] == '\\') { + result[i] = '/'; + } + } + return result + ".php"; +} + +std::string GeneratedServiceFileName(const ServiceDescriptor* service, + const Options& options) { + std::string result = FullClassName(service, options) + "Interface"; + for (int i = 0; i < result.size(); i++) { + if (result[i] == '\\') { + result[i] = '/'; + } + } + return result + ".php"; +} + +std::string IntToString(int32 value) { + std::ostringstream os; + os << value; + return os.str(); +} + +std::string LabelForField(const FieldDescriptor* field) { + switch (field->label()) { + case FieldDescriptor::LABEL_OPTIONAL: return "optional"; + case FieldDescriptor::LABEL_REQUIRED: return "required"; + case FieldDescriptor::LABEL_REPEATED: return "repeated"; + default: assert(false); return ""; + } +} + +std::string PhpSetterTypeName(const FieldDescriptor* field, + const Options& options) { + if (field->is_map()) { + return "array|\\Google\\Protobuf\\Internal\\MapField"; + } + std::string type; + switch (field->type()) { + case FieldDescriptor::TYPE_INT32: + case FieldDescriptor::TYPE_UINT32: + case FieldDescriptor::TYPE_SINT32: + case FieldDescriptor::TYPE_FIXED32: + case FieldDescriptor::TYPE_SFIXED32: + case FieldDescriptor::TYPE_ENUM: + type = "int"; + break; + case FieldDescriptor::TYPE_INT64: + case FieldDescriptor::TYPE_UINT64: + case FieldDescriptor::TYPE_SINT64: + case FieldDescriptor::TYPE_FIXED64: + case FieldDescriptor::TYPE_SFIXED64: + type = "int|string"; + break; + case FieldDescriptor::TYPE_DOUBLE: + case FieldDescriptor::TYPE_FLOAT: + type = "float"; + break; + case FieldDescriptor::TYPE_BOOL: + type = "bool"; + break; + case FieldDescriptor::TYPE_STRING: + case FieldDescriptor::TYPE_BYTES: + type = "string"; + break; + case FieldDescriptor::TYPE_MESSAGE: + type = "\\" + FullClassName(field->message_type(), options); + break; + case FieldDescriptor::TYPE_GROUP: + return "null"; + default: assert(false); return ""; + } + if (field->is_repeated()) { + // accommodate for edge case with multiple types. + size_t start_pos = type.find("|"); + if (start_pos != std::string::npos) { + type.replace(start_pos, 1, "[]|"); + } + type += "[]|\\Google\\Protobuf\\Internal\\RepeatedField"; + } + return type; +} + +std::string PhpSetterTypeName(const FieldDescriptor* field, + bool is_descriptor) { + Options options; + options.is_descriptor = is_descriptor; + return PhpSetterTypeName(field, options); +} + +std::string PhpGetterTypeName(const FieldDescriptor* field, + const Options& options) { + if (field->is_map()) { + return "\\Google\\Protobuf\\Internal\\MapField"; + } + if (field->is_repeated()) { + return "\\Google\\Protobuf\\Internal\\RepeatedField"; + } + switch (field->type()) { + case FieldDescriptor::TYPE_INT32: + case FieldDescriptor::TYPE_UINT32: + case FieldDescriptor::TYPE_SINT32: + case FieldDescriptor::TYPE_FIXED32: + case FieldDescriptor::TYPE_SFIXED32: + case FieldDescriptor::TYPE_ENUM: return "int"; + case FieldDescriptor::TYPE_INT64: + case FieldDescriptor::TYPE_UINT64: + case FieldDescriptor::TYPE_SINT64: + case FieldDescriptor::TYPE_FIXED64: + case FieldDescriptor::TYPE_SFIXED64: return "int|string"; + case FieldDescriptor::TYPE_DOUBLE: + case FieldDescriptor::TYPE_FLOAT: return "float"; + case FieldDescriptor::TYPE_BOOL: return "bool"; + case FieldDescriptor::TYPE_STRING: + case FieldDescriptor::TYPE_BYTES: return "string"; + case FieldDescriptor::TYPE_MESSAGE: + return "\\" + FullClassName(field->message_type(), options); + case FieldDescriptor::TYPE_GROUP: return "null"; + default: assert(false); return ""; + } +} + +std::string PhpGetterTypeName(const FieldDescriptor* field, + bool is_descriptor) { + Options options; + options.is_descriptor = is_descriptor; + return PhpGetterTypeName(field, options); +} + +std::string EnumOrMessageSuffix(const FieldDescriptor* field, + const Options& options) { + if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + return ", '" + + DescriptorFullName(field->message_type(), options.is_descriptor) + + "'"; + } + if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) { + return ", '" + + DescriptorFullName(field->enum_type(), options.is_descriptor) + "'"; + } + return ""; +} + +std::string EnumOrMessageSuffix(const FieldDescriptor* field, + bool is_descriptor) { + Options options; + options.is_descriptor = is_descriptor; + return EnumOrMessageSuffix(field, options); +} + +// Converts a name to camel-case. If cap_first_letter is true, capitalize the +// first letter. +std::string UnderscoresToCamelCase(const std::string& name, + bool cap_first_letter) { + std::string result; + for (int i = 0; i < name.size(); i++) { + if ('a' <= name[i] && name[i] <= 'z') { + if (cap_first_letter) { + result += name[i] + ('A' - 'a'); + } else { + result += name[i]; + } + cap_first_letter = false; + } else if ('A' <= name[i] && name[i] <= 'Z') { + if (i == 0 && !cap_first_letter) { + // Force first letter to lower-case unless explicitly told to + // capitalize it. + result += name[i] + ('a' - 'A'); + } else { + // Capital letters after the first are left as-is. + result += name[i]; + } + cap_first_letter = false; + } else if ('0' <= name[i] && name[i] <= '9') { + result += name[i]; + cap_first_letter = true; + } else { + cap_first_letter = true; + } + } + // Add a trailing "_" if the name should be altered. + if (name[name.size() - 1] == '#') { + result += '_'; + } + return result; +} + +void Indent(io::Printer* printer) { + printer->Indent(); + printer->Indent(); +} +void Outdent(io::Printer* printer) { + printer->Outdent(); + printer->Outdent(); +} + +void GenerateField(const FieldDescriptor* field, io::Printer* printer, + const Options& options) { + if (field->is_repeated()) { + GenerateFieldDocComment(printer, field, options, kFieldProperty); + printer->Print( + "private $^name^;\n", + "name", field->name()); + } else if (field->real_containing_oneof()) { + // Oneof fields are handled by GenerateOneofField. + return; + } else { + std::string initial_value = + field->has_presence() ? "null" : DefaultForField(field); + GenerateFieldDocComment(printer, field, options, kFieldProperty); + printer->Print( + "protected $^name^ = ^initial_value^;\n", + "name", field->name(), + "initial_value", initial_value); + } +} + +void GenerateOneofField(const OneofDescriptor* oneof, io::Printer* printer) { + // Oneof property needs to be protected in order to be accessed by parent + // class in implementation. + printer->Print( + "protected $^name^;\n", + "name", oneof->name()); +} + +void GenerateFieldAccessor(const FieldDescriptor* field, const Options& options, + io::Printer* printer) { + const OneofDescriptor* oneof = field->real_containing_oneof(); + + // Generate getter. + GenerateFieldDocComment(printer, field, options, kFieldGetter); + + // deprecation + std::string deprecation_trigger = (field->options().deprecated()) ? "@trigger_error('" + + field->name() + " is deprecated.', E_USER_DEPRECATED);\n " : ""; + + // Emit getter. + if (oneof != NULL) { + printer->Print( + "public function get^camel_name^()\n" + "{\n" + " ^deprecation_trigger^return $this->readOneof(^number^);\n" + "}\n\n", + "camel_name", UnderscoresToCamelCase(field->name(), true), + "number", IntToString(field->number()), + "deprecation_trigger", deprecation_trigger); + } else if (field->has_presence() && !field->message_type()) { + printer->Print( + "public function get^camel_name^()\n" + "{\n" + " ^deprecation_trigger^return isset($this->^name^) ? $this->^name^ : ^default_value^;\n" + "}\n\n", + "camel_name", UnderscoresToCamelCase(field->name(), true), + "name", field->name(), + "default_value", DefaultForField(field), + "deprecation_trigger", deprecation_trigger); + } else { + printer->Print( + "public function get^camel_name^()\n" + "{\n" + " ^deprecation_trigger^return $this->^name^;\n" + "}\n\n", + "camel_name", UnderscoresToCamelCase(field->name(), true), + "name", field->name(), + "deprecation_trigger", deprecation_trigger); + } + + // Emit hazzers/clear. + if (oneof) { + printer->Print( + "public function has^camel_name^()\n" + "{\n" + " ^deprecation_trigger^return $this->hasOneof(^number^);\n" + "}\n\n", + "camel_name", UnderscoresToCamelCase(field->name(), true), + "number", IntToString(field->number()), + "deprecation_trigger", deprecation_trigger); + } else if (field->has_presence()) { + printer->Print( + "public function has^camel_name^()\n" + "{\n" + " ^deprecation_trigger^return isset($this->^name^);\n" + "}\n\n" + "public function clear^camel_name^()\n" + "{\n" + " ^deprecation_trigger^unset($this->^name^);\n" + "}\n\n", + "camel_name", UnderscoresToCamelCase(field->name(), true), + "name", field->name(), + "default_value", DefaultForField(field), + "deprecation_trigger", deprecation_trigger); + } + + // For wrapper types, generate an additional getXXXUnwrapped getter + if (!field->is_map() && + !field->is_repeated() && + field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && + IsWrapperType(field)) { + GenerateWrapperFieldGetterDocComment(printer, field); + printer->Print( + "public function get^camel_name^Unwrapped()\n" + "{\n" + " ^deprecation_trigger^return $this->readWrapperValue(\"^field_name^\");\n" + "}\n\n", + "camel_name", UnderscoresToCamelCase(field->name(), true), + "field_name", field->name(), + "deprecation_trigger", deprecation_trigger); + } + + // Generate setter. + GenerateFieldDocComment(printer, field, options, kFieldSetter); + printer->Print( + "public function set^camel_name^($var)\n" + "{\n", + "camel_name", UnderscoresToCamelCase(field->name(), true)); + + Indent(printer); + + if (field->options().deprecated()) { + printer->Print( + "^deprecation_trigger^", + "deprecation_trigger", deprecation_trigger + ); + } + + // Type check. + if (field->is_map()) { + const Descriptor* map_entry = field->message_type(); + const FieldDescriptor* key = map_entry->FindFieldByName("key"); + const FieldDescriptor* value = map_entry->FindFieldByName("value"); + printer->Print( + "$arr = GPBUtil::checkMapField($var, " + "\\Google\\Protobuf\\Internal\\GPBType::^key_type^, " + "\\Google\\Protobuf\\Internal\\GPBType::^value_type^", + "key_type", ToUpper(key->type_name()), + "value_type", ToUpper(value->type_name())); + if (value->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + printer->Print( + ", \\^class_name^);\n", + "class_name", + FullClassName(value->message_type(), options) + "::class"); + } else if (value->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) { + printer->Print( + ", \\^class_name^);\n", + "class_name", + FullClassName(value->enum_type(), options) + "::class"); + } else { + printer->Print(");\n"); + } + } else if (field->is_repeated()) { + printer->Print( + "$arr = GPBUtil::checkRepeatedField($var, " + "\\Google\\Protobuf\\Internal\\GPBType::^type^", + "type", ToUpper(field->type_name())); + if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + printer->Print( + ", \\^class_name^);\n", + "class_name", + FullClassName(field->message_type(), options) + "::class"); + } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) { + printer->Print( + ", \\^class_name^);\n", + "class_name", + FullClassName(field->enum_type(), options) + "::class"); + } else { + printer->Print(");\n"); + } + } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + printer->Print( + "GPBUtil::checkMessage($var, \\^class_name^::class);\n", + "class_name", FullClassName(field->message_type(), options)); + } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) { + printer->Print( + "GPBUtil::checkEnum($var, \\^class_name^::class);\n", + "class_name", FullClassName(field->enum_type(), options)); + } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) { + printer->Print( + "GPBUtil::checkString($var, ^utf8^);\n", + "utf8", + field->type() == FieldDescriptor::TYPE_STRING ? "True": "False"); + } else { + printer->Print( + "GPBUtil::check^type^($var);\n", + "type", UnderscoresToCamelCase(field->cpp_type_name(), true)); + } + + if (oneof != NULL) { + printer->Print( + "$this->writeOneof(^number^, $var);\n", + "number", IntToString(field->number())); + } else if (field->is_repeated()) { + printer->Print( + "$this->^name^ = $arr;\n", + "name", field->name()); + } else { + printer->Print( + "$this->^name^ = $var;\n", + "name", field->name()); + } + + printer->Print("\nreturn $this;\n"); + + Outdent(printer); + + printer->Print( + "}\n\n"); + + // For wrapper types, generate an additional setXXXValue getter + if (!field->is_map() && + !field->is_repeated() && + field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && + IsWrapperType(field)) { + GenerateWrapperFieldSetterDocComment(printer, field); + printer->Print( + "public function set^camel_name^Unwrapped($var)\n" + "{\n" + " $this->writeWrapperValue(\"^field_name^\", $var);\n" + " return $this;" + "}\n\n", + "camel_name", UnderscoresToCamelCase(field->name(), true), + "field_name", field->name()); + } +} + +void GenerateEnumToPool(const EnumDescriptor* en, io::Printer* printer) { + printer->Print( + "$pool->addEnum('^name^', " + "\\Google\\Protobuf\\Internal\\^class_name^::class)\n", + "name", DescriptorFullName(en, true), + "class_name", en->name()); + Indent(printer); + + for (int i = 0; i < en->value_count(); i++) { + const EnumValueDescriptor* value = en->value(i); + printer->Print( + "->value(\"^name^\", ^number^)\n", + "name", ConstantNamePrefix(value->name()) + value->name(), + "number", IntToString(value->number())); + } + printer->Print("->finalizeToPool();\n\n"); + Outdent(printer); +} + +void GenerateServiceMethod(const MethodDescriptor* method, + io::Printer* printer) { + printer->Print( + "public function ^camel_name^(\\^request_name^ $request);\n\n", + "camel_name", UnderscoresToCamelCase(method->name(), false), + "request_name", FullClassName( + method->input_type(), false) + ); +} + +void GenerateMessageToPool(const std::string& name_prefix, + const Descriptor* message, io::Printer* printer) { + // Don't generate MapEntry messages -- we use the PHP extension's native + // support for map fields instead. + if (message->options().map_entry()) { + return; + } + std::string class_name = + (name_prefix.empty() ? "" : name_prefix + "\\") + + ReservedNamePrefix(message->name(), message->file()) + message->name(); + + printer->Print( + "$pool->addMessage('^message^', " + "\\Google\\Protobuf\\Internal\\^class_name^::class)\n", + "message", DescriptorFullName(message, true), + "class_name", class_name); + + Indent(printer); + + for (int i = 0; i < message->field_count(); i++) { + const FieldDescriptor* field = message->field(i); + if (field->is_map()) { + const FieldDescriptor* key = + field->message_type()->FindFieldByName("key"); + const FieldDescriptor* val = + field->message_type()->FindFieldByName("value"); + printer->Print( + "->map('^field^', \\Google\\Protobuf\\Internal\\GPBType::^key^, " + "\\Google\\Protobuf\\Internal\\GPBType::^value^, ^number^^other^)\n", + "field", field->name(), + "key", ToUpper(key->type_name()), + "value", ToUpper(val->type_name()), + "number", StrCat(field->number()), + "other", EnumOrMessageSuffix(val, true)); + } else if (!field->real_containing_oneof()) { + printer->Print( + "->^label^('^field^', " + "\\Google\\Protobuf\\Internal\\GPBType::^type^, ^number^^other^)\n", + "field", field->name(), + "label", LabelForField(field), + "type", ToUpper(field->type_name()), + "number", StrCat(field->number()), + "other", EnumOrMessageSuffix(field, true)); + } + } + + // oneofs. + for (int i = 0; i < message->real_oneof_decl_count(); i++) { + const OneofDescriptor* oneof = message->oneof_decl(i); + printer->Print("->oneof(^name^)\n", + "name", oneof->name()); + Indent(printer); + for (int index = 0; index < oneof->field_count(); index++) { + const FieldDescriptor* field = oneof->field(index); + printer->Print( + "->value('^field^', " + "\\Google\\Protobuf\\Internal\\GPBType::^type^, ^number^^other^)\n", + "field", field->name(), + "type", ToUpper(field->type_name()), + "number", StrCat(field->number()), + "other", EnumOrMessageSuffix(field, true)); + } + printer->Print("->finish()\n"); + Outdent(printer); + } + + printer->Print( + "->finalizeToPool();\n"); + + Outdent(printer); + + printer->Print( + "\n"); + + for (int i = 0; i < message->nested_type_count(); i++) { + GenerateMessageToPool(class_name, message->nested_type(i), printer); + } + for (int i = 0; i < message->enum_type_count(); i++) { + GenerateEnumToPool(message->enum_type(i), printer); + } +} + +void GenerateAddFileToPool(const FileDescriptor* file, const Options& options, + io::Printer* printer) { + printer->Print( + "public static $is_initialized = false;\n\n" + "public static function initOnce() {\n"); + Indent(printer); + + if (options.aggregate_metadata) { + GenerateAddFilesToPool(file, options, printer); + } else { + printer->Print( + "$pool = \\Google\\Protobuf\\Internal\\" + "DescriptorPool::getGeneratedPool();\n\n" + "if (static::$is_initialized == true) {\n" + " return;\n" + "}\n"); + + if (options.is_descriptor) { + for (int i = 0; i < file->message_type_count(); i++) { + GenerateMessageToPool("", file->message_type(i), printer); + } + for (int i = 0; i < file->enum_type_count(); i++) { + GenerateEnumToPool(file->enum_type(i), printer); + } + + printer->Print( + "$pool->finish();\n"); + } else { + for (int i = 0; i < file->dependency_count(); i++) { + const std::string& name = file->dependency(i)->name(); + // Currently, descriptor.proto is not ready for external usage. Skip to + // import it for now, so that its dependencies can still work as long as + // they don't use protos defined in descriptor.proto. + if (name == kDescriptorFile) { + continue; + } + std::string dependency_filename = + GeneratedMetadataFileName(file->dependency(i), options); + printer->Print( + "\\^name^::initOnce();\n", + "name", FilenameToClassname(dependency_filename)); + } + + // Add messages and enums to descriptor pool. + FileDescriptorSet files; + FileDescriptorProto* file_proto = files.add_file(); + file->CopyTo(file_proto); + + // Filter out descriptor.proto as it cannot be depended on for now. + RepeatedPtrField<std::string>* dependency = + file_proto->mutable_dependency(); + for (RepeatedPtrField<std::string>::iterator it = dependency->begin(); + it != dependency->end(); ++it) { + if (*it != kDescriptorFile) { + dependency->erase(it); + break; + } + } + + // Filter out all extensions, since we do not support extension yet. + file_proto->clear_extension(); + RepeatedPtrField<DescriptorProto>* message_type = + file_proto->mutable_message_type(); + for (RepeatedPtrField<DescriptorProto>::iterator it = message_type->begin(); + it != message_type->end(); ++it) { + it->clear_extension(); + } + + std::string files_data; + files.SerializeToString(&files_data); + + printer->Print("$pool->internalAddGeneratedFile(\n"); + Indent(printer); + printer->Print("'"); + + for (auto ch : files_data) { + switch (ch) { + case '\\': + printer->Print(R"(\\)"); + break; + case '\'': + printer->Print(R"(\')"); + break; + default: + printer->Print("^char^", "char", std::string(1, ch)); + break; + } + } + + printer->Print("'\n"); + Outdent(printer); + printer->Print( + ", true);\n\n"); + } + printer->Print( + "static::$is_initialized = true;\n"); + } + + Outdent(printer); + printer->Print("}\n"); +} + +static void AnalyzeDependencyForFile( + const FileDescriptor* file, + std::set<const FileDescriptor*>* nodes_without_dependency, + std::map<const FileDescriptor*, std::set<const FileDescriptor*>>* deps, + std::map<const FileDescriptor*, int>* dependency_count) { + int count = file->dependency_count(); + for (int i = 0; i < file->dependency_count(); i++) { + const FileDescriptor* dependency = file->dependency(i); + if (dependency->name() == kDescriptorFile) { + count--; + break; + } + } + + if (count == 0) { + nodes_without_dependency->insert(file); + } else { + (*dependency_count)[file] = count; + for (int i = 0; i < file->dependency_count(); i++) { + const FileDescriptor* dependency = file->dependency(i); + if (dependency->name() == kDescriptorFile) { + continue; + } + if (deps->find(dependency) == deps->end()) { + (*deps)[dependency] = std::set<const FileDescriptor*>(); + } + (*deps)[dependency].insert(file); + AnalyzeDependencyForFile( + dependency, nodes_without_dependency, deps, dependency_count); + } + } +} + +static bool NeedsUnwrapping(const FileDescriptor* file, + const Options& options) { + bool has_aggregate_metadata_prefix = false; + if (options.aggregate_metadata_prefixes.empty()) { + has_aggregate_metadata_prefix = true; + } else { + for (const auto& prefix : options.aggregate_metadata_prefixes) { + if (HasPrefixString(file->package(), prefix)) { + has_aggregate_metadata_prefix = true; + break; + } + } + } + + return has_aggregate_metadata_prefix; +} + +void GenerateAddFilesToPool(const FileDescriptor* file, const Options& options, + io::Printer* printer) { + printer->Print( + "$pool = \\Google\\Protobuf\\Internal\\" + "DescriptorPool::getGeneratedPool();\n" + "if (static::$is_initialized == true) {\n" + " return;\n" + "}\n"); + + // Sort files according to dependency + std::map<const FileDescriptor*, std::set<const FileDescriptor*>> deps; + std::map<const FileDescriptor*, int> dependency_count; + std::set<const FileDescriptor*> nodes_without_dependency; + FileDescriptorSet sorted_file_set; + + AnalyzeDependencyForFile( + file, &nodes_without_dependency, &deps, &dependency_count); + + while (!nodes_without_dependency.empty()) { + auto file_node = *nodes_without_dependency.begin(); + nodes_without_dependency.erase(file_node); + for (auto dependent : deps[file_node]) { + if (dependency_count[dependent] == 1) { + dependency_count.erase(dependent); + nodes_without_dependency.insert(dependent); + } else { + dependency_count[dependent] -= 1; + } + } + + bool needs_aggregate = NeedsUnwrapping(file_node, options); + + if (needs_aggregate) { + auto file_proto = sorted_file_set.add_file(); + file_node->CopyTo(file_proto); + + // Filter out descriptor.proto as it cannot be depended on for now. + RepeatedPtrField<std::string>* dependency = + file_proto->mutable_dependency(); + for (RepeatedPtrField<std::string>::iterator it = dependency->begin(); + it != dependency->end(); ++it) { + if (*it != kDescriptorFile) { + dependency->erase(it); + break; + } + } + + // Filter out all extensions, since we do not support extension yet. + file_proto->clear_extension(); + RepeatedPtrField<DescriptorProto>* message_type = + file_proto->mutable_message_type(); + for (RepeatedPtrField<DescriptorProto>::iterator it = message_type->begin(); + it != message_type->end(); ++it) { + it->clear_extension(); + } + } else { + std::string dependency_filename = GeneratedMetadataFileName(file_node, false); + printer->Print( + "\\^name^::initOnce();\n", + "name", FilenameToClassname(dependency_filename)); + } + } + + std::string files_data; + sorted_file_set.SerializeToString(&files_data); + + printer->Print("$pool->internalAddGeneratedFile(\n"); + Indent(printer); + printer->Print("'"); + + for (auto ch : files_data) { + switch (ch) { + case '\\': + printer->Print(R"(\\)"); + break; + case '\'': + printer->Print(R"(\')"); + break; + default: + printer->Print("^char^", "char", std::string(1, ch)); + break; + } + } + + printer->Print("'\n"); + Outdent(printer); + printer->Print( + ", true);\n"); + + printer->Print( + "static::$is_initialized = true;\n"); +} + +void GenerateUseDeclaration(const Options& options, io::Printer* printer) { + if (!options.is_descriptor) { + printer->Print( + "use Google\\Protobuf\\Internal\\GPBType;\n" + "use Google\\Protobuf\\Internal\\RepeatedField;\n" + "use Google\\Protobuf\\Internal\\GPBUtil;\n\n"); + } else { + printer->Print( + "use Google\\Protobuf\\Internal\\GPBType;\n" + "use Google\\Protobuf\\Internal\\GPBWire;\n" + "use Google\\Protobuf\\Internal\\RepeatedField;\n" + "use Google\\Protobuf\\Internal\\InputStream;\n" + "use Google\\Protobuf\\Internal\\GPBUtil;\n\n"); + } +} + +void GenerateHead(const FileDescriptor* file, io::Printer* printer) { + printer->Print( + "<?php\n" + "# Generated by the protocol buffer compiler. DO NOT EDIT!\n" + "# source: ^filename^\n" + "\n", + "filename", file->name()); +} + +std::string FilenameToClassname(const std::string& filename) { + int lastindex = filename.find_last_of("."); + std::string result = filename.substr(0, lastindex); + for (int i = 0; i < result.size(); i++) { + if (result[i] == '/') { + result[i] = '\\'; + } + } + return result; +} + +void GenerateMetadataFile(const FileDescriptor* file, const Options& options, + GeneratorContext* generator_context) { + std::string filename = GeneratedMetadataFileName(file, options); + std::unique_ptr<io::ZeroCopyOutputStream> output( + generator_context->Open(filename)); + io::Printer printer(output.get(), '^'); + + GenerateHead(file, &printer); + + std::string fullname = FilenameToClassname(filename); + int lastindex = fullname.find_last_of("\\"); + + if (lastindex != std::string::npos) { + printer.Print( + "namespace ^name^;\n\n", + "name", fullname.substr(0, lastindex)); + + printer.Print( + "class ^name^\n" + "{\n", + "name", fullname.substr(lastindex + 1)); + } else { + printer.Print( + "class ^name^\n" + "{\n", + "name", fullname); + } + Indent(&printer); + + GenerateAddFileToPool(file, options, &printer); + + Outdent(&printer); + printer.Print("}\n\n"); +} + +template <typename DescriptorType> +void LegacyGenerateClassFile(const FileDescriptor* file, + const DescriptorType* desc, const Options& options, + GeneratorContext* generator_context) { + std::string filename = LegacyGeneratedClassFileName(desc, options); + std::unique_ptr<io::ZeroCopyOutputStream> output( + generator_context->Open(filename)); + io::Printer printer(output.get(), '^'); + + GenerateHead(file, &printer); + + std::string php_namespace = RootPhpNamespace(desc, options); + if (!php_namespace.empty()) { + printer.Print( + "namespace ^name^;\n\n", + "name", php_namespace); + } + std::string newname = FullClassName(desc, options); + printer.Print("if (false) {\n"); + Indent(&printer); + printer.Print("/**\n"); + printer.Print(" * This class is deprecated. Use ^new^ instead.\n", + "new", newname); + printer.Print(" * @deprecated\n"); + printer.Print(" */\n"); + printer.Print("class ^old^ {}\n", + "old", LegacyGeneratedClassName(desc)); + Outdent(&printer); + printer.Print("}\n"); + printer.Print("class_exists(^new^::class);\n", + "new", GeneratedClassNameImpl(desc)); + printer.Print("@trigger_error('^old^ is deprecated and will be removed in " + "the next major release. Use ^fullname^ instead', E_USER_DEPRECATED);\n\n", + "old", LegacyFullClassName(desc, options), + "fullname", newname); +} + +void GenerateEnumFile(const FileDescriptor* file, const EnumDescriptor* en, + const Options& options, + GeneratorContext* generator_context) { + std::string filename = GeneratedClassFileName(en, options); + std::unique_ptr<io::ZeroCopyOutputStream> output( + generator_context->Open(filename)); + io::Printer printer(output.get(), '^'); + + GenerateHead(file, &printer); + + std::string fullname = FilenameToClassname(filename); + int lastindex = fullname.find_last_of("\\"); + + if (lastindex != std::string::npos) { + printer.Print( + "namespace ^name^;\n\n", + "name", fullname.substr(0, lastindex)); + + // We only need this 'use' statement if the enum has a namespace. + // Otherwise, we get a warning that the use statement has no effect. + printer.Print("use UnexpectedValueException;\n\n"); + } + + GenerateEnumDocComment(&printer, en, options); + + if (lastindex != std::string::npos) { + fullname = fullname.substr(lastindex + 1); + } + + printer.Print( + "class ^name^\n" + "{\n", + "name", fullname); + Indent(&printer); + + for (int i = 0; i < en->value_count(); i++) { + const EnumValueDescriptor* value = en->value(i); + GenerateEnumValueDocComment(&printer, value); + printer.Print("const ^name^ = ^number^;\n", + "name", ConstantNamePrefix(value->name()) + value->name(), + "number", IntToString(value->number())); + } + + printer.Print("\nprivate static $valueToName = [\n"); + Indent(&printer); + for (int i = 0; i < en->value_count(); i++) { + const EnumValueDescriptor* value = en->value(i); + printer.Print("self::^name^ => '^name^',\n", + "name", ConstantNamePrefix(value->name()) + value->name()); + } + Outdent(&printer); + printer.Print("];\n"); + + printer.Print( + "\npublic static function name($value)\n" + "{\n"); + Indent(&printer); + printer.Print("if (!isset(self::$valueToName[$value])) {\n"); + Indent(&printer); + printer.Print("throw new UnexpectedValueException(sprintf(\n"); + Indent(&printer); + Indent(&printer); + printer.Print("'Enum %s has no name defined for value %s', __CLASS__, $value));\n"); + Outdent(&printer); + Outdent(&printer); + Outdent(&printer); + printer.Print("}\n" + "return self::$valueToName[$value];\n"); + Outdent(&printer); + printer.Print("}\n\n"); + + printer.Print( + "\npublic static function value($name)\n" + "{\n"); + Indent(&printer); + printer.Print("$const = __CLASS__ . '::' . strtoupper($name);\n" + "if (!defined($const)) {\n"); + Indent(&printer); + printer.Print("throw new UnexpectedValueException(sprintf(\n"); + Indent(&printer); + Indent(&printer); + printer.Print("'Enum %s has no value defined for name %s', __CLASS__, $name));\n"); + Outdent(&printer); + Outdent(&printer); + Outdent(&printer); + printer.Print("}\n" + "return constant($const);\n"); + Outdent(&printer); + printer.Print("}\n"); + + Outdent(&printer); + printer.Print("}\n\n"); + + // write legacy file for backwards compatibility with nested messages and enums + if (en->containing_type() != NULL) { + printer.Print( + "// Adding a class alias for backwards compatibility with the previous class name.\n"); + printer.Print( + "class_alias(^new^::class, \\^old^::class);\n\n", + "new", fullname, + "old", LegacyFullClassName(en, options)); + LegacyGenerateClassFile(file, en, options, generator_context); + } +} + +void GenerateMessageFile(const FileDescriptor* file, const Descriptor* message, + const Options& options, + GeneratorContext* generator_context) { + // Don't generate MapEntry messages -- we use the PHP extension's native + // support for map fields instead. + if (message->options().map_entry()) { + return; + } + + std::string filename = GeneratedClassFileName(message, options); + std::unique_ptr<io::ZeroCopyOutputStream> output( + generator_context->Open(filename)); + io::Printer printer(output.get(), '^'); + + GenerateHead(file, &printer); + + std::string fullname = FilenameToClassname(filename); + int lastindex = fullname.find_last_of("\\"); + + if (lastindex != std::string::npos) { + printer.Print( + "namespace ^name^;\n\n", + "name", fullname.substr(0, lastindex)); + } + + GenerateUseDeclaration(options, &printer); + + GenerateMessageDocComment(&printer, message, options); + if (lastindex != std::string::npos) { + fullname = fullname.substr(lastindex + 1); + } + + std::string base; + + switch (message->well_known_type()) { + case Descriptor::WELLKNOWNTYPE_ANY: + base = "\\Google\\Protobuf\\Internal\\AnyBase"; + break; + case Descriptor::WELLKNOWNTYPE_TIMESTAMP: + base = "\\Google\\Protobuf\\Internal\\TimestampBase"; + break; + default: + base = "\\Google\\Protobuf\\Internal\\Message"; + break; + } + + printer.Print( + "class ^name^ extends ^base^\n" + "{\n", + "base", base, + "name", fullname); + Indent(&printer); + + // Field and oneof definitions. + for (int i = 0; i < message->field_count(); i++) { + const FieldDescriptor* field = message->field(i); + GenerateField(field, &printer, options); + } + for (int i = 0; i < message->real_oneof_decl_count(); i++) { + const OneofDescriptor* oneof = message->oneof_decl(i); + GenerateOneofField(oneof, &printer); + } + printer.Print("\n"); + + GenerateMessageConstructorDocComment(&printer, message, options); + printer.Print( + "public function __construct($data = NULL) {\n"); + Indent(&printer); + + std::string metadata_filename = GeneratedMetadataFileName(file, options); + std::string metadata_fullname = FilenameToClassname(metadata_filename); + printer.Print( + "\\^fullname^::initOnce();\n", + "fullname", metadata_fullname); + + printer.Print( + "parent::__construct($data);\n"); + + Outdent(&printer); + printer.Print("}\n\n"); + + // Field and oneof accessors. + for (int i = 0; i < message->field_count(); i++) { + const FieldDescriptor* field = message->field(i); + GenerateFieldAccessor(field, options, &printer); + } + for (int i = 0; i < message->real_oneof_decl_count(); i++) { + const OneofDescriptor* oneof = message->oneof_decl(i); + printer.Print( + "/**\n" + " * @return string\n" + " */\n" + "public function get^camel_name^()\n" + "{\n" + " return $this->whichOneof(\"^name^\");\n" + "}\n\n", + "camel_name", UnderscoresToCamelCase(oneof->name(), true), "name", + oneof->name()); + } + + Outdent(&printer); + printer.Print("}\n\n"); + + // write legacy file for backwards compatibility with nested messages and enums + if (message->containing_type() != NULL) { + printer.Print( + "// Adding a class alias for backwards compatibility with the previous class name.\n"); + printer.Print( + "class_alias(^new^::class, \\^old^::class);\n\n", + "new", fullname, + "old", LegacyFullClassName(message, options)); + LegacyGenerateClassFile(file, message, options, generator_context); + } + + // Nested messages and enums. + for (int i = 0; i < message->nested_type_count(); i++) { + GenerateMessageFile(file, message->nested_type(i), options, + generator_context); + } + for (int i = 0; i < message->enum_type_count(); i++) { + GenerateEnumFile(file, message->enum_type(i), options, generator_context); + } +} + +void GenerateServiceFile( + const FileDescriptor* file, const ServiceDescriptor* service, + const Options& options, GeneratorContext* generator_context) { + std::string filename = GeneratedServiceFileName(service, options); + std::unique_ptr<io::ZeroCopyOutputStream> output( + generator_context->Open(filename)); + io::Printer printer(output.get(), '^'); + + GenerateHead(file, &printer); + + std::string fullname = FilenameToClassname(filename); + int lastindex = fullname.find_last_of("\\"); + + if (!file->options().php_namespace().empty() || + (!file->options().has_php_namespace() && !file->package().empty()) || + lastindex != std::string::npos) { + printer.Print( + "namespace ^name^;\n\n", + "name", fullname.substr(0, lastindex)); + } + + GenerateServiceDocComment(&printer, service); + + if (lastindex != std::string::npos) { + printer.Print( + "interface ^name^\n" + "{\n", + "name", fullname.substr(lastindex + 1)); + } else { + printer.Print( + "interface ^name^\n" + "{\n", + "name", fullname); + } + + Indent(&printer); + + for (int i = 0; i < service->method_count(); i++) { + const MethodDescriptor* method = service->method(i); + GenerateServiceMethodDocComment(&printer, method); + GenerateServiceMethod(method, &printer); + } + + Outdent(&printer); + printer.Print("}\n\n"); +} + +void GenerateFile(const FileDescriptor* file, const Options& options, + GeneratorContext* generator_context) { + GenerateMetadataFile(file, options, generator_context); + + for (int i = 0; i < file->message_type_count(); i++) { + GenerateMessageFile(file, file->message_type(i), options, + generator_context); + } + for (int i = 0; i < file->enum_type_count(); i++) { + GenerateEnumFile(file, file->enum_type(i), options, generator_context); + } + if (file->options().php_generic_services()) { + for (int i = 0; i < file->service_count(); i++) { + GenerateServiceFile(file, file->service(i), options, generator_context); + } + } +} + +static std::string EscapePhpdoc(const std::string& input) { + std::string result; + result.reserve(input.size() * 2); + + char prev = '*'; + + for (std::string::size_type i = 0; i < input.size(); i++) { + char c = input[i]; + switch (c) { + case '*': + // Avoid "/*". + if (prev == '/') { + result.append("*"); + } else { + result.push_back(c); + } + break; + case '/': + // Avoid "*/". + if (prev == '*') { + result.append("/"); + } else { + result.push_back(c); + } + break; + case '@': + // '@' starts phpdoc tags including the @deprecated tag, which will + // cause a compile-time error if inserted before a declaration that + // does not have a corresponding @Deprecated annotation. + result.append("@"); + break; + default: + result.push_back(c); + break; + } + + prev = c; + } + + return result; +} + +static void GenerateDocCommentBodyForLocation( + io::Printer* printer, const SourceLocation& location, bool trailingNewline, + int indentCount) { + std::string comments = location.leading_comments.empty() + ? location.trailing_comments + : location.leading_comments; + if (!comments.empty()) { + // TODO(teboring): Ideally we should parse the comment text as Markdown and + // write it back as HTML, but this requires a Markdown parser. For now + // we just use the proto comments unchanged. + + // If the comment itself contains block comment start or end markers, + // HTML-escape them so that they don't accidentally close the doc comment. + comments = EscapePhpdoc(comments); + + std::vector<std::string> lines = Split(comments, "\n", true); + while (!lines.empty() && lines.back().empty()) { + lines.pop_back(); + } + + for (int i = 0; i < lines.size(); i++) { + // Most lines should start with a space. Watch out for lines that start + // with a /, since putting that right after the leading asterisk will + // close the comment. + if (indentCount == 0 && !lines[i].empty() && lines[i][0] == '/') { + printer->Print(" * ^line^\n", "line", lines[i]); + } else { + std::string indent = std::string(indentCount, ' '); + printer->Print(" *^ind^^line^\n", "ind", indent, "line", lines[i]); + } + } + if (trailingNewline) { + printer->Print(" *\n"); + } + } +} + +template <typename DescriptorType> +static void GenerateDocCommentBody( + io::Printer* printer, const DescriptorType* descriptor) { + SourceLocation location; + if (descriptor->GetSourceLocation(&location)) { + GenerateDocCommentBodyForLocation(printer, location, true, 0); + } +} + +static std::string FirstLineOf(const std::string& value) { + std::string result = value; + + std::string::size_type pos = result.find_first_of('\n'); + if (pos != std::string::npos) { + result.erase(pos); + } + + return result; +} + +void GenerateMessageDocComment(io::Printer* printer, const Descriptor* message, + const Options& options) { + printer->Print("/**\n"); + GenerateDocCommentBody(printer, message); + printer->Print( + " * Generated from protobuf message <code>^messagename^</code>\n" + " */\n", + "fullname", EscapePhpdoc(FullClassName(message, options)), + "messagename", EscapePhpdoc(message->full_name())); +} + +void GenerateMessageConstructorDocComment(io::Printer* printer, + const Descriptor* message, + const Options& options) { + // In theory we should have slightly different comments for setters, getters, + // etc., but in practice everyone already knows the difference between these + // so it's redundant information. + + // We start the comment with the main body based on the comments from the + // .proto file (if present). We then end with the field declaration, e.g.: + // optional string foo = 5; + // If the field is a group, the debug string might end with {. + printer->Print("/**\n"); + printer->Print(" * Constructor.\n"); + printer->Print(" *\n"); + printer->Print(" * @param array $data {\n"); + printer->Print(" * Optional. Data for populating the Message object.\n"); + printer->Print(" *\n"); + for (int i = 0; i < message->field_count(); i++) { + const FieldDescriptor* field = message->field(i); + printer->Print(" * @type ^php_type^ $^var^\n", + "php_type", PhpSetterTypeName(field, options), + "var", field->name()); + SourceLocation location; + if (field->GetSourceLocation(&location)) { + GenerateDocCommentBodyForLocation(printer, location, false, 10); + } + } + printer->Print(" * }\n"); + printer->Print(" */\n"); +} + +void GenerateServiceDocComment(io::Printer* printer, + const ServiceDescriptor* service) { + printer->Print("/**\n"); + GenerateDocCommentBody(printer, service); + printer->Print( + " * Protobuf type <code>^fullname^</code>\n" + " */\n", + "fullname", EscapePhpdoc(service->full_name())); +} + +void GenerateFieldDocComment(io::Printer* printer, const FieldDescriptor* field, + const Options& options, int function_type) { + // In theory we should have slightly different comments for setters, getters, + // etc., but in practice everyone already knows the difference between these + // so it's redundant information. + + // We start the comment with the main body based on the comments from the + // .proto file (if present). We then end with the field declaration, e.g.: + // optional string foo = 5; + // If the field is a group, the debug string might end with {. + printer->Print("/**\n"); + GenerateDocCommentBody(printer, field); + printer->Print( + " * Generated from protobuf field <code>^def^</code>\n", + "def", EscapePhpdoc(FirstLineOf(field->DebugString()))); + if (function_type == kFieldSetter) { + printer->Print(" * @param ^php_type^ $var\n", + "php_type", PhpSetterTypeName(field, options)); + printer->Print(" * @return $this\n"); + } else if (function_type == kFieldGetter) { + bool can_return_null = field->has_presence() && + field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE; + printer->Print(" * @return ^php_type^^maybe_null^\n", + "php_type", PhpGetterTypeName(field, options), + "maybe_null", can_return_null ? "|null" : ""); + } + if (field->options().deprecated()) { + printer->Print(" * @deprecated\n"); + } + printer->Print(" */\n"); +} + +void GenerateWrapperFieldGetterDocComment(io::Printer* printer, const FieldDescriptor* field) { + // Generate a doc comment for the special getXXXValue methods that are + // generated for wrapper types. + const FieldDescriptor* primitiveField = field->message_type()->FindFieldByName("value"); + printer->Print("/**\n"); + printer->Print( + " * Returns the unboxed value from <code>get^camel_name^()</code>\n\n", + "camel_name", UnderscoresToCamelCase(field->name(), true)); + GenerateDocCommentBody(printer, field); + printer->Print( + " * Generated from protobuf field <code>^def^</code>\n", + "def", EscapePhpdoc(FirstLineOf(field->DebugString()))); + printer->Print(" * @return ^php_type^|null\n", + "php_type", PhpGetterTypeName(primitiveField, false)); + printer->Print(" */\n"); +} + +void GenerateWrapperFieldSetterDocComment(io::Printer* printer, const FieldDescriptor* field) { + // Generate a doc comment for the special setXXXValue methods that are + // generated for wrapper types. + const FieldDescriptor* primitiveField = field->message_type()->FindFieldByName("value"); + printer->Print("/**\n"); + printer->Print( + " * Sets the field by wrapping a primitive type in a ^message_name^ object.\n\n", + "message_name", FullClassName(field->message_type(), false)); + GenerateDocCommentBody(printer, field); + printer->Print( + " * Generated from protobuf field <code>^def^</code>\n", + "def", EscapePhpdoc(FirstLineOf(field->DebugString()))); + printer->Print(" * @param ^php_type^|null $var\n", + "php_type", PhpSetterTypeName(primitiveField, false)); + printer->Print(" * @return $this\n"); + printer->Print(" */\n"); +} + +void GenerateEnumDocComment(io::Printer* printer, const EnumDescriptor* enum_, + const Options& options) { + printer->Print("/**\n"); + GenerateDocCommentBody(printer, enum_); + printer->Print( + " * Protobuf type <code>^fullname^</code>\n" + " */\n", + "fullname", EscapePhpdoc(enum_->full_name())); +} + +void GenerateEnumValueDocComment(io::Printer* printer, + const EnumValueDescriptor* value) { + printer->Print("/**\n"); + GenerateDocCommentBody(printer, value); + printer->Print( + " * Generated from protobuf enum <code>^def^</code>\n" + " */\n", + "def", EscapePhpdoc(FirstLineOf(value->DebugString()))); +} + +void GenerateServiceMethodDocComment(io::Printer* printer, + const MethodDescriptor* method) { + printer->Print("/**\n"); + GenerateDocCommentBody(printer, method); + printer->Print( + " * Method <code>^method_name^</code>\n" + " *\n", + "method_name", EscapePhpdoc(UnderscoresToCamelCase(method->name(), false))); + printer->Print( + " * @param \\^input_type^ $request\n", + "input_type", EscapePhpdoc(FullClassName(method->input_type(), false))); + printer->Print( + " * @return \\^return_type^\n" + " */\n", + "return_type", EscapePhpdoc(FullClassName(method->output_type(), false))); +} + +std::string FilenameCName(const FileDescriptor* file) { + std::string c_name = file->name(); + c_name = StringReplace(c_name, ".", "_", true); + c_name = StringReplace(c_name, "/", "_", true); + return c_name; +} + +void GenerateCEnum(const EnumDescriptor* desc, io::Printer* printer) { + std::string c_name = desc->full_name(); + c_name = StringReplace(c_name, ".", "_", true); + std::string php_name = FullClassName(desc, Options()); + php_name = StringReplace(php_name, "\\", "\\\\", true); + printer->Print( + "/* $c_name$ */\n" + "\n" + "zend_class_entry* $c_name$_ce;\n" + "\n" + "PHP_METHOD($c_name$, name) {\n" + " $file_c_name$_AddDescriptor();\n" + " const upb_symtab *symtab = DescriptorPool_GetSymbolTable();\n" + " const upb_enumdef *e = upb_symtab_lookupenum(symtab, \"$name$\");\n" + " const char *name;\n" + " zend_long value;\n" + " if (zend_parse_parameters(ZEND_NUM_ARGS(), \"l\", &value) ==\n" + " FAILURE) {\n" + " return;\n" + " }\n" + " name = upb_enumdef_iton(e, value);\n" + " if (!name) {\n" + " zend_throw_exception_ex(NULL, 0,\n" + " \"$php_name$ has no name \"\n" + " \"defined for value \" ZEND_LONG_FMT \".\",\n" + " value);\n" + " return;\n" + " }\n" + " RETURN_STRING(name);\n" + "}\n" + "\n" + "PHP_METHOD($c_name$, value) {\n" + " $file_c_name$_AddDescriptor();\n" + " const upb_symtab *symtab = DescriptorPool_GetSymbolTable();\n" + " const upb_enumdef *e = upb_symtab_lookupenum(symtab, \"$name$\");\n" + " char *name = NULL;\n" + " size_t name_len;\n" + " int32_t num;\n" + " if (zend_parse_parameters(ZEND_NUM_ARGS(), \"s\", &name,\n" + " &name_len) == FAILURE) {\n" + " return;\n" + " }\n" + " if (!upb_enumdef_ntoi(e, name, name_len, &num)) {\n" + " zend_throw_exception_ex(NULL, 0,\n" + " \"$php_name$ has no value \"\n" + " \"defined for name %s.\",\n" + " name);\n" + " return;\n" + " }\n" + " RETURN_LONG(num);\n" + "}\n" + "\n" + "static zend_function_entry $c_name$_phpmethods[] = {\n" + " PHP_ME($c_name$, name, arginfo_lookup, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)\n" + " PHP_ME($c_name$, value, arginfo_lookup, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)\n" + " ZEND_FE_END\n" + "};\n" + "\n" + "static void $c_name$_ModuleInit() {\n" + " zend_class_entry tmp_ce;\n" + "\n" + " INIT_CLASS_ENTRY(tmp_ce, \"$php_name$\",\n" + " $c_name$_phpmethods);\n" + "\n" + " $c_name$_ce = zend_register_internal_class(&tmp_ce);\n", + "name", desc->full_name(), + "file_c_name", FilenameCName(desc->file()), + "c_name", c_name, + "php_name", php_name); + + for (int i = 0; i < desc->value_count(); i++) { + const EnumValueDescriptor* value = desc->value(i); + printer->Print( + " zend_declare_class_constant_long($c_name$_ce, \"$name$\",\n" + " strlen(\"$name$\"), $num$);\n", + "c_name", c_name, + "name", value->name(), + "num", std::to_string(value->number())); + } + + printer->Print( + "}\n" + "\n"); +} + +void GenerateCMessage(const Descriptor* message, io::Printer* printer) { + std::string c_name = message->full_name(); + c_name = StringReplace(c_name, ".", "_", true); + std::string php_name = FullClassName(message, Options()); + php_name = StringReplace(php_name, "\\", "\\\\", true); + printer->Print( + "/* $c_name$ */\n" + "\n" + "zend_class_entry* $c_name$_ce;\n" + "\n" + "static PHP_METHOD($c_name$, __construct) {\n" + " $file_c_name$_AddDescriptor();\n" + " zim_Message___construct(INTERNAL_FUNCTION_PARAM_PASSTHRU);\n" + "}\n" + "\n", + "file_c_name", FilenameCName(message->file()), + "c_name", c_name); + + for (int i = 0; i < message->field_count(); i++) { + auto field = message->field(i); + printer->Print( + "static PHP_METHOD($c_name$, get$camel_name$) {\n" + " Message* intern = (Message*)Z_OBJ_P(getThis());\n" + " const upb_fielddef *f = upb_msgdef_ntofz(intern->desc->msgdef,\n" + " \"$name$\");\n" + " zval ret;\n" + " Message_get(intern, f, &ret);\n" + " RETURN_COPY_VALUE(&ret);\n" + "}\n" + "\n" + "static PHP_METHOD($c_name$, set$camel_name$) {\n" + " Message* intern = (Message*)Z_OBJ_P(getThis());\n" + " const upb_fielddef *f = upb_msgdef_ntofz(intern->desc->msgdef,\n" + " \"$name$\");\n" + " zval *val;\n" + " if (zend_parse_parameters(ZEND_NUM_ARGS(), \"z\", &val)\n" + " == FAILURE) {\n" + " return;\n" + " }\n" + " Message_set(intern, f, val);\n" + " RETURN_COPY(getThis());\n" + "}\n" + "\n", + "c_name", c_name, + "name", field->name(), + "camel_name", UnderscoresToCamelCase(field->name(), true)); + } + + for (int i = 0; i < message->real_oneof_decl_count(); i++) { + auto oneof = message->oneof_decl(i); + printer->Print( + "static PHP_METHOD($c_name$, get$camel_name$) {\n" + " Message* intern = (Message*)Z_OBJ_P(getThis());\n" + " const upb_oneofdef *oneof = upb_msgdef_ntooz(intern->desc->msgdef,\n" + " \"$name$\");\n" + " const upb_fielddef *field = upb_msg_whichoneof(intern->msg, oneof);\n" + " RETURN_STRING(field ? upb_fielddef_name(field) : \"\");\n" + "}\n", + "c_name", c_name, + "name", oneof->name(), + "camel_name", UnderscoresToCamelCase(oneof->name(), true)); + } + + switch (message->well_known_type()) { + case Descriptor::WELLKNOWNTYPE_ANY: + printer->Print( + "ZEND_BEGIN_ARG_INFO_EX(arginfo_is, 0, 0, 1)\n" + " ZEND_ARG_INFO(0, proto)\n" + "ZEND_END_ARG_INFO()\n" + "\n" + ); + break; + case Descriptor::WELLKNOWNTYPE_TIMESTAMP: + printer->Print( + "ZEND_BEGIN_ARG_INFO_EX(arginfo_timestamp_fromdatetime, 0, 0, 1)\n" + " ZEND_ARG_INFO(0, datetime)\n" + "ZEND_END_ARG_INFO()\n" + "\n" + ); + break; + default: + break; + } + + printer->Print( + "static zend_function_entry $c_name$_phpmethods[] = {\n" + " PHP_ME($c_name$, __construct, arginfo_construct, ZEND_ACC_PUBLIC)\n", + "c_name", c_name); + + for (int i = 0; i < message->field_count(); i++) { + auto field = message->field(i); + printer->Print( + " PHP_ME($c_name$, get$camel_name$, arginfo_void, ZEND_ACC_PUBLIC)\n" + " PHP_ME($c_name$, set$camel_name$, arginfo_setter, ZEND_ACC_PUBLIC)\n", + "c_name", c_name, + "camel_name", UnderscoresToCamelCase(field->name(), true)); + } + + for (int i = 0; i < message->real_oneof_decl_count(); i++) { + auto oneof = message->oneof_decl(i); + printer->Print( + " PHP_ME($c_name$, get$camel_name$, arginfo_void, ZEND_ACC_PUBLIC)\n", + "c_name", c_name, + "camel_name", UnderscoresToCamelCase(oneof->name(), true)); + } + + // Extra hand-written functions added to the well-known types. + switch (message->well_known_type()) { + case Descriptor::WELLKNOWNTYPE_ANY: + printer->Print( + " PHP_ME($c_name$, is, arginfo_is, ZEND_ACC_PUBLIC)\n" + " PHP_ME($c_name$, pack, arginfo_setter, ZEND_ACC_PUBLIC)\n" + " PHP_ME($c_name$, unpack, arginfo_void, ZEND_ACC_PUBLIC)\n", + "c_name", c_name); + break; + case Descriptor::WELLKNOWNTYPE_TIMESTAMP: + printer->Print( + " PHP_ME($c_name$, fromDateTime, arginfo_timestamp_fromdatetime, ZEND_ACC_PUBLIC)\n" + " PHP_ME($c_name$, toDateTime, arginfo_void, ZEND_ACC_PUBLIC)\n", + "c_name", c_name); + break; + default: + break; + } + + printer->Print( + " ZEND_FE_END\n" + "};\n" + "\n" + "static void $c_name$_ModuleInit() {\n" + " zend_class_entry tmp_ce;\n" + "\n" + " INIT_CLASS_ENTRY(tmp_ce, \"$php_name$\",\n" + " $c_name$_phpmethods);\n" + "\n" + " $c_name$_ce = zend_register_internal_class(&tmp_ce);\n" + " $c_name$_ce->ce_flags |= ZEND_ACC_FINAL;\n" + " $c_name$_ce->create_object = Message_create;\n" + " zend_do_inheritance($c_name$_ce, message_ce);\n" + "}\n" + "\n", + "c_name", c_name, + "php_name", php_name); + + for (int i = 0; i < message->nested_type_count(); i++) { + GenerateCMessage(message->nested_type(i), printer); + } + for (int i = 0; i < message->enum_type_count(); i++) { + GenerateCEnum(message->enum_type(i), printer); + } +} + +void GenerateEnumCInit(const EnumDescriptor* desc, io::Printer* printer) { + std::string c_name = desc->full_name(); + c_name = StringReplace(c_name, ".", "_", true); + + printer->Print( + " $c_name$_ModuleInit();\n", + "c_name", c_name); +} + +void GenerateCInit(const Descriptor* message, io::Printer* printer) { + std::string c_name = message->full_name(); + c_name = StringReplace(c_name, ".", "_", true); + + printer->Print( + " $c_name$_ModuleInit();\n", + "c_name", c_name); + + for (int i = 0; i < message->nested_type_count(); i++) { + GenerateCInit(message->nested_type(i), printer); + } + for (int i = 0; i < message->enum_type_count(); i++) { + GenerateEnumCInit(message->enum_type(i), printer); + } +} + +void GenerateCWellKnownTypes(const std::vector<const FileDescriptor*>& files, + GeneratorContext* context) { + std::unique_ptr<io::ZeroCopyOutputStream> output( + context->Open("../ext/google/protobuf/wkt.inc")); + io::Printer printer(output.get(), '$'); + + printer.Print( + "// This file is generated from the .proto files for the well-known\n" + "// types. Do not edit!\n\n"); + + printer.Print( + "ZEND_BEGIN_ARG_INFO_EX(arginfo_lookup, 0, 0, 1)\n" + " ZEND_ARG_INFO(0, key)\n" + "ZEND_END_ARG_INFO()\n" + "\n" + ); + + for (auto file : files) { + printer.Print( + "static void $c_name$_AddDescriptor();\n", + "c_name", FilenameCName(file)); + } + + for (auto file : files) { + std::string c_name = FilenameCName(file); + std::string metadata_filename = GeneratedMetadataFileName(file, Options()); + std::string metadata_classname = FilenameToClassname(metadata_filename); + std::string metadata_c_name = + StringReplace(metadata_classname, "\\", "_", true); + metadata_classname = StringReplace(metadata_classname, "\\", "\\\\", true); + FileDescriptorProto file_proto; + file->CopyTo(&file_proto); + std::string serialized; + file_proto.SerializeToString(&serialized); + printer.Print( + "/* $filename$ */\n" + "\n" + "zend_class_entry* $metadata_c_name$_ce;\n" + "\n" + "const char $c_name$_descriptor [$size$] = {\n", + "filename", file->name(), + "c_name", c_name, + "metadata_c_name", metadata_c_name, + "size", std::to_string(serialized.size())); + + for (size_t i = 0; i < serialized.size();) { + for (size_t j = 0; j < 25 && i < serialized.size(); ++i, ++j) { + printer.Print("'$ch$', ", "ch", CEscape(serialized.substr(i, 1))); + } + printer.Print("\n"); + } + + printer.Print( + "};\n" + "\n" + "static void $c_name$_AddDescriptor() {\n" + " if (DescriptorPool_HasFile(\"$filename$\")) return;\n", + "filename", file->name(), + "c_name", c_name, + "metadata_c_name", metadata_c_name); + + for (int i = 0; i < file->dependency_count(); i++) { + std::string dep_c_name = FilenameCName(file->dependency(i)); + printer.Print( + " $dep_c_name$_AddDescriptor();\n", + "dep_c_name", dep_c_name); + } + + printer.Print( + " DescriptorPool_AddDescriptor(\"$filename$\", $c_name$_descriptor,\n" + " sizeof($c_name$_descriptor));\n" + "}\n" + "\n" + "static PHP_METHOD($metadata_c_name$, initOnce) {\n" + " $c_name$_AddDescriptor();\n" + "}\n" + "\n" + "static zend_function_entry $metadata_c_name$_methods[] = {\n" + " PHP_ME($metadata_c_name$, initOnce, arginfo_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)\n" + " ZEND_FE_END\n" + "};\n" + "\n" + "static void $metadata_c_name$_ModuleInit() {\n" + " zend_class_entry tmp_ce;\n" + "\n" + " INIT_CLASS_ENTRY(tmp_ce, \"$metadata_classname$\",\n" + " $metadata_c_name$_methods);\n" + "\n" + " $metadata_c_name$_ce = zend_register_internal_class(&tmp_ce);\n" + "}\n" + "\n", + "filename", file->name(), + "c_name", c_name, + "metadata_c_name", metadata_c_name, + "metadata_classname", metadata_classname); + for (int i = 0; i < file->message_type_count(); i++) { + GenerateCMessage(file->message_type(i), &printer); + } + for (int i = 0; i < file->enum_type_count(); i++) { + GenerateCEnum(file->enum_type(i), &printer); + } + } + + printer.Print( + "static void WellKnownTypes_ModuleInit() {\n"); + + for (auto file : files) { + std::string metadata_filename = GeneratedMetadataFileName(file, Options()); + std::string metadata_classname = FilenameToClassname(metadata_filename); + std::string metadata_c_name = + StringReplace(metadata_classname, "\\", "_", true); + printer.Print( + " $metadata_c_name$_ModuleInit();\n", + "metadata_c_name", metadata_c_name); + for (int i = 0; i < file->message_type_count(); i++) { + GenerateCInit(file->message_type(i), &printer); + } + for (int i = 0; i < file->enum_type_count(); i++) { + GenerateEnumCInit(file->enum_type(i), &printer); + } + } + + printer.Print( + "}\n"); +} + +} // namespace + +std::string GeneratedClassName(const Descriptor* desc) { + return GeneratedClassNameImpl(desc); +} + +std::string GeneratedClassName(const EnumDescriptor* desc) { + return GeneratedClassNameImpl(desc); +} + +std::string GeneratedClassName(const ServiceDescriptor* desc) { + return GeneratedClassNameImpl(desc); +} + +bool Generator::Generate(const FileDescriptor* file, + const std::string& parameter, + GeneratorContext* generator_context, + std::string* error) const { + return Generate(file, Options(), generator_context, error); +} + +bool Generator::Generate(const FileDescriptor* file, const Options& options, + GeneratorContext* generator_context, + std::string* error) const { + if (options.is_descriptor && file->name() != kDescriptorFile) { + *error = + "Can only generate PHP code for google/protobuf/descriptor.proto.\n"; + return false; + } + + if (!options.is_descriptor && file->syntax() != FileDescriptor::SYNTAX_PROTO3) { + *error = + "Can only generate PHP code for proto3 .proto files.\n" + "Please add 'syntax = \"proto3\";' to the top of your .proto file.\n"; + return false; + } + + GenerateFile(file, options, generator_context); + + return true; +} + +bool Generator::GenerateAll(const std::vector<const FileDescriptor*>& files, + const std::string& parameter, + GeneratorContext* generator_context, + std::string* error) const { + Options options; + + for (const auto& option : Split(parameter, ",", true)) { + const std::vector<std::string> option_pair = Split(option, "=", true); + if (HasPrefixString(option_pair[0], "aggregate_metadata")) { + options.aggregate_metadata = true; + for (const auto& prefix : Split(option_pair[1], "#", false)) { + options.aggregate_metadata_prefixes.emplace(prefix); + GOOGLE_LOG(INFO) << prefix; + } + } else if (option_pair[0] == "internal") { + options.is_descriptor = true; + } else if (option_pair[0] == "internal_generate_c_wkt") { + GenerateCWellKnownTypes(files, generator_context); + } else { + GOOGLE_LOG(FATAL) << "Unknown codegen option: " << option_pair[0]; + } + } + + for (auto file : files) { + if (!Generate(file, options, generator_context, error)) { + return false; + } + } + + return true; +} + +} // namespace php +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/php/php_generator.h b/NorthstarDedicatedTest/include/protobuf/compiler/php/php_generator.h new file mode 100644 index 00000000..d3a977aa --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/php/php_generator.h @@ -0,0 +1,92 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_PHP_GENERATOR_H__ +#define GOOGLE_PROTOBUF_COMPILER_PHP_GENERATOR_H__ + +#include <compiler/code_generator.h> +#include <descriptor.h> + +#include <string> + +#include <port_def.inc> + +namespace google { +namespace protobuf { +namespace compiler { +namespace php { + +struct Options; + +class PROTOC_EXPORT Generator : public CodeGenerator { + public: + virtual bool Generate( + const FileDescriptor* file, + const std::string& parameter, + GeneratorContext* generator_context, + std::string* error) const override; + + bool GenerateAll(const std::vector<const FileDescriptor*>& files, + const std::string& parameter, + GeneratorContext* generator_context, + std::string* error) const override; + + uint64_t GetSupportedFeatures() const override { + return FEATURE_PROTO3_OPTIONAL; + } + + private: + bool Generate( + const FileDescriptor* file, + const Options& options, + GeneratorContext* generator_context, + std::string* error) const; +}; + +// To skip reserved keywords in php, some generated classname are prefixed. +// Other code generators may need following API to figure out the actual +// classname. +PROTOC_EXPORT std::string GeneratedClassName(const Descriptor* desc); +PROTOC_EXPORT std::string GeneratedClassName(const EnumDescriptor* desc); +PROTOC_EXPORT std::string GeneratedClassName(const ServiceDescriptor* desc); + +inline bool IsWrapperType(const FieldDescriptor* descriptor) { + return descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && + descriptor->message_type()->file()->name() == "google/protobuf/wrappers.proto"; +} + +} // namespace php +} // namespace compiler +} // namespace protobuf +} // namespace google + +#include <port_undef.inc> + +#endif // GOOGLE_PROTOBUF_COMPILER_PHP_GENERATOR_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/plugin.cc b/NorthstarDedicatedTest/include/protobuf/compiler/plugin.cc new file mode 100644 index 00000000..8ab8dfc8 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/plugin.cc @@ -0,0 +1,200 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) + +#include <compiler/plugin.h> + +#include <iostream> +#include <set> + +#ifdef _WIN32 +#include <fcntl.h> +#else +#include <unistd.h> +#endif + +#include <stubs/logging.h> +#include <stubs/common.h> +#include <compiler/plugin.pb.h> +#include <compiler/code_generator.h> +#include <io/zero_copy_stream_impl.h> +#include <descriptor.h> +#include <io/io_win32.h> + + +namespace google { +namespace protobuf { +namespace compiler { + +#if defined(_WIN32) +// DO NOT include <io.h>, instead create functions in io_win32.{h,cc} and import +// them like we do below. +using google::protobuf::io::win32::setmode; +#endif + +class GeneratorResponseContext : public GeneratorContext { + public: + GeneratorResponseContext( + const Version& compiler_version, CodeGeneratorResponse* response, + const std::vector<const FileDescriptor*>& parsed_files) + : compiler_version_(compiler_version), + response_(response), + parsed_files_(parsed_files) {} + virtual ~GeneratorResponseContext() {} + + // implements GeneratorContext -------------------------------------- + + io::ZeroCopyOutputStream* Open(const std::string& filename) override { + CodeGeneratorResponse::File* file = response_->add_file(); + file->set_name(filename); + return new io::StringOutputStream(file->mutable_content()); + } + + io::ZeroCopyOutputStream* OpenForInsert( + const std::string& filename, + const std::string& insertion_point) override { + CodeGeneratorResponse::File* file = response_->add_file(); + file->set_name(filename); + file->set_insertion_point(insertion_point); + return new io::StringOutputStream(file->mutable_content()); + } + + io::ZeroCopyOutputStream* OpenForInsertWithGeneratedCodeInfo( + const std::string& filename, const std::string& insertion_point, + const google::protobuf::GeneratedCodeInfo& info) override { + CodeGeneratorResponse::File* file = response_->add_file(); + file->set_name(filename); + file->set_insertion_point(insertion_point); + *file->mutable_generated_code_info() = info; + return new io::StringOutputStream(file->mutable_content()); + } + + void ListParsedFiles(std::vector<const FileDescriptor*>* output) override { + *output = parsed_files_; + } + + void GetCompilerVersion(Version* version) const override { + *version = compiler_version_; + } + + private: + Version compiler_version_; + CodeGeneratorResponse* response_; + const std::vector<const FileDescriptor*>& parsed_files_; +}; + +bool GenerateCode(const CodeGeneratorRequest& request, + const CodeGenerator& generator, + CodeGeneratorResponse* response, std::string* error_msg) { + DescriptorPool pool; + for (int i = 0; i < request.proto_file_size(); i++) { + const FileDescriptor* file = pool.BuildFile(request.proto_file(i)); + if (file == NULL) { + // BuildFile() already wrote an error message. + return false; + } + } + + std::vector<const FileDescriptor*> parsed_files; + for (int i = 0; i < request.file_to_generate_size(); i++) { + parsed_files.push_back(pool.FindFileByName(request.file_to_generate(i))); + if (parsed_files.back() == NULL) { + *error_msg = + "protoc asked plugin to generate a file but " + "did not provide a descriptor for the file: " + + request.file_to_generate(i); + return false; + } + } + + GeneratorResponseContext context(request.compiler_version(), response, + parsed_files); + + + std::string error; + bool succeeded = generator.GenerateAll(parsed_files, request.parameter(), + &context, &error); + + response->set_supported_features(generator.GetSupportedFeatures()); + + if (!succeeded && error.empty()) { + error = + "Code generator returned false but provided no error " + "description."; + } + if (!error.empty()) { + response->set_error(error); + } + + return true; +} + +int PluginMain(int argc, char* argv[], const CodeGenerator* generator) { + + if (argc > 1) { + std::cerr << argv[0] << ": Unknown option: " << argv[1] << std::endl; + return 1; + } + +#ifdef _WIN32 + setmode(STDIN_FILENO, _O_BINARY); + setmode(STDOUT_FILENO, _O_BINARY); +#endif + + CodeGeneratorRequest request; + if (!request.ParseFromFileDescriptor(STDIN_FILENO)) { + std::cerr << argv[0] << ": protoc sent unparseable request to plugin." + << std::endl; + return 1; + } + + + std::string error_msg; + CodeGeneratorResponse response; + + if (GenerateCode(request, *generator, &response, &error_msg)) { + if (!response.SerializeToFileDescriptor(STDOUT_FILENO)) { + std::cerr << argv[0] << ": Error writing to stdout." << std::endl; + return 1; + } + } else { + if (!error_msg.empty()) { + std::cerr << argv[0] << ": " << error_msg << std::endl; + } + return 1; + } + + return 0; +} + +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/plugin.h b/NorthstarDedicatedTest/include/protobuf/compiler/plugin.h new file mode 100644 index 00000000..24af7aa1 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/plugin.h @@ -0,0 +1,95 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// +// Front-end for protoc code generator plugins written in C++. +// +// To implement a protoc plugin in C++, simply write an implementation of +// CodeGenerator, then create a main() function like: +// int main(int argc, char* argv[]) { +// MyCodeGenerator generator; +// return google::protobuf::compiler::PluginMain(argc, argv, &generator); +// } +// You must link your plugin against libprotobuf and libprotoc. +// +// The core part of PluginMain is to invoke the given CodeGenerator on a +// CodeGeneratorRequest to generate a CodeGeneratorResponse. This part is +// abstracted out and made into function GenerateCode so that it can be reused, +// for example, to implement a variant of PluginMain that does some +// preprocessing on the input CodeGeneratorRequest before feeding the request +// to the given code generator. +// +// To get protoc to use the plugin, do one of the following: +// * Place the plugin binary somewhere in the PATH and give it the name +// "protoc-gen-NAME" (replacing "NAME" with the name of your plugin). If you +// then invoke protoc with the parameter --NAME_out=OUT_DIR (again, replace +// "NAME" with your plugin's name), protoc will invoke your plugin to generate +// the output, which will be placed in OUT_DIR. +// * Place the plugin binary anywhere, with any name, and pass the --plugin +// parameter to protoc to direct it to your plugin like so: +// protoc --plugin=protoc-gen-NAME=path/to/mybinary --NAME_out=OUT_DIR +// On Windows, make sure to include the .exe suffix: +// protoc --plugin=protoc-gen-NAME=path/to/mybinary.exe --NAME_out=OUT_DIR + +#ifndef GOOGLE_PROTOBUF_COMPILER_PLUGIN_H__ +#define GOOGLE_PROTOBUF_COMPILER_PLUGIN_H__ + +#include <string> + +#include <port_def.inc> + +namespace google { +namespace protobuf { +namespace compiler { + +class CodeGenerator; // code_generator.h +class CodeGeneratorRequest; +class CodeGeneratorResponse; + +// Implements main() for a protoc plugin exposing the given code generator. +PROTOC_EXPORT int PluginMain(int argc, char* argv[], + const CodeGenerator* generator); + + +// Generates code using the given code generator. Returns true if the code +// generation is successful. If the code generation fails, error_msg may be +// populated to describe the failure cause. +bool GenerateCode(const CodeGeneratorRequest& request, + const CodeGenerator& generator, + CodeGeneratorResponse* response, std::string* error_msg); + +} // namespace compiler +} // namespace protobuf +} // namespace google + +#include <port_undef.inc> + +#endif // GOOGLE_PROTOBUF_COMPILER_PLUGIN_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/plugin.pb.cc b/NorthstarDedicatedTest/include/protobuf/compiler/plugin.pb.cc new file mode 100644 index 00000000..28a197d1 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/plugin.pb.cc @@ -0,0 +1,1584 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: google/protobuf/compiler/plugin.proto + +#include <compiler/plugin.pb.h> + +#include <algorithm> + +#include <io/coded_stream.h> +#include <extension_set.h> +#include <wire_format_lite.h> +#include <descriptor.h> +#include <generated_message_reflection.h> +#include <reflection_ops.h> +#include <wire_format.h> +// @@protoc_insertion_point(includes) +#include <port_def.inc> + +PROTOBUF_PRAGMA_INIT_SEG +PROTOBUF_NAMESPACE_OPEN +namespace compiler { +constexpr Version::Version( + ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized) + : suffix_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string) + , major_(0) + , minor_(0) + , patch_(0){} +struct VersionDefaultTypeInternal { + constexpr VersionDefaultTypeInternal() + : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {} + ~VersionDefaultTypeInternal() {} + union { + Version _instance; + }; +}; +PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT VersionDefaultTypeInternal _Version_default_instance_; +constexpr CodeGeneratorRequest::CodeGeneratorRequest( + ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized) + : file_to_generate_() + , proto_file_() + , parameter_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string) + , compiler_version_(nullptr){} +struct CodeGeneratorRequestDefaultTypeInternal { + constexpr CodeGeneratorRequestDefaultTypeInternal() + : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {} + ~CodeGeneratorRequestDefaultTypeInternal() {} + union { + CodeGeneratorRequest _instance; + }; +}; +PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT CodeGeneratorRequestDefaultTypeInternal _CodeGeneratorRequest_default_instance_; +constexpr CodeGeneratorResponse_File::CodeGeneratorResponse_File( + ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized) + : name_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string) + , insertion_point_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string) + , content_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string) + , generated_code_info_(nullptr){} +struct CodeGeneratorResponse_FileDefaultTypeInternal { + constexpr CodeGeneratorResponse_FileDefaultTypeInternal() + : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {} + ~CodeGeneratorResponse_FileDefaultTypeInternal() {} + union { + CodeGeneratorResponse_File _instance; + }; +}; +PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT CodeGeneratorResponse_FileDefaultTypeInternal _CodeGeneratorResponse_File_default_instance_; +constexpr CodeGeneratorResponse::CodeGeneratorResponse( + ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized) + : file_() + , error_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string) + , supported_features_(uint64_t{0u}){} +struct CodeGeneratorResponseDefaultTypeInternal { + constexpr CodeGeneratorResponseDefaultTypeInternal() + : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {} + ~CodeGeneratorResponseDefaultTypeInternal() {} + union { + CodeGeneratorResponse _instance; + }; +}; +PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT CodeGeneratorResponseDefaultTypeInternal _CodeGeneratorResponse_default_instance_; +} // namespace compiler +PROTOBUF_NAMESPACE_CLOSE +static ::PROTOBUF_NAMESPACE_ID::Metadata file_level_metadata_google_2fprotobuf_2fcompiler_2fplugin_2eproto[4]; +static const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* file_level_enum_descriptors_google_2fprotobuf_2fcompiler_2fplugin_2eproto[1]; +static constexpr ::PROTOBUF_NAMESPACE_ID::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2fcompiler_2fplugin_2eproto = nullptr; + +const uint32_t TableStruct_google_2fprotobuf_2fcompiler_2fplugin_2eproto::offsets[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = { + PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::Version, _has_bits_), + PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::Version, _internal_metadata_), + ~0u, // no _extensions_ + ~0u, // no _oneof_case_ + ~0u, // no _weak_field_map_ + ~0u, // no _inlined_string_donated_ + PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::Version, major_), + PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::Version, minor_), + PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::Version, patch_), + PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::Version, suffix_), + 1, + 2, + 3, + 0, + PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorRequest, _has_bits_), + PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorRequest, _internal_metadata_), + ~0u, // no _extensions_ + ~0u, // no _oneof_case_ + ~0u, // no _weak_field_map_ + ~0u, // no _inlined_string_donated_ + PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorRequest, file_to_generate_), + PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorRequest, parameter_), + PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorRequest, proto_file_), + PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorRequest, compiler_version_), + ~0u, + 0, + ~0u, + 1, + PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File, _has_bits_), + PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File, _internal_metadata_), + ~0u, // no _extensions_ + ~0u, // no _oneof_case_ + ~0u, // no _weak_field_map_ + ~0u, // no _inlined_string_donated_ + PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File, name_), + PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File, insertion_point_), + PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File, content_), + PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File, generated_code_info_), + 0, + 1, + 2, + 3, + PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse, _has_bits_), + PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse, _internal_metadata_), + ~0u, // no _extensions_ + ~0u, // no _oneof_case_ + ~0u, // no _weak_field_map_ + ~0u, // no _inlined_string_donated_ + PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse, error_), + PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse, supported_features_), + PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse, file_), + 0, + 1, + ~0u, +}; +static const ::PROTOBUF_NAMESPACE_ID::internal::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = { + { 0, 10, -1, sizeof(::PROTOBUF_NAMESPACE_ID::compiler::Version)}, + { 14, 24, -1, sizeof(::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorRequest)}, + { 28, 38, -1, sizeof(::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File)}, + { 42, 51, -1, sizeof(::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse)}, +}; + +static ::PROTOBUF_NAMESPACE_ID::Message const * const file_default_instances[] = { + reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::PROTOBUF_NAMESPACE_ID::compiler::_Version_default_instance_), + reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::PROTOBUF_NAMESPACE_ID::compiler::_CodeGeneratorRequest_default_instance_), + reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::PROTOBUF_NAMESPACE_ID::compiler::_CodeGeneratorResponse_File_default_instance_), + reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::PROTOBUF_NAMESPACE_ID::compiler::_CodeGeneratorResponse_default_instance_), +}; + +const char descriptor_table_protodef_google_2fprotobuf_2fcompiler_2fplugin_2eproto[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = + "\n%google/protobuf/compiler/plugin.proto\022" + "\030google.protobuf.compiler\032 google/protob" + "uf/descriptor.proto\"F\n\007Version\022\r\n\005major\030" + "\001 \001(\005\022\r\n\005minor\030\002 \001(\005\022\r\n\005patch\030\003 \001(\005\022\016\n\006s" + "uffix\030\004 \001(\t\"\272\001\n\024CodeGeneratorRequest\022\030\n\020" + "file_to_generate\030\001 \003(\t\022\021\n\tparameter\030\002 \001(" + "\t\0228\n\nproto_file\030\017 \003(\0132$.google.protobuf." + "FileDescriptorProto\022;\n\020compiler_version\030" + "\003 \001(\0132!.google.protobuf.compiler.Version" + "\"\301\002\n\025CodeGeneratorResponse\022\r\n\005error\030\001 \001(" + "\t\022\032\n\022supported_features\030\002 \001(\004\022B\n\004file\030\017 " + "\003(\01324.google.protobuf.compiler.CodeGener" + "atorResponse.File\032\177\n\004File\022\014\n\004name\030\001 \001(\t\022" + "\027\n\017insertion_point\030\002 \001(\t\022\017\n\007content\030\017 \001(" + "\t\022\?\n\023generated_code_info\030\020 \001(\0132\".google." + "protobuf.GeneratedCodeInfo\"8\n\007Feature\022\020\n" + "\014FEATURE_NONE\020\000\022\033\n\027FEATURE_PROTO3_OPTION" + "AL\020\001BW\n\034com.google.protobuf.compilerB\014Pl" + "uginProtosZ)google.golang.org/protobuf/t" + "ypes/pluginpb" + ; +static const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable*const descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_deps[1] = { + &::descriptor_table_google_2fprotobuf_2fdescriptor_2eproto, +}; +static ::PROTOBUF_NAMESPACE_ID::internal::once_flag descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_once; +const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto = { + false, false, 773, descriptor_table_protodef_google_2fprotobuf_2fcompiler_2fplugin_2eproto, "google/protobuf/compiler/plugin.proto", + &descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_once, descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_deps, 1, 4, + schemas, file_default_instances, TableStruct_google_2fprotobuf_2fcompiler_2fplugin_2eproto::offsets, + file_level_metadata_google_2fprotobuf_2fcompiler_2fplugin_2eproto, file_level_enum_descriptors_google_2fprotobuf_2fcompiler_2fplugin_2eproto, file_level_service_descriptors_google_2fprotobuf_2fcompiler_2fplugin_2eproto, +}; +PROTOBUF_ATTRIBUTE_WEAK const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable* descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_getter() { + return &descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto; +} + +// Force running AddDescriptors() at dynamic initialization time. +PROTOBUF_ATTRIBUTE_INIT_PRIORITY static ::PROTOBUF_NAMESPACE_ID::internal::AddDescriptorsRunner dynamic_init_dummy_google_2fprotobuf_2fcompiler_2fplugin_2eproto(&descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto); +PROTOBUF_NAMESPACE_OPEN +namespace compiler { +const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* CodeGeneratorResponse_Feature_descriptor() { + ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto); + return file_level_enum_descriptors_google_2fprotobuf_2fcompiler_2fplugin_2eproto[0]; +} +bool CodeGeneratorResponse_Feature_IsValid(int value) { + switch (value) { + case 0: + case 1: + return true; + default: + return false; + } +} + +#if (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912)) +constexpr CodeGeneratorResponse_Feature CodeGeneratorResponse::FEATURE_NONE; +constexpr CodeGeneratorResponse_Feature CodeGeneratorResponse::FEATURE_PROTO3_OPTIONAL; +constexpr CodeGeneratorResponse_Feature CodeGeneratorResponse::Feature_MIN; +constexpr CodeGeneratorResponse_Feature CodeGeneratorResponse::Feature_MAX; +constexpr int CodeGeneratorResponse::Feature_ARRAYSIZE; +#endif // (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912)) + +// =================================================================== + +class Version::_Internal { + public: + using HasBits = decltype(std::declval<Version>()._has_bits_); + static void set_has_major(HasBits* has_bits) { + (*has_bits)[0] |= 2u; + } + static void set_has_minor(HasBits* has_bits) { + (*has_bits)[0] |= 4u; + } + static void set_has_patch(HasBits* has_bits) { + (*has_bits)[0] |= 8u; + } + static void set_has_suffix(HasBits* has_bits) { + (*has_bits)[0] |= 1u; + } +}; + +Version::Version(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned) + : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) { + SharedCtor(); + if (!is_message_owned) { + RegisterArenaDtor(arena); + } + // @@protoc_insertion_point(arena_constructor:google.protobuf.compiler.Version) +} +Version::Version(const Version& from) + : ::PROTOBUF_NAMESPACE_ID::Message(), + _has_bits_(from._has_bits_) { + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); + suffix_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); + #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + suffix_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (from._internal_has_suffix()) { + suffix_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_suffix(), + GetArenaForAllocation()); + } + ::memcpy(&major_, &from.major_, + static_cast<size_t>(reinterpret_cast<char*>(&patch_) - + reinterpret_cast<char*>(&major_)) + sizeof(patch_)); + // @@protoc_insertion_point(copy_constructor:google.protobuf.compiler.Version) +} + +inline void Version::SharedCtor() { +suffix_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + suffix_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING +::memset(reinterpret_cast<char*>(this) + static_cast<size_t>( + reinterpret_cast<char*>(&major_) - reinterpret_cast<char*>(this)), + 0, static_cast<size_t>(reinterpret_cast<char*>(&patch_) - + reinterpret_cast<char*>(&major_)) + sizeof(patch_)); +} + +Version::~Version() { + // @@protoc_insertion_point(destructor:google.protobuf.compiler.Version) + if (GetArenaForAllocation() != nullptr) return; + SharedDtor(); + _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +inline void Version::SharedDtor() { + GOOGLE_DCHECK(GetArenaForAllocation() == nullptr); + suffix_.DestroyNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); +} + +void Version::ArenaDtor(void* object) { + Version* _this = reinterpret_cast< Version* >(object); + (void)_this; +} +void Version::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) { +} +void Version::SetCachedSize(int size) const { + _cached_size_.Set(size); +} + +void Version::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.compiler.Version) + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + cached_has_bits = _has_bits_[0]; + if (cached_has_bits & 0x00000001u) { + suffix_.ClearNonDefaultToEmpty(); + } + if (cached_has_bits & 0x0000000eu) { + ::memset(&major_, 0, static_cast<size_t>( + reinterpret_cast<char*>(&patch_) - + reinterpret_cast<char*>(&major_)) + sizeof(patch_)); + } + _has_bits_.Clear(); + _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +const char* Version::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) { +#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure + _Internal::HasBits has_bits{}; + while (!ctx->Done(&ptr)) { + uint32_t tag; + ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag); + switch (tag >> 3) { + // optional int32 major = 1; + case 1: + if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 8)) { + _Internal::set_has_major(&has_bits); + major_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // optional int32 minor = 2; + case 2: + if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 16)) { + _Internal::set_has_minor(&has_bits); + minor_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // optional int32 patch = 3; + case 3: + if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 24)) { + _Internal::set_has_patch(&has_bits); + patch_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // optional string suffix = 4; + case 4: + if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 34)) { + auto str = _internal_mutable_suffix(); + ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx); + #ifndef NDEBUG + ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.compiler.Version.suffix"); + #endif // !NDEBUG + CHK_(ptr); + } else + goto handle_unusual; + continue; + default: + goto handle_unusual; + } // switch + handle_unusual: + if ((tag == 0) || ((tag & 7) == 4)) { + CHK_(ptr); + ctx->SetLastTag(tag); + goto message_done; + } + ptr = UnknownFieldParse( + tag, + _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(), + ptr, ctx); + CHK_(ptr != nullptr); + } // while +message_done: + _has_bits_.Or(has_bits); + return ptr; +failure: + ptr = nullptr; + goto message_done; +#undef CHK_ +} + +uint8_t* Version::_InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.compiler.Version) + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + cached_has_bits = _has_bits_[0]; + // optional int32 major = 1; + if (cached_has_bits & 0x00000002u) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(1, this->_internal_major(), target); + } + + // optional int32 minor = 2; + if (cached_has_bits & 0x00000004u) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(2, this->_internal_minor(), target); + } + + // optional int32 patch = 3; + if (cached_has_bits & 0x00000008u) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(3, this->_internal_patch(), target); + } + + // optional string suffix = 4; + if (cached_has_bits & 0x00000001u) { + ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField( + this->_internal_suffix().data(), static_cast<int>(this->_internal_suffix().length()), + ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE, + "google.protobuf.compiler.Version.suffix"); + target = stream->WriteStringMaybeAliased( + 4, this->_internal_suffix(), target); + } + + if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray( + _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream); + } + // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.compiler.Version) + return target; +} + +size_t Version::ByteSizeLong() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.compiler.Version) + size_t total_size = 0; + + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + cached_has_bits = _has_bits_[0]; + if (cached_has_bits & 0x0000000fu) { + // optional string suffix = 4; + if (cached_has_bits & 0x00000001u) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize( + this->_internal_suffix()); + } + + // optional int32 major = 1; + if (cached_has_bits & 0x00000002u) { + total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32SizePlusOne(this->_internal_major()); + } + + // optional int32 minor = 2; + if (cached_has_bits & 0x00000004u) { + total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32SizePlusOne(this->_internal_minor()); + } + + // optional int32 patch = 3; + if (cached_has_bits & 0x00000008u) { + total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32SizePlusOne(this->_internal_patch()); + } + + } + return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_); +} + +const ::PROTOBUF_NAMESPACE_ID::Message::ClassData Version::_class_data_ = { + ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSizeCheck, + Version::MergeImpl +}; +const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*Version::GetClassData() const { return &_class_data_; } + +void Version::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, + const ::PROTOBUF_NAMESPACE_ID::Message& from) { + static_cast<Version *>(to)->MergeFrom( + static_cast<const Version &>(from)); +} + + +void Version::MergeFrom(const Version& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.compiler.Version) + GOOGLE_DCHECK_NE(&from, this); + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + cached_has_bits = from._has_bits_[0]; + if (cached_has_bits & 0x0000000fu) { + if (cached_has_bits & 0x00000001u) { + _internal_set_suffix(from._internal_suffix()); + } + if (cached_has_bits & 0x00000002u) { + major_ = from.major_; + } + if (cached_has_bits & 0x00000004u) { + minor_ = from.minor_; + } + if (cached_has_bits & 0x00000008u) { + patch_ = from.patch_; + } + _has_bits_[0] |= cached_has_bits; + } + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); +} + +void Version::CopyFrom(const Version& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.compiler.Version) + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool Version::IsInitialized() const { + return true; +} + +void Version::InternalSwap(Version* other) { + using std::swap; + auto* lhs_arena = GetArenaForAllocation(); + auto* rhs_arena = other->GetArenaForAllocation(); + _internal_metadata_.InternalSwap(&other->_internal_metadata_); + swap(_has_bits_[0], other->_has_bits_[0]); + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap( + &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), + &suffix_, lhs_arena, + &other->suffix_, rhs_arena + ); + ::PROTOBUF_NAMESPACE_ID::internal::memswap< + PROTOBUF_FIELD_OFFSET(Version, patch_) + + sizeof(Version::patch_) + - PROTOBUF_FIELD_OFFSET(Version, major_)>( + reinterpret_cast<char*>(&major_), + reinterpret_cast<char*>(&other->major_)); +} + +::PROTOBUF_NAMESPACE_ID::Metadata Version::GetMetadata() const { + return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors( + &descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_getter, &descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_once, + file_level_metadata_google_2fprotobuf_2fcompiler_2fplugin_2eproto[0]); +} + +// =================================================================== + +class CodeGeneratorRequest::_Internal { + public: + using HasBits = decltype(std::declval<CodeGeneratorRequest>()._has_bits_); + static void set_has_parameter(HasBits* has_bits) { + (*has_bits)[0] |= 1u; + } + static const ::PROTOBUF_NAMESPACE_ID::compiler::Version& compiler_version(const CodeGeneratorRequest* msg); + static void set_has_compiler_version(HasBits* has_bits) { + (*has_bits)[0] |= 2u; + } +}; + +const ::PROTOBUF_NAMESPACE_ID::compiler::Version& +CodeGeneratorRequest::_Internal::compiler_version(const CodeGeneratorRequest* msg) { + return *msg->compiler_version_; +} +void CodeGeneratorRequest::clear_proto_file() { + proto_file_.Clear(); +} +CodeGeneratorRequest::CodeGeneratorRequest(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned) + : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned), + file_to_generate_(arena), + proto_file_(arena) { + SharedCtor(); + if (!is_message_owned) { + RegisterArenaDtor(arena); + } + // @@protoc_insertion_point(arena_constructor:google.protobuf.compiler.CodeGeneratorRequest) +} +CodeGeneratorRequest::CodeGeneratorRequest(const CodeGeneratorRequest& from) + : ::PROTOBUF_NAMESPACE_ID::Message(), + _has_bits_(from._has_bits_), + file_to_generate_(from.file_to_generate_), + proto_file_(from.proto_file_) { + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); + parameter_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); + #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + parameter_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (from._internal_has_parameter()) { + parameter_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_parameter(), + GetArenaForAllocation()); + } + if (from._internal_has_compiler_version()) { + compiler_version_ = new ::PROTOBUF_NAMESPACE_ID::compiler::Version(*from.compiler_version_); + } else { + compiler_version_ = nullptr; + } + // @@protoc_insertion_point(copy_constructor:google.protobuf.compiler.CodeGeneratorRequest) +} + +inline void CodeGeneratorRequest::SharedCtor() { +parameter_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + parameter_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING +compiler_version_ = nullptr; +} + +CodeGeneratorRequest::~CodeGeneratorRequest() { + // @@protoc_insertion_point(destructor:google.protobuf.compiler.CodeGeneratorRequest) + if (GetArenaForAllocation() != nullptr) return; + SharedDtor(); + _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +inline void CodeGeneratorRequest::SharedDtor() { + GOOGLE_DCHECK(GetArenaForAllocation() == nullptr); + parameter_.DestroyNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); + if (this != internal_default_instance()) delete compiler_version_; +} + +void CodeGeneratorRequest::ArenaDtor(void* object) { + CodeGeneratorRequest* _this = reinterpret_cast< CodeGeneratorRequest* >(object); + (void)_this; +} +void CodeGeneratorRequest::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) { +} +void CodeGeneratorRequest::SetCachedSize(int size) const { + _cached_size_.Set(size); +} + +void CodeGeneratorRequest::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.compiler.CodeGeneratorRequest) + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + file_to_generate_.Clear(); + proto_file_.Clear(); + cached_has_bits = _has_bits_[0]; + if (cached_has_bits & 0x00000003u) { + if (cached_has_bits & 0x00000001u) { + parameter_.ClearNonDefaultToEmpty(); + } + if (cached_has_bits & 0x00000002u) { + GOOGLE_DCHECK(compiler_version_ != nullptr); + compiler_version_->Clear(); + } + } + _has_bits_.Clear(); + _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +const char* CodeGeneratorRequest::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) { +#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure + _Internal::HasBits has_bits{}; + while (!ctx->Done(&ptr)) { + uint32_t tag; + ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag); + switch (tag >> 3) { + // repeated string file_to_generate = 1; + case 1: + if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) { + ptr -= 1; + do { + ptr += 1; + auto str = _internal_add_file_to_generate(); + ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx); + #ifndef NDEBUG + ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.compiler.CodeGeneratorRequest.file_to_generate"); + #endif // !NDEBUG + CHK_(ptr); + if (!ctx->DataAvailable(ptr)) break; + } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<10>(ptr)); + } else + goto handle_unusual; + continue; + // optional string parameter = 2; + case 2: + if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 18)) { + auto str = _internal_mutable_parameter(); + ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx); + #ifndef NDEBUG + ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.compiler.CodeGeneratorRequest.parameter"); + #endif // !NDEBUG + CHK_(ptr); + } else + goto handle_unusual; + continue; + // optional .google.protobuf.compiler.Version compiler_version = 3; + case 3: + if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 26)) { + ptr = ctx->ParseMessage(_internal_mutable_compiler_version(), ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // repeated .google.protobuf.FileDescriptorProto proto_file = 15; + case 15: + if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 122)) { + ptr -= 1; + do { + ptr += 1; + ptr = ctx->ParseMessage(_internal_add_proto_file(), ptr); + CHK_(ptr); + if (!ctx->DataAvailable(ptr)) break; + } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<122>(ptr)); + } else + goto handle_unusual; + continue; + default: + goto handle_unusual; + } // switch + handle_unusual: + if ((tag == 0) || ((tag & 7) == 4)) { + CHK_(ptr); + ctx->SetLastTag(tag); + goto message_done; + } + ptr = UnknownFieldParse( + tag, + _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(), + ptr, ctx); + CHK_(ptr != nullptr); + } // while +message_done: + _has_bits_.Or(has_bits); + return ptr; +failure: + ptr = nullptr; + goto message_done; +#undef CHK_ +} + +uint8_t* CodeGeneratorRequest::_InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.compiler.CodeGeneratorRequest) + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + // repeated string file_to_generate = 1; + for (int i = 0, n = this->_internal_file_to_generate_size(); i < n; i++) { + const auto& s = this->_internal_file_to_generate(i); + ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField( + s.data(), static_cast<int>(s.length()), + ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE, + "google.protobuf.compiler.CodeGeneratorRequest.file_to_generate"); + target = stream->WriteString(1, s, target); + } + + cached_has_bits = _has_bits_[0]; + // optional string parameter = 2; + if (cached_has_bits & 0x00000001u) { + ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField( + this->_internal_parameter().data(), static_cast<int>(this->_internal_parameter().length()), + ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE, + "google.protobuf.compiler.CodeGeneratorRequest.parameter"); + target = stream->WriteStringMaybeAliased( + 2, this->_internal_parameter(), target); + } + + // optional .google.protobuf.compiler.Version compiler_version = 3; + if (cached_has_bits & 0x00000002u) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite:: + InternalWriteMessage( + 3, _Internal::compiler_version(this), target, stream); + } + + // repeated .google.protobuf.FileDescriptorProto proto_file = 15; + for (unsigned int i = 0, + n = static_cast<unsigned int>(this->_internal_proto_file_size()); i < n; i++) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite:: + InternalWriteMessage(15, this->_internal_proto_file(i), target, stream); + } + + if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray( + _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream); + } + // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.compiler.CodeGeneratorRequest) + return target; +} + +size_t CodeGeneratorRequest::ByteSizeLong() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.compiler.CodeGeneratorRequest) + size_t total_size = 0; + + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + // repeated string file_to_generate = 1; + total_size += 1 * + ::PROTOBUF_NAMESPACE_ID::internal::FromIntSize(file_to_generate_.size()); + for (int i = 0, n = file_to_generate_.size(); i < n; i++) { + total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize( + file_to_generate_.Get(i)); + } + + // repeated .google.protobuf.FileDescriptorProto proto_file = 15; + total_size += 1UL * this->_internal_proto_file_size(); + for (const auto& msg : this->proto_file_) { + total_size += + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg); + } + + cached_has_bits = _has_bits_[0]; + if (cached_has_bits & 0x00000003u) { + // optional string parameter = 2; + if (cached_has_bits & 0x00000001u) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize( + this->_internal_parameter()); + } + + // optional .google.protobuf.compiler.Version compiler_version = 3; + if (cached_has_bits & 0x00000002u) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize( + *compiler_version_); + } + + } + return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_); +} + +const ::PROTOBUF_NAMESPACE_ID::Message::ClassData CodeGeneratorRequest::_class_data_ = { + ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSizeCheck, + CodeGeneratorRequest::MergeImpl +}; +const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*CodeGeneratorRequest::GetClassData() const { return &_class_data_; } + +void CodeGeneratorRequest::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, + const ::PROTOBUF_NAMESPACE_ID::Message& from) { + static_cast<CodeGeneratorRequest *>(to)->MergeFrom( + static_cast<const CodeGeneratorRequest &>(from)); +} + + +void CodeGeneratorRequest::MergeFrom(const CodeGeneratorRequest& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.compiler.CodeGeneratorRequest) + GOOGLE_DCHECK_NE(&from, this); + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + file_to_generate_.MergeFrom(from.file_to_generate_); + proto_file_.MergeFrom(from.proto_file_); + cached_has_bits = from._has_bits_[0]; + if (cached_has_bits & 0x00000003u) { + if (cached_has_bits & 0x00000001u) { + _internal_set_parameter(from._internal_parameter()); + } + if (cached_has_bits & 0x00000002u) { + _internal_mutable_compiler_version()->::PROTOBUF_NAMESPACE_ID::compiler::Version::MergeFrom(from._internal_compiler_version()); + } + } + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); +} + +void CodeGeneratorRequest::CopyFrom(const CodeGeneratorRequest& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.compiler.CodeGeneratorRequest) + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool CodeGeneratorRequest::IsInitialized() const { + if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(proto_file_)) + return false; + return true; +} + +void CodeGeneratorRequest::InternalSwap(CodeGeneratorRequest* other) { + using std::swap; + auto* lhs_arena = GetArenaForAllocation(); + auto* rhs_arena = other->GetArenaForAllocation(); + _internal_metadata_.InternalSwap(&other->_internal_metadata_); + swap(_has_bits_[0], other->_has_bits_[0]); + file_to_generate_.InternalSwap(&other->file_to_generate_); + proto_file_.InternalSwap(&other->proto_file_); + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap( + &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), + ¶meter_, lhs_arena, + &other->parameter_, rhs_arena + ); + swap(compiler_version_, other->compiler_version_); +} + +::PROTOBUF_NAMESPACE_ID::Metadata CodeGeneratorRequest::GetMetadata() const { + return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors( + &descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_getter, &descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_once, + file_level_metadata_google_2fprotobuf_2fcompiler_2fplugin_2eproto[1]); +} + +// =================================================================== + +class CodeGeneratorResponse_File::_Internal { + public: + using HasBits = decltype(std::declval<CodeGeneratorResponse_File>()._has_bits_); + static void set_has_name(HasBits* has_bits) { + (*has_bits)[0] |= 1u; + } + static void set_has_insertion_point(HasBits* has_bits) { + (*has_bits)[0] |= 2u; + } + static void set_has_content(HasBits* has_bits) { + (*has_bits)[0] |= 4u; + } + static const ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo& generated_code_info(const CodeGeneratorResponse_File* msg); + static void set_has_generated_code_info(HasBits* has_bits) { + (*has_bits)[0] |= 8u; + } +}; + +const ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo& +CodeGeneratorResponse_File::_Internal::generated_code_info(const CodeGeneratorResponse_File* msg) { + return *msg->generated_code_info_; +} +void CodeGeneratorResponse_File::clear_generated_code_info() { + if (generated_code_info_ != nullptr) generated_code_info_->Clear(); + _has_bits_[0] &= ~0x00000008u; +} +CodeGeneratorResponse_File::CodeGeneratorResponse_File(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned) + : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) { + SharedCtor(); + if (!is_message_owned) { + RegisterArenaDtor(arena); + } + // @@protoc_insertion_point(arena_constructor:google.protobuf.compiler.CodeGeneratorResponse.File) +} +CodeGeneratorResponse_File::CodeGeneratorResponse_File(const CodeGeneratorResponse_File& from) + : ::PROTOBUF_NAMESPACE_ID::Message(), + _has_bits_(from._has_bits_) { + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); + name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); + #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (from._internal_has_name()) { + name_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_name(), + GetArenaForAllocation()); + } + insertion_point_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); + #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + insertion_point_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (from._internal_has_insertion_point()) { + insertion_point_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_insertion_point(), + GetArenaForAllocation()); + } + content_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); + #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + content_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (from._internal_has_content()) { + content_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_content(), + GetArenaForAllocation()); + } + if (from._internal_has_generated_code_info()) { + generated_code_info_ = new ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo(*from.generated_code_info_); + } else { + generated_code_info_ = nullptr; + } + // @@protoc_insertion_point(copy_constructor:google.protobuf.compiler.CodeGeneratorResponse.File) +} + +inline void CodeGeneratorResponse_File::SharedCtor() { +name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING +insertion_point_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + insertion_point_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING +content_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + content_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING +generated_code_info_ = nullptr; +} + +CodeGeneratorResponse_File::~CodeGeneratorResponse_File() { + // @@protoc_insertion_point(destructor:google.protobuf.compiler.CodeGeneratorResponse.File) + if (GetArenaForAllocation() != nullptr) return; + SharedDtor(); + _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +inline void CodeGeneratorResponse_File::SharedDtor() { + GOOGLE_DCHECK(GetArenaForAllocation() == nullptr); + name_.DestroyNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); + insertion_point_.DestroyNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); + content_.DestroyNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); + if (this != internal_default_instance()) delete generated_code_info_; +} + +void CodeGeneratorResponse_File::ArenaDtor(void* object) { + CodeGeneratorResponse_File* _this = reinterpret_cast< CodeGeneratorResponse_File* >(object); + (void)_this; +} +void CodeGeneratorResponse_File::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) { +} +void CodeGeneratorResponse_File::SetCachedSize(int size) const { + _cached_size_.Set(size); +} + +void CodeGeneratorResponse_File::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.compiler.CodeGeneratorResponse.File) + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + cached_has_bits = _has_bits_[0]; + if (cached_has_bits & 0x0000000fu) { + if (cached_has_bits & 0x00000001u) { + name_.ClearNonDefaultToEmpty(); + } + if (cached_has_bits & 0x00000002u) { + insertion_point_.ClearNonDefaultToEmpty(); + } + if (cached_has_bits & 0x00000004u) { + content_.ClearNonDefaultToEmpty(); + } + if (cached_has_bits & 0x00000008u) { + GOOGLE_DCHECK(generated_code_info_ != nullptr); + generated_code_info_->Clear(); + } + } + _has_bits_.Clear(); + _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +const char* CodeGeneratorResponse_File::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) { +#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure + _Internal::HasBits has_bits{}; + while (!ctx->Done(&ptr)) { + uint32_t tag; + ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag); + switch (tag >> 3) { + // optional string name = 1; + case 1: + if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) { + auto str = _internal_mutable_name(); + ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx); + #ifndef NDEBUG + ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.compiler.CodeGeneratorResponse.File.name"); + #endif // !NDEBUG + CHK_(ptr); + } else + goto handle_unusual; + continue; + // optional string insertion_point = 2; + case 2: + if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 18)) { + auto str = _internal_mutable_insertion_point(); + ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx); + #ifndef NDEBUG + ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point"); + #endif // !NDEBUG + CHK_(ptr); + } else + goto handle_unusual; + continue; + // optional string content = 15; + case 15: + if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 122)) { + auto str = _internal_mutable_content(); + ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx); + #ifndef NDEBUG + ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.compiler.CodeGeneratorResponse.File.content"); + #endif // !NDEBUG + CHK_(ptr); + } else + goto handle_unusual; + continue; + // optional .google.protobuf.GeneratedCodeInfo generated_code_info = 16; + case 16: + if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 130)) { + ptr = ctx->ParseMessage(_internal_mutable_generated_code_info(), ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + default: + goto handle_unusual; + } // switch + handle_unusual: + if ((tag == 0) || ((tag & 7) == 4)) { + CHK_(ptr); + ctx->SetLastTag(tag); + goto message_done; + } + ptr = UnknownFieldParse( + tag, + _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(), + ptr, ctx); + CHK_(ptr != nullptr); + } // while +message_done: + _has_bits_.Or(has_bits); + return ptr; +failure: + ptr = nullptr; + goto message_done; +#undef CHK_ +} + +uint8_t* CodeGeneratorResponse_File::_InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.compiler.CodeGeneratorResponse.File) + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + cached_has_bits = _has_bits_[0]; + // optional string name = 1; + if (cached_has_bits & 0x00000001u) { + ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField( + this->_internal_name().data(), static_cast<int>(this->_internal_name().length()), + ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE, + "google.protobuf.compiler.CodeGeneratorResponse.File.name"); + target = stream->WriteStringMaybeAliased( + 1, this->_internal_name(), target); + } + + // optional string insertion_point = 2; + if (cached_has_bits & 0x00000002u) { + ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField( + this->_internal_insertion_point().data(), static_cast<int>(this->_internal_insertion_point().length()), + ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE, + "google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point"); + target = stream->WriteStringMaybeAliased( + 2, this->_internal_insertion_point(), target); + } + + // optional string content = 15; + if (cached_has_bits & 0x00000004u) { + ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField( + this->_internal_content().data(), static_cast<int>(this->_internal_content().length()), + ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE, + "google.protobuf.compiler.CodeGeneratorResponse.File.content"); + target = stream->WriteStringMaybeAliased( + 15, this->_internal_content(), target); + } + + // optional .google.protobuf.GeneratedCodeInfo generated_code_info = 16; + if (cached_has_bits & 0x00000008u) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite:: + InternalWriteMessage( + 16, _Internal::generated_code_info(this), target, stream); + } + + if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray( + _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream); + } + // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.compiler.CodeGeneratorResponse.File) + return target; +} + +size_t CodeGeneratorResponse_File::ByteSizeLong() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.compiler.CodeGeneratorResponse.File) + size_t total_size = 0; + + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + cached_has_bits = _has_bits_[0]; + if (cached_has_bits & 0x0000000fu) { + // optional string name = 1; + if (cached_has_bits & 0x00000001u) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize( + this->_internal_name()); + } + + // optional string insertion_point = 2; + if (cached_has_bits & 0x00000002u) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize( + this->_internal_insertion_point()); + } + + // optional string content = 15; + if (cached_has_bits & 0x00000004u) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize( + this->_internal_content()); + } + + // optional .google.protobuf.GeneratedCodeInfo generated_code_info = 16; + if (cached_has_bits & 0x00000008u) { + total_size += 2 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize( + *generated_code_info_); + } + + } + return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_); +} + +const ::PROTOBUF_NAMESPACE_ID::Message::ClassData CodeGeneratorResponse_File::_class_data_ = { + ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSizeCheck, + CodeGeneratorResponse_File::MergeImpl +}; +const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*CodeGeneratorResponse_File::GetClassData() const { return &_class_data_; } + +void CodeGeneratorResponse_File::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, + const ::PROTOBUF_NAMESPACE_ID::Message& from) { + static_cast<CodeGeneratorResponse_File *>(to)->MergeFrom( + static_cast<const CodeGeneratorResponse_File &>(from)); +} + + +void CodeGeneratorResponse_File::MergeFrom(const CodeGeneratorResponse_File& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.compiler.CodeGeneratorResponse.File) + GOOGLE_DCHECK_NE(&from, this); + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + cached_has_bits = from._has_bits_[0]; + if (cached_has_bits & 0x0000000fu) { + if (cached_has_bits & 0x00000001u) { + _internal_set_name(from._internal_name()); + } + if (cached_has_bits & 0x00000002u) { + _internal_set_insertion_point(from._internal_insertion_point()); + } + if (cached_has_bits & 0x00000004u) { + _internal_set_content(from._internal_content()); + } + if (cached_has_bits & 0x00000008u) { + _internal_mutable_generated_code_info()->::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo::MergeFrom(from._internal_generated_code_info()); + } + } + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); +} + +void CodeGeneratorResponse_File::CopyFrom(const CodeGeneratorResponse_File& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.compiler.CodeGeneratorResponse.File) + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool CodeGeneratorResponse_File::IsInitialized() const { + return true; +} + +void CodeGeneratorResponse_File::InternalSwap(CodeGeneratorResponse_File* other) { + using std::swap; + auto* lhs_arena = GetArenaForAllocation(); + auto* rhs_arena = other->GetArenaForAllocation(); + _internal_metadata_.InternalSwap(&other->_internal_metadata_); + swap(_has_bits_[0], other->_has_bits_[0]); + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap( + &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), + &name_, lhs_arena, + &other->name_, rhs_arena + ); + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap( + &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), + &insertion_point_, lhs_arena, + &other->insertion_point_, rhs_arena + ); + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap( + &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), + &content_, lhs_arena, + &other->content_, rhs_arena + ); + swap(generated_code_info_, other->generated_code_info_); +} + +::PROTOBUF_NAMESPACE_ID::Metadata CodeGeneratorResponse_File::GetMetadata() const { + return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors( + &descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_getter, &descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_once, + file_level_metadata_google_2fprotobuf_2fcompiler_2fplugin_2eproto[2]); +} + +// =================================================================== + +class CodeGeneratorResponse::_Internal { + public: + using HasBits = decltype(std::declval<CodeGeneratorResponse>()._has_bits_); + static void set_has_error(HasBits* has_bits) { + (*has_bits)[0] |= 1u; + } + static void set_has_supported_features(HasBits* has_bits) { + (*has_bits)[0] |= 2u; + } +}; + +CodeGeneratorResponse::CodeGeneratorResponse(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned) + : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned), + file_(arena) { + SharedCtor(); + if (!is_message_owned) { + RegisterArenaDtor(arena); + } + // @@protoc_insertion_point(arena_constructor:google.protobuf.compiler.CodeGeneratorResponse) +} +CodeGeneratorResponse::CodeGeneratorResponse(const CodeGeneratorResponse& from) + : ::PROTOBUF_NAMESPACE_ID::Message(), + _has_bits_(from._has_bits_), + file_(from.file_) { + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); + error_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); + #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + error_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (from._internal_has_error()) { + error_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_error(), + GetArenaForAllocation()); + } + supported_features_ = from.supported_features_; + // @@protoc_insertion_point(copy_constructor:google.protobuf.compiler.CodeGeneratorResponse) +} + +inline void CodeGeneratorResponse::SharedCtor() { +error_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + error_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING +supported_features_ = uint64_t{0u}; +} + +CodeGeneratorResponse::~CodeGeneratorResponse() { + // @@protoc_insertion_point(destructor:google.protobuf.compiler.CodeGeneratorResponse) + if (GetArenaForAllocation() != nullptr) return; + SharedDtor(); + _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +inline void CodeGeneratorResponse::SharedDtor() { + GOOGLE_DCHECK(GetArenaForAllocation() == nullptr); + error_.DestroyNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); +} + +void CodeGeneratorResponse::ArenaDtor(void* object) { + CodeGeneratorResponse* _this = reinterpret_cast< CodeGeneratorResponse* >(object); + (void)_this; +} +void CodeGeneratorResponse::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) { +} +void CodeGeneratorResponse::SetCachedSize(int size) const { + _cached_size_.Set(size); +} + +void CodeGeneratorResponse::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.compiler.CodeGeneratorResponse) + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + file_.Clear(); + cached_has_bits = _has_bits_[0]; + if (cached_has_bits & 0x00000001u) { + error_.ClearNonDefaultToEmpty(); + } + supported_features_ = uint64_t{0u}; + _has_bits_.Clear(); + _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +const char* CodeGeneratorResponse::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) { +#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure + _Internal::HasBits has_bits{}; + while (!ctx->Done(&ptr)) { + uint32_t tag; + ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag); + switch (tag >> 3) { + // optional string error = 1; + case 1: + if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) { + auto str = _internal_mutable_error(); + ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx); + #ifndef NDEBUG + ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.compiler.CodeGeneratorResponse.error"); + #endif // !NDEBUG + CHK_(ptr); + } else + goto handle_unusual; + continue; + // optional uint64 supported_features = 2; + case 2: + if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 16)) { + _Internal::set_has_supported_features(&has_bits); + supported_features_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15; + case 15: + if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 122)) { + ptr -= 1; + do { + ptr += 1; + ptr = ctx->ParseMessage(_internal_add_file(), ptr); + CHK_(ptr); + if (!ctx->DataAvailable(ptr)) break; + } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<122>(ptr)); + } else + goto handle_unusual; + continue; + default: + goto handle_unusual; + } // switch + handle_unusual: + if ((tag == 0) || ((tag & 7) == 4)) { + CHK_(ptr); + ctx->SetLastTag(tag); + goto message_done; + } + ptr = UnknownFieldParse( + tag, + _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(), + ptr, ctx); + CHK_(ptr != nullptr); + } // while +message_done: + _has_bits_.Or(has_bits); + return ptr; +failure: + ptr = nullptr; + goto message_done; +#undef CHK_ +} + +uint8_t* CodeGeneratorResponse::_InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.compiler.CodeGeneratorResponse) + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + cached_has_bits = _has_bits_[0]; + // optional string error = 1; + if (cached_has_bits & 0x00000001u) { + ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField( + this->_internal_error().data(), static_cast<int>(this->_internal_error().length()), + ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE, + "google.protobuf.compiler.CodeGeneratorResponse.error"); + target = stream->WriteStringMaybeAliased( + 1, this->_internal_error(), target); + } + + // optional uint64 supported_features = 2; + if (cached_has_bits & 0x00000002u) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteUInt64ToArray(2, this->_internal_supported_features(), target); + } + + // repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15; + for (unsigned int i = 0, + n = static_cast<unsigned int>(this->_internal_file_size()); i < n; i++) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite:: + InternalWriteMessage(15, this->_internal_file(i), target, stream); + } + + if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray( + _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream); + } + // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.compiler.CodeGeneratorResponse) + return target; +} + +size_t CodeGeneratorResponse::ByteSizeLong() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.compiler.CodeGeneratorResponse) + size_t total_size = 0; + + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + // repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15; + total_size += 1UL * this->_internal_file_size(); + for (const auto& msg : this->file_) { + total_size += + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg); + } + + cached_has_bits = _has_bits_[0]; + if (cached_has_bits & 0x00000003u) { + // optional string error = 1; + if (cached_has_bits & 0x00000001u) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize( + this->_internal_error()); + } + + // optional uint64 supported_features = 2; + if (cached_has_bits & 0x00000002u) { + total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::UInt64SizePlusOne(this->_internal_supported_features()); + } + + } + return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_); +} + +const ::PROTOBUF_NAMESPACE_ID::Message::ClassData CodeGeneratorResponse::_class_data_ = { + ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSizeCheck, + CodeGeneratorResponse::MergeImpl +}; +const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*CodeGeneratorResponse::GetClassData() const { return &_class_data_; } + +void CodeGeneratorResponse::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, + const ::PROTOBUF_NAMESPACE_ID::Message& from) { + static_cast<CodeGeneratorResponse *>(to)->MergeFrom( + static_cast<const CodeGeneratorResponse &>(from)); +} + + +void CodeGeneratorResponse::MergeFrom(const CodeGeneratorResponse& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.compiler.CodeGeneratorResponse) + GOOGLE_DCHECK_NE(&from, this); + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + file_.MergeFrom(from.file_); + cached_has_bits = from._has_bits_[0]; + if (cached_has_bits & 0x00000003u) { + if (cached_has_bits & 0x00000001u) { + _internal_set_error(from._internal_error()); + } + if (cached_has_bits & 0x00000002u) { + supported_features_ = from.supported_features_; + } + _has_bits_[0] |= cached_has_bits; + } + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); +} + +void CodeGeneratorResponse::CopyFrom(const CodeGeneratorResponse& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.compiler.CodeGeneratorResponse) + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool CodeGeneratorResponse::IsInitialized() const { + return true; +} + +void CodeGeneratorResponse::InternalSwap(CodeGeneratorResponse* other) { + using std::swap; + auto* lhs_arena = GetArenaForAllocation(); + auto* rhs_arena = other->GetArenaForAllocation(); + _internal_metadata_.InternalSwap(&other->_internal_metadata_); + swap(_has_bits_[0], other->_has_bits_[0]); + file_.InternalSwap(&other->file_); + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap( + &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), + &error_, lhs_arena, + &other->error_, rhs_arena + ); + swap(supported_features_, other->supported_features_); +} + +::PROTOBUF_NAMESPACE_ID::Metadata CodeGeneratorResponse::GetMetadata() const { + return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors( + &descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_getter, &descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_once, + file_level_metadata_google_2fprotobuf_2fcompiler_2fplugin_2eproto[3]); +} + +// @@protoc_insertion_point(namespace_scope) +} // namespace compiler +PROTOBUF_NAMESPACE_CLOSE +PROTOBUF_NAMESPACE_OPEN +template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::compiler::Version* Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::compiler::Version >(Arena* arena) { + return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::compiler::Version >(arena); +} +template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorRequest* Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorRequest >(Arena* arena) { + return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorRequest >(arena); +} +template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File* Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File >(Arena* arena) { + return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File >(arena); +} +template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse* Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse >(Arena* arena) { + return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse >(arena); +} +PROTOBUF_NAMESPACE_CLOSE + +// @@protoc_insertion_point(global_scope) +#include <port_undef.inc> diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/plugin.pb.h b/NorthstarDedicatedTest/include/protobuf/compiler/plugin.pb.h new file mode 100644 index 00000000..a3ed430b --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/plugin.pb.h @@ -0,0 +1,1909 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: google/protobuf/compiler/plugin.proto + +#ifndef GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2fcompiler_2fplugin_2eproto +#define GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2fcompiler_2fplugin_2eproto + +#include <limits> +#include <string> + +#include <port_def.inc> +#if PROTOBUF_VERSION < 3019000 +#error This file was generated by a newer version of protoc which is +#error incompatible with your Protocol Buffer headers. Please update +#error your headers. +#endif +#if 3019004 < PROTOBUF_MIN_PROTOC_VERSION +#error This file was generated by an older version of protoc which is +#error incompatible with your Protocol Buffer headers. Please +#error regenerate this file with a newer version of protoc. +#endif + +#include <port_undef.inc> +#include <io/coded_stream.h> +#include <arena.h> +#include <arenastring.h> +#include <generated_message_table_driven.h> +#include <generated_message_util.h> +#include <metadata_lite.h> +#include <generated_message_reflection.h> +#include <message.h> +#include <repeated_field.h> // IWYU pragma: export +#include <extension_set.h> // IWYU pragma: export +#include <generated_enum_reflection.h> +#include <unknown_field_set.h> +#include <descriptor.pb.h> +// @@protoc_insertion_point(includes) +#include <port_def.inc> +#define PROTOBUF_INTERNAL_EXPORT_google_2fprotobuf_2fcompiler_2fplugin_2eproto PROTOC_EXPORT +#ifdef major +#undef major +#endif +#ifdef minor +#undef minor +#endif +PROTOBUF_NAMESPACE_OPEN +namespace internal { +class AnyMetadata; +} // namespace internal +PROTOBUF_NAMESPACE_CLOSE + +// Internal implementation detail -- do not use these members. +struct PROTOC_EXPORT TableStruct_google_2fprotobuf_2fcompiler_2fplugin_2eproto { + static const ::PROTOBUF_NAMESPACE_ID::internal::ParseTableField entries[] + PROTOBUF_SECTION_VARIABLE(protodesc_cold); + static const ::PROTOBUF_NAMESPACE_ID::internal::AuxiliaryParseTableField aux[] + PROTOBUF_SECTION_VARIABLE(protodesc_cold); + static const ::PROTOBUF_NAMESPACE_ID::internal::ParseTable schema[4] + PROTOBUF_SECTION_VARIABLE(protodesc_cold); + static const ::PROTOBUF_NAMESPACE_ID::internal::FieldMetadata field_metadata[]; + static const ::PROTOBUF_NAMESPACE_ID::internal::SerializationTable serialization_table[]; + static const uint32_t offsets[]; +}; +PROTOC_EXPORT extern const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto; +PROTOBUF_NAMESPACE_OPEN +namespace compiler { +class CodeGeneratorRequest; +struct CodeGeneratorRequestDefaultTypeInternal; +PROTOC_EXPORT extern CodeGeneratorRequestDefaultTypeInternal _CodeGeneratorRequest_default_instance_; +class CodeGeneratorResponse; +struct CodeGeneratorResponseDefaultTypeInternal; +PROTOC_EXPORT extern CodeGeneratorResponseDefaultTypeInternal _CodeGeneratorResponse_default_instance_; +class CodeGeneratorResponse_File; +struct CodeGeneratorResponse_FileDefaultTypeInternal; +PROTOC_EXPORT extern CodeGeneratorResponse_FileDefaultTypeInternal _CodeGeneratorResponse_File_default_instance_; +class Version; +struct VersionDefaultTypeInternal; +PROTOC_EXPORT extern VersionDefaultTypeInternal _Version_default_instance_; +} // namespace compiler +PROTOBUF_NAMESPACE_CLOSE +PROTOBUF_NAMESPACE_OPEN +template<> PROTOC_EXPORT ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorRequest* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorRequest>(Arena*); +template<> PROTOC_EXPORT ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse>(Arena*); +template<> PROTOC_EXPORT ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File>(Arena*); +template<> PROTOC_EXPORT ::PROTOBUF_NAMESPACE_ID::compiler::Version* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::compiler::Version>(Arena*); +PROTOBUF_NAMESPACE_CLOSE +PROTOBUF_NAMESPACE_OPEN +namespace compiler { + +enum CodeGeneratorResponse_Feature : int { + CodeGeneratorResponse_Feature_FEATURE_NONE = 0, + CodeGeneratorResponse_Feature_FEATURE_PROTO3_OPTIONAL = 1 +}; +PROTOC_EXPORT bool CodeGeneratorResponse_Feature_IsValid(int value); +constexpr CodeGeneratorResponse_Feature CodeGeneratorResponse_Feature_Feature_MIN = CodeGeneratorResponse_Feature_FEATURE_NONE; +constexpr CodeGeneratorResponse_Feature CodeGeneratorResponse_Feature_Feature_MAX = CodeGeneratorResponse_Feature_FEATURE_PROTO3_OPTIONAL; +constexpr int CodeGeneratorResponse_Feature_Feature_ARRAYSIZE = CodeGeneratorResponse_Feature_Feature_MAX + 1; + +PROTOC_EXPORT const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* CodeGeneratorResponse_Feature_descriptor(); +template<typename T> +inline const std::string& CodeGeneratorResponse_Feature_Name(T enum_t_value) { + static_assert(::std::is_same<T, CodeGeneratorResponse_Feature>::value || + ::std::is_integral<T>::value, + "Incorrect type passed to function CodeGeneratorResponse_Feature_Name."); + return ::PROTOBUF_NAMESPACE_ID::internal::NameOfEnum( + CodeGeneratorResponse_Feature_descriptor(), enum_t_value); +} +inline bool CodeGeneratorResponse_Feature_Parse( + ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, CodeGeneratorResponse_Feature* value) { + return ::PROTOBUF_NAMESPACE_ID::internal::ParseNamedEnum<CodeGeneratorResponse_Feature>( + CodeGeneratorResponse_Feature_descriptor(), name, value); +} +// =================================================================== + +class PROTOC_EXPORT Version final : + public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.compiler.Version) */ { + public: + inline Version() : Version(nullptr) {} + ~Version() override; + explicit constexpr Version(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized); + + Version(const Version& from); + Version(Version&& from) noexcept + : Version() { + *this = ::std::move(from); + } + + inline Version& operator=(const Version& from) { + CopyFrom(from); + return *this; + } + inline Version& operator=(Version&& from) noexcept { + if (this == &from) return *this; + if (GetOwningArena() == from.GetOwningArena() + #ifdef PROTOBUF_FORCE_COPY_IN_MOVE + && GetOwningArena() != nullptr + #endif // !PROTOBUF_FORCE_COPY_IN_MOVE + ) { + InternalSwap(&from); + } else { + CopyFrom(from); + } + return *this; + } + + inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const { + return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance); + } + inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() { + return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); + } + + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() { + return GetDescriptor(); + } + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() { + return default_instance().GetMetadata().descriptor; + } + static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() { + return default_instance().GetMetadata().reflection; + } + static const Version& default_instance() { + return *internal_default_instance(); + } + static inline const Version* internal_default_instance() { + return reinterpret_cast<const Version*>( + &_Version_default_instance_); + } + static constexpr int kIndexInFileMessages = + 0; + + friend void swap(Version& a, Version& b) { + a.Swap(&b); + } + inline void Swap(Version* other) { + if (other == this) return; + #ifdef PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() != nullptr && + GetOwningArena() == other->GetOwningArena()) { + #else // PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() == other->GetOwningArena()) { + #endif // !PROTOBUF_FORCE_COPY_IN_SWAP + InternalSwap(other); + } else { + ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other); + } + } + void UnsafeArenaSwap(Version* other) { + if (other == this) return; + GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena()); + InternalSwap(other); + } + + // implements Message ---------------------------------------------- + + Version* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final { + return CreateMaybeMessage<Version>(arena); + } + using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom; + void CopyFrom(const Version& from); + using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom; + void MergeFrom(const Version& from); + private: + static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from); + public: + PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final; + bool IsInitialized() const final; + + size_t ByteSizeLong() const final; + const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final; + uint8_t* _InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final; + int GetCachedSize() const final { return _cached_size_.Get(); } + + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const final; + void InternalSwap(Version* other); + + private: + friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata; + static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() { + return "google.protobuf.compiler.Version"; + } + protected: + explicit Version(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned = false); + private: + static void ArenaDtor(void* object); + inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena); + public: + + static const ClassData _class_data_; + const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final; + + ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + enum : int { + kSuffixFieldNumber = 4, + kMajorFieldNumber = 1, + kMinorFieldNumber = 2, + kPatchFieldNumber = 3, + }; + // optional string suffix = 4; + bool has_suffix() const; + private: + bool _internal_has_suffix() const; + public: + void clear_suffix(); + const std::string& suffix() const; + template <typename ArgT0 = const std::string&, typename... ArgT> + void set_suffix(ArgT0&& arg0, ArgT... args); + std::string* mutable_suffix(); + PROTOBUF_NODISCARD std::string* release_suffix(); + void set_allocated_suffix(std::string* suffix); + private: + const std::string& _internal_suffix() const; + inline PROTOBUF_ALWAYS_INLINE void _internal_set_suffix(const std::string& value); + std::string* _internal_mutable_suffix(); + public: + + // optional int32 major = 1; + bool has_major() const; + private: + bool _internal_has_major() const; + public: + void clear_major(); + int32_t major() const; + void set_major(int32_t value); + private: + int32_t _internal_major() const; + void _internal_set_major(int32_t value); + public: + + // optional int32 minor = 2; + bool has_minor() const; + private: + bool _internal_has_minor() const; + public: + void clear_minor(); + int32_t minor() const; + void set_minor(int32_t value); + private: + int32_t _internal_minor() const; + void _internal_set_minor(int32_t value); + public: + + // optional int32 patch = 3; + bool has_patch() const; + private: + bool _internal_has_patch() const; + public: + void clear_patch(); + int32_t patch() const; + void set_patch(int32_t value); + private: + int32_t _internal_patch() const; + void _internal_set_patch(int32_t value); + public: + + // @@protoc_insertion_point(class_scope:google.protobuf.compiler.Version) + private: + class _Internal; + + template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper; + typedef void InternalArenaConstructable_; + typedef void DestructorSkippable_; + ::PROTOBUF_NAMESPACE_ID::internal::HasBits<1> _has_bits_; + mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_; + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr suffix_; + int32_t major_; + int32_t minor_; + int32_t patch_; + friend struct ::TableStruct_google_2fprotobuf_2fcompiler_2fplugin_2eproto; +}; +// ------------------------------------------------------------------- + +class PROTOC_EXPORT CodeGeneratorRequest final : + public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.compiler.CodeGeneratorRequest) */ { + public: + inline CodeGeneratorRequest() : CodeGeneratorRequest(nullptr) {} + ~CodeGeneratorRequest() override; + explicit constexpr CodeGeneratorRequest(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized); + + CodeGeneratorRequest(const CodeGeneratorRequest& from); + CodeGeneratorRequest(CodeGeneratorRequest&& from) noexcept + : CodeGeneratorRequest() { + *this = ::std::move(from); + } + + inline CodeGeneratorRequest& operator=(const CodeGeneratorRequest& from) { + CopyFrom(from); + return *this; + } + inline CodeGeneratorRequest& operator=(CodeGeneratorRequest&& from) noexcept { + if (this == &from) return *this; + if (GetOwningArena() == from.GetOwningArena() + #ifdef PROTOBUF_FORCE_COPY_IN_MOVE + && GetOwningArena() != nullptr + #endif // !PROTOBUF_FORCE_COPY_IN_MOVE + ) { + InternalSwap(&from); + } else { + CopyFrom(from); + } + return *this; + } + + inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const { + return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance); + } + inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() { + return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); + } + + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() { + return GetDescriptor(); + } + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() { + return default_instance().GetMetadata().descriptor; + } + static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() { + return default_instance().GetMetadata().reflection; + } + static const CodeGeneratorRequest& default_instance() { + return *internal_default_instance(); + } + static inline const CodeGeneratorRequest* internal_default_instance() { + return reinterpret_cast<const CodeGeneratorRequest*>( + &_CodeGeneratorRequest_default_instance_); + } + static constexpr int kIndexInFileMessages = + 1; + + friend void swap(CodeGeneratorRequest& a, CodeGeneratorRequest& b) { + a.Swap(&b); + } + inline void Swap(CodeGeneratorRequest* other) { + if (other == this) return; + #ifdef PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() != nullptr && + GetOwningArena() == other->GetOwningArena()) { + #else // PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() == other->GetOwningArena()) { + #endif // !PROTOBUF_FORCE_COPY_IN_SWAP + InternalSwap(other); + } else { + ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other); + } + } + void UnsafeArenaSwap(CodeGeneratorRequest* other) { + if (other == this) return; + GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena()); + InternalSwap(other); + } + + // implements Message ---------------------------------------------- + + CodeGeneratorRequest* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final { + return CreateMaybeMessage<CodeGeneratorRequest>(arena); + } + using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom; + void CopyFrom(const CodeGeneratorRequest& from); + using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom; + void MergeFrom(const CodeGeneratorRequest& from); + private: + static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from); + public: + PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final; + bool IsInitialized() const final; + + size_t ByteSizeLong() const final; + const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final; + uint8_t* _InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final; + int GetCachedSize() const final { return _cached_size_.Get(); } + + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const final; + void InternalSwap(CodeGeneratorRequest* other); + + private: + friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata; + static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() { + return "google.protobuf.compiler.CodeGeneratorRequest"; + } + protected: + explicit CodeGeneratorRequest(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned = false); + private: + static void ArenaDtor(void* object); + inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena); + public: + + static const ClassData _class_data_; + const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final; + + ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + enum : int { + kFileToGenerateFieldNumber = 1, + kProtoFileFieldNumber = 15, + kParameterFieldNumber = 2, + kCompilerVersionFieldNumber = 3, + }; + // repeated string file_to_generate = 1; + int file_to_generate_size() const; + private: + int _internal_file_to_generate_size() const; + public: + void clear_file_to_generate(); + const std::string& file_to_generate(int index) const; + std::string* mutable_file_to_generate(int index); + void set_file_to_generate(int index, const std::string& value); + void set_file_to_generate(int index, std::string&& value); + void set_file_to_generate(int index, const char* value); + void set_file_to_generate(int index, const char* value, size_t size); + std::string* add_file_to_generate(); + void add_file_to_generate(const std::string& value); + void add_file_to_generate(std::string&& value); + void add_file_to_generate(const char* value); + void add_file_to_generate(const char* value, size_t size); + const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string>& file_to_generate() const; + ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string>* mutable_file_to_generate(); + private: + const std::string& _internal_file_to_generate(int index) const; + std::string* _internal_add_file_to_generate(); + public: + + // repeated .google.protobuf.FileDescriptorProto proto_file = 15; + int proto_file_size() const; + private: + int _internal_proto_file_size() const; + public: + void clear_proto_file(); + ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto* mutable_proto_file(int index); + ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto >* + mutable_proto_file(); + private: + const ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto& _internal_proto_file(int index) const; + ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto* _internal_add_proto_file(); + public: + const ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto& proto_file(int index) const; + ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto* add_proto_file(); + const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto >& + proto_file() const; + + // optional string parameter = 2; + bool has_parameter() const; + private: + bool _internal_has_parameter() const; + public: + void clear_parameter(); + const std::string& parameter() const; + template <typename ArgT0 = const std::string&, typename... ArgT> + void set_parameter(ArgT0&& arg0, ArgT... args); + std::string* mutable_parameter(); + PROTOBUF_NODISCARD std::string* release_parameter(); + void set_allocated_parameter(std::string* parameter); + private: + const std::string& _internal_parameter() const; + inline PROTOBUF_ALWAYS_INLINE void _internal_set_parameter(const std::string& value); + std::string* _internal_mutable_parameter(); + public: + + // optional .google.protobuf.compiler.Version compiler_version = 3; + bool has_compiler_version() const; + private: + bool _internal_has_compiler_version() const; + public: + void clear_compiler_version(); + const ::PROTOBUF_NAMESPACE_ID::compiler::Version& compiler_version() const; + PROTOBUF_NODISCARD ::PROTOBUF_NAMESPACE_ID::compiler::Version* release_compiler_version(); + ::PROTOBUF_NAMESPACE_ID::compiler::Version* mutable_compiler_version(); + void set_allocated_compiler_version(::PROTOBUF_NAMESPACE_ID::compiler::Version* compiler_version); + private: + const ::PROTOBUF_NAMESPACE_ID::compiler::Version& _internal_compiler_version() const; + ::PROTOBUF_NAMESPACE_ID::compiler::Version* _internal_mutable_compiler_version(); + public: + void unsafe_arena_set_allocated_compiler_version( + ::PROTOBUF_NAMESPACE_ID::compiler::Version* compiler_version); + ::PROTOBUF_NAMESPACE_ID::compiler::Version* unsafe_arena_release_compiler_version(); + + // @@protoc_insertion_point(class_scope:google.protobuf.compiler.CodeGeneratorRequest) + private: + class _Internal; + + template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper; + typedef void InternalArenaConstructable_; + typedef void DestructorSkippable_; + ::PROTOBUF_NAMESPACE_ID::internal::HasBits<1> _has_bits_; + mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_; + ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string> file_to_generate_; + ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto > proto_file_; + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr parameter_; + ::PROTOBUF_NAMESPACE_ID::compiler::Version* compiler_version_; + friend struct ::TableStruct_google_2fprotobuf_2fcompiler_2fplugin_2eproto; +}; +// ------------------------------------------------------------------- + +class PROTOC_EXPORT CodeGeneratorResponse_File final : + public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.compiler.CodeGeneratorResponse.File) */ { + public: + inline CodeGeneratorResponse_File() : CodeGeneratorResponse_File(nullptr) {} + ~CodeGeneratorResponse_File() override; + explicit constexpr CodeGeneratorResponse_File(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized); + + CodeGeneratorResponse_File(const CodeGeneratorResponse_File& from); + CodeGeneratorResponse_File(CodeGeneratorResponse_File&& from) noexcept + : CodeGeneratorResponse_File() { + *this = ::std::move(from); + } + + inline CodeGeneratorResponse_File& operator=(const CodeGeneratorResponse_File& from) { + CopyFrom(from); + return *this; + } + inline CodeGeneratorResponse_File& operator=(CodeGeneratorResponse_File&& from) noexcept { + if (this == &from) return *this; + if (GetOwningArena() == from.GetOwningArena() + #ifdef PROTOBUF_FORCE_COPY_IN_MOVE + && GetOwningArena() != nullptr + #endif // !PROTOBUF_FORCE_COPY_IN_MOVE + ) { + InternalSwap(&from); + } else { + CopyFrom(from); + } + return *this; + } + + inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const { + return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance); + } + inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() { + return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); + } + + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() { + return GetDescriptor(); + } + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() { + return default_instance().GetMetadata().descriptor; + } + static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() { + return default_instance().GetMetadata().reflection; + } + static const CodeGeneratorResponse_File& default_instance() { + return *internal_default_instance(); + } + static inline const CodeGeneratorResponse_File* internal_default_instance() { + return reinterpret_cast<const CodeGeneratorResponse_File*>( + &_CodeGeneratorResponse_File_default_instance_); + } + static constexpr int kIndexInFileMessages = + 2; + + friend void swap(CodeGeneratorResponse_File& a, CodeGeneratorResponse_File& b) { + a.Swap(&b); + } + inline void Swap(CodeGeneratorResponse_File* other) { + if (other == this) return; + #ifdef PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() != nullptr && + GetOwningArena() == other->GetOwningArena()) { + #else // PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() == other->GetOwningArena()) { + #endif // !PROTOBUF_FORCE_COPY_IN_SWAP + InternalSwap(other); + } else { + ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other); + } + } + void UnsafeArenaSwap(CodeGeneratorResponse_File* other) { + if (other == this) return; + GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena()); + InternalSwap(other); + } + + // implements Message ---------------------------------------------- + + CodeGeneratorResponse_File* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final { + return CreateMaybeMessage<CodeGeneratorResponse_File>(arena); + } + using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom; + void CopyFrom(const CodeGeneratorResponse_File& from); + using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom; + void MergeFrom(const CodeGeneratorResponse_File& from); + private: + static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from); + public: + PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final; + bool IsInitialized() const final; + + size_t ByteSizeLong() const final; + const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final; + uint8_t* _InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final; + int GetCachedSize() const final { return _cached_size_.Get(); } + + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const final; + void InternalSwap(CodeGeneratorResponse_File* other); + + private: + friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata; + static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() { + return "google.protobuf.compiler.CodeGeneratorResponse.File"; + } + protected: + explicit CodeGeneratorResponse_File(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned = false); + private: + static void ArenaDtor(void* object); + inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena); + public: + + static const ClassData _class_data_; + const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final; + + ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + enum : int { + kNameFieldNumber = 1, + kInsertionPointFieldNumber = 2, + kContentFieldNumber = 15, + kGeneratedCodeInfoFieldNumber = 16, + }; + // optional string name = 1; + bool has_name() const; + private: + bool _internal_has_name() const; + public: + void clear_name(); + const std::string& name() const; + template <typename ArgT0 = const std::string&, typename... ArgT> + void set_name(ArgT0&& arg0, ArgT... args); + std::string* mutable_name(); + PROTOBUF_NODISCARD std::string* release_name(); + void set_allocated_name(std::string* name); + private: + const std::string& _internal_name() const; + inline PROTOBUF_ALWAYS_INLINE void _internal_set_name(const std::string& value); + std::string* _internal_mutable_name(); + public: + + // optional string insertion_point = 2; + bool has_insertion_point() const; + private: + bool _internal_has_insertion_point() const; + public: + void clear_insertion_point(); + const std::string& insertion_point() const; + template <typename ArgT0 = const std::string&, typename... ArgT> + void set_insertion_point(ArgT0&& arg0, ArgT... args); + std::string* mutable_insertion_point(); + PROTOBUF_NODISCARD std::string* release_insertion_point(); + void set_allocated_insertion_point(std::string* insertion_point); + private: + const std::string& _internal_insertion_point() const; + inline PROTOBUF_ALWAYS_INLINE void _internal_set_insertion_point(const std::string& value); + std::string* _internal_mutable_insertion_point(); + public: + + // optional string content = 15; + bool has_content() const; + private: + bool _internal_has_content() const; + public: + void clear_content(); + const std::string& content() const; + template <typename ArgT0 = const std::string&, typename... ArgT> + void set_content(ArgT0&& arg0, ArgT... args); + std::string* mutable_content(); + PROTOBUF_NODISCARD std::string* release_content(); + void set_allocated_content(std::string* content); + private: + const std::string& _internal_content() const; + inline PROTOBUF_ALWAYS_INLINE void _internal_set_content(const std::string& value); + std::string* _internal_mutable_content(); + public: + + // optional .google.protobuf.GeneratedCodeInfo generated_code_info = 16; + bool has_generated_code_info() const; + private: + bool _internal_has_generated_code_info() const; + public: + void clear_generated_code_info(); + const ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo& generated_code_info() const; + PROTOBUF_NODISCARD ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo* release_generated_code_info(); + ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo* mutable_generated_code_info(); + void set_allocated_generated_code_info(::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo* generated_code_info); + private: + const ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo& _internal_generated_code_info() const; + ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo* _internal_mutable_generated_code_info(); + public: + void unsafe_arena_set_allocated_generated_code_info( + ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo* generated_code_info); + ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo* unsafe_arena_release_generated_code_info(); + + // @@protoc_insertion_point(class_scope:google.protobuf.compiler.CodeGeneratorResponse.File) + private: + class _Internal; + + template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper; + typedef void InternalArenaConstructable_; + typedef void DestructorSkippable_; + ::PROTOBUF_NAMESPACE_ID::internal::HasBits<1> _has_bits_; + mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_; + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr name_; + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr insertion_point_; + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr content_; + ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo* generated_code_info_; + friend struct ::TableStruct_google_2fprotobuf_2fcompiler_2fplugin_2eproto; +}; +// ------------------------------------------------------------------- + +class PROTOC_EXPORT CodeGeneratorResponse final : + public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.compiler.CodeGeneratorResponse) */ { + public: + inline CodeGeneratorResponse() : CodeGeneratorResponse(nullptr) {} + ~CodeGeneratorResponse() override; + explicit constexpr CodeGeneratorResponse(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized); + + CodeGeneratorResponse(const CodeGeneratorResponse& from); + CodeGeneratorResponse(CodeGeneratorResponse&& from) noexcept + : CodeGeneratorResponse() { + *this = ::std::move(from); + } + + inline CodeGeneratorResponse& operator=(const CodeGeneratorResponse& from) { + CopyFrom(from); + return *this; + } + inline CodeGeneratorResponse& operator=(CodeGeneratorResponse&& from) noexcept { + if (this == &from) return *this; + if (GetOwningArena() == from.GetOwningArena() + #ifdef PROTOBUF_FORCE_COPY_IN_MOVE + && GetOwningArena() != nullptr + #endif // !PROTOBUF_FORCE_COPY_IN_MOVE + ) { + InternalSwap(&from); + } else { + CopyFrom(from); + } + return *this; + } + + inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const { + return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance); + } + inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() { + return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); + } + + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() { + return GetDescriptor(); + } + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() { + return default_instance().GetMetadata().descriptor; + } + static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() { + return default_instance().GetMetadata().reflection; + } + static const CodeGeneratorResponse& default_instance() { + return *internal_default_instance(); + } + static inline const CodeGeneratorResponse* internal_default_instance() { + return reinterpret_cast<const CodeGeneratorResponse*>( + &_CodeGeneratorResponse_default_instance_); + } + static constexpr int kIndexInFileMessages = + 3; + + friend void swap(CodeGeneratorResponse& a, CodeGeneratorResponse& b) { + a.Swap(&b); + } + inline void Swap(CodeGeneratorResponse* other) { + if (other == this) return; + #ifdef PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() != nullptr && + GetOwningArena() == other->GetOwningArena()) { + #else // PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() == other->GetOwningArena()) { + #endif // !PROTOBUF_FORCE_COPY_IN_SWAP + InternalSwap(other); + } else { + ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other); + } + } + void UnsafeArenaSwap(CodeGeneratorResponse* other) { + if (other == this) return; + GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena()); + InternalSwap(other); + } + + // implements Message ---------------------------------------------- + + CodeGeneratorResponse* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final { + return CreateMaybeMessage<CodeGeneratorResponse>(arena); + } + using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom; + void CopyFrom(const CodeGeneratorResponse& from); + using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom; + void MergeFrom(const CodeGeneratorResponse& from); + private: + static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from); + public: + PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final; + bool IsInitialized() const final; + + size_t ByteSizeLong() const final; + const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final; + uint8_t* _InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final; + int GetCachedSize() const final { return _cached_size_.Get(); } + + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const final; + void InternalSwap(CodeGeneratorResponse* other); + + private: + friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata; + static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() { + return "google.protobuf.compiler.CodeGeneratorResponse"; + } + protected: + explicit CodeGeneratorResponse(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned = false); + private: + static void ArenaDtor(void* object); + inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena); + public: + + static const ClassData _class_data_; + const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final; + + ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final; + + // nested types ---------------------------------------------------- + + typedef CodeGeneratorResponse_File File; + + typedef CodeGeneratorResponse_Feature Feature; + static constexpr Feature FEATURE_NONE = + CodeGeneratorResponse_Feature_FEATURE_NONE; + static constexpr Feature FEATURE_PROTO3_OPTIONAL = + CodeGeneratorResponse_Feature_FEATURE_PROTO3_OPTIONAL; + static inline bool Feature_IsValid(int value) { + return CodeGeneratorResponse_Feature_IsValid(value); + } + static constexpr Feature Feature_MIN = + CodeGeneratorResponse_Feature_Feature_MIN; + static constexpr Feature Feature_MAX = + CodeGeneratorResponse_Feature_Feature_MAX; + static constexpr int Feature_ARRAYSIZE = + CodeGeneratorResponse_Feature_Feature_ARRAYSIZE; + static inline const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* + Feature_descriptor() { + return CodeGeneratorResponse_Feature_descriptor(); + } + template<typename T> + static inline const std::string& Feature_Name(T enum_t_value) { + static_assert(::std::is_same<T, Feature>::value || + ::std::is_integral<T>::value, + "Incorrect type passed to function Feature_Name."); + return CodeGeneratorResponse_Feature_Name(enum_t_value); + } + static inline bool Feature_Parse(::PROTOBUF_NAMESPACE_ID::ConstStringParam name, + Feature* value) { + return CodeGeneratorResponse_Feature_Parse(name, value); + } + + // accessors ------------------------------------------------------- + + enum : int { + kFileFieldNumber = 15, + kErrorFieldNumber = 1, + kSupportedFeaturesFieldNumber = 2, + }; + // repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15; + int file_size() const; + private: + int _internal_file_size() const; + public: + void clear_file(); + ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File* mutable_file(int index); + ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File >* + mutable_file(); + private: + const ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File& _internal_file(int index) const; + ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File* _internal_add_file(); + public: + const ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File& file(int index) const; + ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File* add_file(); + const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File >& + file() const; + + // optional string error = 1; + bool has_error() const; + private: + bool _internal_has_error() const; + public: + void clear_error(); + const std::string& error() const; + template <typename ArgT0 = const std::string&, typename... ArgT> + void set_error(ArgT0&& arg0, ArgT... args); + std::string* mutable_error(); + PROTOBUF_NODISCARD std::string* release_error(); + void set_allocated_error(std::string* error); + private: + const std::string& _internal_error() const; + inline PROTOBUF_ALWAYS_INLINE void _internal_set_error(const std::string& value); + std::string* _internal_mutable_error(); + public: + + // optional uint64 supported_features = 2; + bool has_supported_features() const; + private: + bool _internal_has_supported_features() const; + public: + void clear_supported_features(); + uint64_t supported_features() const; + void set_supported_features(uint64_t value); + private: + uint64_t _internal_supported_features() const; + void _internal_set_supported_features(uint64_t value); + public: + + // @@protoc_insertion_point(class_scope:google.protobuf.compiler.CodeGeneratorResponse) + private: + class _Internal; + + template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper; + typedef void InternalArenaConstructable_; + typedef void DestructorSkippable_; + ::PROTOBUF_NAMESPACE_ID::internal::HasBits<1> _has_bits_; + mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_; + ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File > file_; + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr error_; + uint64_t supported_features_; + friend struct ::TableStruct_google_2fprotobuf_2fcompiler_2fplugin_2eproto; +}; +// =================================================================== + + +// =================================================================== + +#ifdef __GNUC__ + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wstrict-aliasing" +#endif // __GNUC__ +// Version + +// optional int32 major = 1; +inline bool Version::_internal_has_major() const { + bool value = (_has_bits_[0] & 0x00000002u) != 0; + return value; +} +inline bool Version::has_major() const { + return _internal_has_major(); +} +inline void Version::clear_major() { + major_ = 0; + _has_bits_[0] &= ~0x00000002u; +} +inline int32_t Version::_internal_major() const { + return major_; +} +inline int32_t Version::major() const { + // @@protoc_insertion_point(field_get:google.protobuf.compiler.Version.major) + return _internal_major(); +} +inline void Version::_internal_set_major(int32_t value) { + _has_bits_[0] |= 0x00000002u; + major_ = value; +} +inline void Version::set_major(int32_t value) { + _internal_set_major(value); + // @@protoc_insertion_point(field_set:google.protobuf.compiler.Version.major) +} + +// optional int32 minor = 2; +inline bool Version::_internal_has_minor() const { + bool value = (_has_bits_[0] & 0x00000004u) != 0; + return value; +} +inline bool Version::has_minor() const { + return _internal_has_minor(); +} +inline void Version::clear_minor() { + minor_ = 0; + _has_bits_[0] &= ~0x00000004u; +} +inline int32_t Version::_internal_minor() const { + return minor_; +} +inline int32_t Version::minor() const { + // @@protoc_insertion_point(field_get:google.protobuf.compiler.Version.minor) + return _internal_minor(); +} +inline void Version::_internal_set_minor(int32_t value) { + _has_bits_[0] |= 0x00000004u; + minor_ = value; +} +inline void Version::set_minor(int32_t value) { + _internal_set_minor(value); + // @@protoc_insertion_point(field_set:google.protobuf.compiler.Version.minor) +} + +// optional int32 patch = 3; +inline bool Version::_internal_has_patch() const { + bool value = (_has_bits_[0] & 0x00000008u) != 0; + return value; +} +inline bool Version::has_patch() const { + return _internal_has_patch(); +} +inline void Version::clear_patch() { + patch_ = 0; + _has_bits_[0] &= ~0x00000008u; +} +inline int32_t Version::_internal_patch() const { + return patch_; +} +inline int32_t Version::patch() const { + // @@protoc_insertion_point(field_get:google.protobuf.compiler.Version.patch) + return _internal_patch(); +} +inline void Version::_internal_set_patch(int32_t value) { + _has_bits_[0] |= 0x00000008u; + patch_ = value; +} +inline void Version::set_patch(int32_t value) { + _internal_set_patch(value); + // @@protoc_insertion_point(field_set:google.protobuf.compiler.Version.patch) +} + +// optional string suffix = 4; +inline bool Version::_internal_has_suffix() const { + bool value = (_has_bits_[0] & 0x00000001u) != 0; + return value; +} +inline bool Version::has_suffix() const { + return _internal_has_suffix(); +} +inline void Version::clear_suffix() { + suffix_.ClearToEmpty(); + _has_bits_[0] &= ~0x00000001u; +} +inline const std::string& Version::suffix() const { + // @@protoc_insertion_point(field_get:google.protobuf.compiler.Version.suffix) + return _internal_suffix(); +} +template <typename ArgT0, typename... ArgT> +inline PROTOBUF_ALWAYS_INLINE +void Version::set_suffix(ArgT0&& arg0, ArgT... args) { + _has_bits_[0] |= 0x00000001u; + suffix_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation()); + // @@protoc_insertion_point(field_set:google.protobuf.compiler.Version.suffix) +} +inline std::string* Version::mutable_suffix() { + std::string* _s = _internal_mutable_suffix(); + // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.Version.suffix) + return _s; +} +inline const std::string& Version::_internal_suffix() const { + return suffix_.Get(); +} +inline void Version::_internal_set_suffix(const std::string& value) { + _has_bits_[0] |= 0x00000001u; + suffix_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, value, GetArenaForAllocation()); +} +inline std::string* Version::_internal_mutable_suffix() { + _has_bits_[0] |= 0x00000001u; + return suffix_.Mutable(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, GetArenaForAllocation()); +} +inline std::string* Version::release_suffix() { + // @@protoc_insertion_point(field_release:google.protobuf.compiler.Version.suffix) + if (!_internal_has_suffix()) { + return nullptr; + } + _has_bits_[0] &= ~0x00000001u; + auto* p = suffix_.ReleaseNonDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (suffix_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) { + suffix_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + } +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + return p; +} +inline void Version::set_allocated_suffix(std::string* suffix) { + if (suffix != nullptr) { + _has_bits_[0] |= 0x00000001u; + } else { + _has_bits_[0] &= ~0x00000001u; + } + suffix_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), suffix, + GetArenaForAllocation()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (suffix_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) { + suffix_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + } +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.Version.suffix) +} + +// ------------------------------------------------------------------- + +// CodeGeneratorRequest + +// repeated string file_to_generate = 1; +inline int CodeGeneratorRequest::_internal_file_to_generate_size() const { + return file_to_generate_.size(); +} +inline int CodeGeneratorRequest::file_to_generate_size() const { + return _internal_file_to_generate_size(); +} +inline void CodeGeneratorRequest::clear_file_to_generate() { + file_to_generate_.Clear(); +} +inline std::string* CodeGeneratorRequest::add_file_to_generate() { + std::string* _s = _internal_add_file_to_generate(); + // @@protoc_insertion_point(field_add_mutable:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate) + return _s; +} +inline const std::string& CodeGeneratorRequest::_internal_file_to_generate(int index) const { + return file_to_generate_.Get(index); +} +inline const std::string& CodeGeneratorRequest::file_to_generate(int index) const { + // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate) + return _internal_file_to_generate(index); +} +inline std::string* CodeGeneratorRequest::mutable_file_to_generate(int index) { + // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate) + return file_to_generate_.Mutable(index); +} +inline void CodeGeneratorRequest::set_file_to_generate(int index, const std::string& value) { + file_to_generate_.Mutable(index)->assign(value); + // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate) +} +inline void CodeGeneratorRequest::set_file_to_generate(int index, std::string&& value) { + file_to_generate_.Mutable(index)->assign(std::move(value)); + // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate) +} +inline void CodeGeneratorRequest::set_file_to_generate(int index, const char* value) { + GOOGLE_DCHECK(value != nullptr); + file_to_generate_.Mutable(index)->assign(value); + // @@protoc_insertion_point(field_set_char:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate) +} +inline void CodeGeneratorRequest::set_file_to_generate(int index, const char* value, size_t size) { + file_to_generate_.Mutable(index)->assign( + reinterpret_cast<const char*>(value), size); + // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate) +} +inline std::string* CodeGeneratorRequest::_internal_add_file_to_generate() { + return file_to_generate_.Add(); +} +inline void CodeGeneratorRequest::add_file_to_generate(const std::string& value) { + file_to_generate_.Add()->assign(value); + // @@protoc_insertion_point(field_add:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate) +} +inline void CodeGeneratorRequest::add_file_to_generate(std::string&& value) { + file_to_generate_.Add(std::move(value)); + // @@protoc_insertion_point(field_add:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate) +} +inline void CodeGeneratorRequest::add_file_to_generate(const char* value) { + GOOGLE_DCHECK(value != nullptr); + file_to_generate_.Add()->assign(value); + // @@protoc_insertion_point(field_add_char:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate) +} +inline void CodeGeneratorRequest::add_file_to_generate(const char* value, size_t size) { + file_to_generate_.Add()->assign(reinterpret_cast<const char*>(value), size); + // @@protoc_insertion_point(field_add_pointer:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate) +} +inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string>& +CodeGeneratorRequest::file_to_generate() const { + // @@protoc_insertion_point(field_list:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate) + return file_to_generate_; +} +inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string>* +CodeGeneratorRequest::mutable_file_to_generate() { + // @@protoc_insertion_point(field_mutable_list:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate) + return &file_to_generate_; +} + +// optional string parameter = 2; +inline bool CodeGeneratorRequest::_internal_has_parameter() const { + bool value = (_has_bits_[0] & 0x00000001u) != 0; + return value; +} +inline bool CodeGeneratorRequest::has_parameter() const { + return _internal_has_parameter(); +} +inline void CodeGeneratorRequest::clear_parameter() { + parameter_.ClearToEmpty(); + _has_bits_[0] &= ~0x00000001u; +} +inline const std::string& CodeGeneratorRequest::parameter() const { + // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorRequest.parameter) + return _internal_parameter(); +} +template <typename ArgT0, typename... ArgT> +inline PROTOBUF_ALWAYS_INLINE +void CodeGeneratorRequest::set_parameter(ArgT0&& arg0, ArgT... args) { + _has_bits_[0] |= 0x00000001u; + parameter_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation()); + // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorRequest.parameter) +} +inline std::string* CodeGeneratorRequest::mutable_parameter() { + std::string* _s = _internal_mutable_parameter(); + // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorRequest.parameter) + return _s; +} +inline const std::string& CodeGeneratorRequest::_internal_parameter() const { + return parameter_.Get(); +} +inline void CodeGeneratorRequest::_internal_set_parameter(const std::string& value) { + _has_bits_[0] |= 0x00000001u; + parameter_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, value, GetArenaForAllocation()); +} +inline std::string* CodeGeneratorRequest::_internal_mutable_parameter() { + _has_bits_[0] |= 0x00000001u; + return parameter_.Mutable(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, GetArenaForAllocation()); +} +inline std::string* CodeGeneratorRequest::release_parameter() { + // @@protoc_insertion_point(field_release:google.protobuf.compiler.CodeGeneratorRequest.parameter) + if (!_internal_has_parameter()) { + return nullptr; + } + _has_bits_[0] &= ~0x00000001u; + auto* p = parameter_.ReleaseNonDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (parameter_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) { + parameter_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + } +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + return p; +} +inline void CodeGeneratorRequest::set_allocated_parameter(std::string* parameter) { + if (parameter != nullptr) { + _has_bits_[0] |= 0x00000001u; + } else { + _has_bits_[0] &= ~0x00000001u; + } + parameter_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), parameter, + GetArenaForAllocation()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (parameter_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) { + parameter_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + } +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.CodeGeneratorRequest.parameter) +} + +// repeated .google.protobuf.FileDescriptorProto proto_file = 15; +inline int CodeGeneratorRequest::_internal_proto_file_size() const { + return proto_file_.size(); +} +inline int CodeGeneratorRequest::proto_file_size() const { + return _internal_proto_file_size(); +} +inline ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto* CodeGeneratorRequest::mutable_proto_file(int index) { + // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorRequest.proto_file) + return proto_file_.Mutable(index); +} +inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto >* +CodeGeneratorRequest::mutable_proto_file() { + // @@protoc_insertion_point(field_mutable_list:google.protobuf.compiler.CodeGeneratorRequest.proto_file) + return &proto_file_; +} +inline const ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto& CodeGeneratorRequest::_internal_proto_file(int index) const { + return proto_file_.Get(index); +} +inline const ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto& CodeGeneratorRequest::proto_file(int index) const { + // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorRequest.proto_file) + return _internal_proto_file(index); +} +inline ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto* CodeGeneratorRequest::_internal_add_proto_file() { + return proto_file_.Add(); +} +inline ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto* CodeGeneratorRequest::add_proto_file() { + ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto* _add = _internal_add_proto_file(); + // @@protoc_insertion_point(field_add:google.protobuf.compiler.CodeGeneratorRequest.proto_file) + return _add; +} +inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto >& +CodeGeneratorRequest::proto_file() const { + // @@protoc_insertion_point(field_list:google.protobuf.compiler.CodeGeneratorRequest.proto_file) + return proto_file_; +} + +// optional .google.protobuf.compiler.Version compiler_version = 3; +inline bool CodeGeneratorRequest::_internal_has_compiler_version() const { + bool value = (_has_bits_[0] & 0x00000002u) != 0; + PROTOBUF_ASSUME(!value || compiler_version_ != nullptr); + return value; +} +inline bool CodeGeneratorRequest::has_compiler_version() const { + return _internal_has_compiler_version(); +} +inline void CodeGeneratorRequest::clear_compiler_version() { + if (compiler_version_ != nullptr) compiler_version_->Clear(); + _has_bits_[0] &= ~0x00000002u; +} +inline const ::PROTOBUF_NAMESPACE_ID::compiler::Version& CodeGeneratorRequest::_internal_compiler_version() const { + const ::PROTOBUF_NAMESPACE_ID::compiler::Version* p = compiler_version_; + return p != nullptr ? *p : reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::compiler::Version&>( + ::PROTOBUF_NAMESPACE_ID::compiler::_Version_default_instance_); +} +inline const ::PROTOBUF_NAMESPACE_ID::compiler::Version& CodeGeneratorRequest::compiler_version() const { + // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorRequest.compiler_version) + return _internal_compiler_version(); +} +inline void CodeGeneratorRequest::unsafe_arena_set_allocated_compiler_version( + ::PROTOBUF_NAMESPACE_ID::compiler::Version* compiler_version) { + if (GetArenaForAllocation() == nullptr) { + delete reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(compiler_version_); + } + compiler_version_ = compiler_version; + if (compiler_version) { + _has_bits_[0] |= 0x00000002u; + } else { + _has_bits_[0] &= ~0x00000002u; + } + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.protobuf.compiler.CodeGeneratorRequest.compiler_version) +} +inline ::PROTOBUF_NAMESPACE_ID::compiler::Version* CodeGeneratorRequest::release_compiler_version() { + _has_bits_[0] &= ~0x00000002u; + ::PROTOBUF_NAMESPACE_ID::compiler::Version* temp = compiler_version_; + compiler_version_ = nullptr; +#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE + auto* old = reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(temp); + temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp); + if (GetArenaForAllocation() == nullptr) { delete old; } +#else // PROTOBUF_FORCE_COPY_IN_RELEASE + if (GetArenaForAllocation() != nullptr) { + temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp); + } +#endif // !PROTOBUF_FORCE_COPY_IN_RELEASE + return temp; +} +inline ::PROTOBUF_NAMESPACE_ID::compiler::Version* CodeGeneratorRequest::unsafe_arena_release_compiler_version() { + // @@protoc_insertion_point(field_release:google.protobuf.compiler.CodeGeneratorRequest.compiler_version) + _has_bits_[0] &= ~0x00000002u; + ::PROTOBUF_NAMESPACE_ID::compiler::Version* temp = compiler_version_; + compiler_version_ = nullptr; + return temp; +} +inline ::PROTOBUF_NAMESPACE_ID::compiler::Version* CodeGeneratorRequest::_internal_mutable_compiler_version() { + _has_bits_[0] |= 0x00000002u; + if (compiler_version_ == nullptr) { + auto* p = CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::compiler::Version>(GetArenaForAllocation()); + compiler_version_ = p; + } + return compiler_version_; +} +inline ::PROTOBUF_NAMESPACE_ID::compiler::Version* CodeGeneratorRequest::mutable_compiler_version() { + ::PROTOBUF_NAMESPACE_ID::compiler::Version* _msg = _internal_mutable_compiler_version(); + // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorRequest.compiler_version) + return _msg; +} +inline void CodeGeneratorRequest::set_allocated_compiler_version(::PROTOBUF_NAMESPACE_ID::compiler::Version* compiler_version) { + ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation(); + if (message_arena == nullptr) { + delete compiler_version_; + } + if (compiler_version) { + ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena = + ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper<::PROTOBUF_NAMESPACE_ID::compiler::Version>::GetOwningArena(compiler_version); + if (message_arena != submessage_arena) { + compiler_version = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage( + message_arena, compiler_version, submessage_arena); + } + _has_bits_[0] |= 0x00000002u; + } else { + _has_bits_[0] &= ~0x00000002u; + } + compiler_version_ = compiler_version; + // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.CodeGeneratorRequest.compiler_version) +} + +// ------------------------------------------------------------------- + +// CodeGeneratorResponse_File + +// optional string name = 1; +inline bool CodeGeneratorResponse_File::_internal_has_name() const { + bool value = (_has_bits_[0] & 0x00000001u) != 0; + return value; +} +inline bool CodeGeneratorResponse_File::has_name() const { + return _internal_has_name(); +} +inline void CodeGeneratorResponse_File::clear_name() { + name_.ClearToEmpty(); + _has_bits_[0] &= ~0x00000001u; +} +inline const std::string& CodeGeneratorResponse_File::name() const { + // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorResponse.File.name) + return _internal_name(); +} +template <typename ArgT0, typename... ArgT> +inline PROTOBUF_ALWAYS_INLINE +void CodeGeneratorResponse_File::set_name(ArgT0&& arg0, ArgT... args) { + _has_bits_[0] |= 0x00000001u; + name_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation()); + // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorResponse.File.name) +} +inline std::string* CodeGeneratorResponse_File::mutable_name() { + std::string* _s = _internal_mutable_name(); + // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.File.name) + return _s; +} +inline const std::string& CodeGeneratorResponse_File::_internal_name() const { + return name_.Get(); +} +inline void CodeGeneratorResponse_File::_internal_set_name(const std::string& value) { + _has_bits_[0] |= 0x00000001u; + name_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, value, GetArenaForAllocation()); +} +inline std::string* CodeGeneratorResponse_File::_internal_mutable_name() { + _has_bits_[0] |= 0x00000001u; + return name_.Mutable(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, GetArenaForAllocation()); +} +inline std::string* CodeGeneratorResponse_File::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.compiler.CodeGeneratorResponse.File.name) + if (!_internal_has_name()) { + return nullptr; + } + _has_bits_[0] &= ~0x00000001u; + auto* p = name_.ReleaseNonDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (name_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) { + name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + } +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + return p; +} +inline void CodeGeneratorResponse_File::set_allocated_name(std::string* name) { + if (name != nullptr) { + _has_bits_[0] |= 0x00000001u; + } else { + _has_bits_[0] &= ~0x00000001u; + } + name_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), name, + GetArenaForAllocation()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (name_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) { + name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + } +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.CodeGeneratorResponse.File.name) +} + +// optional string insertion_point = 2; +inline bool CodeGeneratorResponse_File::_internal_has_insertion_point() const { + bool value = (_has_bits_[0] & 0x00000002u) != 0; + return value; +} +inline bool CodeGeneratorResponse_File::has_insertion_point() const { + return _internal_has_insertion_point(); +} +inline void CodeGeneratorResponse_File::clear_insertion_point() { + insertion_point_.ClearToEmpty(); + _has_bits_[0] &= ~0x00000002u; +} +inline const std::string& CodeGeneratorResponse_File::insertion_point() const { + // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point) + return _internal_insertion_point(); +} +template <typename ArgT0, typename... ArgT> +inline PROTOBUF_ALWAYS_INLINE +void CodeGeneratorResponse_File::set_insertion_point(ArgT0&& arg0, ArgT... args) { + _has_bits_[0] |= 0x00000002u; + insertion_point_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation()); + // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point) +} +inline std::string* CodeGeneratorResponse_File::mutable_insertion_point() { + std::string* _s = _internal_mutable_insertion_point(); + // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point) + return _s; +} +inline const std::string& CodeGeneratorResponse_File::_internal_insertion_point() const { + return insertion_point_.Get(); +} +inline void CodeGeneratorResponse_File::_internal_set_insertion_point(const std::string& value) { + _has_bits_[0] |= 0x00000002u; + insertion_point_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, value, GetArenaForAllocation()); +} +inline std::string* CodeGeneratorResponse_File::_internal_mutable_insertion_point() { + _has_bits_[0] |= 0x00000002u; + return insertion_point_.Mutable(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, GetArenaForAllocation()); +} +inline std::string* CodeGeneratorResponse_File::release_insertion_point() { + // @@protoc_insertion_point(field_release:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point) + if (!_internal_has_insertion_point()) { + return nullptr; + } + _has_bits_[0] &= ~0x00000002u; + auto* p = insertion_point_.ReleaseNonDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (insertion_point_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) { + insertion_point_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + } +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + return p; +} +inline void CodeGeneratorResponse_File::set_allocated_insertion_point(std::string* insertion_point) { + if (insertion_point != nullptr) { + _has_bits_[0] |= 0x00000002u; + } else { + _has_bits_[0] &= ~0x00000002u; + } + insertion_point_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), insertion_point, + GetArenaForAllocation()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (insertion_point_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) { + insertion_point_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + } +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point) +} + +// optional string content = 15; +inline bool CodeGeneratorResponse_File::_internal_has_content() const { + bool value = (_has_bits_[0] & 0x00000004u) != 0; + return value; +} +inline bool CodeGeneratorResponse_File::has_content() const { + return _internal_has_content(); +} +inline void CodeGeneratorResponse_File::clear_content() { + content_.ClearToEmpty(); + _has_bits_[0] &= ~0x00000004u; +} +inline const std::string& CodeGeneratorResponse_File::content() const { + // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorResponse.File.content) + return _internal_content(); +} +template <typename ArgT0, typename... ArgT> +inline PROTOBUF_ALWAYS_INLINE +void CodeGeneratorResponse_File::set_content(ArgT0&& arg0, ArgT... args) { + _has_bits_[0] |= 0x00000004u; + content_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation()); + // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorResponse.File.content) +} +inline std::string* CodeGeneratorResponse_File::mutable_content() { + std::string* _s = _internal_mutable_content(); + // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.File.content) + return _s; +} +inline const std::string& CodeGeneratorResponse_File::_internal_content() const { + return content_.Get(); +} +inline void CodeGeneratorResponse_File::_internal_set_content(const std::string& value) { + _has_bits_[0] |= 0x00000004u; + content_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, value, GetArenaForAllocation()); +} +inline std::string* CodeGeneratorResponse_File::_internal_mutable_content() { + _has_bits_[0] |= 0x00000004u; + return content_.Mutable(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, GetArenaForAllocation()); +} +inline std::string* CodeGeneratorResponse_File::release_content() { + // @@protoc_insertion_point(field_release:google.protobuf.compiler.CodeGeneratorResponse.File.content) + if (!_internal_has_content()) { + return nullptr; + } + _has_bits_[0] &= ~0x00000004u; + auto* p = content_.ReleaseNonDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (content_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) { + content_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + } +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + return p; +} +inline void CodeGeneratorResponse_File::set_allocated_content(std::string* content) { + if (content != nullptr) { + _has_bits_[0] |= 0x00000004u; + } else { + _has_bits_[0] &= ~0x00000004u; + } + content_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), content, + GetArenaForAllocation()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (content_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) { + content_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + } +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.CodeGeneratorResponse.File.content) +} + +// optional .google.protobuf.GeneratedCodeInfo generated_code_info = 16; +inline bool CodeGeneratorResponse_File::_internal_has_generated_code_info() const { + bool value = (_has_bits_[0] & 0x00000008u) != 0; + PROTOBUF_ASSUME(!value || generated_code_info_ != nullptr); + return value; +} +inline bool CodeGeneratorResponse_File::has_generated_code_info() const { + return _internal_has_generated_code_info(); +} +inline const ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo& CodeGeneratorResponse_File::_internal_generated_code_info() const { + const ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo* p = generated_code_info_; + return p != nullptr ? *p : reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo&>( + ::PROTOBUF_NAMESPACE_ID::_GeneratedCodeInfo_default_instance_); +} +inline const ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo& CodeGeneratorResponse_File::generated_code_info() const { + // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorResponse.File.generated_code_info) + return _internal_generated_code_info(); +} +inline void CodeGeneratorResponse_File::unsafe_arena_set_allocated_generated_code_info( + ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo* generated_code_info) { + if (GetArenaForAllocation() == nullptr) { + delete reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(generated_code_info_); + } + generated_code_info_ = generated_code_info; + if (generated_code_info) { + _has_bits_[0] |= 0x00000008u; + } else { + _has_bits_[0] &= ~0x00000008u; + } + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.protobuf.compiler.CodeGeneratorResponse.File.generated_code_info) +} +inline ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo* CodeGeneratorResponse_File::release_generated_code_info() { + _has_bits_[0] &= ~0x00000008u; + ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo* temp = generated_code_info_; + generated_code_info_ = nullptr; +#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE + auto* old = reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(temp); + temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp); + if (GetArenaForAllocation() == nullptr) { delete old; } +#else // PROTOBUF_FORCE_COPY_IN_RELEASE + if (GetArenaForAllocation() != nullptr) { + temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp); + } +#endif // !PROTOBUF_FORCE_COPY_IN_RELEASE + return temp; +} +inline ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo* CodeGeneratorResponse_File::unsafe_arena_release_generated_code_info() { + // @@protoc_insertion_point(field_release:google.protobuf.compiler.CodeGeneratorResponse.File.generated_code_info) + _has_bits_[0] &= ~0x00000008u; + ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo* temp = generated_code_info_; + generated_code_info_ = nullptr; + return temp; +} +inline ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo* CodeGeneratorResponse_File::_internal_mutable_generated_code_info() { + _has_bits_[0] |= 0x00000008u; + if (generated_code_info_ == nullptr) { + auto* p = CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo>(GetArenaForAllocation()); + generated_code_info_ = p; + } + return generated_code_info_; +} +inline ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo* CodeGeneratorResponse_File::mutable_generated_code_info() { + ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo* _msg = _internal_mutable_generated_code_info(); + // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.File.generated_code_info) + return _msg; +} +inline void CodeGeneratorResponse_File::set_allocated_generated_code_info(::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo* generated_code_info) { + ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation(); + if (message_arena == nullptr) { + delete reinterpret_cast< ::PROTOBUF_NAMESPACE_ID::MessageLite*>(generated_code_info_); + } + if (generated_code_info) { + ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena = + ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper< + ::PROTOBUF_NAMESPACE_ID::MessageLite>::GetOwningArena( + reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(generated_code_info)); + if (message_arena != submessage_arena) { + generated_code_info = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage( + message_arena, generated_code_info, submessage_arena); + } + _has_bits_[0] |= 0x00000008u; + } else { + _has_bits_[0] &= ~0x00000008u; + } + generated_code_info_ = generated_code_info; + // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.CodeGeneratorResponse.File.generated_code_info) +} + +// ------------------------------------------------------------------- + +// CodeGeneratorResponse + +// optional string error = 1; +inline bool CodeGeneratorResponse::_internal_has_error() const { + bool value = (_has_bits_[0] & 0x00000001u) != 0; + return value; +} +inline bool CodeGeneratorResponse::has_error() const { + return _internal_has_error(); +} +inline void CodeGeneratorResponse::clear_error() { + error_.ClearToEmpty(); + _has_bits_[0] &= ~0x00000001u; +} +inline const std::string& CodeGeneratorResponse::error() const { + // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorResponse.error) + return _internal_error(); +} +template <typename ArgT0, typename... ArgT> +inline PROTOBUF_ALWAYS_INLINE +void CodeGeneratorResponse::set_error(ArgT0&& arg0, ArgT... args) { + _has_bits_[0] |= 0x00000001u; + error_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation()); + // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorResponse.error) +} +inline std::string* CodeGeneratorResponse::mutable_error() { + std::string* _s = _internal_mutable_error(); + // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.error) + return _s; +} +inline const std::string& CodeGeneratorResponse::_internal_error() const { + return error_.Get(); +} +inline void CodeGeneratorResponse::_internal_set_error(const std::string& value) { + _has_bits_[0] |= 0x00000001u; + error_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, value, GetArenaForAllocation()); +} +inline std::string* CodeGeneratorResponse::_internal_mutable_error() { + _has_bits_[0] |= 0x00000001u; + return error_.Mutable(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, GetArenaForAllocation()); +} +inline std::string* CodeGeneratorResponse::release_error() { + // @@protoc_insertion_point(field_release:google.protobuf.compiler.CodeGeneratorResponse.error) + if (!_internal_has_error()) { + return nullptr; + } + _has_bits_[0] &= ~0x00000001u; + auto* p = error_.ReleaseNonDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (error_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) { + error_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + } +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + return p; +} +inline void CodeGeneratorResponse::set_allocated_error(std::string* error) { + if (error != nullptr) { + _has_bits_[0] |= 0x00000001u; + } else { + _has_bits_[0] &= ~0x00000001u; + } + error_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), error, + GetArenaForAllocation()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (error_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) { + error_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + } +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.CodeGeneratorResponse.error) +} + +// optional uint64 supported_features = 2; +inline bool CodeGeneratorResponse::_internal_has_supported_features() const { + bool value = (_has_bits_[0] & 0x00000002u) != 0; + return value; +} +inline bool CodeGeneratorResponse::has_supported_features() const { + return _internal_has_supported_features(); +} +inline void CodeGeneratorResponse::clear_supported_features() { + supported_features_ = uint64_t{0u}; + _has_bits_[0] &= ~0x00000002u; +} +inline uint64_t CodeGeneratorResponse::_internal_supported_features() const { + return supported_features_; +} +inline uint64_t CodeGeneratorResponse::supported_features() const { + // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorResponse.supported_features) + return _internal_supported_features(); +} +inline void CodeGeneratorResponse::_internal_set_supported_features(uint64_t value) { + _has_bits_[0] |= 0x00000002u; + supported_features_ = value; +} +inline void CodeGeneratorResponse::set_supported_features(uint64_t value) { + _internal_set_supported_features(value); + // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorResponse.supported_features) +} + +// repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15; +inline int CodeGeneratorResponse::_internal_file_size() const { + return file_.size(); +} +inline int CodeGeneratorResponse::file_size() const { + return _internal_file_size(); +} +inline void CodeGeneratorResponse::clear_file() { + file_.Clear(); +} +inline ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File* CodeGeneratorResponse::mutable_file(int index) { + // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.file) + return file_.Mutable(index); +} +inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File >* +CodeGeneratorResponse::mutable_file() { + // @@protoc_insertion_point(field_mutable_list:google.protobuf.compiler.CodeGeneratorResponse.file) + return &file_; +} +inline const ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File& CodeGeneratorResponse::_internal_file(int index) const { + return file_.Get(index); +} +inline const ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File& CodeGeneratorResponse::file(int index) const { + // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorResponse.file) + return _internal_file(index); +} +inline ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File* CodeGeneratorResponse::_internal_add_file() { + return file_.Add(); +} +inline ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File* CodeGeneratorResponse::add_file() { + ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File* _add = _internal_add_file(); + // @@protoc_insertion_point(field_add:google.protobuf.compiler.CodeGeneratorResponse.file) + return _add; +} +inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File >& +CodeGeneratorResponse::file() const { + // @@protoc_insertion_point(field_list:google.protobuf.compiler.CodeGeneratorResponse.file) + return file_; +} + +#ifdef __GNUC__ + #pragma GCC diagnostic pop +#endif // __GNUC__ +// ------------------------------------------------------------------- + +// ------------------------------------------------------------------- + +// ------------------------------------------------------------------- + + +// @@protoc_insertion_point(namespace_scope) + +} // namespace compiler +PROTOBUF_NAMESPACE_CLOSE + +PROTOBUF_NAMESPACE_OPEN + +template <> struct is_proto_enum< ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_Feature> : ::std::true_type {}; +template <> +inline const EnumDescriptor* GetEnumDescriptor< ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_Feature>() { + return ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_Feature_descriptor(); +} + +PROTOBUF_NAMESPACE_CLOSE + +// @@protoc_insertion_point(global_scope) + +#include <port_undef.inc> +#endif // GOOGLE_PROTOBUF_INCLUDED_GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2fcompiler_2fplugin_2eproto diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/plugin.proto b/NorthstarDedicatedTest/include/protobuf/compiler/plugin.proto new file mode 100644 index 00000000..9242aacc --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/plugin.proto @@ -0,0 +1,183 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// +// WARNING: The plugin interface is currently EXPERIMENTAL and is subject to +// change. +// +// protoc (aka the Protocol Compiler) can be extended via plugins. A plugin is +// just a program that reads a CodeGeneratorRequest from stdin and writes a +// CodeGeneratorResponse to stdout. +// +// Plugins written using C++ can use google/protobuf/compiler/plugin.h instead +// of dealing with the raw protocol defined here. +// +// A plugin executable needs only to be placed somewhere in the path. The +// plugin should be named "protoc-gen-$NAME", and will then be used when the +// flag "--${NAME}_out" is passed to protoc. + +syntax = "proto2"; + +package google.protobuf.compiler; +option java_package = "com.google.protobuf.compiler"; +option java_outer_classname = "PluginProtos"; + +option go_package = "google.golang.org/protobuf/types/pluginpb"; + +import "google/protobuf/descriptor.proto"; + +// The version number of protocol compiler. +message Version { + optional int32 major = 1; + optional int32 minor = 2; + optional int32 patch = 3; + // A suffix for alpha, beta or rc release, e.g., "alpha-1", "rc2". It should + // be empty for mainline stable releases. + optional string suffix = 4; +} + +// An encoded CodeGeneratorRequest is written to the plugin's stdin. +message CodeGeneratorRequest { + // The .proto files that were explicitly listed on the command-line. The + // code generator should generate code only for these files. Each file's + // descriptor will be included in proto_file, below. + repeated string file_to_generate = 1; + + // The generator parameter passed on the command-line. + optional string parameter = 2; + + // FileDescriptorProtos for all files in files_to_generate and everything + // they import. The files will appear in topological order, so each file + // appears before any file that imports it. + // + // protoc guarantees that all proto_files will be written after + // the fields above, even though this is not technically guaranteed by the + // protobuf wire format. This theoretically could allow a plugin to stream + // in the FileDescriptorProtos and handle them one by one rather than read + // the entire set into memory at once. However, as of this writing, this + // is not similarly optimized on protoc's end -- it will store all fields in + // memory at once before sending them to the plugin. + // + // Type names of fields and extensions in the FileDescriptorProto are always + // fully qualified. + repeated FileDescriptorProto proto_file = 15; + + // The version number of protocol compiler. + optional Version compiler_version = 3; + +} + +// The plugin writes an encoded CodeGeneratorResponse to stdout. +message CodeGeneratorResponse { + // Error message. If non-empty, code generation failed. The plugin process + // should exit with status code zero even if it reports an error in this way. + // + // This should be used to indicate errors in .proto files which prevent the + // code generator from generating correct code. Errors which indicate a + // problem in protoc itself -- such as the input CodeGeneratorRequest being + // unparseable -- should be reported by writing a message to stderr and + // exiting with a non-zero status code. + optional string error = 1; + + // A bitmask of supported features that the code generator supports. + // This is a bitwise "or" of values from the Feature enum. + optional uint64 supported_features = 2; + + // Sync with code_generator.h. + enum Feature { + FEATURE_NONE = 0; + FEATURE_PROTO3_OPTIONAL = 1; + } + + // Represents a single generated file. + message File { + // The file name, relative to the output directory. The name must not + // contain "." or ".." components and must be relative, not be absolute (so, + // the file cannot lie outside the output directory). "/" must be used as + // the path separator, not "\". + // + // If the name is omitted, the content will be appended to the previous + // file. This allows the generator to break large files into small chunks, + // and allows the generated text to be streamed back to protoc so that large + // files need not reside completely in memory at one time. Note that as of + // this writing protoc does not optimize for this -- it will read the entire + // CodeGeneratorResponse before writing files to disk. + optional string name = 1; + + // If non-empty, indicates that the named file should already exist, and the + // content here is to be inserted into that file at a defined insertion + // point. This feature allows a code generator to extend the output + // produced by another code generator. The original generator may provide + // insertion points by placing special annotations in the file that look + // like: + // @@protoc_insertion_point(NAME) + // The annotation can have arbitrary text before and after it on the line, + // which allows it to be placed in a comment. NAME should be replaced with + // an identifier naming the point -- this is what other generators will use + // as the insertion_point. Code inserted at this point will be placed + // immediately above the line containing the insertion point (thus multiple + // insertions to the same point will come out in the order they were added). + // The double-@ is intended to make it unlikely that the generated code + // could contain things that look like insertion points by accident. + // + // For example, the C++ code generator places the following line in the + // .pb.h files that it generates: + // // @@protoc_insertion_point(namespace_scope) + // This line appears within the scope of the file's package namespace, but + // outside of any particular class. Another plugin can then specify the + // insertion_point "namespace_scope" to generate additional classes or + // other declarations that should be placed in this scope. + // + // Note that if the line containing the insertion point begins with + // whitespace, the same whitespace will be added to every line of the + // inserted text. This is useful for languages like Python, where + // indentation matters. In these languages, the insertion point comment + // should be indented the same amount as any inserted code will need to be + // in order to work correctly in that context. + // + // The code generator that generates the initial file and the one which + // inserts into it must both run as part of a single invocation of protoc. + // Code generators are executed in the order in which they appear on the + // command line. + // + // If |insertion_point| is present, |name| must also be present. + optional string insertion_point = 2; + + // The file contents. + optional string content = 15; + + // Information describing the file content being inserted. If an insertion + // point is used, this information will be appropriately offset and inserted + // into the code generation metadata for the generated files. + optional GeneratedCodeInfo generated_code_info = 16; + } + repeated File file = 15; +} diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/python/python_generator.cc b/NorthstarDedicatedTest/include/protobuf/compiler/python/python_generator.cc new file mode 100644 index 00000000..96b52990 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/python/python_generator.cc @@ -0,0 +1,1577 @@ +// 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. + +// Author: robinson@google.com (Will Robinson) +// +// This module outputs pure-Python protocol message classes that will +// largely be constructed at runtime via the metaclass in reflection.py. +// In other words, our job is basically to output a Python equivalent +// of the C++ *Descriptor objects, and fix up all circular references +// within these objects. +// +// Note that the runtime performance of protocol message classes created in +// this way is expected to be lousy. The plan is to create an alternate +// generator that outputs a Python/C extension module that lets +// performance-minded Python code leverage the fast C++ implementation +// directly. + +#include <compiler/python/python_generator.h> + +#include <algorithm> +#include <limits> +#include <map> +#include <memory> +#include <string> +#include <utility> +#include <vector> + +#include <stubs/logging.h> +#include <stubs/common.h> +#include <stubs/stringprintf.h> +#include <descriptor.pb.h> +#include <io/printer.h> +#include <io/zero_copy_stream.h> +#include <descriptor.h> +#include <stubs/strutil.h> +#include <stubs/substitute.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace python { + +namespace { + + +// Returns the Python module name expected for a given .proto filename. +std::string ModuleName(const std::string& filename) { + std::string basename = StripProto(filename); + ReplaceCharacters(&basename, "-", '_'); + ReplaceCharacters(&basename, "/", '.'); + return basename + "_pb2"; +} + +// Returns the alias we assign to the module of the given .proto filename +// when importing. See testPackageInitializationImport in +// net/proto2/python/internal/reflection_test.py +// to see why we need the alias. +std::string ModuleAlias(const std::string& filename) { + std::string module_name = ModuleName(filename); + // We can't have dots in the module name, so we replace each with _dot_. + // But that could lead to a collision between a.b and a_dot_b, so we also + // duplicate each underscore. + GlobalReplaceSubstring("_", "__", &module_name); + GlobalReplaceSubstring(".", "_dot_", &module_name); + return module_name; +} + +// Keywords reserved by the Python language. +const char* const kKeywords[] = { + "False", "None", "True", "and", "as", "assert", + "async", "await", "break", "class", "continue", "def", + "del", "elif", "else", "except", "finally", "for", + "from", "global", "if", "import", "in", "is", + "lambda", "nonlocal", "not", "or", "pass", "raise", + "return", "try", "while", "with", "yield", "print", +}; +const char* const* kKeywordsEnd = + kKeywords + (sizeof(kKeywords) / sizeof(kKeywords[0])); + +bool ContainsPythonKeyword(const std::string& module_name) { + std::vector<std::string> tokens = Split(module_name, "."); + for (int i = 0; i < tokens.size(); ++i) { + if (std::find(kKeywords, kKeywordsEnd, tokens[i]) != kKeywordsEnd) { + return true; + } + } + return false; +} + +inline bool IsPythonKeyword(const std::string& name) { + return (std::find(kKeywords, kKeywordsEnd, name) != kKeywordsEnd); +} + +std::string ResolveKeyword(const std::string& name) { + if (IsPythonKeyword(name)) { + return "globals()['" + name + "']"; + } + return name; +} + +// Returns the name of all containing types for descriptor, +// in order from outermost to innermost, followed by descriptor's +// own name. Each name is separated by |separator|. +template <typename DescriptorT> +std::string NamePrefixedWithNestedTypes(const DescriptorT& descriptor, + const std::string& separator) { + std::string name = descriptor.name(); + const Descriptor* parent = descriptor.containing_type(); + if (parent != nullptr) { + std::string prefix = NamePrefixedWithNestedTypes(*parent, separator); + if (separator == "." && IsPythonKeyword(name)) { + return "getattr(" + prefix + ", '" + name + "')"; + } else { + return prefix + separator + name; + } + } + if (separator == ".") { + name = ResolveKeyword(name); + } + return name; +} + +// Name of the class attribute where we store the Python +// descriptor.Descriptor instance for the generated class. +// Must stay consistent with the _DESCRIPTOR_KEY constant +// in proto2/public/reflection.py. +const char kDescriptorKey[] = "DESCRIPTOR"; + +// Does the file have top-level enums? +inline bool HasTopLevelEnums(const FileDescriptor* file) { + return file->enum_type_count() > 0; +} + +// Should we generate generic services for this file? +inline bool HasGenericServices(const FileDescriptor* file) { + return file->service_count() > 0 && file->options().py_generic_services(); +} + +// Prints the common boilerplate needed at the top of every .py +// file output by this generator. +void PrintTopBoilerplate(io::Printer* printer, const FileDescriptor* file, + bool descriptor_proto) { + // TODO(robinson): Allow parameterization of Python version? + printer->Print( + "# -*- coding: utf-8 -*-\n" + "# Generated by the protocol buffer compiler. DO NOT EDIT!\n" + "# source: $filename$\n" + "\"\"\"Generated protocol buffer code.\"\"\"\n", + "filename", file->name()); + if (HasTopLevelEnums(file)) { + printer->Print( + "from google.protobuf.internal import enum_type_wrapper\n"); + } + printer->Print( + "from google.protobuf import descriptor as _descriptor\n" + "from google.protobuf import descriptor_pool as " + "_descriptor_pool\n" + "from google.protobuf import message as _message\n" + "from google.protobuf import reflection as _reflection\n" + "from google.protobuf import symbol_database as " + "_symbol_database\n"); + if (HasGenericServices(file)) { + printer->Print( + "from google.protobuf import service as _service\n" + "from google.protobuf import service_reflection\n"); + } + + printer->Print( + "# @@protoc_insertion_point(imports)\n\n" + "_sym_db = _symbol_database.Default()\n"); + printer->Print("\n\n"); +} + +// Returns a Python literal giving the default value for a field. +// If the field specifies no explicit default value, we'll return +// the default default value for the field type (zero for numbers, +// empty string for strings, empty list for repeated fields, and +// None for non-repeated, composite fields). +// +// TODO(robinson): Unify with code from +// //compiler/cpp/internal/primitive_field.cc +// //compiler/cpp/internal/enum_field.cc +// //compiler/cpp/internal/string_field.cc +std::string StringifyDefaultValue(const FieldDescriptor& field) { + if (field.is_repeated()) { + return "[]"; + } + + switch (field.cpp_type()) { + case FieldDescriptor::CPPTYPE_INT32: + return StrCat(field.default_value_int32()); + case FieldDescriptor::CPPTYPE_UINT32: + return StrCat(field.default_value_uint32()); + case FieldDescriptor::CPPTYPE_INT64: + return StrCat(field.default_value_int64()); + case FieldDescriptor::CPPTYPE_UINT64: + return StrCat(field.default_value_uint64()); + case FieldDescriptor::CPPTYPE_DOUBLE: { + double value = field.default_value_double(); + if (value == std::numeric_limits<double>::infinity()) { + // Python pre-2.6 on Windows does not parse "inf" correctly. However, + // a numeric literal that is too big for a double will become infinity. + return "1e10000"; + } else if (value == -std::numeric_limits<double>::infinity()) { + // See above. + return "-1e10000"; + } else if (value != value) { + // infinity * 0 = nan + return "(1e10000 * 0)"; + } else { + return "float(" + SimpleDtoa(value) + ")"; + } + } + case FieldDescriptor::CPPTYPE_FLOAT: { + float value = field.default_value_float(); + if (value == std::numeric_limits<float>::infinity()) { + // Python pre-2.6 on Windows does not parse "inf" correctly. However, + // a numeric literal that is too big for a double will become infinity. + return "1e10000"; + } else if (value == -std::numeric_limits<float>::infinity()) { + // See above. + return "-1e10000"; + } else if (value != value) { + // infinity - infinity = nan + return "(1e10000 * 0)"; + } else { + return "float(" + SimpleFtoa(value) + ")"; + } + } + case FieldDescriptor::CPPTYPE_BOOL: + return field.default_value_bool() ? "True" : "False"; + case FieldDescriptor::CPPTYPE_ENUM: + return StrCat(field.default_value_enum()->number()); + case FieldDescriptor::CPPTYPE_STRING: + return "b\"" + CEscape(field.default_value_string()) + + (field.type() != FieldDescriptor::TYPE_STRING + ? "\"" + : "\".decode('utf-8')"); + case FieldDescriptor::CPPTYPE_MESSAGE: + return "None"; + } + // (We could add a default case above but then we wouldn't get the nice + // compiler warning when a new type is added.) + GOOGLE_LOG(FATAL) << "Not reached."; + return ""; +} + +std::string StringifySyntax(FileDescriptor::Syntax syntax) { + switch (syntax) { + case FileDescriptor::SYNTAX_PROTO2: + return "proto2"; + case FileDescriptor::SYNTAX_PROTO3: + return "proto3"; + case FileDescriptor::SYNTAX_UNKNOWN: + default: + GOOGLE_LOG(FATAL) << "Unsupported syntax; this generator only supports proto2 " + "and proto3 syntax."; + return ""; + } +} + +} // namespace + +Generator::Generator() : file_(nullptr) {} + +Generator::~Generator() {} + +uint64_t Generator::GetSupportedFeatures() const { + return CodeGenerator::Feature::FEATURE_PROTO3_OPTIONAL; +} + +bool Generator::Generate(const FileDescriptor* file, + const std::string& parameter, + GeneratorContext* context, std::string* error) const { + // ----------------------------------------------------------------- + // parse generator options + bool cpp_generated_lib_linked = false; + + std::vector<std::pair<std::string, std::string> > options; + ParseGeneratorParameter(parameter, &options); + + for (int i = 0; i < options.size(); i++) { + if (options[i].first == "cpp_generated_lib_linked") { + cpp_generated_lib_linked = true; + } else { + *error = "Unknown generator option: " + options[i].first; + return false; + } + } + + // Completely serialize all Generate() calls on this instance. The + // thread-safety constraints of the CodeGenerator interface aren't clear so + // just be as conservative as possible. It's easier to relax this later if + // we need to, but I doubt it will be an issue. + // TODO(kenton): The proper thing to do would be to allocate any state on + // the stack and use that, so that the Generator class itself does not need + // to have any mutable members. Then it is implicitly thread-safe. + MutexLock lock(&mutex_); + file_ = file; + std::string module_name = ModuleName(file->name()); + std::string filename = module_name; + ReplaceCharacters(&filename, ".", '/'); + filename += ".py"; + + pure_python_workable_ = !cpp_generated_lib_linked; + if (HasPrefixString(file->name(), "google/protobuf/")) { + pure_python_workable_ = true; + } + + FileDescriptorProto fdp; + file_->CopyTo(&fdp); + fdp.SerializeToString(&file_descriptor_serialized_); + + + std::unique_ptr<io::ZeroCopyOutputStream> output(context->Open(filename)); + GOOGLE_CHECK(output.get()); + io::Printer printer(output.get(), '$'); + printer_ = &printer; + + PrintTopBoilerplate(printer_, file_, GeneratingDescriptorProto()); + if (pure_python_workable_) { + PrintImports(); + } + PrintFileDescriptor(); + PrintTopLevelEnums(); + PrintTopLevelExtensions(); + if (pure_python_workable_) { + if (GeneratingDescriptorProto()) { + printer_->Print("if _descriptor._USE_C_DESCRIPTORS == False:\n"); + printer_->Indent(); + // Create enums before message descriptors + PrintAllNestedEnumsInFile(StripPrintDescriptor::kCreate); + PrintMessageDescriptors(StripPrintDescriptor::kCreate); + FixForeignFieldsInDescriptors(); + printer_->Outdent(); + printer_->Print("else:\n"); + printer_->Indent(); + } + // Find the message descriptors first and then use the message + // descriptor to find enums. + PrintMessageDescriptors(StripPrintDescriptor::kFind); + PrintAllNestedEnumsInFile(StripPrintDescriptor::kFind); + if (GeneratingDescriptorProto()) { + printer_->Outdent(); + } + } + PrintMessages(); + if (pure_python_workable_) { + PrintServiceDescriptors(); + + printer.Print("if _descriptor._USE_C_DESCRIPTORS == False:\n"); + printer_->Indent(); + + // We have to fix up the extensions after the message classes themselves, + // since they need to call static RegisterExtension() methods on these + // classes. + FixForeignFieldsInExtensions(); + // Descriptor options may have custom extensions. These custom options + // can only be successfully parsed after we register corresponding + // extensions. Therefore we parse all options again here to recognize + // custom options that may be unknown when we define the descriptors. + // This does not apply to services because they are not used by extensions. + FixAllDescriptorOptions(); + + // Set serialized_start and serialized_end. + SetSerializedPbInterval(); + + printer_->Outdent(); + } + if (HasGenericServices(file)) { + PrintServices(); + } + + printer.Print("# @@protoc_insertion_point(module_scope)\n"); + + return !printer.failed(); +} + + +// Prints Python imports for all modules imported by |file|. +void Generator::PrintImports() const { + for (int i = 0; i < file_->dependency_count(); ++i) { + const std::string& filename = file_->dependency(i)->name(); + + std::string module_name = ModuleName(filename); + std::string module_alias = ModuleAlias(filename); + if (ContainsPythonKeyword(module_name)) { + // If the module path contains a Python keyword, we have to quote the + // module name and import it using importlib. Otherwise the usual kind of + // import statement would result in a syntax error from the presence of + // the keyword. + printer_->Print("import importlib\n"); + printer_->Print("$alias$ = importlib.import_module('$name$')\n", "alias", + module_alias, "name", module_name); + } else { + int last_dot_pos = module_name.rfind('.'); + std::string import_statement; + if (last_dot_pos == std::string::npos) { + // NOTE(petya): this is not tested as it would require a protocol buffer + // outside of any package, and I don't think that is easily achievable. + import_statement = "import " + module_name; + } else { + import_statement = "from " + module_name.substr(0, last_dot_pos) + + " import " + module_name.substr(last_dot_pos + 1); + } + printer_->Print("$statement$ as $alias$\n", "statement", import_statement, + "alias", module_alias); + } + + CopyPublicDependenciesAliases(module_alias, file_->dependency(i)); + } + printer_->Print("\n"); + + // Print public imports. + for (int i = 0; i < file_->public_dependency_count(); ++i) { + std::string module_name = ModuleName(file_->public_dependency(i)->name()); + printer_->Print("from $module$ import *\n", "module", module_name); + } + printer_->Print("\n"); +} + +// Prints the single file descriptor for this file. +void Generator::PrintFileDescriptor() const { + std::map<std::string, std::string> m; + m["descriptor_name"] = kDescriptorKey; + m["name"] = file_->name(); + m["package"] = file_->package(); + m["syntax"] = StringifySyntax(file_->syntax()); + m["options"] = OptionsValue(file_->options().SerializeAsString()); + m["serialized_descriptor"] = strings::CHexEscape(file_descriptor_serialized_); + if (GeneratingDescriptorProto()) { + printer_->Print("if _descriptor._USE_C_DESCRIPTORS == False:\n"); + printer_->Indent(); + // Pure python's AddSerializedFile() depend on the generated + // descriptor_pb2.py thus we can not use AddSerializedFile() when + // generated descriptor.proto for pure python. + const char file_descriptor_template[] = + "$descriptor_name$ = _descriptor.FileDescriptor(\n" + " name='$name$',\n" + " package='$package$',\n" + " syntax='$syntax$',\n" + " serialized_options=$options$,\n" + " create_key=_descriptor._internal_create_key,\n"; + printer_->Print(m, file_descriptor_template); + printer_->Indent(); + if (pure_python_workable_) { + printer_->Print("serialized_pb=b'$value$'\n", "value", + strings::CHexEscape(file_descriptor_serialized_)); + if (file_->dependency_count() != 0) { + printer_->Print(",\ndependencies=["); + for (int i = 0; i < file_->dependency_count(); ++i) { + std::string module_alias = ModuleAlias(file_->dependency(i)->name()); + printer_->Print("$module_alias$.DESCRIPTOR,", "module_alias", + module_alias); + } + printer_->Print("]"); + } + if (file_->public_dependency_count() > 0) { + printer_->Print(",\npublic_dependencies=["); + for (int i = 0; i < file_->public_dependency_count(); ++i) { + std::string module_alias = + ModuleAlias(file_->public_dependency(i)->name()); + printer_->Print("$module_alias$.DESCRIPTOR,", "module_alias", + module_alias); + } + printer_->Print("]"); + } + } else { + printer_->Print("serialized_pb=''\n"); + } + + // TODO(falk): Also print options and fix the message_type, enum_type, + // service and extension later in the generation. + + printer_->Outdent(); + printer_->Print(")\n"); + + printer_->Outdent(); + printer_->Print("else:\n"); + printer_->Indent(); + } + printer_->Print(m, + "$descriptor_name$ = " + "_descriptor_pool.Default().AddSerializedFile(b'$serialized_" + "descriptor$')\n"); + if (GeneratingDescriptorProto()) { + printer_->Outdent(); + } + printer_->Print("\n"); +} + +// Prints descriptors and module-level constants for all top-level +// enums defined in |file|. +void Generator::PrintTopLevelEnums() const { + std::vector<std::pair<std::string, int> > top_level_enum_values; + for (int i = 0; i < file_->enum_type_count(); ++i) { + const EnumDescriptor& enum_descriptor = *file_->enum_type(i); + PrintFindEnum(enum_descriptor); + printer_->Print( + "$name$ = " + "enum_type_wrapper.EnumTypeWrapper($descriptor_name$)", + "name", ResolveKeyword(enum_descriptor.name()), "descriptor_name", + ModuleLevelDescriptorName(enum_descriptor)); + printer_->Print("\n"); + + for (int j = 0; j < enum_descriptor.value_count(); ++j) { + const EnumValueDescriptor& value_descriptor = *enum_descriptor.value(j); + top_level_enum_values.push_back( + std::make_pair(value_descriptor.name(), value_descriptor.number())); + } + } + + for (int i = 0; i < top_level_enum_values.size(); ++i) { + printer_->Print("$name$ = $value$\n", "name", + ResolveKeyword(top_level_enum_values[i].first), "value", + StrCat(top_level_enum_values[i].second)); + } + printer_->Print("\n"); +} + +// Prints all enums contained in all message types in |file|. +void Generator::PrintAllNestedEnumsInFile( + StripPrintDescriptor print_mode) const { + for (int i = 0; i < file_->message_type_count(); ++i) { + PrintNestedEnums(*file_->message_type(i), print_mode); + } +} + +// Prints a Python statement assigning the appropriate module-level +// enum name to a Python EnumDescriptor object equivalent to +// enum_descriptor. +void Generator::PrintCreateEnum(const EnumDescriptor& enum_descriptor) const { + std::map<std::string, std::string> m; + std::string module_level_descriptor_name = + ModuleLevelDescriptorName(enum_descriptor); + m["descriptor_name"] = module_level_descriptor_name; + m["name"] = enum_descriptor.name(); + m["full_name"] = enum_descriptor.full_name(); + m["file"] = kDescriptorKey; + const char enum_descriptor_template[] = + "$descriptor_name$ = _descriptor.EnumDescriptor(\n" + " name='$name$',\n" + " full_name='$full_name$',\n" + " filename=None,\n" + " file=$file$,\n" + " create_key=_descriptor._internal_create_key,\n" + " values=[\n"; + std::string options_string; + enum_descriptor.options().SerializeToString(&options_string); + printer_->Print(m, enum_descriptor_template); + printer_->Indent(); + printer_->Indent(); + + if (pure_python_workable_) { + for (int i = 0; i < enum_descriptor.value_count(); ++i) { + PrintEnumValueDescriptor(*enum_descriptor.value(i)); + printer_->Print(",\n"); + } + } + + printer_->Outdent(); + printer_->Print("],\n"); + printer_->Print("containing_type=None,\n"); + printer_->Print("serialized_options=$options_value$,\n", "options_value", + OptionsValue(options_string)); + EnumDescriptorProto edp; + printer_->Outdent(); + printer_->Print(")\n"); + if (pure_python_workable_) { + printer_->Print("_sym_db.RegisterEnumDescriptor($name$)\n", "name", + module_level_descriptor_name); + } + printer_->Print("\n"); +} + +void Generator::PrintFindEnum(const EnumDescriptor& enum_descriptor) const { + std::map<std::string, std::string> m; + m["descriptor_name"] = ModuleLevelDescriptorName(enum_descriptor); + m["name"] = enum_descriptor.name(); + m["file"] = kDescriptorKey; + if (enum_descriptor.containing_type()) { + m["containing_type"] = + ModuleLevelDescriptorName(*enum_descriptor.containing_type()); + printer_->Print(m, + "$descriptor_name$ = " + "$containing_type$.enum_types_by_name['$name$']\n"); + } else { + printer_->Print( + m, "$descriptor_name$ = $file$.enum_types_by_name['$name$']\n"); + } +} + +// Recursively prints enums in nested types within descriptor, then +// prints enums contained at the top level in descriptor. +void Generator::PrintNestedEnums(const Descriptor& descriptor, + StripPrintDescriptor print_mode) const { + for (int i = 0; i < descriptor.nested_type_count(); ++i) { + PrintNestedEnums(*descriptor.nested_type(i), print_mode); + } + + for (int i = 0; i < descriptor.enum_type_count(); ++i) { + if (print_mode == StripPrintDescriptor::kCreate) { + PrintCreateEnum(*descriptor.enum_type(i)); + } else { + PrintFindEnum(*descriptor.enum_type(i)); + } + } +} + +void Generator::PrintTopLevelExtensions() const { + for (int i = 0; i < file_->extension_count(); ++i) { + const FieldDescriptor& extension_field = *file_->extension(i); + std::string constant_name = extension_field.name() + "_FIELD_NUMBER"; + ToUpper(&constant_name); + printer_->Print("$constant_name$ = $number$\n", "constant_name", + constant_name, "number", + StrCat(extension_field.number())); + printer_->Print( + "$resolved_name$ = " + "$file$.extensions_by_name['$name$']\n", + "resolved_name", ResolveKeyword(extension_field.name()), "file", + kDescriptorKey, "name", extension_field.name()); + } + printer_->Print("\n"); +} + +// Prints Python equivalents of all Descriptors in |file|. +void Generator::PrintMessageDescriptors(StripPrintDescriptor print_mode) const { + if (print_mode == StripPrintDescriptor::kCreate) { + for (int i = 0; i < file_->message_type_count(); ++i) { + PrintCreateDescriptor(*file_->message_type(i)); + printer_->Print("\n"); + } + } else { + for (int i = 0; i < file_->message_type_count(); ++i) { + PrintFindDescriptor(*file_->message_type(i)); + } + } +} + +void Generator::PrintServiceDescriptors() const { + for (int i = 0; i < file_->service_count(); ++i) { + PrintServiceDescriptor(*file_->service(i)); + } +} + +void Generator::PrintServices() const { + for (int i = 0; i < file_->service_count(); ++i) { + PrintServiceClass(*file_->service(i)); + PrintServiceStub(*file_->service(i)); + printer_->Print("\n"); + } +} + +void Generator::PrintServiceDescriptor( + const ServiceDescriptor& descriptor) const { + std::map<std::string, std::string> m; + m["service_name"] = ModuleLevelServiceDescriptorName(descriptor); + m["name"] = descriptor.name(); + m["file"] = kDescriptorKey; + printer_->Print(m, "$service_name$ = $file$.services_by_name['$name$']\n"); +} + +void Generator::PrintDescriptorKeyAndModuleName( + const ServiceDescriptor& descriptor) const { + std::string name = ModuleLevelServiceDescriptorName(descriptor); + if (!pure_python_workable_) { + name = "_descriptor.ServiceDescriptor(full_name='" + + descriptor.full_name() + "')"; + } + printer_->Print("$descriptor_key$ = $descriptor_name$,\n", "descriptor_key", + kDescriptorKey, "descriptor_name", name); + std::string module_name = ModuleName(file_->name()); + printer_->Print("__module__ = '$module_name$'\n", "module_name", module_name); +} + +void Generator::PrintServiceClass(const ServiceDescriptor& descriptor) const { + // Print the service. + printer_->Print( + "$class_name$ = service_reflection.GeneratedServiceType(" + "'$class_name$', (_service.Service,), dict(\n", + "class_name", descriptor.name()); + printer_->Indent(); + Generator::PrintDescriptorKeyAndModuleName(descriptor); + printer_->Print("))\n\n"); + printer_->Outdent(); +} + +void Generator::PrintServiceStub(const ServiceDescriptor& descriptor) const { + // Print the service stub. + printer_->Print( + "$class_name$_Stub = " + "service_reflection.GeneratedServiceStubType(" + "'$class_name$_Stub', ($class_name$,), dict(\n", + "class_name", descriptor.name()); + printer_->Indent(); + Generator::PrintDescriptorKeyAndModuleName(descriptor); + printer_->Print("))\n\n"); + printer_->Outdent(); +} + +// Prints statement assigning ModuleLevelDescriptorName(message_descriptor) +// to a Python Descriptor object for message_descriptor. +// +// Mutually recursive with PrintNestedDescriptors(). +void Generator::PrintCreateDescriptor( + const Descriptor& message_descriptor) const { + std::map<std::string, std::string> m; + m["name"] = message_descriptor.name(); + m["full_name"] = message_descriptor.full_name(); + m["file"] = kDescriptorKey; + + PrintNestedDescriptors(message_descriptor, StripPrintDescriptor::kCreate); + + printer_->Print("\n"); + printer_->Print("$descriptor_name$ = _descriptor.Descriptor(\n", + "descriptor_name", + ModuleLevelDescriptorName(message_descriptor)); + printer_->Indent(); + const char required_function_arguments[] = + "name='$name$',\n" + "full_name='$full_name$',\n" + "filename=None,\n" + "file=$file$,\n" + "containing_type=None,\n" + "create_key=_descriptor._internal_create_key,\n"; + printer_->Print(m, required_function_arguments); + PrintFieldsInDescriptor(message_descriptor); + PrintExtensionsInDescriptor(message_descriptor); + + // Nested types + printer_->Print("nested_types=["); + for (int i = 0; i < message_descriptor.nested_type_count(); ++i) { + const std::string nested_name = + ModuleLevelDescriptorName(*message_descriptor.nested_type(i)); + printer_->Print("$name$, ", "name", nested_name); + } + printer_->Print("],\n"); + + // Enum types + printer_->Print("enum_types=[\n"); + printer_->Indent(); + for (int i = 0; i < message_descriptor.enum_type_count(); ++i) { + const std::string descriptor_name = + ModuleLevelDescriptorName(*message_descriptor.enum_type(i)); + printer_->Print(descriptor_name.c_str()); + printer_->Print(",\n"); + } + printer_->Outdent(); + printer_->Print("],\n"); + std::string options_string; + message_descriptor.options().SerializeToString(&options_string); + printer_->Print( + "serialized_options=$options_value$,\n" + "is_extendable=$extendable$,\n" + "syntax='$syntax$'", + "options_value", OptionsValue(options_string), "extendable", + message_descriptor.extension_range_count() > 0 ? "True" : "False", + "syntax", StringifySyntax(message_descriptor.file()->syntax())); + printer_->Print(",\n"); + + // Extension ranges + printer_->Print("extension_ranges=["); + for (int i = 0; i < message_descriptor.extension_range_count(); ++i) { + const Descriptor::ExtensionRange* range = + message_descriptor.extension_range(i); + printer_->Print("($start$, $end$), ", "start", StrCat(range->start), + "end", StrCat(range->end)); + } + printer_->Print("],\n"); + printer_->Print("oneofs=[\n"); + printer_->Indent(); + for (int i = 0; i < message_descriptor.oneof_decl_count(); ++i) { + const OneofDescriptor* desc = message_descriptor.oneof_decl(i); + m.clear(); + m["name"] = desc->name(); + m["full_name"] = desc->full_name(); + m["index"] = StrCat(desc->index()); + options_string = OptionsValue(desc->options().SerializeAsString()); + if (options_string == "None") { + m["serialized_options"] = ""; + } else { + m["serialized_options"] = ", serialized_options=" + options_string; + } + printer_->Print(m, + "_descriptor.OneofDescriptor(\n" + " name='$name$', full_name='$full_name$',\n" + " index=$index$, containing_type=None,\n" + " create_key=_descriptor._internal_create_key,\n" + "fields=[]$serialized_options$),\n"); + } + printer_->Outdent(); + printer_->Print("],\n"); + + printer_->Outdent(); + printer_->Print(")\n"); +} + +void Generator::PrintFindDescriptor( + const Descriptor& message_descriptor) const { + std::map<std::string, std::string> m; + m["descriptor_name"] = ModuleLevelDescriptorName(message_descriptor); + m["name"] = message_descriptor.name(); + + if (message_descriptor.containing_type()) { + m["containing_type"] = + ModuleLevelDescriptorName(*message_descriptor.containing_type()); + printer_->Print(m, + "$descriptor_name$ = " + "$containing_type$.nested_types_by_name['$name$']\n"); + } else { + m["file"] = kDescriptorKey; + printer_->Print( + m, "$descriptor_name$ = $file$.message_types_by_name['$name$']\n"); + } + + PrintNestedDescriptors(message_descriptor, StripPrintDescriptor::kFind); +} + +// Prints Python Descriptor objects for all nested types contained in +// message_descriptor. +// +// Mutually recursive with PrintDescriptor(). +void Generator::PrintNestedDescriptors(const Descriptor& containing_descriptor, + StripPrintDescriptor print_mode) const { + if (print_mode == StripPrintDescriptor::kCreate) { + for (int i = 0; i < containing_descriptor.nested_type_count(); ++i) { + PrintCreateDescriptor(*containing_descriptor.nested_type(i)); + } + } else { + for (int i = 0; i < containing_descriptor.nested_type_count(); ++i) { + PrintFindDescriptor(*containing_descriptor.nested_type(i)); + } + } +} + +// Prints all messages in |file|. +void Generator::PrintMessages() const { + for (int i = 0; i < file_->message_type_count(); ++i) { + std::vector<std::string> to_register; + PrintMessage(*file_->message_type(i), "", &to_register, false); + for (int j = 0; j < to_register.size(); ++j) { + printer_->Print("_sym_db.RegisterMessage($name$)\n", "name", + ResolveKeyword(to_register[j])); + } + printer_->Print("\n"); + } +} + +// Prints a Python class for the given message descriptor. We defer to the +// metaclass to do almost all of the work of actually creating a useful class. +// The purpose of this function and its many helper functions above is merely +// to output a Python version of the descriptors, which the metaclass in +// reflection.py will use to construct the meat of the class itself. +// +// Mutually recursive with PrintNestedMessages(). +// Collect nested message names to_register for the symbol_database. +void Generator::PrintMessage(const Descriptor& message_descriptor, + const std::string& prefix, + std::vector<std::string>* to_register, + bool is_nested) const { + std::string qualified_name; + if (is_nested) { + if (IsPythonKeyword(message_descriptor.name())) { + qualified_name = + "getattr(" + prefix + ", '" + message_descriptor.name() + "')"; + } else { + qualified_name = prefix + "." + message_descriptor.name(); + } + printer_->Print( + "'$name$' : _reflection.GeneratedProtocolMessageType('$name$', " + "(_message.Message,), {\n", + "name", message_descriptor.name()); + } else { + qualified_name = ResolveKeyword(message_descriptor.name()); + printer_->Print( + "$qualified_name$ = _reflection.GeneratedProtocolMessageType('$name$', " + "(_message.Message,), {\n", + "qualified_name", qualified_name, "name", message_descriptor.name()); + } + printer_->Indent(); + + to_register->push_back(qualified_name); + + PrintNestedMessages(message_descriptor, qualified_name, to_register); + std::map<std::string, std::string> m; + m["descriptor_key"] = kDescriptorKey; + if (pure_python_workable_) { + m["descriptor_name"] = ModuleLevelDescriptorName(message_descriptor); + } else { + m["descriptor_name"] = "_descriptor.Descriptor(full_name='" + + message_descriptor.full_name() + "')"; + } + printer_->Print(m, "'$descriptor_key$' : $descriptor_name$,\n"); + std::string module_name = ModuleName(file_->name()); + printer_->Print("'__module__' : '$module_name$'\n", "module_name", + module_name); + printer_->Print("# @@protoc_insertion_point(class_scope:$full_name$)\n", + "full_name", message_descriptor.full_name()); + printer_->Print("})\n"); + printer_->Outdent(); +} + +// Prints all nested messages within |containing_descriptor|. +// Mutually recursive with PrintMessage(). +void Generator::PrintNestedMessages( + const Descriptor& containing_descriptor, const std::string& prefix, + std::vector<std::string>* to_register) const { + for (int i = 0; i < containing_descriptor.nested_type_count(); ++i) { + printer_->Print("\n"); + PrintMessage(*containing_descriptor.nested_type(i), prefix, to_register, + true); + printer_->Print(",\n"); + } +} + +// Recursively fixes foreign fields in all nested types in |descriptor|, then +// sets the message_type and enum_type of all message and enum fields to point +// to their respective descriptors. +// Args: +// descriptor: descriptor to print fields for. +// containing_descriptor: if descriptor is a nested type, this is its +// containing type, or NULL if this is a root/top-level type. +void Generator::FixForeignFieldsInDescriptor( + const Descriptor& descriptor, + const Descriptor* containing_descriptor) const { + for (int i = 0; i < descriptor.nested_type_count(); ++i) { + FixForeignFieldsInDescriptor(*descriptor.nested_type(i), &descriptor); + } + + for (int i = 0; i < descriptor.field_count(); ++i) { + const FieldDescriptor& field_descriptor = *descriptor.field(i); + FixForeignFieldsInField(&descriptor, field_descriptor, "fields_by_name"); + } + + FixContainingTypeInDescriptor(descriptor, containing_descriptor); + for (int i = 0; i < descriptor.enum_type_count(); ++i) { + const EnumDescriptor& enum_descriptor = *descriptor.enum_type(i); + FixContainingTypeInDescriptor(enum_descriptor, &descriptor); + } + for (int i = 0; i < descriptor.oneof_decl_count(); ++i) { + std::map<std::string, std::string> m; + const OneofDescriptor* oneof = descriptor.oneof_decl(i); + m["descriptor_name"] = ModuleLevelDescriptorName(descriptor); + m["oneof_name"] = oneof->name(); + for (int j = 0; j < oneof->field_count(); ++j) { + m["field_name"] = oneof->field(j)->name(); + printer_->Print( + m, + "$descriptor_name$.oneofs_by_name['$oneof_name$'].fields.append(\n" + " $descriptor_name$.fields_by_name['$field_name$'])\n"); + printer_->Print( + m, + "$descriptor_name$.fields_by_name['$field_name$'].containing_oneof = " + "$descriptor_name$.oneofs_by_name['$oneof_name$']\n"); + } + } +} + +void Generator::AddMessageToFileDescriptor(const Descriptor& descriptor) const { + std::map<std::string, std::string> m; + m["descriptor_name"] = kDescriptorKey; + m["message_name"] = descriptor.name(); + m["message_descriptor_name"] = ModuleLevelDescriptorName(descriptor); + const char file_descriptor_template[] = + "$descriptor_name$.message_types_by_name['$message_name$'] = " + "$message_descriptor_name$\n"; + printer_->Print(m, file_descriptor_template); +} + +void Generator::AddServiceToFileDescriptor( + const ServiceDescriptor& descriptor) const { + std::map<std::string, std::string> m; + m["descriptor_name"] = kDescriptorKey; + m["service_name"] = descriptor.name(); + m["service_descriptor_name"] = ModuleLevelServiceDescriptorName(descriptor); + const char file_descriptor_template[] = + "$descriptor_name$.services_by_name['$service_name$'] = " + "$service_descriptor_name$\n"; + printer_->Print(m, file_descriptor_template); +} + +void Generator::AddEnumToFileDescriptor( + const EnumDescriptor& descriptor) const { + std::map<std::string, std::string> m; + m["descriptor_name"] = kDescriptorKey; + m["enum_name"] = descriptor.name(); + m["enum_descriptor_name"] = ModuleLevelDescriptorName(descriptor); + const char file_descriptor_template[] = + "$descriptor_name$.enum_types_by_name['$enum_name$'] = " + "$enum_descriptor_name$\n"; + printer_->Print(m, file_descriptor_template); +} + +void Generator::AddExtensionToFileDescriptor( + const FieldDescriptor& descriptor) const { + std::map<std::string, std::string> m; + m["descriptor_name"] = kDescriptorKey; + m["field_name"] = descriptor.name(); + m["resolved_name"] = ResolveKeyword(descriptor.name()); + const char file_descriptor_template[] = + "$descriptor_name$.extensions_by_name['$field_name$'] = " + "$resolved_name$\n"; + printer_->Print(m, file_descriptor_template); +} + +// Sets any necessary message_type and enum_type attributes +// for the Python version of |field|. +// +// containing_type may be NULL, in which case this is a module-level field. +// +// python_dict_name is the name of the Python dict where we should +// look the field up in the containing type. (e.g., fields_by_name +// or extensions_by_name). We ignore python_dict_name if containing_type +// is NULL. +void Generator::FixForeignFieldsInField( + const Descriptor* containing_type, const FieldDescriptor& field, + const std::string& python_dict_name) const { + const std::string field_referencing_expression = + FieldReferencingExpression(containing_type, field, python_dict_name); + std::map<std::string, std::string> m; + m["field_ref"] = field_referencing_expression; + const Descriptor* foreign_message_type = field.message_type(); + if (foreign_message_type) { + m["foreign_type"] = ModuleLevelDescriptorName(*foreign_message_type); + printer_->Print(m, "$field_ref$.message_type = $foreign_type$\n"); + } + const EnumDescriptor* enum_type = field.enum_type(); + if (enum_type) { + m["enum_type"] = ModuleLevelDescriptorName(*enum_type); + printer_->Print(m, "$field_ref$.enum_type = $enum_type$\n"); + } +} + +// Returns the module-level expression for the given FieldDescriptor. +// Only works for fields in the .proto file this Generator is generating for. +// +// containing_type may be NULL, in which case this is a module-level field. +// +// python_dict_name is the name of the Python dict where we should +// look the field up in the containing type. (e.g., fields_by_name +// or extensions_by_name). We ignore python_dict_name if containing_type +// is NULL. +std::string Generator::FieldReferencingExpression( + const Descriptor* containing_type, const FieldDescriptor& field, + const std::string& python_dict_name) const { + // We should only ever be looking up fields in the current file. + // The only things we refer to from other files are message descriptors. + GOOGLE_CHECK_EQ(field.file(), file_) + << field.file()->name() << " vs. " << file_->name(); + if (!containing_type) { + return ResolveKeyword(field.name()); + } + return strings::Substitute("$0.$1['$2']", + ModuleLevelDescriptorName(*containing_type), + python_dict_name, field.name()); +} + +// Prints containing_type for nested descriptors or enum descriptors. +template <typename DescriptorT> +void Generator::FixContainingTypeInDescriptor( + const DescriptorT& descriptor, + const Descriptor* containing_descriptor) const { + if (containing_descriptor != nullptr) { + const std::string nested_name = ModuleLevelDescriptorName(descriptor); + const std::string parent_name = + ModuleLevelDescriptorName(*containing_descriptor); + printer_->Print("$nested_name$.containing_type = $parent_name$\n", + "nested_name", nested_name, "parent_name", parent_name); + } +} + +// Prints statements setting the message_type and enum_type fields in the +// Python descriptor objects we've already output in the file. We must +// do this in a separate step due to circular references (otherwise, we'd +// just set everything in the initial assignment statements). +void Generator::FixForeignFieldsInDescriptors() const { + for (int i = 0; i < file_->message_type_count(); ++i) { + FixForeignFieldsInDescriptor(*file_->message_type(i), nullptr); + } + for (int i = 0; i < file_->message_type_count(); ++i) { + AddMessageToFileDescriptor(*file_->message_type(i)); + } + for (int i = 0; i < file_->enum_type_count(); ++i) { + AddEnumToFileDescriptor(*file_->enum_type(i)); + } + for (int i = 0; i < file_->extension_count(); ++i) { + AddExtensionToFileDescriptor(*file_->extension(i)); + } + + // TODO(jieluo): Move this register to PrintFileDescriptor() when + // FieldDescriptor.file is added in generated file. + printer_->Print("_sym_db.RegisterFileDescriptor($name$)\n", "name", + kDescriptorKey); + printer_->Print("\n"); +} + +// We need to not only set any necessary message_type fields, but +// also need to call RegisterExtension() on each message we're +// extending. +void Generator::FixForeignFieldsInExtensions() const { + // Top-level extensions. + for (int i = 0; i < file_->extension_count(); ++i) { + FixForeignFieldsInExtension(*file_->extension(i)); + } + // Nested extensions. + for (int i = 0; i < file_->message_type_count(); ++i) { + FixForeignFieldsInNestedExtensions(*file_->message_type(i)); + } + printer_->Print("\n"); +} + +void Generator::FixForeignFieldsInExtension( + const FieldDescriptor& extension_field) const { + GOOGLE_CHECK(extension_field.is_extension()); + + std::map<std::string, std::string> m; + // Confusingly, for FieldDescriptors that happen to be extensions, + // containing_type() means "extended type." + // On the other hand, extension_scope() will give us what we normally + // mean by containing_type(). + m["extended_message_class"] = + ModuleLevelMessageName(*extension_field.containing_type()); + m["field"] = FieldReferencingExpression( + extension_field.extension_scope(), extension_field, "extensions_by_name"); + printer_->Print(m, "$extended_message_class$.RegisterExtension($field$)\n"); +} + +void Generator::FixForeignFieldsInNestedExtensions( + const Descriptor& descriptor) const { + // Recursively fix up extensions in all nested types. + for (int i = 0; i < descriptor.nested_type_count(); ++i) { + FixForeignFieldsInNestedExtensions(*descriptor.nested_type(i)); + } + // Fix up extensions directly contained within this type. + for (int i = 0; i < descriptor.extension_count(); ++i) { + FixForeignFieldsInExtension(*descriptor.extension(i)); + } +} + +// Returns a Python expression that instantiates a Python EnumValueDescriptor +// object for the given C++ descriptor. +void Generator::PrintEnumValueDescriptor( + const EnumValueDescriptor& descriptor) const { + // TODO(robinson): Fix up EnumValueDescriptor "type" fields. + // More circular references. ::sigh:: + std::string options_string; + descriptor.options().SerializeToString(&options_string); + std::map<std::string, std::string> m; + m["name"] = descriptor.name(); + m["index"] = StrCat(descriptor.index()); + m["number"] = StrCat(descriptor.number()); + m["options"] = OptionsValue(options_string); + printer_->Print(m, + "_descriptor.EnumValueDescriptor(\n" + " name='$name$', index=$index$, number=$number$,\n" + " serialized_options=$options$,\n" + " type=None,\n" + " create_key=_descriptor._internal_create_key)"); +} + +// Returns a CEscaped string of serialized_options. +std::string Generator::OptionsValue( + const std::string& serialized_options) const { + if (serialized_options.length() == 0 || GeneratingDescriptorProto()) { + return "None"; + } else { + return "b'" + CEscape(serialized_options) + "'"; + } +} + +// Prints an expression for a Python FieldDescriptor for |field|. +void Generator::PrintFieldDescriptor(const FieldDescriptor& field, + bool is_extension) const { + std::string options_string; + field.options().SerializeToString(&options_string); + std::map<std::string, std::string> m; + m["name"] = field.name(); + m["full_name"] = field.full_name(); + m["index"] = StrCat(field.index()); + m["number"] = StrCat(field.number()); + m["type"] = StrCat(field.type()); + m["cpp_type"] = StrCat(field.cpp_type()); + m["label"] = StrCat(field.label()); + m["has_default_value"] = field.has_default_value() ? "True" : "False"; + m["default_value"] = StringifyDefaultValue(field); + m["is_extension"] = is_extension ? "True" : "False"; + m["serialized_options"] = OptionsValue(options_string); + m["json_name"] = + field.has_json_name() ? ", json_name='" + field.json_name() + "'" : ""; + // We always set message_type and enum_type to None at this point, and then + // these fields in correctly after all referenced descriptors have been + // defined and/or imported (see FixForeignFieldsInDescriptors()). + const char field_descriptor_decl[] = + "_descriptor.FieldDescriptor(\n" + " name='$name$', full_name='$full_name$', index=$index$,\n" + " number=$number$, type=$type$, cpp_type=$cpp_type$, label=$label$,\n" + " has_default_value=$has_default_value$, " + "default_value=$default_value$,\n" + " message_type=None, enum_type=None, containing_type=None,\n" + " is_extension=$is_extension$, extension_scope=None,\n" + " serialized_options=$serialized_options$$json_name$, file=DESCRIPTOR," + " create_key=_descriptor._internal_create_key)"; + printer_->Print(m, field_descriptor_decl); +} + +// Helper for Print{Fields,Extensions}InDescriptor(). +void Generator::PrintFieldDescriptorsInDescriptor( + const Descriptor& message_descriptor, bool is_extension, + const std::string& list_variable_name, int (Descriptor::*CountFn)() const, + const FieldDescriptor* (Descriptor::*GetterFn)(int)const) const { + printer_->Print("$list$=[\n", "list", list_variable_name); + printer_->Indent(); + for (int i = 0; i < (message_descriptor.*CountFn)(); ++i) { + PrintFieldDescriptor(*(message_descriptor.*GetterFn)(i), is_extension); + printer_->Print(",\n"); + } + printer_->Outdent(); + printer_->Print("],\n"); +} + +// Prints a statement assigning "fields" to a list of Python FieldDescriptors, +// one for each field present in message_descriptor. +void Generator::PrintFieldsInDescriptor( + const Descriptor& message_descriptor) const { + const bool is_extension = false; + PrintFieldDescriptorsInDescriptor(message_descriptor, is_extension, "fields", + &Descriptor::field_count, + &Descriptor::field); +} + +// Prints a statement assigning "extensions" to a list of Python +// FieldDescriptors, one for each extension present in message_descriptor. +void Generator::PrintExtensionsInDescriptor( + const Descriptor& message_descriptor) const { + const bool is_extension = true; + PrintFieldDescriptorsInDescriptor(message_descriptor, is_extension, + "extensions", &Descriptor::extension_count, + &Descriptor::extension); +} + +bool Generator::GeneratingDescriptorProto() const { + return file_->name() == "net/proto2/proto/descriptor.proto" || + file_->name() == "google/protobuf/descriptor.proto"; +} + +// Returns the unique Python module-level identifier given to a descriptor. +// This name is module-qualified iff the given descriptor describes an +// entity that doesn't come from the current file. +template <typename DescriptorT> +std::string Generator::ModuleLevelDescriptorName( + const DescriptorT& descriptor) const { + // FIXME(robinson): + // We currently don't worry about collisions with underscores in the type + // names, so these would collide in nasty ways if found in the same file: + // OuterProto.ProtoA.ProtoB + // OuterProto_ProtoA.ProtoB # Underscore instead of period. + // As would these: + // OuterProto.ProtoA_.ProtoB + // OuterProto.ProtoA._ProtoB # Leading vs. trailing underscore. + // (Contrived, but certainly possible). + // + // The C++ implementation doesn't guard against this either. Leaving + // it for now... + std::string name = NamePrefixedWithNestedTypes(descriptor, "_"); + ToUpper(&name); + // Module-private for now. Easy to make public later; almost impossible + // to make private later. + name = "_" + name; + // We now have the name relative to its own module. Also qualify with + // the module name iff this descriptor is from a different .proto file. + if (descriptor.file() != file_) { + name = ModuleAlias(descriptor.file()->name()) + "." + name; + } + return name; +} + +// Returns the name of the message class itself, not the descriptor. +// Like ModuleLevelDescriptorName(), module-qualifies the name iff +// the given descriptor describes an entity that doesn't come from +// the current file. +std::string Generator::ModuleLevelMessageName( + const Descriptor& descriptor) const { + std::string name = NamePrefixedWithNestedTypes(descriptor, "."); + if (descriptor.file() != file_) { + name = ModuleAlias(descriptor.file()->name()) + "." + name; + } + return name; +} + +// Returns the unique Python module-level identifier given to a service +// descriptor. +std::string Generator::ModuleLevelServiceDescriptorName( + const ServiceDescriptor& descriptor) const { + std::string name = descriptor.name(); + ToUpper(&name); + name = "_" + name; + if (descriptor.file() != file_) { + name = ModuleAlias(descriptor.file()->name()) + "." + name; + } + return name; +} + +// Prints standard constructor arguments serialized_start and serialized_end. +// Args: +// descriptor: The cpp descriptor to have a serialized reference. +// proto: A proto +// Example printer output: +// serialized_start=41, +// serialized_end=43, +// +template <typename DescriptorT, typename DescriptorProtoT> +void Generator::PrintSerializedPbInterval(const DescriptorT& descriptor, + DescriptorProtoT& proto, + const std::string& name) const { + descriptor.CopyTo(&proto); + std::string sp; + proto.SerializeToString(&sp); + int offset = file_descriptor_serialized_.find(sp); + GOOGLE_CHECK_GE(offset, 0); + + printer_->Print( + "$name$._serialized_start=$serialized_start$\n" + "$name$._serialized_end=$serialized_end$\n", + "name", name, "serialized_start", StrCat(offset), "serialized_end", + StrCat(offset + sp.size())); +} + +namespace { +void PrintDescriptorOptionsFixingCode(const std::string& descriptor, + const std::string& options, + io::Printer* printer) { + // Reset the _options to None thus DescriptorBase.GetOptions() can + // parse _options again after extensions are registered. + printer->Print( + "$descriptor$._options = None\n" + "$descriptor$._serialized_options = $serialized_value$\n", + "descriptor", descriptor, "serialized_value", options); +} +} // namespace + +void Generator::SetSerializedPbInterval() const { + // Top level enums. + for (int i = 0; i < file_->enum_type_count(); ++i) { + EnumDescriptorProto proto; + const EnumDescriptor& descriptor = *file_->enum_type(i); + PrintSerializedPbInterval(descriptor, proto, + ModuleLevelDescriptorName(descriptor)); + } + + // Messages. + for (int i = 0; i < file_->message_type_count(); ++i) { + SetMessagePbInterval(*file_->message_type(i)); + } + + // Services. + for (int i = 0; i < file_->service_count(); ++i) { + ServiceDescriptorProto proto; + const ServiceDescriptor& service = *file_->service(i); + PrintSerializedPbInterval(service, proto, + ModuleLevelServiceDescriptorName(service)); + } +} + +void Generator::SetMessagePbInterval(const Descriptor& descriptor) const { + DescriptorProto message_proto; + PrintSerializedPbInterval(descriptor, message_proto, + ModuleLevelDescriptorName(descriptor)); + + // Nested messages. + for (int i = 0; i < descriptor.nested_type_count(); ++i) { + SetMessagePbInterval(*descriptor.nested_type(i)); + } + + for (int i = 0; i < descriptor.enum_type_count(); ++i) { + EnumDescriptorProto proto; + const EnumDescriptor& enum_des = *descriptor.enum_type(i); + PrintSerializedPbInterval(enum_des, proto, + ModuleLevelDescriptorName(enum_des)); + } +} + +// Prints expressions that set the options field of all descriptors. +void Generator::FixAllDescriptorOptions() const { + // Prints an expression that sets the file descriptor's options. + std::string file_options = OptionsValue(file_->options().SerializeAsString()); + if (file_options != "None") { + PrintDescriptorOptionsFixingCode(kDescriptorKey, file_options, printer_); + } else { + printer_->Print("DESCRIPTOR._options = None\n"); + } + // Prints expressions that set the options for all top level enums. + for (int i = 0; i < file_->enum_type_count(); ++i) { + const EnumDescriptor& enum_descriptor = *file_->enum_type(i); + FixOptionsForEnum(enum_descriptor); + } + // Prints expressions that set the options for all top level extensions. + for (int i = 0; i < file_->extension_count(); ++i) { + const FieldDescriptor& field = *file_->extension(i); + FixOptionsForField(field); + } + // Prints expressions that set the options for all messages, nested enums, + // nested extensions and message fields. + for (int i = 0; i < file_->message_type_count(); ++i) { + FixOptionsForMessage(*file_->message_type(i)); + } + + for (int i = 0; i < file_->service_count(); ++i) { + FixOptionsForService(*file_->service(i)); + } +} + +void Generator::FixOptionsForOneof(const OneofDescriptor& oneof) const { + std::string oneof_options = OptionsValue(oneof.options().SerializeAsString()); + if (oneof_options != "None") { + std::string oneof_name = strings::Substitute( + "$0.$1['$2']", ModuleLevelDescriptorName(*oneof.containing_type()), + "oneofs_by_name", oneof.name()); + PrintDescriptorOptionsFixingCode(oneof_name, oneof_options, printer_); + } +} + +// Prints expressions that set the options for an enum descriptor and its +// value descriptors. +void Generator::FixOptionsForEnum(const EnumDescriptor& enum_descriptor) const { + std::string descriptor_name = ModuleLevelDescriptorName(enum_descriptor); + std::string enum_options = + OptionsValue(enum_descriptor.options().SerializeAsString()); + if (enum_options != "None") { + PrintDescriptorOptionsFixingCode(descriptor_name, enum_options, printer_); + } + for (int i = 0; i < enum_descriptor.value_count(); ++i) { + const EnumValueDescriptor& value_descriptor = *enum_descriptor.value(i); + std::string value_options = + OptionsValue(value_descriptor.options().SerializeAsString()); + if (value_options != "None") { + PrintDescriptorOptionsFixingCode( + StringPrintf("%s.values_by_name[\"%s\"]", descriptor_name.c_str(), + value_descriptor.name().c_str()), + value_options, printer_); + } + } +} + +// Prints expressions that set the options for an service descriptor and its +// value descriptors. +void Generator::FixOptionsForService( + const ServiceDescriptor& service_descriptor) const { + std::string descriptor_name = + ModuleLevelServiceDescriptorName(service_descriptor); + std::string service_options = + OptionsValue(service_descriptor.options().SerializeAsString()); + if (service_options != "None") { + PrintDescriptorOptionsFixingCode(descriptor_name, service_options, + printer_); + } + + for (int i = 0; i < service_descriptor.method_count(); ++i) { + const MethodDescriptor* method = service_descriptor.method(i); + std::string method_options = + OptionsValue(method->options().SerializeAsString()); + if (method_options != "None") { + std::string method_name = + descriptor_name + ".methods_by_name['" + method->name() + "']"; + PrintDescriptorOptionsFixingCode(method_name, method_options, printer_); + } + } +} + +// Prints expressions that set the options for field descriptors (including +// extensions). +void Generator::FixOptionsForField(const FieldDescriptor& field) const { + std::string field_options = OptionsValue(field.options().SerializeAsString()); + if (field_options != "None") { + std::string field_name; + if (field.is_extension()) { + if (field.extension_scope() == nullptr) { + // Top level extensions. + field_name = field.name(); + } else { + field_name = FieldReferencingExpression(field.extension_scope(), field, + "extensions_by_name"); + } + } else { + field_name = FieldReferencingExpression(field.containing_type(), field, + "fields_by_name"); + } + PrintDescriptorOptionsFixingCode(field_name, field_options, printer_); + } +} + +// Prints expressions that set the options for a message and all its inner +// types (nested messages, nested enums, extensions, fields). +void Generator::FixOptionsForMessage(const Descriptor& descriptor) const { + // Nested messages. + for (int i = 0; i < descriptor.nested_type_count(); ++i) { + FixOptionsForMessage(*descriptor.nested_type(i)); + } + // Oneofs. + for (int i = 0; i < descriptor.oneof_decl_count(); ++i) { + FixOptionsForOneof(*descriptor.oneof_decl(i)); + } + // Enums. + for (int i = 0; i < descriptor.enum_type_count(); ++i) { + FixOptionsForEnum(*descriptor.enum_type(i)); + } + // Fields. + for (int i = 0; i < descriptor.field_count(); ++i) { + const FieldDescriptor& field = *descriptor.field(i); + FixOptionsForField(field); + } + // Extensions. + for (int i = 0; i < descriptor.extension_count(); ++i) { + const FieldDescriptor& field = *descriptor.extension(i); + FixOptionsForField(field); + } + // Message option for this message. + std::string message_options = + OptionsValue(descriptor.options().SerializeAsString()); + if (message_options != "None") { + std::string descriptor_name = ModuleLevelDescriptorName(descriptor); + PrintDescriptorOptionsFixingCode(descriptor_name, message_options, + printer_); + } +} + +// If a dependency forwards other files through public dependencies, let's +// copy over the corresponding module aliases. +void Generator::CopyPublicDependenciesAliases( + const std::string& copy_from, const FileDescriptor* file) const { + for (int i = 0; i < file->public_dependency_count(); ++i) { + std::string module_name = ModuleName(file->public_dependency(i)->name()); + std::string module_alias = ModuleAlias(file->public_dependency(i)->name()); + // There's no module alias in the dependent file if it was generated by + // an old protoc (less than 3.0.0-alpha-1). Use module name in this + // situation. + printer_->Print( + "try:\n" + " $alias$ = $copy_from$.$alias$\n" + "except AttributeError:\n" + " $alias$ = $copy_from$.$module$\n", + "alias", module_alias, "module", module_name, "copy_from", copy_from); + CopyPublicDependenciesAliases(copy_from, file->public_dependency(i)); + } +} + +} // namespace python +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/python/python_generator.h b/NorthstarDedicatedTest/include/protobuf/compiler/python/python_generator.h new file mode 100644 index 00000000..6bcfdda9 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/python/python_generator.h @@ -0,0 +1,193 @@ +// 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. + +// Author: robinson@google.com (Will Robinson) +// +// Generates Python code for a given .proto file. + +#ifndef GOOGLE_PROTOBUF_COMPILER_PYTHON_GENERATOR_H__ +#define GOOGLE_PROTOBUF_COMPILER_PYTHON_GENERATOR_H__ + +#include <string> + +#include <compiler/code_generator.h> +#include <stubs/mutex.h> + +#include <port_def.inc> + +namespace google { +namespace protobuf { + +class Descriptor; +class EnumDescriptor; +class EnumValueDescriptor; +class FieldDescriptor; +class OneofDescriptor; +class ServiceDescriptor; + +namespace io { +class Printer; +} + +namespace compiler { +namespace python { + +enum class StripPrintDescriptor { kCreate, kFind }; + +// CodeGenerator implementation for generated Python protocol buffer classes. +// If you create your own protocol compiler binary and you want it to support +// Python output, you can do so by registering an instance of this +// CodeGenerator with the CommandLineInterface in your main() function. +class PROTOC_EXPORT Generator : public CodeGenerator { + public: + Generator(); + virtual ~Generator(); + + // CodeGenerator methods. + bool Generate(const FileDescriptor* file, const std::string& parameter, + GeneratorContext* generator_context, + std::string* error) const override; + + uint64_t GetSupportedFeatures() const override; + + private: + void PrintImports() const; + void PrintFileDescriptor() const; + void PrintTopLevelEnums() const; + void PrintAllNestedEnumsInFile(StripPrintDescriptor print_mode) const; + void PrintNestedEnums(const Descriptor& descriptor, + StripPrintDescriptor print_mode) const; + void PrintCreateEnum(const EnumDescriptor& enum_descriptor) const; + void PrintFindEnum(const EnumDescriptor& enum_descriptor) const; + + void PrintTopLevelExtensions() const; + + void PrintFieldDescriptor(const FieldDescriptor& field, + bool is_extension) const; + void PrintFieldDescriptorsInDescriptor( + const Descriptor& message_descriptor, bool is_extension, + const std::string& list_variable_name, int (Descriptor::*CountFn)() const, + const FieldDescriptor* (Descriptor::*GetterFn)(int)const) const; + void PrintFieldsInDescriptor(const Descriptor& message_descriptor) const; + void PrintExtensionsInDescriptor(const Descriptor& message_descriptor) const; + void PrintMessageDescriptors(StripPrintDescriptor print_mode) const; + void PrintCreateDescriptor(const Descriptor& message_descriptor) const; + void PrintFindDescriptor(const Descriptor& message_descriptor) const; + void PrintNestedDescriptors(const Descriptor& containing_descriptor, + StripPrintDescriptor print_mode) const; + + void PrintMessages() const; + void PrintMessage(const Descriptor& message_descriptor, + const std::string& prefix, + std::vector<std::string>* to_register, + bool is_nested) const; + void PrintNestedMessages(const Descriptor& containing_descriptor, + const std::string& prefix, + std::vector<std::string>* to_register) const; + + void FixForeignFieldsInDescriptors() const; + void FixForeignFieldsInDescriptor( + const Descriptor& descriptor, + const Descriptor* containing_descriptor) const; + void FixForeignFieldsInField(const Descriptor* containing_type, + const FieldDescriptor& field, + const std::string& python_dict_name) const; + void AddMessageToFileDescriptor(const Descriptor& descriptor) const; + void AddEnumToFileDescriptor(const EnumDescriptor& descriptor) const; + void AddExtensionToFileDescriptor(const FieldDescriptor& descriptor) const; + void AddServiceToFileDescriptor(const ServiceDescriptor& descriptor) const; + std::string FieldReferencingExpression( + const Descriptor* containing_type, const FieldDescriptor& field, + const std::string& python_dict_name) const; + template <typename DescriptorT> + void FixContainingTypeInDescriptor( + const DescriptorT& descriptor, + const Descriptor* containing_descriptor) const; + + void FixForeignFieldsInExtensions() const; + void FixForeignFieldsInExtension( + const FieldDescriptor& extension_field) const; + void FixForeignFieldsInNestedExtensions(const Descriptor& descriptor) const; + + void PrintServices() const; + void PrintServiceDescriptors() const; + void PrintServiceDescriptor(const ServiceDescriptor& descriptor) const; + void PrintServiceClass(const ServiceDescriptor& descriptor) const; + void PrintServiceStub(const ServiceDescriptor& descriptor) const; + void PrintDescriptorKeyAndModuleName( + const ServiceDescriptor& descriptor) const; + + void PrintEnumValueDescriptor(const EnumValueDescriptor& descriptor) const; + std::string OptionsValue(const std::string& serialized_options) const; + bool GeneratingDescriptorProto() const; + + template <typename DescriptorT> + std::string ModuleLevelDescriptorName(const DescriptorT& descriptor) const; + std::string ModuleLevelMessageName(const Descriptor& descriptor) const; + std::string ModuleLevelServiceDescriptorName( + const ServiceDescriptor& descriptor) const; + + template <typename DescriptorT, typename DescriptorProtoT> + void PrintSerializedPbInterval(const DescriptorT& descriptor, + DescriptorProtoT& proto, + const std::string& name) const; + + void FixAllDescriptorOptions() const; + void FixOptionsForField(const FieldDescriptor& field) const; + void FixOptionsForOneof(const OneofDescriptor& oneof) const; + void FixOptionsForEnum(const EnumDescriptor& descriptor) const; + void FixOptionsForService(const ServiceDescriptor& descriptor) const; + void FixOptionsForMessage(const Descriptor& descriptor) const; + + void SetSerializedPbInterval() const; + void SetMessagePbInterval(const Descriptor& descriptor) const; + + void CopyPublicDependenciesAliases(const std::string& copy_from, + const FileDescriptor* file) const; + + // Very coarse-grained lock to ensure that Generate() is reentrant. + // Guards file_, printer_ and file_descriptor_serialized_. + mutable Mutex mutex_; + mutable const FileDescriptor* file_; // Set in Generate(). Under mutex_. + mutable std::string file_descriptor_serialized_; + mutable io::Printer* printer_; // Set in Generate(). Under mutex_. + mutable bool pure_python_workable_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Generator); +}; + +} // namespace python +} // namespace compiler +} // namespace protobuf +} // namespace google + +#include <port_undef.inc> + +#endif // GOOGLE_PROTOBUF_COMPILER_PYTHON_GENERATOR_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/python/python_plugin_unittest.cc b/NorthstarDedicatedTest/include/protobuf/compiler/python/python_plugin_unittest.cc new file mode 100644 index 00000000..78b02e92 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/python/python_plugin_unittest.cc @@ -0,0 +1,161 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// +// TODO(kenton): Share code with the versions of this test in other languages? +// It seemed like parameterizing it would add more complexity than it is +// worth. + +#include <memory> + +#include <testing/file.h> +#include <testing/file.h> +#include <compiler/command_line_interface.h> +#include <compiler/python/python_generator.h> +#include <io/printer.h> +#include <io/zero_copy_stream.h> +#include <stubs/strutil.h> +#include <testing/googletest.h> +#include <gtest/gtest.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace python { +namespace { + +class TestGenerator : public CodeGenerator { + public: + TestGenerator() {} + ~TestGenerator() {} + + virtual bool Generate(const FileDescriptor* file, + const std::string& parameter, GeneratorContext* context, + std::string* error) const { + TryInsert("test_pb2.py", "imports", context); + TryInsert("test_pb2.py", "module_scope", context); + TryInsert("test_pb2.py", "class_scope:foo.Bar", context); + TryInsert("test_pb2.py", "class_scope:foo.Bar.Baz", context); + return true; + } + + void TryInsert(const std::string& filename, + const std::string& insertion_point, + GeneratorContext* context) const { + std::unique_ptr<io::ZeroCopyOutputStream> output( + context->OpenForInsert(filename, insertion_point)); + io::Printer printer(output.get(), '$'); + printer.Print("// inserted $name$\n", "name", insertion_point); + } +}; + +// This test verifies that all the expected insertion points exist. It does +// not verify that they are correctly-placed; that would require actually +// compiling the output which is a bit more than I care to do for this test. +TEST(PythonPluginTest, PluginTest) { + GOOGLE_CHECK_OK(File::SetContents(TestTempDir() + "/test.proto", + "syntax = \"proto2\";\n" + "package foo;\n" + "message Bar {\n" + " message Baz {}\n" + "}\n", + true)); + + compiler::CommandLineInterface cli; + cli.SetInputsAreProtoPathRelative(true); + + python::Generator python_generator; + TestGenerator test_generator; + cli.RegisterGenerator("--python_out", &python_generator, ""); + cli.RegisterGenerator("--test_out", &test_generator, ""); + + std::string proto_path = "-I" + TestTempDir(); + std::string python_out = "--python_out=" + TestTempDir(); + std::string test_out = "--test_out=" + TestTempDir(); + + const char* argv[] = {"protoc", proto_path.c_str(), python_out.c_str(), + test_out.c_str(), "test.proto"}; + + EXPECT_EQ(0, cli.Run(5, argv)); +} + +// This test verifies that the generated Python output uses regular imports (as +// opposed to importlib) in the usual case where the .proto file paths do not +// not contain any Python keywords. +TEST(PythonPluginTest, ImportTest) { + // Create files test1.proto and test2.proto with the former importing the + // latter. + GOOGLE_CHECK_OK(File::SetContents(TestTempDir() + "/test1.proto", + "syntax = \"proto3\";\n" + "package foo;\n" + "import \"test2.proto\";" + "message Message1 {\n" + " Message2 message_2 = 1;\n" + "}\n", + true)); + GOOGLE_CHECK_OK(File::SetContents(TestTempDir() + "/test2.proto", + "syntax = \"proto3\";\n" + "package foo;\n" + "message Message2 {}\n", + true)); + + compiler::CommandLineInterface cli; + cli.SetInputsAreProtoPathRelative(true); + python::Generator python_generator; + cli.RegisterGenerator("--python_out", &python_generator, ""); + std::string proto_path = "-I" + TestTempDir(); + std::string python_out = "--python_out=" + TestTempDir(); + const char* argv[] = {"protoc", proto_path.c_str(), "-I.", python_out.c_str(), + "test1.proto"}; + ASSERT_EQ(0, cli.Run(5, argv)); + + // Loop over the lines of the generated code and verify that we find an + // ordinary Python import but do not find the string "importlib". + std::string output; + GOOGLE_CHECK_OK(File::GetContents(TestTempDir() + "/test1_pb2.py", &output, + true)); + std::vector<std::string> lines = Split(output, "\n"); + std::string expected_import = "import test2_pb2"; + bool found_expected_import = false; + for (int i = 0; i < lines.size(); ++i) { + if (lines[i].find(expected_import) != std::string::npos) { + found_expected_import = true; + } + EXPECT_EQ(std::string::npos, lines[i].find("importlib")); + } + EXPECT_TRUE(found_expected_import); +} + +} // namespace +} // namespace python +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/ruby/ruby_generated_code.proto b/NorthstarDedicatedTest/include/protobuf/compiler/ruby/ruby_generated_code.proto new file mode 100644 index 00000000..70ec9f17 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/ruby/ruby_generated_code.proto @@ -0,0 +1,70 @@ +syntax = "proto3"; + +package A.B.C; + +import "ruby_generated_code_proto2_import.proto"; + +message TestMessage { + int32 optional_int32 = 1; + int64 optional_int64 = 2; + uint32 optional_uint32 = 3; + uint64 optional_uint64 = 4; + bool optional_bool = 5; + double optional_double = 6; + float optional_float = 7; + string optional_string = 8; + bytes optional_bytes = 9; + TestEnum optional_enum = 10; + TestMessage optional_msg = 11; + TestImportedMessage optional_proto2_submessage = 12; + + repeated int32 repeated_int32 = 21; + repeated int64 repeated_int64 = 22; + repeated uint32 repeated_uint32 = 23; + repeated uint64 repeated_uint64 = 24; + repeated bool repeated_bool = 25; + repeated double repeated_double = 26; + repeated float repeated_float = 27; + repeated string repeated_string = 28; + repeated bytes repeated_bytes = 29; + repeated TestEnum repeated_enum = 30; + repeated TestMessage repeated_msg = 31; + + oneof my_oneof { + int32 oneof_int32 = 41; + int64 oneof_int64 = 42; + uint32 oneof_uint32 = 43; + uint64 oneof_uint64 = 44; + bool oneof_bool = 45; + double oneof_double = 46; + float oneof_float = 47; + string oneof_string = 48; + bytes oneof_bytes = 49; + TestEnum oneof_enum = 50; + TestMessage oneof_msg = 51; + } + + map<int32, string> map_int32_string = 61; + map<int64, string> map_int64_string = 62; + map<uint32, string> map_uint32_string = 63; + map<uint64, string> map_uint64_string = 64; + map<bool, string> map_bool_string = 65; + map<string, string> map_string_string = 66; + map<string, TestMessage> map_string_msg = 67; + map<string, TestEnum> map_string_enum = 68; + map<string, int32> map_string_int32 = 69; + map<string, bool> map_string_bool = 70; + + message NestedMessage { + int32 foo = 1; + } + + NestedMessage nested_message = 80; +} + +enum TestEnum { + Default = 0; + A = 1; + B = 2; + C = 3; +} diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/ruby/ruby_generated_code_pb.rb b/NorthstarDedicatedTest/include/protobuf/compiler/ruby/ruby_generated_code_pb.rb new file mode 100644 index 00000000..256ac7c1 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/ruby/ruby_generated_code_pb.rb @@ -0,0 +1,79 @@ +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: ruby_generated_code.proto + +require 'google/protobuf' + +require 'ruby_generated_code_proto2_import_pb' + +Google::Protobuf::DescriptorPool.generated_pool.build do + add_file("ruby_generated_code.proto", :syntax => :proto3) do + add_message "A.B.C.TestMessage" do + optional :optional_int32, :int32, 1 + optional :optional_int64, :int64, 2 + optional :optional_uint32, :uint32, 3 + optional :optional_uint64, :uint64, 4 + optional :optional_bool, :bool, 5 + optional :optional_double, :double, 6 + optional :optional_float, :float, 7 + optional :optional_string, :string, 8 + optional :optional_bytes, :bytes, 9 + optional :optional_enum, :enum, 10, "A.B.C.TestEnum" + optional :optional_msg, :message, 11, "A.B.C.TestMessage" + optional :optional_proto2_submessage, :message, 12, "A.B.C.TestImportedMessage" + repeated :repeated_int32, :int32, 21 + repeated :repeated_int64, :int64, 22 + repeated :repeated_uint32, :uint32, 23 + repeated :repeated_uint64, :uint64, 24 + repeated :repeated_bool, :bool, 25 + repeated :repeated_double, :double, 26 + repeated :repeated_float, :float, 27 + repeated :repeated_string, :string, 28 + repeated :repeated_bytes, :bytes, 29 + repeated :repeated_enum, :enum, 30, "A.B.C.TestEnum" + repeated :repeated_msg, :message, 31, "A.B.C.TestMessage" + map :map_int32_string, :int32, :string, 61 + map :map_int64_string, :int64, :string, 62 + map :map_uint32_string, :uint32, :string, 63 + map :map_uint64_string, :uint64, :string, 64 + map :map_bool_string, :bool, :string, 65 + map :map_string_string, :string, :string, 66 + map :map_string_msg, :string, :message, 67, "A.B.C.TestMessage" + map :map_string_enum, :string, :enum, 68, "A.B.C.TestEnum" + map :map_string_int32, :string, :int32, 69 + map :map_string_bool, :string, :bool, 70 + optional :nested_message, :message, 80, "A.B.C.TestMessage.NestedMessage" + oneof :my_oneof do + optional :oneof_int32, :int32, 41 + optional :oneof_int64, :int64, 42 + optional :oneof_uint32, :uint32, 43 + optional :oneof_uint64, :uint64, 44 + optional :oneof_bool, :bool, 45 + optional :oneof_double, :double, 46 + optional :oneof_float, :float, 47 + optional :oneof_string, :string, 48 + optional :oneof_bytes, :bytes, 49 + optional :oneof_enum, :enum, 50, "A.B.C.TestEnum" + optional :oneof_msg, :message, 51, "A.B.C.TestMessage" + end + end + add_message "A.B.C.TestMessage.NestedMessage" do + optional :foo, :int32, 1 + end + add_enum "A.B.C.TestEnum" do + value :Default, 0 + value :A, 1 + value :B, 2 + value :C, 3 + end + end +end + +module A + module B + module C + TestMessage = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("A.B.C.TestMessage").msgclass + TestMessage::NestedMessage = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("A.B.C.TestMessage.NestedMessage").msgclass + TestEnum = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("A.B.C.TestEnum").enummodule + end + end +end diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/ruby/ruby_generated_code_proto2.proto b/NorthstarDedicatedTest/include/protobuf/compiler/ruby/ruby_generated_code_proto2.proto new file mode 100644 index 00000000..ea7f7836 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/ruby/ruby_generated_code_proto2.proto @@ -0,0 +1,71 @@ +syntax = "proto2"; + +package A.B.C; + +import "ruby_generated_code_proto2_import.proto"; + +message TestMessage { + optional int32 optional_int32 = 1 [default = 1]; + optional int64 optional_int64 = 2 [default = 2]; + optional uint32 optional_uint32 = 3 [default = 3]; + optional uint64 optional_uint64 = 4 [default = 4]; + optional bool optional_bool = 5 [default = true]; + optional double optional_double = 6 [default = 6.0]; + optional float optional_float = 7 [default = 7.0]; + optional string optional_string = 8 [default = "default str"]; + optional bytes optional_bytes = 9 [default = "\0\1\2\100fubar"]; + optional TestEnum optional_enum = 10 [default = A]; + optional TestMessage optional_msg = 11; + optional TestImportedMessage optional_proto2_submessage = 12; + + repeated int32 repeated_int32 = 21; + repeated int64 repeated_int64 = 22; + repeated uint32 repeated_uint32 = 23; + repeated uint64 repeated_uint64 = 24; + repeated bool repeated_bool = 25; + repeated double repeated_double = 26; + repeated float repeated_float = 27; + repeated string repeated_string = 28; + repeated bytes repeated_bytes = 29; + repeated TestEnum repeated_enum = 30; + repeated TestMessage repeated_msg = 31; + + required int32 required_int32 = 41; + required int64 required_int64 = 42; + required uint32 required_uint32 = 43; + required uint64 required_uint64 = 44; + required bool required_bool = 45; + required double required_double = 46; + required float required_float = 47; + required string required_string = 48; + required bytes required_bytes = 49; + required TestEnum required_enum = 50; + required TestMessage required_msg = 51; + + oneof my_oneof { + int32 oneof_int32 = 61; + int64 oneof_int64 = 62; + uint32 oneof_uint32 = 63; + uint64 oneof_uint64 = 64; + bool oneof_bool = 65; + double oneof_double = 66; + float oneof_float = 67; + string oneof_string = 68; + bytes oneof_bytes = 69; + TestEnum oneof_enum = 70; + TestMessage oneof_msg = 71; + } + + message NestedMessage { + optional int32 foo = 1; + } + + optional NestedMessage nested_message = 80; +} + +enum TestEnum { + Default = 0; + A = 1; + B = 2; + C = 3; +} diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/ruby/ruby_generated_code_proto2_import.proto b/NorthstarDedicatedTest/include/protobuf/compiler/ruby/ruby_generated_code_proto2_import.proto new file mode 100644 index 00000000..9ec07381 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/ruby/ruby_generated_code_proto2_import.proto @@ -0,0 +1,5 @@ +syntax = "proto2"; + +package A.B.C; + +message TestImportedMessage {} diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/ruby/ruby_generated_code_proto2_pb.rb b/NorthstarDedicatedTest/include/protobuf/compiler/ruby/ruby_generated_code_proto2_pb.rb new file mode 100644 index 00000000..44d31969 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/ruby/ruby_generated_code_proto2_pb.rb @@ -0,0 +1,80 @@ +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: ruby_generated_code_proto2.proto + +require 'google/protobuf' + +require 'ruby_generated_code_proto2_import_pb' + +Google::Protobuf::DescriptorPool.generated_pool.build do + add_file("ruby_generated_code_proto2.proto", :syntax => :proto2) do + add_message "A.B.C.TestMessage" do + optional :optional_int32, :int32, 1, default: 1 + optional :optional_int64, :int64, 2, default: 2 + optional :optional_uint32, :uint32, 3, default: 3 + optional :optional_uint64, :uint64, 4, default: 4 + optional :optional_bool, :bool, 5, default: true + optional :optional_double, :double, 6, default: 6 + optional :optional_float, :float, 7, default: 7 + optional :optional_string, :string, 8, default: "default str" + optional :optional_bytes, :bytes, 9, default: "\x00\x01\x02\x40\x66\x75\x62\x61\x72".force_encoding("ASCII-8BIT") + optional :optional_enum, :enum, 10, "A.B.C.TestEnum", default: 1 + optional :optional_msg, :message, 11, "A.B.C.TestMessage" + optional :optional_proto2_submessage, :message, 12, "A.B.C.TestImportedMessage" + repeated :repeated_int32, :int32, 21 + repeated :repeated_int64, :int64, 22 + repeated :repeated_uint32, :uint32, 23 + repeated :repeated_uint64, :uint64, 24 + repeated :repeated_bool, :bool, 25 + repeated :repeated_double, :double, 26 + repeated :repeated_float, :float, 27 + repeated :repeated_string, :string, 28 + repeated :repeated_bytes, :bytes, 29 + repeated :repeated_enum, :enum, 30, "A.B.C.TestEnum" + repeated :repeated_msg, :message, 31, "A.B.C.TestMessage" + required :required_int32, :int32, 41 + required :required_int64, :int64, 42 + required :required_uint32, :uint32, 43 + required :required_uint64, :uint64, 44 + required :required_bool, :bool, 45 + required :required_double, :double, 46 + required :required_float, :float, 47 + required :required_string, :string, 48 + required :required_bytes, :bytes, 49 + required :required_enum, :enum, 50, "A.B.C.TestEnum" + required :required_msg, :message, 51, "A.B.C.TestMessage" + optional :nested_message, :message, 80, "A.B.C.TestMessage.NestedMessage" + oneof :my_oneof do + optional :oneof_int32, :int32, 61 + optional :oneof_int64, :int64, 62 + optional :oneof_uint32, :uint32, 63 + optional :oneof_uint64, :uint64, 64 + optional :oneof_bool, :bool, 65 + optional :oneof_double, :double, 66 + optional :oneof_float, :float, 67 + optional :oneof_string, :string, 68 + optional :oneof_bytes, :bytes, 69 + optional :oneof_enum, :enum, 70, "A.B.C.TestEnum" + optional :oneof_msg, :message, 71, "A.B.C.TestMessage" + end + end + add_message "A.B.C.TestMessage.NestedMessage" do + optional :foo, :int32, 1 + end + add_enum "A.B.C.TestEnum" do + value :Default, 0 + value :A, 1 + value :B, 2 + value :C, 3 + end + end +end + +module A + module B + module C + TestMessage = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("A.B.C.TestMessage").msgclass + TestMessage::NestedMessage = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("A.B.C.TestMessage.NestedMessage").msgclass + TestEnum = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("A.B.C.TestEnum").enummodule + end + end +end diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/ruby/ruby_generated_pkg_explicit.proto b/NorthstarDedicatedTest/include/protobuf/compiler/ruby/ruby_generated_pkg_explicit.proto new file mode 100644 index 00000000..8d7c948a --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/ruby/ruby_generated_pkg_explicit.proto @@ -0,0 +1,9 @@ +syntax = "proto3"; + +package one.two.a_three; + +option ruby_package = "A::B::C"; + +message Four { + string a_string = 1; +} diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/ruby/ruby_generated_pkg_explicit_legacy.proto b/NorthstarDedicatedTest/include/protobuf/compiler/ruby/ruby_generated_pkg_explicit_legacy.proto new file mode 100644 index 00000000..7a0d2608 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/ruby/ruby_generated_pkg_explicit_legacy.proto @@ -0,0 +1,9 @@ +syntax = "proto3"; + +package one.two.a_three.and; + +option ruby_package = "AA.BB.CC"; + +message Four { + string another_string = 1; +} diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/ruby/ruby_generated_pkg_explicit_legacy_pb.rb b/NorthstarDedicatedTest/include/protobuf/compiler/ruby/ruby_generated_pkg_explicit_legacy_pb.rb new file mode 100644 index 00000000..cdbbe891 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/ruby/ruby_generated_pkg_explicit_legacy_pb.rb @@ -0,0 +1,20 @@ +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: ruby_generated_pkg_explicit_legacy.proto + +require 'google/protobuf' + +Google::Protobuf::DescriptorPool.generated_pool.build do + add_file("ruby_generated_pkg_explicit_legacy.proto", :syntax => :proto3) do + add_message "one.two.a_three.and.Four" do + optional :another_string, :string, 1 + end + end +end + +module AA + module BB + module CC + Four = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("one.two.a_three.and.Four").msgclass + end + end +end diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/ruby/ruby_generated_pkg_explicit_pb.rb b/NorthstarDedicatedTest/include/protobuf/compiler/ruby/ruby_generated_pkg_explicit_pb.rb new file mode 100644 index 00000000..e6d47011 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/ruby/ruby_generated_pkg_explicit_pb.rb @@ -0,0 +1,20 @@ +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: ruby_generated_pkg_explicit.proto + +require 'google/protobuf' + +Google::Protobuf::DescriptorPool.generated_pool.build do + add_file("ruby_generated_pkg_explicit.proto", :syntax => :proto3) do + add_message "one.two.a_three.Four" do + optional :a_string, :string, 1 + end + end +end + +module A + module B + module C + Four = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("one.two.a_three.Four").msgclass + end + end +end diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/ruby/ruby_generated_pkg_implicit.proto b/NorthstarDedicatedTest/include/protobuf/compiler/ruby/ruby_generated_pkg_implicit.proto new file mode 100644 index 00000000..544db64d --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/ruby/ruby_generated_pkg_implicit.proto @@ -0,0 +1,7 @@ +syntax = "proto3"; + +package one.two.a_three; + +message Four { + string a_string = 1; +} diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/ruby/ruby_generated_pkg_implicit_pb.rb b/NorthstarDedicatedTest/include/protobuf/compiler/ruby/ruby_generated_pkg_implicit_pb.rb new file mode 100644 index 00000000..1ac0ef7a --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/ruby/ruby_generated_pkg_implicit_pb.rb @@ -0,0 +1,20 @@ +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: ruby_generated_pkg_implicit.proto + +require 'google/protobuf' + +Google::Protobuf::DescriptorPool.generated_pool.build do + add_file("ruby_generated_pkg_implicit.proto", :syntax => :proto3) do + add_message "one.two.a_three.Four" do + optional :a_string, :string, 1 + end + end +end + +module One + module Two + module AThree + Four = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("one.two.a_three.Four").msgclass + end + end +end diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/ruby/ruby_generator.cc b/NorthstarDedicatedTest/include/protobuf/compiler/ruby/ruby_generator.cc new file mode 100644 index 00000000..7d6d5032 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/ruby/ruby_generator.cc @@ -0,0 +1,575 @@ +// 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 <iomanip> +#include <sstream> + +#include <compiler/code_generator.h> +#include <compiler/plugin.h> +#include <descriptor.h> +#include <descriptor.pb.h> +#include <io/printer.h> +#include <io/zero_copy_stream.h> + +#include <compiler/ruby/ruby_generator.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace ruby { + +// Forward decls. +template <class numeric_type> +std::string NumberToString(numeric_type value); +std::string GetRequireName(const std::string& proto_file); +std::string LabelForField(FieldDescriptor* field); +std::string TypeName(FieldDescriptor* field); +bool GenerateMessage(const Descriptor* message, io::Printer* printer, + std::string* error); +void GenerateEnum(const EnumDescriptor* en, io::Printer* printer); +void GenerateMessageAssignment(const std::string& prefix, + const Descriptor* message, io::Printer* printer); +void GenerateEnumAssignment(const std::string& prefix, const EnumDescriptor* en, + io::Printer* printer); +std::string DefaultValueForField(const FieldDescriptor* field); + +template<class numeric_type> +std::string NumberToString(numeric_type value) { + std::ostringstream os; + os << value; + return os.str(); +} + +std::string GetRequireName(const std::string& proto_file) { + int lastindex = proto_file.find_last_of("."); + return proto_file.substr(0, lastindex) + "_pb"; +} + +std::string GetOutputFilename(const std::string& proto_file) { + return GetRequireName(proto_file) + ".rb"; +} + +std::string LabelForField(const FieldDescriptor* field) { + if (field->has_optional_keyword() && + field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3) { + return "proto3_optional"; + } + switch (field->label()) { + case FieldDescriptor::LABEL_OPTIONAL: return "optional"; + case FieldDescriptor::LABEL_REQUIRED: return "required"; + case FieldDescriptor::LABEL_REPEATED: return "repeated"; + default: assert(false); return ""; + } +} + +std::string TypeName(const FieldDescriptor* field) { + switch (field->type()) { + case FieldDescriptor::TYPE_INT32: return "int32"; + case FieldDescriptor::TYPE_INT64: return "int64"; + case FieldDescriptor::TYPE_UINT32: return "uint32"; + case FieldDescriptor::TYPE_UINT64: return "uint64"; + case FieldDescriptor::TYPE_SINT32: return "sint32"; + case FieldDescriptor::TYPE_SINT64: return "sint64"; + case FieldDescriptor::TYPE_FIXED32: return "fixed32"; + case FieldDescriptor::TYPE_FIXED64: return "fixed64"; + case FieldDescriptor::TYPE_SFIXED32: return "sfixed32"; + case FieldDescriptor::TYPE_SFIXED64: return "sfixed64"; + case FieldDescriptor::TYPE_DOUBLE: return "double"; + case FieldDescriptor::TYPE_FLOAT: return "float"; + case FieldDescriptor::TYPE_BOOL: return "bool"; + case FieldDescriptor::TYPE_ENUM: return "enum"; + case FieldDescriptor::TYPE_STRING: return "string"; + case FieldDescriptor::TYPE_BYTES: return "bytes"; + case FieldDescriptor::TYPE_MESSAGE: return "message"; + case FieldDescriptor::TYPE_GROUP: return "group"; + default: assert(false); return ""; + } +} + +std::string StringifySyntax(FileDescriptor::Syntax syntax) { + switch (syntax) { + case FileDescriptor::SYNTAX_PROTO2: + return "proto2"; + case FileDescriptor::SYNTAX_PROTO3: + return "proto3"; + case FileDescriptor::SYNTAX_UNKNOWN: + default: + GOOGLE_LOG(FATAL) << "Unsupported syntax; this generator only supports " + "proto2 and proto3 syntax."; + return ""; + } +} + +std::string DefaultValueForField(const FieldDescriptor* field) { + switch(field->cpp_type()) { + case FieldDescriptor::CPPTYPE_INT32: + return NumberToString(field->default_value_int32()); + case FieldDescriptor::CPPTYPE_INT64: + return NumberToString(field->default_value_int64()); + case FieldDescriptor::CPPTYPE_UINT32: + return NumberToString(field->default_value_uint32()); + case FieldDescriptor::CPPTYPE_UINT64: + return NumberToString(field->default_value_uint64()); + case FieldDescriptor::CPPTYPE_FLOAT: + return NumberToString(field->default_value_float()); + case FieldDescriptor::CPPTYPE_DOUBLE: + return NumberToString(field->default_value_double()); + case FieldDescriptor::CPPTYPE_BOOL: + return field->default_value_bool() ? "true" : "false"; + case FieldDescriptor::CPPTYPE_ENUM: + return NumberToString(field->default_value_enum()->number()); + case FieldDescriptor::CPPTYPE_STRING: { + std::ostringstream os; + std::string default_str = field->default_value_string(); + + if (field->type() == FieldDescriptor::TYPE_STRING) { + os << "\"" << default_str << "\""; + } else if (field->type() == FieldDescriptor::TYPE_BYTES) { + os << "\""; + + os.fill('0'); + for (int i = 0; i < default_str.length(); ++i) { + // Write the hex form of each byte. + os << "\\x" << std::hex << std::setw(2) + << ((uint16)((unsigned char)default_str.at(i))); + } + os << "\".force_encoding(\"ASCII-8BIT\")"; + } + + return os.str(); + } + default: assert(false); return ""; + } +} + +void GenerateField(const FieldDescriptor* field, io::Printer* printer) { + if (field->is_map()) { + const FieldDescriptor* key_field = + field->message_type()->FindFieldByNumber(1); + const FieldDescriptor* value_field = + field->message_type()->FindFieldByNumber(2); + + printer->Print( + "map :$name$, :$key_type$, :$value_type$, $number$", + "name", field->name(), + "key_type", TypeName(key_field), + "value_type", TypeName(value_field), + "number", NumberToString(field->number())); + + if (value_field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + printer->Print( + ", \"$subtype$\"\n", + "subtype", value_field->message_type()->full_name()); + } else if (value_field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) { + printer->Print( + ", \"$subtype$\"\n", + "subtype", value_field->enum_type()->full_name()); + } else { + printer->Print("\n"); + } + } else { + + printer->Print( + "$label$ :$name$, ", + "label", LabelForField(field), + "name", field->name()); + printer->Print( + ":$type$, $number$", + "type", TypeName(field), + "number", NumberToString(field->number())); + + if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + printer->Print( + ", \"$subtype$\"", + "subtype", field->message_type()->full_name()); + } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) { + printer->Print( + ", \"$subtype$\"", + "subtype", field->enum_type()->full_name()); + } + + if (field->has_default_value()) { + printer->Print(", default: $default$", "default", + DefaultValueForField(field)); + } + + if (field->has_json_name()) { + printer->Print(", json_name: \"$json_name$\"", "json_name", + field->json_name()); + } + + printer->Print("\n"); + } +} + +void GenerateOneof(const OneofDescriptor* oneof, io::Printer* printer) { + printer->Print( + "oneof :$name$ do\n", + "name", oneof->name()); + printer->Indent(); + + for (int i = 0; i < oneof->field_count(); i++) { + const FieldDescriptor* field = oneof->field(i); + GenerateField(field, printer); + } + + printer->Outdent(); + printer->Print("end\n"); +} + +bool GenerateMessage(const Descriptor* message, io::Printer* printer, + std::string* error) { + if (message->extension_range_count() > 0 || message->extension_count() > 0) { + GOOGLE_LOG(WARNING) << "Extensions are not yet supported for proto2 .proto files."; + } + + // Don't generate MapEntry messages -- we use the Ruby extension's native + // support for map fields instead. + if (message->options().map_entry()) { + return true; + } + + printer->Print( + "add_message \"$name$\" do\n", + "name", message->full_name()); + printer->Indent(); + + for (int i = 0; i < message->field_count(); i++) { + const FieldDescriptor* field = message->field(i); + if (!field->real_containing_oneof()) { + GenerateField(field, printer); + } + } + + for (int i = 0; i < message->real_oneof_decl_count(); i++) { + const OneofDescriptor* oneof = message->oneof_decl(i); + GenerateOneof(oneof, printer); + } + + printer->Outdent(); + printer->Print("end\n"); + + for (int i = 0; i < message->nested_type_count(); i++) { + if (!GenerateMessage(message->nested_type(i), printer, error)) { + return false; + } + } + for (int i = 0; i < message->enum_type_count(); i++) { + GenerateEnum(message->enum_type(i), printer); + } + + return true; +} + +void GenerateEnum(const EnumDescriptor* en, io::Printer* printer) { + printer->Print( + "add_enum \"$name$\" do\n", + "name", en->full_name()); + printer->Indent(); + + for (int i = 0; i < en->value_count(); i++) { + const EnumValueDescriptor* value = en->value(i); + printer->Print( + "value :$name$, $number$\n", + "name", value->name(), + "number", NumberToString(value->number())); + } + + printer->Outdent(); + printer->Print( + "end\n"); +} + +// Locale-agnostic utility functions. +bool IsLower(char ch) { return ch >= 'a' && ch <= 'z'; } + +bool IsUpper(char ch) { return ch >= 'A' && ch <= 'Z'; } + +bool IsAlpha(char ch) { return IsLower(ch) || IsUpper(ch); } + +char UpperChar(char ch) { return IsLower(ch) ? (ch - 'a' + 'A') : ch; } + + +// Package names in protobuf are snake_case by convention, but Ruby module +// names must be PascalCased. +// +// foo_bar_baz -> FooBarBaz +std::string PackageToModule(const std::string& name) { + bool next_upper = true; + std::string result; + result.reserve(name.size()); + + for (int i = 0; i < name.size(); i++) { + if (name[i] == '_') { + next_upper = true; + } else { + if (next_upper) { + result.push_back(UpperChar(name[i])); + } else { + result.push_back(name[i]); + } + next_upper = false; + } + } + + return result; +} + +// Class and enum names in protobuf should be PascalCased by convention, but +// since there is nothing enforcing this we need to ensure that they are valid +// Ruby constants. That mainly means making sure that the first character is +// an upper-case letter. +std::string RubifyConstant(const std::string& name) { + std::string ret = name; + if (!ret.empty()) { + if (IsLower(ret[0])) { + // If it starts with a lowercase letter, capitalize it. + ret[0] = UpperChar(ret[0]); + } else if (!IsAlpha(ret[0])) { + // Otherwise (e.g. if it begins with an underscore), we need to come up + // with some prefix that starts with a capital letter. We could be smarter + // here, e.g. try to strip leading underscores, but this may cause other + // problems if the user really intended the name. So let's just prepend a + // well-known suffix. + ret = "PB_" + ret; + } + } + + return ret; +} + +void GenerateMessageAssignment(const std::string& prefix, + const Descriptor* message, + io::Printer* printer) { + // Don't generate MapEntry messages -- we use the Ruby extension's native + // support for map fields instead. + if (message->options().map_entry()) { + return; + } + + printer->Print( + "$prefix$$name$ = ", + "prefix", prefix, + "name", RubifyConstant(message->name())); + printer->Print( + "::Google::Protobuf::DescriptorPool.generated_pool." + "lookup(\"$full_name$\").msgclass\n", + "full_name", message->full_name()); + + std::string nested_prefix = prefix + RubifyConstant(message->name()) + "::"; + for (int i = 0; i < message->nested_type_count(); i++) { + GenerateMessageAssignment(nested_prefix, message->nested_type(i), printer); + } + for (int i = 0; i < message->enum_type_count(); i++) { + GenerateEnumAssignment(nested_prefix, message->enum_type(i), printer); + } +} + +void GenerateEnumAssignment(const std::string& prefix, const EnumDescriptor* en, + io::Printer* printer) { + printer->Print( + "$prefix$$name$ = ", + "prefix", prefix, + "name", RubifyConstant(en->name())); + printer->Print( + "::Google::Protobuf::DescriptorPool.generated_pool." + "lookup(\"$full_name$\").enummodule\n", + "full_name", en->full_name()); +} + +int GeneratePackageModules(const FileDescriptor* file, io::Printer* printer) { + int levels = 0; + bool need_change_to_module = true; + std::string package_name; + + // Determine the name to use in either format: + // proto package: one.two.three + // option ruby_package: One::Two::Three + if (file->options().has_ruby_package()) { + package_name = file->options().ruby_package(); + + // If :: is in the package use the Ruby formatted name as-is + // -> A::B::C + // otherwise, use the dot separator + // -> A.B.C + if (package_name.find("::") != std::string::npos) { + need_change_to_module = false; + } else { + GOOGLE_LOG(WARNING) << "ruby_package option should be in the form of:" + << " 'A::B::C' and not 'A.B.C'"; + } + } else { + package_name = file->package(); + } + + // Use the appropriate delimiter + std::string delimiter = need_change_to_module ? "." : "::"; + int delimiter_size = need_change_to_module ? 1 : 2; + + // Extract each module name and indent + while (!package_name.empty()) { + size_t dot_index = package_name.find(delimiter); + std::string component; + if (dot_index == std::string::npos) { + component = package_name; + package_name = ""; + } else { + component = package_name.substr(0, dot_index); + package_name = package_name.substr(dot_index + delimiter_size); + } + if (need_change_to_module) { + component = PackageToModule(component); + } + printer->Print( + "module $name$\n", + "name", component); + printer->Indent(); + levels++; + } + return levels; +} + +void EndPackageModules(int levels, io::Printer* printer) { + while (levels > 0) { + levels--; + printer->Outdent(); + printer->Print( + "end\n"); + } +} + +bool GenerateDslDescriptor(const FileDescriptor* file, io::Printer* printer, + std::string* error) { + printer->Print("Google::Protobuf::DescriptorPool.generated_pool.build do\n"); + printer->Indent(); + printer->Print("add_file(\"$filename$\", :syntax => :$syntax$) do\n", + "filename", file->name(), "syntax", + StringifySyntax(file->syntax())); + printer->Indent(); + for (int i = 0; i < file->message_type_count(); i++) { + if (!GenerateMessage(file->message_type(i), printer, error)) { + return false; + } + } + for (int i = 0; i < file->enum_type_count(); i++) { + GenerateEnum(file->enum_type(i), printer); + } + printer->Outdent(); + printer->Print("end\n"); + printer->Outdent(); + printer->Print( + "end\n\n"); + return true; +} + +bool GenerateBinaryDescriptor(const FileDescriptor* file, io::Printer* printer, + std::string* error) { + printer->Print( + R"(descriptor_data = File.binread(__FILE__).split("\n__END__\n", 2)[1])"); + printer->Print( + "\nGoogle::Protobuf::DescriptorPool.generated_pool.add_serialized_file(" + "descriptor_data)\n\n"); + return true; +} + +bool GenerateFile(const FileDescriptor* file, io::Printer* printer, + std::string* error) { + printer->Print( + "# Generated by the protocol buffer compiler. DO NOT EDIT!\n" + "# source: $filename$\n" + "\n", + "filename", file->name()); + + printer->Print("require 'google/protobuf'\n\n"); + + if (file->dependency_count() != 0) { + for (int i = 0; i < file->dependency_count(); i++) { + printer->Print("require '$name$'\n", "name", GetRequireName(file->dependency(i)->name())); + } + printer->Print("\n"); + } + + // TODO: Remove this when ruby supports extensions for proto2 syntax. + if (file->syntax() == FileDescriptor::SYNTAX_PROTO2 && + file->extension_count() > 0) { + GOOGLE_LOG(WARNING) << "Extensions are not yet supported for proto2 .proto files."; + } + + bool use_raw_descriptor = file->name() == "google/protobuf/descriptor.proto"; + + if (use_raw_descriptor) { + GenerateBinaryDescriptor(file, printer, error); + } else { + GenerateDslDescriptor(file, printer, error); + } + + int levels = GeneratePackageModules(file, printer); + for (int i = 0; i < file->message_type_count(); i++) { + GenerateMessageAssignment("", file->message_type(i), printer); + } + for (int i = 0; i < file->enum_type_count(); i++) { + GenerateEnumAssignment("", file->enum_type(i), printer); + } + EndPackageModules(levels, printer); + + if (use_raw_descriptor) { + printer->Print("\n__END__\n"); + FileDescriptorProto file_proto; + file->CopyTo(&file_proto); + std::string file_data; + file_proto.SerializeToString(&file_data); + printer->Print("$raw_descriptor$", "raw_descriptor", file_data); + } + return true; +} + +bool Generator::Generate( + const FileDescriptor* file, + const std::string& parameter, + GeneratorContext* generator_context, + std::string* error) const { + + if (file->syntax() != FileDescriptor::SYNTAX_PROTO3 && + file->syntax() != FileDescriptor::SYNTAX_PROTO2) { + *error = "Invalid or unsupported proto syntax"; + return false; + } + + std::unique_ptr<io::ZeroCopyOutputStream> output( + generator_context->Open(GetOutputFilename(file->name()))); + io::Printer printer(output.get(), '$'); + + return GenerateFile(file, &printer, error); +} + +} // namespace ruby +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/ruby/ruby_generator.h b/NorthstarDedicatedTest/include/protobuf/compiler/ruby/ruby_generator.h new file mode 100644 index 00000000..e8e6e566 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/ruby/ruby_generator.h @@ -0,0 +1,67 @@ +// 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. + +// Generates Ruby code for a given .proto file. + +#ifndef GOOGLE_PROTOBUF_COMPILER_RUBY_GENERATOR_H__ +#define GOOGLE_PROTOBUF_COMPILER_RUBY_GENERATOR_H__ + +#include <string> + +#include <compiler/code_generator.h> + +#include <port_def.inc> + +namespace google { +namespace protobuf { +namespace compiler { +namespace ruby { + +// CodeGenerator implementation for generated Ruby protocol buffer classes. +// If you create your own protocol compiler binary and you want it to support +// Ruby output, you can do so by registering an instance of this +// CodeGenerator with the CommandLineInterface in your main() function. +class PROTOC_EXPORT Generator : public CodeGenerator { + bool Generate(const FileDescriptor* file, const std::string& parameter, + GeneratorContext* generator_context, + std::string* error) const override; + uint64_t GetSupportedFeatures() const override { + return FEATURE_PROTO3_OPTIONAL; + } +}; + +} // namespace ruby +} // namespace compiler +} // namespace protobuf +} // namespace google + +#include <port_undef.inc> + +#endif // GOOGLE_PROTOBUF_COMPILER_RUBY_GENERATOR_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/ruby/ruby_generator_unittest.cc b/NorthstarDedicatedTest/include/protobuf/compiler/ruby/ruby_generator_unittest.cc new file mode 100644 index 00000000..cc72c1e6 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/ruby/ruby_generator_unittest.cc @@ -0,0 +1,145 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2014 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 <memory> +#include <list> + +#include <compiler/ruby/ruby_generator.h> +#include <compiler/command_line_interface.h> +#include <io/zero_copy_stream.h> +#include <io/printer.h> + +#include <testing/googletest.h> +#include <gtest/gtest.h> +#include <testing/file.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace ruby { +namespace { + +std::string FindRubyTestDir() { + return TestSourceDir() + "/google/protobuf/compiler/ruby"; +} + +// This test is a simple golden-file test over the output of the Ruby code +// generator. When we make changes to the Ruby extension and alter the Ruby code +// generator to use those changes, we should (i) manually test the output of the +// code generator with the extension, and (ii) update the golden output above. +// Some day, we may integrate build systems between protoc and the language +// extensions to the point where we can do this test in a more automated way. + +void RubyTest(string proto_file, string import_proto_file = "") { + std::string ruby_tests = FindRubyTestDir(); + + google::protobuf::compiler::CommandLineInterface cli; + cli.SetInputsAreProtoPathRelative(true); + + ruby::Generator ruby_generator; + cli.RegisterGenerator("--ruby_out", &ruby_generator, ""); + + // Copy generated_code.proto to the temporary test directory. + std::string test_input; + GOOGLE_CHECK_OK(File::GetContents( + ruby_tests + proto_file + ".proto", + &test_input, + true)); + GOOGLE_CHECK_OK(File::SetContents( + TestTempDir() + proto_file + ".proto", + test_input, + true)); + + // Copy generated_code_import.proto to the temporary test directory. + std::string test_import; + if (!import_proto_file.empty()) { + GOOGLE_CHECK_OK(File::GetContents( + ruby_tests + import_proto_file + ".proto", + &test_import, + true)); + GOOGLE_CHECK_OK(File::SetContents( + TestTempDir() + import_proto_file + ".proto", + test_import, + true)); + } + + // Invoke the proto compiler (we will be inside TestTempDir() at this point). + std::string ruby_out = "--ruby_out=" + TestTempDir(); + std::string proto_path = "--proto_path=" + TestTempDir(); + + std::string proto_target = TestTempDir() + proto_file + ".proto"; + const char* argv[] = { + "protoc", + ruby_out.c_str(), + proto_path.c_str(), + proto_target.c_str(), + }; + + EXPECT_EQ(0, cli.Run(4, argv)); + + // Load the generated output and compare to the expected result. + std::string output; + GOOGLE_CHECK_OK(File::GetContentsAsText( + TestTempDir() + proto_file + "_pb.rb", + &output, + true)); + std::string expected_output; + GOOGLE_CHECK_OK(File::GetContentsAsText( + ruby_tests + proto_file + "_pb.rb", + &expected_output, + true)); + EXPECT_EQ(expected_output, output); +} + +TEST(RubyGeneratorTest, Proto3GeneratorTest) { + RubyTest("/ruby_generated_code", "/ruby_generated_code_proto2_import"); +} + +TEST(RubyGeneratorTest, Proto2GeneratorTest) { + RubyTest("/ruby_generated_code_proto2", "/ruby_generated_code_proto2_import"); +} + +TEST(RubyGeneratorTest, Proto3ImplicitPackageTest) { + RubyTest("/ruby_generated_pkg_implicit"); +} + +TEST(RubyGeneratorTest, Proto3ExplictPackageTest) { + RubyTest("/ruby_generated_pkg_explicit"); +} + +TEST(RubyGeneratorTest, Proto3ExplictLegacyPackageTest) { + RubyTest("/ruby_generated_pkg_explicit_legacy"); +} + +} // namespace +} // namespace ruby +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/scc.h b/NorthstarDedicatedTest/include/protobuf/compiler/scc.h new file mode 100644 index 00000000..93088bf9 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/scc.h @@ -0,0 +1,164 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_SCC_H__ +#define GOOGLE_PROTOBUF_COMPILER_SCC_H__ + +#include <map> + +#include <stubs/logging.h> +#include <stubs/common.h> +#include <descriptor.h> + +#include <port_def.inc> + +namespace google { +namespace protobuf { +namespace compiler { + +// Description of each strongly connected component. Note that the order +// of both the descriptors in this SCC and the order of children is +// deterministic. +struct SCC { + std::vector<const Descriptor*> descriptors; + std::vector<const SCC*> children; + + const Descriptor* GetRepresentative() const { return descriptors[0]; } + + // All messages must necessarily be in the same file. + const FileDescriptor* GetFile() const { return descriptors[0]->file(); } +}; + +// This class is used for analyzing the SCC for each message, to ensure linear +// instead of quadratic performance, if we do this per message we would get +// O(V*(V+E)). +template <class DepsGenerator> +class PROTOC_EXPORT SCCAnalyzer { + public: + explicit SCCAnalyzer() : index_(0) {} + + const SCC* GetSCC(const Descriptor* descriptor) { + if (cache_.count(descriptor)) return cache_[descriptor].scc; + return DFS(descriptor).scc; + } + + private: + struct NodeData { + const SCC* scc; // if null it means its still on the stack + int index; + int lowlink; + }; + + std::map<const Descriptor*, NodeData> cache_; + std::vector<const Descriptor*> stack_; + int index_; + std::vector<std::unique_ptr<SCC>> garbage_bin_; + + SCC* CreateSCC() { + garbage_bin_.emplace_back(new SCC()); + return garbage_bin_.back().get(); + } + + // Tarjan's Strongly Connected Components algo + NodeData DFS(const Descriptor* descriptor) { + // Must not have visited already. + GOOGLE_DCHECK_EQ(cache_.count(descriptor), 0); + + // Mark visited by inserting in map. + NodeData& result = cache_[descriptor]; + // Initialize data structures. + result.index = result.lowlink = index_++; + stack_.push_back(descriptor); + + // Recurse the fields / nodes in graph + for (auto dep : DepsGenerator()(descriptor)) { + GOOGLE_CHECK(dep); + if (cache_.count(dep) == 0) { + // unexplored node + NodeData child_data = DFS(dep); + result.lowlink = std::min(result.lowlink, child_data.lowlink); + } else { + NodeData child_data = cache_[dep]; + if (child_data.scc == nullptr) { + // Still in the stack_ so we found a back edge + result.lowlink = std::min(result.lowlink, child_data.index); + } + } + } + if (result.index == result.lowlink) { + // This is the root of a strongly connected component + SCC* scc = CreateSCC(); + while (true) { + const Descriptor* scc_desc = stack_.back(); + scc->descriptors.push_back(scc_desc); + // Remove from stack + stack_.pop_back(); + cache_[scc_desc].scc = scc; + + if (scc_desc == descriptor) break; + } + + // The order of descriptors is random and depends how this SCC was + // discovered. In-order to ensure maximum stability we sort it by name. + std::sort(scc->descriptors.begin(), scc->descriptors.end(), + [](const Descriptor* a, const Descriptor* b) { + return a->full_name() < b->full_name(); + }); + AddChildren(scc); + } + return result; + } + + // Add the SCC's that are children of this SCC to its children. + void AddChildren(SCC* scc) { + std::set<const SCC*> seen; + for (auto descriptor : scc->descriptors) { + for (auto child_msg : DepsGenerator()(descriptor)) { + GOOGLE_CHECK(child_msg); + const SCC* child = GetSCC(child_msg); + if (child == scc) continue; + if (seen.insert(child).second) { + scc->children.push_back(child); + } + } + } + } + + // This is necessary for compiler bug in msvc2015. + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(SCCAnalyzer); +}; + +} // namespace compiler +} // namespace protobuf +} // namespace google + +#include <port_undef.inc> + +#endif // GOOGLE_PROTOBUF_COMPILER_SCC_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/subprocess.cc b/NorthstarDedicatedTest/include/protobuf/compiler/subprocess.cc new file mode 100644 index 00000000..84e432cc --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/subprocess.cc @@ -0,0 +1,475 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) + +#include <compiler/subprocess.h> + +#include <algorithm> +#include <cstring> +#include <iostream> + +#ifndef _WIN32 +#include <errno.h> +#include <signal.h> +#include <sys/select.h> +#include <sys/wait.h> +#endif + +#include <stubs/logging.h> +#include <stubs/common.h> +#include <message.h> +#include <stubs/substitute.h> + +namespace google { +namespace protobuf { +namespace compiler { + +namespace { +char* portable_strdup(const char* s) { + char* ns = (char*)malloc(strlen(s) + 1); + if (ns != NULL) { + strcpy(ns, s); + } + return ns; +} +} // namespace + +#ifdef _WIN32 + +static void CloseHandleOrDie(HANDLE handle) { + if (!CloseHandle(handle)) { + GOOGLE_LOG(FATAL) << "CloseHandle: " + << Subprocess::Win32ErrorMessage(GetLastError()); + } +} + +Subprocess::Subprocess() + : process_start_error_(ERROR_SUCCESS), + child_handle_(NULL), + child_stdin_(NULL), + child_stdout_(NULL) {} + +Subprocess::~Subprocess() { + if (child_stdin_ != NULL) { + CloseHandleOrDie(child_stdin_); + } + if (child_stdout_ != NULL) { + CloseHandleOrDie(child_stdout_); + } +} + +void Subprocess::Start(const std::string& program, SearchMode search_mode) { + // Create the pipes. + HANDLE stdin_pipe_read; + HANDLE stdin_pipe_write; + HANDLE stdout_pipe_read; + HANDLE stdout_pipe_write; + + if (!CreatePipe(&stdin_pipe_read, &stdin_pipe_write, NULL, 0)) { + GOOGLE_LOG(FATAL) << "CreatePipe: " << Win32ErrorMessage(GetLastError()); + } + if (!CreatePipe(&stdout_pipe_read, &stdout_pipe_write, NULL, 0)) { + GOOGLE_LOG(FATAL) << "CreatePipe: " << Win32ErrorMessage(GetLastError()); + } + + // Make child side of the pipes inheritable. + if (!SetHandleInformation(stdin_pipe_read, HANDLE_FLAG_INHERIT, + HANDLE_FLAG_INHERIT)) { + GOOGLE_LOG(FATAL) << "SetHandleInformation: " + << Win32ErrorMessage(GetLastError()); + } + if (!SetHandleInformation(stdout_pipe_write, HANDLE_FLAG_INHERIT, + HANDLE_FLAG_INHERIT)) { + GOOGLE_LOG(FATAL) << "SetHandleInformation: " + << Win32ErrorMessage(GetLastError()); + } + + // Setup STARTUPINFO to redirect handles. + STARTUPINFOA startup_info; + ZeroMemory(&startup_info, sizeof(startup_info)); + startup_info.cb = sizeof(startup_info); + startup_info.dwFlags = STARTF_USESTDHANDLES; + startup_info.hStdInput = stdin_pipe_read; + startup_info.hStdOutput = stdout_pipe_write; + startup_info.hStdError = GetStdHandle(STD_ERROR_HANDLE); + + if (startup_info.hStdError == INVALID_HANDLE_VALUE) { + GOOGLE_LOG(FATAL) << "GetStdHandle: " << Win32ErrorMessage(GetLastError()); + } + + // Invoking cmd.exe allows for '.bat' files from the path as well as '.exe'. + // Using a malloc'ed string because CreateProcess() can mutate its second + // parameter. + char* command_line = + portable_strdup(("cmd.exe /c \"" + program + "\"").c_str()); + + // Create the process. + PROCESS_INFORMATION process_info; + + if (CreateProcessA((search_mode == SEARCH_PATH) ? NULL : program.c_str(), + (search_mode == SEARCH_PATH) ? command_line : NULL, + NULL, // process security attributes + NULL, // thread security attributes + TRUE, // inherit handles? + 0, // obscure creation flags + NULL, // environment (inherit from parent) + NULL, // current directory (inherit from parent) + &startup_info, &process_info)) { + child_handle_ = process_info.hProcess; + CloseHandleOrDie(process_info.hThread); + child_stdin_ = stdin_pipe_write; + child_stdout_ = stdout_pipe_read; + } else { + process_start_error_ = GetLastError(); + CloseHandleOrDie(stdin_pipe_write); + CloseHandleOrDie(stdout_pipe_read); + } + + CloseHandleOrDie(stdin_pipe_read); + CloseHandleOrDie(stdout_pipe_write); + free(command_line); +} + +bool Subprocess::Communicate(const Message& input, Message* output, + std::string* error) { + if (process_start_error_ != ERROR_SUCCESS) { + *error = Win32ErrorMessage(process_start_error_); + return false; + } + + GOOGLE_CHECK(child_handle_ != NULL) << "Must call Start() first."; + + std::string input_data = input.SerializeAsString(); + std::string output_data; + + int input_pos = 0; + + while (child_stdout_ != NULL) { + HANDLE handles[2]; + int handle_count = 0; + + if (child_stdin_ != NULL) { + handles[handle_count++] = child_stdin_; + } + if (child_stdout_ != NULL) { + handles[handle_count++] = child_stdout_; + } + + DWORD wait_result = + WaitForMultipleObjects(handle_count, handles, FALSE, INFINITE); + + HANDLE signaled_handle = NULL; + if (wait_result >= WAIT_OBJECT_0 && + wait_result < WAIT_OBJECT_0 + handle_count) { + signaled_handle = handles[wait_result - WAIT_OBJECT_0]; + } else if (wait_result == WAIT_FAILED) { + GOOGLE_LOG(FATAL) << "WaitForMultipleObjects: " + << Win32ErrorMessage(GetLastError()); + } else { + GOOGLE_LOG(FATAL) << "WaitForMultipleObjects: Unexpected return code: " + << wait_result; + } + + if (signaled_handle == child_stdin_) { + DWORD n; + if (!WriteFile(child_stdin_, input_data.data() + input_pos, + input_data.size() - input_pos, &n, NULL)) { + // Child closed pipe. Presumably it will report an error later. + // Pretend we're done for now. + input_pos = input_data.size(); + } else { + input_pos += n; + } + + if (input_pos == input_data.size()) { + // We're done writing. Close. + CloseHandleOrDie(child_stdin_); + child_stdin_ = NULL; + } + } else if (signaled_handle == child_stdout_) { + char buffer[4096]; + DWORD n; + + if (!ReadFile(child_stdout_, buffer, sizeof(buffer), &n, NULL)) { + // We're done reading. Close. + CloseHandleOrDie(child_stdout_); + child_stdout_ = NULL; + } else { + output_data.append(buffer, n); + } + } + } + + if (child_stdin_ != NULL) { + // Child did not finish reading input before it closed the output. + // Presumably it exited with an error. + CloseHandleOrDie(child_stdin_); + child_stdin_ = NULL; + } + + DWORD wait_result = WaitForSingleObject(child_handle_, INFINITE); + + if (wait_result == WAIT_FAILED) { + GOOGLE_LOG(FATAL) << "WaitForSingleObject: " + << Win32ErrorMessage(GetLastError()); + } else if (wait_result != WAIT_OBJECT_0) { + GOOGLE_LOG(FATAL) << "WaitForSingleObject: Unexpected return code: " + << wait_result; + } + + DWORD exit_code; + if (!GetExitCodeProcess(child_handle_, &exit_code)) { + GOOGLE_LOG(FATAL) << "GetExitCodeProcess: " + << Win32ErrorMessage(GetLastError()); + } + + CloseHandleOrDie(child_handle_); + child_handle_ = NULL; + + if (exit_code != 0) { + *error = strings::Substitute("Plugin failed with status code $0.", exit_code); + return false; + } + + if (!output->ParseFromString(output_data)) { + *error = "Plugin output is unparseable: " + CEscape(output_data); + return false; + } + + return true; +} + +std::string Subprocess::Win32ErrorMessage(DWORD error_code) { + char* message; + + // WTF? + FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, error_code, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), + (LPSTR)&message, // NOT A BUG! + 0, NULL); + + std::string result = message; + LocalFree(message); + return result; +} + +// =================================================================== + +#else // _WIN32 + +Subprocess::Subprocess() + : child_pid_(-1), child_stdin_(-1), child_stdout_(-1) {} + +Subprocess::~Subprocess() { + if (child_stdin_ != -1) { + close(child_stdin_); + } + if (child_stdout_ != -1) { + close(child_stdout_); + } +} + +void Subprocess::Start(const std::string& program, SearchMode search_mode) { + // Note that we assume that there are no other threads, thus we don't have to + // do crazy stuff like using socket pairs or avoiding libc locks. + + // [0] is read end, [1] is write end. + int stdin_pipe[2]; + int stdout_pipe[2]; + + GOOGLE_CHECK(pipe(stdin_pipe) != -1); + GOOGLE_CHECK(pipe(stdout_pipe) != -1); + + char* argv[2] = {portable_strdup(program.c_str()), NULL}; + + child_pid_ = fork(); + if (child_pid_ == -1) { + GOOGLE_LOG(FATAL) << "fork: " << strerror(errno); + } else if (child_pid_ == 0) { + // We are the child. + dup2(stdin_pipe[0], STDIN_FILENO); + dup2(stdout_pipe[1], STDOUT_FILENO); + + close(stdin_pipe[0]); + close(stdin_pipe[1]); + close(stdout_pipe[0]); + close(stdout_pipe[1]); + + switch (search_mode) { + case SEARCH_PATH: + execvp(argv[0], argv); + break; + case EXACT_NAME: + execv(argv[0], argv); + break; + } + + // Write directly to STDERR_FILENO to avoid stdio code paths that may do + // stuff that is unsafe here. + int ignored; + ignored = write(STDERR_FILENO, argv[0], strlen(argv[0])); + const char* message = + ": program not found or is not executable\n" + "Please specify a program using absolute path or make sure " + "the program is available in your PATH system variable\n"; + ignored = write(STDERR_FILENO, message, strlen(message)); + (void)ignored; + + // Must use _exit() rather than exit() to avoid flushing output buffers + // that will also be flushed by the parent. + _exit(1); + } else { + free(argv[0]); + + close(stdin_pipe[0]); + close(stdout_pipe[1]); + + child_stdin_ = stdin_pipe[1]; + child_stdout_ = stdout_pipe[0]; + } +} + +bool Subprocess::Communicate(const Message& input, Message* output, + std::string* error) { + GOOGLE_CHECK_NE(child_stdin_, -1) << "Must call Start() first."; + + // The "sighandler_t" typedef is GNU-specific, so define our own. + typedef void SignalHandler(int); + + // Make sure SIGPIPE is disabled so that if the child dies it doesn't kill us. + SignalHandler* old_pipe_handler = signal(SIGPIPE, SIG_IGN); + + std::string input_data = input.SerializeAsString(); + std::string output_data; + + int input_pos = 0; + int max_fd = std::max(child_stdin_, child_stdout_); + + while (child_stdout_ != -1) { + fd_set read_fds; + fd_set write_fds; + FD_ZERO(&read_fds); + FD_ZERO(&write_fds); + if (child_stdout_ != -1) { + FD_SET(child_stdout_, &read_fds); + } + if (child_stdin_ != -1) { + FD_SET(child_stdin_, &write_fds); + } + + if (select(max_fd + 1, &read_fds, &write_fds, NULL, NULL) < 0) { + if (errno == EINTR) { + // Interrupted by signal. Try again. + continue; + } else { + GOOGLE_LOG(FATAL) << "select: " << strerror(errno); + } + } + + if (child_stdin_ != -1 && FD_ISSET(child_stdin_, &write_fds)) { + int n = write(child_stdin_, input_data.data() + input_pos, + input_data.size() - input_pos); + if (n < 0) { + // Child closed pipe. Presumably it will report an error later. + // Pretend we're done for now. + input_pos = input_data.size(); + } else { + input_pos += n; + } + + if (input_pos == input_data.size()) { + // We're done writing. Close. + close(child_stdin_); + child_stdin_ = -1; + } + } + + if (child_stdout_ != -1 && FD_ISSET(child_stdout_, &read_fds)) { + char buffer[4096]; + int n = read(child_stdout_, buffer, sizeof(buffer)); + + if (n > 0) { + output_data.append(buffer, n); + } else { + // We're done reading. Close. + close(child_stdout_); + child_stdout_ = -1; + } + } + } + + if (child_stdin_ != -1) { + // Child did not finish reading input before it closed the output. + // Presumably it exited with an error. + close(child_stdin_); + child_stdin_ = -1; + } + + int status; + while (waitpid(child_pid_, &status, 0) == -1) { + if (errno != EINTR) { + GOOGLE_LOG(FATAL) << "waitpid: " << strerror(errno); + } + } + + // Restore SIGPIPE handling. + signal(SIGPIPE, old_pipe_handler); + + if (WIFEXITED(status)) { + if (WEXITSTATUS(status) != 0) { + int error_code = WEXITSTATUS(status); + *error = + strings::Substitute("Plugin failed with status code $0.", error_code); + return false; + } + } else if (WIFSIGNALED(status)) { + int signal = WTERMSIG(status); + *error = strings::Substitute("Plugin killed by signal $0.", signal); + return false; + } else { + *error = "Neither WEXITSTATUS nor WTERMSIG is true?"; + return false; + } + + if (!output->ParseFromString(output_data)) { + *error = "Plugin output is unparseable: " + CEscape(output_data); + return false; + } + + return true; +} + +#endif // !_WIN32 + +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/subprocess.h b/NorthstarDedicatedTest/include/protobuf/compiler/subprocess.h new file mode 100644 index 00000000..dfad84e1 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/subprocess.h @@ -0,0 +1,113 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) + +#ifndef GOOGLE_PROTOBUF_COMPILER_SUBPROCESS_H__ +#define GOOGLE_PROTOBUF_COMPILER_SUBPROCESS_H__ + +#ifdef _WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN // right... +#endif +#include <windows.h> +#else // _WIN32 +#include <sys/types.h> +#include <unistd.h> +#endif // !_WIN32 +#include <stubs/common.h> + +#include <string> + +#include <port_def.inc> + +namespace google { +namespace protobuf { + +class Message; + +namespace compiler { + +// Utility class for launching sub-processes. +class PROTOC_EXPORT Subprocess { + public: + Subprocess(); + ~Subprocess(); + + enum SearchMode { + SEARCH_PATH, // Use PATH environment variable. + EXACT_NAME // Program is an exact file name; don't use the PATH. + }; + + // Start the subprocess. Currently we don't provide a way to specify + // arguments as protoc plugins don't have any. + void Start(const std::string& program, SearchMode search_mode); + + // Serialize the input message and pipe it to the subprocess's stdin, then + // close the pipe. Meanwhile, read from the subprocess's stdout and parse + // the data into *output. All this is done carefully to avoid deadlocks. + // Returns true if successful. On any sort of error, returns false and sets + // *error to a description of the problem. + bool Communicate(const Message& input, Message* output, std::string* error); + +#ifdef _WIN32 + // Given an error code, returns a human-readable error message. This is + // defined here so that CommandLineInterface can share it. + static std::string Win32ErrorMessage(DWORD error_code); +#endif + + private: +#ifdef _WIN32 + DWORD process_start_error_; + HANDLE child_handle_; + + // The file handles for our end of the child's pipes. We close each and + // set it to NULL when no longer needed. + HANDLE child_stdin_; + HANDLE child_stdout_; + +#else // _WIN32 + pid_t child_pid_; + + // The file descriptors for our end of the child's pipes. We close each and + // set it to -1 when no longer needed. + int child_stdin_; + int child_stdout_; + +#endif // !_WIN32 +}; + +} // namespace compiler +} // namespace protobuf +} // namespace google + +#include <port_undef.inc> + +#endif // GOOGLE_PROTOBUF_COMPILER_SUBPROCESS_H__ diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/test_plugin.cc b/NorthstarDedicatedTest/include/protobuf/compiler/test_plugin.cc new file mode 100644 index 00000000..bca1f068 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/test_plugin.cc @@ -0,0 +1,61 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// +// This is a dummy code generator plugin used by +// command_line_interface_unittest. + +#include <stdlib.h> +#include <string> +#include <compiler/mock_code_generator.h> +#include <compiler/plugin.h> + +namespace google { +namespace protobuf { +namespace compiler { + +int ProtobufMain(int argc, char* argv[]) { + MockCodeGenerator generator("test_plugin"); + return PluginMain(argc, argv, &generator); +} + +} // namespace compiler +} // namespace protobuf +} // namespace google + +int main(int argc, char* argv[]) { +#ifdef _MSC_VER + // Don't print a silly message or stick a modal dialog box in my face, + // please. + _set_abort_behavior(0, ~0); +#endif // !_MSC_VER + return google::protobuf::compiler::ProtobufMain(argc, argv); +} diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/zip_output_unittest.sh b/NorthstarDedicatedTest/include/protobuf/compiler/zip_output_unittest.sh new file mode 100644 index 00000000..f8597912 --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/zip_output_unittest.sh @@ -0,0 +1,100 @@ +#!/bin/sh +# +# Protocol Buffers - Google's data interchange format +# Copyright 2009 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. + +# Author: kenton@google.com (Kenton Varda) +# +# Test protoc's zip output mode. + +fail() { + echo "$@" >&2 + exit 1 +} + +TEST_TMPDIR=. +PROTOC=./protoc +JAR=jar +UNZIP=unzip + +echo ' + syntax = "proto2"; + option java_multiple_files = true; + option java_package = "test.jar"; + option java_outer_classname = "Outer"; + message Foo {} + message Bar {} +' > $TEST_TMPDIR/testzip.proto + +$PROTOC \ + --cpp_out=$TEST_TMPDIR/testzip.zip --python_out=$TEST_TMPDIR/testzip.zip \ + --java_out=$TEST_TMPDIR/testzip.jar -I$TEST_TMPDIR testzip.proto \ + || fail 'protoc failed.' + +echo "Testing output to zip..." +if $UNZIP -h > /dev/null; then + $UNZIP -t $TEST_TMPDIR/testzip.zip > $TEST_TMPDIR/testzip.list \ + || fail 'unzip failed.' + + grep 'testing: testzip\.pb\.cc *OK$' $TEST_TMPDIR/testzip.list > /dev/null \ + || fail 'testzip.pb.cc not found in output zip.' + grep 'testing: testzip\.pb\.h *OK$' $TEST_TMPDIR/testzip.list > /dev/null \ + || fail 'testzip.pb.h not found in output zip.' + grep 'testing: testzip_pb2\.py *OK$' $TEST_TMPDIR/testzip.list > /dev/null \ + || fail 'testzip_pb2.py not found in output zip.' + grep -i 'manifest' $TEST_TMPDIR/testzip.list > /dev/null \ + && fail 'Zip file contained manifest.' +else + echo "Warning: 'unzip' command not available. Skipping test." +fi + +echo "Testing output to jar..." +if $JAR c $TEST_TMPDIR/testzip.proto > /dev/null; then + $JAR tf $TEST_TMPDIR/testzip.jar > $TEST_TMPDIR/testzip.list \ + || fail 'jar failed.' + + # Check that -interface.jar timestamps are normalized: + if [[ "$(TZ=UTC $JAR tvf $TEST_TMPDIR/testzip.jar)" != *'Tue Jan 01 00:00:00 UTC 1980'* ]]; then + fail 'Zip did not contain normalized timestamps' + fi + + grep '^test/jar/Foo\.java$' $TEST_TMPDIR/testzip.list > /dev/null \ + || fail 'Foo.java not found in output jar.' + grep '^test/jar/Bar\.java$' $TEST_TMPDIR/testzip.list > /dev/null \ + || fail 'Bar.java not found in output jar.' + grep '^test/jar/Outer\.java$' $TEST_TMPDIR/testzip.list > /dev/null \ + || fail 'Outer.java not found in output jar.' + grep '^META-INF/MANIFEST\.MF$' $TEST_TMPDIR/testzip.list > /dev/null \ + || fail 'Manifest not found in output jar.' +else + echo "Warning: 'jar' command not available. Skipping test." +fi + +echo PASS diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/zip_writer.cc b/NorthstarDedicatedTest/include/protobuf/compiler/zip_writer.cc new file mode 100644 index 00000000..b2361dae --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/zip_writer.cc @@ -0,0 +1,195 @@ +// 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. + +// Author: ambrose@google.com (Ambrose Feinstein), +// kenton@google.com (Kenton Varda) +// +// Based on http://www.pkware.com/documents/casestudies/APPNOTE.TXT + +#include <compiler/zip_writer.h> + +#include <cstdint> + +#include <io/coded_stream.h> + +namespace google { +namespace protobuf { +namespace compiler { + +// January 1, 1980 as a DOS date. +// see https://msdn.microsoft.com/en-us/library/9kkf9tah.aspx +static const uint16_t kDosEpoch = 1 << 5 | 1; + +static const uint32_t kCRC32Table[256] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, + 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, + 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, + 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, + 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, + 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, + 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, + 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, + 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, + 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, + 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, + 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, + 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, + 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, + 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, + 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, + 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, + 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d}; + +static uint32_t ComputeCRC32(const std::string& buf) { + uint32_t x = ~0U; + for (int i = 0; i < buf.size(); ++i) { + unsigned char c = buf[i]; + x = kCRC32Table[(x ^ c) & 0xff] ^ (x >> 8); + } + return ~x; +} + +static void WriteShort(io::CodedOutputStream* out, uint16_t val) { + uint8_t p[2]; + p[0] = static_cast<uint8_t>(val); + p[1] = static_cast<uint8_t>(val >> 8); + out->WriteRaw(p, 2); +} + +ZipWriter::ZipWriter(io::ZeroCopyOutputStream* raw_output) + : raw_output_(raw_output) {} +ZipWriter::~ZipWriter() {} + +bool ZipWriter::Write(const std::string& filename, + const std::string& contents) { + FileInfo info; + + info.name = filename; + uint16_t filename_size = filename.size(); + info.offset = raw_output_->ByteCount(); + info.size = contents.size(); + info.crc32 = ComputeCRC32(contents); + + files_.push_back(info); + + // write file header + io::CodedOutputStream output(raw_output_); + output.WriteLittleEndian32(0x04034b50); // magic + WriteShort(&output, 10); // version needed to extract + WriteShort(&output, 0); // flags + WriteShort(&output, 0); // compression method: stored + WriteShort(&output, 0); // last modified time + WriteShort(&output, kDosEpoch); // last modified date + output.WriteLittleEndian32(info.crc32); // crc-32 + output.WriteLittleEndian32(info.size); // compressed size + output.WriteLittleEndian32(info.size); // uncompressed size + WriteShort(&output, filename_size); // file name length + WriteShort(&output, 0); // extra field length + output.WriteString(filename); // file name + output.WriteString(contents); // file data + + return !output.HadError(); +} + +bool ZipWriter::WriteDirectory() { + uint16_t num_entries = files_.size(); + uint32_t dir_ofs = raw_output_->ByteCount(); + + // write central directory + io::CodedOutputStream output(raw_output_); + for (int i = 0; i < num_entries; ++i) { + const std::string& filename = files_[i].name; + uint16_t filename_size = filename.size(); + uint32_t crc32 = files_[i].crc32; + uint32_t size = files_[i].size; + uint32_t offset = files_[i].offset; + + output.WriteLittleEndian32(0x02014b50); // magic + WriteShort(&output, 10); // version made by + WriteShort(&output, 10); // version needed to extract + WriteShort(&output, 0); // flags + WriteShort(&output, 0); // compression method: stored + WriteShort(&output, 0); // last modified time + WriteShort(&output, kDosEpoch); // last modified date + output.WriteLittleEndian32(crc32); // crc-32 + output.WriteLittleEndian32(size); // compressed size + output.WriteLittleEndian32(size); // uncompressed size + WriteShort(&output, filename_size); // file name length + WriteShort(&output, 0); // extra field length + WriteShort(&output, 0); // file comment length + WriteShort(&output, 0); // starting disk number + WriteShort(&output, 0); // internal file attributes + output.WriteLittleEndian32(0); // external file attributes + output.WriteLittleEndian32(offset); // local header offset + output.WriteString(filename); // file name + } + uint32_t dir_len = output.ByteCount(); + + // write end of central directory marker + output.WriteLittleEndian32(0x06054b50); // magic + WriteShort(&output, 0); // disk number + WriteShort(&output, 0); // disk with start of central directory + WriteShort(&output, num_entries); // central directory entries (this disk) + WriteShort(&output, num_entries); // central directory entries (total) + output.WriteLittleEndian32(dir_len); // central directory byte size + output.WriteLittleEndian32(dir_ofs); // central directory offset + WriteShort(&output, 0); // comment length + + return output.HadError(); +} + +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/NorthstarDedicatedTest/include/protobuf/compiler/zip_writer.h b/NorthstarDedicatedTest/include/protobuf/compiler/zip_writer.h new file mode 100644 index 00000000..243bbf1d --- /dev/null +++ b/NorthstarDedicatedTest/include/protobuf/compiler/zip_writer.h @@ -0,0 +1,65 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) + +#include <cstdint> +#include <vector> + +#include <stubs/common.h> +#include <io/zero_copy_stream.h> + +namespace google { +namespace protobuf { +namespace compiler { + +class ZipWriter { + public: + ZipWriter(io::ZeroCopyOutputStream* raw_output); + ~ZipWriter(); + + bool Write(const std::string& filename, const std::string& contents); + bool WriteDirectory(); + + private: + struct FileInfo { + std::string name; + uint32_t offset; + uint32_t size; + uint32_t crc32; + }; + + io::ZeroCopyOutputStream* raw_output_; + std::vector<FileInfo> files_; +}; + +} // namespace compiler +} // namespace protobuf +} // namespace google |