blob: 7a2b4a068da92d68ce59e26dee30a13bf86b26c0 [file] [log] [blame]
// 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 <algorithm>
#include <google/protobuf/stubs/hash.h>
#include <google/protobuf/compiler/javanano/javanano_message.h>
#include <google/protobuf/compiler/javanano/javanano_enum.h>
#include <google/protobuf/compiler/javanano/javanano_extension.h>
#include <google/protobuf/compiler/javanano/javanano_helpers.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/wire_format.h>
#include <google/protobuf/descriptor.pb.h>
namespace google {
namespace protobuf {
namespace compiler {
namespace javanano {
using internal::WireFormat;
using internal::WireFormatLite;
namespace {
struct FieldOrderingByNumber {
inline bool operator()(const FieldDescriptor* a,
const FieldDescriptor* b) const {
return a->number() < b->number();
}
};
// Sort the fields of the given Descriptor by number into a new[]'d array
// and return it.
const FieldDescriptor** SortFieldsByNumber(const Descriptor* descriptor) {
const FieldDescriptor** fields =
new const FieldDescriptor*[descriptor->field_count()];
for (int i = 0; i < descriptor->field_count(); i++) {
fields[i] = descriptor->field(i);
}
sort(fields, fields + descriptor->field_count(),
FieldOrderingByNumber());
return fields;
}
} // namespace
// ===================================================================
MessageGenerator::MessageGenerator(const Descriptor* descriptor, const Params& params)
: params_(params),
descriptor_(descriptor),
field_generators_(descriptor, params) {
}
MessageGenerator::~MessageGenerator() {}
void MessageGenerator::GenerateStaticVariables(io::Printer* printer) {
// Generate static members for all nested types.
for (int i = 0; i < descriptor_->nested_type_count(); i++) {
// TODO(kenton): Reuse MessageGenerator objects?
MessageGenerator(descriptor_->nested_type(i), params_)
.GenerateStaticVariables(printer);
}
}
void MessageGenerator::GenerateStaticVariableInitializers(
io::Printer* printer) {
// Generate static member initializers for all nested types.
for (int i = 0; i < descriptor_->nested_type_count(); i++) {
// TODO(kenton): Reuse MessageGenerator objects?
MessageGenerator(descriptor_->nested_type(i), params_)
.GenerateStaticVariableInitializers(printer);
}
}
void MessageGenerator::Generate(io::Printer* printer) {
if (!params_.store_unknown_fields() &&
(descriptor_->extension_count() != 0 || descriptor_->extension_range_count() != 0)) {
GOOGLE_LOG(FATAL) << "Extensions are only supported in NANO_RUNTIME if the "
"'store_unknown_fields' generator option is 'true'\n";
}
const string& file_name = descriptor_->file()->name();
bool is_own_file =
params_.java_multiple_files(file_name)
&& descriptor_->containing_type() == NULL;
if (is_own_file) {
// Note: constants (from enums and fields requiring stored defaults, emitted in the loop below)
// may have the same names as constants in the nested classes. This causes Java warnings, but
// is not fatal, so we suppress those warnings here in the top-most class declaration.
printer->Print(
"\n"
"@SuppressWarnings(\"hiding\")\n"
"public final class $classname$ extends\n",
"classname", descriptor_->name());
} else {
printer->Print(
"\n"
"public static final class $classname$ extends\n",
"classname", descriptor_->name());
}
if (params_.store_unknown_fields() && params_.parcelable_messages()) {
printer->Print(
" com.google.protobuf.nano.android.ParcelableExtendableMessageNano<$classname$> {\n",
"classname", descriptor_->name());
} else if (params_.store_unknown_fields()) {
printer->Print(
" com.google.protobuf.nano.ExtendableMessageNano<$classname$> {\n",
"classname", descriptor_->name());
} else if (params_.parcelable_messages()) {
printer->Print(
" com.google.protobuf.nano.android.ParcelableMessageNano {\n");
} else {
printer->Print(
" com.google.protobuf.nano.MessageNano {\n");
}
printer->Indent();
// Nested types and extensions
for (int i = 0; i < descriptor_->extension_count(); i++) {
ExtensionGenerator(descriptor_->extension(i), params_).Generate(printer);
}
for (int i = 0; i < descriptor_->enum_type_count(); i++) {
EnumGenerator(descriptor_->enum_type(i), params_).Generate(printer);
}
for (int i = 0; i < descriptor_->nested_type_count(); i++) {
MessageGenerator(descriptor_->nested_type(i), params_).Generate(printer);
}
// Lazy initialization of otherwise static final fields can help prevent the
// class initializer from being generated. We want to prevent it because it
// stops ProGuard from inlining any methods in this class into call sites and
// therefore reducing the method count. However, extensions are best kept as
// public static final fields with initializers, so with their existence we
// won't bother with lazy initialization.
bool lazy_init = descriptor_->extension_count() == 0;
// Empty array
if (lazy_init) {
printer->Print(
"\n"
"private static volatile $classname$[] _emptyArray;\n"
"public static $classname$[] emptyArray() {\n"
" // Lazily initializes the empty array\n"
" if (_emptyArray == null) {\n"
" synchronized (\n"
" com.google.protobuf.nano.InternalNano.LAZY_INIT_LOCK) {\n"
" if (_emptyArray == null) {\n"
" _emptyArray = new $classname$[0];\n"
" }\n"
" }\n"
" }\n"
" return _emptyArray;\n"
"}\n",
"classname", descriptor_->name());
} else {
printer->Print(
"\n"
"private static final $classname$[] EMPTY_ARRAY = {};\n"
"public static $classname$[] emptyArray() {\n"
" return EMPTY_ARRAY;\n"
"}\n",
"classname", descriptor_->name());
}
// Integers for bit fields
int totalInts = (field_generators_.total_bits() + 31) / 32;
if (totalInts > 0) {
printer->Print("\n");
for (int i = 0; i < totalInts; i++) {
printer->Print("private int $bit_field_name$;\n",
"bit_field_name", GetBitFieldName(i));
}
}
// Fields and maybe their default values
for (int i = 0; i < descriptor_->field_count(); i++) {
printer->Print("\n");
PrintFieldComment(printer, descriptor_->field(i));
field_generators_.get(descriptor_->field(i)).GenerateMembers(
printer, lazy_init);
}
// Constructor, with lazy init code if needed
if (lazy_init && field_generators_.saved_defaults_needed()) {
printer->Print(
"\n"
"private static volatile boolean _classInitialized;\n"
"\n"
"public $classname$() {\n"
" // Lazily initializes the field defaults\n"
" if (!_classInitialized) {\n"
" synchronized (\n"
" com.google.protobuf.nano.InternalNano.LAZY_INIT_LOCK) {\n"
" if (!_classInitialized) {\n",
"classname", descriptor_->name());
printer->Indent();
printer->Indent();
printer->Indent();
printer->Indent();
for (int i = 0; i < descriptor_->field_count(); i++) {
field_generators_.get(descriptor_->field(i))
.GenerateInitSavedDefaultCode(printer);
}
printer->Outdent();
printer->Outdent();
printer->Outdent();
printer->Outdent();
printer->Print(
" _classInitialized = true;\n"
" }\n"
" }\n"
" }\n"
" clear();\n"
"}\n");
} else {
printer->Print(
"\n"
"public $classname$() {\n"
" clear();\n"
"}\n",
"classname", descriptor_->name());
}
// Other methods in this class
GenerateClear(printer);
if (params_.generate_equals()) {
GenerateEquals(printer);
GenerateHashCode(printer);
}
GenerateMessageSerializationMethods(printer);
GenerateMergeFromMethods(printer);
GenerateParseFromMethods(printer);
printer->Outdent();
printer->Print("}\n");
}
// ===================================================================
void MessageGenerator::
GenerateMessageSerializationMethods(io::Printer* printer) {
// Rely on the parent implementations of writeTo() and getSerializedSize()
// if there are no fields to serialize in this message.
if (descriptor_->field_count() == 0) {
return;
}
scoped_array<const FieldDescriptor*> sorted_fields(
SortFieldsByNumber(descriptor_));
printer->Print(
"\n"
"@Override\n"
"public void writeTo(com.google.protobuf.nano.CodedOutputByteBufferNano output)\n"
" throws java.io.IOException {\n");
printer->Indent();
// Output the fields in sorted order
for (int i = 0; i < descriptor_->field_count(); i++) {
GenerateSerializeOneField(printer, sorted_fields[i]);
}
// The parent implementation will write any unknown fields if necessary.
printer->Print(
"super.writeTo(output);\n");
printer->Outdent();
printer->Print("}\n");
// The parent implementation will get the serialized size for unknown
// fields if necessary.
printer->Print(
"\n"
"@Override\n"
"protected int computeSerializedSize() {\n"
" int size = super.computeSerializedSize();\n");
printer->Indent();
for (int i = 0; i < descriptor_->field_count(); i++) {
field_generators_.get(sorted_fields[i]).GenerateSerializedSizeCode(printer);
}
printer->Outdent();
printer->Print(
" return size;\n"
"}\n");
}
void MessageGenerator::GenerateMergeFromMethods(io::Printer* printer) {
scoped_array<const FieldDescriptor*> sorted_fields(
SortFieldsByNumber(descriptor_));
printer->Print(
"\n"
"@Override\n"
"public $classname$ mergeFrom(\n"
" com.google.protobuf.nano.CodedInputByteBufferNano input)\n"
" throws java.io.IOException {\n",
"classname", descriptor_->name());
printer->Indent();
printer->Print(
"while (true) {\n");
printer->Indent();
printer->Print(
"int tag = input.readTag();\n"
"switch (tag) {\n");
printer->Indent();
printer->Print(
"case 0:\n" // zero signals EOF / limit reached
" return this;\n"
"default: {\n");
printer->Indent();
if (params_.store_unknown_fields()) {
printer->Print(
"if (!storeUnknownField(input, tag)) {\n"
" return this;\n"
"}\n");
} else {
printer->Print(
"if (!com.google.protobuf.nano.WireFormatNano.parseUnknownField(input, tag)) {\n"
" return this;\n" // it's an endgroup tag
"}\n");
}
printer->Print("break;\n");
printer->Outdent();
printer->Print("}\n");
for (int i = 0; i < descriptor_->field_count(); i++) {
const FieldDescriptor* field = sorted_fields[i];
uint32 tag = WireFormatLite::MakeTag(field->number(),
WireFormat::WireTypeForFieldType(field->type()));
printer->Print(
"case $tag$: {\n",
"tag", SimpleItoa(tag));
printer->Indent();
field_generators_.get(field).GenerateMergingCode(printer);
printer->Outdent();
printer->Print(
" break;\n"
"}\n");
if (field->is_packable()) {
// To make packed = true wire compatible, we generate parsing code from a
// packed version of this field regardless of field->options().packed().
uint32 packed_tag = WireFormatLite::MakeTag(field->number(),
WireFormatLite::WIRETYPE_LENGTH_DELIMITED);
printer->Print(
"case $tag$: {\n",
"tag", SimpleItoa(packed_tag));
printer->Indent();
field_generators_.get(field).GenerateMergingCodeFromPacked(printer);
printer->Outdent();
printer->Print(
" break;\n"
"}\n");
}
}
printer->Outdent();
printer->Outdent();
printer->Outdent();
printer->Print(
" }\n" // switch (tag)
" }\n" // while (true)
"}\n");
}
void MessageGenerator::
GenerateParseFromMethods(io::Printer* printer) {
// Note: These are separate from GenerateMessageSerializationMethods()
// because they need to be generated even for messages that are optimized
// for code size.
printer->Print(
"\n"
"public static $classname$ parseFrom(byte[] data)\n"
" throws com.google.protobuf.nano.InvalidProtocolBufferNanoException {\n"
" return com.google.protobuf.nano.MessageNano.mergeFrom(new $classname$(), data);\n"
"}\n"
"\n"
"public static $classname$ parseFrom(\n"
" com.google.protobuf.nano.CodedInputByteBufferNano input)\n"
" throws java.io.IOException {\n"
" return new $classname$().mergeFrom(input);\n"
"}\n",
"classname", descriptor_->name());
}
void MessageGenerator::GenerateSerializeOneField(
io::Printer* printer, const FieldDescriptor* field) {
field_generators_.get(field).GenerateSerializationCode(printer);
}
void MessageGenerator::GenerateClear(io::Printer* printer) {
printer->Print(
"\n"
"public $classname$ clear() {\n",
"classname", descriptor_->name());
printer->Indent();
// Clear bit fields.
int totalInts = (field_generators_.total_bits() + 31) / 32;
for (int i = 0; i < totalInts; i++) {
printer->Print("$bit_field_name$ = 0;\n",
"bit_field_name", GetBitFieldName(i));
}
// Call clear for all of the fields.
for (int i = 0; i < descriptor_->field_count(); i++) {
const FieldDescriptor* field = descriptor_->field(i);
field_generators_.get(field).GenerateClearCode(printer);
}
// Clear unknown fields.
if (params_.store_unknown_fields()) {
printer->Print("unknownFieldData = null;\n");
}
printer->Outdent();
printer->Print(
" cachedSize = -1;\n"
" return this;\n"
"}\n");
}
void MessageGenerator::GenerateEquals(io::Printer* printer) {
// Don't override if there are no fields. We could generate an
// equals method that compares types, but often empty messages
// are used as namespaces.
if (descriptor_->field_count() == 0 && !params_.store_unknown_fields()) {
return;
}
printer->Print(
"\n"
"@Override\n"
"public boolean equals(Object o) {\n");
printer->Indent();
printer->Print(
"if (o == this) {\n"
" return true;\n"
"}\n"
"if (!(o instanceof $classname$)) {\n"
" return false;\n"
"}\n"
"$classname$ other = ($classname$) o;\n",
"classname", descriptor_->name());
for (int i = 0; i < descriptor_->field_count(); i++) {
const FieldDescriptor* field = descriptor_->field(i);
field_generators_.get(field).GenerateEqualsCode(printer);
}
if (params_.store_unknown_fields()) {
printer->Print(
"return unknownFieldDataEquals(other);\n");
} else {
printer->Print(
"return true;\n");
}
printer->Outdent();
printer->Print("}\n");
}
void MessageGenerator::GenerateHashCode(io::Printer* printer) {
if (descriptor_->field_count() == 0 && !params_.store_unknown_fields()) {
return;
}
printer->Print(
"\n"
"@Override\n"
"public int hashCode() {\n");
printer->Indent();
printer->Print("int result = 17;\n");
for (int i = 0; i < descriptor_->field_count(); i++) {
const FieldDescriptor* field = descriptor_->field(i);
field_generators_.get(field).GenerateHashCodeCode(printer);
}
if (params_.store_unknown_fields()) {
printer->Print(
"result = 31 * result + unknownFieldDataHashCode();\n");
}
printer->Print("return result;\n");
printer->Outdent();
printer->Print("}\n");
}
// ===================================================================
} // namespace javanano
} // namespace compiler
} // namespace protobuf
} // namespace google