• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
46 namespace google {
47 namespace protobuf {
48 namespace compiler {
49 namespace javamicro {
50 
51 using internal::WireFormat;
52 using internal::WireFormatLite;
53 
54 namespace {
55 
PrintFieldComment(io::Printer * printer,const FieldDescriptor * field)56 void 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 
64 struct FieldOrderingByNumber {
operator ()google::protobuf::compiler::javamicro::__anonb8518ae30111::FieldOrderingByNumber65   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.
SortFieldsByNumber(const Descriptor * descriptor)73 const 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.
UniqueFileScopeIdentifier(const Descriptor * descriptor)87 string 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).
HasRequiredFields(const Descriptor * type,hash_set<const Descriptor * > * already_seen)96 static 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 
HasRequiredFields(const Descriptor * type)132 static 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 
MessageGenerator(const Descriptor * descriptor,const Params & params)141 MessageGenerator::MessageGenerator(const Descriptor* descriptor, const Params& params)
142   : params_(params),
143     descriptor_(descriptor),
144     field_generators_(descriptor, params) {
145 }
146 
~MessageGenerator()147 MessageGenerator::~MessageGenerator() {}
148 
GenerateStaticVariables(io::Printer * printer)149 void 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 
GenerateStaticVariableInitializers(io::Printer * printer)158 void 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 
Generate(io::Printer * printer)172 void MessageGenerator::Generate(io::Printer* printer) {
173   bool is_own_file =
174     params_.java_multiple_files() || ((descriptor_->containing_type() == NULL)
175         && !params_.has_java_outer_classname(descriptor_->file()->name()));
176 
177 #if 0
178   GOOGLE_LOG(INFO) << "is_own_file=" << is_own_file;
179   GOOGLE_LOG(INFO) << "containing_type()=" << ((descriptor_->containing_type() == NULL) ? "NULL" : "not null");
180   GOOGLE_LOG(INFO) << "java_multiple_files()=" << params_.java_multiple_files();
181   GOOGLE_LOG(INFO) << "has_java_outer_classname()=" << params_.has_java_outer_classname(file_->name());
182 #endif
183 
184   if ((descriptor_->extension_count() != 0)
185       || (descriptor_->extension_range_count() != 0)) {
186     GOOGLE_LOG(FATAL) << "Extensions not supported in MICRO_RUNTIME\n";
187   }
188 
189   // Note: Fields (which will be emitted in the loop, below) may have the same names as fields in
190   // the inner or outer class.  This causes Java warnings, but is not fatal, so we suppress those
191   // warnings here in the class declaration.
192   printer->Print(
193     "@SuppressWarnings(\"hiding\")\n"
194     "public $modifiers$ final class $classname$ extends\n"
195     "    com.google.protobuf.micro.MessageMicro {\n",
196     "modifiers", is_own_file ? "" : "static",
197     "classname", descriptor_->name());
198   printer->Indent();
199   printer->Print(
200     "public $classname$() {}\n"
201     "\n",
202     "classname", descriptor_->name());
203 
204   // Nested types and extensions
205   for (int i = 0; i < descriptor_->enum_type_count(); i++) {
206     EnumGenerator(descriptor_->enum_type(i), params_).Generate(printer);
207   }
208 
209   for (int i = 0; i < descriptor_->nested_type_count(); i++) {
210     MessageGenerator(descriptor_->nested_type(i), params_).Generate(printer);
211   }
212 
213   // Fields
214   for (int i = 0; i < descriptor_->field_count(); i++) {
215     PrintFieldComment(printer, descriptor_->field(i));
216     printer->Print("public static final int $constant_name$ = $number$;\n",
217       "constant_name", FieldConstantName(descriptor_->field(i)),
218       "number", SimpleItoa(descriptor_->field(i)->number()));
219     field_generators_.get(descriptor_->field(i)).GenerateMembers(printer);
220     printer->Print("\n");
221   }
222 
223   GenerateClear(printer);
224   GenerateIsInitialized(printer);
225   GenerateMessageSerializationMethods(printer);
226   GenerateMergeFromMethods(printer);
227   GenerateParseFromMethods(printer);
228 
229   printer->Outdent();
230   printer->Print("}\n\n");
231 }
232 
233 // ===================================================================
234 
235 void MessageGenerator::
GenerateMessageSerializationMethods(io::Printer * printer)236 GenerateMessageSerializationMethods(io::Printer* printer) {
237   scoped_array<const FieldDescriptor*> sorted_fields(
238     SortFieldsByNumber(descriptor_));
239 
240   if (descriptor_->extension_range_count() != 0) {
241     GOOGLE_LOG(FATAL) << "Extensions not supported in MICRO_RUNTIME\n";
242   }
243 
244   // writeTo only throws an exception if it contains one or more fields to write
245   if (descriptor_->field_count() > 0) {
246     printer->Print(
247       "@Override\n"
248       "public void writeTo(com.google.protobuf.micro.CodedOutputStreamMicro output)\n"
249       "                    throws java.io.IOException {\n");
250   } else {
251     printer->Print(
252       "@Override\n"
253       "public void writeTo(com.google.protobuf.micro.CodedOutputStreamMicro output) {\n");
254   }
255   printer->Indent();
256 
257   // Output the fields in sorted order
258   for (int i = 0; i < descriptor_->field_count(); i++) {
259       GenerateSerializeOneField(printer, sorted_fields[i]);
260   }
261 
262   printer->Outdent();
263   printer->Print(
264     "}\n"
265     "\n"
266     "private int cachedSize = -1;\n"
267     "@Override\n"
268     "public int getCachedSize() {\n"
269     "  if (cachedSize < 0) {\n"
270     "    // getSerializedSize sets cachedSize\n"
271     "    getSerializedSize();\n"
272     "  }\n"
273     "  return cachedSize;\n"
274     "}\n"
275     "\n"
276     "@Override\n"
277     "public int getSerializedSize() {\n"
278     "  int size = 0;\n");
279   printer->Indent();
280 
281   for (int i = 0; i < descriptor_->field_count(); i++) {
282     field_generators_.get(sorted_fields[i]).GenerateSerializedSizeCode(printer);
283   }
284 
285   printer->Outdent();
286   printer->Print(
287     "  cachedSize = size;\n"
288     "  return size;\n"
289     "}\n"
290     "\n");
291 }
292 
GenerateMergeFromMethods(io::Printer * printer)293 void MessageGenerator::GenerateMergeFromMethods(io::Printer* printer) {
294   scoped_array<const FieldDescriptor*> sorted_fields(
295     SortFieldsByNumber(descriptor_));
296 
297   if (params_.java_use_vector()) {
298     printer->Print(
299       "@Override\n"
300       "public com.google.protobuf.micro.MessageMicro mergeFrom(\n"
301       "    com.google.protobuf.micro.CodedInputStreamMicro input)\n"
302       "    throws java.io.IOException {\n",
303       "classname", descriptor_->name());
304   } else {
305     printer->Print(
306       "@Override\n"
307       "public $classname$ mergeFrom(\n"
308       "    com.google.protobuf.micro.CodedInputStreamMicro input)\n"
309       "    throws java.io.IOException {\n",
310       "classname", descriptor_->name());
311   }
312   printer->Indent();
313 
314   printer->Print(
315     "while (true) {\n");
316   printer->Indent();
317 
318   printer->Print(
319     "int tag = input.readTag();\n"
320     "switch (tag) {\n");
321   printer->Indent();
322 
323   printer->Print(
324     "case 0:\n"          // zero signals EOF / limit reached
325     "  return this;\n"
326     "default: {\n"
327     "  if (!parseUnknownField(input, tag)) {\n"
328     "    return this;\n"   // it's an endgroup tag
329     "  }\n"
330     "  break;\n"
331     "}\n");
332 
333   for (int i = 0; i < descriptor_->field_count(); i++) {
334     const FieldDescriptor* field = sorted_fields[i];
335     uint32 tag = WireFormatLite::MakeTag(field->number(),
336       WireFormat::WireTypeForField(field));
337 
338     printer->Print(
339       "case $tag$: {\n",
340       "tag", SimpleItoa(tag));
341     printer->Indent();
342 
343     field_generators_.get(field).GenerateParsingCode(printer);
344 
345     printer->Outdent();
346     printer->Print(
347       "  break;\n"
348       "}\n");
349   }
350 
351   printer->Outdent();
352   printer->Outdent();
353   printer->Outdent();
354   printer->Print(
355     "    }\n"     // switch (tag)
356     "  }\n"       // while (true)
357     "}\n"
358     "\n");
359 }
360 
361 void MessageGenerator::
GenerateParseFromMethods(io::Printer * printer)362 GenerateParseFromMethods(io::Printer* printer) {
363   bool is_own_file =
364     descriptor_->containing_type() == NULL;
365 
366   // Note:  These are separate from GenerateMessageSerializationMethods()
367   //   because they need to be generated even for messages that are optimized
368   //   for code size.
369   printer->Print(
370     "public $static$ $classname$ parseFrom(byte[] data)\n"
371     "    throws com.google.protobuf.micro.InvalidProtocolBufferMicroException {\n"
372     "  return ($classname$) (new $classname$().mergeFrom(data));\n"
373     "}\n"
374     "\n"
375     "public $static$ $classname$ parseFrom(\n"
376     "        com.google.protobuf.micro.CodedInputStreamMicro input)\n"
377     "    throws java.io.IOException {\n"
378     "  return new $classname$().mergeFrom(input);\n"
379     "}\n"
380     "\n",
381     "static", (is_own_file ? "static" : ""),
382     "classname", descriptor_->name());
383 }
384 
GenerateSerializeOneField(io::Printer * printer,const FieldDescriptor * field)385 void MessageGenerator::GenerateSerializeOneField(
386     io::Printer* printer, const FieldDescriptor* field) {
387   field_generators_.get(field).GenerateSerializationCode(printer);
388 }
389 
GenerateClear(io::Printer * printer)390 void MessageGenerator::GenerateClear(io::Printer* printer) {
391   printer->Print(
392     "public final $classname$ clear() {\n",
393     "classname", descriptor_->name());
394   printer->Indent();
395 
396   // Call clear for all of the fields.
397   for (int i = 0; i < descriptor_->field_count(); i++) {
398     const FieldDescriptor* field = descriptor_->field(i);
399 
400     printer->Print(
401       "clear$name$();\n",
402       "name", UnderscoresToCapitalizedCamelCase(field));
403   }
404 
405   printer->Outdent();
406   printer->Print(
407     "  cachedSize = -1;\n"
408     "  return this;\n"
409     "}\n"
410     "\n");
411 }
412 
413 
GenerateIsInitialized(io::Printer * printer)414 void MessageGenerator::GenerateIsInitialized(io::Printer* printer) {
415   printer->Print(
416     "public final boolean isInitialized() {\n");
417   printer->Indent();
418 
419   // Check that all required fields in this message are set.
420   // TODO(kenton):  We can optimize this when we switch to putting all the
421   //   "has" fields into a single bitfield.
422   for (int i = 0; i < descriptor_->field_count(); i++) {
423     const FieldDescriptor* field = descriptor_->field(i);
424 
425     if (field->is_required()) {
426       printer->Print(
427         "if (!has$name$) return false;\n",
428         "name", UnderscoresToCapitalizedCamelCase(field));
429     }
430   }
431 
432   // Now check that all embedded messages are initialized.
433   for (int i = 0; i < descriptor_->field_count(); i++) {
434     const FieldDescriptor* field = descriptor_->field(i);
435     if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
436         HasRequiredFields(field->message_type())) {
437       switch (field->label()) {
438         case FieldDescriptor::LABEL_REQUIRED:
439           printer->Print(
440             "if (!get$name$().isInitialized()) return false;\n",
441             "type", ClassName(params_, field->message_type()),
442             "name", UnderscoresToCapitalizedCamelCase(field));
443           break;
444         case FieldDescriptor::LABEL_OPTIONAL:
445           printer->Print(
446             "if (has$name$()) {\n"
447             "  if (!get$name$().isInitialized()) return false;\n"
448             "}\n",
449             "type", ClassName(params_, field->message_type()),
450             "name", UnderscoresToCapitalizedCamelCase(field));
451           break;
452         case FieldDescriptor::LABEL_REPEATED:
453           if (params_.java_use_vector()) {
454             printer->Print(
455               "for (int i = 0; i < get$name$List().size(); i++) {\n"
456               "  if (get$name$(i).isInitialized()) return false;\n"
457               "}\n",
458               "type", ClassName(params_, field->message_type()),
459               "name", UnderscoresToCapitalizedCamelCase(field));
460           } else {
461             printer->Print(
462               "for ($type$ element : get$name$List()) {\n"
463               "  if (!element.isInitialized()) return false;\n"
464               "}\n",
465               "type", ClassName(params_, field->message_type()),
466               "name", UnderscoresToCapitalizedCamelCase(field));
467           }
468           break;
469       }
470     }
471   }
472 
473   if (descriptor_->extension_range_count() > 0) {
474     printer->Print(
475       "if (!extensionsAreInitialized()) return false;\n");
476   }
477 
478   printer->Outdent();
479   printer->Print(
480     "  return true;\n"
481     "}\n"
482     "\n");
483 }
484 
485 // ===================================================================
486 
487 }  // namespace javamicro
488 }  // namespace compiler
489 }  // namespace protobuf
490 }  // namespace google
491