1// Protocol Buffers - Google's data interchange format
2// Copyright 2008 Google Inc.  All rights reserved.
3// http://code.google.com/p/protobuf/
4//
5// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are
7// met:
8//
9//     * Redistributions of source code must retain the above copyright
10// notice, this list of conditions and the following disclaimer.
11//     * Redistributions in binary form must reproduce the above
12// copyright notice, this list of conditions and the following disclaimer
13// in the documentation and/or other materials provided with the
14// distribution.
15//     * Neither the name of Google Inc. nor the names of its
16// contributors may be used to endorse or promote products derived from
17// this software without specific prior written permission.
18//
19// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31// Author: kenton@google.com (Kenton Varda)
32//  Based on original Protocol Buffers design by
33//  Sanjay Ghemawat, Jeff Dean, and others.
34
35#include <algorithm>
36#include <google/protobuf/stubs/hash.h>
37#include <google/protobuf/compiler/javamicro/javamicro_message.h>
38#include <google/protobuf/compiler/javamicro/javamicro_enum.h>
39#include <google/protobuf/compiler/javamicro/javamicro_helpers.h>
40#include <google/protobuf/stubs/strutil.h>
41#include <google/protobuf/io/printer.h>
42#include <google/protobuf/io/coded_stream.h>
43#include <google/protobuf/wire_format.h>
44#include <google/protobuf/descriptor.pb.h>
45
46namespace google {
47namespace protobuf {
48namespace compiler {
49namespace javamicro {
50
51using internal::WireFormat;
52using internal::WireFormatLite;
53
54namespace {
55
56void PrintFieldComment(io::Printer* printer, const FieldDescriptor* field) {
57  // Print the field's proto-syntax definition as a comment.  We don't want to
58  // print group bodies so we cut off after the first line.
59  string def = field->DebugString();
60  printer->Print("// $def$\n",
61    "def", def.substr(0, def.find_first_of('\n')));
62}
63
64struct FieldOrderingByNumber {
65  inline bool operator()(const FieldDescriptor* a,
66                         const FieldDescriptor* b) const {
67    return a->number() < b->number();
68  }
69};
70
71// Sort the fields of the given Descriptor by number into a new[]'d array
72// and return it.
73const FieldDescriptor** SortFieldsByNumber(const Descriptor* descriptor) {
74  const FieldDescriptor** fields =
75    new const FieldDescriptor*[descriptor->field_count()];
76  for (int i = 0; i < descriptor->field_count(); i++) {
77    fields[i] = descriptor->field(i);
78  }
79  sort(fields, fields + descriptor->field_count(),
80       FieldOrderingByNumber());
81  return fields;
82}
83
84// Get an identifier that uniquely identifies this type within the file.
85// This is used to declare static variables related to this type at the
86// outermost file scope.
87string UniqueFileScopeIdentifier(const Descriptor* descriptor) {
88  return "static_" + StringReplace(descriptor->full_name(), ".", "_", true);
89}
90
91// Returns true if the message type has any required fields.  If it doesn't,
92// we can optimize out calls to its isInitialized() method.
93//
94// already_seen is used to avoid checking the same type multiple times
95// (and also to protect against recursion).
96static bool HasRequiredFields(
97    const Descriptor* type,
98    hash_set<const Descriptor*>* already_seen) {
99  if (already_seen->count(type) > 0) {
100    // The type is already in cache.  This means that either:
101    // a. The type has no required fields.
102    // b. We are in the midst of checking if the type has required fields,
103    //    somewhere up the stack.  In this case, we know that if the type
104    //    has any required fields, they'll be found when we return to it,
105    //    and the whole call to HasRequiredFields() will return true.
106    //    Therefore, we don't have to check if this type has required fields
107    //    here.
108    return false;
109  }
110  already_seen->insert(type);
111
112  // If the type has extensions, an extension with message type could contain
113  // required fields, so we have to be conservative and assume such an
114  // extension exists.
115  if (type->extension_range_count() > 0) return true;
116
117  for (int i = 0; i < type->field_count(); i++) {
118    const FieldDescriptor* field = type->field(i);
119    if (field->is_required()) {
120      return true;
121    }
122    if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
123      if (HasRequiredFields(field->message_type(), already_seen)) {
124        return true;
125      }
126    }
127  }
128
129  return false;
130}
131
132static bool HasRequiredFields(const Descriptor* type) {
133  hash_set<const Descriptor*> already_seen;
134  return HasRequiredFields(type, &already_seen);
135}
136
137}  // namespace
138
139// ===================================================================
140
141MessageGenerator::MessageGenerator(const Descriptor* descriptor, const Params& params)
142  : params_(params),
143    descriptor_(descriptor),
144    field_generators_(descriptor, params) {
145}
146
147MessageGenerator::~MessageGenerator() {}
148
149void MessageGenerator::GenerateStaticVariables(io::Printer* printer) {
150  // Generate static members for all nested types.
151  for (int i = 0; i < descriptor_->nested_type_count(); i++) {
152    // TODO(kenton):  Reuse MessageGenerator objects?
153    MessageGenerator(descriptor_->nested_type(i), params_)
154      .GenerateStaticVariables(printer);
155  }
156}
157
158void MessageGenerator::GenerateStaticVariableInitializers(
159    io::Printer* printer) {
160  // Generate static member initializers for all nested types.
161  for (int i = 0; i < descriptor_->nested_type_count(); i++) {
162    // TODO(kenton):  Reuse MessageGenerator objects?
163    MessageGenerator(descriptor_->nested_type(i), params_)
164      .GenerateStaticVariableInitializers(printer);
165  }
166
167  if (descriptor_->extension_count() != 0) {
168    GOOGLE_LOG(FATAL) << "Extensions not supported in MICRO_RUNTIME\n";
169  }
170}
171
172void MessageGenerator::Generate(io::Printer* printer) {
173  const string& file_name = descriptor_->file()->name();
174  bool is_own_file =
175    params_.java_multiple_files(file_name)
176      && descriptor_->containing_type() == NULL;
177
178  if ((descriptor_->extension_count() != 0)
179      || (descriptor_->extension_range_count() != 0)) {
180    GOOGLE_LOG(FATAL) << "Extensions not supported in MICRO_RUNTIME\n";
181  }
182
183  // Note: Fields (which will be emitted in the loop, below) may have the same names as fields in
184  // the inner or outer class.  This causes Java warnings, but is not fatal, so we suppress those
185  // warnings here in the class declaration.
186  printer->Print(
187    "@SuppressWarnings(\"hiding\")\n"
188    "public $modifiers$ final class $classname$ extends\n"
189    "    com.google.protobuf.micro.MessageMicro {\n",
190    "modifiers", is_own_file ? "" : "static",
191    "classname", descriptor_->name());
192  printer->Indent();
193  printer->Print(
194    "public $classname$() {}\n"
195    "\n",
196    "classname", descriptor_->name());
197
198  // Nested types and extensions
199  for (int i = 0; i < descriptor_->enum_type_count(); i++) {
200    EnumGenerator(descriptor_->enum_type(i), params_).Generate(printer);
201  }
202
203  for (int i = 0; i < descriptor_->nested_type_count(); i++) {
204    MessageGenerator(descriptor_->nested_type(i), params_).Generate(printer);
205  }
206
207  // Fields
208  for (int i = 0; i < descriptor_->field_count(); i++) {
209    PrintFieldComment(printer, descriptor_->field(i));
210    printer->Print("public static final int $constant_name$ = $number$;\n",
211      "constant_name", FieldConstantName(descriptor_->field(i)),
212      "number", SimpleItoa(descriptor_->field(i)->number()));
213    field_generators_.get(descriptor_->field(i)).GenerateMembers(printer);
214    printer->Print("\n");
215  }
216
217  GenerateClear(printer);
218  GenerateIsInitialized(printer);
219  GenerateMessageSerializationMethods(printer);
220  GenerateMergeFromMethods(printer);
221  GenerateParseFromMethods(printer);
222
223  printer->Outdent();
224  printer->Print("}\n\n");
225}
226
227// ===================================================================
228
229void MessageGenerator::
230GenerateMessageSerializationMethods(io::Printer* printer) {
231  scoped_array<const FieldDescriptor*> sorted_fields(
232    SortFieldsByNumber(descriptor_));
233
234  if (descriptor_->extension_range_count() != 0) {
235    GOOGLE_LOG(FATAL) << "Extensions not supported in MICRO_RUNTIME\n";
236  }
237
238  // writeTo only throws an exception if it contains one or more fields to write
239  if (descriptor_->field_count() > 0) {
240    printer->Print(
241      "@Override\n"
242      "public void writeTo(com.google.protobuf.micro.CodedOutputStreamMicro output)\n"
243      "                    throws java.io.IOException {\n");
244  } else {
245    printer->Print(
246      "@Override\n"
247      "public void writeTo(com.google.protobuf.micro.CodedOutputStreamMicro output) {\n");
248  }
249  printer->Indent();
250
251  // Output the fields in sorted order
252  for (int i = 0; i < descriptor_->field_count(); i++) {
253      GenerateSerializeOneField(printer, sorted_fields[i]);
254  }
255
256  printer->Outdent();
257  printer->Print(
258    "}\n"
259    "\n"
260    "private int cachedSize = -1;\n"
261    "@Override\n"
262    "public int getCachedSize() {\n"
263    "  if (cachedSize < 0) {\n"
264    "    // getSerializedSize sets cachedSize\n"
265    "    getSerializedSize();\n"
266    "  }\n"
267    "  return cachedSize;\n"
268    "}\n"
269    "\n"
270    "@Override\n"
271    "public int getSerializedSize() {\n"
272    "  int size = 0;\n");
273  printer->Indent();
274
275  for (int i = 0; i < descriptor_->field_count(); i++) {
276    field_generators_.get(sorted_fields[i]).GenerateSerializedSizeCode(printer);
277  }
278
279  printer->Outdent();
280  printer->Print(
281    "  cachedSize = size;\n"
282    "  return size;\n"
283    "}\n"
284    "\n");
285}
286
287void MessageGenerator::GenerateMergeFromMethods(io::Printer* printer) {
288  scoped_array<const FieldDescriptor*> sorted_fields(
289    SortFieldsByNumber(descriptor_));
290
291  if (params_.java_use_vector()) {
292    printer->Print(
293      "@Override\n"
294      "public com.google.protobuf.micro.MessageMicro mergeFrom(\n"
295      "    com.google.protobuf.micro.CodedInputStreamMicro input)\n"
296      "    throws java.io.IOException {\n",
297      "classname", descriptor_->name());
298  } else {
299    printer->Print(
300      "@Override\n"
301      "public $classname$ mergeFrom(\n"
302      "    com.google.protobuf.micro.CodedInputStreamMicro input)\n"
303      "    throws java.io.IOException {\n",
304      "classname", descriptor_->name());
305  }
306  printer->Indent();
307
308  printer->Print(
309    "while (true) {\n");
310  printer->Indent();
311
312  printer->Print(
313    "int tag = input.readTag();\n"
314    "switch (tag) {\n");
315  printer->Indent();
316
317  printer->Print(
318    "case 0:\n"          // zero signals EOF / limit reached
319    "  return this;\n"
320    "default: {\n"
321    "  if (!parseUnknownField(input, tag)) {\n"
322    "    return this;\n"   // it's an endgroup tag
323    "  }\n"
324    "  break;\n"
325    "}\n");
326
327  for (int i = 0; i < descriptor_->field_count(); i++) {
328    const FieldDescriptor* field = sorted_fields[i];
329    uint32 tag = WireFormatLite::MakeTag(field->number(),
330      WireFormat::WireTypeForField(field));
331
332    printer->Print(
333      "case $tag$: {\n",
334      "tag", SimpleItoa(tag));
335    printer->Indent();
336
337    field_generators_.get(field).GenerateParsingCode(printer);
338
339    printer->Outdent();
340    printer->Print(
341      "  break;\n"
342      "}\n");
343  }
344
345  printer->Outdent();
346  printer->Outdent();
347  printer->Outdent();
348  printer->Print(
349    "    }\n"     // switch (tag)
350    "  }\n"       // while (true)
351    "}\n"
352    "\n");
353}
354
355void MessageGenerator::
356GenerateParseFromMethods(io::Printer* printer) {
357  // Note:  These are separate from GenerateMessageSerializationMethods()
358  //   because they need to be generated even for messages that are optimized
359  //   for code size.
360  printer->Print(
361    "public static $classname$ parseFrom(byte[] data)\n"
362    "    throws com.google.protobuf.micro.InvalidProtocolBufferMicroException {\n"
363    "  return ($classname$) (new $classname$().mergeFrom(data));\n"
364    "}\n"
365    "\n"
366    "public static $classname$ parseFrom(\n"
367    "        com.google.protobuf.micro.CodedInputStreamMicro input)\n"
368    "    throws java.io.IOException {\n"
369    "  return new $classname$().mergeFrom(input);\n"
370    "}\n"
371    "\n",
372    "classname", descriptor_->name());
373}
374
375void MessageGenerator::GenerateSerializeOneField(
376    io::Printer* printer, const FieldDescriptor* field) {
377  field_generators_.get(field).GenerateSerializationCode(printer);
378}
379
380void MessageGenerator::GenerateClear(io::Printer* printer) {
381  printer->Print(
382    "public final $classname$ clear() {\n",
383    "classname", descriptor_->name());
384  printer->Indent();
385
386  // Call clear for all of the fields.
387  for (int i = 0; i < descriptor_->field_count(); i++) {
388    const FieldDescriptor* field = descriptor_->field(i);
389
390    printer->Print(
391      "clear$name$();\n",
392      "name", UnderscoresToCapitalizedCamelCase(field));
393  }
394
395  printer->Outdent();
396  printer->Print(
397    "  cachedSize = -1;\n"
398    "  return this;\n"
399    "}\n"
400    "\n");
401}
402
403
404void MessageGenerator::GenerateIsInitialized(io::Printer* printer) {
405  printer->Print(
406    "public final boolean isInitialized() {\n");
407  printer->Indent();
408
409  // Check that all required fields in this message are set.
410  // TODO(kenton):  We can optimize this when we switch to putting all the
411  //   "has" fields into a single bitfield.
412  for (int i = 0; i < descriptor_->field_count(); i++) {
413    const FieldDescriptor* field = descriptor_->field(i);
414
415    if (field->is_required()) {
416      printer->Print(
417        "if (!has$name$) return false;\n",
418        "name", UnderscoresToCapitalizedCamelCase(field));
419    }
420  }
421
422  // Now check that all embedded messages are initialized.
423  for (int i = 0; i < descriptor_->field_count(); i++) {
424    const FieldDescriptor* field = descriptor_->field(i);
425    if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
426        HasRequiredFields(field->message_type())) {
427      switch (field->label()) {
428        case FieldDescriptor::LABEL_REQUIRED:
429          printer->Print(
430            "if (!get$name$().isInitialized()) return false;\n",
431            "type", ClassName(params_, field->message_type()),
432            "name", UnderscoresToCapitalizedCamelCase(field));
433          break;
434        case FieldDescriptor::LABEL_OPTIONAL:
435          printer->Print(
436            "if (has$name$()) {\n"
437            "  if (!get$name$().isInitialized()) return false;\n"
438            "}\n",
439            "type", ClassName(params_, field->message_type()),
440            "name", UnderscoresToCapitalizedCamelCase(field));
441          break;
442        case FieldDescriptor::LABEL_REPEATED:
443          if (params_.java_use_vector()) {
444            printer->Print(
445              "for (int i = 0; i < get$name$List().size(); i++) {\n"
446              "  if (get$name$(i).isInitialized()) return false;\n"
447              "}\n",
448              "type", ClassName(params_, field->message_type()),
449              "name", UnderscoresToCapitalizedCamelCase(field));
450          } else {
451            printer->Print(
452              "for ($type$ element : get$name$List()) {\n"
453              "  if (!element.isInitialized()) return false;\n"
454              "}\n",
455              "type", ClassName(params_, field->message_type()),
456              "name", UnderscoresToCapitalizedCamelCase(field));
457          }
458          break;
459      }
460    }
461  }
462
463  if (descriptor_->extension_range_count() > 0) {
464    printer->Print(
465      "if (!extensionsAreInitialized()) return false;\n");
466  }
467
468  printer->Outdent();
469  printer->Print(
470    "  return true;\n"
471    "}\n"
472    "\n");
473}
474
475// ===================================================================
476
477}  // namespace javamicro
478}  // namespace compiler
479}  // namespace protobuf
480}  // namespace google
481