mirror of
https://github.com/alliedmodders/hl2sdk.git
synced 2024-12-23 01:59:43 +08:00
Update protobuf source from v2.3.0 to 2.5.0.
This commit is contained in:
parent
486133fea8
commit
2d3cc15cd4
@ -1,373 +0,0 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// 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 <google/protobuf/compiler/java/java_enum_field.h>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/compiler/java/java_helpers.h>
|
||||
#include <google/protobuf/io/printer.h>
|
||||
#include <google/protobuf/wire_format.h>
|
||||
#include <google/protobuf/stubs/strutil.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace java {
|
||||
|
||||
namespace {
|
||||
|
||||
// TODO(kenton): Factor out a "SetCommonFieldVariables()" to get rid of
|
||||
// repeat code between this and the other field types.
|
||||
void SetEnumVariables(const FieldDescriptor* descriptor,
|
||||
map<string, string>* variables) {
|
||||
(*variables)["name"] =
|
||||
UnderscoresToCamelCase(descriptor);
|
||||
(*variables)["capitalized_name"] =
|
||||
UnderscoresToCapitalizedCamelCase(descriptor);
|
||||
(*variables)["number"] = SimpleItoa(descriptor->number());
|
||||
(*variables)["type"] = ClassName(descriptor->enum_type());
|
||||
(*variables)["default"] = DefaultValue(descriptor);
|
||||
(*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor));
|
||||
(*variables)["tag_size"] = SimpleItoa(
|
||||
internal::WireFormat::TagSize(descriptor->number(), GetType(descriptor)));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// ===================================================================
|
||||
|
||||
EnumFieldGenerator::
|
||||
EnumFieldGenerator(const FieldDescriptor* descriptor)
|
||||
: descriptor_(descriptor) {
|
||||
SetEnumVariables(descriptor, &variables_);
|
||||
}
|
||||
|
||||
EnumFieldGenerator::~EnumFieldGenerator() {}
|
||||
|
||||
void EnumFieldGenerator::
|
||||
GenerateMembers(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"private boolean has$capitalized_name$;\n"
|
||||
"private $type$ $name$_;\n"
|
||||
"public boolean has$capitalized_name$() { return has$capitalized_name$; }\n"
|
||||
"public $type$ get$capitalized_name$() { return $name$_; }\n");
|
||||
}
|
||||
|
||||
void EnumFieldGenerator::
|
||||
GenerateBuilderMembers(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"public boolean has$capitalized_name$() {\n"
|
||||
" return result.has$capitalized_name$();\n"
|
||||
"}\n"
|
||||
"public $type$ get$capitalized_name$() {\n"
|
||||
" return result.get$capitalized_name$();\n"
|
||||
"}\n"
|
||||
"public Builder set$capitalized_name$($type$ value) {\n"
|
||||
" if (value == null) {\n"
|
||||
" throw new NullPointerException();\n"
|
||||
" }\n"
|
||||
" result.has$capitalized_name$ = true;\n"
|
||||
" result.$name$_ = value;\n"
|
||||
" return this;\n"
|
||||
"}\n"
|
||||
"public Builder clear$capitalized_name$() {\n"
|
||||
" result.has$capitalized_name$ = false;\n"
|
||||
" result.$name$_ = $default$;\n"
|
||||
" return this;\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void EnumFieldGenerator::
|
||||
GenerateInitializationCode(io::Printer* printer) const {
|
||||
printer->Print(variables_, "$name$_ = $default$;\n");
|
||||
}
|
||||
|
||||
void EnumFieldGenerator::
|
||||
GenerateMergingCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"if (other.has$capitalized_name$()) {\n"
|
||||
" set$capitalized_name$(other.get$capitalized_name$());\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void EnumFieldGenerator::
|
||||
GenerateBuildingCode(io::Printer* printer) const {
|
||||
// Nothing to do here for enum types.
|
||||
}
|
||||
|
||||
void EnumFieldGenerator::
|
||||
GenerateParsingCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"int rawValue = input.readEnum();\n"
|
||||
"$type$ value = $type$.valueOf(rawValue);\n");
|
||||
if (HasUnknownFields(descriptor_->containing_type())) {
|
||||
printer->Print(variables_,
|
||||
"if (value == null) {\n"
|
||||
" unknownFields.mergeVarintField($number$, rawValue);\n"
|
||||
"} else {\n");
|
||||
} else {
|
||||
printer->Print(variables_,
|
||||
"if (value != null) {\n");
|
||||
}
|
||||
printer->Print(variables_,
|
||||
" set$capitalized_name$(value);\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void EnumFieldGenerator::
|
||||
GenerateSerializationCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"if (has$capitalized_name$()) {\n"
|
||||
" output.writeEnum($number$, get$capitalized_name$().getNumber());\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void EnumFieldGenerator::
|
||||
GenerateSerializedSizeCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"if (has$capitalized_name$()) {\n"
|
||||
" size += com.google.protobuf.CodedOutputStream\n"
|
||||
" .computeEnumSize($number$, get$capitalized_name$().getNumber());\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
string EnumFieldGenerator::GetBoxedType() const {
|
||||
return ClassName(descriptor_->enum_type());
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
RepeatedEnumFieldGenerator::
|
||||
RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor)
|
||||
: descriptor_(descriptor) {
|
||||
SetEnumVariables(descriptor, &variables_);
|
||||
}
|
||||
|
||||
RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() {}
|
||||
|
||||
void RepeatedEnumFieldGenerator::
|
||||
GenerateMembers(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"private java.util.List<$type$> $name$_ =\n"
|
||||
" java.util.Collections.emptyList();\n"
|
||||
"public java.util.List<$type$> get$capitalized_name$List() {\n"
|
||||
" return $name$_;\n" // note: unmodifiable list
|
||||
"}\n"
|
||||
"public int get$capitalized_name$Count() { return $name$_.size(); }\n"
|
||||
"public $type$ get$capitalized_name$(int index) {\n"
|
||||
" return $name$_.get(index);\n"
|
||||
"}\n");
|
||||
|
||||
if (descriptor_->options().packed() &&
|
||||
HasGeneratedMethods(descriptor_->containing_type())) {
|
||||
printer->Print(variables_,
|
||||
"private int $name$MemoizedSerializedSize;\n");
|
||||
}
|
||||
}
|
||||
|
||||
void RepeatedEnumFieldGenerator::
|
||||
GenerateBuilderMembers(io::Printer* printer) const {
|
||||
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.
|
||||
"public java.util.List<$type$> get$capitalized_name$List() {\n"
|
||||
" return java.util.Collections.unmodifiableList(result.$name$_);\n"
|
||||
"}\n"
|
||||
"public int get$capitalized_name$Count() {\n"
|
||||
" return result.get$capitalized_name$Count();\n"
|
||||
"}\n"
|
||||
"public $type$ get$capitalized_name$(int index) {\n"
|
||||
" return result.get$capitalized_name$(index);\n"
|
||||
"}\n"
|
||||
"public Builder set$capitalized_name$(int index, $type$ value) {\n"
|
||||
" if (value == null) {\n"
|
||||
" throw new NullPointerException();\n"
|
||||
" }\n"
|
||||
" result.$name$_.set(index, value);\n"
|
||||
" return this;\n"
|
||||
"}\n"
|
||||
"public Builder add$capitalized_name$($type$ value) {\n"
|
||||
" if (value == null) {\n"
|
||||
" throw new NullPointerException();\n"
|
||||
" }\n"
|
||||
" if (result.$name$_.isEmpty()) {\n"
|
||||
" result.$name$_ = new java.util.ArrayList<$type$>();\n"
|
||||
" }\n"
|
||||
" result.$name$_.add(value);\n"
|
||||
" return this;\n"
|
||||
"}\n"
|
||||
"public Builder addAll$capitalized_name$(\n"
|
||||
" java.lang.Iterable<? extends $type$> values) {\n"
|
||||
" if (result.$name$_.isEmpty()) {\n"
|
||||
" result.$name$_ = new java.util.ArrayList<$type$>();\n"
|
||||
" }\n"
|
||||
" super.addAll(values, result.$name$_);\n"
|
||||
" return this;\n"
|
||||
"}\n"
|
||||
"public Builder clear$capitalized_name$() {\n"
|
||||
" result.$name$_ = java.util.Collections.emptyList();\n"
|
||||
" return this;\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void RepeatedEnumFieldGenerator::
|
||||
GenerateInitializationCode(io::Printer* printer) const {
|
||||
// Initialized inline.
|
||||
}
|
||||
|
||||
void RepeatedEnumFieldGenerator::
|
||||
GenerateMergingCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"if (!other.$name$_.isEmpty()) {\n"
|
||||
" if (result.$name$_.isEmpty()) {\n"
|
||||
" result.$name$_ = new java.util.ArrayList<$type$>();\n"
|
||||
" }\n"
|
||||
" result.$name$_.addAll(other.$name$_);\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void RepeatedEnumFieldGenerator::
|
||||
GenerateBuildingCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"if (result.$name$_ != java.util.Collections.EMPTY_LIST) {\n"
|
||||
" result.$name$_ =\n"
|
||||
" java.util.Collections.unmodifiableList(result.$name$_);\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void RepeatedEnumFieldGenerator::
|
||||
GenerateParsingCode(io::Printer* printer) const {
|
||||
// Read and store the enum
|
||||
printer->Print(variables_,
|
||||
"int rawValue = input.readEnum();\n"
|
||||
"$type$ value = $type$.valueOf(rawValue);\n");
|
||||
if (HasUnknownFields(descriptor_->containing_type())) {
|
||||
printer->Print(variables_,
|
||||
"if (value == null) {\n"
|
||||
" unknownFields.mergeVarintField($number$, rawValue);\n"
|
||||
"} else {\n");
|
||||
} else {
|
||||
printer->Print(variables_,
|
||||
"if (value != null) {\n");
|
||||
}
|
||||
printer->Print(variables_,
|
||||
" add$capitalized_name$(value);\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void RepeatedEnumFieldGenerator::
|
||||
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 RepeatedEnumFieldGenerator::
|
||||
GenerateSerializationCode(io::Printer* printer) const {
|
||||
if (descriptor_->options().packed()) {
|
||||
printer->Print(variables_,
|
||||
"if (get$capitalized_name$List().size() > 0) {\n"
|
||||
" output.writeRawVarint32($tag$);\n"
|
||||
" output.writeRawVarint32($name$MemoizedSerializedSize);\n"
|
||||
"}\n"
|
||||
"for ($type$ element : get$capitalized_name$List()) {\n"
|
||||
" output.writeEnumNoTag(element.getNumber());\n"
|
||||
"}\n");
|
||||
} else {
|
||||
printer->Print(variables_,
|
||||
"for ($type$ element : get$capitalized_name$List()) {\n"
|
||||
" output.writeEnum($number$, element.getNumber());\n"
|
||||
"}\n");
|
||||
}
|
||||
}
|
||||
|
||||
void RepeatedEnumFieldGenerator::
|
||||
GenerateSerializedSizeCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"{\n"
|
||||
" int dataSize = 0;\n");
|
||||
printer->Indent();
|
||||
|
||||
printer->Print(variables_,
|
||||
"for ($type$ element : get$capitalized_name$List()) {\n"
|
||||
" dataSize += com.google.protobuf.CodedOutputStream\n"
|
||||
" .computeEnumSizeNoTag(element.getNumber());\n"
|
||||
"}\n");
|
||||
printer->Print(
|
||||
"size += dataSize;\n");
|
||||
if (descriptor_->options().packed()) {
|
||||
printer->Print(variables_,
|
||||
"if (!get$capitalized_name$List().isEmpty()) {"
|
||||
" size += $tag_size$;\n"
|
||||
" size += com.google.protobuf.CodedOutputStream\n"
|
||||
" .computeRawVarint32Size(dataSize);\n"
|
||||
"}");
|
||||
} else {
|
||||
printer->Print(variables_,
|
||||
"size += $tag_size$ * get$capitalized_name$List().size();\n");
|
||||
}
|
||||
|
||||
// cache the data size for packed fields.
|
||||
if (descriptor_->options().packed()) {
|
||||
printer->Print(variables_,
|
||||
"$name$MemoizedSerializedSize = dataSize;\n");
|
||||
}
|
||||
|
||||
printer->Outdent();
|
||||
printer->Print("}\n");
|
||||
}
|
||||
|
||||
string RepeatedEnumFieldGenerator::GetBoxedType() const {
|
||||
return ClassName(descriptor_->enum_type());
|
||||
}
|
||||
|
||||
} // namespace java
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -1,335 +0,0 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// 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 <google/protobuf/compiler/java/java_message_field.h>
|
||||
#include <google/protobuf/compiler/java/java_helpers.h>
|
||||
#include <google/protobuf/io/printer.h>
|
||||
#include <google/protobuf/wire_format.h>
|
||||
#include <google/protobuf/stubs/strutil.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace java {
|
||||
|
||||
namespace {
|
||||
|
||||
// TODO(kenton): Factor out a "SetCommonFieldVariables()" to get rid of
|
||||
// repeat code between this and the other field types.
|
||||
void SetMessageVariables(const FieldDescriptor* descriptor,
|
||||
map<string, string>* variables) {
|
||||
(*variables)["name"] =
|
||||
UnderscoresToCamelCase(descriptor);
|
||||
(*variables)["capitalized_name"] =
|
||||
UnderscoresToCapitalizedCamelCase(descriptor);
|
||||
(*variables)["number"] = SimpleItoa(descriptor->number());
|
||||
(*variables)["type"] = ClassName(descriptor->message_type());
|
||||
(*variables)["group_or_message"] =
|
||||
(GetType(descriptor) == FieldDescriptor::TYPE_GROUP) ?
|
||||
"Group" : "Message";
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// ===================================================================
|
||||
|
||||
MessageFieldGenerator::
|
||||
MessageFieldGenerator(const FieldDescriptor* descriptor)
|
||||
: descriptor_(descriptor) {
|
||||
SetMessageVariables(descriptor, &variables_);
|
||||
}
|
||||
|
||||
MessageFieldGenerator::~MessageFieldGenerator() {}
|
||||
|
||||
void MessageFieldGenerator::
|
||||
GenerateMembers(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"private boolean has$capitalized_name$;\n"
|
||||
"private $type$ $name$_;\n"
|
||||
"public boolean has$capitalized_name$() { return has$capitalized_name$; }\n"
|
||||
"public $type$ get$capitalized_name$() { return $name$_; }\n");
|
||||
}
|
||||
|
||||
void MessageFieldGenerator::
|
||||
GenerateBuilderMembers(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"public boolean has$capitalized_name$() {\n"
|
||||
" return result.has$capitalized_name$();\n"
|
||||
"}\n"
|
||||
"public $type$ get$capitalized_name$() {\n"
|
||||
" return result.get$capitalized_name$();\n"
|
||||
"}\n"
|
||||
"public Builder set$capitalized_name$($type$ value) {\n"
|
||||
" if (value == null) {\n"
|
||||
" throw new NullPointerException();\n"
|
||||
" }\n"
|
||||
" result.has$capitalized_name$ = true;\n"
|
||||
" result.$name$_ = value;\n"
|
||||
" return this;\n"
|
||||
"}\n"
|
||||
"public Builder set$capitalized_name$($type$.Builder builderForValue) {\n"
|
||||
" result.has$capitalized_name$ = true;\n"
|
||||
" result.$name$_ = builderForValue.build();\n"
|
||||
" return this;\n"
|
||||
"}\n"
|
||||
"public Builder merge$capitalized_name$($type$ value) {\n"
|
||||
" if (result.has$capitalized_name$() &&\n"
|
||||
" result.$name$_ != $type$.getDefaultInstance()) {\n"
|
||||
" result.$name$_ =\n"
|
||||
" $type$.newBuilder(result.$name$_).mergeFrom(value).buildPartial();\n"
|
||||
" } else {\n"
|
||||
" result.$name$_ = value;\n"
|
||||
" }\n"
|
||||
" result.has$capitalized_name$ = true;\n"
|
||||
" return this;\n"
|
||||
"}\n"
|
||||
"public Builder clear$capitalized_name$() {\n"
|
||||
" result.has$capitalized_name$ = false;\n"
|
||||
" result.$name$_ = $type$.getDefaultInstance();\n"
|
||||
" return this;\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void MessageFieldGenerator::
|
||||
GenerateInitializationCode(io::Printer* printer) const {
|
||||
printer->Print(variables_, "$name$_ = $type$.getDefaultInstance();\n");
|
||||
}
|
||||
|
||||
void MessageFieldGenerator::
|
||||
GenerateMergingCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"if (other.has$capitalized_name$()) {\n"
|
||||
" merge$capitalized_name$(other.get$capitalized_name$());\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void MessageFieldGenerator::
|
||||
GenerateBuildingCode(io::Printer* printer) const {
|
||||
// Nothing to do for singular fields.
|
||||
}
|
||||
|
||||
void MessageFieldGenerator::
|
||||
GenerateParsingCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"$type$.Builder subBuilder = $type$.newBuilder();\n"
|
||||
"if (has$capitalized_name$()) {\n"
|
||||
" subBuilder.mergeFrom(get$capitalized_name$());\n"
|
||||
"}\n");
|
||||
|
||||
if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) {
|
||||
printer->Print(variables_,
|
||||
"input.readGroup($number$, subBuilder, extensionRegistry);\n");
|
||||
} else {
|
||||
printer->Print(variables_,
|
||||
"input.readMessage(subBuilder, extensionRegistry);\n");
|
||||
}
|
||||
|
||||
printer->Print(variables_,
|
||||
"set$capitalized_name$(subBuilder.buildPartial());\n");
|
||||
}
|
||||
|
||||
void MessageFieldGenerator::
|
||||
GenerateSerializationCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"if (has$capitalized_name$()) {\n"
|
||||
" output.write$group_or_message$($number$, get$capitalized_name$());\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void MessageFieldGenerator::
|
||||
GenerateSerializedSizeCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"if (has$capitalized_name$()) {\n"
|
||||
" size += com.google.protobuf.CodedOutputStream\n"
|
||||
" .compute$group_or_message$Size($number$, get$capitalized_name$());\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
string MessageFieldGenerator::GetBoxedType() const {
|
||||
return ClassName(descriptor_->message_type());
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
RepeatedMessageFieldGenerator::
|
||||
RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor)
|
||||
: descriptor_(descriptor) {
|
||||
SetMessageVariables(descriptor, &variables_);
|
||||
}
|
||||
|
||||
RepeatedMessageFieldGenerator::~RepeatedMessageFieldGenerator() {}
|
||||
|
||||
void RepeatedMessageFieldGenerator::
|
||||
GenerateMembers(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"private java.util.List<$type$> $name$_ =\n"
|
||||
" java.util.Collections.emptyList();\n"
|
||||
"public java.util.List<$type$> get$capitalized_name$List() {\n"
|
||||
" return $name$_;\n" // note: unmodifiable list
|
||||
"}\n"
|
||||
"public int get$capitalized_name$Count() { return $name$_.size(); }\n"
|
||||
"public $type$ get$capitalized_name$(int index) {\n"
|
||||
" return $name$_.get(index);\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void RepeatedMessageFieldGenerator::
|
||||
GenerateBuilderMembers(io::Printer* printer) const {
|
||||
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.
|
||||
"public java.util.List<$type$> get$capitalized_name$List() {\n"
|
||||
" return java.util.Collections.unmodifiableList(result.$name$_);\n"
|
||||
"}\n"
|
||||
"public int get$capitalized_name$Count() {\n"
|
||||
" return result.get$capitalized_name$Count();\n"
|
||||
"}\n"
|
||||
"public $type$ get$capitalized_name$(int index) {\n"
|
||||
" return result.get$capitalized_name$(index);\n"
|
||||
"}\n"
|
||||
"public Builder set$capitalized_name$(int index, $type$ value) {\n"
|
||||
" if (value == null) {\n"
|
||||
" throw new NullPointerException();\n"
|
||||
" }\n"
|
||||
" result.$name$_.set(index, value);\n"
|
||||
" return this;\n"
|
||||
"}\n"
|
||||
"public Builder set$capitalized_name$(int index, "
|
||||
"$type$.Builder builderForValue) {\n"
|
||||
" result.$name$_.set(index, builderForValue.build());\n"
|
||||
" return this;\n"
|
||||
"}\n"
|
||||
"public Builder add$capitalized_name$($type$ value) {\n"
|
||||
" if (value == null) {\n"
|
||||
" throw new NullPointerException();\n"
|
||||
" }\n"
|
||||
" if (result.$name$_.isEmpty()) {\n"
|
||||
" result.$name$_ = new java.util.ArrayList<$type$>();\n"
|
||||
" }\n"
|
||||
" result.$name$_.add(value);\n"
|
||||
" return this;\n"
|
||||
"}\n"
|
||||
"public Builder add$capitalized_name$($type$.Builder builderForValue) {\n"
|
||||
" if (result.$name$_.isEmpty()) {\n"
|
||||
" result.$name$_ = new java.util.ArrayList<$type$>();\n"
|
||||
" }\n"
|
||||
" result.$name$_.add(builderForValue.build());\n"
|
||||
" return this;\n"
|
||||
"}\n"
|
||||
"public Builder addAll$capitalized_name$(\n"
|
||||
" java.lang.Iterable<? extends $type$> values) {\n"
|
||||
" if (result.$name$_.isEmpty()) {\n"
|
||||
" result.$name$_ = new java.util.ArrayList<$type$>();\n"
|
||||
" }\n"
|
||||
" super.addAll(values, result.$name$_);\n"
|
||||
" return this;\n"
|
||||
"}\n"
|
||||
"public Builder clear$capitalized_name$() {\n"
|
||||
" result.$name$_ = java.util.Collections.emptyList();\n"
|
||||
" return this;\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void RepeatedMessageFieldGenerator::
|
||||
GenerateInitializationCode(io::Printer* printer) const {
|
||||
// Initialized inline.
|
||||
}
|
||||
|
||||
void RepeatedMessageFieldGenerator::
|
||||
GenerateMergingCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"if (!other.$name$_.isEmpty()) {\n"
|
||||
" if (result.$name$_.isEmpty()) {\n"
|
||||
" result.$name$_ = new java.util.ArrayList<$type$>();\n"
|
||||
" }\n"
|
||||
" result.$name$_.addAll(other.$name$_);\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void RepeatedMessageFieldGenerator::
|
||||
GenerateBuildingCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"if (result.$name$_ != java.util.Collections.EMPTY_LIST) {\n"
|
||||
" result.$name$_ =\n"
|
||||
" java.util.Collections.unmodifiableList(result.$name$_);\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void RepeatedMessageFieldGenerator::
|
||||
GenerateParsingCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"$type$.Builder subBuilder = $type$.newBuilder();\n");
|
||||
|
||||
if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) {
|
||||
printer->Print(variables_,
|
||||
"input.readGroup($number$, subBuilder, extensionRegistry);\n");
|
||||
} else {
|
||||
printer->Print(variables_,
|
||||
"input.readMessage(subBuilder, extensionRegistry);\n");
|
||||
}
|
||||
|
||||
printer->Print(variables_,
|
||||
"add$capitalized_name$(subBuilder.buildPartial());\n");
|
||||
}
|
||||
|
||||
void RepeatedMessageFieldGenerator::
|
||||
GenerateSerializationCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"for ($type$ element : get$capitalized_name$List()) {\n"
|
||||
" output.write$group_or_message$($number$, element);\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void RepeatedMessageFieldGenerator::
|
||||
GenerateSerializedSizeCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"for ($type$ element : get$capitalized_name$List()) {\n"
|
||||
" size += com.google.protobuf.CodedOutputStream\n"
|
||||
" .compute$group_or_message$Size($number$, element);\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
string RepeatedMessageFieldGenerator::GetBoxedType() const {
|
||||
return ClassName(descriptor_->message_type());
|
||||
}
|
||||
|
||||
} // namespace java
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -1,465 +0,0 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// 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 <google/protobuf/compiler/java/java_primitive_field.h>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/compiler/java/java_helpers.h>
|
||||
#include <google/protobuf/io/printer.h>
|
||||
#include <google/protobuf/wire_format.h>
|
||||
#include <google/protobuf/stubs/strutil.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace java {
|
||||
|
||||
using internal::WireFormat;
|
||||
using internal::WireFormatLite;
|
||||
|
||||
namespace {
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
|
||||
void SetPrimitiveVariables(const FieldDescriptor* descriptor,
|
||||
map<string, string>* variables) {
|
||||
(*variables)["name"] =
|
||||
UnderscoresToCamelCase(descriptor);
|
||||
(*variables)["capitalized_name"] =
|
||||
UnderscoresToCapitalizedCamelCase(descriptor);
|
||||
(*variables)["number"] = SimpleItoa(descriptor->number());
|
||||
(*variables)["type"] = PrimitiveTypeName(GetJavaType(descriptor));
|
||||
(*variables)["boxed_type"] = BoxedPrimitiveTypeName(GetJavaType(descriptor));
|
||||
(*variables)["default"] = DefaultValue(descriptor);
|
||||
(*variables)["capitalized_type"] = GetCapitalizedType(descriptor);
|
||||
(*variables)["tag"] = SimpleItoa(WireFormat::MakeTag(descriptor));
|
||||
(*variables)["tag_size"] = SimpleItoa(
|
||||
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"] = "";
|
||||
}
|
||||
int fixed_size = FixedSize(GetType(descriptor));
|
||||
if (fixed_size != -1) {
|
||||
(*variables)["fixed_size"] = SimpleItoa(fixed_size);
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
// ===================================================================
|
||||
|
||||
PrimitiveFieldGenerator::
|
||||
PrimitiveFieldGenerator(const FieldDescriptor* descriptor)
|
||||
: descriptor_(descriptor) {
|
||||
SetPrimitiveVariables(descriptor, &variables_);
|
||||
}
|
||||
|
||||
PrimitiveFieldGenerator::~PrimitiveFieldGenerator() {}
|
||||
|
||||
void PrimitiveFieldGenerator::
|
||||
GenerateMembers(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"private boolean has$capitalized_name$;\n"
|
||||
"private $type$ $name$_ = $default$;\n"
|
||||
"public boolean has$capitalized_name$() { return has$capitalized_name$; }\n"
|
||||
"public $type$ get$capitalized_name$() { return $name$_; }\n");
|
||||
}
|
||||
|
||||
void PrimitiveFieldGenerator::
|
||||
GenerateBuilderMembers(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"public boolean has$capitalized_name$() {\n"
|
||||
" return result.has$capitalized_name$();\n"
|
||||
"}\n"
|
||||
"public $type$ get$capitalized_name$() {\n"
|
||||
" return result.get$capitalized_name$();\n"
|
||||
"}\n"
|
||||
"public Builder set$capitalized_name$($type$ value) {\n"
|
||||
"$null_check$"
|
||||
" result.has$capitalized_name$ = true;\n"
|
||||
" result.$name$_ = value;\n"
|
||||
" return this;\n"
|
||||
"}\n"
|
||||
"public Builder clear$capitalized_name$() {\n"
|
||||
" result.has$capitalized_name$ = false;\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_,
|
||||
" result.$name$_ = getDefaultInstance().get$capitalized_name$();\n");
|
||||
} else {
|
||||
printer->Print(variables_,
|
||||
" result.$name$_ = $default$;\n");
|
||||
}
|
||||
printer->Print(variables_,
|
||||
" return this;\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void PrimitiveFieldGenerator::
|
||||
GenerateInitializationCode(io::Printer* printer) const {
|
||||
// Initialized inline.
|
||||
}
|
||||
|
||||
void PrimitiveFieldGenerator::
|
||||
GenerateMergingCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"if (other.has$capitalized_name$()) {\n"
|
||||
" set$capitalized_name$(other.get$capitalized_name$());\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void PrimitiveFieldGenerator::
|
||||
GenerateBuildingCode(io::Printer* printer) const {
|
||||
// Nothing to do here for primitive types.
|
||||
}
|
||||
|
||||
void PrimitiveFieldGenerator::
|
||||
GenerateParsingCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"set$capitalized_name$(input.read$capitalized_type$());\n");
|
||||
}
|
||||
|
||||
void PrimitiveFieldGenerator::
|
||||
GenerateSerializationCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"if (has$capitalized_name$()) {\n"
|
||||
" output.write$capitalized_type$($number$, get$capitalized_name$());\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void PrimitiveFieldGenerator::
|
||||
GenerateSerializedSizeCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"if (has$capitalized_name$()) {\n"
|
||||
" size += com.google.protobuf.CodedOutputStream\n"
|
||||
" .compute$capitalized_type$Size($number$, get$capitalized_name$());\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
string PrimitiveFieldGenerator::GetBoxedType() const {
|
||||
return BoxedPrimitiveTypeName(GetJavaType(descriptor_));
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
RepeatedPrimitiveFieldGenerator::
|
||||
RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor)
|
||||
: descriptor_(descriptor) {
|
||||
SetPrimitiveVariables(descriptor, &variables_);
|
||||
}
|
||||
|
||||
RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() {}
|
||||
|
||||
void RepeatedPrimitiveFieldGenerator::
|
||||
GenerateMembers(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"private java.util.List<$boxed_type$> $name$_ =\n"
|
||||
" java.util.Collections.emptyList();\n"
|
||||
"public java.util.List<$boxed_type$> get$capitalized_name$List() {\n"
|
||||
" return $name$_;\n" // note: unmodifiable list
|
||||
"}\n"
|
||||
"public int get$capitalized_name$Count() { return $name$_.size(); }\n"
|
||||
"public $type$ get$capitalized_name$(int index) {\n"
|
||||
" return $name$_.get(index);\n"
|
||||
"}\n");
|
||||
|
||||
if (descriptor_->options().packed() &&
|
||||
HasGeneratedMethods(descriptor_->containing_type())) {
|
||||
printer->Print(variables_,
|
||||
"private int $name$MemoizedSerializedSize = -1;\n");
|
||||
}
|
||||
}
|
||||
|
||||
void RepeatedPrimitiveFieldGenerator::
|
||||
GenerateBuilderMembers(io::Printer* printer) const {
|
||||
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.
|
||||
"public java.util.List<$boxed_type$> get$capitalized_name$List() {\n"
|
||||
" return java.util.Collections.unmodifiableList(result.$name$_);\n"
|
||||
"}\n"
|
||||
"public int get$capitalized_name$Count() {\n"
|
||||
" return result.get$capitalized_name$Count();\n"
|
||||
"}\n"
|
||||
"public $type$ get$capitalized_name$(int index) {\n"
|
||||
" return result.get$capitalized_name$(index);\n"
|
||||
"}\n"
|
||||
"public Builder set$capitalized_name$(int index, $type$ value) {\n"
|
||||
"$null_check$"
|
||||
" result.$name$_.set(index, value);\n"
|
||||
" return this;\n"
|
||||
"}\n"
|
||||
"public Builder add$capitalized_name$($type$ value) {\n"
|
||||
"$null_check$"
|
||||
" if (result.$name$_.isEmpty()) {\n"
|
||||
" result.$name$_ = new java.util.ArrayList<$boxed_type$>();\n"
|
||||
" }\n"
|
||||
" result.$name$_.add(value);\n"
|
||||
" return this;\n"
|
||||
"}\n"
|
||||
"public Builder addAll$capitalized_name$(\n"
|
||||
" java.lang.Iterable<? extends $boxed_type$> values) {\n"
|
||||
" if (result.$name$_.isEmpty()) {\n"
|
||||
" result.$name$_ = new java.util.ArrayList<$boxed_type$>();\n"
|
||||
" }\n"
|
||||
" super.addAll(values, result.$name$_);\n"
|
||||
" return this;\n"
|
||||
"}\n"
|
||||
"public Builder clear$capitalized_name$() {\n"
|
||||
" result.$name$_ = java.util.Collections.emptyList();\n"
|
||||
" return this;\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void RepeatedPrimitiveFieldGenerator::
|
||||
GenerateInitializationCode(io::Printer* printer) const {
|
||||
// Initialized inline.
|
||||
}
|
||||
|
||||
void RepeatedPrimitiveFieldGenerator::
|
||||
GenerateMergingCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"if (!other.$name$_.isEmpty()) {\n"
|
||||
" if (result.$name$_.isEmpty()) {\n"
|
||||
" result.$name$_ = new java.util.ArrayList<$boxed_type$>();\n"
|
||||
" }\n"
|
||||
" result.$name$_.addAll(other.$name$_);\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void RepeatedPrimitiveFieldGenerator::
|
||||
GenerateBuildingCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"if (result.$name$_ != java.util.Collections.EMPTY_LIST) {\n"
|
||||
" result.$name$_ =\n"
|
||||
" java.util.Collections.unmodifiableList(result.$name$_);\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void RepeatedPrimitiveFieldGenerator::
|
||||
GenerateParsingCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"add$capitalized_name$(input.read$capitalized_type$());\n");
|
||||
}
|
||||
|
||||
void RepeatedPrimitiveFieldGenerator::
|
||||
GenerateParsingCodeFromPacked(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"int length = input.readRawVarint32();\n"
|
||||
"int limit = input.pushLimit(length);\n"
|
||||
"while (input.getBytesUntilLimit() > 0) {\n"
|
||||
" add$capitalized_name$(input.read$capitalized_type$());\n"
|
||||
"}\n"
|
||||
"input.popLimit(limit);\n");
|
||||
}
|
||||
|
||||
void RepeatedPrimitiveFieldGenerator::
|
||||
GenerateSerializationCode(io::Printer* printer) const {
|
||||
if (descriptor_->options().packed()) {
|
||||
printer->Print(variables_,
|
||||
"if (get$capitalized_name$List().size() > 0) {\n"
|
||||
" output.writeRawVarint32($tag$);\n"
|
||||
" output.writeRawVarint32($name$MemoizedSerializedSize);\n"
|
||||
"}\n"
|
||||
"for ($type$ element : get$capitalized_name$List()) {\n"
|
||||
" output.write$capitalized_type$NoTag(element);\n"
|
||||
"}\n");
|
||||
} else {
|
||||
printer->Print(variables_,
|
||||
"for ($type$ element : get$capitalized_name$List()) {\n"
|
||||
" output.write$capitalized_type$($number$, element);\n"
|
||||
"}\n");
|
||||
}
|
||||
}
|
||||
|
||||
void RepeatedPrimitiveFieldGenerator::
|
||||
GenerateSerializedSizeCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"{\n"
|
||||
" int dataSize = 0;\n");
|
||||
printer->Indent();
|
||||
|
||||
if (FixedSize(GetType(descriptor_)) == -1) {
|
||||
printer->Print(variables_,
|
||||
"for ($type$ element : get$capitalized_name$List()) {\n"
|
||||
" dataSize += com.google.protobuf.CodedOutputStream\n"
|
||||
" .compute$capitalized_type$SizeNoTag(element);\n"
|
||||
"}\n");
|
||||
} else {
|
||||
printer->Print(variables_,
|
||||
"dataSize = $fixed_size$ * get$capitalized_name$List().size();\n");
|
||||
}
|
||||
|
||||
printer->Print(
|
||||
"size += dataSize;\n");
|
||||
|
||||
if (descriptor_->options().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_->options().packed()) {
|
||||
printer->Print(variables_,
|
||||
"$name$MemoizedSerializedSize = dataSize;\n");
|
||||
}
|
||||
|
||||
printer->Outdent();
|
||||
printer->Print("}\n");
|
||||
}
|
||||
|
||||
string RepeatedPrimitiveFieldGenerator::GetBoxedType() const {
|
||||
return BoxedPrimitiveTypeName(GetJavaType(descriptor_));
|
||||
}
|
||||
|
||||
} // namespace java
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -37,54 +37,70 @@ CLEANFILES = $(protoc_outputs) unittest_proto_middleman \
|
||||
MAINTAINERCLEANFILES = \
|
||||
Makefile.in
|
||||
|
||||
nobase_include_HEADERS = \
|
||||
google/protobuf/stubs/common.h \
|
||||
google/protobuf/stubs/once.h \
|
||||
google/protobuf/descriptor.h \
|
||||
google/protobuf/descriptor.pb.h \
|
||||
google/protobuf/descriptor_database.h \
|
||||
google/protobuf/dynamic_message.h \
|
||||
google/protobuf/extension_set.h \
|
||||
google/protobuf/generated_message_util.h \
|
||||
google/protobuf/generated_message_reflection.h \
|
||||
google/protobuf/message.h \
|
||||
google/protobuf/message_lite.h \
|
||||
google/protobuf/reflection_ops.h \
|
||||
google/protobuf/repeated_field.h \
|
||||
google/protobuf/service.h \
|
||||
google/protobuf/text_format.h \
|
||||
google/protobuf/unknown_field_set.h \
|
||||
google/protobuf/wire_format.h \
|
||||
google/protobuf/wire_format_lite.h \
|
||||
google/protobuf/wire_format_lite_inl.h \
|
||||
google/protobuf/io/coded_stream.h \
|
||||
$(GZHEADERS) \
|
||||
google/protobuf/io/printer.h \
|
||||
google/protobuf/io/tokenizer.h \
|
||||
google/protobuf/io/zero_copy_stream.h \
|
||||
google/protobuf/io/zero_copy_stream_impl.h \
|
||||
google/protobuf/io/zero_copy_stream_impl_lite.h \
|
||||
google/protobuf/compiler/code_generator.h \
|
||||
google/protobuf/compiler/command_line_interface.h \
|
||||
google/protobuf/compiler/importer.h \
|
||||
google/protobuf/compiler/parser.h \
|
||||
google/protobuf/compiler/plugin.h \
|
||||
google/protobuf/compiler/plugin.pb.h \
|
||||
google/protobuf/compiler/cpp/cpp_generator.h \
|
||||
google/protobuf/compiler/java/java_generator.h \
|
||||
nobase_include_HEADERS = \
|
||||
google/protobuf/stubs/atomicops.h \
|
||||
google/protobuf/stubs/atomicops_internals_arm_gcc.h \
|
||||
google/protobuf/stubs/atomicops_internals_arm_qnx.h \
|
||||
google/protobuf/stubs/atomicops_internals_atomicword_compat.h \
|
||||
google/protobuf/stubs/atomicops_internals_macosx.h \
|
||||
google/protobuf/stubs/atomicops_internals_mips_gcc.h \
|
||||
google/protobuf/stubs/atomicops_internals_pnacl.h \
|
||||
google/protobuf/stubs/atomicops_internals_x86_gcc.h \
|
||||
google/protobuf/stubs/atomicops_internals_x86_msvc.h \
|
||||
google/protobuf/stubs/common.h \
|
||||
google/protobuf/stubs/platform_macros.h \
|
||||
google/protobuf/stubs/once.h \
|
||||
google/protobuf/stubs/template_util.h \
|
||||
google/protobuf/stubs/type_traits.h \
|
||||
google/protobuf/descriptor.h \
|
||||
google/protobuf/descriptor.pb.h \
|
||||
google/protobuf/descriptor_database.h \
|
||||
google/protobuf/dynamic_message.h \
|
||||
google/protobuf/extension_set.h \
|
||||
google/protobuf/generated_enum_reflection.h \
|
||||
google/protobuf/generated_message_util.h \
|
||||
google/protobuf/generated_message_reflection.h \
|
||||
google/protobuf/message.h \
|
||||
google/protobuf/message_lite.h \
|
||||
google/protobuf/reflection_ops.h \
|
||||
google/protobuf/repeated_field.h \
|
||||
google/protobuf/service.h \
|
||||
google/protobuf/text_format.h \
|
||||
google/protobuf/unknown_field_set.h \
|
||||
google/protobuf/wire_format.h \
|
||||
google/protobuf/wire_format_lite.h \
|
||||
google/protobuf/wire_format_lite_inl.h \
|
||||
google/protobuf/io/coded_stream.h \
|
||||
$(GZHEADERS) \
|
||||
google/protobuf/io/printer.h \
|
||||
google/protobuf/io/tokenizer.h \
|
||||
google/protobuf/io/zero_copy_stream.h \
|
||||
google/protobuf/io/zero_copy_stream_impl.h \
|
||||
google/protobuf/io/zero_copy_stream_impl_lite.h \
|
||||
google/protobuf/compiler/code_generator.h \
|
||||
google/protobuf/compiler/command_line_interface.h \
|
||||
google/protobuf/compiler/importer.h \
|
||||
google/protobuf/compiler/parser.h \
|
||||
google/protobuf/compiler/plugin.h \
|
||||
google/protobuf/compiler/plugin.pb.h \
|
||||
google/protobuf/compiler/cpp/cpp_generator.h \
|
||||
google/protobuf/compiler/java/java_generator.h \
|
||||
google/protobuf/compiler/python/python_generator.h
|
||||
|
||||
lib_LTLIBRARIES = libprotobuf-lite.la libprotobuf.la libprotoc.la
|
||||
|
||||
libprotobuf_lite_la_LIBADD = $(PTHREAD_LIBS)
|
||||
libprotobuf_lite_la_LDFLAGS = -version-info 6:0:0 -export-dynamic -no-undefined
|
||||
libprotobuf_lite_la_LDFLAGS = -version-info 8:0:0 -export-dynamic -no-undefined
|
||||
libprotobuf_lite_la_SOURCES = \
|
||||
google/protobuf/stubs/atomicops_internals_x86_gcc.cc \
|
||||
google/protobuf/stubs/atomicops_internals_x86_msvc.cc \
|
||||
google/protobuf/stubs/common.cc \
|
||||
google/protobuf/stubs/once.cc \
|
||||
google/protobuf/stubs/hash.cc \
|
||||
google/protobuf/stubs/hash.h \
|
||||
google/protobuf/stubs/map-util.h \
|
||||
google/protobuf/stubs/stl_util-inl.h \
|
||||
google/protobuf/stubs/stl_util.h \
|
||||
google/protobuf/stubs/stringprintf.cc \
|
||||
google/protobuf/stubs/stringprintf.h \
|
||||
google/protobuf/extension_set.cc \
|
||||
google/protobuf/generated_message_util.cc \
|
||||
google/protobuf/message_lite.cc \
|
||||
@ -96,7 +112,7 @@ libprotobuf_lite_la_SOURCES = \
|
||||
google/protobuf/io/zero_copy_stream_impl_lite.cc
|
||||
|
||||
libprotobuf_la_LIBADD = $(PTHREAD_LIBS)
|
||||
libprotobuf_la_LDFLAGS = -version-info 6:0:0 -export-dynamic -no-undefined
|
||||
libprotobuf_la_LDFLAGS = -version-info 8:0:0 -export-dynamic -no-undefined
|
||||
libprotobuf_la_SOURCES = \
|
||||
$(libprotobuf_lite_la_SOURCES) \
|
||||
google/protobuf/stubs/strutil.cc \
|
||||
@ -124,7 +140,7 @@ libprotobuf_la_SOURCES = \
|
||||
google/protobuf/compiler/parser.cc
|
||||
|
||||
libprotoc_la_LIBADD = $(PTHREAD_LIBS) libprotobuf.la
|
||||
libprotoc_la_LDFLAGS = -version-info 6:0:0 -export-dynamic -no-undefined
|
||||
libprotoc_la_LDFLAGS = -version-info 8:0:0 -export-dynamic -no-undefined
|
||||
libprotoc_la_SOURCES = \
|
||||
google/protobuf/compiler/code_generator.cc \
|
||||
google/protobuf/compiler/command_line_interface.cc \
|
||||
@ -151,6 +167,7 @@ libprotoc_la_SOURCES = \
|
||||
google/protobuf/compiler/cpp/cpp_message.h \
|
||||
google/protobuf/compiler/cpp/cpp_message_field.cc \
|
||||
google/protobuf/compiler/cpp/cpp_message_field.h \
|
||||
google/protobuf/compiler/cpp/cpp_options.h \
|
||||
google/protobuf/compiler/cpp/cpp_primitive_field.cc \
|
||||
google/protobuf/compiler/cpp/cpp_primitive_field.h \
|
||||
google/protobuf/compiler/cpp/cpp_service.cc \
|
||||
@ -178,6 +195,10 @@ libprotoc_la_SOURCES = \
|
||||
google/protobuf/compiler/java/java_primitive_field.h \
|
||||
google/protobuf/compiler/java/java_service.cc \
|
||||
google/protobuf/compiler/java/java_service.h \
|
||||
google/protobuf/compiler/java/java_string_field.cc \
|
||||
google/protobuf/compiler/java/java_string_field.h \
|
||||
google/protobuf/compiler/java/java_doc_comment.cc \
|
||||
google/protobuf/compiler/java/java_doc_comment.h \
|
||||
google/protobuf/compiler/python/python_generator.cc
|
||||
|
||||
bin_PROGRAMS = protoc
|
||||
@ -190,12 +211,14 @@ protoc_inputs = \
|
||||
google/protobuf/unittest.proto \
|
||||
google/protobuf/unittest_empty.proto \
|
||||
google/protobuf/unittest_import.proto \
|
||||
google/protobuf/unittest_import_public.proto \
|
||||
google/protobuf/unittest_mset.proto \
|
||||
google/protobuf/unittest_optimize_for.proto \
|
||||
google/protobuf/unittest_embed_optimize_for.proto \
|
||||
google/protobuf/unittest_custom_options.proto \
|
||||
google/protobuf/unittest_lite.proto \
|
||||
google/protobuf/unittest_import_lite.proto \
|
||||
google/protobuf/unittest_import_public_lite.proto \
|
||||
google/protobuf/unittest_lite_imports_nonlite.proto \
|
||||
google/protobuf/unittest_no_generic_services.proto \
|
||||
google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto
|
||||
@ -219,7 +242,9 @@ protoc_lite_outputs = \
|
||||
google/protobuf/unittest_lite.pb.cc \
|
||||
google/protobuf/unittest_lite.pb.h \
|
||||
google/protobuf/unittest_import_lite.pb.cc \
|
||||
google/protobuf/unittest_import_lite.pb.h
|
||||
google/protobuf/unittest_import_lite.pb.h \
|
||||
google/protobuf/unittest_import_public_lite.pb.cc \
|
||||
google/protobuf/unittest_import_public_lite.pb.h
|
||||
|
||||
protoc_outputs = \
|
||||
$(protoc_lite_outputs) \
|
||||
@ -229,6 +254,8 @@ protoc_outputs = \
|
||||
google/protobuf/unittest_empty.pb.h \
|
||||
google/protobuf/unittest_import.pb.cc \
|
||||
google/protobuf/unittest_import.pb.h \
|
||||
google/protobuf/unittest_import_public.pb.cc \
|
||||
google/protobuf/unittest_import_public.pb.h \
|
||||
google/protobuf/unittest_mset.pb.cc \
|
||||
google/protobuf/unittest_mset.pb.h \
|
||||
google/protobuf/unittest_optimize_for.pb.cc \
|
||||
@ -289,6 +316,9 @@ protobuf_test_SOURCES = \
|
||||
google/protobuf/stubs/once_unittest.cc \
|
||||
google/protobuf/stubs/strutil_unittest.cc \
|
||||
google/protobuf/stubs/structurally_valid_unittest.cc \
|
||||
google/protobuf/stubs/stringprintf_unittest.cc \
|
||||
google/protobuf/stubs/template_util_unittest.cc \
|
||||
google/protobuf/stubs/type_traits_unittest.cc \
|
||||
google/protobuf/descriptor_database_unittest.cc \
|
||||
google/protobuf/descriptor_unittest.cc \
|
||||
google/protobuf/dynamic_message_unittest.cc \
|
||||
@ -297,6 +327,7 @@ protobuf_test_SOURCES = \
|
||||
google/protobuf/message_unittest.cc \
|
||||
google/protobuf/reflection_ops_unittest.cc \
|
||||
google/protobuf/repeated_field_unittest.cc \
|
||||
google/protobuf/repeated_field_reflection_unittest.cc \
|
||||
google/protobuf/text_format_unittest.cc \
|
||||
google/protobuf/unknown_field_set_unittest.cc \
|
||||
google/protobuf/wire_format_unittest.cc \
|
||||
@ -310,9 +341,11 @@ protobuf_test_SOURCES = \
|
||||
google/protobuf/compiler/mock_code_generator.h \
|
||||
google/protobuf/compiler/parser_unittest.cc \
|
||||
google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc \
|
||||
google/protobuf/compiler/cpp/cpp_unittest.h \
|
||||
google/protobuf/compiler/cpp/cpp_unittest.cc \
|
||||
google/protobuf/compiler/cpp/cpp_plugin_unittest.cc \
|
||||
google/protobuf/compiler/java/java_plugin_unittest.cc \
|
||||
google/protobuf/compiler/java/java_doc_comment_unittest.cc \
|
||||
google/protobuf/compiler/python/python_plugin_unittest.cc \
|
||||
$(COMMON_TEST_SOURCES)
|
||||
nodist_protobuf_test_SOURCES = $(protoc_outputs)
|
File diff suppressed because it is too large
Load Diff
@ -42,14 +42,19 @@ namespace protobuf {
|
||||
namespace compiler {
|
||||
|
||||
CodeGenerator::~CodeGenerator() {}
|
||||
OutputDirectory::~OutputDirectory() {}
|
||||
GeneratorContext::~GeneratorContext() {}
|
||||
|
||||
io::ZeroCopyOutputStream* OutputDirectory::OpenForInsert(
|
||||
io::ZeroCopyOutputStream* GeneratorContext::OpenForInsert(
|
||||
const string& filename, const string& insertion_point) {
|
||||
GOOGLE_LOG(FATAL) << "This OutputDirectory does not support insertion.";
|
||||
GOOGLE_LOG(FATAL) << "This GeneratorContext does not support insertion.";
|
||||
return NULL; // make compiler happy
|
||||
}
|
||||
|
||||
void GeneratorContext::ListParsedFiles(
|
||||
vector<const FileDescriptor*>* output) {
|
||||
GOOGLE_LOG(FATAL) << "This GeneratorContext does not support ListParsedFiles";
|
||||
}
|
||||
|
||||
// Parses a set of comma-delimited name/value pairs.
|
||||
void ParseGeneratorParameter(const string& text,
|
||||
vector<pair<string, string> >* output) {
|
@ -53,7 +53,7 @@ namespace compiler {
|
||||
|
||||
// Defined in this file.
|
||||
class CodeGenerator;
|
||||
class OutputDirectory;
|
||||
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
|
||||
@ -76,7 +76,7 @@ class LIBPROTOC_EXPORT CodeGenerator {
|
||||
// the problem (e.g. "invalid parameter") and returns false.
|
||||
virtual bool Generate(const FileDescriptor* file,
|
||||
const string& parameter,
|
||||
OutputDirectory* output_directory,
|
||||
GeneratorContext* generator_context,
|
||||
string* error) const = 0;
|
||||
|
||||
private:
|
||||
@ -85,11 +85,12 @@ class LIBPROTOC_EXPORT CodeGenerator {
|
||||
|
||||
// CodeGenerators generate one or more files in a given directory. This
|
||||
// abstract interface represents the directory to which the CodeGenerator is
|
||||
// to write.
|
||||
class LIBPROTOC_EXPORT OutputDirectory {
|
||||
// to write and other information about the context in which the Generator
|
||||
// runs.
|
||||
class LIBPROTOC_EXPORT GeneratorContext {
|
||||
public:
|
||||
inline OutputDirectory() {}
|
||||
virtual ~OutputDirectory();
|
||||
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
|
||||
@ -112,10 +113,19 @@ class LIBPROTOC_EXPORT OutputDirectory {
|
||||
virtual io::ZeroCopyOutputStream* OpenForInsert(
|
||||
const string& filename, const string& insertion_point);
|
||||
|
||||
// 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(vector<const FileDescriptor*>* output);
|
||||
|
||||
private:
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(OutputDirectory);
|
||||
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.,
|
@ -48,6 +48,9 @@
|
||||
#include <iostream>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <google/protobuf/stubs/hash.h>
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/compiler/importer.h>
|
||||
#include <google/protobuf/compiler/code_generator.h>
|
||||
#include <google/protobuf/compiler/plugin.pb.h>
|
||||
@ -56,14 +59,13 @@
|
||||
#include <google/protobuf/descriptor.h>
|
||||
#include <google/protobuf/text_format.h>
|
||||
#include <google/protobuf/dynamic_message.h>
|
||||
#include <google/protobuf/io/coded_stream.h>
|
||||
#include <google/protobuf/io/zero_copy_stream_impl.h>
|
||||
#include <google/protobuf/io/printer.h>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/stubs/strutil.h>
|
||||
#include <google/protobuf/stubs/substitute.h>
|
||||
#include <google/protobuf/stubs/map-util.h>
|
||||
#include <google/protobuf/stubs/stl_util-inl.h>
|
||||
#include <google/protobuf/stubs/hash.h>
|
||||
#include <google/protobuf/stubs/stl_util.h>
|
||||
|
||||
|
||||
namespace google {
|
||||
@ -144,7 +146,7 @@ void AddTrailingSlash(string* path) {
|
||||
bool VerifyDirectoryExists(const string& path) {
|
||||
if (path.empty()) return true;
|
||||
|
||||
if (access(path.c_str(), W_OK) == -1) {
|
||||
if (access(path.c_str(), F_OK) == -1) {
|
||||
cerr << path << ": " << strerror(errno) << endl;
|
||||
return false;
|
||||
} else {
|
||||
@ -182,14 +184,23 @@ bool TryCreateParentDirectory(const string& prefix, const string& filename) {
|
||||
class CommandLineInterface::ErrorPrinter : public MultiFileErrorCollector,
|
||||
public io::ErrorCollector {
|
||||
public:
|
||||
ErrorPrinter(ErrorFormat format) : format_(format) {}
|
||||
ErrorPrinter(ErrorFormat format, DiskSourceTree *tree = NULL)
|
||||
: format_(format), tree_(tree) {}
|
||||
~ErrorPrinter() {}
|
||||
|
||||
// implements MultiFileErrorCollector ------------------------------
|
||||
void AddError(const string& filename, int line, int column,
|
||||
const string& message) {
|
||||
|
||||
cerr << filename;
|
||||
// Print full path when running under MSVS
|
||||
string dfile;
|
||||
if (format_ == CommandLineInterface::ERROR_FORMAT_MSVS &&
|
||||
tree_ != NULL &&
|
||||
tree_->VirtualFileToDiskFile(filename, &dfile)) {
|
||||
cerr << dfile;
|
||||
} else {
|
||||
cerr << filename;
|
||||
}
|
||||
|
||||
// Users typically expect 1-based line/column numbers, so we add 1
|
||||
// to each here.
|
||||
@ -215,16 +226,17 @@ class CommandLineInterface::ErrorPrinter : public MultiFileErrorCollector,
|
||||
|
||||
private:
|
||||
const ErrorFormat format_;
|
||||
DiskSourceTree *tree_;
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
// An OutputDirectory implementation that buffers files in memory, then dumps
|
||||
// A GeneratorContext implementation that buffers files in memory, then dumps
|
||||
// them all to disk on demand.
|
||||
class CommandLineInterface::MemoryOutputDirectory : public OutputDirectory {
|
||||
class CommandLineInterface::GeneratorContextImpl : public GeneratorContext {
|
||||
public:
|
||||
MemoryOutputDirectory();
|
||||
~MemoryOutputDirectory();
|
||||
GeneratorContextImpl(const vector<const FileDescriptor*>& parsed_files);
|
||||
~GeneratorContextImpl();
|
||||
|
||||
// Write all files in the directory to disk at the given output location,
|
||||
// which must end in a '/'.
|
||||
@ -238,10 +250,13 @@ class CommandLineInterface::MemoryOutputDirectory : public OutputDirectory {
|
||||
// format, unless one has already been written.
|
||||
void AddJarManifest();
|
||||
|
||||
// implements OutputDirectory --------------------------------------
|
||||
// implements GeneratorContext --------------------------------------
|
||||
io::ZeroCopyOutputStream* Open(const string& filename);
|
||||
io::ZeroCopyOutputStream* OpenForInsert(
|
||||
const string& filename, const string& insertion_point);
|
||||
void ListParsedFiles(vector<const FileDescriptor*>* output) {
|
||||
*output = parsed_files_;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class MemoryOutputStream;
|
||||
@ -249,14 +264,15 @@ class CommandLineInterface::MemoryOutputDirectory : public OutputDirectory {
|
||||
// map instead of hash_map so that files are written in order (good when
|
||||
// writing zips).
|
||||
map<string, string*> files_;
|
||||
const vector<const FileDescriptor*>& parsed_files_;
|
||||
bool had_error_;
|
||||
};
|
||||
|
||||
class CommandLineInterface::MemoryOutputStream
|
||||
: public io::ZeroCopyOutputStream {
|
||||
public:
|
||||
MemoryOutputStream(MemoryOutputDirectory* directory, const string& filename);
|
||||
MemoryOutputStream(MemoryOutputDirectory* directory, const string& filename,
|
||||
MemoryOutputStream(GeneratorContextImpl* directory, const string& filename);
|
||||
MemoryOutputStream(GeneratorContextImpl* directory, const string& filename,
|
||||
const string& insertion_point);
|
||||
virtual ~MemoryOutputStream();
|
||||
|
||||
@ -267,7 +283,7 @@ class CommandLineInterface::MemoryOutputStream
|
||||
|
||||
private:
|
||||
// Where to insert the string when it's done.
|
||||
MemoryOutputDirectory* directory_;
|
||||
GeneratorContextImpl* directory_;
|
||||
string filename_;
|
||||
string insertion_point_;
|
||||
|
||||
@ -280,14 +296,17 @@ class CommandLineInterface::MemoryOutputStream
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
CommandLineInterface::MemoryOutputDirectory::MemoryOutputDirectory()
|
||||
: had_error_(false) {}
|
||||
CommandLineInterface::GeneratorContextImpl::GeneratorContextImpl(
|
||||
const vector<const FileDescriptor*>& parsed_files)
|
||||
: parsed_files_(parsed_files),
|
||||
had_error_(false) {
|
||||
}
|
||||
|
||||
CommandLineInterface::MemoryOutputDirectory::~MemoryOutputDirectory() {
|
||||
CommandLineInterface::GeneratorContextImpl::~GeneratorContextImpl() {
|
||||
STLDeleteValues(&files_);
|
||||
}
|
||||
|
||||
bool CommandLineInterface::MemoryOutputDirectory::WriteAllToDisk(
|
||||
bool CommandLineInterface::GeneratorContextImpl::WriteAllToDisk(
|
||||
const string& prefix) {
|
||||
if (had_error_) {
|
||||
return false;
|
||||
@ -362,7 +381,7 @@ bool CommandLineInterface::MemoryOutputDirectory::WriteAllToDisk(
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CommandLineInterface::MemoryOutputDirectory::WriteAllToZip(
|
||||
bool CommandLineInterface::GeneratorContextImpl::WriteAllToZip(
|
||||
const string& filename) {
|
||||
if (had_error_) {
|
||||
return false;
|
||||
@ -403,7 +422,7 @@ bool CommandLineInterface::MemoryOutputDirectory::WriteAllToZip(
|
||||
return true;
|
||||
}
|
||||
|
||||
void CommandLineInterface::MemoryOutputDirectory::AddJarManifest() {
|
||||
void CommandLineInterface::GeneratorContextImpl::AddJarManifest() {
|
||||
string** map_slot = &files_["META-INF/MANIFEST.MF"];
|
||||
if (*map_slot == NULL) {
|
||||
*map_slot = new string(
|
||||
@ -413,13 +432,13 @@ void CommandLineInterface::MemoryOutputDirectory::AddJarManifest() {
|
||||
}
|
||||
}
|
||||
|
||||
io::ZeroCopyOutputStream* CommandLineInterface::MemoryOutputDirectory::Open(
|
||||
io::ZeroCopyOutputStream* CommandLineInterface::GeneratorContextImpl::Open(
|
||||
const string& filename) {
|
||||
return new MemoryOutputStream(this, filename);
|
||||
}
|
||||
|
||||
io::ZeroCopyOutputStream*
|
||||
CommandLineInterface::MemoryOutputDirectory::OpenForInsert(
|
||||
CommandLineInterface::GeneratorContextImpl::OpenForInsert(
|
||||
const string& filename, const string& insertion_point) {
|
||||
return new MemoryOutputStream(this, filename, insertion_point);
|
||||
}
|
||||
@ -427,14 +446,14 @@ CommandLineInterface::MemoryOutputDirectory::OpenForInsert(
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
CommandLineInterface::MemoryOutputStream::MemoryOutputStream(
|
||||
MemoryOutputDirectory* directory, const string& filename)
|
||||
GeneratorContextImpl* directory, const string& filename)
|
||||
: directory_(directory),
|
||||
filename_(filename),
|
||||
inner_(new io::StringOutputStream(&data_)) {
|
||||
}
|
||||
|
||||
CommandLineInterface::MemoryOutputStream::MemoryOutputStream(
|
||||
MemoryOutputDirectory* directory, const string& filename,
|
||||
GeneratorContextImpl* directory, const string& filename,
|
||||
const string& insertion_point)
|
||||
: directory_(directory),
|
||||
filename_(filename),
|
||||
@ -548,6 +567,7 @@ CommandLineInterface::CommandLineInterface()
|
||||
: mode_(MODE_COMPILE),
|
||||
error_format_(ERROR_FORMAT_GCC),
|
||||
imports_in_descriptor_set_(false),
|
||||
source_info_in_descriptor_set_(false),
|
||||
disallow_services_(false),
|
||||
inputs_are_proto_path_relative_(false) {}
|
||||
CommandLineInterface::~CommandLineInterface() {}
|
||||
@ -556,9 +576,23 @@ void CommandLineInterface::RegisterGenerator(const string& flag_name,
|
||||
CodeGenerator* generator,
|
||||
const string& help_text) {
|
||||
GeneratorInfo info;
|
||||
info.flag_name = flag_name;
|
||||
info.generator = generator;
|
||||
info.help_text = help_text;
|
||||
generators_[flag_name] = info;
|
||||
generators_by_flag_name_[flag_name] = info;
|
||||
}
|
||||
|
||||
void CommandLineInterface::RegisterGenerator(const string& flag_name,
|
||||
const string& option_flag_name,
|
||||
CodeGenerator* generator,
|
||||
const 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 string& exe_name_prefix) {
|
||||
@ -567,7 +601,14 @@ void CommandLineInterface::AllowPlugins(const string& exe_name_prefix) {
|
||||
|
||||
int CommandLineInterface::Run(int argc, const char* const argv[]) {
|
||||
Clear();
|
||||
if (!ParseArguments(argc, argv)) return 1;
|
||||
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;
|
||||
}
|
||||
|
||||
// Set up the source tree.
|
||||
DiskSourceTree source_tree;
|
||||
@ -583,7 +624,7 @@ int CommandLineInterface::Run(int argc, const char* const argv[]) {
|
||||
}
|
||||
|
||||
// Allocate the Importer.
|
||||
ErrorPrinter error_collector(error_format_);
|
||||
ErrorPrinter error_collector(error_format_, &source_tree);
|
||||
Importer importer(&source_tree, &error_collector);
|
||||
|
||||
vector<const FileDescriptor*> parsed_files;
|
||||
@ -603,11 +644,11 @@ int CommandLineInterface::Run(int argc, const char* const argv[]) {
|
||||
}
|
||||
}
|
||||
|
||||
// We construct a separate OutputDirectory for each output location. Note
|
||||
// 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 OutputDirectory (so that OpenForInsert() works).
|
||||
typedef hash_map<string, MemoryOutputDirectory*> OutputDirectoryMap;
|
||||
OutputDirectoryMap output_directories;
|
||||
// they should share a single GeneratorContext so that OpenForInsert() works.
|
||||
typedef hash_map<string, GeneratorContextImpl*> GeneratorContextMap;
|
||||
GeneratorContextMap output_directories;
|
||||
|
||||
// Generate output.
|
||||
if (mode_ == MODE_COMPILE) {
|
||||
@ -617,11 +658,11 @@ int CommandLineInterface::Run(int argc, const char* const argv[]) {
|
||||
!HasSuffixString(output_location, ".jar")) {
|
||||
AddTrailingSlash(&output_location);
|
||||
}
|
||||
MemoryOutputDirectory** map_slot = &output_directories[output_location];
|
||||
GeneratorContextImpl** map_slot = &output_directories[output_location];
|
||||
|
||||
if (*map_slot == NULL) {
|
||||
// First time we've seen this output location.
|
||||
*map_slot = new MemoryOutputDirectory;
|
||||
*map_slot = new GeneratorContextImpl(parsed_files);
|
||||
}
|
||||
|
||||
if (!GenerateOutput(parsed_files, output_directives_[i], *map_slot)) {
|
||||
@ -632,10 +673,10 @@ int CommandLineInterface::Run(int argc, const char* const argv[]) {
|
||||
}
|
||||
|
||||
// Write all output to disk.
|
||||
for (OutputDirectoryMap::iterator iter = output_directories.begin();
|
||||
for (GeneratorContextMap::iterator iter = output_directories.begin();
|
||||
iter != output_directories.end(); ++iter) {
|
||||
const string& location = iter->first;
|
||||
MemoryOutputDirectory* directory = iter->second;
|
||||
GeneratorContextImpl* directory = iter->second;
|
||||
if (HasSuffixString(location, "/")) {
|
||||
if (!directory->WriteAllToDisk(location)) {
|
||||
STLDeleteValues(&output_directories);
|
||||
@ -695,6 +736,7 @@ void CommandLineInterface::Clear() {
|
||||
|
||||
mode_ = MODE_COMPILE;
|
||||
imports_in_descriptor_set_ = false;
|
||||
source_info_in_descriptor_set_ = false;
|
||||
disallow_services_ = false;
|
||||
}
|
||||
|
||||
@ -737,7 +779,8 @@ bool CommandLineInterface::MakeInputsBeProtoPathRelative(
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CommandLineInterface::ParseArguments(int argc, const char* const argv[]) {
|
||||
CommandLineInterface::ParseArgumentStatus
|
||||
CommandLineInterface::ParseArguments(int argc, const char* const argv[]) {
|
||||
executable_name_ = argv[0];
|
||||
|
||||
// Iterate through all arguments and parse them.
|
||||
@ -751,41 +794,50 @@ bool CommandLineInterface::ParseArguments(int argc, const char* const argv[]) {
|
||||
if (name == "--decode") {
|
||||
cerr << "To decode an unknown message, use --decode_raw." << endl;
|
||||
}
|
||||
return false;
|
||||
return PARSE_ARGUMENT_FAIL;
|
||||
} else {
|
||||
++i;
|
||||
value = argv[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (!InterpretArgument(name, value)) return false;
|
||||
ParseArgumentStatus status = InterpretArgument(name, value);
|
||||
if (status != PARSE_ARGUMENT_DONE_AND_CONTINUE)
|
||||
return status;
|
||||
}
|
||||
|
||||
// If no --proto_path was given, use the current working directory.
|
||||
if (proto_path_.empty()) {
|
||||
proto_path_.push_back(make_pair("", "."));
|
||||
// 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(pair<string, string>("", "."));
|
||||
}
|
||||
|
||||
// Check some errror cases.
|
||||
bool decoding_raw = (mode_ == MODE_DECODE) && codec_type_.empty();
|
||||
if (decoding_raw && !input_files_.empty()) {
|
||||
cerr << "When using --decode_raw, no input files should be given." << endl;
|
||||
return false;
|
||||
return PARSE_ARGUMENT_FAIL;
|
||||
} else if (!decoding_raw && input_files_.empty()) {
|
||||
cerr << "Missing input file." << endl;
|
||||
return false;
|
||||
return PARSE_ARGUMENT_FAIL;
|
||||
}
|
||||
if (mode_ == MODE_COMPILE && output_directives_.empty() &&
|
||||
descriptor_set_name_.empty()) {
|
||||
cerr << "Missing output directives." << endl;
|
||||
return false;
|
||||
return PARSE_ARGUMENT_FAIL;
|
||||
}
|
||||
if (imports_in_descriptor_set_ && descriptor_set_name_.empty()) {
|
||||
cerr << "--include_imports only makes sense when combined with "
|
||||
"--descriptor_set_out." << endl;
|
||||
}
|
||||
if (source_info_in_descriptor_set_ && descriptor_set_name_.empty()) {
|
||||
cerr << "--include_source_info only makes sense when combined with "
|
||||
"--descriptor_set_out." << endl;
|
||||
}
|
||||
|
||||
return true;
|
||||
return PARSE_ARGUMENT_DONE_AND_CONTINUE;
|
||||
}
|
||||
|
||||
bool CommandLineInterface::ParseArgument(const char* arg,
|
||||
@ -835,6 +887,7 @@ bool CommandLineInterface::ParseArgument(const char* arg,
|
||||
if (*name == "-h" || *name == "--help" ||
|
||||
*name == "--disallow_services" ||
|
||||
*name == "--include_imports" ||
|
||||
*name == "--include_source_info" ||
|
||||
*name == "--version" ||
|
||||
*name == "--decode_raw") {
|
||||
// HACK: These are the only flags that don't take a value.
|
||||
@ -847,8 +900,9 @@ bool CommandLineInterface::ParseArgument(const char* arg,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CommandLineInterface::InterpretArgument(const string& name,
|
||||
const string& value) {
|
||||
CommandLineInterface::ParseArgumentStatus
|
||||
CommandLineInterface::InterpretArgument(const string& name,
|
||||
const string& value) {
|
||||
if (name.empty()) {
|
||||
// Not a flag. Just a filename.
|
||||
if (value.empty()) {
|
||||
@ -856,7 +910,7 @@ bool CommandLineInterface::InterpretArgument(const string& name,
|
||||
"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." << endl;
|
||||
return false;
|
||||
return PARSE_ARGUMENT_FAIL;
|
||||
}
|
||||
|
||||
input_files_.push_back(value);
|
||||
@ -872,7 +926,7 @@ bool CommandLineInterface::InterpretArgument(const string& name,
|
||||
string virtual_path;
|
||||
string disk_path;
|
||||
|
||||
int equals_pos = parts[i].find_first_of('=');
|
||||
string::size_type equals_pos = parts[i].find_first_of('=');
|
||||
if (equals_pos == string::npos) {
|
||||
virtual_path = "";
|
||||
disk_path = parts[i];
|
||||
@ -884,7 +938,7 @@ bool CommandLineInterface::InterpretArgument(const string& name,
|
||||
if (disk_path.empty()) {
|
||||
cerr << "--proto_path passed empty directory name. (Use \".\" for "
|
||||
"current directory.)" << endl;
|
||||
return false;
|
||||
return PARSE_ARGUMENT_FAIL;
|
||||
}
|
||||
|
||||
// Make sure disk path exists, warn otherwise.
|
||||
@ -892,35 +946,45 @@ bool CommandLineInterface::InterpretArgument(const string& name,
|
||||
cerr << disk_path << ": warning: directory does not exist." << endl;
|
||||
}
|
||||
|
||||
proto_path_.push_back(make_pair(virtual_path, disk_path));
|
||||
// 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(pair<string, string>(virtual_path, disk_path));
|
||||
}
|
||||
|
||||
} else if (name == "-o" || name == "--descriptor_set_out") {
|
||||
if (!descriptor_set_name_.empty()) {
|
||||
cerr << name << " may only be passed once." << endl;
|
||||
return false;
|
||||
return PARSE_ARGUMENT_FAIL;
|
||||
}
|
||||
if (value.empty()) {
|
||||
cerr << name << " requires a non-empty value." << endl;
|
||||
return false;
|
||||
return PARSE_ARGUMENT_FAIL;
|
||||
}
|
||||
if (mode_ != MODE_COMPILE) {
|
||||
cerr << "Cannot use --encode or --decode and generate descriptors at the "
|
||||
"same time." << endl;
|
||||
return false;
|
||||
return PARSE_ARGUMENT_FAIL;
|
||||
}
|
||||
descriptor_set_name_ = value;
|
||||
|
||||
} else if (name == "--include_imports") {
|
||||
if (imports_in_descriptor_set_) {
|
||||
cerr << name << " may only be passed once." << endl;
|
||||
return false;
|
||||
return PARSE_ARGUMENT_FAIL;
|
||||
}
|
||||
imports_in_descriptor_set_ = true;
|
||||
|
||||
} else if (name == "--include_source_info") {
|
||||
if (source_info_in_descriptor_set_) {
|
||||
cerr << name << " may only be passed once." << endl;
|
||||
return PARSE_ARGUMENT_FAIL;
|
||||
}
|
||||
source_info_in_descriptor_set_ = true;
|
||||
|
||||
} else if (name == "-h" || name == "--help") {
|
||||
PrintHelpText();
|
||||
return false; // Exit without running compiler.
|
||||
return PARSE_ARGUMENT_DONE_AND_EXIT; // Exit without running compiler.
|
||||
|
||||
} else if (name == "--version") {
|
||||
if (!version_info_.empty()) {
|
||||
@ -929,7 +993,7 @@ bool CommandLineInterface::InterpretArgument(const string& name,
|
||||
cout << "libprotoc "
|
||||
<< protobuf::internal::VersionString(GOOGLE_PROTOBUF_VERSION)
|
||||
<< endl;
|
||||
return false; // Exit without running compiler.
|
||||
return PARSE_ARGUMENT_DONE_AND_EXIT; // Exit without running compiler.
|
||||
|
||||
} else if (name == "--disallow_services") {
|
||||
disallow_services_ = true;
|
||||
@ -938,12 +1002,12 @@ bool CommandLineInterface::InterpretArgument(const string& name,
|
||||
name == "--decode_raw") {
|
||||
if (mode_ != MODE_COMPILE) {
|
||||
cerr << "Only one of --encode and --decode can be specified." << endl;
|
||||
return false;
|
||||
return PARSE_ARGUMENT_FAIL;
|
||||
}
|
||||
if (!output_directives_.empty() || !descriptor_set_name_.empty()) {
|
||||
cerr << "Cannot use " << name
|
||||
<< " and generate code or descriptors at the same time." << endl;
|
||||
return false;
|
||||
return PARSE_ARGUMENT_FAIL;
|
||||
}
|
||||
|
||||
mode_ = (name == "--encode") ? MODE_ENCODE : MODE_DECODE;
|
||||
@ -953,10 +1017,10 @@ bool CommandLineInterface::InterpretArgument(const string& name,
|
||||
if (name == "--decode") {
|
||||
cerr << "To decode an unknown message, use --decode_raw." << endl;
|
||||
}
|
||||
return false;
|
||||
return PARSE_ARGUMENT_FAIL;
|
||||
} else if (!value.empty() && name == "--decode_raw") {
|
||||
cerr << "--decode_raw does not take a parameter." << endl;
|
||||
return false;
|
||||
return PARSE_ARGUMENT_FAIL;
|
||||
}
|
||||
|
||||
codec_type_ = value;
|
||||
@ -968,16 +1032,16 @@ bool CommandLineInterface::InterpretArgument(const string& name,
|
||||
error_format_ = ERROR_FORMAT_MSVS;
|
||||
} else {
|
||||
cerr << "Unknown error format: " << value << endl;
|
||||
return false;
|
||||
return PARSE_ARGUMENT_FAIL;
|
||||
}
|
||||
|
||||
} else if (name == "--plugin") {
|
||||
if (plugin_prefix_.empty()) {
|
||||
cerr << "This compiler does not support plugins." << endl;
|
||||
return false;
|
||||
return PARSE_ARGUMENT_FAIL;
|
||||
}
|
||||
|
||||
string name;
|
||||
string plugin_name;
|
||||
string path;
|
||||
|
||||
string::size_type equals_pos = value.find_first_of('=');
|
||||
@ -985,57 +1049,68 @@ bool CommandLineInterface::InterpretArgument(const string& name,
|
||||
// Use the basename of the file.
|
||||
string::size_type slash_pos = value.find_last_of('/');
|
||||
if (slash_pos == string::npos) {
|
||||
name = value;
|
||||
plugin_name = value;
|
||||
} else {
|
||||
name = value.substr(slash_pos + 1);
|
||||
plugin_name = value.substr(slash_pos + 1);
|
||||
}
|
||||
path = value;
|
||||
} else {
|
||||
name = value.substr(0, equals_pos);
|
||||
plugin_name = value.substr(0, equals_pos);
|
||||
path = value.substr(equals_pos + 1);
|
||||
}
|
||||
|
||||
plugins_[name] = path;
|
||||
plugins_[plugin_name] = path;
|
||||
|
||||
} else {
|
||||
// Some other flag. Look it up in the generators list.
|
||||
const GeneratorInfo* generator_info = FindOrNull(generators_, name);
|
||||
const GeneratorInfo* generator_info =
|
||||
FindOrNull(generators_by_flag_name_, name);
|
||||
if (generator_info == NULL &&
|
||||
(plugin_prefix_.empty() || !HasSuffixString(name, "_out"))) {
|
||||
cerr << "Unknown flag: " << name << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// It's an output flag. Add it to the output directives.
|
||||
if (mode_ != MODE_COMPILE) {
|
||||
cerr << "Cannot use --encode or --decode and generate code at the "
|
||||
"same time." << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
OutputDirective directive;
|
||||
directive.name = name;
|
||||
if (generator_info == NULL) {
|
||||
directive.generator = NULL;
|
||||
// Check if it's a generator option flag.
|
||||
generator_info = FindOrNull(generators_by_option_name_, name);
|
||||
if (generator_info == NULL) {
|
||||
cerr << "Unknown flag: " << name << endl;
|
||||
return PARSE_ARGUMENT_FAIL;
|
||||
} else {
|
||||
string* parameters = &generator_parameters_[generator_info->flag_name];
|
||||
if (!parameters->empty()) {
|
||||
parameters->append(",");
|
||||
}
|
||||
parameters->append(value);
|
||||
}
|
||||
} else {
|
||||
directive.generator = generator_info->generator;
|
||||
}
|
||||
// It's an output flag. Add it to the output directives.
|
||||
if (mode_ != MODE_COMPILE) {
|
||||
cerr << "Cannot use --encode or --decode and generate code at the "
|
||||
"same time." << endl;
|
||||
return PARSE_ARGUMENT_FAIL;
|
||||
}
|
||||
|
||||
// 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.
|
||||
string::size_type colon_pos = value.find_first_of(':');
|
||||
if (colon_pos == string::npos || IsWindowsAbsolutePath(value)) {
|
||||
directive.output_location = value;
|
||||
} else {
|
||||
directive.parameter = value.substr(0, colon_pos);
|
||||
directive.output_location = value.substr(colon_pos + 1);
|
||||
}
|
||||
OutputDirective directive;
|
||||
directive.name = name;
|
||||
if (generator_info == NULL) {
|
||||
directive.generator = NULL;
|
||||
} else {
|
||||
directive.generator = generator_info->generator;
|
||||
}
|
||||
|
||||
output_directives_.push_back(directive);
|
||||
// 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.
|
||||
string::size_type colon_pos = value.find_first_of(':');
|
||||
if (colon_pos == 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 true;
|
||||
return PARSE_ARGUMENT_DONE_AND_CONTINUE;
|
||||
}
|
||||
|
||||
void CommandLineInterface::PrintHelpText() {
|
||||
@ -1068,6 +1143,12 @@ void CommandLineInterface::PrintHelpText() {
|
||||
" --include_imports When using --descriptor_set_out, also include\n"
|
||||
" all dependencies of the input files in the\n"
|
||||
" set, so that the set is self-contained.\n"
|
||||
" --include_source_info When using --descriptor_set_out, do not strip\n"
|
||||
" SourceCodeInfo from the FileDescriptorProto.\n"
|
||||
" This results in vastly larger descriptors that\n"
|
||||
" include information about the original\n"
|
||||
" location of each decl in the source file as\n"
|
||||
" well as surrounding comments.\n"
|
||||
" --error_format=FORMAT Set the format in which to print errors.\n"
|
||||
" FORMAT may be 'gcc' (the default) or 'msvs'\n"
|
||||
" (Microsoft Visual Studio format)." << endl;
|
||||
@ -1083,8 +1164,8 @@ void CommandLineInterface::PrintHelpText() {
|
||||
" the executable's own name differs." << endl;
|
||||
}
|
||||
|
||||
for (GeneratorMap::iterator iter = generators_.begin();
|
||||
iter != generators_.end(); ++iter) {
|
||||
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.
|
||||
@ -1097,7 +1178,7 @@ void CommandLineInterface::PrintHelpText() {
|
||||
bool CommandLineInterface::GenerateOutput(
|
||||
const vector<const FileDescriptor*>& parsed_files,
|
||||
const OutputDirective& output_directive,
|
||||
OutputDirectory* output_directory) {
|
||||
GeneratorContext* generator_context) {
|
||||
// Call the generator.
|
||||
string error;
|
||||
if (output_directive.generator == NULL) {
|
||||
@ -1112,16 +1193,22 @@ bool CommandLineInterface::GenerateOutput(
|
||||
|
||||
if (!GeneratePluginOutput(parsed_files, plugin_name,
|
||||
output_directive.parameter,
|
||||
output_directory, &error)) {
|
||||
generator_context, &error)) {
|
||||
cerr << output_directive.name << ": " << error << endl;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// Regular generator.
|
||||
string parameters = output_directive.parameter;
|
||||
if (!generator_parameters_[output_directive.name].empty()) {
|
||||
if (!parameters.empty()) {
|
||||
parameters.append(",");
|
||||
}
|
||||
parameters.append(generator_parameters_[output_directive.name]);
|
||||
}
|
||||
for (int i = 0; i < parsed_files.size(); i++) {
|
||||
if (!output_directive.generator->Generate(
|
||||
parsed_files[i], output_directive.parameter,
|
||||
output_directory, &error)) {
|
||||
if (!output_directive.generator->Generate(parsed_files[i], parameters,
|
||||
generator_context, &error)) {
|
||||
// Generator returned an error.
|
||||
cerr << output_directive.name << ": " << parsed_files[i]->name() << ": "
|
||||
<< error << endl;
|
||||
@ -1137,7 +1224,7 @@ bool CommandLineInterface::GeneratePluginOutput(
|
||||
const vector<const FileDescriptor*>& parsed_files,
|
||||
const string& plugin_name,
|
||||
const string& parameter,
|
||||
OutputDirectory* output_directory,
|
||||
GeneratorContext* generator_context,
|
||||
string* error) {
|
||||
CodeGeneratorRequest request;
|
||||
CodeGeneratorResponse response;
|
||||
@ -1150,8 +1237,9 @@ bool CommandLineInterface::GeneratePluginOutput(
|
||||
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], &already_seen,
|
||||
request.mutable_proto_file());
|
||||
GetTransitiveDependencies(parsed_files[i],
|
||||
true, // Include source code info.
|
||||
&already_seen, request.mutable_proto_file());
|
||||
}
|
||||
|
||||
// Invoke the plugin.
|
||||
@ -1180,14 +1268,14 @@ bool CommandLineInterface::GeneratePluginOutput(
|
||||
// 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(output_directory->OpenForInsert(
|
||||
current_output.reset(generator_context->OpenForInsert(
|
||||
output_file.name(), output_file.insertion_point()));
|
||||
} 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(output_directory->Open(output_file.name()));
|
||||
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.",
|
||||
@ -1281,12 +1369,17 @@ bool CommandLineInterface::WriteDescriptorSet(
|
||||
if (imports_in_descriptor_set_) {
|
||||
set<const FileDescriptor*> already_seen;
|
||||
for (int i = 0; i < parsed_files.size(); i++) {
|
||||
GetTransitiveDependencies(
|
||||
parsed_files[i], &already_seen, file_set.mutable_file());
|
||||
GetTransitiveDependencies(parsed_files[i],
|
||||
source_info_in_descriptor_set_,
|
||||
&already_seen, file_set.mutable_file());
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < parsed_files.size(); i++) {
|
||||
parsed_files[i]->CopyTo(file_set.add_file());
|
||||
FileDescriptorProto* file_proto = file_set.add_file();
|
||||
parsed_files[i]->CopyTo(file_proto);
|
||||
if (source_info_in_descriptor_set_) {
|
||||
parsed_files[i]->CopySourceCodeInfoTo(file_proto);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1316,7 +1409,7 @@ bool CommandLineInterface::WriteDescriptorSet(
|
||||
}
|
||||
|
||||
void CommandLineInterface::GetTransitiveDependencies(
|
||||
const FileDescriptor* file,
|
||||
const FileDescriptor* file, bool include_source_code_info,
|
||||
set<const FileDescriptor*>* already_seen,
|
||||
RepeatedPtrField<FileDescriptorProto>* output) {
|
||||
if (!already_seen->insert(file).second) {
|
||||
@ -1326,11 +1419,16 @@ void CommandLineInterface::GetTransitiveDependencies(
|
||||
|
||||
// Add all dependencies.
|
||||
for (int i = 0; i < file->dependency_count(); i++) {
|
||||
GetTransitiveDependencies(file->dependency(i), already_seen, output);
|
||||
GetTransitiveDependencies(file->dependency(i), include_source_code_info,
|
||||
already_seen, output);
|
||||
}
|
||||
|
||||
// Add this file.
|
||||
file->CopyTo(output->Add());
|
||||
FileDescriptorProto* new_descriptor = output->Add();
|
||||
file->CopyTo(new_descriptor);
|
||||
if (include_source_code_info) {
|
||||
file->CopySourceCodeInfoTo(new_descriptor);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -56,7 +56,7 @@ template<typename T> class RepeatedPtrField; // repeated_field.h
|
||||
namespace compiler {
|
||||
|
||||
class CodeGenerator; // code_generator.h
|
||||
class OutputDirectory; // code_generator.h
|
||||
class GeneratorContext; // code_generator.h
|
||||
class DiskSourceTree; // importer.h
|
||||
|
||||
// This class implements the command-line interface to the protocol compiler.
|
||||
@ -112,6 +112,19 @@ class LIBPROTOC_EXPORT CommandLineInterface {
|
||||
CodeGenerator* generator,
|
||||
const 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 string& flag_name,
|
||||
const string& option_flag_name,
|
||||
CodeGenerator* generator,
|
||||
const 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.
|
||||
@ -174,7 +187,7 @@ class LIBPROTOC_EXPORT CommandLineInterface {
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
class ErrorPrinter;
|
||||
class MemoryOutputDirectory;
|
||||
class GeneratorContextImpl;
|
||||
class MemoryOutputStream;
|
||||
|
||||
// Clear state from previous Run().
|
||||
@ -186,8 +199,15 @@ class LIBPROTOC_EXPORT CommandLineInterface {
|
||||
bool MakeInputsBeProtoPathRelative(
|
||||
DiskSourceTree* source_tree);
|
||||
|
||||
// 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.
|
||||
bool ParseArguments(int argc, const char* const argv[]);
|
||||
ParseArgumentStatus ParseArguments(int argc, const char* const argv[]);
|
||||
|
||||
// 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,
|
||||
@ -203,7 +223,8 @@ class LIBPROTOC_EXPORT CommandLineInterface {
|
||||
bool ParseArgument(const char* arg, string* name, string* value);
|
||||
|
||||
// Interprets arguments parsed with ParseArgument.
|
||||
bool InterpretArgument(const string& name, const string& value);
|
||||
ParseArgumentStatus InterpretArgument(const string& name,
|
||||
const string& value);
|
||||
|
||||
// Print the --help text to stderr.
|
||||
void PrintHelpText();
|
||||
@ -212,11 +233,11 @@ class LIBPROTOC_EXPORT CommandLineInterface {
|
||||
struct OutputDirective; // see below
|
||||
bool GenerateOutput(const vector<const FileDescriptor*>& parsed_files,
|
||||
const OutputDirective& output_directive,
|
||||
OutputDirectory* output_directory);
|
||||
GeneratorContext* generator_context);
|
||||
bool GeneratePluginOutput(const vector<const FileDescriptor*>& parsed_files,
|
||||
const string& plugin_name,
|
||||
const string& parameter,
|
||||
OutputDirectory* output_directory,
|
||||
GeneratorContext* generator_context,
|
||||
string* error);
|
||||
|
||||
// Implements --encode and --decode.
|
||||
@ -230,9 +251,11 @@ class LIBPROTOC_EXPORT CommandLineInterface {
|
||||
// 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.
|
||||
// added will be inserted into *already_seen. If include_source_code_info is
|
||||
// true then include the source code information in the FileDescriptorProtos.
|
||||
static void GetTransitiveDependencies(
|
||||
const FileDescriptor* file,
|
||||
bool include_source_code_info,
|
||||
set<const FileDescriptor*>* already_seen,
|
||||
RepeatedPtrField<FileDescriptorProto>* output);
|
||||
|
||||
@ -244,13 +267,21 @@ class LIBPROTOC_EXPORT CommandLineInterface {
|
||||
// Version info set with SetVersionInfo().
|
||||
string version_info_;
|
||||
|
||||
// Map from flag names to registered generators.
|
||||
// Registered generators.
|
||||
struct GeneratorInfo {
|
||||
string flag_name;
|
||||
string option_flag_name;
|
||||
CodeGenerator* generator;
|
||||
string help_text;
|
||||
};
|
||||
typedef map<string, GeneratorInfo> GeneratorMap;
|
||||
GeneratorMap generators_;
|
||||
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.
|
||||
map<string, string> generator_parameters_;
|
||||
|
||||
// See AllowPlugins(). If this is empty, plugins aren't allowed.
|
||||
string plugin_prefix_;
|
||||
@ -302,6 +333,10 @@ class LIBPROTOC_EXPORT CommandLineInterface {
|
||||
// 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_;
|
||||
|
||||
// Was the --disallow_services flag used?
|
||||
bool disallow_services_;
|
||||
|
@ -48,6 +48,7 @@
|
||||
#include <google/protobuf/compiler/command_line_interface.h>
|
||||
#include <google/protobuf/compiler/code_generator.h>
|
||||
#include <google/protobuf/compiler/mock_code_generator.h>
|
||||
#include <google/protobuf/compiler/subprocess.h>
|
||||
#include <google/protobuf/io/printer.h>
|
||||
#include <google/protobuf/unittest.pb.h>
|
||||
#include <google/protobuf/testing/file.h>
|
||||
@ -121,6 +122,10 @@ class CommandLineInterfaceTest : public testing::Test {
|
||||
// substring.
|
||||
void ExpectErrorSubstring(const string& expected_substring);
|
||||
|
||||
// Like ExpectErrorSubstring, but checks that Run() returned zero.
|
||||
void ExpectErrorSubstringWithZeroReturnCode(
|
||||
const string& expected_substring);
|
||||
|
||||
// Returns true if ExpectErrorSubstring(expected_substring) would pass, but
|
||||
// does not fail otherwise.
|
||||
bool HasAlternateErrorSubstring(const string& expected_substring);
|
||||
@ -143,6 +148,10 @@ class CommandLineInterfaceTest : public testing::Test {
|
||||
const string& proto_name,
|
||||
const string& message_name,
|
||||
const string& output_directory);
|
||||
void ExpectGeneratedWithMultipleInputs(const string& generator_name,
|
||||
const string& all_proto_names,
|
||||
const string& proto_name,
|
||||
const string& message_name);
|
||||
void ExpectGeneratedWithInsertions(const string& generator_name,
|
||||
const string& parameter,
|
||||
const string& insertions,
|
||||
@ -190,7 +199,7 @@ class CommandLineInterfaceTest::NullCodeGenerator : public CodeGenerator {
|
||||
// implements CodeGenerator ----------------------------------------
|
||||
bool Generate(const FileDescriptor* file,
|
||||
const string& parameter,
|
||||
OutputDirectory* output_directory,
|
||||
GeneratorContext* context,
|
||||
string* error) const {
|
||||
called_ = true;
|
||||
parameter_ = parameter;
|
||||
@ -220,7 +229,7 @@ void CommandLineInterfaceTest::SetUp() {
|
||||
// Register generators.
|
||||
CodeGenerator* generator = new MockCodeGenerator("test_generator");
|
||||
mock_generators_to_delete_.push_back(generator);
|
||||
cli_.RegisterGenerator("--test_out", generator, "Test output.");
|
||||
cli_.RegisterGenerator("--test_out", "--test_opt", generator, "Test output.");
|
||||
cli_.RegisterGenerator("-t", generator, "Test output.");
|
||||
|
||||
generator = new MockCodeGenerator("alt_generator");
|
||||
@ -251,7 +260,6 @@ void CommandLineInterfaceTest::Run(const string& command) {
|
||||
|
||||
if (!disallow_plugins_) {
|
||||
cli_.AllowPlugins("prefix-");
|
||||
|
||||
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.
|
||||
@ -341,6 +349,12 @@ void CommandLineInterfaceTest::ExpectErrorSubstring(
|
||||
EXPECT_PRED_FORMAT2(testing::IsSubstring, expected_substring, error_text_);
|
||||
}
|
||||
|
||||
void CommandLineInterfaceTest::ExpectErrorSubstringWithZeroReturnCode(
|
||||
const string& expected_substring) {
|
||||
EXPECT_EQ(0, return_code_);
|
||||
EXPECT_PRED_FORMAT2(testing::IsSubstring, expected_substring, error_text_);
|
||||
}
|
||||
|
||||
bool CommandLineInterfaceTest::HasAlternateErrorSubstring(
|
||||
const string& expected_substring) {
|
||||
EXPECT_NE(0, return_code_);
|
||||
@ -353,7 +367,8 @@ void CommandLineInterfaceTest::ExpectGenerated(
|
||||
const string& proto_name,
|
||||
const string& message_name) {
|
||||
MockCodeGenerator::ExpectGenerated(
|
||||
generator_name, parameter, "", proto_name, message_name, temp_directory_);
|
||||
generator_name, parameter, "", proto_name, message_name, proto_name,
|
||||
temp_directory_);
|
||||
}
|
||||
|
||||
void CommandLineInterfaceTest::ExpectGenerated(
|
||||
@ -363,10 +378,21 @@ void CommandLineInterfaceTest::ExpectGenerated(
|
||||
const string& message_name,
|
||||
const string& output_directory) {
|
||||
MockCodeGenerator::ExpectGenerated(
|
||||
generator_name, parameter, "", proto_name, message_name,
|
||||
generator_name, parameter, "", proto_name, message_name, proto_name,
|
||||
temp_directory_ + "/" + output_directory);
|
||||
}
|
||||
|
||||
void CommandLineInterfaceTest::ExpectGeneratedWithMultipleInputs(
|
||||
const string& generator_name,
|
||||
const string& all_proto_names,
|
||||
const string& proto_name,
|
||||
const string& message_name) {
|
||||
MockCodeGenerator::ExpectGenerated(
|
||||
generator_name, "", "", proto_name, message_name,
|
||||
all_proto_names,
|
||||
temp_directory_);
|
||||
}
|
||||
|
||||
void CommandLineInterfaceTest::ExpectGeneratedWithInsertions(
|
||||
const string& generator_name,
|
||||
const string& parameter,
|
||||
@ -375,7 +401,7 @@ void CommandLineInterfaceTest::ExpectGeneratedWithInsertions(
|
||||
const string& message_name) {
|
||||
MockCodeGenerator::ExpectGenerated(
|
||||
generator_name, parameter, insertions, proto_name, message_name,
|
||||
temp_directory_);
|
||||
proto_name, temp_directory_);
|
||||
}
|
||||
|
||||
void CommandLineInterfaceTest::ExpectNullCodeGeneratorCalled(
|
||||
@ -455,8 +481,44 @@ TEST_F(CommandLineInterfaceTest, MultipleInputs) {
|
||||
"--proto_path=$tmpdir foo.proto bar.proto");
|
||||
|
||||
ExpectNoErrors();
|
||||
ExpectGenerated("test_generator", "", "foo.proto", "Foo");
|
||||
ExpectGenerated("test_generator", "", "bar.proto", "Bar");
|
||||
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) {
|
||||
// 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, CreateDirectory) {
|
||||
@ -492,6 +554,32 @@ TEST_F(CommandLineInterfaceTest, GeneratorParameters) {
|
||||
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, Insert) {
|
||||
// Test running a generator that inserts code into another's output.
|
||||
|
||||
@ -515,7 +603,7 @@ TEST_F(CommandLineInterfaceTest, Insert) {
|
||||
"foo.proto", "Foo");
|
||||
}
|
||||
|
||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||
#if defined(_WIN32)
|
||||
|
||||
TEST_F(CommandLineInterfaceTest, WindowsOutputPath) {
|
||||
// Test that the output path can be a Windows-style path.
|
||||
@ -727,6 +815,33 @@ TEST_F(CommandLineInterfaceTest, WriteDescriptorSet) {
|
||||
if (HasFatalFailure()) return;
|
||||
ASSERT_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());
|
||||
}
|
||||
|
||||
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;
|
||||
ASSERT_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) {
|
||||
@ -755,6 +870,40 @@ TEST_F(CommandLineInterfaceTest, WriteTransitiveDescriptorSet) {
|
||||
}
|
||||
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;
|
||||
ASSERT_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());
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
@ -1077,6 +1226,17 @@ TEST_F(CommandLineInterfaceTest, GeneratorPluginCrash) {
|
||||
#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, GeneratorPluginNotFound) {
|
||||
// Test what happens if the plugin isn't found.
|
||||
|
||||
@ -1089,9 +1249,8 @@ TEST_F(CommandLineInterfaceTest, GeneratorPluginNotFound) {
|
||||
"--proto_path=$tmpdir error.proto");
|
||||
|
||||
#ifdef _WIN32
|
||||
ExpectErrorSubstring(
|
||||
"--badplug_out: prefix-gen-badplug: The system cannot find the file "
|
||||
"specified.");
|
||||
ExpectErrorSubstring("--badplug_out: prefix-gen-badplug: " +
|
||||
Subprocess::Win32ErrorMessage(ERROR_FILE_NOT_FOUND));
|
||||
#else
|
||||
// Error written to stdout by child process after exec() fails.
|
||||
ExpectErrorSubstring(
|
||||
@ -1120,11 +1279,11 @@ TEST_F(CommandLineInterfaceTest, GeneratorPluginNotAllowed) {
|
||||
TEST_F(CommandLineInterfaceTest, HelpText) {
|
||||
Run("test_exec_name --help");
|
||||
|
||||
ExpectErrorSubstring("Usage: test_exec_name ");
|
||||
ExpectErrorSubstring("--test_out=OUT_DIR");
|
||||
ExpectErrorSubstring("Test output.");
|
||||
ExpectErrorSubstring("--alt_out=OUT_DIR");
|
||||
ExpectErrorSubstring("Alt output.");
|
||||
ExpectErrorSubstringWithZeroReturnCode("Usage: test_exec_name ");
|
||||
ExpectErrorSubstringWithZeroReturnCode("--test_out=OUT_DIR");
|
||||
ExpectErrorSubstringWithZeroReturnCode("Test output.");
|
||||
ExpectErrorSubstringWithZeroReturnCode("--alt_out=OUT_DIR");
|
||||
ExpectErrorSubstringWithZeroReturnCode("Alt output.");
|
||||
}
|
||||
|
||||
TEST_F(CommandLineInterfaceTest, GccFormatErrors) {
|
||||
@ -1153,7 +1312,7 @@ TEST_F(CommandLineInterfaceTest, MsvsFormatErrors) {
|
||||
"--proto_path=$tmpdir --error_format=msvs foo.proto");
|
||||
|
||||
ExpectErrorText(
|
||||
"foo.proto(2) : error in column=1: Expected top-level statement "
|
||||
"$tmpdir/foo.proto(2) : error in column=1: Expected top-level statement "
|
||||
"(e.g. \"message\").\n");
|
||||
}
|
||||
|
@ -48,8 +48,8 @@
|
||||
#include <google/protobuf/compiler/importer.h>
|
||||
#include <google/protobuf/descriptor.h>
|
||||
#include <google/protobuf/io/zero_copy_stream_impl.h>
|
||||
#include <google/protobuf/stubs/stl_util-inl.h>
|
||||
#include <google/protobuf/stubs/map-util.h>
|
||||
#include <google/protobuf/stubs/stl_util.h>
|
||||
#include <google/protobuf/stubs/strutil.h>
|
||||
#include <google/protobuf/stubs/substitute.h>
|
||||
|
||||
@ -79,10 +79,10 @@ class MockErrorCollector : public MultiFileErrorCollector {
|
||||
}
|
||||
};
|
||||
|
||||
class MockOutputDirectory : public OutputDirectory {
|
||||
class MockGeneratorContext : public GeneratorContext {
|
||||
public:
|
||||
MockOutputDirectory() {}
|
||||
~MockOutputDirectory() {
|
||||
MockGeneratorContext() {}
|
||||
~MockGeneratorContext() {
|
||||
STLDeleteValues(&files_);
|
||||
}
|
||||
|
||||
@ -102,7 +102,7 @@ class MockOutputDirectory : public OutputDirectory {
|
||||
"to your CL.";
|
||||
}
|
||||
|
||||
// implements OutputDirectory --------------------------------------
|
||||
// implements GeneratorContext --------------------------------------
|
||||
|
||||
virtual io::ZeroCopyOutputStream* Open(const string& filename) {
|
||||
string** map_slot = &files_[filename];
|
||||
@ -130,24 +130,24 @@ TEST(BootstrapTest, GeneratedDescriptorMatches) {
|
||||
ASSERT_TRUE(plugin_proto_file != NULL);
|
||||
|
||||
CppGenerator generator;
|
||||
MockOutputDirectory output_directory;
|
||||
MockGeneratorContext context;
|
||||
string error;
|
||||
string parameter;
|
||||
parameter = "dllexport_decl=LIBPROTOBUF_EXPORT";
|
||||
ASSERT_TRUE(generator.Generate(proto_file, parameter,
|
||||
&output_directory, &error));
|
||||
&context, &error));
|
||||
parameter = "dllexport_decl=LIBPROTOC_EXPORT";
|
||||
ASSERT_TRUE(generator.Generate(plugin_proto_file, parameter,
|
||||
&output_directory, &error));
|
||||
&context, &error));
|
||||
|
||||
output_directory.ExpectFileMatches("google/protobuf/descriptor.pb.h",
|
||||
"google/protobuf/descriptor.pb.h");
|
||||
output_directory.ExpectFileMatches("google/protobuf/descriptor.pb.cc",
|
||||
"google/protobuf/descriptor.pb.cc");
|
||||
output_directory.ExpectFileMatches("google/protobuf/compiler/plugin.pb.h",
|
||||
"google/protobuf/compiler/plugin.pb.h");
|
||||
output_directory.ExpectFileMatches("google/protobuf/compiler/plugin.pb.cc",
|
||||
"google/protobuf/compiler/plugin.pb.cc");
|
||||
context.ExpectFileMatches("google/protobuf/descriptor.pb.h",
|
||||
"google/protobuf/descriptor.pb.h");
|
||||
context.ExpectFileMatches("google/protobuf/descriptor.pb.cc",
|
||||
"google/protobuf/descriptor.pb.cc");
|
||||
context.ExpectFileMatches("google/protobuf/compiler/plugin.pb.h",
|
||||
"google/protobuf/compiler/plugin.pb.h");
|
||||
context.ExpectFileMatches("google/protobuf/compiler/plugin.pb.cc",
|
||||
"google/protobuf/compiler/plugin.pb.cc");
|
||||
}
|
||||
|
||||
} // namespace
|
@ -46,10 +46,10 @@ namespace compiler {
|
||||
namespace cpp {
|
||||
|
||||
EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor,
|
||||
const string& dllexport_decl)
|
||||
const Options& options)
|
||||
: descriptor_(descriptor),
|
||||
classname_(ClassName(descriptor, false)),
|
||||
dllexport_decl_(dllexport_decl) {
|
||||
options_(options) {
|
||||
}
|
||||
|
||||
EnumGenerator::~EnumGenerator() {}
|
||||
@ -88,10 +88,10 @@ void EnumGenerator::GenerateDefinition(io::Printer* printer) {
|
||||
vars["min_name"] = min_value->name();
|
||||
vars["max_name"] = max_value->name();
|
||||
|
||||
if (dllexport_decl_.empty()) {
|
||||
if (options_.dllexport_decl.empty()) {
|
||||
vars["dllexport"] = "";
|
||||
} else {
|
||||
vars["dllexport"] = dllexport_decl_ + " ";
|
||||
vars["dllexport"] = options_.dllexport_decl + " ";
|
||||
}
|
||||
|
||||
printer->Print(vars,
|
@ -36,8 +36,10 @@
|
||||
#define GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_H__
|
||||
|
||||
#include <string>
|
||||
#include <google/protobuf/compiler/cpp/cpp_options.h>
|
||||
#include <google/protobuf/descriptor.h>
|
||||
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace io {
|
||||
@ -53,7 +55,7 @@ class EnumGenerator {
|
||||
public:
|
||||
// See generator.cc for the meaning of dllexport_decl.
|
||||
explicit EnumGenerator(const EnumDescriptor* descriptor,
|
||||
const string& dllexport_decl);
|
||||
const Options& options);
|
||||
~EnumGenerator();
|
||||
|
||||
// Header stuff.
|
||||
@ -86,7 +88,7 @@ class EnumGenerator {
|
||||
private:
|
||||
const EnumDescriptor* descriptor_;
|
||||
string classname_;
|
||||
string dllexport_decl_;
|
||||
Options options_;
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumGenerator);
|
||||
};
|
@ -46,8 +46,9 @@ namespace cpp {
|
||||
namespace {
|
||||
|
||||
void SetEnumVariables(const FieldDescriptor* descriptor,
|
||||
map<string, string>* variables) {
|
||||
SetCommonFieldVariables(descriptor, variables);
|
||||
map<string, string>* variables,
|
||||
const Options& options) {
|
||||
SetCommonFieldVariables(descriptor, variables, options);
|
||||
const EnumValueDescriptor* default_value = descriptor->default_value_enum();
|
||||
(*variables)["type"] = ClassName(descriptor->enum_type(), true);
|
||||
(*variables)["default"] = SimpleItoa(default_value->number());
|
||||
@ -58,9 +59,10 @@ void SetEnumVariables(const FieldDescriptor* descriptor,
|
||||
// ===================================================================
|
||||
|
||||
EnumFieldGenerator::
|
||||
EnumFieldGenerator(const FieldDescriptor* descriptor)
|
||||
EnumFieldGenerator(const FieldDescriptor* descriptor,
|
||||
const Options& options)
|
||||
: descriptor_(descriptor) {
|
||||
SetEnumVariables(descriptor, &variables_);
|
||||
SetEnumVariables(descriptor, &variables_, options);
|
||||
}
|
||||
|
||||
EnumFieldGenerator::~EnumFieldGenerator() {}
|
||||
@ -84,8 +86,8 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
|
||||
" return static_cast< $type$ >($name$_);\n"
|
||||
"}\n"
|
||||
"inline void $classname$::set_$name$($type$ value) {\n"
|
||||
" GOOGLE_DCHECK($type$_IsValid(value));\n"
|
||||
" _set_bit($index$);\n"
|
||||
" assert($type$_IsValid(value));\n"
|
||||
" set_has_$name$();\n"
|
||||
" $name$_ = value;\n"
|
||||
"}\n");
|
||||
}
|
||||
@ -152,9 +154,10 @@ GenerateByteSize(io::Printer* printer) const {
|
||||
// ===================================================================
|
||||
|
||||
RepeatedEnumFieldGenerator::
|
||||
RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor)
|
||||
RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor,
|
||||
const Options& options)
|
||||
: descriptor_(descriptor) {
|
||||
SetEnumVariables(descriptor, &variables_);
|
||||
SetEnumVariables(descriptor, &variables_, options);
|
||||
}
|
||||
|
||||
RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() {}
|
||||
@ -187,11 +190,11 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
|
||||
" return static_cast< $type$ >($name$_.Get(index));\n"
|
||||
"}\n"
|
||||
"inline void $classname$::set_$name$(int index, $type$ value) {\n"
|
||||
" GOOGLE_DCHECK($type$_IsValid(value));\n"
|
||||
" assert($type$_IsValid(value));\n"
|
||||
" $name$_.Set(index, value);\n"
|
||||
"}\n"
|
||||
"inline void $classname$::add_$name$($type$ value) {\n"
|
||||
" GOOGLE_DCHECK($type$_IsValid(value));\n"
|
||||
" assert($type$_IsValid(value));\n"
|
||||
" $name$_.Add(value);\n"
|
||||
"}\n");
|
||||
printer->Print(variables_,
|
||||
@ -345,7 +348,9 @@ GenerateByteSize(io::Printer* printer) const {
|
||||
" total_size += $tag_size$ +\n"
|
||||
" ::google::protobuf::internal::WireFormatLite::Int32Size(data_size);\n"
|
||||
"}\n"
|
||||
"GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();\n"
|
||||
"_$name$_cached_byte_size_ = data_size;\n"
|
||||
"GOOGLE_SAFE_CONCURRENT_WRITES_END();\n"
|
||||
"total_size += data_size;\n");
|
||||
} else {
|
||||
printer->Print(variables_,
|
@ -46,7 +46,8 @@ namespace cpp {
|
||||
|
||||
class EnumFieldGenerator : public FieldGenerator {
|
||||
public:
|
||||
explicit EnumFieldGenerator(const FieldDescriptor* descriptor);
|
||||
explicit EnumFieldGenerator(const FieldDescriptor* descriptor,
|
||||
const Options& options);
|
||||
~EnumFieldGenerator();
|
||||
|
||||
// implements FieldGenerator ---------------------------------------
|
||||
@ -71,7 +72,8 @@ class EnumFieldGenerator : public FieldGenerator {
|
||||
|
||||
class RepeatedEnumFieldGenerator : public FieldGenerator {
|
||||
public:
|
||||
explicit RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor);
|
||||
explicit RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor,
|
||||
const Options& options);
|
||||
~RepeatedEnumFieldGenerator();
|
||||
|
||||
// implements FieldGenerator ---------------------------------------
|
@ -57,9 +57,9 @@ string ExtendeeClassName(const FieldDescriptor* descriptor) {
|
||||
} // anonymous namespace
|
||||
|
||||
ExtensionGenerator::ExtensionGenerator(const FieldDescriptor* descriptor,
|
||||
const string& dllexport_decl)
|
||||
const Options& options)
|
||||
: descriptor_(descriptor),
|
||||
dllexport_decl_(dllexport_decl) {
|
||||
options_(options) {
|
||||
// Construct type_traits_.
|
||||
if (descriptor_->is_repeated()) {
|
||||
type_traits_ = "Repeated";
|
||||
@ -106,8 +106,8 @@ void ExtensionGenerator::GenerateDeclaration(io::Printer* printer) {
|
||||
// export/import specifier.
|
||||
if (descriptor_->extension_scope() == NULL) {
|
||||
vars["qualifier"] = "extern";
|
||||
if (!dllexport_decl_.empty()) {
|
||||
vars["qualifier"] = dllexport_decl_ + " " + vars["qualifier"];
|
||||
if (!options_.dllexport_decl.empty()) {
|
||||
vars["qualifier"] = options_.dllexport_decl + " " + vars["qualifier"];
|
||||
}
|
||||
} else {
|
||||
vars["qualifier"] = "static";
|
@ -37,6 +37,7 @@
|
||||
|
||||
#include <string>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/compiler/cpp/cpp_options.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
@ -56,8 +57,8 @@ namespace cpp {
|
||||
class ExtensionGenerator {
|
||||
public:
|
||||
// See generator.cc for the meaning of dllexport_decl.
|
||||
explicit ExtensionGenerator(const FieldDescriptor* descriptor,
|
||||
const string& dllexport_decl);
|
||||
explicit ExtensionGenerator(const FieldDescriptor* desycriptor,
|
||||
const Options& options);
|
||||
~ExtensionGenerator();
|
||||
|
||||
// Header stuff.
|
||||
@ -72,7 +73,7 @@ class ExtensionGenerator {
|
||||
private:
|
||||
const FieldDescriptor* descriptor_;
|
||||
string type_traits_;
|
||||
string dllexport_decl_;
|
||||
Options options_;
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ExtensionGenerator);
|
||||
};
|
@ -52,7 +52,8 @@ namespace cpp {
|
||||
using internal::WireFormat;
|
||||
|
||||
void SetCommonFieldVariables(const FieldDescriptor* descriptor,
|
||||
map<string, string>* variables) {
|
||||
map<string, string>* variables,
|
||||
const Options& options) {
|
||||
(*variables)["name"] = FieldName(descriptor);
|
||||
(*variables)["index"] = SimpleItoa(descriptor->index());
|
||||
(*variables)["number"] = SimpleItoa(descriptor->number());
|
||||
@ -64,6 +65,7 @@ void SetCommonFieldVariables(const FieldDescriptor* descriptor,
|
||||
(*variables)["deprecation"] = descriptor->options().deprecated()
|
||||
? " PROTOBUF_DEPRECATED" : "";
|
||||
|
||||
(*variables)["cppget"] = "Get";
|
||||
}
|
||||
|
||||
FieldGenerator::~FieldGenerator() {}
|
||||
@ -80,46 +82,47 @@ GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const {
|
||||
|
||||
}
|
||||
|
||||
FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor)
|
||||
FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor,
|
||||
const Options& options)
|
||||
: descriptor_(descriptor),
|
||||
field_generators_(
|
||||
new scoped_ptr<FieldGenerator>[descriptor->field_count()]) {
|
||||
field_generators_(new scoped_ptr<FieldGenerator>[descriptor->field_count()]) {
|
||||
// Construct all the FieldGenerators.
|
||||
for (int i = 0; i < descriptor->field_count(); i++) {
|
||||
field_generators_[i].reset(MakeGenerator(descriptor->field(i)));
|
||||
field_generators_[i].reset(MakeGenerator(descriptor->field(i), options));
|
||||
}
|
||||
}
|
||||
|
||||
FieldGenerator* FieldGeneratorMap::MakeGenerator(const FieldDescriptor* field) {
|
||||
FieldGenerator* FieldGeneratorMap::MakeGenerator(const FieldDescriptor* field,
|
||||
const Options& options) {
|
||||
if (field->is_repeated()) {
|
||||
switch (field->cpp_type()) {
|
||||
case FieldDescriptor::CPPTYPE_MESSAGE:
|
||||
return new RepeatedMessageFieldGenerator(field);
|
||||
return new RepeatedMessageFieldGenerator(field, options);
|
||||
case FieldDescriptor::CPPTYPE_STRING:
|
||||
switch (field->options().ctype()) {
|
||||
default: // RepeatedStringFieldGenerator handles unknown ctypes.
|
||||
case FieldOptions::STRING:
|
||||
return new RepeatedStringFieldGenerator(field);
|
||||
return new RepeatedStringFieldGenerator(field, options);
|
||||
}
|
||||
case FieldDescriptor::CPPTYPE_ENUM:
|
||||
return new RepeatedEnumFieldGenerator(field);
|
||||
return new RepeatedEnumFieldGenerator(field, options);
|
||||
default:
|
||||
return new RepeatedPrimitiveFieldGenerator(field);
|
||||
return new RepeatedPrimitiveFieldGenerator(field, options);
|
||||
}
|
||||
} else {
|
||||
switch (field->cpp_type()) {
|
||||
case FieldDescriptor::CPPTYPE_MESSAGE:
|
||||
return new MessageFieldGenerator(field);
|
||||
return new MessageFieldGenerator(field, options);
|
||||
case FieldDescriptor::CPPTYPE_STRING:
|
||||
switch (field->options().ctype()) {
|
||||
default: // StringFieldGenerator handles unknown ctypes.
|
||||
case FieldOptions::STRING:
|
||||
return new StringFieldGenerator(field);
|
||||
return new StringFieldGenerator(field, options);
|
||||
}
|
||||
case FieldDescriptor::CPPTYPE_ENUM:
|
||||
return new EnumFieldGenerator(field);
|
||||
return new EnumFieldGenerator(field, options);
|
||||
default:
|
||||
return new PrimitiveFieldGenerator(field);
|
||||
return new PrimitiveFieldGenerator(field, options);
|
||||
}
|
||||
}
|
||||
}
|
@ -40,6 +40,7 @@
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/descriptor.h>
|
||||
#include <google/protobuf/compiler/cpp/cpp_options.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
@ -57,7 +58,8 @@ namespace cpp {
|
||||
// ['name', 'index', 'number', 'classname', 'declared_type', 'tag_size',
|
||||
// 'deprecation'].
|
||||
void SetCommonFieldVariables(const FieldDescriptor* descriptor,
|
||||
map<string, string>* variables);
|
||||
map<string, string>* variables,
|
||||
const Options& options);
|
||||
|
||||
class FieldGenerator {
|
||||
public:
|
||||
@ -114,6 +116,13 @@ class FieldGenerator {
|
||||
// Most field types don't need this, so the default implementation is empty.
|
||||
virtual void GenerateDestructorCode(io::Printer* printer) const {}
|
||||
|
||||
// Generate code that allocates the fields's default instance.
|
||||
virtual void GenerateDefaultInstanceAllocator(io::Printer* printer) const {}
|
||||
|
||||
// Generate code that should be run when ShutdownProtobufLibrary() is called,
|
||||
// to delete all dynamically-allocated objects.
|
||||
virtual void GenerateShutdownCode(io::Printer* printer) const {}
|
||||
|
||||
// Generate lines to decode this field, which will be placed inside the
|
||||
// message's MergeFromCodedStream() method.
|
||||
virtual void GenerateMergeFromCodedStream(io::Printer* printer) const = 0;
|
||||
@ -144,7 +153,7 @@ class FieldGenerator {
|
||||
// Convenience class which constructs FieldGenerators for a Descriptor.
|
||||
class FieldGeneratorMap {
|
||||
public:
|
||||
explicit FieldGeneratorMap(const Descriptor* descriptor);
|
||||
explicit FieldGeneratorMap(const Descriptor* descriptor, const Options& options);
|
||||
~FieldGeneratorMap();
|
||||
|
||||
const FieldGenerator& get(const FieldDescriptor* field) const;
|
||||
@ -153,7 +162,8 @@ class FieldGeneratorMap {
|
||||
const Descriptor* descriptor_;
|
||||
scoped_array<scoped_ptr<FieldGenerator> > field_generators_;
|
||||
|
||||
static FieldGenerator* MakeGenerator(const FieldDescriptor* field);
|
||||
static FieldGenerator* MakeGenerator(const FieldDescriptor* field,
|
||||
const Options& options);
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGeneratorMap);
|
||||
};
|
@ -51,7 +51,7 @@ namespace cpp {
|
||||
// ===================================================================
|
||||
|
||||
FileGenerator::FileGenerator(const FileDescriptor* file,
|
||||
const string& dllexport_decl)
|
||||
const Options& options)
|
||||
: file_(file),
|
||||
message_generators_(
|
||||
new scoped_ptr<MessageGenerator>[file->message_type_count()]),
|
||||
@ -61,26 +61,26 @@ FileGenerator::FileGenerator(const FileDescriptor* file,
|
||||
new scoped_ptr<ServiceGenerator>[file->service_count()]),
|
||||
extension_generators_(
|
||||
new scoped_ptr<ExtensionGenerator>[file->extension_count()]),
|
||||
dllexport_decl_(dllexport_decl) {
|
||||
options_(options) {
|
||||
|
||||
for (int i = 0; i < file->message_type_count(); i++) {
|
||||
message_generators_[i].reset(
|
||||
new MessageGenerator(file->message_type(i), dllexport_decl));
|
||||
new MessageGenerator(file->message_type(i), options));
|
||||
}
|
||||
|
||||
for (int i = 0; i < file->enum_type_count(); i++) {
|
||||
enum_generators_[i].reset(
|
||||
new EnumGenerator(file->enum_type(i), dllexport_decl));
|
||||
new EnumGenerator(file->enum_type(i), options));
|
||||
}
|
||||
|
||||
for (int i = 0; i < file->service_count(); i++) {
|
||||
service_generators_[i].reset(
|
||||
new ServiceGenerator(file->service(i), dllexport_decl));
|
||||
new ServiceGenerator(file->service(i), options));
|
||||
}
|
||||
|
||||
for (int i = 0; i < file->extension_count(); i++) {
|
||||
extension_generators_[i].reset(
|
||||
new ExtensionGenerator(file->extension(i), dllexport_decl));
|
||||
new ExtensionGenerator(file->extension(i), options));
|
||||
}
|
||||
|
||||
SplitStringUsing(file_->package(), ".", &package_parts_);
|
||||
@ -104,6 +104,7 @@ void FileGenerator::GenerateHeader(io::Printer* printer) {
|
||||
"filename", file_->name(),
|
||||
"filename_identifier", filename_identifier);
|
||||
|
||||
|
||||
printer->Print(
|
||||
"#include <google/protobuf/stubs/common.h>\n"
|
||||
"\n");
|
||||
@ -128,13 +129,23 @@ void FileGenerator::GenerateHeader(io::Printer* printer) {
|
||||
|
||||
// OK, it's now safe to #include other files.
|
||||
printer->Print(
|
||||
"#include <google/protobuf/generated_message_util.h>\n"
|
||||
"#include <google/protobuf/generated_message_util.h>\n");
|
||||
if (file_->message_type_count() > 0) {
|
||||
if (HasDescriptorMethods(file_)) {
|
||||
printer->Print(
|
||||
"#include <google/protobuf/message.h>\n");
|
||||
} else {
|
||||
printer->Print(
|
||||
"#include <google/protobuf/message_lite.h>\n");
|
||||
}
|
||||
}
|
||||
printer->Print(
|
||||
"#include <google/protobuf/repeated_field.h>\n"
|
||||
"#include <google/protobuf/extension_set.h>\n");
|
||||
|
||||
if (HasDescriptorMethods(file_)) {
|
||||
if (HasDescriptorMethods(file_) && HasEnumDefinitions(file_)) {
|
||||
printer->Print(
|
||||
"#include <google/protobuf/generated_message_reflection.h>\n");
|
||||
"#include <google/protobuf/generated_enum_reflection.h>\n");
|
||||
}
|
||||
|
||||
if (HasGenericServices(file_)) {
|
||||
@ -142,6 +153,11 @@ void FileGenerator::GenerateHeader(io::Printer* printer) {
|
||||
"#include <google/protobuf/service.h>\n");
|
||||
}
|
||||
|
||||
if (HasUnknownFields(file_) && file_->message_type_count() > 0) {
|
||||
printer->Print(
|
||||
"#include <google/protobuf/unknown_field_set.h>\n");
|
||||
}
|
||||
|
||||
|
||||
for (int i = 0; i < file_->dependency_count(); i++) {
|
||||
printer->Print(
|
||||
@ -149,9 +165,11 @@ void FileGenerator::GenerateHeader(io::Printer* printer) {
|
||||
"dependency", StripProto(file_->dependency(i)->name()));
|
||||
}
|
||||
|
||||
|
||||
printer->Print(
|
||||
"// @@protoc_insertion_point(includes)\n");
|
||||
|
||||
|
||||
// Open namespace.
|
||||
GenerateNamespaceOpeners(printer);
|
||||
|
||||
@ -162,7 +180,7 @@ void FileGenerator::GenerateHeader(io::Printer* printer) {
|
||||
"// Internal implementation detail -- do not call these.\n"
|
||||
"void $dllexport_decl$ $adddescriptorsname$();\n",
|
||||
"adddescriptorsname", GlobalAddDescriptorsName(file_->name()),
|
||||
"dllexport_decl", dllexport_decl_);
|
||||
"dllexport_decl", options_.dllexport_decl);
|
||||
|
||||
printer->Print(
|
||||
// Note that we don't put dllexport_decl on these because they are only
|
||||
@ -282,20 +300,27 @@ void FileGenerator::GenerateHeader(io::Printer* printer) {
|
||||
void FileGenerator::GenerateSource(io::Printer* printer) {
|
||||
printer->Print(
|
||||
"// Generated by the protocol buffer compiler. DO NOT EDIT!\n"
|
||||
"// source: $filename$\n"
|
||||
"\n"
|
||||
|
||||
// The generated code calls accessors that might be deprecated. We don't
|
||||
// want the compiler to warn in generated code.
|
||||
"#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION\n"
|
||||
"#include \"$basename$.pb.h\"\n"
|
||||
|
||||
"\n"
|
||||
"#include <algorithm>\n" // for swap()
|
||||
"\n"
|
||||
"#include <google/protobuf/stubs/common.h>\n"
|
||||
"#include <google/protobuf/stubs/once.h>\n"
|
||||
"#include <google/protobuf/io/coded_stream.h>\n"
|
||||
"#include <google/protobuf/wire_format_lite_inl.h>\n",
|
||||
"filename", file_->name(),
|
||||
"basename", StripProto(file_->name()));
|
||||
|
||||
if (HasDescriptorMethods(file_)) {
|
||||
printer->Print(
|
||||
"#include <google/protobuf/descriptor.h>\n"
|
||||
"#include <google/protobuf/generated_message_reflection.h>\n"
|
||||
"#include <google/protobuf/reflection_ops.h>\n"
|
||||
"#include <google/protobuf/wire_format.h>\n");
|
||||
}
|
||||
@ -378,11 +403,12 @@ void FileGenerator::GenerateSource(io::Printer* printer) {
|
||||
|
||||
void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) {
|
||||
// AddDescriptors() is a file-level procedure which adds the encoded
|
||||
// FileDescriptorProto for this .proto file to the global DescriptorPool
|
||||
// for generated files (DescriptorPool::generated_pool()). It always runs
|
||||
// at static initialization time, so all files will be registered before
|
||||
// main() starts. This procedure also constructs default instances and
|
||||
// registers extensions.
|
||||
// FileDescriptorProto for this .proto file to the global DescriptorPool for
|
||||
// generated files (DescriptorPool::generated_pool()). It either runs at
|
||||
// static initialization time (by default) or when default_instance() is
|
||||
// called for the first time (in LITE_RUNTIME mode with
|
||||
// GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER flag enabled). This procedure also
|
||||
// constructs default instances and registers extensions.
|
||||
//
|
||||
// Its sibling, AssignDescriptors(), actually pulls the compiled
|
||||
// FileDescriptor from the DescriptorPool and uses it to populate all of
|
||||
@ -486,22 +512,29 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) {
|
||||
|
||||
printer->Outdent();
|
||||
printer->Print(
|
||||
"}\n");
|
||||
"}\n\n");
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
// Now generate the AddDescriptors() function.
|
||||
printer->Print(
|
||||
"\n"
|
||||
PrintHandlingOptionalStaticInitializers(
|
||||
file_, printer,
|
||||
// With static initializers.
|
||||
// Note that we don't need any special synchronization in the following code
|
||||
// because it is called at static init time before any threads exist.
|
||||
"void $adddescriptorsname$() {\n"
|
||||
// We don't need any special synchronization here because this code is
|
||||
// called at static init time before any threads exist.
|
||||
" static bool already_here = false;\n"
|
||||
" if (already_here) return;\n"
|
||||
" already_here = true;\n"
|
||||
" GOOGLE_PROTOBUF_VERIFY_VERSION;\n"
|
||||
"\n",
|
||||
// Without.
|
||||
"void $adddescriptorsname$_impl() {\n"
|
||||
" GOOGLE_PROTOBUF_VERIFY_VERSION;\n"
|
||||
"\n",
|
||||
// Vars.
|
||||
"adddescriptorsname", GlobalAddDescriptorsName(file_->name()));
|
||||
|
||||
printer->Indent();
|
||||
|
||||
// Call the AddDescriptors() methods for all of our dependencies, to make
|
||||
@ -512,9 +545,9 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) {
|
||||
vector<string> dependency_package_parts;
|
||||
SplitStringUsing(dependency->package(), ".", &dependency_package_parts);
|
||||
printer->Print("::");
|
||||
for (int i = 0; i < dependency_package_parts.size(); i++) {
|
||||
for (int j = 0; j < dependency_package_parts.size(); j++) {
|
||||
printer->Print("$name$::",
|
||||
"name", dependency_package_parts[i]);
|
||||
"name", dependency_package_parts[j]);
|
||||
}
|
||||
// Call its AddDescriptors function.
|
||||
printer->Print(
|
||||
@ -538,10 +571,12 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) {
|
||||
static const int kBytesPerLine = 40;
|
||||
for (int i = 0; i < file_data.size(); i += kBytesPerLine) {
|
||||
printer->Print("\n \"$data$\"",
|
||||
"data", CEscape(file_data.substr(i, kBytesPerLine)));
|
||||
"data",
|
||||
EscapeTrigraphs(
|
||||
CEscape(file_data.substr(i, kBytesPerLine))));
|
||||
}
|
||||
printer->Print(
|
||||
", $size$);\n",
|
||||
", $size$);\n",
|
||||
"size", SimpleItoa(file_data.size()));
|
||||
|
||||
// Call MessageFactory::InternalRegisterGeneratedFile().
|
||||
@ -569,17 +604,26 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) {
|
||||
"shutdownfilename", GlobalShutdownFileName(file_->name()));
|
||||
|
||||
printer->Outdent();
|
||||
|
||||
printer->Print(
|
||||
"}\n"
|
||||
"\n"
|
||||
"\n");
|
||||
|
||||
PrintHandlingOptionalStaticInitializers(
|
||||
file_, printer,
|
||||
// With static initializers.
|
||||
"// Force AddDescriptors() to be called at static initialization time.\n"
|
||||
"struct StaticDescriptorInitializer_$filename$ {\n"
|
||||
" StaticDescriptorInitializer_$filename$() {\n"
|
||||
" $adddescriptorsname$();\n"
|
||||
" }\n"
|
||||
"} static_descriptor_initializer_$filename$_;\n"
|
||||
"\n",
|
||||
"} static_descriptor_initializer_$filename$_;\n",
|
||||
// Without.
|
||||
"GOOGLE_PROTOBUF_DECLARE_ONCE($adddescriptorsname$_once_);\n"
|
||||
"void $adddescriptorsname$() {\n"
|
||||
" ::google::protobuf::::google::protobuf::GoogleOnceInit(&$adddescriptorsname$_once_,\n"
|
||||
" &$adddescriptorsname$_impl);\n"
|
||||
"}\n",
|
||||
// Vars.
|
||||
"adddescriptorsname", GlobalAddDescriptorsName(file_->name()),
|
||||
"filename", FilenameIdentifier(file_->name()));
|
||||
}
|
@ -39,6 +39,7 @@
|
||||
#include <vector>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/compiler/cpp/cpp_field.h>
|
||||
#include <google/protobuf/compiler/cpp/cpp_options.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
@ -61,7 +62,7 @@ class FileGenerator {
|
||||
public:
|
||||
// See generator.cc for the meaning of dllexport_decl.
|
||||
explicit FileGenerator(const FileDescriptor* file,
|
||||
const string& dllexport_decl);
|
||||
const Options& options);
|
||||
~FileGenerator();
|
||||
|
||||
void GenerateHeader(io::Printer* printer);
|
||||
@ -85,7 +86,7 @@ class FileGenerator {
|
||||
// E.g. if the package is foo.bar, package_parts_ is {"foo", "bar"}.
|
||||
vector<string> package_parts_;
|
||||
|
||||
string dllexport_decl_;
|
||||
const Options options_;
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileGenerator);
|
||||
};
|
@ -53,7 +53,7 @@ CppGenerator::~CppGenerator() {}
|
||||
|
||||
bool CppGenerator::Generate(const FileDescriptor* file,
|
||||
const string& parameter,
|
||||
OutputDirectory* output_directory,
|
||||
GeneratorContext* generator_context,
|
||||
string* error) const {
|
||||
vector<pair<string, string> > options;
|
||||
ParseGeneratorParameter(parameter, &options);
|
||||
@ -78,11 +78,13 @@ bool CppGenerator::Generate(const FileDescriptor* file,
|
||||
// }
|
||||
// FOO_EXPORT is a macro which should expand to __declspec(dllexport) or
|
||||
// __declspec(dllimport) depending on what is being compiled.
|
||||
string dllexport_decl;
|
||||
Options file_options;
|
||||
|
||||
for (int i = 0; i < options.size(); i++) {
|
||||
if (options[i].first == "dllexport_decl") {
|
||||
dllexport_decl = options[i].second;
|
||||
file_options.dllexport_decl = options[i].second;
|
||||
} else if (options[i].first == "safe_boundary_check") {
|
||||
file_options.safe_boundary_check = true;
|
||||
} else {
|
||||
*error = "Unknown generator option: " + options[i].first;
|
||||
return false;
|
||||
@ -95,12 +97,12 @@ bool CppGenerator::Generate(const FileDescriptor* file,
|
||||
string basename = StripProto(file->name());
|
||||
basename.append(".pb");
|
||||
|
||||
FileGenerator file_generator(file, dllexport_decl);
|
||||
FileGenerator file_generator(file, file_options);
|
||||
|
||||
// Generate header.
|
||||
{
|
||||
scoped_ptr<io::ZeroCopyOutputStream> output(
|
||||
output_directory->Open(basename + ".h"));
|
||||
generator_context->Open(basename + ".h"));
|
||||
io::Printer printer(output.get(), '$');
|
||||
file_generator.GenerateHeader(&printer);
|
||||
}
|
||||
@ -108,7 +110,7 @@ bool CppGenerator::Generate(const FileDescriptor* file,
|
||||
// Generate cc file.
|
||||
{
|
||||
scoped_ptr<io::ZeroCopyOutputStream> output(
|
||||
output_directory->Open(basename + ".cc"));
|
||||
generator_context->Open(basename + ".cc"));
|
||||
io::Printer printer(output.get(), '$');
|
||||
file_generator.GenerateSource(&printer);
|
||||
}
|
@ -57,7 +57,7 @@ class LIBPROTOC_EXPORT CppGenerator : public CodeGenerator {
|
||||
// implements CodeGenerator ----------------------------------------
|
||||
bool Generate(const FileDescriptor* file,
|
||||
const string& parameter,
|
||||
OutputDirectory* output_directory,
|
||||
GeneratorContext* generator_context,
|
||||
string* error) const;
|
||||
|
||||
private:
|
@ -33,10 +33,12 @@
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <google/protobuf/stubs/hash.h>
|
||||
|
||||
#include <google/protobuf/compiler/cpp/cpp_helpers.h>
|
||||
#include <google/protobuf/io/printer.h>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/stubs/strutil.h>
|
||||
#include <google/protobuf/stubs/substitute.h>
|
||||
@ -105,6 +107,20 @@ string UnderscoresToCamelCase(const string& input, bool cap_next_letter) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// Returns whether the provided descriptor has an extension. This includes its
|
||||
// nested types.
|
||||
bool HasExtension(const Descriptor* descriptor) {
|
||||
if (descriptor->extension_count() > 0) {
|
||||
return true;
|
||||
}
|
||||
for (int i = 0; i < descriptor->nested_type_count(); ++i) {
|
||||
if (HasExtension(descriptor->nested_type(i))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
const char kThickSeparator[] =
|
||||
@ -132,7 +148,7 @@ string ClassName(const Descriptor* descriptor, bool qualified) {
|
||||
string ClassName(const EnumDescriptor* enum_descriptor, bool qualified) {
|
||||
if (enum_descriptor->containing_type() == NULL) {
|
||||
if (qualified) {
|
||||
return DotsToColons(enum_descriptor->full_name());
|
||||
return "::" + DotsToColons(enum_descriptor->full_name());
|
||||
} else {
|
||||
return enum_descriptor->name();
|
||||
}
|
||||
@ -243,10 +259,23 @@ const char* DeclaredTypeMethodName(FieldDescriptor::Type type) {
|
||||
string DefaultValue(const FieldDescriptor* field) {
|
||||
switch (field->cpp_type()) {
|
||||
case FieldDescriptor::CPPTYPE_INT32:
|
||||
// gcc rejects the decimal form of kint32min and kint64min.
|
||||
if (field->default_value_int32() == kint32min) {
|
||||
// Make sure we are in a 2's complement system.
|
||||
GOOGLE_COMPILE_ASSERT(kint32min == -0x80000000, kint32min_value_error);
|
||||
return "-0x80000000";
|
||||
}
|
||||
return SimpleItoa(field->default_value_int32());
|
||||
case FieldDescriptor::CPPTYPE_UINT32:
|
||||
return SimpleItoa(field->default_value_uint32()) + "u";
|
||||
case FieldDescriptor::CPPTYPE_INT64:
|
||||
// See the comments for CPPTYPE_INT32.
|
||||
if (field->default_value_int64() == kint64min) {
|
||||
// Make sure we are in a 2's complement system.
|
||||
GOOGLE_COMPILE_ASSERT(kint64min == GOOGLE_LONGLONG(-0x8000000000000000),
|
||||
kint64min_value_error);
|
||||
return "GOOGLE_LONGLONG(-0x8000000000000000)";
|
||||
}
|
||||
return "GOOGLE_LONGLONG(" + SimpleItoa(field->default_value_int64()) + ")";
|
||||
case FieldDescriptor::CPPTYPE_UINT64:
|
||||
return "GOOGLE_ULONGLONG(" + SimpleItoa(field->default_value_uint64())+ ")";
|
||||
@ -292,7 +321,9 @@ string DefaultValue(const FieldDescriptor* field) {
|
||||
ClassName(field->enum_type(), true),
|
||||
field->default_value_enum()->number());
|
||||
case FieldDescriptor::CPPTYPE_STRING:
|
||||
return "\"" + CEscape(field->default_value_string()) + "\"";
|
||||
return "\"" + EscapeTrigraphs(
|
||||
CEscape(field->default_value_string())) +
|
||||
"\"";
|
||||
case FieldDescriptor::CPPTYPE_MESSAGE:
|
||||
return FieldMessageTypeName(field) + "::default_instance()";
|
||||
}
|
||||
@ -335,6 +366,72 @@ string GlobalShutdownFileName(const string& filename) {
|
||||
return "protobuf_ShutdownFile_" + FilenameIdentifier(filename);
|
||||
}
|
||||
|
||||
// Escape C++ trigraphs by escaping question marks to \?
|
||||
string EscapeTrigraphs(const string& to_escape) {
|
||||
return StringReplace(to_escape, "?", "\\?", true);
|
||||
}
|
||||
|
||||
bool StaticInitializersForced(const FileDescriptor* file) {
|
||||
if (HasDescriptorMethods(file) || file->extension_count() > 0) {
|
||||
return true;
|
||||
}
|
||||
for (int i = 0; i < file->message_type_count(); ++i) {
|
||||
if (HasExtension(file->message_type(i))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void PrintHandlingOptionalStaticInitializers(
|
||||
const FileDescriptor* file, io::Printer* printer,
|
||||
const char* with_static_init, const char* without_static_init,
|
||||
const char* var1, const string& val1,
|
||||
const char* var2, const string& val2) {
|
||||
map<string, string> vars;
|
||||
if (var1) {
|
||||
vars[var1] = val1;
|
||||
}
|
||||
if (var2) {
|
||||
vars[var2] = val2;
|
||||
}
|
||||
PrintHandlingOptionalStaticInitializers(
|
||||
vars, file, printer, with_static_init, without_static_init);
|
||||
}
|
||||
|
||||
void PrintHandlingOptionalStaticInitializers(
|
||||
const map<string, string>& vars, const FileDescriptor* file,
|
||||
io::Printer* printer, const char* with_static_init,
|
||||
const char* without_static_init) {
|
||||
if (StaticInitializersForced(file)) {
|
||||
printer->Print(vars, with_static_init);
|
||||
} else {
|
||||
printer->Print(vars, (string(
|
||||
"#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER\n") +
|
||||
without_static_init +
|
||||
"#else\n" +
|
||||
with_static_init +
|
||||
"#endif\n").c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
@ -35,12 +35,18 @@
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_HELPERS_H__
|
||||
#define GOOGLE_PROTOBUF_COMPILER_CPP_HELPERS_H__
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <google/protobuf/descriptor.h>
|
||||
#include <google/protobuf/descriptor.pb.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
namespace io {
|
||||
class Printer;
|
||||
}
|
||||
|
||||
namespace compiler {
|
||||
namespace cpp {
|
||||
|
||||
@ -112,24 +118,31 @@ string GlobalAssignDescriptorsName(const string& filename);
|
||||
// Return the name of the ShutdownFile() function for a given file.
|
||||
string GlobalShutdownFileName(const string& filename);
|
||||
|
||||
// Escape C++ trigraphs by escaping question marks to \?
|
||||
string EscapeTrigraphs(const string& to_escape);
|
||||
|
||||
// Do message classes in this file keep track of unknown fields?
|
||||
inline bool HasUnknownFields(const FileDescriptor *file) {
|
||||
inline bool HasUnknownFields(const FileDescriptor* file) {
|
||||
return file->options().optimize_for() != FileOptions::LITE_RUNTIME;
|
||||
}
|
||||
|
||||
|
||||
// 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) {
|
||||
inline bool HasGeneratedMethods(const FileDescriptor* file) {
|
||||
return file->options().optimize_for() != FileOptions::CODE_SIZE;
|
||||
}
|
||||
|
||||
// Do message classes in this file have descriptor and refelction methods?
|
||||
inline bool HasDescriptorMethods(const FileDescriptor *file) {
|
||||
// Do message classes in this file have descriptor and reflection methods?
|
||||
inline bool HasDescriptorMethods(const FileDescriptor* file) {
|
||||
return file->options().optimize_for() != FileOptions::LITE_RUNTIME;
|
||||
}
|
||||
|
||||
// Should we generate generic services for this file?
|
||||
inline bool HasGenericServices(const FileDescriptor *file) {
|
||||
inline bool HasGenericServices(const FileDescriptor* file) {
|
||||
return file->service_count() > 0 &&
|
||||
file->options().optimize_for() != FileOptions::LITE_RUNTIME &&
|
||||
file->options().cc_generic_services();
|
||||
@ -147,6 +160,23 @@ inline bool HasFastArraySerialization(const FileDescriptor* file) {
|
||||
return file->options().optimize_for() == FileOptions::SPEED;
|
||||
}
|
||||
|
||||
// Returns whether we have to generate code with static initializers.
|
||||
bool StaticInitializersForced(const FileDescriptor* file);
|
||||
|
||||
// Prints 'with_static_init' if static initializers have to be used for the
|
||||
// provided file. Otherwise emits both 'with_static_init' and
|
||||
// 'without_static_init' using #ifdef.
|
||||
void PrintHandlingOptionalStaticInitializers(
|
||||
const FileDescriptor* file, io::Printer* printer,
|
||||
const char* with_static_init, const char* without_static_init,
|
||||
const char* var1 = NULL, const string& val1 = "",
|
||||
const char* var2 = NULL, const string& val2 = "");
|
||||
|
||||
void PrintHandlingOptionalStaticInitializers(
|
||||
const map<string, string>& vars, const FileDescriptor* file,
|
||||
io::Printer* printer, const char* with_static_init,
|
||||
const char* without_static_init);
|
||||
|
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
@ -35,6 +35,7 @@
|
||||
#include <algorithm>
|
||||
#include <google/protobuf/stubs/hash.h>
|
||||
#include <map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <google/protobuf/compiler/cpp/cpp_message.h>
|
||||
#include <google/protobuf/compiler/cpp/cpp_field.h>
|
||||
@ -47,6 +48,7 @@
|
||||
#include <google/protobuf/wire_format.h>
|
||||
#include <google/protobuf/descriptor.pb.h>
|
||||
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
@ -102,6 +104,13 @@ struct ExtensionRangeSorter {
|
||||
}
|
||||
};
|
||||
|
||||
// Returns true if the "required" restriction check should be ignored for the
|
||||
// given field.
|
||||
inline static bool ShouldIgnoreRequiredFieldCheck(
|
||||
const FieldDescriptor* field) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Returns true if the message type has any required fields. If it doesn't,
|
||||
// we can optimize out calls to its IsInitialized() method.
|
||||
//
|
||||
@ -128,7 +137,8 @@ static bool HasRequiredFields(
|
||||
if (field->is_required()) {
|
||||
return true;
|
||||
}
|
||||
if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
|
||||
if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
|
||||
!ShouldIgnoreRequiredFieldCheck(field)) {
|
||||
if (HasRequiredFields(field->message_type(), already_seen)) {
|
||||
return true;
|
||||
}
|
||||
@ -143,16 +153,147 @@ static bool HasRequiredFields(const Descriptor* type) {
|
||||
return HasRequiredFields(type, &already_seen);
|
||||
}
|
||||
|
||||
// This 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) {
|
||||
if (field == NULL) 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.
|
||||
}
|
||||
|
||||
// FieldGroup is just a helper for OptimizePadding 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 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_;
|
||||
vector<const FieldDescriptor*> fields_;
|
||||
// We rely on the default copy constructor and operator= so this type can be
|
||||
// used in a vector.
|
||||
};
|
||||
|
||||
// Reorder 'fields' so that if the fields are output into a c++ class in the new
|
||||
// order, the alignment padding is minimized. We try to do this while keeping
|
||||
// each field as close as possible to its original position so that we don't
|
||||
// reduce cache locality much for function that access each field in order.
|
||||
void OptimizePadding(vector<const FieldDescriptor*>* fields) {
|
||||
// First divide fields into those that align to 1 byte, 4 bytes or 8 bytes.
|
||||
vector<FieldGroup> aligned_to_1, aligned_to_4, aligned_to_8;
|
||||
for (int i = 0; i < fields->size(); ++i) {
|
||||
switch (EstimateAlignmentSize((*fields)[i])) {
|
||||
case 1: aligned_to_1.push_back(FieldGroup(i, (*fields)[i])); break;
|
||||
case 4: aligned_to_4.push_back(FieldGroup(i, (*fields)[i])); break;
|
||||
case 8: aligned_to_8.push_back(FieldGroup(i, (*fields)[i])); break;
|
||||
default:
|
||||
GOOGLE_LOG(FATAL) << "Unknown alignment size.";
|
||||
}
|
||||
}
|
||||
|
||||
// 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.size(); i += 4) {
|
||||
FieldGroup field_group;
|
||||
for (int j = i; j < aligned_to_1.size() && j < i + 4; ++j) {
|
||||
field_group.Append(aligned_to_1[j]);
|
||||
}
|
||||
aligned_to_4.push_back(field_group);
|
||||
}
|
||||
// Sort by preferred location to keep fields as close to their original
|
||||
// location as possible.
|
||||
sort(aligned_to_4.begin(), aligned_to_4.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.size(); i += 2) {
|
||||
FieldGroup field_group;
|
||||
for (int j = i; j < aligned_to_4.size() && j < i + 2; ++j) {
|
||||
field_group.Append(aligned_to_4[j]);
|
||||
}
|
||||
if (i == aligned_to_4.size() - 1) {
|
||||
// Move incomplete 4-byte block to the end.
|
||||
field_group.SetPreferredLocation(fields->size() + 1);
|
||||
}
|
||||
aligned_to_8.push_back(field_group);
|
||||
}
|
||||
// Sort by preferred location to keep fields as close to their original
|
||||
// location as possible.
|
||||
sort(aligned_to_8.begin(), aligned_to_8.end());
|
||||
|
||||
// Now pull out all the FieldDescriptors in order.
|
||||
fields->clear();
|
||||
for (int i = 0; i < aligned_to_8.size(); ++i) {
|
||||
fields->insert(fields->end(),
|
||||
aligned_to_8[i].fields().begin(),
|
||||
aligned_to_8[i].fields().end());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
MessageGenerator::MessageGenerator(const Descriptor* descriptor,
|
||||
const string& dllexport_decl)
|
||||
const Options& options)
|
||||
: descriptor_(descriptor),
|
||||
classname_(ClassName(descriptor, false)),
|
||||
dllexport_decl_(dllexport_decl),
|
||||
field_generators_(descriptor),
|
||||
options_(options),
|
||||
field_generators_(descriptor, options),
|
||||
nested_generators_(new scoped_ptr<MessageGenerator>[
|
||||
descriptor->nested_type_count()]),
|
||||
enum_generators_(new scoped_ptr<EnumGenerator>[
|
||||
@ -162,17 +303,17 @@ MessageGenerator::MessageGenerator(const Descriptor* descriptor,
|
||||
|
||||
for (int i = 0; i < descriptor->nested_type_count(); i++) {
|
||||
nested_generators_[i].reset(
|
||||
new MessageGenerator(descriptor->nested_type(i), dllexport_decl));
|
||||
new MessageGenerator(descriptor->nested_type(i), options));
|
||||
}
|
||||
|
||||
for (int i = 0; i < descriptor->enum_type_count(); i++) {
|
||||
enum_generators_[i].reset(
|
||||
new EnumGenerator(descriptor->enum_type(i), dllexport_decl));
|
||||
new EnumGenerator(descriptor->enum_type(i), options));
|
||||
}
|
||||
|
||||
for (int i = 0; i < descriptor->extension_count(); i++) {
|
||||
extension_generators_[i].reset(
|
||||
new ExtensionGenerator(descriptor->extension(i), dllexport_decl));
|
||||
new ExtensionGenerator(descriptor->extension(i), options));
|
||||
}
|
||||
}
|
||||
|
||||
@ -217,7 +358,7 @@ GenerateFieldAccessorDeclarations(io::Printer* printer) {
|
||||
PrintFieldComment(printer, field);
|
||||
|
||||
map<string, string> vars;
|
||||
SetCommonFieldVariables(field, &vars);
|
||||
SetCommonFieldVariables(field, &vars, options_);
|
||||
vars["constant_name"] = FieldConstantName(field);
|
||||
|
||||
if (field->is_repeated()) {
|
||||
@ -254,7 +395,7 @@ GenerateFieldAccessorDefinitions(io::Printer* printer) {
|
||||
PrintFieldComment(printer, field);
|
||||
|
||||
map<string, string> vars;
|
||||
SetCommonFieldVariables(field, &vars);
|
||||
SetCommonFieldVariables(field, &vars, options_);
|
||||
|
||||
// Generate has_$name$() or $name$_size().
|
||||
if (field->is_repeated()) {
|
||||
@ -264,10 +405,20 @@ GenerateFieldAccessorDefinitions(io::Printer* printer) {
|
||||
"}\n");
|
||||
} else {
|
||||
// Singular field.
|
||||
char buffer[kFastToBufferSize];
|
||||
vars["has_array_index"] = SimpleItoa(field->index() / 32);
|
||||
vars["has_mask"] = FastHex32ToBuffer(1u << (field->index() % 32), buffer);
|
||||
printer->Print(vars,
|
||||
"inline bool $classname$::has_$name$() const {\n"
|
||||
" return _has_bit($index$);\n"
|
||||
"}\n");
|
||||
" return (_has_bits_[$has_array_index$] & 0x$has_mask$u) != 0;\n"
|
||||
"}\n"
|
||||
"inline void $classname$::set_has_$name$() {\n"
|
||||
" _has_bits_[$has_array_index$] |= 0x$has_mask$u;\n"
|
||||
"}\n"
|
||||
"inline void $classname$::clear_has_$name$() {\n"
|
||||
" _has_bits_[$has_array_index$] &= ~0x$has_mask$u;\n"
|
||||
"}\n"
|
||||
);
|
||||
}
|
||||
|
||||
// Generate clear_$name$()
|
||||
@ -279,7 +430,8 @@ GenerateFieldAccessorDefinitions(io::Printer* printer) {
|
||||
printer->Outdent();
|
||||
|
||||
if (!field->is_repeated()) {
|
||||
printer->Print(vars, " _clear_bit($index$);\n");
|
||||
printer->Print(vars,
|
||||
" clear_has_$name$();\n");
|
||||
}
|
||||
|
||||
printer->Print("}\n");
|
||||
@ -303,10 +455,10 @@ GenerateClassDefinition(io::Printer* printer) {
|
||||
map<string, string> vars;
|
||||
vars["classname"] = classname_;
|
||||
vars["field_count"] = SimpleItoa(descriptor_->field_count());
|
||||
if (dllexport_decl_.empty()) {
|
||||
if (options_.dllexport_decl.empty()) {
|
||||
vars["dllexport"] = "";
|
||||
} else {
|
||||
vars["dllexport"] = dllexport_decl_ + " ";
|
||||
vars["dllexport"] = options_.dllexport_decl + " ";
|
||||
}
|
||||
vars["superclass"] = SuperClassName(descriptor_);
|
||||
|
||||
@ -350,6 +502,20 @@ GenerateClassDefinition(io::Printer* printer) {
|
||||
"static const $classname$& default_instance();\n"
|
||||
"\n");
|
||||
|
||||
if (!StaticInitializersForced(descriptor_->file())) {
|
||||
printer->Print(vars,
|
||||
"#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER\n"
|
||||
"// Returns the internal default instance pointer. This function can\n"
|
||||
"// return NULL thus should not be used by the user. This is intended\n"
|
||||
"// for Protobuf internal code. Please use default_instance() declared\n"
|
||||
"// above instead.\n"
|
||||
"static inline const $classname$* internal_default_instance() {\n"
|
||||
" return default_instance_;\n"
|
||||
"}\n"
|
||||
"#endif\n"
|
||||
"\n");
|
||||
}
|
||||
|
||||
|
||||
printer->Print(vars,
|
||||
"void Swap($classname$* other);\n"
|
||||
@ -444,38 +610,91 @@ GenerateClassDefinition(io::Printer* printer) {
|
||||
"// @@protoc_insertion_point(class_scope:$full_name$)\n",
|
||||
"full_name", descriptor_->full_name());
|
||||
|
||||
// Generate private members for fields.
|
||||
// Generate private members.
|
||||
printer->Outdent();
|
||||
printer->Print(" private:\n");
|
||||
printer->Indent();
|
||||
|
||||
|
||||
for (int i = 0; i < descriptor_->field_count(); i++) {
|
||||
if (!descriptor_->field(i)->is_repeated()) {
|
||||
printer->Print(
|
||||
"inline void set_has_$name$();\n",
|
||||
"name", FieldName(descriptor_->field(i)));
|
||||
printer->Print(
|
||||
"inline void clear_has_$name$();\n",
|
||||
"name", FieldName(descriptor_->field(i)));
|
||||
}
|
||||
}
|
||||
printer->Print("\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) {
|
||||
printer->Print(
|
||||
"::google::protobuf::internal::ExtensionSet _extensions_;\n");
|
||||
"::google::protobuf::internal::ExtensionSet _extensions_;\n"
|
||||
"\n");
|
||||
}
|
||||
|
||||
if (HasUnknownFields(descriptor_->file())) {
|
||||
printer->Print(
|
||||
"::google::protobuf::UnknownFieldSet _unknown_fields_;\n");
|
||||
"::google::protobuf::UnknownFieldSet _unknown_fields_;\n"
|
||||
"\n");
|
||||
}
|
||||
|
||||
// Field members:
|
||||
|
||||
vector<const FieldDescriptor*> fields;
|
||||
for (int i = 0; i < descriptor_->field_count(); i++) {
|
||||
fields.push_back(descriptor_->field(i));
|
||||
}
|
||||
OptimizePadding(&fields);
|
||||
for (int i = 0; i < fields.size(); ++i) {
|
||||
field_generators_.get(fields[i]).GeneratePrivateMembers(printer);
|
||||
}
|
||||
|
||||
// Members assumed to align to 4 bytes:
|
||||
|
||||
// TODO(kenton): Make _cached_size_ an atomic<int> when C++ supports it.
|
||||
printer->Print(
|
||||
"mutable int _cached_size_;\n"
|
||||
"\n");
|
||||
for (int i = 0; i < descriptor_->field_count(); i++) {
|
||||
field_generators_.get(descriptor_->field(i))
|
||||
.GeneratePrivateMembers(printer);
|
||||
"\n"
|
||||
"mutable int _cached_size_;\n");
|
||||
|
||||
// Generate _has_bits_.
|
||||
if (descriptor_->field_count() > 0) {
|
||||
printer->Print(vars,
|
||||
"::google::protobuf::uint32 _has_bits_[($field_count$ + 31) / 32];\n"
|
||||
"\n");
|
||||
} else {
|
||||
// Zero-size arrays aren't technically allowed, and MSVC in particular
|
||||
// doesn't like them. We still need to declare these arrays to make
|
||||
// other code compile. Since this is an uncommon case, we'll just declare
|
||||
// them with size 1 and waste some space. Oh well.
|
||||
printer->Print(
|
||||
"::google::protobuf::uint32 _has_bits_[1];\n"
|
||||
"\n");
|
||||
}
|
||||
|
||||
// Declare AddDescriptors(), BuildDescriptors(), and ShutdownFile() as
|
||||
// friends so that they can access private static variables like
|
||||
// default_instance_ and reflection_.
|
||||
printer->Print(
|
||||
PrintHandlingOptionalStaticInitializers(
|
||||
descriptor_->file(), printer,
|
||||
// With static initializers.
|
||||
"friend void $dllexport_decl$ $adddescriptorsname$();\n",
|
||||
"dllexport_decl", dllexport_decl_,
|
||||
// Without.
|
||||
"friend void $dllexport_decl$ $adddescriptorsname$_impl();\n",
|
||||
// Vars.
|
||||
"dllexport_decl", options_.dllexport_decl,
|
||||
"adddescriptorsname",
|
||||
GlobalAddDescriptorsName(descriptor_->file()->name()));
|
||||
GlobalAddDescriptorsName(descriptor_->file()->name()));
|
||||
|
||||
printer->Print(
|
||||
"friend void $assigndescriptorsname$();\n"
|
||||
"friend void $shutdownfilename$();\n"
|
||||
@ -484,32 +703,7 @@ GenerateClassDefinition(io::Printer* printer) {
|
||||
GlobalAssignDescriptorsName(descriptor_->file()->name()),
|
||||
"shutdownfilename", GlobalShutdownFileName(descriptor_->file()->name()));
|
||||
|
||||
// Generate offsets and _has_bits_ boilerplate.
|
||||
if (descriptor_->field_count() > 0) {
|
||||
printer->Print(vars,
|
||||
"::google::protobuf::uint32 _has_bits_[($field_count$ + 31) / 32];\n");
|
||||
} else {
|
||||
// Zero-size arrays aren't technically allowed, and MSVC in particular
|
||||
// doesn't like them. We still need to declare these arrays to make
|
||||
// other code compile. Since this is an uncommon case, we'll just declare
|
||||
// them with size 1 and waste some space. Oh well.
|
||||
printer->Print(
|
||||
"::google::protobuf::uint32 _has_bits_[1];\n");
|
||||
}
|
||||
|
||||
printer->Print(
|
||||
"\n"
|
||||
"// WHY DOES & HAVE LOWER PRECEDENCE THAN != !?\n"
|
||||
"inline bool _has_bit(int index) const {\n"
|
||||
" return (_has_bits_[index / 32] & (1u << (index % 32))) != 0;\n"
|
||||
"}\n"
|
||||
"inline void _set_bit(int index) {\n"
|
||||
" _has_bits_[index / 32] |= (1u << (index % 32));\n"
|
||||
"}\n"
|
||||
"inline void _clear_bit(int index) {\n"
|
||||
" _has_bits_[index / 32] &= ~(1u << (index % 32));\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"void InitAsDefaultInstance();\n"
|
||||
"static $classname$* default_instance_;\n",
|
||||
"classname", classname_);
|
||||
@ -589,9 +783,11 @@ GenerateDescriptorInitializer(io::Printer* printer, int index) {
|
||||
printer->Print(vars,
|
||||
" -1,\n");
|
||||
}
|
||||
printer->Print(
|
||||
" ::google::protobuf::DescriptorPool::generated_pool(),\n");
|
||||
printer->Print(vars,
|
||||
" ::google::protobuf::MessageFactory::generated_factory(),\n");
|
||||
printer->Print(vars,
|
||||
" ::google::protobuf::DescriptorPool::generated_pool(),\n"
|
||||
" ::google::protobuf::MessageFactory::generated_factory(),\n"
|
||||
" sizeof($classname$));\n");
|
||||
|
||||
// Handle nested types.
|
||||
@ -620,6 +816,13 @@ GenerateTypeRegistrations(io::Printer* printer) {
|
||||
|
||||
void MessageGenerator::
|
||||
GenerateDefaultInstanceAllocator(io::Printer* printer) {
|
||||
// Construct the default instances of all fields, as they will be used
|
||||
// when creating the default instance of the entire message.
|
||||
for (int i = 0; i < descriptor_->field_count(); i++) {
|
||||
field_generators_.get(descriptor_->field(i))
|
||||
.GenerateDefaultInstanceAllocator(printer);
|
||||
}
|
||||
|
||||
// Construct the default instance. We can't call InitAsDefaultInstance() yet
|
||||
// because we need to make sure all default instances that this one might
|
||||
// depend on are constructed first.
|
||||
@ -663,6 +866,12 @@ GenerateShutdownCode(io::Printer* printer) {
|
||||
"classname", classname_);
|
||||
}
|
||||
|
||||
// Handle default instances of fields.
|
||||
for (int i = 0; i < descriptor_->field_count(); i++) {
|
||||
field_generators_.get(descriptor_->field(i))
|
||||
.GenerateShutdownCode(printer);
|
||||
}
|
||||
|
||||
// Handle nested types.
|
||||
for (int i = 0; i < descriptor_->nested_type_count(); i++) {
|
||||
nested_generators_[i]->GenerateShutdownCode(printer);
|
||||
@ -817,8 +1026,12 @@ GenerateSharedDestructorCode(io::Printer* printer) {
|
||||
.GenerateDestructorCode(printer);
|
||||
}
|
||||
|
||||
printer->Print(
|
||||
"if (this != default_instance_) {\n");
|
||||
PrintHandlingOptionalStaticInitializers(
|
||||
descriptor_->file(), printer,
|
||||
// With static initializers.
|
||||
"if (this != default_instance_) {\n",
|
||||
// Without.
|
||||
"if (this != &default_instance()) {\n");
|
||||
|
||||
// We need to delete all embedded messages.
|
||||
// TODO(kenton): If we make unset messages point at default instances
|
||||
@ -870,10 +1083,16 @@ GenerateStructors(io::Printer* printer) {
|
||||
|
||||
if (!field->is_repeated() &&
|
||||
field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
|
||||
printer->Print(
|
||||
" $name$_ = const_cast< $type$*>(&$type$::default_instance());\n",
|
||||
"name", FieldName(field),
|
||||
"type", FieldMessageTypeName(field));
|
||||
PrintHandlingOptionalStaticInitializers(
|
||||
descriptor_->file(), printer,
|
||||
// With static initializers.
|
||||
" $name$_ = const_cast< $type$*>(&$type$::default_instance());\n",
|
||||
// Without.
|
||||
" $name$_ = const_cast< $type$*>(\n"
|
||||
" $type$::internal_default_instance());\n",
|
||||
// Vars.
|
||||
"name", FieldName(field),
|
||||
"type", FieldMessageTypeName(field));
|
||||
}
|
||||
}
|
||||
printer->Print(
|
||||
@ -929,8 +1148,20 @@ GenerateStructors(io::Printer* printer) {
|
||||
}
|
||||
|
||||
printer->Print(
|
||||
"const $classname$& $classname$::default_instance() {\n"
|
||||
" if (default_instance_ == NULL) $adddescriptorsname$();"
|
||||
"const $classname$& $classname$::default_instance() {\n",
|
||||
"classname", classname_);
|
||||
|
||||
PrintHandlingOptionalStaticInitializers(
|
||||
descriptor_->file(), printer,
|
||||
// With static initializers.
|
||||
" if (default_instance_ == NULL) $adddescriptorsname$();\n",
|
||||
// Without.
|
||||
" $adddescriptorsname$();\n",
|
||||
// Vars.
|
||||
"adddescriptorsname",
|
||||
GlobalAddDescriptorsName(descriptor_->file()->name()));
|
||||
|
||||
printer->Print(
|
||||
" return *default_instance_;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
@ -942,7 +1173,6 @@ GenerateStructors(io::Printer* printer) {
|
||||
"classname", classname_,
|
||||
"adddescriptorsname",
|
||||
GlobalAddDescriptorsName(descriptor_->file()->name()));
|
||||
|
||||
}
|
||||
|
||||
void MessageGenerator::
|
||||
@ -961,9 +1191,6 @@ GenerateClear(io::Printer* printer) {
|
||||
const FieldDescriptor* field = descriptor_->field(i);
|
||||
|
||||
if (!field->is_repeated()) {
|
||||
map<string, string> vars;
|
||||
vars["index"] = SimpleItoa(field->index());
|
||||
|
||||
// We can use the fact that _has_bits_ is a giant bitfield to our
|
||||
// advantage: We can check up to 32 bits at a time for equality to
|
||||
// zero, and skip the whole range if so. This can improve the speed
|
||||
@ -975,8 +1202,9 @@ GenerateClear(io::Printer* printer) {
|
||||
printer->Outdent();
|
||||
printer->Print("}\n");
|
||||
}
|
||||
printer->Print(vars,
|
||||
"if (_has_bits_[$index$ / 32] & (0xffu << ($index$ % 32))) {\n");
|
||||
printer->Print(
|
||||
"if (_has_bits_[$index$ / 32] & (0xffu << ($index$ % 32))) {\n",
|
||||
"index", SimpleItoa(field->index()));
|
||||
printer->Indent();
|
||||
}
|
||||
last_index = i;
|
||||
@ -989,7 +1217,9 @@ GenerateClear(io::Printer* printer) {
|
||||
field->cpp_type() == FieldDescriptor::CPPTYPE_STRING;
|
||||
|
||||
if (should_check_bit) {
|
||||
printer->Print(vars, "if (_has_bit($index$)) {\n");
|
||||
printer->Print(
|
||||
"if (has_$name$()) {\n",
|
||||
"name", FieldName(field));
|
||||
printer->Indent();
|
||||
}
|
||||
|
||||
@ -1129,24 +1359,23 @@ GenerateMergeFrom(io::Printer* printer) {
|
||||
const FieldDescriptor* field = descriptor_->field(i);
|
||||
|
||||
if (!field->is_repeated()) {
|
||||
map<string, string> vars;
|
||||
vars["index"] = SimpleItoa(field->index());
|
||||
|
||||
// See above in GenerateClear for an explanation of this.
|
||||
if (i / 8 != last_index / 8 || last_index < 0) {
|
||||
if (last_index >= 0) {
|
||||
printer->Outdent();
|
||||
printer->Print("}\n");
|
||||
}
|
||||
printer->Print(vars,
|
||||
"if (from._has_bits_[$index$ / 32] & (0xffu << ($index$ % 32))) {\n");
|
||||
printer->Print(
|
||||
"if (from._has_bits_[$index$ / 32] & (0xffu << ($index$ % 32))) {\n",
|
||||
"index", SimpleItoa(field->index()));
|
||||
printer->Indent();
|
||||
}
|
||||
|
||||
last_index = i;
|
||||
|
||||
printer->Print(vars,
|
||||
"if (from._has_bit($index$)) {\n");
|
||||
printer->Print(
|
||||
"if (from.has_$name$()) {\n",
|
||||
"name", FieldName(field));
|
||||
printer->Indent();
|
||||
|
||||
field_generators_.get(field).GenerateMergingCode(printer);
|
||||
@ -1214,11 +1443,22 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
|
||||
// Special-case MessageSet.
|
||||
printer->Print(
|
||||
"bool $classname$::MergePartialFromCodedStream(\n"
|
||||
" ::google::protobuf::io::CodedInputStream* input) {\n"
|
||||
" return _extensions_.ParseMessageSet(input, default_instance_,\n"
|
||||
" mutable_unknown_fields());\n"
|
||||
"}\n",
|
||||
" ::google::protobuf::io::CodedInputStream* input) {\n",
|
||||
"classname", classname_);
|
||||
|
||||
PrintHandlingOptionalStaticInitializers(
|
||||
descriptor_->file(), printer,
|
||||
// With static initializers.
|
||||
" return _extensions_.ParseMessageSet(input, default_instance_,\n"
|
||||
" mutable_unknown_fields());\n",
|
||||
// Without.
|
||||
" return _extensions_.ParseMessageSet(input, &default_instance(),\n"
|
||||
" mutable_unknown_fields());\n",
|
||||
// Vars.
|
||||
"classname", classname_);
|
||||
|
||||
printer->Print(
|
||||
"}\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1378,12 +1618,21 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
|
||||
}
|
||||
printer->Print(") {\n");
|
||||
if (HasUnknownFields(descriptor_->file())) {
|
||||
printer->Print(
|
||||
PrintHandlingOptionalStaticInitializers(
|
||||
descriptor_->file(), printer,
|
||||
// With static initializers.
|
||||
" DO_(_extensions_.ParseField(tag, input, default_instance_,\n"
|
||||
" mutable_unknown_fields()));\n",
|
||||
// Without.
|
||||
" DO_(_extensions_.ParseField(tag, input, &default_instance(),\n"
|
||||
" mutable_unknown_fields()));\n");
|
||||
} else {
|
||||
printer->Print(
|
||||
" DO_(_extensions_.ParseField(tag, input, default_instance_));\n");
|
||||
PrintHandlingOptionalStaticInitializers(
|
||||
descriptor_->file(), printer,
|
||||
// With static initializers.
|
||||
" DO_(_extensions_.ParseField(tag, input, default_instance_));\n",
|
||||
// Without.
|
||||
" DO_(_extensions_.ParseField(tag, input, &default_instance()));\n");
|
||||
}
|
||||
printer->Print(
|
||||
" continue;\n"
|
||||
@ -1423,8 +1672,8 @@ void MessageGenerator::GenerateSerializeOneField(
|
||||
|
||||
if (!field->is_repeated()) {
|
||||
printer->Print(
|
||||
"if (_has_bit($index$)) {\n",
|
||||
"index", SimpleItoa(field->index()));
|
||||
"if (has_$name$()) {\n",
|
||||
"name", FieldName(field));
|
||||
printer->Indent();
|
||||
}
|
||||
|
||||
@ -1734,6 +1983,7 @@ GenerateIsInitialized(io::Printer* printer) {
|
||||
for (int i = 0; i < descriptor_->field_count(); i++) {
|
||||
const FieldDescriptor* field = descriptor_->field(i);
|
||||
if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
|
||||
!ShouldIgnoreRequiredFieldCheck(field) &&
|
||||
HasRequiredFields(field->message_type())) {
|
||||
if (field->is_repeated()) {
|
||||
printer->Print(
|
@ -38,6 +38,7 @@
|
||||
#include <string>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/compiler/cpp/cpp_field.h>
|
||||
#include <google/protobuf/compiler/cpp/cpp_options.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
@ -57,7 +58,7 @@ class MessageGenerator {
|
||||
public:
|
||||
// See generator.cc for the meaning of dllexport_decl.
|
||||
explicit MessageGenerator(const Descriptor* descriptor,
|
||||
const string& dllexport_decl);
|
||||
const Options& options);
|
||||
~MessageGenerator();
|
||||
|
||||
// Header stuff.
|
||||
@ -153,7 +154,7 @@ class MessageGenerator {
|
||||
|
||||
const Descriptor* descriptor_;
|
||||
string classname_;
|
||||
string dllexport_decl_;
|
||||
Options options_;
|
||||
FieldGeneratorMap field_generators_;
|
||||
scoped_array<scoped_ptr<MessageGenerator> > nested_generators_;
|
||||
scoped_array<scoped_ptr<EnumGenerator> > enum_generators_;
|
@ -45,8 +45,9 @@ namespace cpp {
|
||||
namespace {
|
||||
|
||||
void SetMessageVariables(const FieldDescriptor* descriptor,
|
||||
map<string, string>* variables) {
|
||||
SetCommonFieldVariables(descriptor, variables);
|
||||
map<string, string>* variables,
|
||||
const Options& options) {
|
||||
SetCommonFieldVariables(descriptor, variables, options);
|
||||
(*variables)["type"] = FieldMessageTypeName(descriptor);
|
||||
(*variables)["stream_writer"] = (*variables)["declared_type"] +
|
||||
(HasFastArraySerialization(descriptor->message_type()->file()) ?
|
||||
@ -59,9 +60,10 @@ void SetMessageVariables(const FieldDescriptor* descriptor,
|
||||
// ===================================================================
|
||||
|
||||
MessageFieldGenerator::
|
||||
MessageFieldGenerator(const FieldDescriptor* descriptor)
|
||||
MessageFieldGenerator(const FieldDescriptor* descriptor,
|
||||
const Options& options)
|
||||
: descriptor_(descriptor) {
|
||||
SetMessageVariables(descriptor, &variables_);
|
||||
SetMessageVariables(descriptor, &variables_, options);
|
||||
}
|
||||
|
||||
MessageFieldGenerator::~MessageFieldGenerator() {}
|
||||
@ -75,19 +77,44 @@ void MessageFieldGenerator::
|
||||
GenerateAccessorDeclarations(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"inline const $type$& $name$() const$deprecation$;\n"
|
||||
"inline $type$* mutable_$name$()$deprecation$;\n");
|
||||
"inline $type$* mutable_$name$()$deprecation$;\n"
|
||||
"inline $type$* release_$name$()$deprecation$;\n"
|
||||
"inline void set_allocated_$name$($type$* $name$)$deprecation$;\n");
|
||||
}
|
||||
|
||||
void MessageFieldGenerator::
|
||||
GenerateInlineAccessorDefinitions(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"inline const $type$& $classname$::$name$() const {\n"
|
||||
" return $name$_ != NULL ? *$name$_ : *default_instance_->$name$_;\n"
|
||||
"inline const $type$& $classname$::$name$() const {\n");
|
||||
|
||||
PrintHandlingOptionalStaticInitializers(
|
||||
variables_, descriptor_->file(), printer,
|
||||
// With static initializers.
|
||||
" return $name$_ != NULL ? *$name$_ : *default_instance_->$name$_;\n",
|
||||
// Without.
|
||||
" return $name$_ != NULL ? *$name$_ : *default_instance().$name$_;\n");
|
||||
|
||||
printer->Print(variables_,
|
||||
"}\n"
|
||||
"inline $type$* $classname$::mutable_$name$() {\n"
|
||||
" _set_bit($index$);\n"
|
||||
" set_has_$name$();\n"
|
||||
" if ($name$_ == NULL) $name$_ = new $type$;\n"
|
||||
" return $name$_;\n"
|
||||
"}\n"
|
||||
"inline $type$* $classname$::release_$name$() {\n"
|
||||
" clear_has_$name$();\n"
|
||||
" $type$* temp = $name$_;\n"
|
||||
" $name$_ = NULL;\n"
|
||||
" return temp;\n"
|
||||
"}\n"
|
||||
"inline void $classname$::set_allocated_$name$($type$* $name$) {\n"
|
||||
" delete $name$_;\n"
|
||||
" $name$_ = $name$;\n"
|
||||
" if ($name$) {\n"
|
||||
" set_has_$name$();\n"
|
||||
" } else {\n"
|
||||
" clear_has_$name$();\n"
|
||||
" }\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
@ -152,9 +179,10 @@ GenerateByteSize(io::Printer* printer) const {
|
||||
// ===================================================================
|
||||
|
||||
RepeatedMessageFieldGenerator::
|
||||
RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor)
|
||||
RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor,
|
||||
const Options& options)
|
||||
: descriptor_(descriptor) {
|
||||
SetMessageVariables(descriptor, &variables_);
|
||||
SetMessageVariables(descriptor, &variables_, options);
|
||||
}
|
||||
|
||||
RepeatedMessageFieldGenerator::~RepeatedMessageFieldGenerator() {}
|
||||
@ -182,7 +210,7 @@ void RepeatedMessageFieldGenerator::
|
||||
GenerateInlineAccessorDefinitions(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"inline const $type$& $classname$::$name$(int index) const {\n"
|
||||
" return $name$_.Get(index);\n"
|
||||
" return $name$_.$cppget$(index);\n"
|
||||
"}\n"
|
||||
"inline $type$* $classname$::mutable_$name$(int index) {\n"
|
||||
" return $name$_.Mutable(index);\n"
|
@ -46,7 +46,8 @@ namespace cpp {
|
||||
|
||||
class MessageFieldGenerator : public FieldGenerator {
|
||||
public:
|
||||
explicit MessageFieldGenerator(const FieldDescriptor* descriptor);
|
||||
explicit MessageFieldGenerator(const FieldDescriptor* descriptor,
|
||||
const Options& options);
|
||||
~MessageFieldGenerator();
|
||||
|
||||
// implements FieldGenerator ---------------------------------------
|
||||
@ -71,7 +72,8 @@ class MessageFieldGenerator : public FieldGenerator {
|
||||
|
||||
class RepeatedMessageFieldGenerator : public FieldGenerator {
|
||||
public:
|
||||
explicit RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor);
|
||||
explicit RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor,
|
||||
const Options& options);
|
||||
~RepeatedMessageFieldGenerator();
|
||||
|
||||
// implements FieldGenerator ---------------------------------------
|
@ -28,36 +28,31 @@
|
||||
// (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: rennie@google.com (Jeffrey Rennie)
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_OPTIONS_H__
|
||||
#define GOOGLE_PROTOBUF_COMPILER_CPP_OPTIONS_H__
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <vector>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/io/zero_copy_stream.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace cpp {
|
||||
|
||||
class ZipWriter {
|
||||
public:
|
||||
ZipWriter(io::ZeroCopyOutputStream* raw_output);
|
||||
~ZipWriter();
|
||||
|
||||
bool Write(const string& filename, const string& contents);
|
||||
bool WriteDirectory();
|
||||
|
||||
private:
|
||||
struct FileInfo {
|
||||
string name;
|
||||
uint32 offset;
|
||||
uint32 size;
|
||||
uint32 crc32;
|
||||
};
|
||||
|
||||
io::ZeroCopyOutputStream* raw_output_;
|
||||
vector<FileInfo> files_;
|
||||
// Generator options:
|
||||
struct Options {
|
||||
Options() : safe_boundary_check(false) {
|
||||
}
|
||||
string dllexport_decl;
|
||||
bool safe_boundary_check;
|
||||
};
|
||||
|
||||
} // namespace google
|
||||
} // namespace protobuf
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_OPTIONS_H__
|
@ -56,24 +56,24 @@ class TestGenerator : public CodeGenerator {
|
||||
|
||||
virtual bool Generate(const FileDescriptor* file,
|
||||
const string& parameter,
|
||||
OutputDirectory* output_directory,
|
||||
GeneratorContext* context,
|
||||
string* error) const {
|
||||
TryInsert("test.pb.h", "includes", output_directory);
|
||||
TryInsert("test.pb.h", "namespace_scope", output_directory);
|
||||
TryInsert("test.pb.h", "global_scope", output_directory);
|
||||
TryInsert("test.pb.h", "class_scope:foo.Bar", output_directory);
|
||||
TryInsert("test.pb.h", "class_scope:foo.Bar.Baz", output_directory);
|
||||
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", output_directory);
|
||||
TryInsert("test.pb.cc", "namespace_scope", output_directory);
|
||||
TryInsert("test.pb.cc", "global_scope", output_directory);
|
||||
TryInsert("test.pb.cc", "includes", context);
|
||||
TryInsert("test.pb.cc", "namespace_scope", context);
|
||||
TryInsert("test.pb.cc", "global_scope", context);
|
||||
return true;
|
||||
}
|
||||
|
||||
void TryInsert(const string& filename, const string& insertion_point,
|
||||
OutputDirectory* output_directory) const {
|
||||
GeneratorContext* context) const {
|
||||
scoped_ptr<io::ZeroCopyOutputStream> output(
|
||||
output_directory->OpenForInsert(filename, insertion_point));
|
||||
context->OpenForInsert(filename, insertion_point));
|
||||
io::Printer printer(output.get(), '$');
|
||||
printer.Print("// inserted $name$\n", "name", insertion_point);
|
||||
}
|
@ -80,8 +80,9 @@ int FixedSize(FieldDescriptor::Type type) {
|
||||
}
|
||||
|
||||
void SetPrimitiveVariables(const FieldDescriptor* descriptor,
|
||||
map<string, string>* variables) {
|
||||
SetCommonFieldVariables(descriptor, variables);
|
||||
map<string, string>* variables,
|
||||
const Options& options) {
|
||||
SetCommonFieldVariables(descriptor, variables, options);
|
||||
(*variables)["type"] = PrimitiveTypeName(descriptor->cpp_type());
|
||||
(*variables)["default"] = DefaultValue(descriptor);
|
||||
(*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor));
|
||||
@ -99,9 +100,10 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor,
|
||||
// ===================================================================
|
||||
|
||||
PrimitiveFieldGenerator::
|
||||
PrimitiveFieldGenerator(const FieldDescriptor* descriptor)
|
||||
PrimitiveFieldGenerator(const FieldDescriptor* descriptor,
|
||||
const Options& options)
|
||||
: descriptor_(descriptor) {
|
||||
SetPrimitiveVariables(descriptor, &variables_);
|
||||
SetPrimitiveVariables(descriptor, &variables_, options);
|
||||
}
|
||||
|
||||
PrimitiveFieldGenerator::~PrimitiveFieldGenerator() {}
|
||||
@ -125,7 +127,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
|
||||
" return $name$_;\n"
|
||||
"}\n"
|
||||
"inline void $classname$::set_$name$($type$ value) {\n"
|
||||
" _set_bit($index$);\n"
|
||||
" set_has_$name$();\n"
|
||||
" $name$_ = value;\n"
|
||||
"}\n");
|
||||
}
|
||||
@ -156,7 +158,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) const {
|
||||
"DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n"
|
||||
" $type$, $wire_format_field_type$>(\n"
|
||||
" input, &$name$_)));\n"
|
||||
"_set_bit($index$);\n");
|
||||
"set_has_$name$();\n");
|
||||
}
|
||||
|
||||
void PrimitiveFieldGenerator::
|
||||
@ -190,9 +192,10 @@ GenerateByteSize(io::Printer* printer) const {
|
||||
// ===================================================================
|
||||
|
||||
RepeatedPrimitiveFieldGenerator::
|
||||
RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor)
|
||||
RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor,
|
||||
const Options& options)
|
||||
: descriptor_(descriptor) {
|
||||
SetPrimitiveVariables(descriptor, &variables_);
|
||||
SetPrimitiveVariables(descriptor, &variables_, options);
|
||||
|
||||
if (descriptor->options().packed()) {
|
||||
variables_["packed_reader"] = "ReadPackedPrimitive";
|
||||
@ -366,7 +369,9 @@ GenerateByteSize(io::Printer* printer) const {
|
||||
" total_size += $tag_size$ +\n"
|
||||
" ::google::protobuf::internal::WireFormatLite::Int32Size(data_size);\n"
|
||||
"}\n"
|
||||
"GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();\n"
|
||||
"_$name$_cached_byte_size_ = data_size;\n"
|
||||
"GOOGLE_SAFE_CONCURRENT_WRITES_END();\n"
|
||||
"total_size += data_size;\n");
|
||||
} else {
|
||||
printer->Print(variables_,
|
@ -46,7 +46,8 @@ namespace cpp {
|
||||
|
||||
class PrimitiveFieldGenerator : public FieldGenerator {
|
||||
public:
|
||||
explicit PrimitiveFieldGenerator(const FieldDescriptor* descriptor);
|
||||
explicit PrimitiveFieldGenerator(const FieldDescriptor* descriptor,
|
||||
const Options& options);
|
||||
~PrimitiveFieldGenerator();
|
||||
|
||||
// implements FieldGenerator ---------------------------------------
|
||||
@ -71,7 +72,8 @@ class PrimitiveFieldGenerator : public FieldGenerator {
|
||||
|
||||
class RepeatedPrimitiveFieldGenerator : public FieldGenerator {
|
||||
public:
|
||||
explicit RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor);
|
||||
explicit RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor,
|
||||
const Options& options);
|
||||
~RepeatedPrimitiveFieldGenerator();
|
||||
|
||||
// implements FieldGenerator ---------------------------------------
|
@ -43,14 +43,14 @@ namespace compiler {
|
||||
namespace cpp {
|
||||
|
||||
ServiceGenerator::ServiceGenerator(const ServiceDescriptor* descriptor,
|
||||
const string& dllexport_decl)
|
||||
const Options& options)
|
||||
: descriptor_(descriptor) {
|
||||
vars_["classname"] = descriptor_->name();
|
||||
vars_["full_name"] = descriptor_->full_name();
|
||||
if (dllexport_decl.empty()) {
|
||||
if (options.dllexport_decl.empty()) {
|
||||
vars_["dllexport"] = "";
|
||||
} else {
|
||||
vars_["dllexport"] = dllexport_decl + " ";
|
||||
vars_["dllexport"] = options.dllexport_decl + " ";
|
||||
}
|
||||
}
|
||||
|
@ -38,6 +38,7 @@
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/compiler/cpp/cpp_options.h>
|
||||
#include <google/protobuf/descriptor.h>
|
||||
|
||||
namespace google {
|
||||
@ -55,7 +56,7 @@ class ServiceGenerator {
|
||||
public:
|
||||
// See generator.cc for the meaning of dllexport_decl.
|
||||
explicit ServiceGenerator(const ServiceDescriptor* descriptor,
|
||||
const string& dllexport_decl);
|
||||
const Options& options);
|
||||
~ServiceGenerator();
|
||||
|
||||
// Header stuff.
|
@ -46,10 +46,15 @@ namespace cpp {
|
||||
namespace {
|
||||
|
||||
void SetStringVariables(const FieldDescriptor* descriptor,
|
||||
map<string, string>* variables) {
|
||||
SetCommonFieldVariables(descriptor, variables);
|
||||
(*variables)["default"] =
|
||||
"\"" + CEscape(descriptor->default_value_string()) + "\"";
|
||||
map<string, string>* variables,
|
||||
const Options& options) {
|
||||
SetCommonFieldVariables(descriptor, variables, options);
|
||||
(*variables)["default"] = DefaultValue(descriptor);
|
||||
(*variables)["default_length"] =
|
||||
SimpleItoa(descriptor->default_value_string().length());
|
||||
(*variables)["default_variable"] = descriptor->default_value_string().empty()
|
||||
? "&::google::protobuf::internal::kEmptyString"
|
||||
: "_default_" + FieldName(descriptor) + "_";
|
||||
(*variables)["pointer_type"] =
|
||||
descriptor->type() == FieldDescriptor::TYPE_BYTES ? "void" : "char";
|
||||
}
|
||||
@ -59,18 +64,20 @@ void SetStringVariables(const FieldDescriptor* descriptor,
|
||||
// ===================================================================
|
||||
|
||||
StringFieldGenerator::
|
||||
StringFieldGenerator(const FieldDescriptor* descriptor)
|
||||
StringFieldGenerator(const FieldDescriptor* descriptor,
|
||||
const Options& options)
|
||||
: descriptor_(descriptor) {
|
||||
SetStringVariables(descriptor, &variables_);
|
||||
SetStringVariables(descriptor, &variables_, options);
|
||||
}
|
||||
|
||||
StringFieldGenerator::~StringFieldGenerator() {}
|
||||
|
||||
void StringFieldGenerator::
|
||||
GeneratePrivateMembers(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"::std::string* $name$_;\n"
|
||||
"static const ::std::string _default_$name$_;\n");
|
||||
printer->Print(variables_, "::std::string* $name$_;\n");
|
||||
if (!descriptor_->default_value_string().empty()) {
|
||||
printer->Print(variables_, "static ::std::string* $default_variable$;\n");
|
||||
}
|
||||
}
|
||||
|
||||
void StringFieldGenerator::
|
||||
@ -105,7 +112,10 @@ GenerateAccessorDeclarations(io::Printer* printer) const {
|
||||
"inline void set_$name$(const char* value)$deprecation$;\n"
|
||||
"inline void set_$name$(const $pointer_type$* value, size_t size)"
|
||||
"$deprecation$;\n"
|
||||
"inline ::std::string* mutable_$name$()$deprecation$;\n");
|
||||
"inline ::std::string* mutable_$name$()$deprecation$;\n"
|
||||
"inline ::std::string* release_$name$()$deprecation$;\n"
|
||||
"inline void set_allocated_$name$(::std::string* $name$)$deprecation$;\n");
|
||||
|
||||
|
||||
if (descriptor_->options().ctype() != FieldOptions::STRING) {
|
||||
printer->Outdent();
|
||||
@ -121,51 +131,71 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
|
||||
" return *$name$_;\n"
|
||||
"}\n"
|
||||
"inline void $classname$::set_$name$(const ::std::string& value) {\n"
|
||||
" _set_bit($index$);\n"
|
||||
" if ($name$_ == &_default_$name$_) {\n"
|
||||
" set_has_$name$();\n"
|
||||
" if ($name$_ == $default_variable$) {\n"
|
||||
" $name$_ = new ::std::string;\n"
|
||||
" }\n"
|
||||
" $name$_->assign(value);\n"
|
||||
"}\n"
|
||||
"inline void $classname$::set_$name$(const char* value) {\n"
|
||||
" _set_bit($index$);\n"
|
||||
" if ($name$_ == &_default_$name$_) {\n"
|
||||
" set_has_$name$();\n"
|
||||
" if ($name$_ == $default_variable$) {\n"
|
||||
" $name$_ = new ::std::string;\n"
|
||||
" }\n"
|
||||
" $name$_->assign(value);\n"
|
||||
"}\n"
|
||||
"inline "
|
||||
"void $classname$::set_$name$(const $pointer_type$* value, size_t size) {\n"
|
||||
" _set_bit($index$);\n"
|
||||
" if ($name$_ == &_default_$name$_) {\n"
|
||||
" set_has_$name$();\n"
|
||||
" if ($name$_ == $default_variable$) {\n"
|
||||
" $name$_ = new ::std::string;\n"
|
||||
" }\n"
|
||||
" $name$_->assign(reinterpret_cast<const char*>(value), size);\n"
|
||||
"}\n"
|
||||
"inline ::std::string* $classname$::mutable_$name$() {\n"
|
||||
" _set_bit($index$);\n"
|
||||
" if ($name$_ == &_default_$name$_) {\n");
|
||||
" set_has_$name$();\n"
|
||||
" if ($name$_ == $default_variable$) {\n");
|
||||
if (descriptor_->default_value_string().empty()) {
|
||||
printer->Print(variables_,
|
||||
" $name$_ = new ::std::string;\n");
|
||||
} else {
|
||||
printer->Print(variables_,
|
||||
" $name$_ = new ::std::string(_default_$name$_);\n");
|
||||
" $name$_ = new ::std::string(*$default_variable$);\n");
|
||||
}
|
||||
printer->Print(variables_,
|
||||
" }\n"
|
||||
" return $name$_;\n"
|
||||
"}\n"
|
||||
"inline ::std::string* $classname$::release_$name$() {\n"
|
||||
" clear_has_$name$();\n"
|
||||
" if ($name$_ == $default_variable$) {\n"
|
||||
" return NULL;\n"
|
||||
" } else {\n"
|
||||
" ::std::string* temp = $name$_;\n"
|
||||
" $name$_ = const_cast< ::std::string*>($default_variable$);\n"
|
||||
" return temp;\n"
|
||||
" }\n"
|
||||
"}\n"
|
||||
"inline void $classname$::set_allocated_$name$(::std::string* $name$) {\n"
|
||||
" if ($name$_ != $default_variable$) {\n"
|
||||
" delete $name$_;\n"
|
||||
" }\n"
|
||||
" if ($name$) {\n"
|
||||
" set_has_$name$();\n"
|
||||
" $name$_ = $name$;\n"
|
||||
" } else {\n"
|
||||
" clear_has_$name$();\n"
|
||||
" $name$_ = const_cast< ::std::string*>($default_variable$);\n"
|
||||
" }\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void StringFieldGenerator::
|
||||
GenerateNonInlineAccessorDefinitions(io::Printer* printer) const {
|
||||
if (descriptor_->default_value_string().empty()) {
|
||||
if (!descriptor_->default_value_string().empty()) {
|
||||
// Initialized in GenerateDefaultInstanceAllocator.
|
||||
printer->Print(variables_,
|
||||
"const ::std::string $classname$::_default_$name$_;\n");
|
||||
} else {
|
||||
printer->Print(variables_,
|
||||
"const ::std::string $classname$::_default_$name$_($default$);\n");
|
||||
"::std::string* $classname$::$default_variable$ = NULL;\n");
|
||||
}
|
||||
}
|
||||
|
||||
@ -173,13 +203,13 @@ void StringFieldGenerator::
|
||||
GenerateClearingCode(io::Printer* printer) const {
|
||||
if (descriptor_->default_value_string().empty()) {
|
||||
printer->Print(variables_,
|
||||
"if ($name$_ != &_default_$name$_) {\n"
|
||||
"if ($name$_ != $default_variable$) {\n"
|
||||
" $name$_->clear();\n"
|
||||
"}\n");
|
||||
} else {
|
||||
printer->Print(variables_,
|
||||
"if ($name$_ != &_default_$name$_) {\n"
|
||||
" $name$_->assign(_default_$name$_);\n"
|
||||
"if ($name$_ != $default_variable$) {\n"
|
||||
" $name$_->assign(*$default_variable$);\n"
|
||||
"}\n");
|
||||
}
|
||||
}
|
||||
@ -197,17 +227,34 @@ GenerateSwappingCode(io::Printer* printer) const {
|
||||
void StringFieldGenerator::
|
||||
GenerateConstructorCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"$name$_ = const_cast< ::std::string*>(&_default_$name$_);\n");
|
||||
"$name$_ = const_cast< ::std::string*>($default_variable$);\n");
|
||||
}
|
||||
|
||||
void StringFieldGenerator::
|
||||
GenerateDestructorCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"if ($name$_ != &_default_$name$_) {\n"
|
||||
"if ($name$_ != $default_variable$) {\n"
|
||||
" delete $name$_;\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void StringFieldGenerator::
|
||||
GenerateDefaultInstanceAllocator(io::Printer* printer) const {
|
||||
if (!descriptor_->default_value_string().empty()) {
|
||||
printer->Print(variables_,
|
||||
"$classname$::$default_variable$ =\n"
|
||||
" new ::std::string($default$, $default_length$);\n");
|
||||
}
|
||||
}
|
||||
|
||||
void StringFieldGenerator::
|
||||
GenerateShutdownCode(io::Printer* printer) const {
|
||||
if (!descriptor_->default_value_string().empty()) {
|
||||
printer->Print(variables_,
|
||||
"delete $classname$::$default_variable$;\n");
|
||||
}
|
||||
}
|
||||
|
||||
void StringFieldGenerator::
|
||||
GenerateMergeFromCodedStream(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
@ -262,9 +309,10 @@ GenerateByteSize(io::Printer* printer) const {
|
||||
// ===================================================================
|
||||
|
||||
RepeatedStringFieldGenerator::
|
||||
RepeatedStringFieldGenerator(const FieldDescriptor* descriptor)
|
||||
RepeatedStringFieldGenerator(const FieldDescriptor* descriptor,
|
||||
const Options& options)
|
||||
: descriptor_(descriptor) {
|
||||
SetStringVariables(descriptor, &variables_);
|
||||
SetStringVariables(descriptor, &variables_, options);
|
||||
}
|
||||
|
||||
RepeatedStringFieldGenerator::~RepeatedStringFieldGenerator() {}
|
||||
@ -317,7 +365,7 @@ void RepeatedStringFieldGenerator::
|
||||
GenerateInlineAccessorDefinitions(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"inline const ::std::string& $classname$::$name$(int index) const {\n"
|
||||
" return $name$_.Get(index);\n"
|
||||
" return $name$_.$cppget$(index);\n"
|
||||
"}\n"
|
||||
"inline ::std::string* $classname$::mutable_$name$(int index) {\n"
|
||||
" return $name$_.Mutable(index);\n"
|
||||
@ -387,7 +435,8 @@ GenerateMergeFromCodedStream(io::Printer* printer) const {
|
||||
descriptor_->type() == FieldDescriptor::TYPE_STRING) {
|
||||
printer->Print(variables_,
|
||||
"::google::protobuf::internal::WireFormat::VerifyUTF8String(\n"
|
||||
" this->$name$(0).data(), this->$name$(0).length(),\n"
|
||||
" this->$name$(this->$name$_size() - 1).data(),\n"
|
||||
" this->$name$(this->$name$_size() - 1).length(),\n"
|
||||
" ::google::protobuf::internal::WireFormat::PARSE);\n");
|
||||
}
|
||||
}
|
@ -46,7 +46,8 @@ namespace cpp {
|
||||
|
||||
class StringFieldGenerator : public FieldGenerator {
|
||||
public:
|
||||
explicit StringFieldGenerator(const FieldDescriptor* descriptor);
|
||||
explicit StringFieldGenerator(const FieldDescriptor* descriptor,
|
||||
const Options& options);
|
||||
~StringFieldGenerator();
|
||||
|
||||
// implements FieldGenerator ---------------------------------------
|
||||
@ -59,6 +60,8 @@ class StringFieldGenerator : public FieldGenerator {
|
||||
void GenerateSwappingCode(io::Printer* printer) const;
|
||||
void GenerateConstructorCode(io::Printer* printer) const;
|
||||
void GenerateDestructorCode(io::Printer* printer) const;
|
||||
void GenerateDefaultInstanceAllocator(io::Printer* printer) const;
|
||||
void GenerateShutdownCode(io::Printer* printer) const;
|
||||
void GenerateMergeFromCodedStream(io::Printer* printer) const;
|
||||
void GenerateSerializeWithCachedSizes(io::Printer* printer) const;
|
||||
void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const;
|
||||
@ -73,7 +76,8 @@ class StringFieldGenerator : public FieldGenerator {
|
||||
|
||||
class RepeatedStringFieldGenerator : public FieldGenerator {
|
||||
public:
|
||||
explicit RepeatedStringFieldGenerator(const FieldDescriptor* descriptor);
|
||||
explicit RepeatedStringFieldGenerator(const FieldDescriptor* descriptor,
|
||||
const Options& options);
|
||||
~RepeatedStringFieldGenerator();
|
||||
|
||||
// implements FieldGenerator ---------------------------------------
|
@ -36,6 +36,10 @@
|
||||
// though the same identifiers are used internally by the C++ code generator.
|
||||
|
||||
|
||||
// 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;
|
||||
@ -99,9 +103,19 @@ message TestConflictingSymbolNames {
|
||||
message DO {}
|
||||
optional DO do = 32;
|
||||
|
||||
// Some template parameter names for extensions.
|
||||
optional int32 field_type = 33;
|
||||
optional bool is_packed = 34;
|
||||
|
||||
extensions 1000 to max;
|
||||
}
|
||||
|
||||
message TestConflictingSymbolNamesExtension {
|
||||
extend TestConflictingSymbolNames {
|
||||
repeated int32 repeated_int32_ext = 20423638 [packed=true];
|
||||
}
|
||||
}
|
||||
|
||||
message DummyMessage {}
|
||||
|
||||
service TestConflictingMethodNames {
|
@ -44,6 +44,8 @@
|
||||
// correctly and produces the interfaces we expect, which is why this test
|
||||
// is written this way.
|
||||
|
||||
#include <google/protobuf/compiler/cpp/cpp_unittest.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <google/protobuf/unittest.pb.h>
|
||||
@ -64,7 +66,7 @@
|
||||
#include <google/protobuf/stubs/substitute.h>
|
||||
#include <google/protobuf/testing/googletest.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <google/protobuf/stubs/stl_util-inl.h>
|
||||
#include <google/protobuf/stubs/stl_util.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
@ -74,6 +76,8 @@ namespace cpp {
|
||||
// Can't use an anonymous namespace here due to brokenness of Tru64 compiler.
|
||||
namespace cpp_unittest {
|
||||
|
||||
namespace protobuf_unittest = ::protobuf_unittest;
|
||||
|
||||
|
||||
class MockErrorCollector : public MultiFileErrorCollector {
|
||||
public:
|
||||
@ -167,6 +171,22 @@ TEST(GeneratedMessageTest, FloatingPointDefaults) {
|
||||
EXPECT_TRUE(extreme_default.nan_float() != extreme_default.nan_float());
|
||||
}
|
||||
|
||||
TEST(GeneratedMessageTest, Trigraph) {
|
||||
const unittest::TestExtremeDefaultValues& extreme_default =
|
||||
unittest::TestExtremeDefaultValues::default_instance();
|
||||
|
||||
EXPECT_EQ("? ? ?? ?? ??? ?\?/ ?\?-", extreme_default.cpp_trigraph());
|
||||
}
|
||||
|
||||
TEST(GeneratedMessageTest, ExtremeSmallIntegerDefault) {
|
||||
const unittest::TestExtremeDefaultValues& extreme_default =
|
||||
unittest::TestExtremeDefaultValues::default_instance();
|
||||
EXPECT_EQ(-0x80000000, kint32min);
|
||||
EXPECT_EQ(GOOGLE_LONGLONG(-0x8000000000000000), kint64min);
|
||||
EXPECT_EQ(kint32min, extreme_default.really_small_int32());
|
||||
EXPECT_EQ(kint64min, extreme_default.really_small_int64());
|
||||
}
|
||||
|
||||
TEST(GeneratedMessageTest, Accessors) {
|
||||
// Set every field to a unique value then go back and check all those
|
||||
// values.
|
||||
@ -195,6 +215,98 @@ TEST(GeneratedMessageTest, MutableStringDefault) {
|
||||
EXPECT_EQ("hello", *message.mutable_default_string());
|
||||
}
|
||||
|
||||
TEST(GeneratedMessageTest, StringDefaults) {
|
||||
unittest::TestExtremeDefaultValues message;
|
||||
// Check if '\000' can be used in default string value.
|
||||
EXPECT_EQ(string("hel\000lo", 6), message.string_with_zero());
|
||||
EXPECT_EQ(string("wor\000ld", 6), message.bytes_with_zero());
|
||||
}
|
||||
|
||||
TEST(GeneratedMessageTest, 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());
|
||||
string* str = message.release_default_string();
|
||||
EXPECT_FALSE(message.has_default_string());
|
||||
ASSERT_TRUE(str != NULL);
|
||||
EXPECT_EQ("blah", *str);
|
||||
delete str;
|
||||
|
||||
EXPECT_EQ(NULL, message.release_default_string());
|
||||
EXPECT_FALSE(message.has_default_string());
|
||||
EXPECT_EQ("hello", message.default_string());
|
||||
}
|
||||
|
||||
TEST(GeneratedMessageTest, 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);
|
||||
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());
|
||||
delete nest;
|
||||
|
||||
EXPECT_EQ(NULL, message.release_optional_nested_message());
|
||||
EXPECT_FALSE(message.has_optional_nested_message());
|
||||
}
|
||||
|
||||
TEST(GeneratedMessageTest, SetAllocatedString) {
|
||||
// Check that set_allocated_foo() works for strings.
|
||||
unittest::TestAllTypes message;
|
||||
|
||||
EXPECT_FALSE(message.has_optional_string());
|
||||
const 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 string(kHello));
|
||||
EXPECT_TRUE(message.has_optional_string());
|
||||
EXPECT_EQ(kHello, message.optional_string());
|
||||
}
|
||||
|
||||
TEST(GeneratedMessageTest, 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(GeneratedMessageTest, Clear) {
|
||||
// Set every field to a unique value, clear the message, then check that
|
||||
// it is cleared.
|
||||
@ -269,7 +381,6 @@ TEST(GeneratedMessageTest, StringCharStarLength) {
|
||||
EXPECT_EQ("wx", message.repeated_string(0));
|
||||
}
|
||||
|
||||
|
||||
TEST(GeneratedMessageTest, CopyFrom) {
|
||||
unittest::TestAllTypes message1, message2;
|
||||
|
||||
@ -376,10 +487,12 @@ TEST(GeneratedMessageTest, CopyAssignmentOperator) {
|
||||
TestUtil::ExpectAllFieldsSet(message2);
|
||||
|
||||
// Make sure that self-assignment does something sane.
|
||||
message2 = message2;
|
||||
message2.operator=(message2);
|
||||
TestUtil::ExpectAllFieldsSet(message2);
|
||||
}
|
||||
|
||||
#if !defined(PROTOBUF_TEST_NO_DESCRIPTORS) || \
|
||||
!defined(GOOGLE_PROTOBUF_NO_RTTI)
|
||||
TEST(GeneratedMessageTest, UpcastCopyFrom) {
|
||||
// Test the CopyFrom method that takes in the generic const Message&
|
||||
// parameter.
|
||||
@ -392,6 +505,7 @@ TEST(GeneratedMessageTest, UpcastCopyFrom) {
|
||||
|
||||
TestUtil::ExpectAllFieldsSet(message2);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef PROTOBUF_TEST_NO_DESCRIPTORS
|
||||
|
||||
@ -443,7 +557,9 @@ TEST(GeneratedMessageTest, NonEmptyMergeFrom) {
|
||||
TestUtil::ExpectAllFieldsSet(message1);
|
||||
}
|
||||
|
||||
#ifdef GTEST_HAS_DEATH_TEST
|
||||
#if !defined(PROTOBUF_TEST_NO_DESCRIPTORS) || \
|
||||
!defined(GOOGLE_PROTOBUF_NO_RTTI)
|
||||
#ifdef PROTOBUF_HAS_DEATH_TEST
|
||||
|
||||
TEST(GeneratedMessageTest, MergeFromSelf) {
|
||||
unittest::TestAllTypes message;
|
||||
@ -452,7 +568,8 @@ TEST(GeneratedMessageTest, MergeFromSelf) {
|
||||
"&from");
|
||||
}
|
||||
|
||||
#endif // GTEST_HAS_DEATH_TEST
|
||||
#endif // PROTOBUF_HAS_DEATH_TEST
|
||||
#endif // !PROTOBUF_TEST_NO_DESCRIPTORS || !GOOGLE_PROTOBUF_NO_RTTI
|
||||
|
||||
// Test the generated SerializeWithCachedSizesToArray(),
|
||||
TEST(GeneratedMessageTest, SerializationToArray) {
|
||||
@ -645,6 +762,13 @@ TEST(GeneratedMessageTest, TestConflictingSymbolNames) {
|
||||
|
||||
message.set_friend_(5);
|
||||
EXPECT_EQ(5, message.friend_());
|
||||
|
||||
// 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));
|
||||
}
|
||||
|
||||
#ifndef PROTOBUF_TEST_NO_DESCRIPTORS
|
||||
@ -718,6 +842,7 @@ TEST(GeneratedMessageTest, TestSpaceUsed) {
|
||||
|
||||
#endif // !PROTOBUF_TEST_NO_DESCRIPTORS
|
||||
|
||||
|
||||
TEST(GeneratedMessageTest, FieldConstantValues) {
|
||||
unittest::TestRequired message;
|
||||
EXPECT_EQ(unittest::TestAllTypes_NestedMessage::kBbFieldNumber, 1);
|
||||
@ -809,20 +934,19 @@ TEST(GeneratedEnumTest, MinAndMax) {
|
||||
EXPECT_EQ(12589235, unittest::TestSparseEnum_ARRAYSIZE);
|
||||
|
||||
// Make sure we can take the address of _MIN, _MAX and _ARRAYSIZE.
|
||||
void* nullptr = 0; // NULL may be integer-type, not pointer-type.
|
||||
EXPECT_NE(nullptr, &unittest::TestAllTypes::NestedEnum_MIN);
|
||||
EXPECT_NE(nullptr, &unittest::TestAllTypes::NestedEnum_MAX);
|
||||
EXPECT_NE(nullptr, &unittest::TestAllTypes::NestedEnum_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(nullptr, &unittest::ForeignEnum_MIN);
|
||||
EXPECT_NE(nullptr, &unittest::ForeignEnum_MAX);
|
||||
EXPECT_NE(nullptr, &unittest::ForeignEnum_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, _MAX and _ARRAYSIZE as switch cases.
|
||||
// Make sure we can use _MIN and _MAX as switch cases.
|
||||
switch (unittest::SPARSE_A) {
|
||||
case unittest::TestSparseEnum_MIN:
|
||||
case unittest::TestSparseEnum_MAX:
|
||||
case unittest::TestSparseEnum_ARRAYSIZE:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -1079,7 +1203,7 @@ TEST_F(GeneratedServiceTest, CallMethod) {
|
||||
TEST_F(GeneratedServiceTest, CallMethodTypeFailure) {
|
||||
// Verify death if we call Foo() with Bar's message types.
|
||||
|
||||
#ifdef GTEST_HAS_DEATH_TEST // death tests do not work on Windows yet
|
||||
#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()),
|
||||
@ -1090,7 +1214,7 @@ TEST_F(GeneratedServiceTest, CallMethodTypeFailure) {
|
||||
mock_service_.CallMethod(foo_, &mock_controller_,
|
||||
&bar_request_, &foo_response_, done_.get()),
|
||||
"dynamic_cast");
|
||||
#endif // GTEST_HAS_DEATH_TEST
|
||||
#endif // PROTOBUF_HAS_DEATH_TEST
|
||||
}
|
||||
|
||||
TEST_F(GeneratedServiceTest, GetPrototypes) {
|
@ -0,0 +1,51 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// 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__
|
@ -231,7 +231,12 @@ static string CanonicalizePath(string path) {
|
||||
// The Win32 API accepts forward slashes as a path delimiter even though
|
||||
// backslashes are standard. Let's avoid confusion and use only forward
|
||||
// slashes.
|
||||
path = StringReplace(path, "\\", "/", true);
|
||||
if (HasPrefixString(path, "\\\\")) {
|
||||
// Avoid converting two leading backslashes.
|
||||
path = "\\\\" + StringReplace(path.substr(2), "\\", "/", true);
|
||||
} else {
|
||||
path = StringReplace(path, "\\", "/", true);
|
||||
}
|
||||
#endif
|
||||
|
||||
vector<string> parts;
|
@ -280,8 +280,9 @@ class LIBPROTOBUF_EXPORT DiskSourceTree : public SourceTree {
|
||||
string virtual_path;
|
||||
string disk_path;
|
||||
|
||||
inline Mapping(const string& virtual_path, const string& disk_path)
|
||||
: virtual_path(virtual_path), disk_path(disk_path) {}
|
||||
inline Mapping(const string& virtual_path_param,
|
||||
const string& disk_path_param)
|
||||
: virtual_path(virtual_path_param), disk_path(disk_path_param) {}
|
||||
};
|
||||
vector<Mapping> mappings_;
|
||||
|
@ -0,0 +1,236 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// 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 <google/protobuf/compiler/java/java_doc_comment.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <google/protobuf/io/printer.h>
|
||||
#include <google/protobuf/stubs/strutil.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace java {
|
||||
|
||||
string EscapeJavadoc(const string& input) {
|
||||
string result;
|
||||
result.reserve(input.size() * 2);
|
||||
|
||||
char prev = '*';
|
||||
|
||||
for (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 markup.
|
||||
if (prev == '{') {
|
||||
result.append("@");
|
||||
} else {
|
||||
result.push_back(c);
|
||||
}
|
||||
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) {
|
||||
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);
|
||||
|
||||
vector<string> lines;
|
||||
SplitStringAllowEmpty(comments, "\n", &lines);
|
||||
while (!lines.empty() && lines.back().empty()) {
|
||||
lines.pop_back();
|
||||
}
|
||||
|
||||
printer->Print(
|
||||
" *\n"
|
||||
" * <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");
|
||||
}
|
||||
}
|
||||
|
||||
template <typename DescriptorType>
|
||||
static void WriteDocCommentBody(
|
||||
io::Printer* printer, const DescriptorType* descriptor) {
|
||||
SourceLocation location;
|
||||
if (descriptor->GetSourceLocation(&location)) {
|
||||
WriteDocCommentBodyForLocation(printer, location);
|
||||
}
|
||||
}
|
||||
|
||||
static string FirstLineOf(const string& value) {
|
||||
string result = value;
|
||||
|
||||
string::size_type pos = result.find_first_of('\n');
|
||||
if (pos != 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"
|
||||
" * Protobuf type {@code $fullname$}\n",
|
||||
"fullname", EscapeJavadoc(message->full_name()));
|
||||
WriteDocCommentBody(printer, message);
|
||||
printer->Print(" */\n");
|
||||
}
|
||||
|
||||
void WriteFieldDocComment(io::Printer* printer, const FieldDescriptor* field) {
|
||||
// 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 use the field declaration as the first line of the comment, e.g.:
|
||||
// optional string foo = 5;
|
||||
// This communicates a lot of information about the field in a small space.
|
||||
// If the field is a group, the debug string might end with {.
|
||||
printer->Print(
|
||||
"/**\n"
|
||||
" * <code>$def$</code>\n",
|
||||
"def", EscapeJavadoc(FirstLineOf(field->DebugString())));
|
||||
WriteDocCommentBody(printer, field);
|
||||
printer->Print(" */\n");
|
||||
}
|
||||
|
||||
void WriteEnumDocComment(io::Printer* printer, const EnumDescriptor* enum_) {
|
||||
printer->Print(
|
||||
"/**\n"
|
||||
" * Protobuf enum {@code $fullname$}\n",
|
||||
"fullname", EscapeJavadoc(enum_->full_name()));
|
||||
WriteDocCommentBody(printer, enum_);
|
||||
printer->Print(" */\n");
|
||||
}
|
||||
|
||||
void WriteEnumValueDocComment(io::Printer* printer,
|
||||
const EnumValueDescriptor* value) {
|
||||
printer->Print(
|
||||
"/**\n"
|
||||
" * <code>$def$</code>\n",
|
||||
"def", EscapeJavadoc(FirstLineOf(value->DebugString())));
|
||||
WriteDocCommentBody(printer, value);
|
||||
printer->Print(" */\n");
|
||||
}
|
||||
|
||||
void WriteServiceDocComment(io::Printer* printer,
|
||||
const ServiceDescriptor* service) {
|
||||
printer->Print(
|
||||
"/**\n"
|
||||
" * Protobuf service {@code $fullname$}\n",
|
||||
"fullname", EscapeJavadoc(service->full_name()));
|
||||
WriteDocCommentBody(printer, service);
|
||||
printer->Print(" */\n");
|
||||
}
|
||||
|
||||
void WriteMethodDocComment(io::Printer* printer,
|
||||
const MethodDescriptor* method) {
|
||||
printer->Print(
|
||||
"/**\n"
|
||||
" * <code>$def$</code>\n",
|
||||
"def", EscapeJavadoc(FirstLineOf(method->DebugString())));
|
||||
WriteDocCommentBody(printer, method);
|
||||
printer->Print(" */\n");
|
||||
}
|
||||
|
||||
} // namespace java
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,69 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// 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 <google/protobuf/descriptor.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace io {
|
||||
class Printer; // printer.h
|
||||
}
|
||||
}
|
||||
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace java {
|
||||
|
||||
void WriteMessageDocComment(io::Printer* printer, const Descriptor* message);
|
||||
void WriteFieldDocComment(io::Printer* printer, const FieldDescriptor* field);
|
||||
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.
|
||||
LIBPROTOC_EXPORT string EscapeJavadoc(const string& input);
|
||||
|
||||
} // namespace java
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_DOC_COMMENT_H__
|
@ -0,0 +1,66 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// 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 <google/protobuf/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"));
|
||||
}
|
||||
|
||||
// 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
|
@ -36,6 +36,7 @@
|
||||
#include <string>
|
||||
|
||||
#include <google/protobuf/compiler/java/java_enum.h>
|
||||
#include <google/protobuf/compiler/java/java_doc_comment.h>
|
||||
#include <google/protobuf/compiler/java/java_helpers.h>
|
||||
#include <google/protobuf/io/printer.h>
|
||||
#include <google/protobuf/descriptor.pb.h>
|
||||
@ -67,6 +68,7 @@ EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor)
|
||||
EnumGenerator::~EnumGenerator() {}
|
||||
|
||||
void EnumGenerator::Generate(io::Printer* printer) {
|
||||
WriteEnumDocComment(printer, descriptor_);
|
||||
if (HasDescriptorMethods(descriptor_)) {
|
||||
printer->Print(
|
||||
"public enum $classname$\n"
|
||||
@ -85,6 +87,7 @@ void EnumGenerator::Generate(io::Printer* printer) {
|
||||
vars["name"] = canonical_values_[i]->name();
|
||||
vars["index"] = SimpleItoa(canonical_values_[i]->index());
|
||||
vars["number"] = SimpleItoa(canonical_values_[i]->number());
|
||||
WriteEnumValueDocComment(printer, canonical_values_[i]);
|
||||
printer->Print(vars,
|
||||
"$name$($index$, $number$),\n");
|
||||
}
|
||||
@ -100,10 +103,21 @@ void EnumGenerator::Generate(io::Printer* printer) {
|
||||
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");
|
||||
}
|
||||
|
||||
for (int i = 0; i < descriptor_->value_count(); i++) {
|
||||
map<string, string> vars;
|
||||
vars["name"] = descriptor_->value(i)->name();
|
||||
vars["number"] = SimpleItoa(descriptor_->value(i)->number());
|
||||
WriteEnumValueDocComment(printer, descriptor_->value(i));
|
||||
printer->Print(vars,
|
||||
"public static final int $name$_VALUE = $number$;\n");
|
||||
}
|
||||
printer->Print("\n");
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
printer->Print(
|
||||
@ -138,7 +152,7 @@ void EnumGenerator::Generate(io::Printer* printer) {
|
||||
" internalValueMap =\n"
|
||||
" new com.google.protobuf.Internal.EnumLiteMap<$classname$>() {\n"
|
||||
" public $classname$ findValueByNumber(int number) {\n"
|
||||
" return $classname$.valueOf(number)\n;"
|
||||
" return $classname$.valueOf(number);\n"
|
||||
" }\n"
|
||||
" };\n"
|
||||
"\n",
|
||||
@ -178,18 +192,30 @@ void EnumGenerator::Generate(io::Printer* printer) {
|
||||
printer->Print(
|
||||
"}\n"
|
||||
"\n"
|
||||
"private static final $classname$[] VALUES = {\n"
|
||||
" ",
|
||||
"private static final $classname$[] VALUES = ",
|
||||
"classname", descriptor_->name());
|
||||
|
||||
for (int i = 0; i < descriptor_->value_count(); i++) {
|
||||
printer->Print("$name$, ",
|
||||
"name", descriptor_->value(i)->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(
|
||||
"{\n"
|
||||
" ");
|
||||
for (int i = 0; i < descriptor_->value_count(); i++) {
|
||||
printer->Print("$name$, ",
|
||||
"name", descriptor_->value(i)->name());
|
||||
}
|
||||
printer->Print(
|
||||
"\n"
|
||||
"};\n");
|
||||
}
|
||||
|
||||
printer->Print(
|
||||
"\n"
|
||||
"};\n"
|
||||
"public static $classname$ valueOf(\n"
|
||||
" com.google.protobuf.Descriptors.EnumValueDescriptor desc) {\n"
|
||||
" if (desc.getType() != getDescriptor()) {\n"
|
||||
@ -197,31 +223,26 @@ void EnumGenerator::Generate(io::Printer* printer) {
|
||||
" \"EnumValueDescriptor is not for this type.\");\n"
|
||||
" }\n"
|
||||
" return VALUES[desc.getIndex()];\n"
|
||||
"}\n",
|
||||
"}\n"
|
||||
"\n",
|
||||
"classname", descriptor_->name());
|
||||
|
||||
// index is only used for reflection; lite implementation does not need it
|
||||
printer->Print("private final int index;\n");
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
printer->Print(
|
||||
"private final int index;\n"
|
||||
"private final int value;\n"
|
||||
"private $classname$(int index, int value) {\n"
|
||||
" this.index = index;\n"
|
||||
" this.value = value;\n"
|
||||
"}\n",
|
||||
"private final int value;\n\n"
|
||||
"private $classname$(int index, int value) {\n",
|
||||
"classname", descriptor_->name());
|
||||
|
||||
if (HasDescriptorMethods(descriptor_)) {
|
||||
// Force the static initialization code for the file to run, since it may
|
||||
// initialize static variables declared in this class.
|
||||
printer->Print(
|
||||
"\n"
|
||||
"static {\n"
|
||||
" $file$.getDescriptor();\n"
|
||||
"}\n",
|
||||
"file", ClassName(descriptor_->file()));
|
||||
printer->Print(" this.index = index;\n");
|
||||
}
|
||||
printer->Print(
|
||||
" this.value = value;\n"
|
||||
"}\n");
|
||||
|
||||
printer->Print(
|
||||
"\n"
|
||||
@ -232,6 +253,18 @@ void EnumGenerator::Generate(io::Printer* printer) {
|
||||
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
|
@ -73,6 +73,8 @@ class EnumGenerator {
|
||||
};
|
||||
vector<Alias> aliases_;
|
||||
|
||||
bool CanUseEnumValues();
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumGenerator);
|
||||
};
|
||||
|
@ -0,0 +1,603 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// 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 <google/protobuf/compiler/java/java_enum_field.h>
|
||||
#include <google/protobuf/compiler/java/java_doc_comment.h>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/compiler/java/java_helpers.h>
|
||||
#include <google/protobuf/io/printer.h>
|
||||
#include <google/protobuf/wire_format.h>
|
||||
#include <google/protobuf/stubs/strutil.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace java {
|
||||
|
||||
namespace {
|
||||
|
||||
// TODO(kenton): Factor out a "SetCommonFieldVariables()" to get rid of
|
||||
// repeat code between this and the other field types.
|
||||
void SetEnumVariables(const FieldDescriptor* descriptor,
|
||||
int messageBitIndex,
|
||||
int builderBitIndex,
|
||||
map<string, string>* variables) {
|
||||
(*variables)["name"] =
|
||||
UnderscoresToCamelCase(descriptor);
|
||||
(*variables)["capitalized_name"] =
|
||||
UnderscoresToCapitalizedCamelCase(descriptor);
|
||||
(*variables)["constant_name"] = FieldConstantName(descriptor);
|
||||
(*variables)["number"] = SimpleItoa(descriptor->number());
|
||||
(*variables)["type"] = ClassName(descriptor->enum_type());
|
||||
(*variables)["default"] = DefaultValue(descriptor);
|
||||
(*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor));
|
||||
(*variables)["tag_size"] = SimpleItoa(
|
||||
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)["on_changed"] =
|
||||
HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : "";
|
||||
|
||||
// For singular messages and builders, one bit is used for the hasField bit.
|
||||
(*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex);
|
||||
(*variables)["set_has_field_bit_message"] = GenerateSetBit(messageBitIndex);
|
||||
|
||||
(*variables)["get_has_field_bit_builder"] = GenerateGetBit(builderBitIndex);
|
||||
(*variables)["set_has_field_bit_builder"] = GenerateSetBit(builderBitIndex);
|
||||
(*variables)["clear_has_field_bit_builder"] =
|
||||
GenerateClearBit(builderBitIndex);
|
||||
|
||||
// For repated 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
|
||||
|
||||
// ===================================================================
|
||||
|
||||
EnumFieldGenerator::
|
||||
EnumFieldGenerator(const FieldDescriptor* descriptor,
|
||||
int messageBitIndex,
|
||||
int builderBitIndex)
|
||||
: descriptor_(descriptor), messageBitIndex_(messageBitIndex),
|
||||
builderBitIndex_(builderBitIndex) {
|
||||
SetEnumVariables(descriptor, messageBitIndex, builderBitIndex, &variables_);
|
||||
}
|
||||
|
||||
EnumFieldGenerator::~EnumFieldGenerator() {}
|
||||
|
||||
int EnumFieldGenerator::GetNumBitsForMessage() const {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int EnumFieldGenerator::GetNumBitsForBuilder() const {
|
||||
return 1;
|
||||
}
|
||||
|
||||
void EnumFieldGenerator::
|
||||
GenerateInterfaceMembers(io::Printer* printer) const {
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$boolean has$capitalized_name$();\n");
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$$type$ get$capitalized_name$();\n");
|
||||
}
|
||||
|
||||
void EnumFieldGenerator::
|
||||
GenerateMembers(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"private $type$ $name$_;\n");
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public boolean has$capitalized_name$() {\n"
|
||||
" return $get_has_field_bit_message$;\n"
|
||||
"}\n");
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public $type$ get$capitalized_name$() {\n"
|
||||
" return $name$_;\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void EnumFieldGenerator::
|
||||
GenerateBuilderMembers(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"private $type$ $name$_ = $default$;\n");
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public boolean has$capitalized_name$() {\n"
|
||||
" return $get_has_field_bit_builder$;\n"
|
||||
"}\n");
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public $type$ get$capitalized_name$() {\n"
|
||||
" return $name$_;\n"
|
||||
"}\n");
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
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;\n"
|
||||
" $on_changed$\n"
|
||||
" return this;\n"
|
||||
"}\n");
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public Builder clear$capitalized_name$() {\n"
|
||||
" $clear_has_field_bit_builder$;\n"
|
||||
" $name$_ = $default$;\n"
|
||||
" $on_changed$\n"
|
||||
" return this;\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void EnumFieldGenerator::
|
||||
GenerateFieldBuilderInitializationCode(io::Printer* printer) const {
|
||||
// noop for enums
|
||||
}
|
||||
|
||||
void EnumFieldGenerator::
|
||||
GenerateInitializationCode(io::Printer* printer) const {
|
||||
printer->Print(variables_, "$name$_ = $default$;\n");
|
||||
}
|
||||
|
||||
void EnumFieldGenerator::
|
||||
GenerateBuilderClearCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"$name$_ = $default$;\n"
|
||||
"$clear_has_field_bit_builder$;\n");
|
||||
}
|
||||
|
||||
void EnumFieldGenerator::
|
||||
GenerateMergingCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"if (other.has$capitalized_name$()) {\n"
|
||||
" set$capitalized_name$(other.get$capitalized_name$());\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void EnumFieldGenerator::
|
||||
GenerateBuildingCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"if ($get_has_field_bit_from_local$) {\n"
|
||||
" $set_has_field_bit_to_local$;\n"
|
||||
"}\n"
|
||||
"result.$name$_ = $name$_;\n");
|
||||
}
|
||||
|
||||
void EnumFieldGenerator::
|
||||
GenerateParsingCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"int rawValue = input.readEnum();\n"
|
||||
"$type$ value = $type$.valueOf(rawValue);\n");
|
||||
if (HasUnknownFields(descriptor_->containing_type())) {
|
||||
printer->Print(variables_,
|
||||
"if (value == null) {\n"
|
||||
" unknownFields.mergeVarintField($number$, rawValue);\n"
|
||||
"} else {\n");
|
||||
} else {
|
||||
printer->Print(variables_,
|
||||
"if (value != null) {\n");
|
||||
}
|
||||
printer->Print(variables_,
|
||||
" $set_has_field_bit_message$;\n"
|
||||
" $name$_ = value;\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void EnumFieldGenerator::
|
||||
GenerateParsingDoneCode(io::Printer* printer) const {
|
||||
// noop for enums
|
||||
}
|
||||
|
||||
void EnumFieldGenerator::
|
||||
GenerateSerializationCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"if ($get_has_field_bit_message$) {\n"
|
||||
" output.writeEnum($number$, $name$_.getNumber());\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void EnumFieldGenerator::
|
||||
GenerateSerializedSizeCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"if ($get_has_field_bit_message$) {\n"
|
||||
" size += com.google.protobuf.CodedOutputStream\n"
|
||||
" .computeEnumSize($number$, $name$_.getNumber());\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void EnumFieldGenerator::
|
||||
GenerateEqualsCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"result = result &&\n"
|
||||
" (get$capitalized_name$() == other.get$capitalized_name$());\n");
|
||||
}
|
||||
|
||||
void EnumFieldGenerator::
|
||||
GenerateHashCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"hash = (37 * hash) + $constant_name$;\n"
|
||||
"hash = (53 * hash) + hashEnum(get$capitalized_name$());\n");
|
||||
}
|
||||
|
||||
string EnumFieldGenerator::GetBoxedType() const {
|
||||
return ClassName(descriptor_->enum_type());
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
RepeatedEnumFieldGenerator::
|
||||
RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor,
|
||||
int messageBitIndex,
|
||||
int builderBitIndex)
|
||||
: descriptor_(descriptor), messageBitIndex_(messageBitIndex),
|
||||
builderBitIndex_(builderBitIndex) {
|
||||
SetEnumVariables(descriptor, messageBitIndex, builderBitIndex, &variables_);
|
||||
}
|
||||
|
||||
RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() {}
|
||||
|
||||
int RepeatedEnumFieldGenerator::GetNumBitsForMessage() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int RepeatedEnumFieldGenerator::GetNumBitsForBuilder() const {
|
||||
return 1;
|
||||
}
|
||||
|
||||
void RepeatedEnumFieldGenerator::
|
||||
GenerateInterfaceMembers(io::Printer* printer) const {
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$java.util.List<$type$> get$capitalized_name$List();\n");
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$int get$capitalized_name$Count();\n");
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$$type$ get$capitalized_name$(int index);\n");
|
||||
}
|
||||
|
||||
void RepeatedEnumFieldGenerator::
|
||||
GenerateMembers(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"private java.util.List<$type$> $name$_;\n");
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public java.util.List<$type$> get$capitalized_name$List() {\n"
|
||||
" return $name$_;\n" // note: unmodifiable list
|
||||
"}\n");
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public int get$capitalized_name$Count() {\n"
|
||||
" return $name$_.size();\n"
|
||||
"}\n");
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public $type$ get$capitalized_name$(int index) {\n"
|
||||
" return $name$_.get(index);\n"
|
||||
"}\n");
|
||||
|
||||
if (descriptor_->options().packed() &&
|
||||
HasGeneratedMethods(descriptor_->containing_type())) {
|
||||
printer->Print(variables_,
|
||||
"private int $name$MemoizedSerializedSize;\n");
|
||||
}
|
||||
}
|
||||
|
||||
void RepeatedEnumFieldGenerator::
|
||||
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 refererence 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");
|
||||
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
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 java.util.Collections.unmodifiableList($name$_);\n"
|
||||
"}\n");
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public int get$capitalized_name$Count() {\n"
|
||||
" return $name$_.size();\n"
|
||||
"}\n");
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public $type$ get$capitalized_name$(int index) {\n"
|
||||
" return $name$_.get(index);\n"
|
||||
"}\n");
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
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);\n"
|
||||
" $on_changed$\n"
|
||||
" return this;\n"
|
||||
"}\n");
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
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);\n"
|
||||
" $on_changed$\n"
|
||||
" return this;\n"
|
||||
"}\n");
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public Builder addAll$capitalized_name$(\n"
|
||||
" java.lang.Iterable<? extends $type$> values) {\n"
|
||||
" ensure$capitalized_name$IsMutable();\n"
|
||||
" super.addAll(values, $name$_);\n"
|
||||
" $on_changed$\n"
|
||||
" return this;\n"
|
||||
"}\n");
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
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");
|
||||
}
|
||||
|
||||
void RepeatedEnumFieldGenerator::
|
||||
GenerateFieldBuilderInitializationCode(io::Printer* printer) const {
|
||||
// noop for enums
|
||||
}
|
||||
|
||||
void RepeatedEnumFieldGenerator::
|
||||
GenerateInitializationCode(io::Printer* printer) const {
|
||||
printer->Print(variables_, "$name$_ = java.util.Collections.emptyList();\n");
|
||||
}
|
||||
|
||||
void RepeatedEnumFieldGenerator::
|
||||
GenerateBuilderClearCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"$name$_ = java.util.Collections.emptyList();\n"
|
||||
"$clear_mutable_bit_builder$;\n");
|
||||
}
|
||||
|
||||
void RepeatedEnumFieldGenerator::
|
||||
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 RepeatedEnumFieldGenerator::
|
||||
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 RepeatedEnumFieldGenerator::
|
||||
GenerateParsingCode(io::Printer* printer) const {
|
||||
// Read and store the enum
|
||||
printer->Print(variables_,
|
||||
"int rawValue = input.readEnum();\n"
|
||||
"$type$ value = $type$.valueOf(rawValue);\n");
|
||||
if (HasUnknownFields(descriptor_->containing_type())) {
|
||||
printer->Print(variables_,
|
||||
"if (value == null) {\n"
|
||||
" unknownFields.mergeVarintField($number$, rawValue);\n"
|
||||
"} else {\n");
|
||||
} else {
|
||||
printer->Print(variables_,
|
||||
"if (value != null) {\n");
|
||||
}
|
||||
printer->Print(variables_,
|
||||
" if (!$get_mutable_bit_parser$) {\n"
|
||||
" $name$_ = new java.util.ArrayList<$type$>();\n"
|
||||
" $set_mutable_bit_parser$;\n"
|
||||
" }\n"
|
||||
" $name$_.add(value);\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void RepeatedEnumFieldGenerator::
|
||||
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 RepeatedEnumFieldGenerator::
|
||||
GenerateParsingDoneCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"if ($get_mutable_bit_parser$) {\n"
|
||||
" $name$_ = java.util.Collections.unmodifiableList($name$_);\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void RepeatedEnumFieldGenerator::
|
||||
GenerateSerializationCode(io::Printer* printer) const {
|
||||
if (descriptor_->options().packed()) {
|
||||
printer->Print(variables_,
|
||||
"if (get$capitalized_name$List().size() > 0) {\n"
|
||||
" output.writeRawVarint32($tag$);\n"
|
||||
" output.writeRawVarint32($name$MemoizedSerializedSize);\n"
|
||||
"}\n"
|
||||
"for (int i = 0; i < $name$_.size(); i++) {\n"
|
||||
" output.writeEnumNoTag($name$_.get(i).getNumber());\n"
|
||||
"}\n");
|
||||
} else {
|
||||
printer->Print(variables_,
|
||||
"for (int i = 0; i < $name$_.size(); i++) {\n"
|
||||
" output.writeEnum($number$, $name$_.get(i).getNumber());\n"
|
||||
"}\n");
|
||||
}
|
||||
}
|
||||
|
||||
void RepeatedEnumFieldGenerator::
|
||||
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).getNumber());\n"
|
||||
"}\n");
|
||||
printer->Print(
|
||||
"size += dataSize;\n");
|
||||
if (descriptor_->options().packed()) {
|
||||
printer->Print(variables_,
|
||||
"if (!get$capitalized_name$List().isEmpty()) {"
|
||||
" size += $tag_size$;\n"
|
||||
" size += com.google.protobuf.CodedOutputStream\n"
|
||||
" .computeRawVarint32Size(dataSize);\n"
|
||||
"}");
|
||||
} else {
|
||||
printer->Print(variables_,
|
||||
"size += $tag_size$ * $name$_.size();\n");
|
||||
}
|
||||
|
||||
// cache the data size for packed fields.
|
||||
if (descriptor_->options().packed()) {
|
||||
printer->Print(variables_,
|
||||
"$name$MemoizedSerializedSize = dataSize;\n");
|
||||
}
|
||||
|
||||
printer->Outdent();
|
||||
printer->Print("}\n");
|
||||
}
|
||||
|
||||
void RepeatedEnumFieldGenerator::
|
||||
GenerateEqualsCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"result = result && get$capitalized_name$List()\n"
|
||||
" .equals(other.get$capitalized_name$List());\n");
|
||||
}
|
||||
|
||||
void RepeatedEnumFieldGenerator::
|
||||
GenerateHashCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"if (get$capitalized_name$Count() > 0) {\n"
|
||||
" hash = (37 * hash) + $constant_name$;\n"
|
||||
" hash = (53 * hash) + hashEnumList(get$capitalized_name$List());\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
string RepeatedEnumFieldGenerator::GetBoxedType() const {
|
||||
return ClassName(descriptor_->enum_type());
|
||||
}
|
||||
|
||||
} // namespace java
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -46,49 +46,71 @@ namespace java {
|
||||
|
||||
class EnumFieldGenerator : public FieldGenerator {
|
||||
public:
|
||||
explicit EnumFieldGenerator(const FieldDescriptor* descriptor);
|
||||
explicit EnumFieldGenerator(const FieldDescriptor* descriptor,
|
||||
int messageBitIndex, int builderBitIndex);
|
||||
~EnumFieldGenerator();
|
||||
|
||||
// implements FieldGenerator ---------------------------------------
|
||||
int GetNumBitsForMessage() const;
|
||||
int GetNumBitsForBuilder() const;
|
||||
void GenerateInterfaceMembers(io::Printer* printer) const;
|
||||
void GenerateMembers(io::Printer* printer) const;
|
||||
void GenerateBuilderMembers(io::Printer* printer) const;
|
||||
void GenerateInitializationCode(io::Printer* printer) const;
|
||||
void GenerateBuilderClearCode(io::Printer* printer) const;
|
||||
void GenerateMergingCode(io::Printer* printer) const;
|
||||
void GenerateBuildingCode(io::Printer* printer) const;
|
||||
void GenerateParsingCode(io::Printer* printer) const;
|
||||
void GenerateParsingDoneCode(io::Printer* printer) const;
|
||||
void GenerateSerializationCode(io::Printer* printer) const;
|
||||
void GenerateSerializedSizeCode(io::Printer* printer) const;
|
||||
void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
|
||||
void GenerateEqualsCode(io::Printer* printer) const;
|
||||
void GenerateHashCode(io::Printer* printer) const;
|
||||
|
||||
string GetBoxedType() const;
|
||||
|
||||
private:
|
||||
const FieldDescriptor* descriptor_;
|
||||
map<string, string> variables_;
|
||||
const int messageBitIndex_;
|
||||
const int builderBitIndex_;
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumFieldGenerator);
|
||||
};
|
||||
|
||||
class RepeatedEnumFieldGenerator : public FieldGenerator {
|
||||
public:
|
||||
explicit RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor);
|
||||
explicit RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor,
|
||||
int messageBitIndex, int builderBitIndex);
|
||||
~RepeatedEnumFieldGenerator();
|
||||
|
||||
// implements FieldGenerator ---------------------------------------
|
||||
int GetNumBitsForMessage() const;
|
||||
int GetNumBitsForBuilder() const;
|
||||
void GenerateInterfaceMembers(io::Printer* printer) const;
|
||||
void GenerateMembers(io::Printer* printer) const;
|
||||
void GenerateBuilderMembers(io::Printer* printer) const;
|
||||
void GenerateInitializationCode(io::Printer* printer) const;
|
||||
void GenerateBuilderClearCode(io::Printer* printer) const;
|
||||
void GenerateMergingCode(io::Printer* printer) const;
|
||||
void GenerateBuildingCode(io::Printer* printer) const;
|
||||
void GenerateParsingCode(io::Printer* printer) const;
|
||||
void GenerateParsingCodeFromPacked(io::Printer* printer) const;
|
||||
void GenerateParsingDoneCode(io::Printer* printer) const;
|
||||
void GenerateSerializationCode(io::Printer* printer) const;
|
||||
void GenerateSerializedSizeCode(io::Printer* printer) const;
|
||||
void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
|
||||
void GenerateEqualsCode(io::Printer* printer) const;
|
||||
void GenerateHashCode(io::Printer* printer) const;
|
||||
|
||||
string GetBoxedType() const;
|
||||
|
||||
private:
|
||||
const FieldDescriptor* descriptor_;
|
||||
map<string, string> variables_;
|
||||
const int messageBitIndex_;
|
||||
const int builderBitIndex_;
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedEnumFieldGenerator);
|
||||
};
|
@ -33,6 +33,7 @@
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#include <google/protobuf/compiler/java/java_extension.h>
|
||||
#include <google/protobuf/compiler/java/java_doc_comment.h>
|
||||
#include <google/protobuf/compiler/java/java_helpers.h>
|
||||
#include <google/protobuf/stubs/strutil.h>
|
||||
#include <google/protobuf/io/printer.h>
|
||||
@ -86,105 +87,121 @@ ExtensionGenerator::ExtensionGenerator(const FieldDescriptor* descriptor)
|
||||
|
||||
ExtensionGenerator::~ExtensionGenerator() {}
|
||||
|
||||
void ExtensionGenerator::Generate(io::Printer* printer) {
|
||||
map<string, string> vars;
|
||||
vars["name"] = UnderscoresToCamelCase(descriptor_);
|
||||
vars["containing_type"] = ClassName(descriptor_->containing_type());
|
||||
vars["number"] = SimpleItoa(descriptor_->number());
|
||||
vars["constant_name"] = FieldConstantName(descriptor_);
|
||||
vars["lite"] = HasDescriptorMethods(descriptor_->file()) ? "" : "Lite";
|
||||
|
||||
JavaType java_type = GetJavaType(descriptor_);
|
||||
string singular_type;
|
||||
switch (java_type) {
|
||||
case JAVATYPE_MESSAGE:
|
||||
vars["type"] = ClassName(descriptor_->message_type());
|
||||
break;
|
||||
case JAVATYPE_ENUM:
|
||||
vars["type"] = ClassName(descriptor_->enum_type());
|
||||
break;
|
||||
default:
|
||||
vars["type"] = BoxedPrimitiveTypeName(java_type);
|
||||
break;
|
||||
}
|
||||
|
||||
printer->Print(vars,
|
||||
"public static final int $constant_name$ = $number$;\n");
|
||||
if (descriptor_->is_repeated()) {
|
||||
printer->Print(vars,
|
||||
"public static final\n"
|
||||
" com.google.protobuf.GeneratedMessage$lite$.GeneratedExtension<\n"
|
||||
" $containing_type$,\n"
|
||||
" java.util.List<$type$>> $name$ =\n"
|
||||
" com.google.protobuf.GeneratedMessage$lite$\n"
|
||||
" .newGeneratedExtension();\n");
|
||||
} else {
|
||||
printer->Print(vars,
|
||||
"public static final\n"
|
||||
" com.google.protobuf.GeneratedMessage$lite$.GeneratedExtension<\n"
|
||||
" $containing_type$,\n"
|
||||
" $type$> $name$ =\n"
|
||||
" com.google.protobuf.GeneratedMessage$lite$\n"
|
||||
" .newGeneratedExtension();\n");
|
||||
}
|
||||
}
|
||||
|
||||
void ExtensionGenerator::GenerateInitializationCode(io::Printer* printer) {
|
||||
map<string, string> vars;
|
||||
vars["name"] = UnderscoresToCamelCase(descriptor_);
|
||||
vars["scope"] = scope_;
|
||||
vars["index"] = SimpleItoa(descriptor_->index());
|
||||
vars["extendee"] = ClassName(descriptor_->containing_type());
|
||||
vars["default"] = descriptor_->is_repeated() ? "" : DefaultValue(descriptor_);
|
||||
vars["number"] = SimpleItoa(descriptor_->number());
|
||||
vars["type_constant"] = TypeName(GetType(descriptor_));
|
||||
vars["packed"] = descriptor_->options().packed() ? "true" : "false";
|
||||
// Initializes the vars referenced in the generated code templates.
|
||||
void InitTemplateVars(const FieldDescriptor* descriptor,
|
||||
const string& scope,
|
||||
map<string, string>* vars_pointer) {
|
||||
map<string, string> &vars = *vars_pointer;
|
||||
vars["scope"] = scope;
|
||||
vars["name"] = UnderscoresToCamelCase(descriptor);
|
||||
vars["containing_type"] = ClassName(descriptor->containing_type());
|
||||
vars["number"] = SimpleItoa(descriptor->number());
|
||||
vars["constant_name"] = FieldConstantName(descriptor);
|
||||
vars["index"] = SimpleItoa(descriptor->index());
|
||||
vars["default"] =
|
||||
descriptor->is_repeated() ? "" : DefaultValue(descriptor);
|
||||
vars["type_constant"] = TypeName(GetType(descriptor));
|
||||
vars["packed"] = descriptor->options().packed() ? "true" : "false";
|
||||
vars["enum_map"] = "null";
|
||||
vars["prototype"] = "null";
|
||||
|
||||
JavaType java_type = GetJavaType(descriptor_);
|
||||
JavaType java_type = GetJavaType(descriptor);
|
||||
string singular_type;
|
||||
switch (java_type) {
|
||||
case JAVATYPE_MESSAGE:
|
||||
vars["type"] = ClassName(descriptor_->message_type());
|
||||
vars["prototype"] = ClassName(descriptor_->message_type()) +
|
||||
".getDefaultInstance()";
|
||||
singular_type = ClassName(descriptor->message_type());
|
||||
vars["prototype"] = singular_type + ".getDefaultInstance()";
|
||||
break;
|
||||
case JAVATYPE_ENUM:
|
||||
vars["type"] = ClassName(descriptor_->enum_type());
|
||||
vars["enum_map"] = ClassName(descriptor_->enum_type()) +
|
||||
".internalGetValueMap()";
|
||||
singular_type = ClassName(descriptor->enum_type());
|
||||
vars["enum_map"] = singular_type + ".internalGetValueMap()";
|
||||
break;
|
||||
default:
|
||||
vars["type"] = BoxedPrimitiveTypeName(java_type);
|
||||
singular_type = BoxedPrimitiveTypeName(java_type);
|
||||
break;
|
||||
}
|
||||
vars["type"] = descriptor->is_repeated() ?
|
||||
"java.util.List<" + singular_type + ">" : singular_type;
|
||||
vars["singular_type"] = singular_type;
|
||||
}
|
||||
|
||||
void ExtensionGenerator::Generate(io::Printer* printer) {
|
||||
map<string, string> vars;
|
||||
InitTemplateVars(descriptor_, scope_, &vars);
|
||||
printer->Print(vars,
|
||||
"public static final int $constant_name$ = $number$;\n");
|
||||
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
if (HasDescriptorMethods(descriptor_->file())) {
|
||||
printer->Print(vars,
|
||||
"$scope$.$name$.internalInit(\n"
|
||||
" $scope$.getDescriptor().getExtensions().get($index$),\n"
|
||||
" $type$.class);\n");
|
||||
} else {
|
||||
if (descriptor_->is_repeated()) {
|
||||
printer->Print(vars,
|
||||
"$scope$.$name$.internalInitRepeated(\n"
|
||||
" $extendee$.getDefaultInstance(),\n"
|
||||
" $prototype$,\n"
|
||||
" $enum_map$,\n"
|
||||
" $number$,\n"
|
||||
" com.google.protobuf.WireFormat.FieldType.$type_constant$,\n"
|
||||
" $packed$);\n");
|
||||
// Non-lite extensions
|
||||
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 {
|
||||
printer->Print(vars,
|
||||
"$scope$.$name$.internalInitSingular(\n"
|
||||
" $extendee$.getDefaultInstance(),\n"
|
||||
" $default$,\n"
|
||||
" $prototype$,\n"
|
||||
" $enum_map$,\n"
|
||||
" $number$,\n"
|
||||
" com.google.protobuf.WireFormat.FieldType.$type_constant$);\n");
|
||||
// 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");
|
||||
}
|
||||
} else {
|
||||
// Lite extensions
|
||||
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");
|
||||
} 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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ExtensionGenerator::GenerateNonNestedInitializationCode(
|
||||
io::Printer* printer) {
|
||||
if (descriptor_->extension_scope() == NULL &&
|
||||
HasDescriptorMethods(descriptor_->file())) {
|
||||
// Only applies to non-nested, non-lite extensions.
|
||||
printer->Print(
|
||||
"$name$.internalInit(descriptor.getExtensions().get($index$));\n",
|
||||
"name", UnderscoresToCamelCase(descriptor_),
|
||||
"index", SimpleItoa(descriptor_->index()));
|
||||
}
|
||||
}
|
||||
|
@ -60,7 +60,7 @@ class ExtensionGenerator {
|
||||
~ExtensionGenerator();
|
||||
|
||||
void Generate(io::Printer* printer);
|
||||
void GenerateInitializationCode(io::Printer* printer);
|
||||
void GenerateNonNestedInitializationCode(io::Printer* printer);
|
||||
void GenerateRegistrationCode(io::Printer* printer);
|
||||
|
||||
private:
|
@ -37,6 +37,7 @@
|
||||
#include <google/protobuf/compiler/java/java_primitive_field.h>
|
||||
#include <google/protobuf/compiler/java/java_enum_field.h>
|
||||
#include <google/protobuf/compiler/java/java_message_field.h>
|
||||
#include <google/protobuf/compiler/java/java_string_field.h>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
namespace google {
|
||||
@ -63,33 +64,57 @@ FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor)
|
||||
extension_generators_(
|
||||
new scoped_ptr<FieldGenerator>[descriptor->extension_count()]) {
|
||||
|
||||
// Construct all the FieldGenerators.
|
||||
// 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++) {
|
||||
field_generators_[i].reset(MakeGenerator(descriptor->field(i)));
|
||||
FieldGenerator* generator = MakeGenerator(descriptor->field(i),
|
||||
messageBitIndex, builderBitIndex);
|
||||
field_generators_[i].reset(generator);
|
||||
messageBitIndex += generator->GetNumBitsForMessage();
|
||||
builderBitIndex += generator->GetNumBitsForBuilder();
|
||||
}
|
||||
for (int i = 0; i < descriptor->extension_count(); i++) {
|
||||
extension_generators_[i].reset(MakeGenerator(descriptor->extension(i)));
|
||||
FieldGenerator* generator = MakeGenerator(descriptor->extension(i),
|
||||
messageBitIndex, builderBitIndex);
|
||||
extension_generators_[i].reset(generator);
|
||||
messageBitIndex += generator->GetNumBitsForMessage();
|
||||
builderBitIndex += generator->GetNumBitsForBuilder();
|
||||
}
|
||||
}
|
||||
|
||||
FieldGenerator* FieldGeneratorMap::MakeGenerator(const FieldDescriptor* field) {
|
||||
FieldGenerator* FieldGeneratorMap::MakeGenerator(
|
||||
const FieldDescriptor* field, int messageBitIndex, int builderBitIndex) {
|
||||
if (field->is_repeated()) {
|
||||
switch (GetJavaType(field)) {
|
||||
case JAVATYPE_MESSAGE:
|
||||
return new RepeatedMessageFieldGenerator(field);
|
||||
return new RepeatedMessageFieldGenerator(
|
||||
field, messageBitIndex, builderBitIndex);
|
||||
case JAVATYPE_ENUM:
|
||||
return new RepeatedEnumFieldGenerator(field);
|
||||
return new RepeatedEnumFieldGenerator(
|
||||
field, messageBitIndex, builderBitIndex);
|
||||
case JAVATYPE_STRING:
|
||||
return new RepeatedStringFieldGenerator(
|
||||
field, messageBitIndex, builderBitIndex);
|
||||
default:
|
||||
return new RepeatedPrimitiveFieldGenerator(field);
|
||||
return new RepeatedPrimitiveFieldGenerator(
|
||||
field, messageBitIndex, builderBitIndex);
|
||||
}
|
||||
} else {
|
||||
switch (GetJavaType(field)) {
|
||||
case JAVATYPE_MESSAGE:
|
||||
return new MessageFieldGenerator(field);
|
||||
return new MessageFieldGenerator(
|
||||
field, messageBitIndex, builderBitIndex);
|
||||
case JAVATYPE_ENUM:
|
||||
return new EnumFieldGenerator(field);
|
||||
return new EnumFieldGenerator(
|
||||
field, messageBitIndex, builderBitIndex);
|
||||
case JAVATYPE_STRING:
|
||||
return new StringFieldGenerator(
|
||||
field, messageBitIndex, builderBitIndex);
|
||||
default:
|
||||
return new PrimitiveFieldGenerator(field);
|
||||
return new PrimitiveFieldGenerator(
|
||||
field, messageBitIndex, builderBitIndex);
|
||||
}
|
||||
}
|
||||
}
|
@ -55,15 +55,25 @@ class FieldGenerator {
|
||||
FieldGenerator() {}
|
||||
virtual ~FieldGenerator();
|
||||
|
||||
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 GenerateEqualsCode(io::Printer* printer) const = 0;
|
||||
virtual void GenerateHashCode(io::Printer* printer) const = 0;
|
||||
|
||||
virtual string GetBoxedType() const = 0;
|
||||
|
||||
@ -85,7 +95,8 @@ class FieldGeneratorMap {
|
||||
scoped_array<scoped_ptr<FieldGenerator> > field_generators_;
|
||||
scoped_array<scoped_ptr<FieldGenerator> > extension_generators_;
|
||||
|
||||
static FieldGenerator* MakeGenerator(const FieldDescriptor* field);
|
||||
static FieldGenerator* MakeGenerator(const FieldDescriptor* field,
|
||||
int messageBitIndex, int builderBitIndex);
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGeneratorMap);
|
||||
};
|
@ -42,6 +42,7 @@
|
||||
#include <google/protobuf/io/printer.h>
|
||||
#include <google/protobuf/io/zero_copy_stream.h>
|
||||
#include <google/protobuf/descriptor.pb.h>
|
||||
#include <google/protobuf/dynamic_message.h>
|
||||
#include <google/protobuf/stubs/strutil.h>
|
||||
|
||||
namespace google {
|
||||
@ -51,18 +52,24 @@ namespace java {
|
||||
|
||||
namespace {
|
||||
|
||||
// Recursively searches the given message to see if it contains any extensions.
|
||||
bool UsesExtensions(const Message& message) {
|
||||
|
||||
// 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,
|
||||
vector<const FieldDescriptor*>* extensions) {
|
||||
const Reflection* reflection = message.GetReflection();
|
||||
|
||||
// We conservatively assume that unknown fields are extensions.
|
||||
if (reflection->GetUnknownFields(message).field_count() > 0) return true;
|
||||
// There are unknown fields that could be extensions, thus this call fails.
|
||||
if (reflection->GetUnknownFields(message).field_count() > 0) return false;
|
||||
|
||||
vector<const FieldDescriptor*> fields;
|
||||
reflection->ListFields(message, &fields);
|
||||
|
||||
for (int i = 0; i < fields.size(); i++) {
|
||||
if (fields[i]->is_extension()) return true;
|
||||
if (fields[i]->is_extension()) extensions->push_back(fields[i]);
|
||||
|
||||
if (GetJavaType(fields[i]) == JAVATYPE_MESSAGE) {
|
||||
if (fields[i]->is_repeated()) {
|
||||
@ -70,16 +77,56 @@ bool UsesExtensions(const Message& message) {
|
||||
for (int j = 0; j < size; j++) {
|
||||
const Message& sub_message =
|
||||
reflection->GetRepeatedMessage(message, fields[i], j);
|
||||
if (UsesExtensions(sub_message)) return true;
|
||||
if (!CollectExtensions(sub_message, extensions)) return false;
|
||||
}
|
||||
} else {
|
||||
const Message& sub_message = reflection->GetMessage(message, fields[i]);
|
||||
if (UsesExtensions(sub_message)) return true;
|
||||
if (!CollectExtensions(sub_message, extensions)) return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
vector<const FieldDescriptor*>* extensions,
|
||||
const 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;
|
||||
scoped_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.";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -88,7 +135,8 @@ bool UsesExtensions(const Message& message) {
|
||||
FileGenerator::FileGenerator(const FileDescriptor* file)
|
||||
: file_(file),
|
||||
java_package_(FileJavaPackage(file)),
|
||||
classname_(FileClassName(file)) {}
|
||||
classname_(FileClassName(file)) {
|
||||
}
|
||||
|
||||
FileGenerator::~FileGenerator() {}
|
||||
|
||||
@ -179,7 +227,9 @@ void FileGenerator::Generate(io::Printer* printer) {
|
||||
EnumGenerator(file_->enum_type(i)).Generate(printer);
|
||||
}
|
||||
for (int i = 0; i < file_->message_type_count(); i++) {
|
||||
MessageGenerator(file_->message_type(i)).Generate(printer);
|
||||
MessageGenerator messageGenerator(file_->message_type(i));
|
||||
messageGenerator.GenerateInterface(printer);
|
||||
messageGenerator.Generate(printer);
|
||||
}
|
||||
if (HasGenericServices(file_)) {
|
||||
for (int i = 0; i < file_->service_count(); i++) {
|
||||
@ -215,24 +265,11 @@ void FileGenerator::Generate(io::Printer* printer) {
|
||||
.GenerateStaticVariableInitializers(printer);
|
||||
}
|
||||
|
||||
for (int i = 0; i < file_->extension_count(); i++) {
|
||||
// TODO(kenton): Reuse ExtensionGenerator objects?
|
||||
ExtensionGenerator(file_->extension(i))
|
||||
.GenerateInitializationCode(printer);
|
||||
}
|
||||
|
||||
printer->Outdent();
|
||||
printer->Print(
|
||||
"}\n");
|
||||
}
|
||||
|
||||
// Dummy function we can use to force the static initialization block to
|
||||
// run. Needed by inner classes. Cannot be private due to
|
||||
// java_multiple_files option.
|
||||
printer->Print(
|
||||
"\n"
|
||||
"public static void internalForceInit() {}\n");
|
||||
|
||||
printer->Print(
|
||||
"\n"
|
||||
"// @@protoc_insertion_point(outer_class_scope)\n");
|
||||
@ -310,24 +347,38 @@ void FileGenerator::GenerateEmbeddedDescriptor(io::Printer* printer) {
|
||||
MessageGenerator(file_->message_type(i))
|
||||
.GenerateStaticVariableInitializers(printer);
|
||||
}
|
||||
|
||||
for (int i = 0; i < file_->extension_count(); i++) {
|
||||
// TODO(kenton): Reuse ExtensionGenerator objects?
|
||||
ExtensionGenerator(file_->extension(i))
|
||||
.GenerateInitializationCode(printer);
|
||||
.GenerateNonNestedInitializationCode(printer);
|
||||
}
|
||||
|
||||
if (UsesExtensions(file_proto)) {
|
||||
// Must construct an ExtensionRegistry containing all possible extensions
|
||||
// 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
|
||||
vector<const FieldDescriptor*> extensions;
|
||||
CollectExtensions(file_proto, *file_->pool(), &extensions, file_data);
|
||||
|
||||
if (extensions.size() > 0) {
|
||||
// Must construct an ExtensionRegistry containing all existing extensions
|
||||
// and return it.
|
||||
printer->Print(
|
||||
"com.google.protobuf.ExtensionRegistry registry =\n"
|
||||
" com.google.protobuf.ExtensionRegistry.newInstance();\n"
|
||||
"registerAllExtensions(registry);\n");
|
||||
for (int i = 0; i < file_->dependency_count(); i++) {
|
||||
printer->Print(
|
||||
"$dependency$.registerAllExtensions(registry);\n",
|
||||
"dependency", ClassName(file_->dependency(i)));
|
||||
" com.google.protobuf.ExtensionRegistry.newInstance();\n");
|
||||
for (int i = 0; i < extensions.size(); i++) {
|
||||
ExtensionGenerator(extensions[i]).GenerateRegistrationCode(printer);
|
||||
}
|
||||
printer->Print(
|
||||
"return registry;\n");
|
||||
@ -372,18 +423,21 @@ template<typename GeneratorClass, typename DescriptorClass>
|
||||
static void GenerateSibling(const string& package_dir,
|
||||
const string& java_package,
|
||||
const DescriptorClass* descriptor,
|
||||
OutputDirectory* output_directory,
|
||||
vector<string>* file_list) {
|
||||
string filename = package_dir + descriptor->name() + ".java";
|
||||
GeneratorContext* context,
|
||||
vector<string>* file_list,
|
||||
const string& name_suffix,
|
||||
void (GeneratorClass::*pfn)(io::Printer* printer)) {
|
||||
string filename = package_dir + descriptor->name() + name_suffix + ".java";
|
||||
file_list->push_back(filename);
|
||||
|
||||
scoped_ptr<io::ZeroCopyOutputStream> output(
|
||||
output_directory->Open(filename));
|
||||
scoped_ptr<io::ZeroCopyOutputStream> output(context->Open(filename));
|
||||
io::Printer printer(output.get(), '$');
|
||||
|
||||
printer.Print(
|
||||
"// Generated by the protocol buffer compiler. DO NOT EDIT!\n"
|
||||
"\n");
|
||||
"// source: $filename$\n"
|
||||
"\n",
|
||||
"filename", descriptor->file()->name());
|
||||
if (!java_package.empty()) {
|
||||
printer.Print(
|
||||
"package $package$;\n"
|
||||
@ -391,28 +445,36 @@ static void GenerateSibling(const string& package_dir,
|
||||
"package", java_package);
|
||||
}
|
||||
|
||||
GeneratorClass(descriptor).Generate(&printer);
|
||||
GeneratorClass generator(descriptor);
|
||||
(generator.*pfn)(&printer);
|
||||
}
|
||||
|
||||
void FileGenerator::GenerateSiblings(const string& package_dir,
|
||||
OutputDirectory* output_directory,
|
||||
GeneratorContext* context,
|
||||
vector<string>* file_list) {
|
||||
if (file_->options().java_multiple_files()) {
|
||||
for (int i = 0; i < file_->enum_type_count(); i++) {
|
||||
GenerateSibling<EnumGenerator>(package_dir, java_package_,
|
||||
file_->enum_type(i),
|
||||
output_directory, file_list);
|
||||
context, file_list, "",
|
||||
&EnumGenerator::Generate);
|
||||
}
|
||||
for (int i = 0; i < file_->message_type_count(); i++) {
|
||||
GenerateSibling<MessageGenerator>(package_dir, java_package_,
|
||||
file_->message_type(i),
|
||||
output_directory, file_list);
|
||||
context, file_list, "OrBuilder",
|
||||
&MessageGenerator::GenerateInterface);
|
||||
GenerateSibling<MessageGenerator>(package_dir, java_package_,
|
||||
file_->message_type(i),
|
||||
context, file_list, "",
|
||||
&MessageGenerator::Generate);
|
||||
}
|
||||
if (HasGenericServices(file_)) {
|
||||
for (int i = 0; i < file_->service_count(); i++) {
|
||||
GenerateSibling<ServiceGenerator>(package_dir, java_package_,
|
||||
file_->service(i),
|
||||
output_directory, file_list);
|
||||
context, file_list, "",
|
||||
&ServiceGenerator::Generate);
|
||||
}
|
||||
}
|
||||
}
|
@ -46,7 +46,7 @@ namespace protobuf {
|
||||
class Printer; // printer.h
|
||||
}
|
||||
namespace compiler {
|
||||
class OutputDirectory; // code_generator.h
|
||||
class GeneratorContext; // code_generator.h
|
||||
}
|
||||
}
|
||||
|
||||
@ -70,12 +70,13 @@ class FileGenerator {
|
||||
// files other than the outer file (i.e. one for each message, enum, and
|
||||
// service type).
|
||||
void GenerateSiblings(const string& package_dir,
|
||||
OutputDirectory* output_directory,
|
||||
GeneratorContext* generator_context,
|
||||
vector<string>* file_list);
|
||||
|
||||
const string& java_package() { return java_package_; }
|
||||
const string& classname() { return classname_; }
|
||||
|
||||
|
||||
private:
|
||||
// Returns whether the dependency should be included in the output file.
|
||||
// Always returns true for opensource, but used internally at Google to help
|
||||
@ -86,6 +87,7 @@ class FileGenerator {
|
||||
string java_package_;
|
||||
string classname_;
|
||||
|
||||
|
||||
void GenerateEmbeddedDescriptor(io::Printer* printer);
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileGenerator);
|
@ -51,11 +51,8 @@ JavaGenerator::~JavaGenerator() {}
|
||||
|
||||
bool JavaGenerator::Generate(const FileDescriptor* file,
|
||||
const string& parameter,
|
||||
OutputDirectory* output_directory,
|
||||
GeneratorContext* context,
|
||||
string* error) const {
|
||||
vector<pair<string, string> > options;
|
||||
ParseGeneratorParameter(parameter, &options);
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// parse generator options
|
||||
|
||||
@ -63,6 +60,10 @@ bool JavaGenerator::Generate(const FileDescriptor* file,
|
||||
// per line.
|
||||
string output_list_file;
|
||||
|
||||
|
||||
vector<pair<string, string> > options;
|
||||
ParseGeneratorParameter(parameter, &options);
|
||||
|
||||
for (int i = 0; i < options.size(); i++) {
|
||||
if (options[i].first == "output_list_file") {
|
||||
output_list_file = options[i].second;
|
||||
@ -72,18 +73,23 @@ bool JavaGenerator::Generate(const FileDescriptor* file,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
|
||||
if (file->options().optimize_for() == FileOptions::LITE_RUNTIME &&
|
||||
file->options().java_generate_equals_and_hash()) {
|
||||
*error = "The \"java_generate_equals_and_hash\" option is incompatible "
|
||||
"with \"optimize_for = LITE_RUNTIME\". You must optimize for "
|
||||
"SPEED or CODE_SIZE if you want to use this option.";
|
||||
return false;
|
||||
}
|
||||
|
||||
FileGenerator file_generator(file);
|
||||
if (!file_generator.Validate(error)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
string package_dir =
|
||||
StringReplace(file_generator.java_package(), ".", "/", true);
|
||||
if (!package_dir.empty()) package_dir += "/";
|
||||
string package_dir = JavaPackageToDir(file_generator.java_package());
|
||||
|
||||
vector<string> all_files;
|
||||
|
||||
@ -94,19 +100,19 @@ bool JavaGenerator::Generate(const FileDescriptor* file,
|
||||
|
||||
// Generate main java file.
|
||||
scoped_ptr<io::ZeroCopyOutputStream> output(
|
||||
output_directory->Open(java_filename));
|
||||
context->Open(java_filename));
|
||||
io::Printer printer(output.get(), '$');
|
||||
file_generator.Generate(&printer);
|
||||
|
||||
// Generate sibling files.
|
||||
file_generator.GenerateSiblings(package_dir, output_directory, &all_files);
|
||||
file_generator.GenerateSiblings(package_dir, context, &all_files);
|
||||
|
||||
// Generate output list if requested.
|
||||
if (!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.
|
||||
scoped_ptr<io::ZeroCopyOutputStream> srclist_raw_output(
|
||||
output_directory->Open(output_list_file));
|
||||
context->Open(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]);
|
@ -57,7 +57,7 @@ class LIBPROTOC_EXPORT JavaGenerator : public CodeGenerator {
|
||||
// implements CodeGenerator ----------------------------------------
|
||||
bool Generate(const FileDescriptor* file,
|
||||
const string& parameter,
|
||||
OutputDirectory* output_directory,
|
||||
GeneratorContext* context,
|
||||
string* error) const;
|
||||
|
||||
private:
|
@ -134,16 +134,27 @@ string FileClassName(const FileDescriptor* file) {
|
||||
}
|
||||
|
||||
string FileJavaPackage(const FileDescriptor* file) {
|
||||
string result;
|
||||
|
||||
if (file->options().has_java_package()) {
|
||||
return file->options().java_package();
|
||||
result = file->options().java_package();
|
||||
} else {
|
||||
string result = kDefaultPackage;
|
||||
result = kDefaultPackage;
|
||||
if (!file->package().empty()) {
|
||||
if (!result.empty()) result += '.';
|
||||
result += file->package();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
string JavaPackageToDir(string package_name) {
|
||||
string package_dir =
|
||||
StringReplace(package_name, ".", "/", true);
|
||||
if (!package_dir.empty()) package_dir += "/";
|
||||
return package_dir;
|
||||
}
|
||||
|
||||
string ToJavaName(const string& full_name, const FileDescriptor* file) {
|
||||
@ -166,6 +177,18 @@ string ToJavaName(const string& full_name, const FileDescriptor* file) {
|
||||
return result;
|
||||
}
|
||||
|
||||
string ClassName(const Descriptor* descriptor) {
|
||||
return ToJavaName(descriptor->full_name(), descriptor->file());
|
||||
}
|
||||
|
||||
string ClassName(const EnumDescriptor* descriptor) {
|
||||
return ToJavaName(descriptor->full_name(), descriptor->file());
|
||||
}
|
||||
|
||||
string ClassName(const ServiceDescriptor* descriptor) {
|
||||
return ToJavaName(descriptor->full_name(), descriptor->file());
|
||||
}
|
||||
|
||||
string ClassName(const FileDescriptor* descriptor) {
|
||||
string result = FileJavaPackage(descriptor);
|
||||
if (!result.empty()) result += '.';
|
||||
@ -315,14 +338,14 @@ string DefaultValue(const FieldDescriptor* field) {
|
||||
} else {
|
||||
// See comments in Internal.java for gory details.
|
||||
return strings::Substitute(
|
||||
"com.google.protobuf.Internal.stringDefaultValue(\"$0\")",
|
||||
CEscape(field->default_value_string()));
|
||||
"com.google.protobuf.Internal.stringDefaultValue(\"$0\")",
|
||||
CEscape(field->default_value_string()));
|
||||
}
|
||||
}
|
||||
|
||||
case FieldDescriptor::CPPTYPE_ENUM:
|
||||
return ClassName(field->enum_type()) + "." +
|
||||
field->default_value_enum()->name();
|
||||
field->default_value_enum()->name();
|
||||
|
||||
case FieldDescriptor::CPPTYPE_MESSAGE:
|
||||
return ClassName(field->message_type()) + ".getDefaultInstance()";
|
||||
@ -335,6 +358,142 @@ string DefaultValue(const FieldDescriptor* field) {
|
||||
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_STRING:
|
||||
case FieldDescriptor::CPPTYPE_ENUM:
|
||||
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;
|
||||
}
|
||||
|
||||
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",
|
||||
};
|
||||
|
||||
string GetBitFieldName(int index) {
|
||||
string varName = "bitField";
|
||||
varName += SimpleItoa(index);
|
||||
varName += "_";
|
||||
return varName;
|
||||
}
|
||||
|
||||
string GetBitFieldNameForBit(int bitIndex) {
|
||||
return GetBitFieldName(bitIndex / 32);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
string GenerateGetBitInternal(const string& prefix, int bitIndex) {
|
||||
string varName = prefix + GetBitFieldNameForBit(bitIndex);
|
||||
int bitInVarIndex = bitIndex % 32;
|
||||
|
||||
string mask = bit_masks[bitInVarIndex];
|
||||
string result = "((" + varName + " & " + mask + ") == " + mask + ")";
|
||||
return result;
|
||||
}
|
||||
|
||||
string GenerateSetBitInternal(const string& prefix, int bitIndex) {
|
||||
string varName = prefix + GetBitFieldNameForBit(bitIndex);
|
||||
int bitInVarIndex = bitIndex % 32;
|
||||
|
||||
string mask = bit_masks[bitInVarIndex];
|
||||
string result = varName + " |= " + mask;
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
string GenerateGetBit(int bitIndex) {
|
||||
return GenerateGetBitInternal("", bitIndex);
|
||||
}
|
||||
|
||||
string GenerateSetBit(int bitIndex) {
|
||||
return GenerateSetBitInternal("", bitIndex);
|
||||
}
|
||||
|
||||
string GenerateClearBit(int bitIndex) {
|
||||
string varName = GetBitFieldNameForBit(bitIndex);
|
||||
int bitInVarIndex = bitIndex % 32;
|
||||
|
||||
string mask = bit_masks[bitInVarIndex];
|
||||
string result = varName + " = (" + varName + " & ~" + mask + ")";
|
||||
return result;
|
||||
}
|
||||
|
||||
string GenerateGetBitFromLocal(int bitIndex) {
|
||||
return GenerateGetBitInternal("from_", bitIndex);
|
||||
}
|
||||
|
||||
string GenerateSetBitToLocal(int bitIndex) {
|
||||
return GenerateSetBitInternal("to_", bitIndex);
|
||||
}
|
||||
|
||||
string GenerateGetBitMutableLocal(int bitIndex) {
|
||||
return GenerateGetBitInternal("mutable_", bitIndex);
|
||||
}
|
||||
|
||||
string GenerateSetBitMutableLocal(int bitIndex) {
|
||||
return GenerateSetBitInternal("mutable_", bitIndex);
|
||||
}
|
||||
|
||||
} // namespace java
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
@ -68,6 +68,9 @@ string FileClassName(const FileDescriptor* file);
|
||||
// Returns the file's Java package name.
|
||||
string FileJavaPackage(const FileDescriptor* file);
|
||||
|
||||
// Returns output directory for the given package name.
|
||||
string JavaPackageToDir(string package_name);
|
||||
|
||||
// Converts the given fully-qualified name in the proto namespace to its
|
||||
// fully-qualified name in the Java namespace, given that it is in the given
|
||||
// file.
|
||||
@ -75,19 +78,14 @@ string ToJavaName(const string& full_name, const FileDescriptor* file);
|
||||
|
||||
// These return the fully-qualified class name corresponding to the given
|
||||
// descriptor.
|
||||
inline string ClassName(const Descriptor* descriptor) {
|
||||
return ToJavaName(descriptor->full_name(), descriptor->file());
|
||||
}
|
||||
inline string ClassName(const EnumDescriptor* descriptor) {
|
||||
return ToJavaName(descriptor->full_name(), descriptor->file());
|
||||
}
|
||||
inline string ClassName(const ServiceDescriptor* descriptor) {
|
||||
return ToJavaName(descriptor->full_name(), descriptor->file());
|
||||
}
|
||||
string ClassName(const Descriptor* descriptor);
|
||||
string ClassName(const EnumDescriptor* descriptor);
|
||||
string ClassName(const ServiceDescriptor* descriptor);
|
||||
string ClassName(const FileDescriptor* descriptor);
|
||||
|
||||
inline string ExtensionIdentifierName(const FieldDescriptor* descriptor) {
|
||||
return ToJavaName(descriptor->full_name(), descriptor->file());
|
||||
}
|
||||
string ClassName(const FileDescriptor* descriptor);
|
||||
|
||||
// Get the unqualified name that should be used for a field's field
|
||||
// number constant.
|
||||
@ -118,6 +116,7 @@ JavaType GetJavaType(const FieldDescriptor* field);
|
||||
const char* BoxedPrimitiveTypeName(JavaType type);
|
||||
|
||||
string DefaultValue(const FieldDescriptor* field);
|
||||
bool IsDefaultValueJavaDefault(const FieldDescriptor* field);
|
||||
|
||||
// Does this message class keep track of unknown fields?
|
||||
inline bool HasUnknownFields(const Descriptor* descriptor) {
|
||||
@ -132,6 +131,11 @@ inline bool HasGeneratedMethods(const Descriptor* descriptor) {
|
||||
FileOptions::CODE_SIZE;
|
||||
}
|
||||
|
||||
// Does this message have specialized equals() and hashCode() methods?
|
||||
inline bool HasEqualsAndHashCode(const Descriptor* descriptor) {
|
||||
return descriptor->file()->options().java_generate_equals_and_hash();
|
||||
}
|
||||
|
||||
// Does this message class have descriptor and reflection methods?
|
||||
inline bool HasDescriptorMethods(const Descriptor* descriptor) {
|
||||
return descriptor->file()->options().optimize_for() !=
|
||||
@ -146,6 +150,12 @@ inline bool HasDescriptorMethods(const FileDescriptor* descriptor) {
|
||||
FileOptions::LITE_RUNTIME;
|
||||
}
|
||||
|
||||
inline bool HasNestedBuilders(const Descriptor* descriptor) {
|
||||
// The proto-lite version doesn't support nested builders.
|
||||
return descriptor->file()->options().optimize_for() !=
|
||||
FileOptions::LITE_RUNTIME;
|
||||
}
|
||||
|
||||
// Should we generate generic services for this file?
|
||||
inline bool HasGenericServices(const FileDescriptor *file) {
|
||||
return file->service_count() > 0 &&
|
||||
@ -153,6 +163,55 @@ inline bool HasGenericServices(const FileDescriptor *file) {
|
||||
file->options().java_generic_services();
|
||||
}
|
||||
|
||||
|
||||
// Methods for shared bitfields.
|
||||
|
||||
// Gets the name of the shared bitfield for the given index.
|
||||
string GetBitFieldName(int index);
|
||||
|
||||
// Gets the name of the shared bitfield for the given bit index.
|
||||
// Effectively, GetBitFieldName(bitIndex / 32)
|
||||
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)"
|
||||
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)"
|
||||
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)"
|
||||
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)"
|
||||
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)"
|
||||
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)"
|
||||
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)"
|
||||
string GenerateSetBitMutableLocal(int bitIndex);
|
||||
|
||||
} // namespace java
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
File diff suppressed because it is too large
Load Diff
@ -67,11 +67,19 @@ class MessageGenerator {
|
||||
// Generate the class itself.
|
||||
void Generate(io::Printer* printer);
|
||||
|
||||
// Generates the base interface that both the class and its builder implement
|
||||
void GenerateInterface(io::Printer* printer);
|
||||
|
||||
// Generate code to register all contained extensions with an
|
||||
// ExtensionRegistry.
|
||||
void GenerateExtensionRegistrationCode(io::Printer* printer);
|
||||
|
||||
private:
|
||||
enum UseMemoization {
|
||||
MEMOIZE,
|
||||
DONT_MEMOIZE
|
||||
};
|
||||
|
||||
void GenerateMessageSerializationMethods(io::Printer* printer);
|
||||
void GenerateParseFromMethods(io::Printer* printer);
|
||||
void GenerateSerializeOneField(io::Printer* printer,
|
||||
@ -81,8 +89,14 @@ class MessageGenerator {
|
||||
|
||||
void GenerateBuilder(io::Printer* printer);
|
||||
void GenerateCommonBuilderMethods(io::Printer* printer);
|
||||
void GenerateDescriptorMethods(io::Printer* printer);
|
||||
void GenerateBuilderParsingMethods(io::Printer* printer);
|
||||
void GenerateIsInitialized(io::Printer* printer);
|
||||
void GenerateIsInitialized(io::Printer* printer,
|
||||
UseMemoization useMemoization);
|
||||
void GenerateEqualsAndHashCode(io::Printer* printer);
|
||||
|
||||
void GenerateParser(io::Printer* printer);
|
||||
void GenerateParsingConstructor(io::Printer* printer);
|
||||
|
||||
const Descriptor* descriptor_;
|
||||
FieldGeneratorMap field_generators_;
|
@ -0,0 +1,974 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// 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 <google/protobuf/compiler/java/java_message_field.h>
|
||||
#include <google/protobuf/compiler/java/java_doc_comment.h>
|
||||
#include <google/protobuf/compiler/java/java_helpers.h>
|
||||
#include <google/protobuf/io/printer.h>
|
||||
#include <google/protobuf/wire_format.h>
|
||||
#include <google/protobuf/stubs/strutil.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace java {
|
||||
|
||||
namespace {
|
||||
|
||||
// TODO(kenton): Factor out a "SetCommonFieldVariables()" to get rid of
|
||||
// repeat code between this and the other field types.
|
||||
void SetMessageVariables(const FieldDescriptor* descriptor,
|
||||
int messageBitIndex,
|
||||
int builderBitIndex,
|
||||
map<string, string>* variables) {
|
||||
(*variables)["name"] =
|
||||
UnderscoresToCamelCase(descriptor);
|
||||
(*variables)["capitalized_name"] =
|
||||
UnderscoresToCapitalizedCamelCase(descriptor);
|
||||
(*variables)["constant_name"] = FieldConstantName(descriptor);
|
||||
(*variables)["number"] = SimpleItoa(descriptor->number());
|
||||
(*variables)["type"] = ClassName(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)["on_changed"] =
|
||||
HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : "";
|
||||
|
||||
// For singular messages and builders, one bit is used for the hasField bit.
|
||||
(*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex);
|
||||
(*variables)["set_has_field_bit_message"] = GenerateSetBit(messageBitIndex);
|
||||
|
||||
(*variables)["get_has_field_bit_builder"] = GenerateGetBit(builderBitIndex);
|
||||
(*variables)["set_has_field_bit_builder"] = GenerateSetBit(builderBitIndex);
|
||||
(*variables)["clear_has_field_bit_builder"] =
|
||||
GenerateClearBit(builderBitIndex);
|
||||
|
||||
// For repated 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
|
||||
|
||||
// ===================================================================
|
||||
|
||||
MessageFieldGenerator::
|
||||
MessageFieldGenerator(const FieldDescriptor* descriptor,
|
||||
int messageBitIndex,
|
||||
int builderBitIndex)
|
||||
: descriptor_(descriptor), messageBitIndex_(messageBitIndex),
|
||||
builderBitIndex_(builderBitIndex) {
|
||||
SetMessageVariables(descriptor, messageBitIndex, builderBitIndex,
|
||||
&variables_);
|
||||
}
|
||||
|
||||
MessageFieldGenerator::~MessageFieldGenerator() {}
|
||||
|
||||
int MessageFieldGenerator::GetNumBitsForMessage() const {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int MessageFieldGenerator::GetNumBitsForBuilder() const {
|
||||
return 1;
|
||||
}
|
||||
|
||||
void MessageFieldGenerator::
|
||||
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.
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$boolean has$capitalized_name$();\n");
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$$type$ get$capitalized_name$();\n");
|
||||
|
||||
if (HasNestedBuilders(descriptor_->containing_type())) {
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$$type$OrBuilder get$capitalized_name$OrBuilder();\n");
|
||||
}
|
||||
}
|
||||
|
||||
void MessageFieldGenerator::
|
||||
GenerateMembers(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"private $type$ $name$_;\n");
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public boolean has$capitalized_name$() {\n"
|
||||
" return $get_has_field_bit_message$;\n"
|
||||
"}\n");
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public $type$ get$capitalized_name$() {\n"
|
||||
" return $name$_;\n"
|
||||
"}\n");
|
||||
|
||||
if (HasNestedBuilders(descriptor_->containing_type())) {
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder() {\n"
|
||||
" return $name$_;\n"
|
||||
"}\n");
|
||||
}
|
||||
}
|
||||
|
||||
void MessageFieldGenerator::PrintNestedBuilderCondition(
|
||||
io::Printer* printer,
|
||||
const char* regular_case,
|
||||
const char* nested_builder_case) const {
|
||||
if (HasNestedBuilders(descriptor_->containing_type())) {
|
||||
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");
|
||||
} else {
|
||||
printer->Print(variables_, regular_case);
|
||||
}
|
||||
}
|
||||
|
||||
void MessageFieldGenerator::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->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 MessageFieldGenerator::
|
||||
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.
|
||||
"private $type$ $name$_ = $type$.getDefaultInstance();\n");
|
||||
|
||||
if (HasNestedBuilders(descriptor_->containing_type())) {
|
||||
printer->Print(variables_,
|
||||
// If this builder is non-null, it is used and the other fields are
|
||||
// ignored.
|
||||
"private com.google.protobuf.SingleFieldBuilder<\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()
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public boolean has$capitalized_name$() {\n"
|
||||
" return $get_has_field_bit_builder$;\n"
|
||||
"}\n");
|
||||
|
||||
// Field getField()
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
PrintNestedBuilderFunction(printer,
|
||||
"$deprecation$public $type$ get$capitalized_name$()",
|
||||
|
||||
"return $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)",
|
||||
|
||||
"if ($get_has_field_bit_builder$ &&\n"
|
||||
" $name$_ != $type$.getDefaultInstance()) {\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$_ = $type$.getDefaultInstance();\n"
|
||||
"$on_changed$\n",
|
||||
|
||||
"$name$Builder_.clear();\n",
|
||||
|
||||
"$clear_has_field_bit_builder$;\n"
|
||||
"return this;\n");
|
||||
|
||||
if (HasNestedBuilders(descriptor_->containing_type())) {
|
||||
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");
|
||||
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$_;\n"
|
||||
" }\n"
|
||||
"}\n");
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"private com.google.protobuf.SingleFieldBuilder<\n"
|
||||
" $type$, $type$.Builder, $type$OrBuilder> \n"
|
||||
" get$capitalized_name$FieldBuilder() {\n"
|
||||
" if ($name$Builder_ == null) {\n"
|
||||
" $name$Builder_ = new com.google.protobuf.SingleFieldBuilder<\n"
|
||||
" $type$, $type$.Builder, $type$OrBuilder>(\n"
|
||||
" $name$_,\n"
|
||||
" getParentForChildren(),\n"
|
||||
" isClean());\n"
|
||||
" $name$_ = null;\n"
|
||||
" }\n"
|
||||
" return $name$Builder_;\n"
|
||||
"}\n");
|
||||
}
|
||||
}
|
||||
|
||||
void MessageFieldGenerator::
|
||||
GenerateFieldBuilderInitializationCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"get$capitalized_name$FieldBuilder();\n");
|
||||
}
|
||||
|
||||
|
||||
void MessageFieldGenerator::
|
||||
GenerateInitializationCode(io::Printer* printer) const {
|
||||
printer->Print(variables_, "$name$_ = $type$.getDefaultInstance();\n");
|
||||
}
|
||||
|
||||
void MessageFieldGenerator::
|
||||
GenerateBuilderClearCode(io::Printer* printer) const {
|
||||
PrintNestedBuilderCondition(printer,
|
||||
"$name$_ = $type$.getDefaultInstance();\n",
|
||||
|
||||
"$name$Builder_.clear();\n");
|
||||
printer->Print(variables_, "$clear_has_field_bit_builder$;\n");
|
||||
}
|
||||
|
||||
void MessageFieldGenerator::
|
||||
GenerateMergingCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"if (other.has$capitalized_name$()) {\n"
|
||||
" merge$capitalized_name$(other.get$capitalized_name$());\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void MessageFieldGenerator::
|
||||
GenerateBuildingCode(io::Printer* printer) const {
|
||||
|
||||
printer->Print(variables_,
|
||||
"if ($get_has_field_bit_from_local$) {\n"
|
||||
" $set_has_field_bit_to_local$;\n"
|
||||
"}\n");
|
||||
|
||||
PrintNestedBuilderCondition(printer,
|
||||
"result.$name$_ = $name$_;\n",
|
||||
|
||||
"result.$name$_ = $name$Builder_.build();\n");
|
||||
}
|
||||
|
||||
void MessageFieldGenerator::
|
||||
GenerateParsingCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"$type$.Builder subBuilder = null;\n"
|
||||
"if ($get_has_field_bit_message$) {\n"
|
||||
" subBuilder = $name$_.toBuilder();\n"
|
||||
"}\n");
|
||||
|
||||
if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) {
|
||||
printer->Print(variables_,
|
||||
"$name$_ = input.readGroup($number$, $type$.PARSER,\n"
|
||||
" extensionRegistry);\n");
|
||||
} else {
|
||||
printer->Print(variables_,
|
||||
"$name$_ = input.readMessage($type$.PARSER, extensionRegistry);\n");
|
||||
}
|
||||
|
||||
printer->Print(variables_,
|
||||
"if (subBuilder != null) {\n"
|
||||
" subBuilder.mergeFrom($name$_);\n"
|
||||
" $name$_ = subBuilder.buildPartial();\n"
|
||||
"}\n");
|
||||
printer->Print(variables_,
|
||||
"$set_has_field_bit_message$;\n");
|
||||
}
|
||||
|
||||
void MessageFieldGenerator::
|
||||
GenerateParsingDoneCode(io::Printer* printer) const {
|
||||
// noop for messages.
|
||||
}
|
||||
|
||||
void MessageFieldGenerator::
|
||||
GenerateSerializationCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"if ($get_has_field_bit_message$) {\n"
|
||||
" output.write$group_or_message$($number$, $name$_);\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void MessageFieldGenerator::
|
||||
GenerateSerializedSizeCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"if ($get_has_field_bit_message$) {\n"
|
||||
" size += com.google.protobuf.CodedOutputStream\n"
|
||||
" .compute$group_or_message$Size($number$, $name$_);\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void MessageFieldGenerator::
|
||||
GenerateEqualsCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"result = result && get$capitalized_name$()\n"
|
||||
" .equals(other.get$capitalized_name$());\n");
|
||||
}
|
||||
|
||||
void MessageFieldGenerator::
|
||||
GenerateHashCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"hash = (37 * hash) + $constant_name$;\n"
|
||||
"hash = (53 * hash) + get$capitalized_name$().hashCode();\n");
|
||||
}
|
||||
|
||||
string MessageFieldGenerator::GetBoxedType() const {
|
||||
return ClassName(descriptor_->message_type());
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
RepeatedMessageFieldGenerator::
|
||||
RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor,
|
||||
int messageBitIndex,
|
||||
int builderBitIndex)
|
||||
: descriptor_(descriptor), messageBitIndex_(messageBitIndex),
|
||||
builderBitIndex_(builderBitIndex) {
|
||||
SetMessageVariables(descriptor, messageBitIndex, builderBitIndex,
|
||||
&variables_);
|
||||
}
|
||||
|
||||
RepeatedMessageFieldGenerator::~RepeatedMessageFieldGenerator() {}
|
||||
|
||||
int RepeatedMessageFieldGenerator::GetNumBitsForMessage() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int RepeatedMessageFieldGenerator::GetNumBitsForBuilder() const {
|
||||
return 1;
|
||||
}
|
||||
|
||||
void RepeatedMessageFieldGenerator::
|
||||
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");
|
||||
if (HasNestedBuilders(descriptor_->containing_type())) {
|
||||
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 RepeatedMessageFieldGenerator::
|
||||
GenerateMembers(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"private java.util.List<$type$> $name$_;\n");
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public java.util.List<$type$> get$capitalized_name$List() {\n"
|
||||
" return $name$_;\n" // note: unmodifiable list
|
||||
"}\n");
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public java.util.List<? extends $type$OrBuilder> \n"
|
||||
" get$capitalized_name$OrBuilderList() {\n"
|
||||
" return $name$_;\n"
|
||||
"}\n");
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public int get$capitalized_name$Count() {\n"
|
||||
" return $name$_.size();\n"
|
||||
"}\n");
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public $type$ get$capitalized_name$(int index) {\n"
|
||||
" return $name$_.get(index);\n"
|
||||
"}\n");
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder(\n"
|
||||
" int index) {\n"
|
||||
" return $name$_.get(index);\n"
|
||||
"}\n");
|
||||
|
||||
}
|
||||
|
||||
void RepeatedMessageFieldGenerator::PrintNestedBuilderCondition(
|
||||
io::Printer* printer,
|
||||
const char* regular_case,
|
||||
const char* nested_builder_case) const {
|
||||
if (HasNestedBuilders(descriptor_->containing_type())) {
|
||||
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");
|
||||
} else {
|
||||
printer->Print(variables_, regular_case);
|
||||
}
|
||||
}
|
||||
|
||||
void RepeatedMessageFieldGenerator::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->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 RepeatedMessageFieldGenerator::
|
||||
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 refererence 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");
|
||||
|
||||
if (HasNestedBuilders(descriptor_->containing_type())) {
|
||||
printer->Print(variables_,
|
||||
// If this builder is non-null, it is used and the other fields are
|
||||
// ignored.
|
||||
"private com.google.protobuf.RepeatedFieldBuilder<\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"
|
||||
"super.addAll(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");
|
||||
|
||||
if (HasNestedBuilders(descriptor_->containing_type())) {
|
||||
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");
|
||||
|
||||
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");
|
||||
|
||||
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");
|
||||
|
||||
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");
|
||||
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");
|
||||
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<\n"
|
||||
" $type$, $type$.Builder, $type$OrBuilder> \n"
|
||||
" get$capitalized_name$FieldBuilder() {\n"
|
||||
" if ($name$Builder_ == null) {\n"
|
||||
" $name$Builder_ = new com.google.protobuf.RepeatedFieldBuilder<\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");
|
||||
}
|
||||
}
|
||||
|
||||
void RepeatedMessageFieldGenerator::
|
||||
GenerateFieldBuilderInitializationCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"get$capitalized_name$FieldBuilder();\n");
|
||||
}
|
||||
|
||||
void RepeatedMessageFieldGenerator::
|
||||
GenerateInitializationCode(io::Printer* printer) const {
|
||||
printer->Print(variables_, "$name$_ = java.util.Collections.emptyList();\n");
|
||||
}
|
||||
|
||||
void RepeatedMessageFieldGenerator::
|
||||
GenerateBuilderClearCode(io::Printer* printer) const {
|
||||
PrintNestedBuilderCondition(printer,
|
||||
"$name$_ = java.util.Collections.emptyList();\n"
|
||||
"$clear_mutable_bit_builder$;\n",
|
||||
|
||||
"$name$Builder_.clear();\n");
|
||||
}
|
||||
|
||||
void RepeatedMessageFieldGenerator::
|
||||
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.alwaysUseFieldBuilders ?\n"
|
||||
" get$capitalized_name$FieldBuilder() : null;\n"
|
||||
" } else {\n"
|
||||
" $name$Builder_.addAllMessages(other.$name$_);\n"
|
||||
" }\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void RepeatedMessageFieldGenerator::
|
||||
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 RepeatedMessageFieldGenerator::
|
||||
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$.PARSER,\n"
|
||||
" extensionRegistry));\n");
|
||||
} else {
|
||||
printer->Print(variables_,
|
||||
"$name$_.add(input.readMessage($type$.PARSER, extensionRegistry));\n");
|
||||
}
|
||||
}
|
||||
|
||||
void RepeatedMessageFieldGenerator::
|
||||
GenerateParsingDoneCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"if ($get_mutable_bit_parser$) {\n"
|
||||
" $name$_ = java.util.Collections.unmodifiableList($name$_);\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void RepeatedMessageFieldGenerator::
|
||||
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 RepeatedMessageFieldGenerator::
|
||||
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 RepeatedMessageFieldGenerator::
|
||||
GenerateEqualsCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"result = result && get$capitalized_name$List()\n"
|
||||
" .equals(other.get$capitalized_name$List());\n");
|
||||
}
|
||||
|
||||
void RepeatedMessageFieldGenerator::
|
||||
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");
|
||||
}
|
||||
|
||||
string RepeatedMessageFieldGenerator::GetBoxedType() const {
|
||||
return ClassName(descriptor_->message_type());
|
||||
}
|
||||
|
||||
} // namespace java
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -46,50 +46,86 @@ namespace java {
|
||||
|
||||
class MessageFieldGenerator : public FieldGenerator {
|
||||
public:
|
||||
explicit MessageFieldGenerator(const FieldDescriptor* descriptor);
|
||||
explicit MessageFieldGenerator(const FieldDescriptor* descriptor,
|
||||
int messageBitIndex, int builderBitIndex);
|
||||
~MessageFieldGenerator();
|
||||
|
||||
// implements FieldGenerator ---------------------------------------
|
||||
int GetNumBitsForMessage() const;
|
||||
int GetNumBitsForBuilder() const;
|
||||
void GenerateInterfaceMembers(io::Printer* printer) const;
|
||||
void GenerateMembers(io::Printer* printer) const;
|
||||
void GenerateBuilderMembers(io::Printer* printer) const;
|
||||
void GenerateInitializationCode(io::Printer* printer) const;
|
||||
void GenerateBuilderClearCode(io::Printer* printer) const;
|
||||
void GenerateMergingCode(io::Printer* printer) const;
|
||||
void GenerateBuildingCode(io::Printer* printer) const;
|
||||
void GenerateParsingCode(io::Printer* printer) const;
|
||||
void GenerateParsingDoneCode(io::Printer* printer) const;
|
||||
void GenerateSerializationCode(io::Printer* printer) const;
|
||||
void GenerateSerializedSizeCode(io::Printer* printer) const;
|
||||
void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
|
||||
void GenerateEqualsCode(io::Printer* printer) const;
|
||||
void GenerateHashCode(io::Printer* printer) const;
|
||||
|
||||
string GetBoxedType() const;
|
||||
|
||||
private:
|
||||
const FieldDescriptor* descriptor_;
|
||||
map<string, string> variables_;
|
||||
const int messageBitIndex_;
|
||||
const int builderBitIndex_;
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageFieldGenerator);
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
class RepeatedMessageFieldGenerator : public FieldGenerator {
|
||||
public:
|
||||
explicit RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor);
|
||||
explicit RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor,
|
||||
int messageBitIndex, int builderBitIndex);
|
||||
~RepeatedMessageFieldGenerator();
|
||||
|
||||
// implements FieldGenerator ---------------------------------------
|
||||
int GetNumBitsForMessage() const;
|
||||
int GetNumBitsForBuilder() const;
|
||||
void GenerateInterfaceMembers(io::Printer* printer) const;
|
||||
void GenerateMembers(io::Printer* printer) const;
|
||||
void GenerateBuilderMembers(io::Printer* printer) const;
|
||||
void GenerateInitializationCode(io::Printer* printer) const;
|
||||
void GenerateBuilderClearCode(io::Printer* printer) const;
|
||||
void GenerateMergingCode(io::Printer* printer) const;
|
||||
void GenerateBuildingCode(io::Printer* printer) const;
|
||||
void GenerateParsingCode(io::Printer* printer) const;
|
||||
void GenerateParsingDoneCode(io::Printer* printer) const;
|
||||
void GenerateSerializationCode(io::Printer* printer) const;
|
||||
void GenerateSerializedSizeCode(io::Printer* printer) const;
|
||||
void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
|
||||
void GenerateEqualsCode(io::Printer* printer) const;
|
||||
void GenerateHashCode(io::Printer* printer) const;
|
||||
|
||||
string GetBoxedType() const;
|
||||
|
||||
private:
|
||||
const FieldDescriptor* descriptor_;
|
||||
map<string, string> variables_;
|
||||
const int messageBitIndex_;
|
||||
const int builderBitIndex_;
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedMessageFieldGenerator);
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
} // namespace java
|
@ -56,21 +56,22 @@ class TestGenerator : public CodeGenerator {
|
||||
|
||||
virtual bool Generate(const FileDescriptor* file,
|
||||
const string& parameter,
|
||||
OutputDirectory* output_directory,
|
||||
GeneratorContext* context,
|
||||
string* error) const {
|
||||
TryInsert("Test.java", "outer_class_scope", output_directory);
|
||||
TryInsert("Test.java", "class_scope:foo.Bar", output_directory);
|
||||
TryInsert("Test.java", "class_scope:foo.Bar.Baz", output_directory);
|
||||
TryInsert("Test.java", "builder_scope:foo.Bar", output_directory);
|
||||
TryInsert("Test.java", "builder_scope:foo.Bar.Baz", output_directory);
|
||||
TryInsert("Test.java", "enum_scope:foo.Qux", output_directory);
|
||||
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 string& filename, const string& insertion_point,
|
||||
OutputDirectory* output_directory) const {
|
||||
GeneratorContext* context) const {
|
||||
scoped_ptr<io::ZeroCopyOutputStream> output(
|
||||
output_directory->OpenForInsert(filename, insertion_point));
|
||||
context->OpenForInsert(filename, insertion_point));
|
||||
io::Printer printer(output.get(), '$');
|
||||
printer.Print("// inserted $name$\n", "name", insertion_point);
|
||||
}
|
@ -0,0 +1,787 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// 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 <google/protobuf/compiler/java/java_primitive_field.h>
|
||||
#include <google/protobuf/compiler/java/java_doc_comment.h>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/compiler/java/java_helpers.h>
|
||||
#include <google/protobuf/io/printer.h>
|
||||
#include <google/protobuf/wire_format.h>
|
||||
#include <google/protobuf/stubs/strutil.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace java {
|
||||
|
||||
using internal::WireFormat;
|
||||
using internal::WireFormatLite;
|
||||
|
||||
namespace {
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
|
||||
void SetPrimitiveVariables(const FieldDescriptor* descriptor,
|
||||
int messageBitIndex,
|
||||
int builderBitIndex,
|
||||
map<string, string>* variables) {
|
||||
(*variables)["name"] =
|
||||
UnderscoresToCamelCase(descriptor);
|
||||
(*variables)["capitalized_name"] =
|
||||
UnderscoresToCapitalizedCamelCase(descriptor);
|
||||
(*variables)["constant_name"] = FieldConstantName(descriptor);
|
||||
(*variables)["number"] = SimpleItoa(descriptor->number());
|
||||
(*variables)["type"] = PrimitiveTypeName(GetJavaType(descriptor));
|
||||
(*variables)["boxed_type"] = BoxedPrimitiveTypeName(GetJavaType(descriptor));
|
||||
(*variables)["field_type"] = (*variables)["type"];
|
||||
(*variables)["field_list_type"] = "java.util.List<" +
|
||||
(*variables)["boxed_type"] + ">";
|
||||
(*variables)["empty_list"] = "java.util.Collections.emptyList()";
|
||||
(*variables)["default"] = DefaultValue(descriptor);
|
||||
(*variables)["default_init"] = IsDefaultValueJavaDefault(descriptor) ?
|
||||
"" : ("= " + DefaultValue(descriptor));
|
||||
(*variables)["capitalized_type"] = GetCapitalizedType(descriptor);
|
||||
(*variables)["tag"] = SimpleItoa(WireFormat::MakeTag(descriptor));
|
||||
(*variables)["tag_size"] = SimpleItoa(
|
||||
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 " : "";
|
||||
int fixed_size = FixedSize(GetType(descriptor));
|
||||
if (fixed_size != -1) {
|
||||
(*variables)["fixed_size"] = SimpleItoa(fixed_size);
|
||||
}
|
||||
(*variables)["on_changed"] =
|
||||
HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : "";
|
||||
|
||||
// For singular messages and builders, one bit is used for the hasField bit.
|
||||
(*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex);
|
||||
(*variables)["set_has_field_bit_message"] = GenerateSetBit(messageBitIndex);
|
||||
|
||||
(*variables)["get_has_field_bit_builder"] = GenerateGetBit(builderBitIndex);
|
||||
(*variables)["set_has_field_bit_builder"] = GenerateSetBit(builderBitIndex);
|
||||
(*variables)["clear_has_field_bit_builder"] =
|
||||
GenerateClearBit(builderBitIndex);
|
||||
|
||||
// For repated 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
|
||||
|
||||
// ===================================================================
|
||||
|
||||
PrimitiveFieldGenerator::
|
||||
PrimitiveFieldGenerator(const FieldDescriptor* descriptor,
|
||||
int messageBitIndex,
|
||||
int builderBitIndex)
|
||||
: descriptor_(descriptor), messageBitIndex_(messageBitIndex),
|
||||
builderBitIndex_(builderBitIndex) {
|
||||
SetPrimitiveVariables(descriptor, messageBitIndex, builderBitIndex,
|
||||
&variables_);
|
||||
}
|
||||
|
||||
PrimitiveFieldGenerator::~PrimitiveFieldGenerator() {}
|
||||
|
||||
int PrimitiveFieldGenerator::GetNumBitsForMessage() const {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int PrimitiveFieldGenerator::GetNumBitsForBuilder() const {
|
||||
return 1;
|
||||
}
|
||||
|
||||
void PrimitiveFieldGenerator::
|
||||
GenerateInterfaceMembers(io::Printer* printer) const {
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$boolean has$capitalized_name$();\n");
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$$type$ get$capitalized_name$();\n");
|
||||
}
|
||||
|
||||
void PrimitiveFieldGenerator::
|
||||
GenerateMembers(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"private $field_type$ $name$_;\n");
|
||||
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public boolean has$capitalized_name$() {\n"
|
||||
" return $get_has_field_bit_message$;\n"
|
||||
"}\n");
|
||||
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public $type$ get$capitalized_name$() {\n"
|
||||
" return $name$_;\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void PrimitiveFieldGenerator::
|
||||
GenerateBuilderMembers(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"private $field_type$ $name$_ $default_init$;\n");
|
||||
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public boolean has$capitalized_name$() {\n"
|
||||
" return $get_has_field_bit_builder$;\n"
|
||||
"}\n");
|
||||
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public $type$ get$capitalized_name$() {\n"
|
||||
" return $name$_;\n"
|
||||
"}\n");
|
||||
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
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");
|
||||
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public Builder clear$capitalized_name$() {\n"
|
||||
" $clear_has_field_bit_builder$;\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_,
|
||||
" $on_changed$\n"
|
||||
" return this;\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void PrimitiveFieldGenerator::
|
||||
GenerateFieldBuilderInitializationCode(io::Printer* printer) const {
|
||||
// noop for primitives
|
||||
}
|
||||
|
||||
void PrimitiveFieldGenerator::
|
||||
GenerateInitializationCode(io::Printer* printer) const {
|
||||
printer->Print(variables_, "$name$_ = $default$;\n");
|
||||
}
|
||||
|
||||
void PrimitiveFieldGenerator::
|
||||
GenerateBuilderClearCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"$name$_ = $default$;\n"
|
||||
"$clear_has_field_bit_builder$;\n");
|
||||
}
|
||||
|
||||
void PrimitiveFieldGenerator::
|
||||
GenerateMergingCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"if (other.has$capitalized_name$()) {\n"
|
||||
" set$capitalized_name$(other.get$capitalized_name$());\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void PrimitiveFieldGenerator::
|
||||
GenerateBuildingCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"if ($get_has_field_bit_from_local$) {\n"
|
||||
" $set_has_field_bit_to_local$;\n"
|
||||
"}\n"
|
||||
"result.$name$_ = $name$_;\n");
|
||||
}
|
||||
|
||||
void PrimitiveFieldGenerator::
|
||||
GenerateParsingCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"$set_has_field_bit_message$;\n"
|
||||
"$name$_ = input.read$capitalized_type$();\n");
|
||||
}
|
||||
|
||||
void PrimitiveFieldGenerator::
|
||||
GenerateParsingDoneCode(io::Printer* printer) const {
|
||||
// noop for primitives.
|
||||
}
|
||||
|
||||
void PrimitiveFieldGenerator::
|
||||
GenerateSerializationCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"if ($get_has_field_bit_message$) {\n"
|
||||
" output.write$capitalized_type$($number$, $name$_);\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void PrimitiveFieldGenerator::
|
||||
GenerateSerializedSizeCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"if ($get_has_field_bit_message$) {\n"
|
||||
" size += com.google.protobuf.CodedOutputStream\n"
|
||||
" .compute$capitalized_type$Size($number$, $name$_);\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void PrimitiveFieldGenerator::
|
||||
GenerateEqualsCode(io::Printer* printer) const {
|
||||
switch (GetJavaType(descriptor_)) {
|
||||
case JAVATYPE_INT:
|
||||
case JAVATYPE_LONG:
|
||||
case JAVATYPE_BOOLEAN:
|
||||
printer->Print(variables_,
|
||||
"result = result && (get$capitalized_name$()\n"
|
||||
" == other.get$capitalized_name$());\n");
|
||||
break;
|
||||
|
||||
case JAVATYPE_FLOAT:
|
||||
printer->Print(variables_,
|
||||
"result = result && (Float.floatToIntBits(get$capitalized_name$())"
|
||||
" == Float.floatToIntBits(other.get$capitalized_name$()));\n");
|
||||
break;
|
||||
|
||||
case JAVATYPE_DOUBLE:
|
||||
printer->Print(variables_,
|
||||
"result = result && (Double.doubleToLongBits(get$capitalized_name$())"
|
||||
" == Double.doubleToLongBits(other.get$capitalized_name$()));\n");
|
||||
break;
|
||||
|
||||
case JAVATYPE_STRING:
|
||||
case JAVATYPE_BYTES:
|
||||
printer->Print(variables_,
|
||||
"result = result && get$capitalized_name$()\n"
|
||||
" .equals(other.get$capitalized_name$());\n");
|
||||
break;
|
||||
|
||||
case JAVATYPE_ENUM:
|
||||
case JAVATYPE_MESSAGE:
|
||||
default:
|
||||
GOOGLE_LOG(FATAL) << "Can't get here.";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void PrimitiveFieldGenerator::
|
||||
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) + hashLong(get$capitalized_name$());\n");
|
||||
break;
|
||||
|
||||
case JAVATYPE_BOOLEAN:
|
||||
printer->Print(variables_,
|
||||
"hash = (53 * hash) + hashBoolean(get$capitalized_name$());\n");
|
||||
break;
|
||||
|
||||
case JAVATYPE_FLOAT:
|
||||
printer->Print(variables_,
|
||||
"hash = (53 * hash) + Float.floatToIntBits(\n"
|
||||
" get$capitalized_name$());\n");
|
||||
break;
|
||||
|
||||
case JAVATYPE_DOUBLE:
|
||||
printer->Print(variables_,
|
||||
"hash = (53 * hash) + hashLong(\n"
|
||||
" 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;
|
||||
}
|
||||
}
|
||||
|
||||
string PrimitiveFieldGenerator::GetBoxedType() const {
|
||||
return BoxedPrimitiveTypeName(GetJavaType(descriptor_));
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
RepeatedPrimitiveFieldGenerator::
|
||||
RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor,
|
||||
int messageBitIndex,
|
||||
int builderBitIndex)
|
||||
: descriptor_(descriptor), messageBitIndex_(messageBitIndex),
|
||||
builderBitIndex_(builderBitIndex) {
|
||||
SetPrimitiveVariables(descriptor, messageBitIndex, builderBitIndex,
|
||||
&variables_);
|
||||
}
|
||||
|
||||
RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() {}
|
||||
|
||||
int RepeatedPrimitiveFieldGenerator::GetNumBitsForMessage() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int RepeatedPrimitiveFieldGenerator::GetNumBitsForBuilder() const {
|
||||
return 1;
|
||||
}
|
||||
|
||||
void RepeatedPrimitiveFieldGenerator::
|
||||
GenerateInterfaceMembers(io::Printer* printer) const {
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$java.util.List<$boxed_type$> get$capitalized_name$List();\n");
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$int get$capitalized_name$Count();\n");
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$$type$ get$capitalized_name$(int index);\n");
|
||||
}
|
||||
|
||||
|
||||
void RepeatedPrimitiveFieldGenerator::
|
||||
GenerateMembers(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"private $field_list_type$ $name$_;\n");
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public java.util.List<$boxed_type$>\n"
|
||||
" get$capitalized_name$List() {\n"
|
||||
" return $name$_;\n" // note: unmodifiable list
|
||||
"}\n");
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public int get$capitalized_name$Count() {\n"
|
||||
" return $name$_.size();\n"
|
||||
"}\n");
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public $type$ get$capitalized_name$(int index) {\n"
|
||||
" return $name$_.get(index);\n"
|
||||
"}\n");
|
||||
|
||||
if (descriptor_->options().packed() &&
|
||||
HasGeneratedMethods(descriptor_->containing_type())) {
|
||||
printer->Print(variables_,
|
||||
"private int $name$MemoizedSerializedSize = -1;\n");
|
||||
}
|
||||
}
|
||||
|
||||
void RepeatedPrimitiveFieldGenerator::
|
||||
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 refererence 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$_ = new java.util.ArrayList<$boxed_type$>($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.
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public java.util.List<$boxed_type$>\n"
|
||||
" get$capitalized_name$List() {\n"
|
||||
" return java.util.Collections.unmodifiableList($name$_);\n"
|
||||
"}\n");
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public int get$capitalized_name$Count() {\n"
|
||||
" return $name$_.size();\n"
|
||||
"}\n");
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public $type$ get$capitalized_name$(int index) {\n"
|
||||
" return $name$_.get(index);\n"
|
||||
"}\n");
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public Builder set$capitalized_name$(\n"
|
||||
" int index, $type$ value) {\n"
|
||||
"$null_check$"
|
||||
" ensure$capitalized_name$IsMutable();\n"
|
||||
" $name$_.set(index, value);\n"
|
||||
" $on_changed$\n"
|
||||
" return this;\n"
|
||||
"}\n");
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public Builder add$capitalized_name$($type$ value) {\n"
|
||||
"$null_check$"
|
||||
" ensure$capitalized_name$IsMutable();\n"
|
||||
" $name$_.add(value);\n"
|
||||
" $on_changed$\n"
|
||||
" return this;\n"
|
||||
"}\n");
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public Builder addAll$capitalized_name$(\n"
|
||||
" java.lang.Iterable<? extends $boxed_type$> values) {\n"
|
||||
" ensure$capitalized_name$IsMutable();\n"
|
||||
" super.addAll(values, $name$_);\n"
|
||||
" $on_changed$\n"
|
||||
" return this;\n"
|
||||
"}\n");
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
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");
|
||||
}
|
||||
|
||||
void RepeatedPrimitiveFieldGenerator::
|
||||
GenerateFieldBuilderInitializationCode(io::Printer* printer) const {
|
||||
// noop for primitives
|
||||
}
|
||||
|
||||
void RepeatedPrimitiveFieldGenerator::
|
||||
GenerateInitializationCode(io::Printer* printer) const {
|
||||
printer->Print(variables_, "$name$_ = $empty_list$;\n");
|
||||
}
|
||||
|
||||
void RepeatedPrimitiveFieldGenerator::
|
||||
GenerateBuilderClearCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"$name$_ = $empty_list$;\n"
|
||||
"$clear_mutable_bit_builder$;\n");
|
||||
}
|
||||
|
||||
void RepeatedPrimitiveFieldGenerator::
|
||||
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 RepeatedPrimitiveFieldGenerator::
|
||||
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 RepeatedPrimitiveFieldGenerator::
|
||||
GenerateParsingCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"if (!$get_mutable_bit_parser$) {\n"
|
||||
" $name$_ = new java.util.ArrayList<$boxed_type$>();\n"
|
||||
" $set_mutable_bit_parser$;\n"
|
||||
"}\n"
|
||||
"$name$_.add(input.read$capitalized_type$());\n");
|
||||
}
|
||||
|
||||
void RepeatedPrimitiveFieldGenerator::
|
||||
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$_ = new java.util.ArrayList<$boxed_type$>();\n"
|
||||
" $set_mutable_bit_parser$;\n"
|
||||
"}\n"
|
||||
"while (input.getBytesUntilLimit() > 0) {\n"
|
||||
" $name$_.add(input.read$capitalized_type$());\n"
|
||||
"}\n"
|
||||
"input.popLimit(limit);\n");
|
||||
}
|
||||
|
||||
void RepeatedPrimitiveFieldGenerator::
|
||||
GenerateParsingDoneCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"if ($get_mutable_bit_parser$) {\n"
|
||||
" $name$_ = java.util.Collections.unmodifiableList($name$_);\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void RepeatedPrimitiveFieldGenerator::
|
||||
GenerateSerializationCode(io::Printer* printer) const {
|
||||
if (descriptor_->options().packed()) {
|
||||
printer->Print(variables_,
|
||||
"if (get$capitalized_name$List().size() > 0) {\n"
|
||||
" output.writeRawVarint32($tag$);\n"
|
||||
" output.writeRawVarint32($name$MemoizedSerializedSize);\n"
|
||||
"}\n"
|
||||
"for (int i = 0; i < $name$_.size(); i++) {\n"
|
||||
" output.write$capitalized_type$NoTag($name$_.get(i));\n"
|
||||
"}\n");
|
||||
} else {
|
||||
printer->Print(variables_,
|
||||
"for (int i = 0; i < $name$_.size(); i++) {\n"
|
||||
" output.write$capitalized_type$($number$, $name$_.get(i));\n"
|
||||
"}\n");
|
||||
}
|
||||
}
|
||||
|
||||
void RepeatedPrimitiveFieldGenerator::
|
||||
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($name$_.get(i));\n"
|
||||
"}\n");
|
||||
} else {
|
||||
printer->Print(variables_,
|
||||
"dataSize = $fixed_size$ * get$capitalized_name$List().size();\n");
|
||||
}
|
||||
|
||||
printer->Print(
|
||||
"size += dataSize;\n");
|
||||
|
||||
if (descriptor_->options().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_->options().packed()) {
|
||||
printer->Print(variables_,
|
||||
"$name$MemoizedSerializedSize = dataSize;\n");
|
||||
}
|
||||
|
||||
printer->Outdent();
|
||||
printer->Print("}\n");
|
||||
}
|
||||
|
||||
void RepeatedPrimitiveFieldGenerator::
|
||||
GenerateEqualsCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"result = result && get$capitalized_name$List()\n"
|
||||
" .equals(other.get$capitalized_name$List());\n");
|
||||
}
|
||||
|
||||
void RepeatedPrimitiveFieldGenerator::
|
||||
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");
|
||||
}
|
||||
|
||||
string RepeatedPrimitiveFieldGenerator::GetBoxedType() const {
|
||||
return BoxedPrimitiveTypeName(GetJavaType(descriptor_));
|
||||
}
|
||||
|
||||
} // namespace java
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -46,49 +46,71 @@ namespace java {
|
||||
|
||||
class PrimitiveFieldGenerator : public FieldGenerator {
|
||||
public:
|
||||
explicit PrimitiveFieldGenerator(const FieldDescriptor* descriptor);
|
||||
explicit PrimitiveFieldGenerator(const FieldDescriptor* descriptor,
|
||||
int messageBitIndex, int builderBitIndex);
|
||||
~PrimitiveFieldGenerator();
|
||||
|
||||
// implements FieldGenerator ---------------------------------------
|
||||
int GetNumBitsForMessage() const;
|
||||
int GetNumBitsForBuilder() const;
|
||||
void GenerateInterfaceMembers(io::Printer* printer) const;
|
||||
void GenerateMembers(io::Printer* printer) const;
|
||||
void GenerateBuilderMembers(io::Printer* printer) const;
|
||||
void GenerateInitializationCode(io::Printer* printer) const;
|
||||
void GenerateBuilderClearCode(io::Printer* printer) const;
|
||||
void GenerateMergingCode(io::Printer* printer) const;
|
||||
void GenerateBuildingCode(io::Printer* printer) const;
|
||||
void GenerateParsingCode(io::Printer* printer) const;
|
||||
void GenerateParsingDoneCode(io::Printer* printer) const;
|
||||
void GenerateSerializationCode(io::Printer* printer) const;
|
||||
void GenerateSerializedSizeCode(io::Printer* printer) const;
|
||||
void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
|
||||
void GenerateEqualsCode(io::Printer* printer) const;
|
||||
void GenerateHashCode(io::Printer* printer) const;
|
||||
|
||||
string GetBoxedType() const;
|
||||
|
||||
private:
|
||||
const FieldDescriptor* descriptor_;
|
||||
map<string, string> variables_;
|
||||
const int messageBitIndex_;
|
||||
const int builderBitIndex_;
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PrimitiveFieldGenerator);
|
||||
};
|
||||
|
||||
class RepeatedPrimitiveFieldGenerator : public FieldGenerator {
|
||||
public:
|
||||
explicit RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor);
|
||||
explicit RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor,
|
||||
int messageBitIndex, int builderBitIndex);
|
||||
~RepeatedPrimitiveFieldGenerator();
|
||||
|
||||
// implements FieldGenerator ---------------------------------------
|
||||
int GetNumBitsForMessage() const;
|
||||
int GetNumBitsForBuilder() const;
|
||||
void GenerateInterfaceMembers(io::Printer* printer) const;
|
||||
void GenerateMembers(io::Printer* printer) const;
|
||||
void GenerateBuilderMembers(io::Printer* printer) const;
|
||||
void GenerateInitializationCode(io::Printer* printer) const;
|
||||
void GenerateBuilderClearCode(io::Printer* printer) const;
|
||||
void GenerateMergingCode(io::Printer* printer) const;
|
||||
void GenerateBuildingCode(io::Printer* printer) const;
|
||||
void GenerateParsingCode(io::Printer* printer) const;
|
||||
void GenerateParsingCodeFromPacked(io::Printer* printer) const;
|
||||
void GenerateParsingDoneCode(io::Printer* printer) const;
|
||||
void GenerateSerializationCode(io::Printer* printer) const;
|
||||
void GenerateSerializedSizeCode(io::Printer* printer) const;
|
||||
void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
|
||||
void GenerateEqualsCode(io::Printer* printer) const;
|
||||
void GenerateHashCode(io::Printer* printer) const;
|
||||
|
||||
string GetBoxedType() const;
|
||||
|
||||
private:
|
||||
const FieldDescriptor* descriptor_;
|
||||
map<string, string> variables_;
|
||||
const int messageBitIndex_;
|
||||
const int builderBitIndex_;
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedPrimitiveFieldGenerator);
|
||||
};
|
@ -33,6 +33,7 @@
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#include <google/protobuf/compiler/java/java_service.h>
|
||||
#include <google/protobuf/compiler/java/java_doc_comment.h>
|
||||
#include <google/protobuf/compiler/java/java_helpers.h>
|
||||
#include <google/protobuf/io/printer.h>
|
||||
#include <google/protobuf/descriptor.pb.h>
|
||||
@ -50,6 +51,7 @@ ServiceGenerator::~ServiceGenerator() {}
|
||||
|
||||
void ServiceGenerator::Generate(io::Printer* printer) {
|
||||
bool is_own_file = descriptor_->file()->options().java_multiple_files();
|
||||
WriteServiceDocComment(printer, descriptor_);
|
||||
printer->Print(
|
||||
"public $static$ abstract class $classname$\n"
|
||||
" implements com.google.protobuf.Service {\n",
|
||||
@ -86,6 +88,12 @@ void ServiceGenerator::Generate(io::Printer* 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");
|
||||
}
|
||||
@ -118,7 +126,7 @@ void ServiceGenerator::GenerateNewReflectiveServiceMethod(
|
||||
|
||||
for (int i = 0; i < descriptor_->method_count(); i++) {
|
||||
const MethodDescriptor* method = descriptor_->method(i);
|
||||
printer->Print("@Override\n");
|
||||
printer->Print("@java.lang.Override\n");
|
||||
GenerateMethodSignature(printer, method, IS_CONCRETE);
|
||||
printer->Print(
|
||||
" {\n"
|
||||
@ -157,6 +165,7 @@ void ServiceGenerator::GenerateNewReflectiveBlockingServiceMethod(
|
||||
void ServiceGenerator::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");
|
||||
}
|
@ -0,0 +1,726 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// 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 <map>
|
||||
#include <string>
|
||||
|
||||
#include <google/protobuf/compiler/java/java_string_field.h>
|
||||
#include <google/protobuf/compiler/java/java_doc_comment.h>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/compiler/java/java_helpers.h>
|
||||
#include <google/protobuf/io/printer.h>
|
||||
#include <google/protobuf/wire_format.h>
|
||||
#include <google/protobuf/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,
|
||||
map<string, string>* variables) {
|
||||
(*variables)["name"] =
|
||||
UnderscoresToCamelCase(descriptor);
|
||||
(*variables)["capitalized_name"] =
|
||||
UnderscoresToCapitalizedCamelCase(descriptor);
|
||||
(*variables)["constant_name"] = FieldConstantName(descriptor);
|
||||
(*variables)["number"] = SimpleItoa(descriptor->number());
|
||||
(*variables)["empty_list"] = "com.google.protobuf.LazyStringArrayList.EMPTY";
|
||||
|
||||
(*variables)["default"] = DefaultValue(descriptor);
|
||||
(*variables)["default_init"] = ("= " + DefaultValue(descriptor));
|
||||
(*variables)["capitalized_type"] = "String";
|
||||
(*variables)["tag"] = SimpleItoa(WireFormat::MakeTag(descriptor));
|
||||
(*variables)["tag_size"] = SimpleItoa(
|
||||
WireFormat::TagSize(descriptor->number(), GetType(descriptor)));
|
||||
(*variables)["null_check"] =
|
||||
" if (value == null) {\n"
|
||||
" throw new NullPointerException();\n"
|
||||
" }\n";
|
||||
|
||||
// TODO(birdo): Add @deprecated javadoc when generating javadoc is supported
|
||||
// by the proto compiler
|
||||
(*variables)["deprecation"] = descriptor->options().deprecated()
|
||||
? "@java.lang.Deprecated " : "";
|
||||
(*variables)["on_changed"] =
|
||||
HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : "";
|
||||
|
||||
// For singular messages and builders, one bit is used for the hasField bit.
|
||||
(*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex);
|
||||
(*variables)["set_has_field_bit_message"] = GenerateSetBit(messageBitIndex);
|
||||
|
||||
(*variables)["get_has_field_bit_builder"] = GenerateGetBit(builderBitIndex);
|
||||
(*variables)["set_has_field_bit_builder"] = GenerateSetBit(builderBitIndex);
|
||||
(*variables)["clear_has_field_bit_builder"] =
|
||||
GenerateClearBit(builderBitIndex);
|
||||
|
||||
// For repated 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
|
||||
|
||||
// ===================================================================
|
||||
|
||||
StringFieldGenerator::
|
||||
StringFieldGenerator(const FieldDescriptor* descriptor,
|
||||
int messageBitIndex,
|
||||
int builderBitIndex)
|
||||
: descriptor_(descriptor), messageBitIndex_(messageBitIndex),
|
||||
builderBitIndex_(builderBitIndex) {
|
||||
SetPrimitiveVariables(descriptor, messageBitIndex, builderBitIndex,
|
||||
&variables_);
|
||||
}
|
||||
|
||||
StringFieldGenerator::~StringFieldGenerator() {}
|
||||
|
||||
int StringFieldGenerator::GetNumBitsForMessage() const {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int StringFieldGenerator::GetNumBitsForBuilder() const {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 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 vaid 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 StringFieldGenerator::
|
||||
GenerateInterfaceMembers(io::Printer* printer) const {
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$boolean has$capitalized_name$();\n");
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$java.lang.String get$capitalized_name$();\n");
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$com.google.protobuf.ByteString\n"
|
||||
" get$capitalized_name$Bytes();\n");
|
||||
}
|
||||
|
||||
void StringFieldGenerator::
|
||||
GenerateMembers(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"private java.lang.Object $name$_;\n");
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public boolean has$capitalized_name$() {\n"
|
||||
" return $get_has_field_bit_message$;\n"
|
||||
"}\n");
|
||||
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
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"
|
||||
" 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"
|
||||
" if (bs.isValidUtf8()) {\n"
|
||||
" $name$_ = s;\n"
|
||||
" }\n"
|
||||
" return s;\n"
|
||||
" }\n"
|
||||
"}\n");
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$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");
|
||||
}
|
||||
|
||||
void StringFieldGenerator::
|
||||
GenerateBuilderMembers(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"private java.lang.Object $name$_ $default_init$;\n");
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public boolean has$capitalized_name$() {\n"
|
||||
" return $get_has_field_bit_builder$;\n"
|
||||
"}\n");
|
||||
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
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"
|
||||
" java.lang.String s = ((com.google.protobuf.ByteString) ref)\n"
|
||||
" .toStringUtf8();\n"
|
||||
" $name$_ = s;\n"
|
||||
" return s;\n"
|
||||
" } else {\n"
|
||||
" return (java.lang.String) ref;\n"
|
||||
" }\n"
|
||||
"}\n");
|
||||
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
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");
|
||||
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
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");
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public Builder clear$capitalized_name$() {\n"
|
||||
" $clear_has_field_bit_builder$;\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.
|
||||
printer->Print(variables_,
|
||||
" $name$_ = getDefaultInstance().get$capitalized_name$();\n");
|
||||
printer->Print(variables_,
|
||||
" $on_changed$\n"
|
||||
" return this;\n"
|
||||
"}\n");
|
||||
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public Builder set$capitalized_name$Bytes(\n"
|
||||
" com.google.protobuf.ByteString value) {\n"
|
||||
"$null_check$"
|
||||
" $set_has_field_bit_builder$;\n"
|
||||
" $name$_ = value;\n"
|
||||
" $on_changed$\n"
|
||||
" return this;\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void StringFieldGenerator::
|
||||
GenerateFieldBuilderInitializationCode(io::Printer* printer) const {
|
||||
// noop for primitives
|
||||
}
|
||||
|
||||
void StringFieldGenerator::
|
||||
GenerateInitializationCode(io::Printer* printer) const {
|
||||
printer->Print(variables_, "$name$_ = $default$;\n");
|
||||
}
|
||||
|
||||
void StringFieldGenerator::
|
||||
GenerateBuilderClearCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"$name$_ = $default$;\n"
|
||||
"$clear_has_field_bit_builder$;\n");
|
||||
}
|
||||
|
||||
void StringFieldGenerator::
|
||||
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_,
|
||||
"if (other.has$capitalized_name$()) {\n"
|
||||
" $set_has_field_bit_builder$;\n"
|
||||
" $name$_ = other.$name$_;\n"
|
||||
" $on_changed$\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void StringFieldGenerator::
|
||||
GenerateBuildingCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"if ($get_has_field_bit_from_local$) {\n"
|
||||
" $set_has_field_bit_to_local$;\n"
|
||||
"}\n"
|
||||
"result.$name$_ = $name$_;\n");
|
||||
}
|
||||
|
||||
void StringFieldGenerator::
|
||||
GenerateParsingCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"$set_has_field_bit_message$;\n"
|
||||
"$name$_ = input.readBytes();\n");
|
||||
}
|
||||
|
||||
void StringFieldGenerator::
|
||||
GenerateParsingDoneCode(io::Printer* printer) const {
|
||||
// noop for strings.
|
||||
}
|
||||
|
||||
void StringFieldGenerator::
|
||||
GenerateSerializationCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"if ($get_has_field_bit_message$) {\n"
|
||||
" output.writeBytes($number$, get$capitalized_name$Bytes());\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void StringFieldGenerator::
|
||||
GenerateSerializedSizeCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"if ($get_has_field_bit_message$) {\n"
|
||||
" size += com.google.protobuf.CodedOutputStream\n"
|
||||
" .computeBytesSize($number$, get$capitalized_name$Bytes());\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void StringFieldGenerator::
|
||||
GenerateEqualsCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"result = result && get$capitalized_name$()\n"
|
||||
" .equals(other.get$capitalized_name$());\n");
|
||||
}
|
||||
|
||||
void StringFieldGenerator::
|
||||
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");
|
||||
}
|
||||
|
||||
string StringFieldGenerator::GetBoxedType() const {
|
||||
return "java.lang.String";
|
||||
}
|
||||
|
||||
|
||||
// ===================================================================
|
||||
|
||||
RepeatedStringFieldGenerator::
|
||||
RepeatedStringFieldGenerator(const FieldDescriptor* descriptor,
|
||||
int messageBitIndex,
|
||||
int builderBitIndex)
|
||||
: descriptor_(descriptor), messageBitIndex_(messageBitIndex),
|
||||
builderBitIndex_(builderBitIndex) {
|
||||
SetPrimitiveVariables(descriptor, messageBitIndex, builderBitIndex,
|
||||
&variables_);
|
||||
}
|
||||
|
||||
RepeatedStringFieldGenerator::~RepeatedStringFieldGenerator() {}
|
||||
|
||||
int RepeatedStringFieldGenerator::GetNumBitsForMessage() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int RepeatedStringFieldGenerator::GetNumBitsForBuilder() const {
|
||||
return 1;
|
||||
}
|
||||
|
||||
void RepeatedStringFieldGenerator::
|
||||
GenerateInterfaceMembers(io::Printer* printer) const {
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$java.util.List<java.lang.String>\n"
|
||||
"get$capitalized_name$List();\n");
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$int get$capitalized_name$Count();\n");
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$java.lang.String get$capitalized_name$(int index);\n");
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$com.google.protobuf.ByteString\n"
|
||||
" get$capitalized_name$Bytes(int index);\n");
|
||||
}
|
||||
|
||||
|
||||
void RepeatedStringFieldGenerator::
|
||||
GenerateMembers(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"private com.google.protobuf.LazyStringList $name$_;\n");
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public java.util.List<java.lang.String>\n"
|
||||
" get$capitalized_name$List() {\n"
|
||||
" return $name$_;\n" // note: unmodifiable list
|
||||
"}\n");
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public int get$capitalized_name$Count() {\n"
|
||||
" return $name$_.size();\n"
|
||||
"}\n");
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public java.lang.String get$capitalized_name$(int index) {\n"
|
||||
" return $name$_.get(index);\n"
|
||||
"}\n");
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public com.google.protobuf.ByteString\n"
|
||||
" get$capitalized_name$Bytes(int index) {\n"
|
||||
" return $name$_.getByteString(index);\n"
|
||||
"}\n");
|
||||
|
||||
if (descriptor_->options().packed() &&
|
||||
HasGeneratedMethods(descriptor_->containing_type())) {
|
||||
printer->Print(variables_,
|
||||
"private int $name$MemoizedSerializedSize = -1;\n");
|
||||
}
|
||||
}
|
||||
|
||||
void RepeatedStringFieldGenerator::
|
||||
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 refererence 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.
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public java.util.List<java.lang.String>\n"
|
||||
" get$capitalized_name$List() {\n"
|
||||
" return java.util.Collections.unmodifiableList($name$_);\n"
|
||||
"}\n");
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public int get$capitalized_name$Count() {\n"
|
||||
" return $name$_.size();\n"
|
||||
"}\n");
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public java.lang.String get$capitalized_name$(int index) {\n"
|
||||
" return $name$_.get(index);\n"
|
||||
"}\n");
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public com.google.protobuf.ByteString\n"
|
||||
" get$capitalized_name$Bytes(int index) {\n"
|
||||
" return $name$_.getByteString(index);\n"
|
||||
"}\n");
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
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");
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
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");
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public Builder addAll$capitalized_name$(\n"
|
||||
" java.lang.Iterable<java.lang.String> values) {\n"
|
||||
" ensure$capitalized_name$IsMutable();\n"
|
||||
" super.addAll(values, $name$_);\n"
|
||||
" $on_changed$\n"
|
||||
" return this;\n"
|
||||
"}\n");
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
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");
|
||||
|
||||
WriteFieldDocComment(printer, descriptor_);
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public Builder add$capitalized_name$Bytes(\n"
|
||||
" com.google.protobuf.ByteString value) {\n"
|
||||
"$null_check$"
|
||||
" ensure$capitalized_name$IsMutable();\n"
|
||||
" $name$_.add(value);\n"
|
||||
" $on_changed$\n"
|
||||
" return this;\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void RepeatedStringFieldGenerator::
|
||||
GenerateFieldBuilderInitializationCode(io::Printer* printer) const {
|
||||
// noop for primitives
|
||||
}
|
||||
|
||||
void RepeatedStringFieldGenerator::
|
||||
GenerateInitializationCode(io::Printer* printer) const {
|
||||
printer->Print(variables_, "$name$_ = $empty_list$;\n");
|
||||
}
|
||||
|
||||
void RepeatedStringFieldGenerator::
|
||||
GenerateBuilderClearCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"$name$_ = $empty_list$;\n"
|
||||
"$clear_mutable_bit_builder$;\n");
|
||||
}
|
||||
|
||||
void RepeatedStringFieldGenerator::
|
||||
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 RepeatedStringFieldGenerator::
|
||||
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$_ = new com.google.protobuf.UnmodifiableLazyStringList(\n"
|
||||
" $name$_);\n"
|
||||
" $clear_mutable_bit_builder$;\n"
|
||||
"}\n"
|
||||
"result.$name$_ = $name$_;\n");
|
||||
}
|
||||
|
||||
void RepeatedStringFieldGenerator::
|
||||
GenerateParsingCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"if (!$get_mutable_bit_parser$) {\n"
|
||||
" $name$_ = new com.google.protobuf.LazyStringArrayList();\n"
|
||||
" $set_mutable_bit_parser$;\n"
|
||||
"}\n"
|
||||
"$name$_.add(input.readBytes());\n");
|
||||
}
|
||||
|
||||
void RepeatedStringFieldGenerator::
|
||||
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$_ = new com.google.protobuf.LazyStringArrayList();\n"
|
||||
" $set_mutable_bit_parser$;\n"
|
||||
"}\n"
|
||||
"while (input.getBytesUntilLimit() > 0) {\n"
|
||||
" $name$.add(input.read$capitalized_type$());\n"
|
||||
"}\n"
|
||||
"input.popLimit(limit);\n");
|
||||
}
|
||||
|
||||
void RepeatedStringFieldGenerator::
|
||||
GenerateParsingDoneCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"if ($get_mutable_bit_parser$) {\n"
|
||||
" $name$_ = new com.google.protobuf.UnmodifiableLazyStringList($name$_);\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void RepeatedStringFieldGenerator::
|
||||
GenerateSerializationCode(io::Printer* printer) const {
|
||||
if (descriptor_->options().packed()) {
|
||||
printer->Print(variables_,
|
||||
"if (get$capitalized_name$List().size() > 0) {\n"
|
||||
" output.writeRawVarint32($tag$);\n"
|
||||
" output.writeRawVarint32($name$MemoizedSerializedSize);\n"
|
||||
"}\n"
|
||||
"for (int i = 0; i < $name$_.size(); i++) {\n"
|
||||
" output.write$capitalized_type$NoTag($name$_.get(i));\n"
|
||||
"}\n");
|
||||
} else {
|
||||
printer->Print(variables_,
|
||||
"for (int i = 0; i < $name$_.size(); i++) {\n"
|
||||
" output.writeBytes($number$, $name$_.getByteString(i));\n"
|
||||
"}\n");
|
||||
}
|
||||
}
|
||||
|
||||
void RepeatedStringFieldGenerator::
|
||||
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"
|
||||
" .computeBytesSizeNoTag($name$_.getByteString(i));\n"
|
||||
"}\n");
|
||||
|
||||
printer->Print(
|
||||
"size += dataSize;\n");
|
||||
|
||||
if (descriptor_->options().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_->options().packed()) {
|
||||
printer->Print(variables_,
|
||||
"$name$MemoizedSerializedSize = dataSize;\n");
|
||||
}
|
||||
|
||||
printer->Outdent();
|
||||
printer->Print("}\n");
|
||||
}
|
||||
|
||||
void RepeatedStringFieldGenerator::
|
||||
GenerateEqualsCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"result = result && get$capitalized_name$List()\n"
|
||||
" .equals(other.get$capitalized_name$List());\n");
|
||||
}
|
||||
|
||||
void RepeatedStringFieldGenerator::
|
||||
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");
|
||||
}
|
||||
|
||||
string RepeatedStringFieldGenerator::GetBoxedType() const {
|
||||
return "String";
|
||||
}
|
||||
|
||||
} // namespace java
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,122 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// 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 <google/protobuf/compiler/java/java_field.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace java {
|
||||
|
||||
class StringFieldGenerator : public FieldGenerator {
|
||||
public:
|
||||
explicit StringFieldGenerator(const FieldDescriptor* descriptor,
|
||||
int messageBitIndex, int builderBitIndex);
|
||||
~StringFieldGenerator();
|
||||
|
||||
// implements FieldGenerator ---------------------------------------
|
||||
int GetNumBitsForMessage() const;
|
||||
int GetNumBitsForBuilder() const;
|
||||
void GenerateInterfaceMembers(io::Printer* printer) const;
|
||||
void GenerateMembers(io::Printer* printer) const;
|
||||
void GenerateBuilderMembers(io::Printer* printer) const;
|
||||
void GenerateInitializationCode(io::Printer* printer) const;
|
||||
void GenerateBuilderClearCode(io::Printer* printer) const;
|
||||
void GenerateMergingCode(io::Printer* printer) const;
|
||||
void GenerateBuildingCode(io::Printer* printer) const;
|
||||
void GenerateParsingCode(io::Printer* printer) const;
|
||||
void GenerateParsingDoneCode(io::Printer* printer) const;
|
||||
void GenerateSerializationCode(io::Printer* printer) const;
|
||||
void GenerateSerializedSizeCode(io::Printer* printer) const;
|
||||
void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
|
||||
void GenerateEqualsCode(io::Printer* printer) const;
|
||||
void GenerateHashCode(io::Printer* printer) const;
|
||||
string GetBoxedType() const;
|
||||
|
||||
private:
|
||||
const FieldDescriptor* descriptor_;
|
||||
map<string, string> variables_;
|
||||
const int messageBitIndex_;
|
||||
const int builderBitIndex_;
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StringFieldGenerator);
|
||||
};
|
||||
|
||||
class RepeatedStringFieldGenerator : public FieldGenerator {
|
||||
public:
|
||||
explicit RepeatedStringFieldGenerator(const FieldDescriptor* descriptor,
|
||||
int messageBitIndex, int builderBitIndex);
|
||||
~RepeatedStringFieldGenerator();
|
||||
|
||||
// implements FieldGenerator ---------------------------------------
|
||||
int GetNumBitsForMessage() const;
|
||||
int GetNumBitsForBuilder() const;
|
||||
void GenerateInterfaceMembers(io::Printer* printer) const;
|
||||
void GenerateMembers(io::Printer* printer) const;
|
||||
void GenerateBuilderMembers(io::Printer* printer) const;
|
||||
void GenerateInitializationCode(io::Printer* printer) const;
|
||||
void GenerateBuilderClearCode(io::Printer* printer) const;
|
||||
void GenerateMergingCode(io::Printer* printer) const;
|
||||
void GenerateBuildingCode(io::Printer* printer) const;
|
||||
void GenerateParsingCode(io::Printer* printer) const;
|
||||
void GenerateParsingCodeFromPacked(io::Printer* printer) const;
|
||||
void GenerateParsingDoneCode(io::Printer* printer) const;
|
||||
void GenerateSerializationCode(io::Printer* printer) const;
|
||||
void GenerateSerializedSizeCode(io::Printer* printer) const;
|
||||
void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
|
||||
void GenerateEqualsCode(io::Printer* printer) const;
|
||||
void GenerateHashCode(io::Printer* printer) const;
|
||||
string GetBoxedType() const;
|
||||
|
||||
private:
|
||||
const FieldDescriptor* descriptor_;
|
||||
map<string, string> variables_;
|
||||
const int messageBitIndex_;
|
||||
const int builderBitIndex_;
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedStringFieldGenerator);
|
||||
};
|
||||
|
||||
} // namespace java
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_STRING_FIELD_H__
|
@ -43,7 +43,7 @@ int main(int argc, char* argv[]) {
|
||||
|
||||
// Proto2 C++
|
||||
google::protobuf::compiler::cpp::CppGenerator cpp_generator;
|
||||
cli.RegisterGenerator("--cpp_out", &cpp_generator,
|
||||
cli.RegisterGenerator("--cpp_out", "--cpp_opt", &cpp_generator,
|
||||
"Generate C++ header and source.");
|
||||
|
||||
// Proto2 Java
|
@ -33,18 +33,29 @@
|
||||
#include <google/protobuf/compiler/mock_code_generator.h>
|
||||
|
||||
#include <google/protobuf/testing/file.h>
|
||||
#include <google/protobuf/descriptor.pb.h>
|
||||
#include <google/protobuf/descriptor.h>
|
||||
#include <google/protobuf/io/zero_copy_stream.h>
|
||||
#include <google/protobuf/io/printer.h>
|
||||
#include <google/protobuf/stubs/strutil.h>
|
||||
#include <google/protobuf/stubs/substitute.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <google/protobuf/stubs/stl_util-inl.h>
|
||||
#include <google/protobuf/stubs/stl_util.h>
|
||||
|
||||
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.
|
||||
string CommaSeparatedList(const vector<const FileDescriptor*> all_files) {
|
||||
vector<string> names;
|
||||
for (int i = 0; i < all_files.size(); i++) {
|
||||
names.push_back(all_files[i]->name());
|
||||
}
|
||||
return JoinStrings(names, ",");
|
||||
}
|
||||
|
||||
static const char* kFirstInsertionPointName = "first_mock_insertion_point";
|
||||
static const char* kSecondInsertionPointName = "second_mock_insertion_point";
|
||||
static const char* kFirstInsertionPoint =
|
||||
@ -63,6 +74,7 @@ void MockCodeGenerator::ExpectGenerated(
|
||||
const string& insertions,
|
||||
const string& file,
|
||||
const string& first_message_name,
|
||||
const string& first_parsed_file_name,
|
||||
const string& output_directory) {
|
||||
string content;
|
||||
ASSERT_TRUE(File::ReadFileToString(
|
||||
@ -84,7 +96,8 @@ void MockCodeGenerator::ExpectGenerated(
|
||||
}
|
||||
|
||||
ASSERT_EQ(lines.size(), 3 + insertion_list.size() * 2);
|
||||
EXPECT_EQ(GetOutputFileContent(name, parameter, file, first_message_name),
|
||||
EXPECT_EQ(GetOutputFileContent(name, parameter, file,
|
||||
first_parsed_file_name, first_message_name),
|
||||
lines[0]);
|
||||
|
||||
EXPECT_EQ(kFirstInsertionPoint, lines[1 + insertion_list.size()]);
|
||||
@ -92,12 +105,12 @@ void MockCodeGenerator::ExpectGenerated(
|
||||
|
||||
for (int i = 0; i < insertion_list.size(); i++) {
|
||||
EXPECT_EQ(GetOutputFileContent(insertion_list[i], "first_insert",
|
||||
file, first_message_name),
|
||||
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, first_message_name),
|
||||
file, file, first_message_name),
|
||||
lines[2 + insertion_list.size() + i]);
|
||||
}
|
||||
}
|
||||
@ -105,7 +118,7 @@ void MockCodeGenerator::ExpectGenerated(
|
||||
bool MockCodeGenerator::Generate(
|
||||
const FileDescriptor* file,
|
||||
const string& parameter,
|
||||
OutputDirectory* output_directory,
|
||||
GeneratorContext* context,
|
||||
string* error) const {
|
||||
for (int i = 0; i < file->message_type_count(); i++) {
|
||||
if (HasPrefixString(file->message_type(i)->name(), "MockCodeGenerator_")) {
|
||||
@ -120,6 +133,15 @@ bool MockCodeGenerator::Generate(
|
||||
} else if (command == "Abort") {
|
||||
cerr << "Saw message type MockCodeGenerator_Abort." << 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;
|
||||
cerr << "Saw message type MockCodeGenerator_HasSourceCodeInfo: "
|
||||
<< has_source_code_info << "." << endl;
|
||||
abort();
|
||||
} else {
|
||||
GOOGLE_LOG(FATAL) << "Unknown MockCodeGenerator command: " << command;
|
||||
}
|
||||
@ -134,11 +156,12 @@ bool MockCodeGenerator::Generate(
|
||||
for (int i = 0; i < insert_into.size(); i++) {
|
||||
{
|
||||
scoped_ptr<io::ZeroCopyOutputStream> output(
|
||||
output_directory->OpenForInsert(
|
||||
context->OpenForInsert(
|
||||
GetOutputFileName(insert_into[i], file),
|
||||
kFirstInsertionPointName));
|
||||
io::Printer printer(output.get(), '$');
|
||||
printer.PrintRaw(GetOutputFileContent(name_, "first_insert", file));
|
||||
printer.PrintRaw(GetOutputFileContent(name_, "first_insert",
|
||||
file, context));
|
||||
if (printer.failed()) {
|
||||
*error = "MockCodeGenerator detected write error.";
|
||||
return false;
|
||||
@ -147,11 +170,12 @@ bool MockCodeGenerator::Generate(
|
||||
|
||||
{
|
||||
scoped_ptr<io::ZeroCopyOutputStream> output(
|
||||
output_directory->OpenForInsert(
|
||||
context->OpenForInsert(
|
||||
GetOutputFileName(insert_into[i], file),
|
||||
kSecondInsertionPointName));
|
||||
io::Printer printer(output.get(), '$');
|
||||
printer.PrintRaw(GetOutputFileContent(name_, "second_insert", file));
|
||||
printer.PrintRaw(GetOutputFileContent(name_, "second_insert",
|
||||
file, context));
|
||||
if (printer.failed()) {
|
||||
*error = "MockCodeGenerator detected write error.";
|
||||
return false;
|
||||
@ -160,10 +184,11 @@ bool MockCodeGenerator::Generate(
|
||||
}
|
||||
} else {
|
||||
scoped_ptr<io::ZeroCopyOutputStream> output(
|
||||
output_directory->Open(GetOutputFileName(name_, file)));
|
||||
context->Open(GetOutputFileName(name_, file)));
|
||||
|
||||
io::Printer printer(output.get(), '$');
|
||||
printer.PrintRaw(GetOutputFileContent(name_, parameter, file));
|
||||
printer.PrintRaw(GetOutputFileContent(name_, parameter,
|
||||
file, context));
|
||||
printer.PrintRaw(kFirstInsertionPoint);
|
||||
printer.PrintRaw(kSecondInsertionPoint);
|
||||
|
||||
@ -186,11 +211,16 @@ string MockCodeGenerator::GetOutputFileName(const string& generator_name,
|
||||
return file + ".MockCodeGenerator." + generator_name;
|
||||
}
|
||||
|
||||
string MockCodeGenerator::GetOutputFileContent(const string& generator_name,
|
||||
const string& parameter,
|
||||
const FileDescriptor* file) {
|
||||
string MockCodeGenerator::GetOutputFileContent(
|
||||
const string& generator_name,
|
||||
const string& parameter,
|
||||
const FileDescriptor* file,
|
||||
GeneratorContext *context) {
|
||||
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)");
|
||||
}
|
||||
@ -199,9 +229,11 @@ string MockCodeGenerator::GetOutputFileContent(
|
||||
const string& generator_name,
|
||||
const string& parameter,
|
||||
const string& file,
|
||||
const string& parsed_file_list,
|
||||
const string& first_message_name) {
|
||||
return strings::Substitute("$0: $1, $2, $3\n",
|
||||
generator_name, parameter, file, first_message_name);
|
||||
return strings::Substitute("$0: $1, $2, $3, $4\n",
|
||||
generator_name, parameter, file,
|
||||
first_message_name, parsed_file_list);
|
||||
}
|
||||
|
||||
} // namespace compiler
|
@ -59,6 +59,10 @@ namespace compiler {
|
||||
// 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.
|
||||
class MockCodeGenerator : public CodeGenerator {
|
||||
public:
|
||||
MockCodeGenerator(const string& name);
|
||||
@ -69,11 +73,14 @@ class MockCodeGenerator : public CodeGenerator {
|
||||
//
|
||||
// |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 string& name,
|
||||
const string& parameter,
|
||||
const string& insertions,
|
||||
const string& file,
|
||||
const string& first_message_name,
|
||||
const string& parsed_file_list,
|
||||
const string& output_directory);
|
||||
|
||||
// Get the name of the file which would be written by the given generator.
|
||||
@ -86,7 +93,7 @@ class MockCodeGenerator : public CodeGenerator {
|
||||
|
||||
virtual bool Generate(const FileDescriptor* file,
|
||||
const string& parameter,
|
||||
OutputDirectory* output_directory,
|
||||
GeneratorContext* context,
|
||||
string* error) const;
|
||||
|
||||
private:
|
||||
@ -94,10 +101,12 @@ class MockCodeGenerator : public CodeGenerator {
|
||||
|
||||
static string GetOutputFileContent(const string& generator_name,
|
||||
const string& parameter,
|
||||
const FileDescriptor* file);
|
||||
const FileDescriptor* file,
|
||||
GeneratorContext *context);
|
||||
static string GetOutputFileContent(const string& generator_name,
|
||||
const string& parameter,
|
||||
const string& file,
|
||||
const string& parsed_file_list,
|
||||
const string& first_message_name);
|
||||
};
|
||||
|
1611
common/protobuf-2.5.0/src/google/protobuf/compiler/parser.cc
Normal file
1611
common/protobuf-2.5.0/src/google/protobuf/compiler/parser.cc
Normal file
File diff suppressed because it is too large
Load Diff
@ -74,6 +74,9 @@ class LIBPROTOBUF_EXPORT Parser {
|
||||
|
||||
// Optional fetaures:
|
||||
|
||||
// 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.
|
||||
@ -82,7 +85,7 @@ class LIBPROTOBUF_EXPORT Parser {
|
||||
source_location_table_ = location_table;
|
||||
}
|
||||
|
||||
// Requsets that errors be recorded to the given ErrorCollector while
|
||||
// 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;
|
||||
@ -113,6 +116,8 @@ class LIBPROTOBUF_EXPORT Parser {
|
||||
}
|
||||
|
||||
private:
|
||||
class LocationRecorder;
|
||||
|
||||
// =================================================================
|
||||
// Error recovery helpers
|
||||
|
||||
@ -161,6 +166,8 @@ class LIBPROTOBUF_EXPORT Parser {
|
||||
bool ConsumeIdentifier(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 max_value, uint64* output, const char* error);
|
||||
@ -170,6 +177,20 @@ class LIBPROTOBUF_EXPORT Parser {
|
||||
// Consume a string literal and store its (unescaped) value in "output".
|
||||
bool ConsumeString(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 ConsumeEndOfDeclaration(const char* text,
|
||||
const LocationRecorder* location);
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// Error logging helpers
|
||||
|
||||
@ -180,16 +201,64 @@ class LIBPROTOBUF_EXPORT Parser {
|
||||
// of the current token.
|
||||
void AddError(const string& error);
|
||||
|
||||
// Record the given line and column and associate it with this descriptor
|
||||
// in the SourceLocationTable.
|
||||
void RecordLocation(const Message* descriptor,
|
||||
DescriptorPool::ErrorCollector::ErrorLocation location,
|
||||
int line, int column);
|
||||
// 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 LIBPROTOBUF_EXPORT LocationRecorder {
|
||||
public:
|
||||
// Construct the file's "root" location.
|
||||
LocationRecorder(Parser* parser);
|
||||
|
||||
// Record the current line and column and associate it with this descriptor
|
||||
// in the SourceLocationTable.
|
||||
void RecordLocation(const Message* descriptor,
|
||||
DescriptorPool::ErrorCollector::ErrorLocation location);
|
||||
// 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);
|
||||
|
||||
~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);
|
||||
|
||||
// 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);
|
||||
|
||||
// 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(string* leading, string* trailing) const;
|
||||
|
||||
private:
|
||||
Parser* parser_;
|
||||
SourceCodeInfo::Location* location_;
|
||||
|
||||
void Init(const LocationRecorder& parent);
|
||||
};
|
||||
|
||||
// =================================================================
|
||||
// Parsers for various language constructs
|
||||
@ -210,50 +279,88 @@ class LIBPROTOBUF_EXPORT Parser {
|
||||
// makes logic much simpler for the caller.
|
||||
|
||||
// Parse a top-level message, enum, service, etc.
|
||||
bool ParseTopLevelStatement(FileDescriptorProto* file);
|
||||
bool ParseTopLevelStatement(FileDescriptorProto* file,
|
||||
const LocationRecorder& root_location);
|
||||
|
||||
// Parse various language high-level language construrcts.
|
||||
bool ParseMessageDefinition(DescriptorProto* message);
|
||||
bool ParseEnumDefinition(EnumDescriptorProto* enum_type);
|
||||
bool ParseServiceDefinition(ServiceDescriptorProto* service);
|
||||
bool ParsePackage(FileDescriptorProto* file);
|
||||
bool ParseImport(string* import_filename);
|
||||
bool ParseOption(Message* options);
|
||||
bool ParseMessageDefinition(DescriptorProto* message,
|
||||
const LocationRecorder& message_location);
|
||||
bool ParseEnumDefinition(EnumDescriptorProto* enum_type,
|
||||
const LocationRecorder& enum_location);
|
||||
bool ParseServiceDefinition(ServiceDescriptorProto* service,
|
||||
const LocationRecorder& service_location);
|
||||
bool ParsePackage(FileDescriptorProto* file,
|
||||
const LocationRecorder& root_location);
|
||||
bool ParseImport(RepeatedPtrField<string>* dependency,
|
||||
RepeatedField<int32>* public_dependency,
|
||||
RepeatedField<int32>* weak_dependency,
|
||||
const LocationRecorder& root_location);
|
||||
bool ParseOption(Message* options,
|
||||
const LocationRecorder& options_location);
|
||||
|
||||
// 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);
|
||||
bool ParseEnumBlock(EnumDescriptorProto* enum_type);
|
||||
bool ParseServiceBlock(ServiceDescriptorProto* service);
|
||||
bool ParseMessageBlock(DescriptorProto* message,
|
||||
const LocationRecorder& message_location);
|
||||
bool ParseEnumBlock(EnumDescriptorProto* enum_type,
|
||||
const LocationRecorder& enum_location);
|
||||
bool ParseServiceBlock(ServiceDescriptorProto* service,
|
||||
const LocationRecorder& service_location);
|
||||
|
||||
// Parse one statement within a message, enum, or service block, inclunding
|
||||
// final semicolon.
|
||||
bool ParseMessageStatement(DescriptorProto* message);
|
||||
bool ParseEnumStatement(EnumDescriptorProto* message);
|
||||
bool ParseServiceStatement(ServiceDescriptorProto* message);
|
||||
bool ParseMessageStatement(DescriptorProto* message,
|
||||
const LocationRecorder& message_location);
|
||||
bool ParseEnumStatement(EnumDescriptorProto* message,
|
||||
const LocationRecorder& enum_location);
|
||||
bool ParseServiceStatement(ServiceDescriptorProto* message,
|
||||
const LocationRecorder& service_location);
|
||||
|
||||
// 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);
|
||||
RepeatedPtrField<DescriptorProto>* messages,
|
||||
const LocationRecorder& parent_location,
|
||||
int location_field_number_for_nested_type,
|
||||
const LocationRecorder& field_location);
|
||||
|
||||
// Parse an "extensions" declaration.
|
||||
bool ParseExtensions(DescriptorProto* message);
|
||||
bool ParseExtensions(DescriptorProto* message,
|
||||
const LocationRecorder& extensions_location);
|
||||
|
||||
// Parse an "extend" declaration.
|
||||
// Parse an "extend" declaration. (See also comments for
|
||||
// ParseMessageField().)
|
||||
bool ParseExtend(RepeatedPtrField<FieldDescriptorProto>* extensions,
|
||||
RepeatedPtrField<DescriptorProto>* messages);
|
||||
RepeatedPtrField<DescriptorProto>* messages,
|
||||
const LocationRecorder& parent_location,
|
||||
int location_field_number_for_nested_type,
|
||||
const LocationRecorder& extend_location);
|
||||
|
||||
// Parse a single enum value within an enum block.
|
||||
bool ParseEnumConstant(EnumValueDescriptorProto* enum_value);
|
||||
bool ParseEnumConstant(EnumValueDescriptorProto* enum_value,
|
||||
const LocationRecorder& enum_value_location);
|
||||
|
||||
// Parse enum constant options, i.e. the list in square brackets at the end
|
||||
// of the enum constant value definition.
|
||||
bool ParseEnumConstantOptions(EnumValueDescriptorProto* value);
|
||||
bool ParseEnumConstantOptions(EnumValueDescriptorProto* value,
|
||||
const LocationRecorder& enum_value_location);
|
||||
|
||||
// Parse a single method within a service definition.
|
||||
bool ParseServiceMethod(MethodDescriptorProto* method);
|
||||
bool ParseServiceMethod(MethodDescriptorProto* method,
|
||||
const LocationRecorder& method_location);
|
||||
|
||||
|
||||
// Parse options of a single method or stream.
|
||||
bool ParseOptions(const LocationRecorder& parent_location,
|
||||
const int optionsFieldNumber,
|
||||
Message* mutable_options);
|
||||
|
||||
// Parse "required", "optional", or "repeated" and fill in "label"
|
||||
// with the value.
|
||||
@ -269,39 +376,71 @@ class LIBPROTOBUF_EXPORT Parser {
|
||||
|
||||
// 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);
|
||||
bool ParseFieldOptions(FieldDescriptorProto* field,
|
||||
const LocationRecorder& field_location);
|
||||
|
||||
// Parse the "default" option. This needs special handling because its
|
||||
// type is the field's type.
|
||||
bool ParseDefaultAssignment(FieldDescriptorProto* field);
|
||||
bool ParseDefaultAssignment(FieldDescriptorProto* field,
|
||||
const LocationRecorder& field_location);
|
||||
|
||||
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 ParseOptionAssignment(Message* options);
|
||||
bool ParseOption(Message* options,
|
||||
const LocationRecorder& options_location,
|
||||
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);
|
||||
bool ParseOptionNamePart(UninterpretedOption* uninterpreted_option,
|
||||
const LocationRecorder& part_location);
|
||||
|
||||
// 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(string* value);
|
||||
|
||||
// =================================================================
|
||||
|
||||
io::Tokenizer* input_;
|
||||
io::ErrorCollector* error_collector_;
|
||||
SourceLocationTable* source_location_table_;
|
||||
SourceCodeInfo* source_code_info_;
|
||||
SourceLocationTable* source_location_table_; // legacy
|
||||
bool had_errors_;
|
||||
bool require_syntax_identifier_;
|
||||
bool stop_after_syntax_identifier_;
|
||||
string syntax_identifier_;
|
||||
|
||||
// Leading doc comments for the next declaration. These are not complete
|
||||
// yet; use ConsumeEndOfDeclaration() to get the complete comments.
|
||||
string upcoming_doc_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 LIBPROTOBUF_EXPORT SourceLocationTable {
|
||||
public:
|
||||
SourceLocationTable();
|
File diff suppressed because it is too large
Load Diff
@ -59,13 +59,15 @@ namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
|
||||
class GeneratorResponseOutputDirectory : public OutputDirectory {
|
||||
class GeneratorResponseContext : public GeneratorContext {
|
||||
public:
|
||||
GeneratorResponseOutputDirectory(CodeGeneratorResponse* response)
|
||||
: response_(response) {}
|
||||
virtual ~GeneratorResponseOutputDirectory() {}
|
||||
GeneratorResponseContext(CodeGeneratorResponse* response,
|
||||
const vector<const FileDescriptor*>& parsed_files)
|
||||
: response_(response),
|
||||
parsed_files_(parsed_files) {}
|
||||
virtual ~GeneratorResponseContext() {}
|
||||
|
||||
// implements OutputDirectory --------------------------------------
|
||||
// implements GeneratorContext --------------------------------------
|
||||
|
||||
virtual io::ZeroCopyOutputStream* Open(const string& filename) {
|
||||
CodeGeneratorResponse::File* file = response_->add_file();
|
||||
@ -81,8 +83,13 @@ class GeneratorResponseOutputDirectory : public OutputDirectory {
|
||||
return new io::StringOutputStream(file->mutable_content());
|
||||
}
|
||||
|
||||
void ListParsedFiles(vector<const FileDescriptor*>* output) {
|
||||
*output = parsed_files_;
|
||||
}
|
||||
|
||||
private:
|
||||
CodeGeneratorResponse* response_;
|
||||
const vector<const FileDescriptor*>& parsed_files_;
|
||||
};
|
||||
|
||||
int PluginMain(int argc, char* argv[], const CodeGenerator* generator) {
|
||||
@ -112,22 +119,26 @@ int PluginMain(int argc, char* argv[], const CodeGenerator* generator) {
|
||||
}
|
||||
}
|
||||
|
||||
CodeGeneratorResponse response;
|
||||
GeneratorResponseOutputDirectory output_directory(&response);
|
||||
|
||||
vector<const FileDescriptor*> parsed_files;
|
||||
for (int i = 0; i < request.file_to_generate_size(); i++) {
|
||||
const FileDescriptor* file =
|
||||
pool.FindFileByName(request.file_to_generate(i));
|
||||
if (file == NULL) {
|
||||
parsed_files.push_back(pool.FindFileByName(request.file_to_generate(i)));
|
||||
if (parsed_files.back() == NULL) {
|
||||
cerr << argv[0] << ": protoc asked plugin to generate a file but "
|
||||
"did not provide a descriptor for the file: "
|
||||
<< request.file_to_generate(i) << endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
CodeGeneratorResponse response;
|
||||
GeneratorResponseContext context(&response, parsed_files);
|
||||
|
||||
for (int i = 0; i < parsed_files.size(); i++) {
|
||||
const FileDescriptor* file = parsed_files[i];
|
||||
|
||||
string error;
|
||||
bool succeeded = generator->Generate(
|
||||
file, request.parameter(), &output_directory, &error);
|
||||
file, request.parameter(), &context, &error);
|
||||
|
||||
if (!succeeded && error.empty()) {
|
||||
error = "Code generator returned false but provided no error "
|
@ -56,7 +56,6 @@
|
||||
#define GOOGLE_PROTOBUF_COMPILER_PLUGIN_H__
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
@ -1,11 +1,17 @@
|
||||
// Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
// source: google/protobuf/compiler/plugin.proto
|
||||
|
||||
#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION
|
||||
#include "google/protobuf/compiler/plugin.pb.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/stubs/once.h>
|
||||
#include <google/protobuf/io/coded_stream.h>
|
||||
#include <google/protobuf/wire_format_lite_inl.h>
|
||||
#include <google/protobuf/descriptor.h>
|
||||
#include <google/protobuf/generated_message_reflection.h>
|
||||
#include <google/protobuf/reflection_ops.h>
|
||||
#include <google/protobuf/wire_format.h>
|
||||
// @@protoc_insertion_point(includes)
|
||||
@ -133,7 +139,9 @@ void protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto() {
|
||||
"atorResponse\022\r\n\005error\030\001 \001(\t\022B\n\004file\030\017 \003("
|
||||
"\01324.google.protobuf.compiler.CodeGenerat"
|
||||
"orResponse.File\032>\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", 399);
|
||||
"\017insertion_point\030\002 \001(\t\022\017\n\007content\030\017 \001(\tB"
|
||||
",\n\034com.google.protobuf.compilerB\014PluginP"
|
||||
"rotos", 445);
|
||||
::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
|
||||
"google/protobuf/compiler/plugin.proto", &protobuf_RegisterTypes);
|
||||
CodeGeneratorRequest::default_instance_ = new CodeGeneratorRequest();
|
||||
@ -152,10 +160,8 @@ struct StaticDescriptorInitializer_google_2fprotobuf_2fcompiler_2fplugin_2eproto
|
||||
}
|
||||
} static_descriptor_initializer_google_2fprotobuf_2fcompiler_2fplugin_2eproto_;
|
||||
|
||||
|
||||
// ===================================================================
|
||||
|
||||
const ::std::string CodeGeneratorRequest::_default_parameter_;
|
||||
#ifndef _MSC_VER
|
||||
const int CodeGeneratorRequest::kFileToGenerateFieldNumber;
|
||||
const int CodeGeneratorRequest::kParameterFieldNumber;
|
||||
@ -178,7 +184,7 @@ CodeGeneratorRequest::CodeGeneratorRequest(const CodeGeneratorRequest& from)
|
||||
|
||||
void CodeGeneratorRequest::SharedCtor() {
|
||||
_cached_size_ = 0;
|
||||
parameter_ = const_cast< ::std::string*>(&_default_parameter_);
|
||||
parameter_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
|
||||
::memset(_has_bits_, 0, sizeof(_has_bits_));
|
||||
}
|
||||
|
||||
@ -187,7 +193,7 @@ CodeGeneratorRequest::~CodeGeneratorRequest() {
|
||||
}
|
||||
|
||||
void CodeGeneratorRequest::SharedDtor() {
|
||||
if (parameter_ != &_default_parameter_) {
|
||||
if (parameter_ != &::google::protobuf::internal::kEmptyString) {
|
||||
delete parameter_;
|
||||
}
|
||||
if (this != default_instance_) {
|
||||
@ -205,7 +211,8 @@ const ::google::protobuf::Descriptor* CodeGeneratorRequest::descriptor() {
|
||||
}
|
||||
|
||||
const CodeGeneratorRequest& CodeGeneratorRequest::default_instance() {
|
||||
if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); return *default_instance_;
|
||||
if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto();
|
||||
return *default_instance_;
|
||||
}
|
||||
|
||||
CodeGeneratorRequest* CodeGeneratorRequest::default_instance_ = NULL;
|
||||
@ -216,8 +223,8 @@ CodeGeneratorRequest* CodeGeneratorRequest::New() const {
|
||||
|
||||
void CodeGeneratorRequest::Clear() {
|
||||
if (_has_bits_[1 / 32] & (0xffu << (1 % 32))) {
|
||||
if (_has_bit(1)) {
|
||||
if (parameter_ != &_default_parameter_) {
|
||||
if (has_parameter()) {
|
||||
if (parameter_ != &::google::protobuf::internal::kEmptyString) {
|
||||
parameter_->clear();
|
||||
}
|
||||
}
|
||||
@ -242,7 +249,8 @@ bool CodeGeneratorRequest::MergePartialFromCodedStream(
|
||||
DO_(::google::protobuf::internal::WireFormatLite::ReadString(
|
||||
input, this->add_file_to_generate()));
|
||||
::google::protobuf::internal::WireFormat::VerifyUTF8String(
|
||||
this->file_to_generate(0).data(), this->file_to_generate(0).length(),
|
||||
this->file_to_generate(this->file_to_generate_size() - 1).data(),
|
||||
this->file_to_generate(this->file_to_generate_size() - 1).length(),
|
||||
::google::protobuf::internal::WireFormat::PARSE);
|
||||
} else {
|
||||
goto handle_uninterpreted;
|
||||
@ -251,7 +259,7 @@ bool CodeGeneratorRequest::MergePartialFromCodedStream(
|
||||
if (input->ExpectTag(18)) goto parse_parameter;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
// optional string parameter = 2;
|
||||
case 2: {
|
||||
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
|
||||
@ -268,7 +276,7 @@ bool CodeGeneratorRequest::MergePartialFromCodedStream(
|
||||
if (input->ExpectTag(122)) goto parse_proto_file;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
// repeated .google.protobuf.FileDescriptorProto proto_file = 15;
|
||||
case 15: {
|
||||
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
|
||||
@ -283,7 +291,7 @@ bool CodeGeneratorRequest::MergePartialFromCodedStream(
|
||||
if (input->ExpectAtEnd()) return true;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
default: {
|
||||
handle_uninterpreted:
|
||||
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
|
||||
@ -310,22 +318,22 @@ void CodeGeneratorRequest::SerializeWithCachedSizes(
|
||||
::google::protobuf::internal::WireFormatLite::WriteString(
|
||||
1, this->file_to_generate(i), output);
|
||||
}
|
||||
|
||||
|
||||
// optional string parameter = 2;
|
||||
if (_has_bit(1)) {
|
||||
if (has_parameter()) {
|
||||
::google::protobuf::internal::WireFormat::VerifyUTF8String(
|
||||
this->parameter().data(), this->parameter().length(),
|
||||
::google::protobuf::internal::WireFormat::SERIALIZE);
|
||||
::google::protobuf::internal::WireFormatLite::WriteString(
|
||||
2, this->parameter(), output);
|
||||
}
|
||||
|
||||
|
||||
// repeated .google.protobuf.FileDescriptorProto proto_file = 15;
|
||||
for (int i = 0; i < this->proto_file_size(); i++) {
|
||||
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
|
||||
15, this->proto_file(i), output);
|
||||
}
|
||||
|
||||
|
||||
if (!unknown_fields().empty()) {
|
||||
::google::protobuf::internal::WireFormat::SerializeUnknownFields(
|
||||
unknown_fields(), output);
|
||||
@ -342,9 +350,9 @@ void CodeGeneratorRequest::SerializeWithCachedSizes(
|
||||
target = ::google::protobuf::internal::WireFormatLite::
|
||||
WriteStringToArray(1, this->file_to_generate(i), target);
|
||||
}
|
||||
|
||||
|
||||
// optional string parameter = 2;
|
||||
if (_has_bit(1)) {
|
||||
if (has_parameter()) {
|
||||
::google::protobuf::internal::WireFormat::VerifyUTF8String(
|
||||
this->parameter().data(), this->parameter().length(),
|
||||
::google::protobuf::internal::WireFormat::SERIALIZE);
|
||||
@ -352,14 +360,14 @@ void CodeGeneratorRequest::SerializeWithCachedSizes(
|
||||
::google::protobuf::internal::WireFormatLite::WriteStringToArray(
|
||||
2, this->parameter(), target);
|
||||
}
|
||||
|
||||
|
||||
// repeated .google.protobuf.FileDescriptorProto proto_file = 15;
|
||||
for (int i = 0; i < this->proto_file_size(); i++) {
|
||||
target = ::google::protobuf::internal::WireFormatLite::
|
||||
WriteMessageNoVirtualToArray(
|
||||
15, this->proto_file(i), target);
|
||||
}
|
||||
|
||||
|
||||
if (!unknown_fields().empty()) {
|
||||
target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
|
||||
unknown_fields(), target);
|
||||
@ -369,7 +377,7 @@ void CodeGeneratorRequest::SerializeWithCachedSizes(
|
||||
|
||||
int CodeGeneratorRequest::ByteSize() const {
|
||||
int total_size = 0;
|
||||
|
||||
|
||||
if (_has_bits_[1 / 32] & (0xffu << (1 % 32))) {
|
||||
// optional string parameter = 2;
|
||||
if (has_parameter()) {
|
||||
@ -377,7 +385,7 @@ int CodeGeneratorRequest::ByteSize() const {
|
||||
::google::protobuf::internal::WireFormatLite::StringSize(
|
||||
this->parameter());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
// repeated string file_to_generate = 1;
|
||||
total_size += 1 * this->file_to_generate_size();
|
||||
@ -385,7 +393,7 @@ int CodeGeneratorRequest::ByteSize() const {
|
||||
total_size += ::google::protobuf::internal::WireFormatLite::StringSize(
|
||||
this->file_to_generate(i));
|
||||
}
|
||||
|
||||
|
||||
// repeated .google.protobuf.FileDescriptorProto proto_file = 15;
|
||||
total_size += 1 * this->proto_file_size();
|
||||
for (int i = 0; i < this->proto_file_size(); i++) {
|
||||
@ -393,7 +401,7 @@ int CodeGeneratorRequest::ByteSize() const {
|
||||
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
|
||||
this->proto_file(i));
|
||||
}
|
||||
|
||||
|
||||
if (!unknown_fields().empty()) {
|
||||
total_size +=
|
||||
::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
|
||||
@ -422,7 +430,7 @@ void CodeGeneratorRequest::MergeFrom(const CodeGeneratorRequest& from) {
|
||||
file_to_generate_.MergeFrom(from.file_to_generate_);
|
||||
proto_file_.MergeFrom(from.proto_file_);
|
||||
if (from._has_bits_[1 / 32] & (0xffu << (1 % 32))) {
|
||||
if (from._has_bit(1)) {
|
||||
if (from.has_parameter()) {
|
||||
set_parameter(from.parameter());
|
||||
}
|
||||
}
|
||||
@ -442,7 +450,7 @@ void CodeGeneratorRequest::CopyFrom(const CodeGeneratorRequest& from) {
|
||||
}
|
||||
|
||||
bool CodeGeneratorRequest::IsInitialized() const {
|
||||
|
||||
|
||||
for (int i = 0; i < proto_file_size(); i++) {
|
||||
if (!this->proto_file(i).IsInitialized()) return false;
|
||||
}
|
||||
@ -471,9 +479,6 @@ void CodeGeneratorRequest::Swap(CodeGeneratorRequest* other) {
|
||||
|
||||
// ===================================================================
|
||||
|
||||
const ::std::string CodeGeneratorResponse_File::_default_name_;
|
||||
const ::std::string CodeGeneratorResponse_File::_default_insertion_point_;
|
||||
const ::std::string CodeGeneratorResponse_File::_default_content_;
|
||||
#ifndef _MSC_VER
|
||||
const int CodeGeneratorResponse_File::kNameFieldNumber;
|
||||
const int CodeGeneratorResponse_File::kInsertionPointFieldNumber;
|
||||
@ -496,9 +501,9 @@ CodeGeneratorResponse_File::CodeGeneratorResponse_File(const CodeGeneratorRespon
|
||||
|
||||
void CodeGeneratorResponse_File::SharedCtor() {
|
||||
_cached_size_ = 0;
|
||||
name_ = const_cast< ::std::string*>(&_default_name_);
|
||||
insertion_point_ = const_cast< ::std::string*>(&_default_insertion_point_);
|
||||
content_ = const_cast< ::std::string*>(&_default_content_);
|
||||
name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
|
||||
insertion_point_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
|
||||
content_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
|
||||
::memset(_has_bits_, 0, sizeof(_has_bits_));
|
||||
}
|
||||
|
||||
@ -507,13 +512,13 @@ CodeGeneratorResponse_File::~CodeGeneratorResponse_File() {
|
||||
}
|
||||
|
||||
void CodeGeneratorResponse_File::SharedDtor() {
|
||||
if (name_ != &_default_name_) {
|
||||
if (name_ != &::google::protobuf::internal::kEmptyString) {
|
||||
delete name_;
|
||||
}
|
||||
if (insertion_point_ != &_default_insertion_point_) {
|
||||
if (insertion_point_ != &::google::protobuf::internal::kEmptyString) {
|
||||
delete insertion_point_;
|
||||
}
|
||||
if (content_ != &_default_content_) {
|
||||
if (content_ != &::google::protobuf::internal::kEmptyString) {
|
||||
delete content_;
|
||||
}
|
||||
if (this != default_instance_) {
|
||||
@ -531,7 +536,8 @@ const ::google::protobuf::Descriptor* CodeGeneratorResponse_File::descriptor() {
|
||||
}
|
||||
|
||||
const CodeGeneratorResponse_File& CodeGeneratorResponse_File::default_instance() {
|
||||
if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); return *default_instance_;
|
||||
if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto();
|
||||
return *default_instance_;
|
||||
}
|
||||
|
||||
CodeGeneratorResponse_File* CodeGeneratorResponse_File::default_instance_ = NULL;
|
||||
@ -542,18 +548,18 @@ CodeGeneratorResponse_File* CodeGeneratorResponse_File::New() const {
|
||||
|
||||
void CodeGeneratorResponse_File::Clear() {
|
||||
if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
|
||||
if (_has_bit(0)) {
|
||||
if (name_ != &_default_name_) {
|
||||
if (has_name()) {
|
||||
if (name_ != &::google::protobuf::internal::kEmptyString) {
|
||||
name_->clear();
|
||||
}
|
||||
}
|
||||
if (_has_bit(1)) {
|
||||
if (insertion_point_ != &_default_insertion_point_) {
|
||||
if (has_insertion_point()) {
|
||||
if (insertion_point_ != &::google::protobuf::internal::kEmptyString) {
|
||||
insertion_point_->clear();
|
||||
}
|
||||
}
|
||||
if (_has_bit(2)) {
|
||||
if (content_ != &_default_content_) {
|
||||
if (has_content()) {
|
||||
if (content_ != &::google::protobuf::internal::kEmptyString) {
|
||||
content_->clear();
|
||||
}
|
||||
}
|
||||
@ -583,7 +589,7 @@ bool CodeGeneratorResponse_File::MergePartialFromCodedStream(
|
||||
if (input->ExpectTag(18)) goto parse_insertion_point;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
// optional string insertion_point = 2;
|
||||
case 2: {
|
||||
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
|
||||
@ -600,7 +606,7 @@ bool CodeGeneratorResponse_File::MergePartialFromCodedStream(
|
||||
if (input->ExpectTag(122)) goto parse_content;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
// optional string content = 15;
|
||||
case 15: {
|
||||
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
|
||||
@ -617,7 +623,7 @@ bool CodeGeneratorResponse_File::MergePartialFromCodedStream(
|
||||
if (input->ExpectAtEnd()) return true;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
default: {
|
||||
handle_uninterpreted:
|
||||
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
|
||||
@ -637,32 +643,32 @@ bool CodeGeneratorResponse_File::MergePartialFromCodedStream(
|
||||
void CodeGeneratorResponse_File::SerializeWithCachedSizes(
|
||||
::google::protobuf::io::CodedOutputStream* output) const {
|
||||
// optional string name = 1;
|
||||
if (_has_bit(0)) {
|
||||
if (has_name()) {
|
||||
::google::protobuf::internal::WireFormat::VerifyUTF8String(
|
||||
this->name().data(), this->name().length(),
|
||||
::google::protobuf::internal::WireFormat::SERIALIZE);
|
||||
::google::protobuf::internal::WireFormatLite::WriteString(
|
||||
1, this->name(), output);
|
||||
}
|
||||
|
||||
|
||||
// optional string insertion_point = 2;
|
||||
if (_has_bit(1)) {
|
||||
if (has_insertion_point()) {
|
||||
::google::protobuf::internal::WireFormat::VerifyUTF8String(
|
||||
this->insertion_point().data(), this->insertion_point().length(),
|
||||
::google::protobuf::internal::WireFormat::SERIALIZE);
|
||||
::google::protobuf::internal::WireFormatLite::WriteString(
|
||||
2, this->insertion_point(), output);
|
||||
}
|
||||
|
||||
|
||||
// optional string content = 15;
|
||||
if (_has_bit(2)) {
|
||||
if (has_content()) {
|
||||
::google::protobuf::internal::WireFormat::VerifyUTF8String(
|
||||
this->content().data(), this->content().length(),
|
||||
::google::protobuf::internal::WireFormat::SERIALIZE);
|
||||
::google::protobuf::internal::WireFormatLite::WriteString(
|
||||
15, this->content(), output);
|
||||
}
|
||||
|
||||
|
||||
if (!unknown_fields().empty()) {
|
||||
::google::protobuf::internal::WireFormat::SerializeUnknownFields(
|
||||
unknown_fields(), output);
|
||||
@ -672,7 +678,7 @@ void CodeGeneratorResponse_File::SerializeWithCachedSizes(
|
||||
::google::protobuf::uint8* CodeGeneratorResponse_File::SerializeWithCachedSizesToArray(
|
||||
::google::protobuf::uint8* target) const {
|
||||
// optional string name = 1;
|
||||
if (_has_bit(0)) {
|
||||
if (has_name()) {
|
||||
::google::protobuf::internal::WireFormat::VerifyUTF8String(
|
||||
this->name().data(), this->name().length(),
|
||||
::google::protobuf::internal::WireFormat::SERIALIZE);
|
||||
@ -680,9 +686,9 @@ void CodeGeneratorResponse_File::SerializeWithCachedSizes(
|
||||
::google::protobuf::internal::WireFormatLite::WriteStringToArray(
|
||||
1, this->name(), target);
|
||||
}
|
||||
|
||||
|
||||
// optional string insertion_point = 2;
|
||||
if (_has_bit(1)) {
|
||||
if (has_insertion_point()) {
|
||||
::google::protobuf::internal::WireFormat::VerifyUTF8String(
|
||||
this->insertion_point().data(), this->insertion_point().length(),
|
||||
::google::protobuf::internal::WireFormat::SERIALIZE);
|
||||
@ -690,9 +696,9 @@ void CodeGeneratorResponse_File::SerializeWithCachedSizes(
|
||||
::google::protobuf::internal::WireFormatLite::WriteStringToArray(
|
||||
2, this->insertion_point(), target);
|
||||
}
|
||||
|
||||
|
||||
// optional string content = 15;
|
||||
if (_has_bit(2)) {
|
||||
if (has_content()) {
|
||||
::google::protobuf::internal::WireFormat::VerifyUTF8String(
|
||||
this->content().data(), this->content().length(),
|
||||
::google::protobuf::internal::WireFormat::SERIALIZE);
|
||||
@ -700,7 +706,7 @@ void CodeGeneratorResponse_File::SerializeWithCachedSizes(
|
||||
::google::protobuf::internal::WireFormatLite::WriteStringToArray(
|
||||
15, this->content(), target);
|
||||
}
|
||||
|
||||
|
||||
if (!unknown_fields().empty()) {
|
||||
target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
|
||||
unknown_fields(), target);
|
||||
@ -710,7 +716,7 @@ void CodeGeneratorResponse_File::SerializeWithCachedSizes(
|
||||
|
||||
int CodeGeneratorResponse_File::ByteSize() const {
|
||||
int total_size = 0;
|
||||
|
||||
|
||||
if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
|
||||
// optional string name = 1;
|
||||
if (has_name()) {
|
||||
@ -718,21 +724,21 @@ int CodeGeneratorResponse_File::ByteSize() const {
|
||||
::google::protobuf::internal::WireFormatLite::StringSize(
|
||||
this->name());
|
||||
}
|
||||
|
||||
|
||||
// optional string insertion_point = 2;
|
||||
if (has_insertion_point()) {
|
||||
total_size += 1 +
|
||||
::google::protobuf::internal::WireFormatLite::StringSize(
|
||||
this->insertion_point());
|
||||
}
|
||||
|
||||
|
||||
// optional string content = 15;
|
||||
if (has_content()) {
|
||||
total_size += 1 +
|
||||
::google::protobuf::internal::WireFormatLite::StringSize(
|
||||
this->content());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
if (!unknown_fields().empty()) {
|
||||
total_size +=
|
||||
@ -760,13 +766,13 @@ void CodeGeneratorResponse_File::MergeFrom(const ::google::protobuf::Message& fr
|
||||
void CodeGeneratorResponse_File::MergeFrom(const CodeGeneratorResponse_File& from) {
|
||||
GOOGLE_CHECK_NE(&from, this);
|
||||
if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
|
||||
if (from._has_bit(0)) {
|
||||
if (from.has_name()) {
|
||||
set_name(from.name());
|
||||
}
|
||||
if (from._has_bit(1)) {
|
||||
if (from.has_insertion_point()) {
|
||||
set_insertion_point(from.insertion_point());
|
||||
}
|
||||
if (from._has_bit(2)) {
|
||||
if (from.has_content()) {
|
||||
set_content(from.content());
|
||||
}
|
||||
}
|
||||
@ -786,7 +792,7 @@ void CodeGeneratorResponse_File::CopyFrom(const CodeGeneratorResponse_File& from
|
||||
}
|
||||
|
||||
bool CodeGeneratorResponse_File::IsInitialized() const {
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -812,7 +818,6 @@ void CodeGeneratorResponse_File::Swap(CodeGeneratorResponse_File* other) {
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
const ::std::string CodeGeneratorResponse::_default_error_;
|
||||
#ifndef _MSC_VER
|
||||
const int CodeGeneratorResponse::kErrorFieldNumber;
|
||||
const int CodeGeneratorResponse::kFileFieldNumber;
|
||||
@ -834,7 +839,7 @@ CodeGeneratorResponse::CodeGeneratorResponse(const CodeGeneratorResponse& from)
|
||||
|
||||
void CodeGeneratorResponse::SharedCtor() {
|
||||
_cached_size_ = 0;
|
||||
error_ = const_cast< ::std::string*>(&_default_error_);
|
||||
error_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
|
||||
::memset(_has_bits_, 0, sizeof(_has_bits_));
|
||||
}
|
||||
|
||||
@ -843,7 +848,7 @@ CodeGeneratorResponse::~CodeGeneratorResponse() {
|
||||
}
|
||||
|
||||
void CodeGeneratorResponse::SharedDtor() {
|
||||
if (error_ != &_default_error_) {
|
||||
if (error_ != &::google::protobuf::internal::kEmptyString) {
|
||||
delete error_;
|
||||
}
|
||||
if (this != default_instance_) {
|
||||
@ -861,7 +866,8 @@ const ::google::protobuf::Descriptor* CodeGeneratorResponse::descriptor() {
|
||||
}
|
||||
|
||||
const CodeGeneratorResponse& CodeGeneratorResponse::default_instance() {
|
||||
if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); return *default_instance_;
|
||||
if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto();
|
||||
return *default_instance_;
|
||||
}
|
||||
|
||||
CodeGeneratorResponse* CodeGeneratorResponse::default_instance_ = NULL;
|
||||
@ -872,8 +878,8 @@ CodeGeneratorResponse* CodeGeneratorResponse::New() const {
|
||||
|
||||
void CodeGeneratorResponse::Clear() {
|
||||
if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
|
||||
if (_has_bit(0)) {
|
||||
if (error_ != &_default_error_) {
|
||||
if (has_error()) {
|
||||
if (error_ != &::google::protobuf::internal::kEmptyString) {
|
||||
error_->clear();
|
||||
}
|
||||
}
|
||||
@ -904,7 +910,7 @@ bool CodeGeneratorResponse::MergePartialFromCodedStream(
|
||||
if (input->ExpectTag(122)) goto parse_file;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
// repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15;
|
||||
case 15: {
|
||||
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
|
||||
@ -919,7 +925,7 @@ bool CodeGeneratorResponse::MergePartialFromCodedStream(
|
||||
if (input->ExpectAtEnd()) return true;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
default: {
|
||||
handle_uninterpreted:
|
||||
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
|
||||
@ -939,20 +945,20 @@ bool CodeGeneratorResponse::MergePartialFromCodedStream(
|
||||
void CodeGeneratorResponse::SerializeWithCachedSizes(
|
||||
::google::protobuf::io::CodedOutputStream* output) const {
|
||||
// optional string error = 1;
|
||||
if (_has_bit(0)) {
|
||||
if (has_error()) {
|
||||
::google::protobuf::internal::WireFormat::VerifyUTF8String(
|
||||
this->error().data(), this->error().length(),
|
||||
::google::protobuf::internal::WireFormat::SERIALIZE);
|
||||
::google::protobuf::internal::WireFormatLite::WriteString(
|
||||
1, this->error(), output);
|
||||
}
|
||||
|
||||
|
||||
// repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15;
|
||||
for (int i = 0; i < this->file_size(); i++) {
|
||||
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
|
||||
15, this->file(i), output);
|
||||
}
|
||||
|
||||
|
||||
if (!unknown_fields().empty()) {
|
||||
::google::protobuf::internal::WireFormat::SerializeUnknownFields(
|
||||
unknown_fields(), output);
|
||||
@ -962,7 +968,7 @@ void CodeGeneratorResponse::SerializeWithCachedSizes(
|
||||
::google::protobuf::uint8* CodeGeneratorResponse::SerializeWithCachedSizesToArray(
|
||||
::google::protobuf::uint8* target) const {
|
||||
// optional string error = 1;
|
||||
if (_has_bit(0)) {
|
||||
if (has_error()) {
|
||||
::google::protobuf::internal::WireFormat::VerifyUTF8String(
|
||||
this->error().data(), this->error().length(),
|
||||
::google::protobuf::internal::WireFormat::SERIALIZE);
|
||||
@ -970,14 +976,14 @@ void CodeGeneratorResponse::SerializeWithCachedSizes(
|
||||
::google::protobuf::internal::WireFormatLite::WriteStringToArray(
|
||||
1, this->error(), target);
|
||||
}
|
||||
|
||||
|
||||
// repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15;
|
||||
for (int i = 0; i < this->file_size(); i++) {
|
||||
target = ::google::protobuf::internal::WireFormatLite::
|
||||
WriteMessageNoVirtualToArray(
|
||||
15, this->file(i), target);
|
||||
}
|
||||
|
||||
|
||||
if (!unknown_fields().empty()) {
|
||||
target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
|
||||
unknown_fields(), target);
|
||||
@ -987,7 +993,7 @@ void CodeGeneratorResponse::SerializeWithCachedSizes(
|
||||
|
||||
int CodeGeneratorResponse::ByteSize() const {
|
||||
int total_size = 0;
|
||||
|
||||
|
||||
if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
|
||||
// optional string error = 1;
|
||||
if (has_error()) {
|
||||
@ -995,7 +1001,7 @@ int CodeGeneratorResponse::ByteSize() const {
|
||||
::google::protobuf::internal::WireFormatLite::StringSize(
|
||||
this->error());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
// repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15;
|
||||
total_size += 1 * this->file_size();
|
||||
@ -1004,7 +1010,7 @@ int CodeGeneratorResponse::ByteSize() const {
|
||||
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
|
||||
this->file(i));
|
||||
}
|
||||
|
||||
|
||||
if (!unknown_fields().empty()) {
|
||||
total_size +=
|
||||
::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
|
||||
@ -1032,7 +1038,7 @@ void CodeGeneratorResponse::MergeFrom(const CodeGeneratorResponse& from) {
|
||||
GOOGLE_CHECK_NE(&from, this);
|
||||
file_.MergeFrom(from.file_);
|
||||
if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
|
||||
if (from._has_bit(0)) {
|
||||
if (from.has_error()) {
|
||||
set_error(from.error());
|
||||
}
|
||||
}
|
||||
@ -1052,7 +1058,7 @@ void CodeGeneratorResponse::CopyFrom(const CodeGeneratorResponse& from) {
|
||||
}
|
||||
|
||||
bool CodeGeneratorResponse::IsInitialized() const {
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -8,21 +8,22 @@
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
#if GOOGLE_PROTOBUF_VERSION < 2003000
|
||||
#if GOOGLE_PROTOBUF_VERSION < 2005000
|
||||
#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 2003000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
|
||||
#if 2005000 < GOOGLE_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 <google/protobuf/generated_message_util.h>
|
||||
#include <google/protobuf/message.h>
|
||||
#include <google/protobuf/repeated_field.h>
|
||||
#include <google/protobuf/extension_set.h>
|
||||
#include <google/protobuf/generated_message_reflection.h>
|
||||
#include <google/protobuf/unknown_field_set.h>
|
||||
#include "google/protobuf/descriptor.pb.h"
|
||||
// @@protoc_insertion_point(includes)
|
||||
|
||||
@ -45,29 +46,29 @@ class LIBPROTOC_EXPORT CodeGeneratorRequest : public ::google::protobuf::Message
|
||||
public:
|
||||
CodeGeneratorRequest();
|
||||
virtual ~CodeGeneratorRequest();
|
||||
|
||||
|
||||
CodeGeneratorRequest(const CodeGeneratorRequest& from);
|
||||
|
||||
|
||||
inline CodeGeneratorRequest& operator=(const CodeGeneratorRequest& from) {
|
||||
CopyFrom(from);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
|
||||
return _unknown_fields_;
|
||||
}
|
||||
|
||||
|
||||
inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
|
||||
return &_unknown_fields_;
|
||||
}
|
||||
|
||||
|
||||
static const ::google::protobuf::Descriptor* descriptor();
|
||||
static const CodeGeneratorRequest& default_instance();
|
||||
|
||||
|
||||
void Swap(CodeGeneratorRequest* other);
|
||||
|
||||
|
||||
// implements Message ----------------------------------------------
|
||||
|
||||
|
||||
CodeGeneratorRequest* New() const;
|
||||
void CopyFrom(const ::google::protobuf::Message& from);
|
||||
void MergeFrom(const ::google::protobuf::Message& from);
|
||||
@ -75,7 +76,7 @@ class LIBPROTOC_EXPORT CodeGeneratorRequest : public ::google::protobuf::Message
|
||||
void MergeFrom(const CodeGeneratorRequest& from);
|
||||
void Clear();
|
||||
bool IsInitialized() const;
|
||||
|
||||
|
||||
int ByteSize() const;
|
||||
bool MergePartialFromCodedStream(
|
||||
::google::protobuf::io::CodedInputStream* input);
|
||||
@ -88,13 +89,13 @@ class LIBPROTOC_EXPORT CodeGeneratorRequest : public ::google::protobuf::Message
|
||||
void SharedDtor();
|
||||
void SetCachedSize(int size) const;
|
||||
public:
|
||||
|
||||
|
||||
::google::protobuf::Metadata GetMetadata() const;
|
||||
|
||||
|
||||
// nested types ----------------------------------------------------
|
||||
|
||||
|
||||
// accessors -------------------------------------------------------
|
||||
|
||||
|
||||
// repeated string file_to_generate = 1;
|
||||
inline int file_to_generate_size() const;
|
||||
inline void clear_file_to_generate();
|
||||
@ -110,7 +111,7 @@ class LIBPROTOC_EXPORT CodeGeneratorRequest : public ::google::protobuf::Message
|
||||
inline void add_file_to_generate(const char* value, size_t size);
|
||||
inline const ::google::protobuf::RepeatedPtrField< ::std::string>& file_to_generate() const;
|
||||
inline ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_file_to_generate();
|
||||
|
||||
|
||||
// optional string parameter = 2;
|
||||
inline bool has_parameter() const;
|
||||
inline void clear_parameter();
|
||||
@ -120,7 +121,9 @@ class LIBPROTOC_EXPORT CodeGeneratorRequest : public ::google::protobuf::Message
|
||||
inline void set_parameter(const char* value);
|
||||
inline void set_parameter(const char* value, size_t size);
|
||||
inline ::std::string* mutable_parameter();
|
||||
|
||||
inline ::std::string* release_parameter();
|
||||
inline void set_allocated_parameter(::std::string* parameter);
|
||||
|
||||
// repeated .google.protobuf.FileDescriptorProto proto_file = 15;
|
||||
inline int proto_file_size() const;
|
||||
inline void clear_proto_file();
|
||||
@ -132,33 +135,25 @@ class LIBPROTOC_EXPORT CodeGeneratorRequest : public ::google::protobuf::Message
|
||||
proto_file() const;
|
||||
inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >*
|
||||
mutable_proto_file();
|
||||
|
||||
|
||||
// @@protoc_insertion_point(class_scope:google.protobuf.compiler.CodeGeneratorRequest)
|
||||
private:
|
||||
inline void set_has_parameter();
|
||||
inline void clear_has_parameter();
|
||||
|
||||
::google::protobuf::UnknownFieldSet _unknown_fields_;
|
||||
mutable int _cached_size_;
|
||||
|
||||
|
||||
::google::protobuf::RepeatedPtrField< ::std::string> file_to_generate_;
|
||||
::std::string* parameter_;
|
||||
static const ::std::string _default_parameter_;
|
||||
::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto > proto_file_;
|
||||
|
||||
mutable int _cached_size_;
|
||||
::google::protobuf::uint32 _has_bits_[(3 + 31) / 32];
|
||||
|
||||
friend void LIBPROTOC_EXPORT protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto();
|
||||
friend void protobuf_AssignDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto();
|
||||
friend void protobuf_ShutdownFile_google_2fprotobuf_2fcompiler_2fplugin_2eproto();
|
||||
|
||||
::google::protobuf::uint32 _has_bits_[(3 + 31) / 32];
|
||||
|
||||
// WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
|
||||
inline bool _has_bit(int index) const {
|
||||
return (_has_bits_[index / 32] & (1u << (index % 32))) != 0;
|
||||
}
|
||||
inline void _set_bit(int index) {
|
||||
_has_bits_[index / 32] |= (1u << (index % 32));
|
||||
}
|
||||
inline void _clear_bit(int index) {
|
||||
_has_bits_[index / 32] &= ~(1u << (index % 32));
|
||||
}
|
||||
|
||||
|
||||
void InitAsDefaultInstance();
|
||||
static CodeGeneratorRequest* default_instance_;
|
||||
};
|
||||
@ -168,29 +163,29 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse_File : public ::google::protobuf::M
|
||||
public:
|
||||
CodeGeneratorResponse_File();
|
||||
virtual ~CodeGeneratorResponse_File();
|
||||
|
||||
|
||||
CodeGeneratorResponse_File(const CodeGeneratorResponse_File& from);
|
||||
|
||||
|
||||
inline CodeGeneratorResponse_File& operator=(const CodeGeneratorResponse_File& from) {
|
||||
CopyFrom(from);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
|
||||
return _unknown_fields_;
|
||||
}
|
||||
|
||||
|
||||
inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
|
||||
return &_unknown_fields_;
|
||||
}
|
||||
|
||||
|
||||
static const ::google::protobuf::Descriptor* descriptor();
|
||||
static const CodeGeneratorResponse_File& default_instance();
|
||||
|
||||
|
||||
void Swap(CodeGeneratorResponse_File* other);
|
||||
|
||||
|
||||
// implements Message ----------------------------------------------
|
||||
|
||||
|
||||
CodeGeneratorResponse_File* New() const;
|
||||
void CopyFrom(const ::google::protobuf::Message& from);
|
||||
void MergeFrom(const ::google::protobuf::Message& from);
|
||||
@ -198,7 +193,7 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse_File : public ::google::protobuf::M
|
||||
void MergeFrom(const CodeGeneratorResponse_File& from);
|
||||
void Clear();
|
||||
bool IsInitialized() const;
|
||||
|
||||
|
||||
int ByteSize() const;
|
||||
bool MergePartialFromCodedStream(
|
||||
::google::protobuf::io::CodedInputStream* input);
|
||||
@ -211,13 +206,13 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse_File : public ::google::protobuf::M
|
||||
void SharedDtor();
|
||||
void SetCachedSize(int size) const;
|
||||
public:
|
||||
|
||||
|
||||
::google::protobuf::Metadata GetMetadata() const;
|
||||
|
||||
|
||||
// nested types ----------------------------------------------------
|
||||
|
||||
|
||||
// accessors -------------------------------------------------------
|
||||
|
||||
|
||||
// optional string name = 1;
|
||||
inline bool has_name() const;
|
||||
inline void clear_name();
|
||||
@ -227,7 +222,9 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse_File : public ::google::protobuf::M
|
||||
inline void set_name(const char* value);
|
||||
inline void set_name(const char* value, size_t size);
|
||||
inline ::std::string* mutable_name();
|
||||
|
||||
inline ::std::string* release_name();
|
||||
inline void set_allocated_name(::std::string* name);
|
||||
|
||||
// optional string insertion_point = 2;
|
||||
inline bool has_insertion_point() const;
|
||||
inline void clear_insertion_point();
|
||||
@ -237,7 +234,9 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse_File : public ::google::protobuf::M
|
||||
inline void set_insertion_point(const char* value);
|
||||
inline void set_insertion_point(const char* value, size_t size);
|
||||
inline ::std::string* mutable_insertion_point();
|
||||
|
||||
inline ::std::string* release_insertion_point();
|
||||
inline void set_allocated_insertion_point(::std::string* insertion_point);
|
||||
|
||||
// optional string content = 15;
|
||||
inline bool has_content() const;
|
||||
inline void clear_content();
|
||||
@ -247,35 +246,31 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse_File : public ::google::protobuf::M
|
||||
inline void set_content(const char* value);
|
||||
inline void set_content(const char* value, size_t size);
|
||||
inline ::std::string* mutable_content();
|
||||
|
||||
inline ::std::string* release_content();
|
||||
inline void set_allocated_content(::std::string* content);
|
||||
|
||||
// @@protoc_insertion_point(class_scope:google.protobuf.compiler.CodeGeneratorResponse.File)
|
||||
private:
|
||||
inline void set_has_name();
|
||||
inline void clear_has_name();
|
||||
inline void set_has_insertion_point();
|
||||
inline void clear_has_insertion_point();
|
||||
inline void set_has_content();
|
||||
inline void clear_has_content();
|
||||
|
||||
::google::protobuf::UnknownFieldSet _unknown_fields_;
|
||||
mutable int _cached_size_;
|
||||
|
||||
|
||||
::std::string* name_;
|
||||
static const ::std::string _default_name_;
|
||||
::std::string* insertion_point_;
|
||||
static const ::std::string _default_insertion_point_;
|
||||
::std::string* content_;
|
||||
static const ::std::string _default_content_;
|
||||
|
||||
mutable int _cached_size_;
|
||||
::google::protobuf::uint32 _has_bits_[(3 + 31) / 32];
|
||||
|
||||
friend void LIBPROTOC_EXPORT protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto();
|
||||
friend void protobuf_AssignDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto();
|
||||
friend void protobuf_ShutdownFile_google_2fprotobuf_2fcompiler_2fplugin_2eproto();
|
||||
|
||||
::google::protobuf::uint32 _has_bits_[(3 + 31) / 32];
|
||||
|
||||
// WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
|
||||
inline bool _has_bit(int index) const {
|
||||
return (_has_bits_[index / 32] & (1u << (index % 32))) != 0;
|
||||
}
|
||||
inline void _set_bit(int index) {
|
||||
_has_bits_[index / 32] |= (1u << (index % 32));
|
||||
}
|
||||
inline void _clear_bit(int index) {
|
||||
_has_bits_[index / 32] &= ~(1u << (index % 32));
|
||||
}
|
||||
|
||||
|
||||
void InitAsDefaultInstance();
|
||||
static CodeGeneratorResponse_File* default_instance_;
|
||||
};
|
||||
@ -285,29 +280,29 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse : public ::google::protobuf::Messag
|
||||
public:
|
||||
CodeGeneratorResponse();
|
||||
virtual ~CodeGeneratorResponse();
|
||||
|
||||
|
||||
CodeGeneratorResponse(const CodeGeneratorResponse& from);
|
||||
|
||||
|
||||
inline CodeGeneratorResponse& operator=(const CodeGeneratorResponse& from) {
|
||||
CopyFrom(from);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
|
||||
return _unknown_fields_;
|
||||
}
|
||||
|
||||
|
||||
inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
|
||||
return &_unknown_fields_;
|
||||
}
|
||||
|
||||
|
||||
static const ::google::protobuf::Descriptor* descriptor();
|
||||
static const CodeGeneratorResponse& default_instance();
|
||||
|
||||
|
||||
void Swap(CodeGeneratorResponse* other);
|
||||
|
||||
|
||||
// implements Message ----------------------------------------------
|
||||
|
||||
|
||||
CodeGeneratorResponse* New() const;
|
||||
void CopyFrom(const ::google::protobuf::Message& from);
|
||||
void MergeFrom(const ::google::protobuf::Message& from);
|
||||
@ -315,7 +310,7 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse : public ::google::protobuf::Messag
|
||||
void MergeFrom(const CodeGeneratorResponse& from);
|
||||
void Clear();
|
||||
bool IsInitialized() const;
|
||||
|
||||
|
||||
int ByteSize() const;
|
||||
bool MergePartialFromCodedStream(
|
||||
::google::protobuf::io::CodedInputStream* input);
|
||||
@ -328,15 +323,15 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse : public ::google::protobuf::Messag
|
||||
void SharedDtor();
|
||||
void SetCachedSize(int size) const;
|
||||
public:
|
||||
|
||||
|
||||
::google::protobuf::Metadata GetMetadata() const;
|
||||
|
||||
|
||||
// nested types ----------------------------------------------------
|
||||
|
||||
|
||||
typedef CodeGeneratorResponse_File File;
|
||||
|
||||
|
||||
// accessors -------------------------------------------------------
|
||||
|
||||
|
||||
// optional string error = 1;
|
||||
inline bool has_error() const;
|
||||
inline void clear_error();
|
||||
@ -346,7 +341,9 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse : public ::google::protobuf::Messag
|
||||
inline void set_error(const char* value);
|
||||
inline void set_error(const char* value, size_t size);
|
||||
inline ::std::string* mutable_error();
|
||||
|
||||
inline ::std::string* release_error();
|
||||
inline void set_allocated_error(::std::string* error);
|
||||
|
||||
// repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15;
|
||||
inline int file_size() const;
|
||||
inline void clear_file();
|
||||
@ -358,32 +355,24 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse : public ::google::protobuf::Messag
|
||||
file() const;
|
||||
inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >*
|
||||
mutable_file();
|
||||
|
||||
|
||||
// @@protoc_insertion_point(class_scope:google.protobuf.compiler.CodeGeneratorResponse)
|
||||
private:
|
||||
inline void set_has_error();
|
||||
inline void clear_has_error();
|
||||
|
||||
::google::protobuf::UnknownFieldSet _unknown_fields_;
|
||||
mutable int _cached_size_;
|
||||
|
||||
|
||||
::std::string* error_;
|
||||
static const ::std::string _default_error_;
|
||||
::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File > file_;
|
||||
|
||||
mutable int _cached_size_;
|
||||
::google::protobuf::uint32 _has_bits_[(2 + 31) / 32];
|
||||
|
||||
friend void LIBPROTOC_EXPORT protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto();
|
||||
friend void protobuf_AssignDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto();
|
||||
friend void protobuf_ShutdownFile_google_2fprotobuf_2fcompiler_2fplugin_2eproto();
|
||||
|
||||
::google::protobuf::uint32 _has_bits_[(2 + 31) / 32];
|
||||
|
||||
// WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
|
||||
inline bool _has_bit(int index) const {
|
||||
return (_has_bits_[index / 32] & (1u << (index % 32))) != 0;
|
||||
}
|
||||
inline void _set_bit(int index) {
|
||||
_has_bits_[index / 32] |= (1u << (index % 32));
|
||||
}
|
||||
inline void _clear_bit(int index) {
|
||||
_has_bits_[index / 32] &= ~(1u << (index % 32));
|
||||
}
|
||||
|
||||
|
||||
void InitAsDefaultInstance();
|
||||
static CodeGeneratorResponse* default_instance_;
|
||||
};
|
||||
@ -440,45 +429,73 @@ CodeGeneratorRequest::mutable_file_to_generate() {
|
||||
|
||||
// optional string parameter = 2;
|
||||
inline bool CodeGeneratorRequest::has_parameter() const {
|
||||
return _has_bit(1);
|
||||
return (_has_bits_[0] & 0x00000002u) != 0;
|
||||
}
|
||||
inline void CodeGeneratorRequest::set_has_parameter() {
|
||||
_has_bits_[0] |= 0x00000002u;
|
||||
}
|
||||
inline void CodeGeneratorRequest::clear_has_parameter() {
|
||||
_has_bits_[0] &= ~0x00000002u;
|
||||
}
|
||||
inline void CodeGeneratorRequest::clear_parameter() {
|
||||
if (parameter_ != &_default_parameter_) {
|
||||
if (parameter_ != &::google::protobuf::internal::kEmptyString) {
|
||||
parameter_->clear();
|
||||
}
|
||||
_clear_bit(1);
|
||||
clear_has_parameter();
|
||||
}
|
||||
inline const ::std::string& CodeGeneratorRequest::parameter() const {
|
||||
return *parameter_;
|
||||
}
|
||||
inline void CodeGeneratorRequest::set_parameter(const ::std::string& value) {
|
||||
_set_bit(1);
|
||||
if (parameter_ == &_default_parameter_) {
|
||||
set_has_parameter();
|
||||
if (parameter_ == &::google::protobuf::internal::kEmptyString) {
|
||||
parameter_ = new ::std::string;
|
||||
}
|
||||
parameter_->assign(value);
|
||||
}
|
||||
inline void CodeGeneratorRequest::set_parameter(const char* value) {
|
||||
_set_bit(1);
|
||||
if (parameter_ == &_default_parameter_) {
|
||||
set_has_parameter();
|
||||
if (parameter_ == &::google::protobuf::internal::kEmptyString) {
|
||||
parameter_ = new ::std::string;
|
||||
}
|
||||
parameter_->assign(value);
|
||||
}
|
||||
inline void CodeGeneratorRequest::set_parameter(const char* value, size_t size) {
|
||||
_set_bit(1);
|
||||
if (parameter_ == &_default_parameter_) {
|
||||
set_has_parameter();
|
||||
if (parameter_ == &::google::protobuf::internal::kEmptyString) {
|
||||
parameter_ = new ::std::string;
|
||||
}
|
||||
parameter_->assign(reinterpret_cast<const char*>(value), size);
|
||||
}
|
||||
inline ::std::string* CodeGeneratorRequest::mutable_parameter() {
|
||||
_set_bit(1);
|
||||
if (parameter_ == &_default_parameter_) {
|
||||
set_has_parameter();
|
||||
if (parameter_ == &::google::protobuf::internal::kEmptyString) {
|
||||
parameter_ = new ::std::string;
|
||||
}
|
||||
return parameter_;
|
||||
}
|
||||
inline ::std::string* CodeGeneratorRequest::release_parameter() {
|
||||
clear_has_parameter();
|
||||
if (parameter_ == &::google::protobuf::internal::kEmptyString) {
|
||||
return NULL;
|
||||
} else {
|
||||
::std::string* temp = parameter_;
|
||||
parameter_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
|
||||
return temp;
|
||||
}
|
||||
}
|
||||
inline void CodeGeneratorRequest::set_allocated_parameter(::std::string* parameter) {
|
||||
if (parameter_ != &::google::protobuf::internal::kEmptyString) {
|
||||
delete parameter_;
|
||||
}
|
||||
if (parameter) {
|
||||
set_has_parameter();
|
||||
parameter_ = parameter;
|
||||
} else {
|
||||
clear_has_parameter();
|
||||
parameter_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
|
||||
}
|
||||
}
|
||||
|
||||
// repeated .google.protobuf.FileDescriptorProto proto_file = 15;
|
||||
inline int CodeGeneratorRequest::proto_file_size() const {
|
||||
@ -511,129 +528,213 @@ CodeGeneratorRequest::mutable_proto_file() {
|
||||
|
||||
// optional string name = 1;
|
||||
inline bool CodeGeneratorResponse_File::has_name() const {
|
||||
return _has_bit(0);
|
||||
return (_has_bits_[0] & 0x00000001u) != 0;
|
||||
}
|
||||
inline void CodeGeneratorResponse_File::set_has_name() {
|
||||
_has_bits_[0] |= 0x00000001u;
|
||||
}
|
||||
inline void CodeGeneratorResponse_File::clear_has_name() {
|
||||
_has_bits_[0] &= ~0x00000001u;
|
||||
}
|
||||
inline void CodeGeneratorResponse_File::clear_name() {
|
||||
if (name_ != &_default_name_) {
|
||||
if (name_ != &::google::protobuf::internal::kEmptyString) {
|
||||
name_->clear();
|
||||
}
|
||||
_clear_bit(0);
|
||||
clear_has_name();
|
||||
}
|
||||
inline const ::std::string& CodeGeneratorResponse_File::name() const {
|
||||
return *name_;
|
||||
}
|
||||
inline void CodeGeneratorResponse_File::set_name(const ::std::string& value) {
|
||||
_set_bit(0);
|
||||
if (name_ == &_default_name_) {
|
||||
set_has_name();
|
||||
if (name_ == &::google::protobuf::internal::kEmptyString) {
|
||||
name_ = new ::std::string;
|
||||
}
|
||||
name_->assign(value);
|
||||
}
|
||||
inline void CodeGeneratorResponse_File::set_name(const char* value) {
|
||||
_set_bit(0);
|
||||
if (name_ == &_default_name_) {
|
||||
set_has_name();
|
||||
if (name_ == &::google::protobuf::internal::kEmptyString) {
|
||||
name_ = new ::std::string;
|
||||
}
|
||||
name_->assign(value);
|
||||
}
|
||||
inline void CodeGeneratorResponse_File::set_name(const char* value, size_t size) {
|
||||
_set_bit(0);
|
||||
if (name_ == &_default_name_) {
|
||||
set_has_name();
|
||||
if (name_ == &::google::protobuf::internal::kEmptyString) {
|
||||
name_ = new ::std::string;
|
||||
}
|
||||
name_->assign(reinterpret_cast<const char*>(value), size);
|
||||
}
|
||||
inline ::std::string* CodeGeneratorResponse_File::mutable_name() {
|
||||
_set_bit(0);
|
||||
if (name_ == &_default_name_) {
|
||||
set_has_name();
|
||||
if (name_ == &::google::protobuf::internal::kEmptyString) {
|
||||
name_ = new ::std::string;
|
||||
}
|
||||
return name_;
|
||||
}
|
||||
inline ::std::string* CodeGeneratorResponse_File::release_name() {
|
||||
clear_has_name();
|
||||
if (name_ == &::google::protobuf::internal::kEmptyString) {
|
||||
return NULL;
|
||||
} else {
|
||||
::std::string* temp = name_;
|
||||
name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
|
||||
return temp;
|
||||
}
|
||||
}
|
||||
inline void CodeGeneratorResponse_File::set_allocated_name(::std::string* name) {
|
||||
if (name_ != &::google::protobuf::internal::kEmptyString) {
|
||||
delete name_;
|
||||
}
|
||||
if (name) {
|
||||
set_has_name();
|
||||
name_ = name;
|
||||
} else {
|
||||
clear_has_name();
|
||||
name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
|
||||
}
|
||||
}
|
||||
|
||||
// optional string insertion_point = 2;
|
||||
inline bool CodeGeneratorResponse_File::has_insertion_point() const {
|
||||
return _has_bit(1);
|
||||
return (_has_bits_[0] & 0x00000002u) != 0;
|
||||
}
|
||||
inline void CodeGeneratorResponse_File::set_has_insertion_point() {
|
||||
_has_bits_[0] |= 0x00000002u;
|
||||
}
|
||||
inline void CodeGeneratorResponse_File::clear_has_insertion_point() {
|
||||
_has_bits_[0] &= ~0x00000002u;
|
||||
}
|
||||
inline void CodeGeneratorResponse_File::clear_insertion_point() {
|
||||
if (insertion_point_ != &_default_insertion_point_) {
|
||||
if (insertion_point_ != &::google::protobuf::internal::kEmptyString) {
|
||||
insertion_point_->clear();
|
||||
}
|
||||
_clear_bit(1);
|
||||
clear_has_insertion_point();
|
||||
}
|
||||
inline const ::std::string& CodeGeneratorResponse_File::insertion_point() const {
|
||||
return *insertion_point_;
|
||||
}
|
||||
inline void CodeGeneratorResponse_File::set_insertion_point(const ::std::string& value) {
|
||||
_set_bit(1);
|
||||
if (insertion_point_ == &_default_insertion_point_) {
|
||||
set_has_insertion_point();
|
||||
if (insertion_point_ == &::google::protobuf::internal::kEmptyString) {
|
||||
insertion_point_ = new ::std::string;
|
||||
}
|
||||
insertion_point_->assign(value);
|
||||
}
|
||||
inline void CodeGeneratorResponse_File::set_insertion_point(const char* value) {
|
||||
_set_bit(1);
|
||||
if (insertion_point_ == &_default_insertion_point_) {
|
||||
set_has_insertion_point();
|
||||
if (insertion_point_ == &::google::protobuf::internal::kEmptyString) {
|
||||
insertion_point_ = new ::std::string;
|
||||
}
|
||||
insertion_point_->assign(value);
|
||||
}
|
||||
inline void CodeGeneratorResponse_File::set_insertion_point(const char* value, size_t size) {
|
||||
_set_bit(1);
|
||||
if (insertion_point_ == &_default_insertion_point_) {
|
||||
set_has_insertion_point();
|
||||
if (insertion_point_ == &::google::protobuf::internal::kEmptyString) {
|
||||
insertion_point_ = new ::std::string;
|
||||
}
|
||||
insertion_point_->assign(reinterpret_cast<const char*>(value), size);
|
||||
}
|
||||
inline ::std::string* CodeGeneratorResponse_File::mutable_insertion_point() {
|
||||
_set_bit(1);
|
||||
if (insertion_point_ == &_default_insertion_point_) {
|
||||
set_has_insertion_point();
|
||||
if (insertion_point_ == &::google::protobuf::internal::kEmptyString) {
|
||||
insertion_point_ = new ::std::string;
|
||||
}
|
||||
return insertion_point_;
|
||||
}
|
||||
inline ::std::string* CodeGeneratorResponse_File::release_insertion_point() {
|
||||
clear_has_insertion_point();
|
||||
if (insertion_point_ == &::google::protobuf::internal::kEmptyString) {
|
||||
return NULL;
|
||||
} else {
|
||||
::std::string* temp = insertion_point_;
|
||||
insertion_point_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
|
||||
return temp;
|
||||
}
|
||||
}
|
||||
inline void CodeGeneratorResponse_File::set_allocated_insertion_point(::std::string* insertion_point) {
|
||||
if (insertion_point_ != &::google::protobuf::internal::kEmptyString) {
|
||||
delete insertion_point_;
|
||||
}
|
||||
if (insertion_point) {
|
||||
set_has_insertion_point();
|
||||
insertion_point_ = insertion_point;
|
||||
} else {
|
||||
clear_has_insertion_point();
|
||||
insertion_point_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
|
||||
}
|
||||
}
|
||||
|
||||
// optional string content = 15;
|
||||
inline bool CodeGeneratorResponse_File::has_content() const {
|
||||
return _has_bit(2);
|
||||
return (_has_bits_[0] & 0x00000004u) != 0;
|
||||
}
|
||||
inline void CodeGeneratorResponse_File::set_has_content() {
|
||||
_has_bits_[0] |= 0x00000004u;
|
||||
}
|
||||
inline void CodeGeneratorResponse_File::clear_has_content() {
|
||||
_has_bits_[0] &= ~0x00000004u;
|
||||
}
|
||||
inline void CodeGeneratorResponse_File::clear_content() {
|
||||
if (content_ != &_default_content_) {
|
||||
if (content_ != &::google::protobuf::internal::kEmptyString) {
|
||||
content_->clear();
|
||||
}
|
||||
_clear_bit(2);
|
||||
clear_has_content();
|
||||
}
|
||||
inline const ::std::string& CodeGeneratorResponse_File::content() const {
|
||||
return *content_;
|
||||
}
|
||||
inline void CodeGeneratorResponse_File::set_content(const ::std::string& value) {
|
||||
_set_bit(2);
|
||||
if (content_ == &_default_content_) {
|
||||
set_has_content();
|
||||
if (content_ == &::google::protobuf::internal::kEmptyString) {
|
||||
content_ = new ::std::string;
|
||||
}
|
||||
content_->assign(value);
|
||||
}
|
||||
inline void CodeGeneratorResponse_File::set_content(const char* value) {
|
||||
_set_bit(2);
|
||||
if (content_ == &_default_content_) {
|
||||
set_has_content();
|
||||
if (content_ == &::google::protobuf::internal::kEmptyString) {
|
||||
content_ = new ::std::string;
|
||||
}
|
||||
content_->assign(value);
|
||||
}
|
||||
inline void CodeGeneratorResponse_File::set_content(const char* value, size_t size) {
|
||||
_set_bit(2);
|
||||
if (content_ == &_default_content_) {
|
||||
set_has_content();
|
||||
if (content_ == &::google::protobuf::internal::kEmptyString) {
|
||||
content_ = new ::std::string;
|
||||
}
|
||||
content_->assign(reinterpret_cast<const char*>(value), size);
|
||||
}
|
||||
inline ::std::string* CodeGeneratorResponse_File::mutable_content() {
|
||||
_set_bit(2);
|
||||
if (content_ == &_default_content_) {
|
||||
set_has_content();
|
||||
if (content_ == &::google::protobuf::internal::kEmptyString) {
|
||||
content_ = new ::std::string;
|
||||
}
|
||||
return content_;
|
||||
}
|
||||
inline ::std::string* CodeGeneratorResponse_File::release_content() {
|
||||
clear_has_content();
|
||||
if (content_ == &::google::protobuf::internal::kEmptyString) {
|
||||
return NULL;
|
||||
} else {
|
||||
::std::string* temp = content_;
|
||||
content_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
|
||||
return temp;
|
||||
}
|
||||
}
|
||||
inline void CodeGeneratorResponse_File::set_allocated_content(::std::string* content) {
|
||||
if (content_ != &::google::protobuf::internal::kEmptyString) {
|
||||
delete content_;
|
||||
}
|
||||
if (content) {
|
||||
set_has_content();
|
||||
content_ = content;
|
||||
} else {
|
||||
clear_has_content();
|
||||
content_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
@ -641,45 +742,73 @@ inline ::std::string* CodeGeneratorResponse_File::mutable_content() {
|
||||
|
||||
// optional string error = 1;
|
||||
inline bool CodeGeneratorResponse::has_error() const {
|
||||
return _has_bit(0);
|
||||
return (_has_bits_[0] & 0x00000001u) != 0;
|
||||
}
|
||||
inline void CodeGeneratorResponse::set_has_error() {
|
||||
_has_bits_[0] |= 0x00000001u;
|
||||
}
|
||||
inline void CodeGeneratorResponse::clear_has_error() {
|
||||
_has_bits_[0] &= ~0x00000001u;
|
||||
}
|
||||
inline void CodeGeneratorResponse::clear_error() {
|
||||
if (error_ != &_default_error_) {
|
||||
if (error_ != &::google::protobuf::internal::kEmptyString) {
|
||||
error_->clear();
|
||||
}
|
||||
_clear_bit(0);
|
||||
clear_has_error();
|
||||
}
|
||||
inline const ::std::string& CodeGeneratorResponse::error() const {
|
||||
return *error_;
|
||||
}
|
||||
inline void CodeGeneratorResponse::set_error(const ::std::string& value) {
|
||||
_set_bit(0);
|
||||
if (error_ == &_default_error_) {
|
||||
set_has_error();
|
||||
if (error_ == &::google::protobuf::internal::kEmptyString) {
|
||||
error_ = new ::std::string;
|
||||
}
|
||||
error_->assign(value);
|
||||
}
|
||||
inline void CodeGeneratorResponse::set_error(const char* value) {
|
||||
_set_bit(0);
|
||||
if (error_ == &_default_error_) {
|
||||
set_has_error();
|
||||
if (error_ == &::google::protobuf::internal::kEmptyString) {
|
||||
error_ = new ::std::string;
|
||||
}
|
||||
error_->assign(value);
|
||||
}
|
||||
inline void CodeGeneratorResponse::set_error(const char* value, size_t size) {
|
||||
_set_bit(0);
|
||||
if (error_ == &_default_error_) {
|
||||
set_has_error();
|
||||
if (error_ == &::google::protobuf::internal::kEmptyString) {
|
||||
error_ = new ::std::string;
|
||||
}
|
||||
error_->assign(reinterpret_cast<const char*>(value), size);
|
||||
}
|
||||
inline ::std::string* CodeGeneratorResponse::mutable_error() {
|
||||
_set_bit(0);
|
||||
if (error_ == &_default_error_) {
|
||||
set_has_error();
|
||||
if (error_ == &::google::protobuf::internal::kEmptyString) {
|
||||
error_ = new ::std::string;
|
||||
}
|
||||
return error_;
|
||||
}
|
||||
inline ::std::string* CodeGeneratorResponse::release_error() {
|
||||
clear_has_error();
|
||||
if (error_ == &::google::protobuf::internal::kEmptyString) {
|
||||
return NULL;
|
||||
} else {
|
||||
::std::string* temp = error_;
|
||||
error_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
|
||||
return temp;
|
||||
}
|
||||
}
|
||||
inline void CodeGeneratorResponse::set_allocated_error(::std::string* error) {
|
||||
if (error_ != &::google::protobuf::internal::kEmptyString) {
|
||||
delete error_;
|
||||
}
|
||||
if (error) {
|
||||
set_has_error();
|
||||
error_ = error;
|
||||
} else {
|
||||
clear_has_error();
|
||||
error_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
|
||||
}
|
||||
}
|
||||
|
||||
// repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15;
|
||||
inline int CodeGeneratorResponse::file_size() const {
|
@ -45,6 +45,8 @@
|
||||
// flag "--${NAME}_out" is passed to protoc.
|
||||
|
||||
package google.protobuf.compiler;
|
||||
option java_package = "com.google.protobuf.compiler";
|
||||
option java_outer_classname = "PluginProtos";
|
||||
|
||||
import "google/protobuf/descriptor.proto";
|
||||
|
||||
@ -131,7 +133,7 @@ message CodeGeneratorResponse {
|
||||
// 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 invocatino of protoc.
|
||||
// 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.
|
||||
//
|
@ -52,6 +52,7 @@
|
||||
#include <google/protobuf/descriptor.pb.h>
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/stubs/stringprintf.h>
|
||||
#include <google/protobuf/io/printer.h>
|
||||
#include <google/protobuf/descriptor.h>
|
||||
#include <google/protobuf/io/zero_copy_stream.h>
|
||||
@ -106,6 +107,12 @@ string NamePrefixedWithNestedTypes(const DescriptorT& descriptor,
|
||||
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 &&
|
||||
@ -120,13 +127,21 @@ void PrintTopBoilerplate(
|
||||
// TODO(robinson): Allow parameterization of Python version?
|
||||
printer->Print(
|
||||
"# Generated by the protocol buffer compiler. DO NOT EDIT!\n"
|
||||
"\n"
|
||||
"from google.protobuf import descriptor\n"
|
||||
"from google.protobuf import message\n"
|
||||
"from google.protobuf import reflection\n");
|
||||
"# source: $filename$\n"
|
||||
"\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 message as _message\n"
|
||||
"from google.protobuf import reflection as _reflection\n"
|
||||
);
|
||||
if (HasGenericServices(file)) {
|
||||
printer->Print(
|
||||
"from google.protobuf import service\n"
|
||||
"from google.protobuf import service as _service\n"
|
||||
"from google.protobuf import service_reflection\n");
|
||||
}
|
||||
|
||||
@ -204,12 +219,12 @@ string StringifyDefaultValue(const FieldDescriptor& field) {
|
||||
case FieldDescriptor::CPPTYPE_STRING:
|
||||
if (field.type() == FieldDescriptor::TYPE_STRING) {
|
||||
return "unicode(\"" + CEscape(field.default_value_string()) +
|
||||
"\", \"utf-8\")";
|
||||
"\", \"utf-8\")";
|
||||
} else {
|
||||
return "\"" + CEscape(field.default_value_string()) + "\"";
|
||||
}
|
||||
case FieldDescriptor::CPPTYPE_MESSAGE:
|
||||
return "None";
|
||||
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.)
|
||||
@ -230,7 +245,7 @@ Generator::~Generator() {
|
||||
|
||||
bool Generator::Generate(const FileDescriptor* file,
|
||||
const string& parameter,
|
||||
OutputDirectory* output_directory,
|
||||
GeneratorContext* context,
|
||||
string* error) const {
|
||||
|
||||
// Completely serialize all Generate() calls on this instance. The
|
||||
@ -252,26 +267,29 @@ bool Generator::Generate(const FileDescriptor* file,
|
||||
fdp.SerializeToString(&file_descriptor_serialized_);
|
||||
|
||||
|
||||
scoped_ptr<io::ZeroCopyOutputStream> output(output_directory->Open(filename));
|
||||
scoped_ptr<io::ZeroCopyOutputStream> output(context->Open(filename));
|
||||
GOOGLE_CHECK(output.get());
|
||||
io::Printer printer(output.get(), '$');
|
||||
printer_ = &printer;
|
||||
|
||||
PrintTopBoilerplate(printer_, file_, GeneratingDescriptorProto());
|
||||
PrintImports();
|
||||
PrintFileDescriptor();
|
||||
PrintTopLevelEnums();
|
||||
PrintTopLevelExtensions();
|
||||
PrintAllNestedEnumsInFile();
|
||||
PrintMessageDescriptors();
|
||||
// We have to print the imports after the descriptors, so that mutually
|
||||
// recursive protos in separate files can successfully reference each other.
|
||||
PrintImports();
|
||||
FixForeignFieldsInDescriptors();
|
||||
PrintMessages();
|
||||
// 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.
|
||||
FixAllDescriptorOptions();
|
||||
if (HasGenericServices(file)) {
|
||||
PrintServices();
|
||||
}
|
||||
@ -290,6 +308,13 @@ void Generator::PrintImports() const {
|
||||
module_name);
|
||||
}
|
||||
printer_->Print("\n");
|
||||
|
||||
// Print public imports.
|
||||
for (int i = 0; i < file_->public_dependency_count(); ++i) {
|
||||
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.
|
||||
@ -299,7 +324,7 @@ void Generator::PrintFileDescriptor() const {
|
||||
m["name"] = file_->name();
|
||||
m["package"] = file_->package();
|
||||
const char file_descriptor_template[] =
|
||||
"$descriptor_name$ = descriptor.FileDescriptor(\n"
|
||||
"$descriptor_name$ = _descriptor.FileDescriptor(\n"
|
||||
" name='$name$',\n"
|
||||
" package='$package$',\n";
|
||||
printer_->Print(m, file_descriptor_template);
|
||||
@ -323,6 +348,11 @@ void Generator::PrintTopLevelEnums() const {
|
||||
for (int i = 0; i < file_->enum_type_count(); ++i) {
|
||||
const EnumDescriptor& enum_descriptor = *file_->enum_type(i);
|
||||
PrintEnum(enum_descriptor);
|
||||
printer_->Print("$name$ = "
|
||||
"enum_type_wrapper.EnumTypeWrapper($descriptor_name$)",
|
||||
"name", enum_descriptor.name(),
|
||||
"descriptor_name",
|
||||
ModuleLevelDescriptorName(enum_descriptor));
|
||||
printer_->Print("\n");
|
||||
|
||||
for (int j = 0; j < enum_descriptor.value_count(); ++j) {
|
||||
@ -357,7 +387,7 @@ void Generator::PrintEnum(const EnumDescriptor& enum_descriptor) const {
|
||||
m["full_name"] = enum_descriptor.full_name();
|
||||
m["file"] = kDescriptorKey;
|
||||
const char enum_descriptor_template[] =
|
||||
"$descriptor_name$ = descriptor.EnumDescriptor(\n"
|
||||
"$descriptor_name$ = _descriptor.EnumDescriptor(\n"
|
||||
" name='$name$',\n"
|
||||
" full_name='$full_name$',\n"
|
||||
" filename=None,\n"
|
||||
@ -377,7 +407,7 @@ void Generator::PrintEnum(const EnumDescriptor& enum_descriptor) const {
|
||||
printer_->Print("containing_type=None,\n");
|
||||
printer_->Print("options=$options_value$,\n",
|
||||
"options_value",
|
||||
OptionsValue("EnumOptions", CEscape(options_string)));
|
||||
OptionsValue("EnumOptions", options_string));
|
||||
EnumDescriptorProto edp;
|
||||
PrintSerializedPbInterval(enum_descriptor, edp);
|
||||
printer_->Outdent();
|
||||
@ -438,7 +468,7 @@ void Generator::PrintServiceDescriptor(
|
||||
descriptor.options().SerializeToString(&options_string);
|
||||
|
||||
printer_->Print(
|
||||
"$service_name$ = descriptor.ServiceDescriptor(\n",
|
||||
"$service_name$ = _descriptor.ServiceDescriptor(\n",
|
||||
"service_name", service_name);
|
||||
printer_->Indent();
|
||||
map<string, string> m;
|
||||
@ -461,7 +491,6 @@ void Generator::PrintServiceDescriptor(
|
||||
printer_->Print("methods=[\n");
|
||||
for (int i = 0; i < descriptor.method_count(); ++i) {
|
||||
const MethodDescriptor* method = descriptor.method(i);
|
||||
string options_string;
|
||||
method->options().SerializeToString(&options_string);
|
||||
|
||||
m.clear();
|
||||
@ -472,7 +501,7 @@ void Generator::PrintServiceDescriptor(
|
||||
m["input_type"] = ModuleLevelDescriptorName(*(method->input_type()));
|
||||
m["output_type"] = ModuleLevelDescriptorName(*(method->output_type()));
|
||||
m["options_value"] = OptionsValue("MethodOptions", options_string);
|
||||
printer_->Print("descriptor.MethodDescriptor(\n");
|
||||
printer_->Print("_descriptor.MethodDescriptor(\n");
|
||||
printer_->Indent();
|
||||
printer_->Print(
|
||||
m,
|
||||
@ -493,7 +522,7 @@ void Generator::PrintServiceDescriptor(
|
||||
|
||||
void Generator::PrintServiceClass(const ServiceDescriptor& descriptor) const {
|
||||
// Print the service.
|
||||
printer_->Print("class $class_name$(service.Service):\n",
|
||||
printer_->Print("class $class_name$(_service.Service):\n",
|
||||
"class_name", descriptor.name());
|
||||
printer_->Indent();
|
||||
printer_->Print(
|
||||
@ -525,7 +554,7 @@ void Generator::PrintDescriptor(const Descriptor& message_descriptor) const {
|
||||
PrintNestedDescriptors(message_descriptor);
|
||||
|
||||
printer_->Print("\n");
|
||||
printer_->Print("$descriptor_name$ = descriptor.Descriptor(\n",
|
||||
printer_->Print("$descriptor_name$ = _descriptor.Descriptor(\n",
|
||||
"descriptor_name",
|
||||
ModuleLevelDescriptorName(message_descriptor));
|
||||
printer_->Indent();
|
||||
@ -620,10 +649,10 @@ void Generator::PrintMessages() const {
|
||||
// Mutually recursive with PrintNestedMessages().
|
||||
void Generator::PrintMessage(
|
||||
const Descriptor& message_descriptor) const {
|
||||
printer_->Print("class $name$(message.Message):\n", "name",
|
||||
printer_->Print("class $name$(_message.Message):\n", "name",
|
||||
message_descriptor.name());
|
||||
printer_->Indent();
|
||||
printer_->Print("__metaclass__ = reflection.GeneratedProtocolMessageType\n");
|
||||
printer_->Print("__metaclass__ = _reflection.GeneratedProtocolMessageType\n");
|
||||
PrintNestedMessages(message_descriptor);
|
||||
map<string, string> m;
|
||||
m["descriptor_key"] = kDescriptorKey;
|
||||
@ -674,6 +703,17 @@ void Generator::FixForeignFieldsInDescriptor(
|
||||
}
|
||||
}
|
||||
|
||||
void Generator::AddMessageToFileDescriptor(const Descriptor& descriptor) const {
|
||||
map<string, 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);
|
||||
}
|
||||
|
||||
// Sets any necessary message_type and enum_type attributes
|
||||
// for the Python version of |field|.
|
||||
//
|
||||
@ -752,6 +792,9 @@ void Generator::FixForeignFieldsInDescriptors() const {
|
||||
for (int i = 0; i < file_->message_type_count(); ++i) {
|
||||
FixForeignFieldsInDescriptor(*file_->message_type(i), NULL);
|
||||
}
|
||||
for (int i = 0; i < file_->message_type_count(); ++i) {
|
||||
AddMessageToFileDescriptor(*file_->message_type(i));
|
||||
}
|
||||
printer_->Print("\n");
|
||||
}
|
||||
|
||||
@ -767,6 +810,7 @@ void Generator::FixForeignFieldsInExtensions() const {
|
||||
for (int i = 0; i < file_->message_type_count(); ++i) {
|
||||
FixForeignFieldsInNestedExtensions(*file_->message_type(i));
|
||||
}
|
||||
printer_->Print("\n");
|
||||
}
|
||||
|
||||
void Generator::FixForeignFieldsInExtension(
|
||||
@ -817,19 +861,21 @@ void Generator::PrintEnumValueDescriptor(
|
||||
m["options"] = OptionsValue("EnumValueOptions", options_string);
|
||||
printer_->Print(
|
||||
m,
|
||||
"descriptor.EnumValueDescriptor(\n"
|
||||
"_descriptor.EnumValueDescriptor(\n"
|
||||
" name='$name$', index=$index$, number=$number$,\n"
|
||||
" options=$options$,\n"
|
||||
" type=None)");
|
||||
}
|
||||
|
||||
// Returns a Python expression that calls descriptor._ParseOptions using
|
||||
// the given descriptor class name and serialized options protobuf string.
|
||||
string Generator::OptionsValue(
|
||||
const string& class_name, const string& serialized_options) const {
|
||||
if (serialized_options.length() == 0 || GeneratingDescriptorProto()) {
|
||||
return "None";
|
||||
} else {
|
||||
string full_class_name = "descriptor_pb2." + class_name;
|
||||
return "descriptor._ParseOptions(" + full_class_name + "(), '"
|
||||
return "_descriptor._ParseOptions(" + full_class_name + "(), '"
|
||||
+ CEscape(serialized_options)+ "')";
|
||||
}
|
||||
}
|
||||
@ -855,7 +901,7 @@ void Generator::PrintFieldDescriptor(
|
||||
// these fields in correctly after all referenced descriptors have been
|
||||
// defined and/or imported (see FixForeignFieldsInDescriptors()).
|
||||
const char field_descriptor_decl[] =
|
||||
"descriptor.FieldDescriptor(\n"
|
||||
"_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"
|
||||
@ -986,6 +1032,125 @@ void Generator::PrintSerializedPbInterval(
|
||||
"serialized_end", SimpleItoa(offset + sp.size()));
|
||||
}
|
||||
|
||||
namespace {
|
||||
void PrintDescriptorOptionsFixingCode(const string& descriptor,
|
||||
const string& options,
|
||||
io::Printer* printer) {
|
||||
// TODO(xiaofeng): I have added a method _SetOptions() to DescriptorBase
|
||||
// in proto2 python runtime but it couldn't be used here because appengine
|
||||
// uses a snapshot version of the library in which the new method is not
|
||||
// yet present. After appengine has synced their runtime library, the code
|
||||
// below should be cleaned up to use _SetOptions().
|
||||
printer->Print(
|
||||
"$descriptor$.has_options = True\n"
|
||||
"$descriptor$._options = $options$\n",
|
||||
"descriptor", descriptor, "options", options);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
// Prints expressions that set the options field of all descriptors.
|
||||
void Generator::FixAllDescriptorOptions() const {
|
||||
// Prints an expression that sets the file descriptor's options.
|
||||
string file_options = OptionsValue(
|
||||
"FileOptions", file_->options().SerializeAsString());
|
||||
if (file_options != "None") {
|
||||
PrintDescriptorOptionsFixingCode(kDescriptorKey, file_options, printer_);
|
||||
}
|
||||
// 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));
|
||||
}
|
||||
}
|
||||
|
||||
// Prints expressions that set the options for an enum descriptor and its
|
||||
// value descriptors.
|
||||
void Generator::FixOptionsForEnum(const EnumDescriptor& enum_descriptor) const {
|
||||
string descriptor_name = ModuleLevelDescriptorName(enum_descriptor);
|
||||
string enum_options = OptionsValue(
|
||||
"EnumOptions", 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);
|
||||
string value_options = OptionsValue(
|
||||
"EnumValueOptions", 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 field descriptors (including
|
||||
// extensions).
|
||||
void Generator::FixOptionsForField(
|
||||
const FieldDescriptor& field) const {
|
||||
string field_options = OptionsValue(
|
||||
"FieldOptions", field.options().SerializeAsString());
|
||||
if (field_options != "None") {
|
||||
string field_name;
|
||||
if (field.is_extension()) {
|
||||
if (field.extension_scope() == NULL) {
|
||||
// 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));
|
||||
}
|
||||
// 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.
|
||||
string message_options = OptionsValue(
|
||||
"MessageOptions", descriptor.options().SerializeAsString());
|
||||
if (message_options != "None") {
|
||||
string descriptor_name = ModuleLevelDescriptorName(descriptor);
|
||||
PrintDescriptorOptionsFixingCode(descriptor_name,
|
||||
message_options,
|
||||
printer_);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace python
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
@ -66,7 +66,7 @@ class LIBPROTOC_EXPORT Generator : public CodeGenerator {
|
||||
// CodeGenerator methods.
|
||||
virtual bool Generate(const FileDescriptor* file,
|
||||
const string& parameter,
|
||||
OutputDirectory* output_directory,
|
||||
GeneratorContext* generator_context,
|
||||
string* error) const;
|
||||
|
||||
private:
|
||||
@ -104,6 +104,7 @@ class LIBPROTOC_EXPORT Generator : public CodeGenerator {
|
||||
void FixForeignFieldsInField(const Descriptor* containing_type,
|
||||
const FieldDescriptor& field,
|
||||
const string& python_dict_name) const;
|
||||
void AddMessageToFileDescriptor(const Descriptor& descriptor) const;
|
||||
string FieldReferencingExpression(const Descriptor* containing_type,
|
||||
const FieldDescriptor& field,
|
||||
const string& python_dict_name) const;
|
||||
@ -137,6 +138,11 @@ class LIBPROTOC_EXPORT Generator : public CodeGenerator {
|
||||
void PrintSerializedPbInterval(
|
||||
const DescriptorT& descriptor, DescriptorProtoT& proto) const;
|
||||
|
||||
void FixAllDescriptorOptions() const;
|
||||
void FixOptionsForField(const FieldDescriptor& field) const;
|
||||
void FixOptionsForEnum(const EnumDescriptor& descriptor) const;
|
||||
void FixOptionsForMessage(const Descriptor& descriptor) const;
|
||||
|
||||
// Very coarse-grained lock to ensure that Generate() is reentrant.
|
||||
// Guards file_, printer_ and file_descriptor_serialized_.
|
||||
mutable Mutex mutex_;
|
@ -56,19 +56,19 @@ class TestGenerator : public CodeGenerator {
|
||||
|
||||
virtual bool Generate(const FileDescriptor* file,
|
||||
const string& parameter,
|
||||
OutputDirectory* output_directory,
|
||||
GeneratorContext* context,
|
||||
string* error) const {
|
||||
TryInsert("test_pb2.py", "imports", output_directory);
|
||||
TryInsert("test_pb2.py", "module_scope", output_directory);
|
||||
TryInsert("test_pb2.py", "class_scope:foo.Bar", output_directory);
|
||||
TryInsert("test_pb2.py", "class_scope:foo.Bar.Baz", output_directory);
|
||||
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 string& filename, const string& insertion_point,
|
||||
OutputDirectory* output_directory) const {
|
||||
GeneratorContext* context) const {
|
||||
scoped_ptr<io::ZeroCopyOutputStream> output(
|
||||
output_directory->OpenForInsert(filename, insertion_point));
|
||||
context->OpenForInsert(filename, insertion_point));
|
||||
io::Printer printer(output.get(), '$');
|
||||
printer.Print("// inserted $name$\n", "name", insertion_point);
|
||||
}
|
@ -32,13 +32,16 @@
|
||||
|
||||
#include <google/protobuf/compiler/subprocess.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <errno.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/wait.h>
|
||||
#include <signal.h>
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/message.h>
|
||||
#include <google/protobuf/stubs/substitute.h>
|
||||
@ -96,7 +99,7 @@ void Subprocess::Start(const string& program, SearchMode search_mode) {
|
||||
}
|
||||
|
||||
// Setup STARTUPINFO to redirect handles.
|
||||
STARTUPINFO startup_info;
|
||||
STARTUPINFOA startup_info;
|
||||
ZeroMemory(&startup_info, sizeof(startup_info));
|
||||
startup_info.cb = sizeof(startup_info);
|
||||
startup_info.dwFlags = STARTF_USESTDHANDLES;
|
||||
@ -115,16 +118,16 @@ void Subprocess::Start(const string& program, SearchMode search_mode) {
|
||||
// Create the process.
|
||||
PROCESS_INFORMATION process_info;
|
||||
|
||||
if (CreateProcess((search_mode == SEARCH_PATH) ? NULL : program.c_str(),
|
||||
(search_mode == SEARCH_PATH) ? name_copy : 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)) {
|
||||
if (CreateProcessA((search_mode == SEARCH_PATH) ? NULL : program.c_str(),
|
||||
(search_mode == SEARCH_PATH) ? name_copy : 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;
|
||||
@ -292,8 +295,8 @@ void Subprocess::Start(const string& program, SearchMode search_mode) {
|
||||
int stdin_pipe[2];
|
||||
int stdout_pipe[2];
|
||||
|
||||
pipe(stdin_pipe);
|
||||
pipe(stdout_pipe);
|
||||
GOOGLE_CHECK(pipe(stdin_pipe) != -1);
|
||||
GOOGLE_CHECK(pipe(stdout_pipe) != -1);
|
||||
|
||||
char* argv[2] = { strdup(program.c_str()), NULL };
|
||||
|
||||
@ -321,9 +324,11 @@ void Subprocess::Start(const string& program, SearchMode search_mode) {
|
||||
|
||||
// Write directly to STDERR_FILENO to avoid stdio code paths that may do
|
||||
// stuff that is unsafe here.
|
||||
write(STDERR_FILENO, argv[0], strlen(argv[0]));
|
||||
int ignored;
|
||||
ignored = write(STDERR_FILENO, argv[0], strlen(argv[0]));
|
||||
const char* message = ": program not found or is not executable\n";
|
||||
write(STDERR_FILENO, message, strlen(message));
|
||||
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.
|
@ -40,9 +40,10 @@
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#endif // !_WIN32
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
#include <string>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
@ -52,7 +53,7 @@ class Message;
|
||||
namespace compiler {
|
||||
|
||||
// Utility class for launching sub-processes.
|
||||
class Subprocess {
|
||||
class LIBPROTOC_EXPORT Subprocess {
|
||||
public:
|
||||
Subprocess();
|
||||
~Subprocess();
|
||||
@ -76,7 +77,7 @@ class Subprocess {
|
||||
#ifdef _WIN32
|
||||
// Given an error code, returns a human-readable error message. This is
|
||||
// defined here so that CommandLineInterface can share it.
|
||||
static string Subprocess::Win32ErrorMessage(DWORD error_code);
|
||||
static string Win32ErrorMessage(DWORD error_code);
|
||||
#endif
|
||||
|
||||
private:
|
@ -39,45 +39,51 @@ fail() {
|
||||
exit 1
|
||||
}
|
||||
|
||||
TEST_TMPDIR=.
|
||||
PROTOC=./protoc
|
||||
|
||||
echo '
|
||||
syntax = "proto2";
|
||||
option java_multiple_files = true;
|
||||
option java_package = "test.jar";
|
||||
option java_outer_classname = "Outer";
|
||||
message Foo {}
|
||||
message Bar {}
|
||||
' > testzip.proto
|
||||
' > $TEST_TMPDIR/testzip.proto
|
||||
|
||||
./protoc --cpp_out=testzip.zip --python_out=testzip.zip --java_out=testzip.jar \
|
||||
testzip.proto || fail 'protoc failed.'
|
||||
$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 testzip.zip > testzip.list || fail 'unzip failed.'
|
||||
unzip -t $TEST_TMPDIR/testzip.zip > $TEST_TMPDIR/testzip.list || fail 'unzip failed.'
|
||||
|
||||
grep 'testing: testzip\.pb\.cc *OK$' testzip.list > /dev/null \
|
||||
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$' testzip.list > /dev/null \
|
||||
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$' testzip.list > /dev/null \
|
||||
grep 'testing: testzip_pb2\.py *OK$' $TEST_TMPDIR/testzip.list > /dev/null \
|
||||
|| fail 'testzip_pb2.py not found in output zip.'
|
||||
grep -i 'manifest' testzip.list > /dev/null \
|
||||
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 testzip.proto > /dev/null; then
|
||||
jar tf testzip.jar > testzip.list || fail 'jar failed.'
|
||||
if jar c $TEST_TMPDIR/testzip.proto > /dev/null; then
|
||||
jar tf $TEST_TMPDIR/testzip.jar > $TEST_TMPDIR/testzip.list || fail 'jar failed.'
|
||||
|
||||
grep '^test/jar/Foo\.java$' testzip.list > /dev/null \
|
||||
grep '^test/jar/Foo\.java$' $TEST_TMPDIR/testzip.list > /dev/null \
|
||||
|| fail 'Foo.java not found in output jar.'
|
||||
grep '^test/jar/Bar\.java$' testzip.list > /dev/null \
|
||||
grep '^test/jar/Bar\.java$' $TEST_TMPDIR/testzip.list > /dev/null \
|
||||
|| fail 'Bar.java not found in output jar.'
|
||||
grep '^test/jar/Outer\.java$' testzip.list > /dev/null \
|
||||
grep '^test/jar/Outer\.java$' $TEST_TMPDIR/testzip.list > /dev/null \
|
||||
|| fail 'Outer.java not found in output jar.'
|
||||
grep '^META-INF/MANIFEST\.MF$' testzip.list > /dev/null \
|
||||
|| fail 'Manifest not ofund 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
|
@ -28,6 +28,36 @@
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
@ -183,6 +213,6 @@ bool ZipWriter::WriteDirectory() {
|
||||
return output.HadError();
|
||||
}
|
||||
|
||||
} // namespace google
|
||||
} // namespace protobuf
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,93 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// 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.
|
||||
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// 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 <vector>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/io/zero_copy_stream.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
|
||||
class ZipWriter {
|
||||
public:
|
||||
ZipWriter(io::ZeroCopyOutputStream* raw_output);
|
||||
~ZipWriter();
|
||||
|
||||
bool Write(const string& filename, const string& contents);
|
||||
bool WriteDirectory();
|
||||
|
||||
private:
|
||||
struct FileInfo {
|
||||
string name;
|
||||
uint32 offset;
|
||||
uint32 size;
|
||||
uint32 crc32;
|
||||
};
|
||||
|
||||
io::ZeroCopyOutputStream* raw_output_;
|
||||
vector<FileInfo> files_;
|
||||
};
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
File diff suppressed because it is too large
Load Diff
@ -58,6 +58,10 @@
|
||||
#include <vector>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
// TYPE_BOOL is defined in the MacOS's ConditionalMacros.h.
|
||||
#ifdef TYPE_BOOL
|
||||
#undef TYPE_BOOL
|
||||
#endif // TYPE_BOOL
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
@ -89,6 +93,7 @@ class ServiceOptions;
|
||||
class MethodOptions;
|
||||
class FileOptions;
|
||||
class UninterpretedOption;
|
||||
class SourceCodeInfo;
|
||||
|
||||
// Defined in message.h
|
||||
class Message;
|
||||
@ -100,6 +105,20 @@ class FileDescriptorTables;
|
||||
// Defined in unknown_field_set.h.
|
||||
class UnknownField;
|
||||
|
||||
// NB, all indices are zero-based.
|
||||
struct SourceLocation {
|
||||
int start_line;
|
||||
int end_line;
|
||||
int start_column;
|
||||
int end_column;
|
||||
|
||||
// Doc comments found at the source location.
|
||||
// TODO(kenton): Maybe this struct should have been named SourceInfo or
|
||||
// something instead. Oh well.
|
||||
string leading_comments;
|
||||
string trailing_comments;
|
||||
};
|
||||
|
||||
// Describes a type of protocol message, or a particular group within a
|
||||
// message. To obtain the Descriptor for a given message object, call
|
||||
// Message::GetDescriptor(). Generated message classes also have a
|
||||
@ -236,6 +255,13 @@ class LIBPROTOBUF_EXPORT Descriptor {
|
||||
// this message type's scope.
|
||||
const FieldDescriptor* FindExtensionByCamelcaseName(const string& name) const;
|
||||
|
||||
// Source Location ---------------------------------------------------
|
||||
|
||||
// Updates |*out_location| to the source location of the complete
|
||||
// extent of this message declaration. Returns false and leaves
|
||||
// |*out_location| unchanged iff location information was not available.
|
||||
bool GetSourceLocation(SourceLocation* out_location) const;
|
||||
|
||||
private:
|
||||
typedef MessageOptions OptionsType;
|
||||
|
||||
@ -243,6 +269,10 @@ class LIBPROTOBUF_EXPORT Descriptor {
|
||||
// correct depth
|
||||
void DebugString(int depth, string *contents) const;
|
||||
|
||||
// Walks up the descriptor tree to generate the source location path
|
||||
// to this descriptor from the file root.
|
||||
void GetLocationPath(vector<int>* output) const;
|
||||
|
||||
const string* name_;
|
||||
const string* full_name_;
|
||||
const FileDescriptor* file_;
|
||||
@ -388,15 +418,19 @@ class LIBPROTOBUF_EXPORT FieldDescriptor {
|
||||
// when parsing formats which prefer to use camel-case naming style.
|
||||
const string& camelcase_name() const;
|
||||
|
||||
Type type() const; // Declared type of this field.
|
||||
CppType cpp_type() const; // C++ type of this field.
|
||||
Label label() const; // optional/required/repeated
|
||||
Type type() const; // Declared type of this field.
|
||||
const char* type_name() const; // Name of the declared type.
|
||||
CppType cpp_type() const; // C++ type of this field.
|
||||
const char* cpp_type_name() const; // Name of the C++ type.
|
||||
Label label() const; // optional/required/repeated
|
||||
|
||||
bool is_required() const; // shorthand for label() == LABEL_REQUIRED
|
||||
bool is_optional() const; // shorthand for label() == LABEL_OPTIONAL
|
||||
bool is_repeated() const; // shorthand for label() == LABEL_REPEATED
|
||||
bool is_packable() const; // shorthand for is_repeated() &&
|
||||
// IsTypePackable(type())
|
||||
bool is_packed() const; // shorthand for is_packable() &&
|
||||
// options().packed()
|
||||
|
||||
// Index of this field within the message's field array, or the file or
|
||||
// extension scope's extensions array.
|
||||
@ -479,6 +513,13 @@ class LIBPROTOBUF_EXPORT FieldDescriptor {
|
||||
// Return true iff [packed = true] is valid for fields of this type.
|
||||
static inline bool IsTypePackable(Type field_type);
|
||||
|
||||
// Source Location ---------------------------------------------------
|
||||
|
||||
// Updates |*out_location| to the source location of the complete
|
||||
// extent of this field declaration. Returns false and leaves
|
||||
// |*out_location| unchanged iff location information was not available.
|
||||
bool GetSourceLocation(SourceLocation* out_location) const;
|
||||
|
||||
private:
|
||||
typedef FieldOptions OptionsType;
|
||||
|
||||
@ -490,6 +531,10 @@ class LIBPROTOBUF_EXPORT FieldDescriptor {
|
||||
// types of CPPTYPE_STRING whill be surrounded by quotes and CEscaped.
|
||||
string DefaultValueAsString(bool quote_string_type) const;
|
||||
|
||||
// Walks up the descriptor tree to generate the source location path
|
||||
// to this descriptor from the file root.
|
||||
void GetLocationPath(vector<int>* output) const;
|
||||
|
||||
const string* name_;
|
||||
const string* full_name_;
|
||||
const string* lowercase_name_;
|
||||
@ -527,6 +572,8 @@ class LIBPROTOBUF_EXPORT FieldDescriptor {
|
||||
|
||||
static const char * const kTypeToName[MAX_TYPE + 1];
|
||||
|
||||
static const char * const kCppTypeToName[MAX_CPPTYPE + 1];
|
||||
|
||||
static const char * const kLabelToName[MAX_LABEL + 1];
|
||||
|
||||
// Must be constructed using DescriptorPool.
|
||||
@ -583,12 +630,23 @@ class LIBPROTOBUF_EXPORT EnumDescriptor {
|
||||
// See Descriptor::DebugString().
|
||||
string DebugString() const;
|
||||
|
||||
// Source Location ---------------------------------------------------
|
||||
|
||||
// Updates |*out_location| to the source location of the complete
|
||||
// extent of this enum declaration. Returns false and leaves
|
||||
// |*out_location| unchanged iff location information was not available.
|
||||
bool GetSourceLocation(SourceLocation* out_location) const;
|
||||
|
||||
private:
|
||||
typedef EnumOptions OptionsType;
|
||||
|
||||
// See Descriptor::DebugString().
|
||||
void DebugString(int depth, string *contents) const;
|
||||
|
||||
// Walks up the descriptor tree to generate the source location path
|
||||
// to this descriptor from the file root.
|
||||
void GetLocationPath(vector<int>* output) const;
|
||||
|
||||
const string* name_;
|
||||
const string* full_name_;
|
||||
const FileDescriptor* file_;
|
||||
@ -650,12 +708,23 @@ class LIBPROTOBUF_EXPORT EnumValueDescriptor {
|
||||
// See Descriptor::DebugString().
|
||||
string DebugString() const;
|
||||
|
||||
// Source Location ---------------------------------------------------
|
||||
|
||||
// Updates |*out_location| to the source location of the complete
|
||||
// extent of this enum value declaration. Returns false and leaves
|
||||
// |*out_location| unchanged iff location information was not available.
|
||||
bool GetSourceLocation(SourceLocation* out_location) const;
|
||||
|
||||
private:
|
||||
typedef EnumValueOptions OptionsType;
|
||||
|
||||
// See Descriptor::DebugString().
|
||||
void DebugString(int depth, string *contents) const;
|
||||
|
||||
// Walks up the descriptor tree to generate the source location path
|
||||
// to this descriptor from the file root.
|
||||
void GetLocationPath(vector<int>* output) const;
|
||||
|
||||
const string* name_;
|
||||
const string* full_name_;
|
||||
int number_;
|
||||
@ -703,19 +772,29 @@ class LIBPROTOBUF_EXPORT ServiceDescriptor {
|
||||
|
||||
// Look up a MethodDescriptor by name.
|
||||
const MethodDescriptor* FindMethodByName(const string& name) const;
|
||||
|
||||
// See Descriptor::CopyTo().
|
||||
void CopyTo(ServiceDescriptorProto* proto) const;
|
||||
|
||||
// See Descriptor::DebugString().
|
||||
string DebugString() const;
|
||||
|
||||
// Source Location ---------------------------------------------------
|
||||
|
||||
// Updates |*out_location| to the source location of the complete
|
||||
// extent of this service declaration. Returns false and leaves
|
||||
// |*out_location| unchanged iff location information was not available.
|
||||
bool GetSourceLocation(SourceLocation* out_location) const;
|
||||
|
||||
private:
|
||||
typedef ServiceOptions OptionsType;
|
||||
|
||||
// See Descriptor::DebugString().
|
||||
void DebugString(string *contents) const;
|
||||
|
||||
// Walks up the descriptor tree to generate the source location path
|
||||
// to this descriptor from the file root.
|
||||
void GetLocationPath(vector<int>* output) const;
|
||||
|
||||
const string* name_;
|
||||
const string* full_name_;
|
||||
const FileDescriptor* file_;
|
||||
@ -768,12 +847,23 @@ class LIBPROTOBUF_EXPORT MethodDescriptor {
|
||||
// See Descriptor::DebugString().
|
||||
string DebugString() const;
|
||||
|
||||
// Source Location ---------------------------------------------------
|
||||
|
||||
// Updates |*out_location| to the source location of the complete
|
||||
// extent of this method declaration. Returns false and leaves
|
||||
// |*out_location| unchanged iff location information was not available.
|
||||
bool GetSourceLocation(SourceLocation* out_location) const;
|
||||
|
||||
private:
|
||||
typedef MethodOptions OptionsType;
|
||||
|
||||
// See Descriptor::DebugString().
|
||||
void DebugString(int depth, string *contents) const;
|
||||
|
||||
// Walks up the descriptor tree to generate the source location path
|
||||
// to this descriptor from the file root.
|
||||
void GetLocationPath(vector<int>* output) const;
|
||||
|
||||
const string* name_;
|
||||
const string* full_name_;
|
||||
const ServiceDescriptor* service_;
|
||||
@ -791,6 +881,7 @@ class LIBPROTOBUF_EXPORT MethodDescriptor {
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MethodDescriptor);
|
||||
};
|
||||
|
||||
|
||||
// Describes a whole .proto file. To get the FileDescriptor for a compiled-in
|
||||
// file, get the descriptor for something defined in that file and call
|
||||
// descriptor->file(). Use DescriptorPool to construct your own descriptors.
|
||||
@ -813,6 +904,22 @@ class LIBPROTOBUF_EXPORT FileDescriptor {
|
||||
// These are returned in the order they were defined in the .proto file.
|
||||
const FileDescriptor* dependency(int index) const;
|
||||
|
||||
// The number of files public imported by this one.
|
||||
// The public dependency list is a subset of the dependency list.
|
||||
int public_dependency_count() const;
|
||||
// Gets a public imported file by index, where 0 <= index <
|
||||
// public_dependency_count().
|
||||
// These are returned in the order they were defined in the .proto file.
|
||||
const FileDescriptor* public_dependency(int index) const;
|
||||
|
||||
// The number of files that are imported for weak fields.
|
||||
// The weak dependency list is a subset of the dependency list.
|
||||
int weak_dependency_count() const;
|
||||
// Gets a weak imported file by index, where 0 <= index <
|
||||
// weak_dependency_count().
|
||||
// These are returned in the order they were defined in the .proto file.
|
||||
const FileDescriptor* weak_dependency(int index) const;
|
||||
|
||||
// Number of top-level message types defined in this file. (This does not
|
||||
// include nested types.)
|
||||
int message_type_count() const;
|
||||
@ -866,12 +973,28 @@ class LIBPROTOBUF_EXPORT FileDescriptor {
|
||||
const FieldDescriptor* FindExtensionByCamelcaseName(const string& name) const;
|
||||
|
||||
// See Descriptor::CopyTo().
|
||||
// Notes:
|
||||
// - This method does NOT copy source code information since it is relatively
|
||||
// large and rarely needed. See CopySourceCodeInfoTo() below.
|
||||
void CopyTo(FileDescriptorProto* proto) const;
|
||||
// Write the source code information of this FileDescriptor into the given
|
||||
// FileDescriptorProto. See CopyTo() above.
|
||||
void CopySourceCodeInfoTo(FileDescriptorProto* proto) const;
|
||||
|
||||
// See Descriptor::DebugString().
|
||||
string DebugString() const;
|
||||
|
||||
private:
|
||||
// Source Location ---------------------------------------------------
|
||||
|
||||
// Updates |*out_location| to the source location of the complete
|
||||
// extent of the declaration or declaration-part denoted by |path|.
|
||||
// Returns false and leaves |*out_location| unchanged iff location
|
||||
// information was not available. (See SourceCodeInfo for
|
||||
// description of path encoding.)
|
||||
bool GetSourceLocation(const vector<int>& path,
|
||||
SourceLocation* out_location) const;
|
||||
|
||||
typedef FileOptions OptionsType;
|
||||
|
||||
const string* name_;
|
||||
@ -879,6 +1002,10 @@ class LIBPROTOBUF_EXPORT FileDescriptor {
|
||||
const DescriptorPool* pool_;
|
||||
int dependency_count_;
|
||||
const FileDescriptor** dependencies_;
|
||||
int public_dependency_count_;
|
||||
int* public_dependencies_;
|
||||
int weak_dependency_count_;
|
||||
int* weak_dependencies_;
|
||||
int message_type_count_;
|
||||
Descriptor* message_types_;
|
||||
int enum_type_count_;
|
||||
@ -890,6 +1017,7 @@ class LIBPROTOBUF_EXPORT FileDescriptor {
|
||||
const FileOptions* options_;
|
||||
|
||||
const FileDescriptorTables* tables_;
|
||||
const SourceCodeInfo* source_code_info_;
|
||||
// IMPORTANT: If you add a new field, make sure to search for all instances
|
||||
// of Allocate<FileDescriptor>() and AllocateArray<FileDescriptor>() in
|
||||
// descriptor.cc and update them to initialize the field.
|
||||
@ -899,6 +1027,8 @@ class LIBPROTOBUF_EXPORT FileDescriptor {
|
||||
friend class Descriptor;
|
||||
friend class FieldDescriptor;
|
||||
friend class EnumDescriptor;
|
||||
friend class EnumValueDescriptor;
|
||||
friend class MethodDescriptor;
|
||||
friend class ServiceDescriptor;
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileDescriptor);
|
||||
};
|
||||
@ -1106,7 +1236,7 @@ class LIBPROTOBUF_EXPORT DescriptorPool {
|
||||
// For internal use only: Gets a non-const pointer to the generated pool.
|
||||
// This is called at static-initialization time only, so thread-safety is
|
||||
// not a concern. If both an underlay and a fallback database are present,
|
||||
// the fallback database takes precedence.
|
||||
// the underlay takes precedence.
|
||||
static DescriptorPool* internal_generated_pool();
|
||||
|
||||
// For internal use only: Changes the behavior of BuildFile() such that it
|
||||
@ -1132,6 +1262,11 @@ class LIBPROTOBUF_EXPORT DescriptorPool {
|
||||
friend class FileDescriptor;
|
||||
friend class DescriptorBuilder;
|
||||
|
||||
// Return true if the given name is a sub-symbol of any non-package
|
||||
// descriptor that already exists in the descriptor pool. (The full
|
||||
// definition of such types is already known.)
|
||||
bool IsSubSymbolOfBuiltType(const string& name) const;
|
||||
|
||||
// Tries to find something in the fallback database and link in the
|
||||
// corresponding proto file. Returns true if successful, in which case
|
||||
// the caller should search for the thing again. These are declared
|
||||
@ -1203,7 +1338,7 @@ PROTOBUF_DEFINE_ARRAY_ACCESSOR(Descriptor, extension_range,
|
||||
const Descriptor::ExtensionRange*)
|
||||
PROTOBUF_DEFINE_ARRAY_ACCESSOR(Descriptor, extension,
|
||||
const FieldDescriptor*)
|
||||
PROTOBUF_DEFINE_OPTIONS_ACCESSOR(Descriptor, MessageOptions);
|
||||
PROTOBUF_DEFINE_OPTIONS_ACCESSOR(Descriptor, MessageOptions)
|
||||
|
||||
PROTOBUF_DEFINE_STRING_ACCESSOR(FieldDescriptor, name)
|
||||
PROTOBUF_DEFINE_STRING_ACCESSOR(FieldDescriptor, full_name)
|
||||
@ -1220,7 +1355,7 @@ PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, message_type, const Descriptor*)
|
||||
PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, enum_type, const EnumDescriptor*)
|
||||
PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, experimental_map_key,
|
||||
const FieldDescriptor*)
|
||||
PROTOBUF_DEFINE_OPTIONS_ACCESSOR(FieldDescriptor, FieldOptions);
|
||||
PROTOBUF_DEFINE_OPTIONS_ACCESSOR(FieldDescriptor, FieldOptions)
|
||||
PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, has_default_value, bool)
|
||||
PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, default_value_int32 , int32 )
|
||||
PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, default_value_int64 , int64 )
|
||||
@ -1240,13 +1375,13 @@ PROTOBUF_DEFINE_ACCESSOR(EnumDescriptor, containing_type, const Descriptor*)
|
||||
PROTOBUF_DEFINE_ACCESSOR(EnumDescriptor, value_count, int)
|
||||
PROTOBUF_DEFINE_ARRAY_ACCESSOR(EnumDescriptor, value,
|
||||
const EnumValueDescriptor*)
|
||||
PROTOBUF_DEFINE_OPTIONS_ACCESSOR(EnumDescriptor, EnumOptions);
|
||||
PROTOBUF_DEFINE_OPTIONS_ACCESSOR(EnumDescriptor, EnumOptions)
|
||||
|
||||
PROTOBUF_DEFINE_STRING_ACCESSOR(EnumValueDescriptor, name)
|
||||
PROTOBUF_DEFINE_STRING_ACCESSOR(EnumValueDescriptor, full_name)
|
||||
PROTOBUF_DEFINE_ACCESSOR(EnumValueDescriptor, number, int)
|
||||
PROTOBUF_DEFINE_ACCESSOR(EnumValueDescriptor, type, const EnumDescriptor*)
|
||||
PROTOBUF_DEFINE_OPTIONS_ACCESSOR(EnumValueDescriptor, EnumValueOptions);
|
||||
PROTOBUF_DEFINE_OPTIONS_ACCESSOR(EnumValueDescriptor, EnumValueOptions)
|
||||
|
||||
PROTOBUF_DEFINE_STRING_ACCESSOR(ServiceDescriptor, name)
|
||||
PROTOBUF_DEFINE_STRING_ACCESSOR(ServiceDescriptor, full_name)
|
||||
@ -1254,24 +1389,25 @@ PROTOBUF_DEFINE_ACCESSOR(ServiceDescriptor, file, const FileDescriptor*)
|
||||
PROTOBUF_DEFINE_ACCESSOR(ServiceDescriptor, method_count, int)
|
||||
PROTOBUF_DEFINE_ARRAY_ACCESSOR(ServiceDescriptor, method,
|
||||
const MethodDescriptor*)
|
||||
PROTOBUF_DEFINE_OPTIONS_ACCESSOR(ServiceDescriptor, ServiceOptions);
|
||||
PROTOBUF_DEFINE_OPTIONS_ACCESSOR(ServiceDescriptor, ServiceOptions)
|
||||
|
||||
PROTOBUF_DEFINE_STRING_ACCESSOR(MethodDescriptor, name)
|
||||
PROTOBUF_DEFINE_STRING_ACCESSOR(MethodDescriptor, full_name)
|
||||
PROTOBUF_DEFINE_ACCESSOR(MethodDescriptor, service, const ServiceDescriptor*)
|
||||
PROTOBUF_DEFINE_ACCESSOR(MethodDescriptor, input_type, const Descriptor*)
|
||||
PROTOBUF_DEFINE_ACCESSOR(MethodDescriptor, output_type, const Descriptor*)
|
||||
PROTOBUF_DEFINE_OPTIONS_ACCESSOR(MethodDescriptor, MethodOptions);
|
||||
|
||||
PROTOBUF_DEFINE_OPTIONS_ACCESSOR(MethodDescriptor, MethodOptions)
|
||||
PROTOBUF_DEFINE_STRING_ACCESSOR(FileDescriptor, name)
|
||||
PROTOBUF_DEFINE_STRING_ACCESSOR(FileDescriptor, package)
|
||||
PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, pool, const DescriptorPool*)
|
||||
PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, dependency_count, int)
|
||||
PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, public_dependency_count, int)
|
||||
PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, weak_dependency_count, int)
|
||||
PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, message_type_count, int)
|
||||
PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, enum_type_count, int)
|
||||
PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, service_count, int)
|
||||
PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, extension_count, int)
|
||||
PROTOBUF_DEFINE_OPTIONS_ACCESSOR(FileDescriptor, FileOptions);
|
||||
PROTOBUF_DEFINE_OPTIONS_ACCESSOR(FileDescriptor, FileOptions)
|
||||
|
||||
PROTOBUF_DEFINE_ARRAY_ACCESSOR(FileDescriptor, message_type, const Descriptor*)
|
||||
PROTOBUF_DEFINE_ARRAY_ACCESSOR(FileDescriptor, enum_type, const EnumDescriptor*)
|
||||
@ -1342,10 +1478,18 @@ inline int MethodDescriptor::index() const {
|
||||
return this - service_->methods_;
|
||||
}
|
||||
|
||||
inline const char* FieldDescriptor::type_name() const {
|
||||
return kTypeToName[type_];
|
||||
}
|
||||
|
||||
inline FieldDescriptor::CppType FieldDescriptor::cpp_type() const {
|
||||
return kTypeToCppTypeMap[type_];
|
||||
}
|
||||
|
||||
inline const char* FieldDescriptor::cpp_type_name() const {
|
||||
return kCppTypeToName[kTypeToCppTypeMap[type_]];
|
||||
}
|
||||
|
||||
inline FieldDescriptor::CppType FieldDescriptor::TypeToCppType(Type type) {
|
||||
return kTypeToCppTypeMap[type];
|
||||
}
|
||||
@ -1361,6 +1505,16 @@ inline const FileDescriptor* FileDescriptor::dependency(int index) const {
|
||||
return dependencies_[index];
|
||||
}
|
||||
|
||||
inline const FileDescriptor* FileDescriptor::public_dependency(
|
||||
int index) const {
|
||||
return dependencies_[public_dependencies_[index]];
|
||||
}
|
||||
|
||||
inline const FileDescriptor* FileDescriptor::weak_dependency(
|
||||
int index) const {
|
||||
return dependencies_[weak_dependencies_[index]];
|
||||
}
|
||||
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -59,6 +59,11 @@ message FileDescriptorProto {
|
||||
|
||||
// Names of files imported by this file.
|
||||
repeated string dependency = 3;
|
||||
// Indexes of the public imported files in the dependency list above.
|
||||
repeated int32 public_dependency = 10;
|
||||
// Indexes of the weak imported files in the dependency list.
|
||||
// For Google-internal migration only. Do not use.
|
||||
repeated int32 weak_dependency = 11;
|
||||
|
||||
// All top-level definitions in this file.
|
||||
repeated DescriptorProto message_type = 4;
|
||||
@ -67,6 +72,12 @@ message FileDescriptorProto {
|
||||
repeated FieldDescriptorProto extension = 7;
|
||||
|
||||
optional FileOptions options = 8;
|
||||
|
||||
// This field contains optional information about the original source code.
|
||||
// You may safely remove this entire field whithout harming runtime
|
||||
// functionality of the descriptors -- the information is needed only by
|
||||
// development tools.
|
||||
optional SourceCodeInfo source_code_info = 9;
|
||||
}
|
||||
|
||||
// Describes a message type.
|
||||
@ -95,13 +106,13 @@ message FieldDescriptorProto {
|
||||
// Order is weird for historical reasons.
|
||||
TYPE_DOUBLE = 1;
|
||||
TYPE_FLOAT = 2;
|
||||
TYPE_INT64 = 3; // Not ZigZag encoded. Negative numbers
|
||||
// take 10 bytes. Use TYPE_SINT64 if negative
|
||||
// values are likely.
|
||||
// Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT64 if
|
||||
// negative values are likely.
|
||||
TYPE_INT64 = 3;
|
||||
TYPE_UINT64 = 4;
|
||||
TYPE_INT32 = 5; // Not ZigZag encoded. Negative numbers
|
||||
// take 10 bytes. Use TYPE_SINT32 if negative
|
||||
// values are likely.
|
||||
// Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT32 if
|
||||
// negative values are likely.
|
||||
TYPE_INT32 = 5;
|
||||
TYPE_FIXED64 = 6;
|
||||
TYPE_FIXED32 = 7;
|
||||
TYPE_BOOL = 8;
|
||||
@ -193,6 +204,7 @@ message MethodDescriptorProto {
|
||||
optional MethodOptions options = 4;
|
||||
}
|
||||
|
||||
|
||||
// ===================================================================
|
||||
// Options
|
||||
|
||||
@ -214,10 +226,15 @@ message MethodDescriptorProto {
|
||||
// through 99999. It is up to you to ensure that you do not use the
|
||||
// same number for multiple options.
|
||||
// * For options which will be published and used publicly by multiple
|
||||
// independent entities, e-mail kenton@google.com to reserve extension
|
||||
// numbers. Simply tell me how many you need and I'll send you back a
|
||||
// set of numbers to use -- there's no need to explain how you intend to
|
||||
// use them. If this turns out to be popular, a web service will be set up
|
||||
// independent entities, e-mail protobuf-global-extension-registry@google.com
|
||||
// to reserve extension numbers. Simply provide your project name (e.g.
|
||||
// Object-C plugin) and your porject website (if available) -- there's no need
|
||||
// to explain how you intend to use them. Usually you only need one extension
|
||||
// number. You can declare multiple options with only one extension number by
|
||||
// putting them in a sub-message. See the Custom Options section of the docs
|
||||
// for examples:
|
||||
// http://code.google.com/apis/protocolbuffers/docs/proto.html#options
|
||||
// If this turns out to be popular, a web service will be set up
|
||||
// to automatically assign option numbers.
|
||||
|
||||
|
||||
@ -245,6 +262,12 @@ message FileOptions {
|
||||
// top-level extensions defined in the file.
|
||||
optional bool java_multiple_files = 10 [default=false];
|
||||
|
||||
// If set true, then the Java code generator will generate equals() and
|
||||
// hashCode() methods for all messages defined in the .proto file. This is
|
||||
// purely a speed optimization, as the AbstractMessage base class includes
|
||||
// reflection-based implementations of these methods.
|
||||
optional bool java_generate_equals_and_hash = 20 [default=false];
|
||||
|
||||
// Generated classes can be optimized for speed or code size.
|
||||
enum OptimizeMode {
|
||||
SPEED = 1; // Generate complete code for parsing, serialization,
|
||||
@ -254,6 +277,9 @@ message FileOptions {
|
||||
}
|
||||
optional OptimizeMode optimize_for = 9 [default=SPEED];
|
||||
|
||||
// Sets the Go package where structs generated from this .proto will be
|
||||
// placed. There is no default.
|
||||
optional string go_package = 11;
|
||||
|
||||
|
||||
|
||||
@ -264,13 +290,12 @@ message FileOptions {
|
||||
// early versions of proto2.
|
||||
//
|
||||
// Generic services are now considered deprecated in favor of using plugins
|
||||
// that generate code specific to your particular RPC system. If you are
|
||||
// using such a plugin, set these to false. In the future, we may change
|
||||
// the default to false, so if you explicitly want generic services, you
|
||||
// should explicitly set these to true.
|
||||
optional bool cc_generic_services = 16 [default=true];
|
||||
optional bool java_generic_services = 17 [default=true];
|
||||
optional bool py_generic_services = 18 [default=true];
|
||||
// that generate code specific to your particular RPC system. Therefore,
|
||||
// these default to false. Old code which depends on generic services should
|
||||
// explicitly set them to true.
|
||||
optional bool cc_generic_services = 16 [default=false];
|
||||
optional bool java_generic_services = 17 [default=false];
|
||||
optional bool py_generic_services = 18 [default=false];
|
||||
|
||||
// The parser stores options it doesn't recognize here. See above.
|
||||
repeated UninterpretedOption uninterpreted_option = 999;
|
||||
@ -333,6 +358,37 @@ message FieldOptions {
|
||||
optional bool packed = 2;
|
||||
|
||||
|
||||
|
||||
// Should this field be parsed lazily? Lazy applies only to message-type
|
||||
// fields. It means that when the outer message is initially parsed, the
|
||||
// inner message's contents will not be parsed but instead stored in encoded
|
||||
// form. The inner message will actually be parsed when it is first accessed.
|
||||
//
|
||||
// This is only a hint. Implementations are free to choose whether to use
|
||||
// eager or lazy parsing regardless of the value of this option. However,
|
||||
// setting this option true suggests that the protocol author believes that
|
||||
// using lazy parsing on this field is worth the additional bookkeeping
|
||||
// overhead typically needed to implement it.
|
||||
//
|
||||
// This option does not affect the public interface of any generated code;
|
||||
// all method signatures remain the same. Furthermore, thread-safety of the
|
||||
// interface is not affected by this option; const methods remain safe to
|
||||
// call from multiple threads concurrently, while non-const methods continue
|
||||
// to require exclusive access.
|
||||
//
|
||||
//
|
||||
// Note that implementations may choose not to check required fields within
|
||||
// a lazy sub-message. That is, calling IsInitialized() on the outher message
|
||||
// may return true even if the inner message has missing required fields.
|
||||
// This is necessary because otherwise the inner message would have to be
|
||||
// parsed in order to perform the check, defeating the purpose of lazy
|
||||
// parsing. An implementation which chooses not to check required fields
|
||||
// must be consistent about it. That is, for any particular sub-message, the
|
||||
// implementation must either *always* check its required fields, or *never*
|
||||
// check its required fields, regardless of whether or not the message has
|
||||
// been parsed.
|
||||
optional bool lazy = 5 [default=false];
|
||||
|
||||
// Is this field deprecated?
|
||||
// Depending on the target platform, this can emit Deprecated annotations
|
||||
// for accessors, or it will be completely ignored; in the very least, this
|
||||
@ -353,6 +409,9 @@ message FieldOptions {
|
||||
// TODO: Fully-implement this, then remove the "experimental_" prefix.
|
||||
optional string experimental_map_key = 9;
|
||||
|
||||
// For Google-internal migration only. Do not use.
|
||||
optional bool weak = 10 [default=false];
|
||||
|
||||
// The parser stores options it doesn't recognize here. See above.
|
||||
repeated UninterpretedOption uninterpreted_option = 999;
|
||||
|
||||
@ -362,6 +421,10 @@ message FieldOptions {
|
||||
|
||||
message EnumOptions {
|
||||
|
||||
// Set this option to false to disallow mapping different tag names to a same
|
||||
// value.
|
||||
optional bool allow_alias = 2 [default=true];
|
||||
|
||||
// The parser stores options it doesn't recognize here. See above.
|
||||
repeated UninterpretedOption uninterpreted_option = 999;
|
||||
|
||||
@ -405,6 +468,7 @@ message MethodOptions {
|
||||
extensions 1000 to max;
|
||||
}
|
||||
|
||||
|
||||
// A message representing a option the parser does not recognize. This only
|
||||
// appears in options protos created by the compiler::Parser class.
|
||||
// DescriptorPool resolves these when building Descriptor objects. Therefore,
|
||||
@ -430,4 +494,127 @@ message UninterpretedOption {
|
||||
optional int64 negative_int_value = 5;
|
||||
optional double double_value = 6;
|
||||
optional bytes string_value = 7;
|
||||
optional string aggregate_value = 8;
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
// Optional source code info
|
||||
|
||||
// Encapsulates information about the original source file from which a
|
||||
// FileDescriptorProto was generated.
|
||||
message SourceCodeInfo {
|
||||
// A Location identifies a piece of source code in a .proto file which
|
||||
// corresponds to a particular definition. This information is intended
|
||||
// to be useful to IDEs, code indexers, documentation generators, and similar
|
||||
// tools.
|
||||
//
|
||||
// For example, say we have a file like:
|
||||
// message Foo {
|
||||
// optional string foo = 1;
|
||||
// }
|
||||
// Let's look at just the field definition:
|
||||
// optional string foo = 1;
|
||||
// ^ ^^ ^^ ^ ^^^
|
||||
// a bc de f ghi
|
||||
// We have the following locations:
|
||||
// span path represents
|
||||
// [a,i) [ 4, 0, 2, 0 ] The whole field definition.
|
||||
// [a,b) [ 4, 0, 2, 0, 4 ] The label (optional).
|
||||
// [c,d) [ 4, 0, 2, 0, 5 ] The type (string).
|
||||
// [e,f) [ 4, 0, 2, 0, 1 ] The name (foo).
|
||||
// [g,h) [ 4, 0, 2, 0, 3 ] The number (1).
|
||||
//
|
||||
// Notes:
|
||||
// - A location may refer to a repeated field itself (i.e. not to any
|
||||
// particular index within it). This is used whenever a set of elements are
|
||||
// logically enclosed in a single code segment. For example, an entire
|
||||
// extend block (possibly containing multiple extension definitions) will
|
||||
// have an outer location whose path refers to the "extensions" repeated
|
||||
// field without an index.
|
||||
// - Multiple locations may have the same path. This happens when a single
|
||||
// logical declaration is spread out across multiple places. The most
|
||||
// obvious example is the "extend" block again -- there may be multiple
|
||||
// extend blocks in the same scope, each of which will have the same path.
|
||||
// - A location's span is not always a subset of its parent's span. For
|
||||
// example, the "extendee" of an extension declaration appears at the
|
||||
// beginning of the "extend" block and is shared by all extensions within
|
||||
// the block.
|
||||
// - Just because a location's span is a subset of some other location's span
|
||||
// does not mean that it is a descendent. For example, a "group" defines
|
||||
// both a type and a field in a single declaration. Thus, the locations
|
||||
// corresponding to the type and field and their components will overlap.
|
||||
// - Code which tries to interpret locations should probably be designed to
|
||||
// ignore those that it doesn't understand, as more types of locations could
|
||||
// be recorded in the future.
|
||||
repeated Location location = 1;
|
||||
message Location {
|
||||
// Identifies which part of the FileDescriptorProto was defined at this
|
||||
// location.
|
||||
//
|
||||
// Each element is a field number or an index. They form a path from
|
||||
// the root FileDescriptorProto to the place where the definition. For
|
||||
// example, this path:
|
||||
// [ 4, 3, 2, 7, 1 ]
|
||||
// refers to:
|
||||
// file.message_type(3) // 4, 3
|
||||
// .field(7) // 2, 7
|
||||
// .name() // 1
|
||||
// This is because FileDescriptorProto.message_type has field number 4:
|
||||
// repeated DescriptorProto message_type = 4;
|
||||
// and DescriptorProto.field has field number 2:
|
||||
// repeated FieldDescriptorProto field = 2;
|
||||
// and FieldDescriptorProto.name has field number 1:
|
||||
// optional string name = 1;
|
||||
//
|
||||
// Thus, the above path gives the location of a field name. If we removed
|
||||
// the last element:
|
||||
// [ 4, 3, 2, 7 ]
|
||||
// this path refers to the whole field declaration (from the beginning
|
||||
// of the label to the terminating semicolon).
|
||||
repeated int32 path = 1 [packed=true];
|
||||
|
||||
// Always has exactly three or four elements: start line, start column,
|
||||
// end line (optional, otherwise assumed same as start line), end column.
|
||||
// These are packed into a single field for efficiency. Note that line
|
||||
// and column numbers are zero-based -- typically you will want to add
|
||||
// 1 to each before displaying to a user.
|
||||
repeated int32 span = 2 [packed=true];
|
||||
|
||||
// If this SourceCodeInfo represents a complete declaration, these are any
|
||||
// comments appearing before and after the declaration which appear to be
|
||||
// attached to the declaration.
|
||||
//
|
||||
// A series of line comments appearing on consecutive lines, with no other
|
||||
// tokens appearing on those lines, will be treated as a single comment.
|
||||
//
|
||||
// Only the comment content is provided; comment markers (e.g. //) are
|
||||
// stripped out. For block comments, leading whitespace and an asterisk
|
||||
// will be stripped from the beginning of each line other than the first.
|
||||
// Newlines are included in the output.
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// optional int32 foo = 1; // Comment attached to foo.
|
||||
// // Comment attached to bar.
|
||||
// optional int32 bar = 2;
|
||||
//
|
||||
// optional string baz = 3;
|
||||
// // Comment attached to baz.
|
||||
// // Another line attached to baz.
|
||||
//
|
||||
// // Comment attached to qux.
|
||||
// //
|
||||
// // Another line attached to qux.
|
||||
// optional double qux = 4;
|
||||
//
|
||||
// optional string corge = 5;
|
||||
// /* Block comment attached
|
||||
// * to corge. Leading asterisks
|
||||
// * will be removed. */
|
||||
// /* Block comment attached to
|
||||
// * grault. */
|
||||
// optional int32 grault = 6;
|
||||
optional string leading_comments = 3;
|
||||
optional string trailing_comments = 4;
|
||||
}
|
||||
}
|
@ -39,7 +39,7 @@
|
||||
#include <google/protobuf/descriptor.pb.h>
|
||||
#include <google/protobuf/wire_format_lite_inl.h>
|
||||
#include <google/protobuf/stubs/strutil.h>
|
||||
#include <google/protobuf/stubs/stl_util-inl.h>
|
||||
#include <google/protobuf/stubs/stl_util.h>
|
||||
#include <google/protobuf/stubs/map-util.h>
|
||||
|
||||
namespace google {
|
||||
@ -101,7 +101,7 @@ bool SimpleDescriptorDatabase::DescriptorIndex<Value>::AddSymbol(
|
||||
|
||||
if (iter == by_symbol_.end()) {
|
||||
// Apparently the map is currently empty. Just insert and be done with it.
|
||||
by_symbol_.insert(make_pair(name, value));
|
||||
by_symbol_.insert(typename map<string, Value>::value_type(name, value));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -128,7 +128,7 @@ bool SimpleDescriptorDatabase::DescriptorIndex<Value>::AddSymbol(
|
||||
|
||||
// Insert the new symbol using the iterator as a hint, the new entry will
|
||||
// appear immediately before the one the iterator is pointing at.
|
||||
by_symbol_.insert(iter, make_pair(name, value));
|
||||
by_symbol_.insert(iter, typename map<string, Value>::value_type(name, value));
|
||||
|
||||
return true;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user