1
0
mirror of https://github.com/alliedmodders/hl2sdk.git synced 2024-12-22 17:47:38 +08:00

Update protobuf source from v2.3.0 to 2.5.0.

This commit is contained in:
Nicholas Hastings 2014-09-01 11:12:42 -04:00
parent 486133fea8
commit 2d3cc15cd4
229 changed files with 26776 additions and 7210 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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) {

View File

@ -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.,

View File

@ -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);
}
}

View File

@ -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_;

View File

@ -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");
}

View File

@ -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

View File

@ -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,

View File

@ -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);
};

View File

@ -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_,

View File

@ -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 ---------------------------------------

View File

@ -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";

View File

@ -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);
};

View File

@ -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);
}
}
}

View File

@ -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);
};

View File

@ -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()));
}

View File

@ -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);
};

View File

@ -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);
}

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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(

View File

@ -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_;

View File

@ -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"

View File

@ -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 ---------------------------------------

View File

@ -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__

View File

@ -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);
}

View File

@ -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_,

View File

@ -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 ---------------------------------------

View File

@ -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 + " ";
}
}

View File

@ -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.

View File

@ -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");
}
}

View File

@ -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 ---------------------------------------

View File

@ -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 {

View File

@ -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) {

View File

@ -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__

View File

@ -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;

View File

@ -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_;

View File

@ -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("&#42;");
} else {
result.push_back(c);
}
break;
case '/':
// Avoid "*/".
if (prev == '*') {
result.append("&#47;");
} else {
result.push_back(c);
}
break;
case '@':
// "{@" starts Javadoc markup.
if (prev == '{') {
result.append("&#64;");
} else {
result.push_back(c);
}
break;
case '<':
// Avoid interpretation as HTML.
result.append("&lt;");
break;
case '>':
// Avoid interpretation as HTML.
result.append("&gt;");
break;
case '&':
// Avoid interpretation as HTML.
result.append("&amp;");
break;
case '\\':
// Java interprets Unicode escape sequences anywhere!
result.append("&#92;");
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

View File

@ -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__

View File

@ -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 /&#42; bar *&#47; baz", EscapeJavadoc("foo /* bar */ baz"));
EXPECT_EQ("foo /&#42;&#47; baz", EscapeJavadoc("foo /*/ baz"));
EXPECT_EQ("{&#64;foo}", EscapeJavadoc("{@foo}"));
EXPECT_EQ("&lt;i&gt;&amp;&lt;/i&gt;", EscapeJavadoc("<i>&</i>"));
EXPECT_EQ("foo&#92;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

View File

@ -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

View File

@ -73,6 +73,8 @@ class EnumGenerator {
};
vector<Alias> aliases_;
bool CanUseEnumValues();
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumGenerator);
};

View File

@ -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

View File

@ -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);
};

View File

@ -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()));
}
}

View File

@ -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:

View File

@ -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);
}
}
}

View File

@ -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);
};

View File

@ -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);
}
}
}

View File

@ -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);

View File

@ -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]);

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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_;

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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);
};

View File

@ -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");
}

View File

@ -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

View File

@ -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__

View File

@ -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

View File

@ -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

View File

@ -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);
};

File diff suppressed because it is too large Load Diff

View File

@ -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();

View File

@ -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 "

View File

@ -56,7 +56,6 @@
#define GOOGLE_PROTOBUF_COMPILER_PLUGIN_H__
#include <google/protobuf/stubs/common.h>
namespace google {
namespace protobuf {
namespace compiler {

View File

@ -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;
}

View File

@ -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 {

View File

@ -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.
//

View File

@ -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

View File

@ -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_;

View File

@ -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);
}

View File

@ -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.

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;
}
}

View File

@ -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