• 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 <limits>
36 #include <vector>
37 
38 #include <google/protobuf/compiler/javanano/javanano_helpers.h>
39 #include <google/protobuf/compiler/javanano/javanano_params.h>
40 #include <google/protobuf/descriptor.pb.h>
41 #include <google/protobuf/stubs/hash.h>
42 #include <google/protobuf/stubs/strutil.h>
43 #include <google/protobuf/stubs/substitute.h>
44 
45 namespace google {
46 namespace protobuf {
47 namespace compiler {
48 namespace javanano {
49 
50 const char kThickSeparator[] =
51   "// ===================================================================\n";
52 const char kThinSeparator[] =
53   "// -------------------------------------------------------------------\n";
54 
55 class RenameKeywords {
56  private:
57   hash_set<string> java_keywords_set_;
58 
59  public:
RenameKeywords()60   RenameKeywords() {
61     static const char* kJavaKeywordsList[] = {
62       // Reserved Java Keywords
63       "abstract", "assert", "boolean", "break", "byte", "case", "catch",
64       "char", "class", "const", "continue", "default", "do", "double", "else",
65       "enum", "extends", "final", "finally", "float", "for", "goto", "if",
66       "implements", "import", "instanceof", "int", "interface", "long",
67       "native", "new", "package", "private", "protected", "public", "return",
68       "short", "static", "strictfp", "super", "switch", "synchronized",
69       "this", "throw", "throws", "transient", "try", "void", "volatile", "while",
70 
71       // Reserved Keywords for Literals
72       "false", "null", "true"
73     };
74 
75     for (int i = 0; i < GOOGLE_ARRAYSIZE(kJavaKeywordsList); i++) {
76       java_keywords_set_.insert(kJavaKeywordsList[i]);
77     }
78   }
79 
80   // Used to rename the a field name if it's a java keyword.  Specifically
81   // this is used to rename the ["name"] or ["capitalized_name"] field params.
82   // (http://docs.oracle.com/javase/tutorial/java/nutsandbolts/_keywords.html)
RenameJavaKeywordsImpl(const string & input)83   string RenameJavaKeywordsImpl(const string& input) {
84     string result = input;
85 
86     if (java_keywords_set_.find(result) != java_keywords_set_.end()) {
87       result += "_";
88     }
89 
90     return result;
91   }
92 
93 };
94 
95 static RenameKeywords sRenameKeywords;
96 
97 namespace {
98 
99 const char* kDefaultPackage = "";
100 
FieldName(const FieldDescriptor * field)101 const string& FieldName(const FieldDescriptor* field) {
102   // Groups are hacky:  The name of the field is just the lower-cased name
103   // of the group type.  In Java, though, we would like to retain the original
104   // capitalization of the type name.
105   if (field->type() == FieldDescriptor::TYPE_GROUP) {
106     return field->message_type()->name();
107   } else {
108     return field->name();
109   }
110 }
111 
UnderscoresToCamelCaseImpl(const string & input,bool cap_next_letter)112 string UnderscoresToCamelCaseImpl(const string& input, bool cap_next_letter) {
113   string result;
114   // Note:  I distrust ctype.h due to locales.
115   for (int i = 0; i < input.size(); i++) {
116     if ('a' <= input[i] && input[i] <= 'z') {
117       if (cap_next_letter) {
118         result += input[i] + ('A' - 'a');
119       } else {
120         result += input[i];
121       }
122       cap_next_letter = false;
123     } else if ('A' <= input[i] && input[i] <= 'Z') {
124       if (i == 0 && !cap_next_letter) {
125         // Force first letter to lower-case unless explicitly told to
126         // capitalize it.
127         result += input[i] + ('a' - 'A');
128       } else {
129         // Capital letters after the first are left as-is.
130         result += input[i];
131       }
132       cap_next_letter = false;
133     } else if ('0' <= input[i] && input[i] <= '9') {
134       result += input[i];
135       cap_next_letter = true;
136     } else {
137       cap_next_letter = true;
138     }
139   }
140   return result;
141 }
142 
143 }  // namespace
144 
UnderscoresToCamelCase(const FieldDescriptor * field)145 string UnderscoresToCamelCase(const FieldDescriptor* field) {
146   return UnderscoresToCamelCaseImpl(FieldName(field), false);
147 }
148 
UnderscoresToCapitalizedCamelCase(const FieldDescriptor * field)149 string UnderscoresToCapitalizedCamelCase(const FieldDescriptor* field) {
150   return UnderscoresToCamelCaseImpl(FieldName(field), true);
151 }
152 
UnderscoresToCamelCase(const MethodDescriptor * method)153 string UnderscoresToCamelCase(const MethodDescriptor* method) {
154   return UnderscoresToCamelCaseImpl(method->name(), false);
155 }
156 
UnderscoresToCamelCase(const OneofDescriptor * oneof)157 string UnderscoresToCamelCase(const OneofDescriptor* oneof) {
158   return UnderscoresToCamelCaseImpl(oneof->name(), false);
159 }
160 
UnderscoresToCapitalizedCamelCase(const OneofDescriptor * oneof)161 string UnderscoresToCapitalizedCamelCase(const OneofDescriptor* oneof) {
162   return UnderscoresToCamelCaseImpl(oneof->name(), true);
163 }
164 
RenameJavaKeywords(const string & input)165 string RenameJavaKeywords(const string& input) {
166   return sRenameKeywords.RenameJavaKeywordsImpl(input);
167 }
168 
StripProto(const string & filename)169 string StripProto(const string& filename) {
170   if (HasSuffixString(filename, ".protodevel")) {
171     return StripSuffixString(filename, ".protodevel");
172   } else {
173     return StripSuffixString(filename, ".proto");
174   }
175 }
176 
FileClassName(const Params & params,const FileDescriptor * file)177 string FileClassName(const Params& params, const FileDescriptor* file) {
178   if (params.has_java_outer_classname(file->name())) {
179     return params.java_outer_classname(file->name());
180   } else {
181     // Use the filename itself with underscores removed
182     // and a CamelCase style name.
183     string basename;
184     string::size_type last_slash = file->name().find_last_of('/');
185     if (last_slash == string::npos) {
186       basename = file->name();
187     } else {
188       basename = file->name().substr(last_slash + 1);
189     }
190     return UnderscoresToCamelCaseImpl(StripProto(basename), true);
191   }
192 }
193 
FileJavaPackage(const Params & params,const FileDescriptor * file)194 string FileJavaPackage(const Params& params, const FileDescriptor* file) {
195   if (params.has_java_package(file->name())) {
196     return params.java_package(file->name());
197   } else {
198     string result = kDefaultPackage;
199     if (!file->package().empty()) {
200       if (!result.empty()) result += '.';
201       result += file->package();
202     }
203 
204     if (!result.empty()) {
205       result += ".";
206     }
207     result += "nano";
208 
209     return result;
210   }
211 }
212 
IsOuterClassNeeded(const Params & params,const FileDescriptor * file)213 bool IsOuterClassNeeded(const Params& params, const FileDescriptor* file) {
214   // If java_multiple_files is false, the outer class is always needed.
215   if (!params.java_multiple_files(file->name())) {
216     return true;
217   }
218 
219   // File-scope extensions need the outer class as the scope.
220   if (file->extension_count() != 0) {
221     return true;
222   }
223 
224   // If container interfaces are not generated, file-scope enums need the
225   // outer class as the scope.
226   if (file->enum_type_count() != 0 && !params.java_enum_style()) {
227     return true;
228   }
229 
230   return false;
231 }
232 
ToJavaName(const Params & params,const string & name,bool is_class,const Descriptor * parent,const FileDescriptor * file)233 string ToJavaName(const Params& params, const string& name, bool is_class,
234     const Descriptor* parent, const FileDescriptor* file) {
235   string result;
236   if (parent != NULL) {
237     result.append(ClassName(params, parent));
238   } else if (is_class && params.java_multiple_files(file->name())) {
239     result.append(FileJavaPackage(params, file));
240   } else {
241     result.append(ClassName(params, file));
242   }
243   if (!result.empty()) result.append(1, '.');
244   result.append(RenameJavaKeywords(name));
245   return result;
246 }
247 
ClassName(const Params & params,const FileDescriptor * descriptor)248 string ClassName(const Params& params, const FileDescriptor* descriptor) {
249   string result = FileJavaPackage(params, descriptor);
250   if (!result.empty()) result += '.';
251   result += FileClassName(params, descriptor);
252   return result;
253 }
254 
ClassName(const Params & params,const EnumDescriptor * descriptor)255 string ClassName(const Params& params, const EnumDescriptor* descriptor) {
256   const Descriptor* parent = descriptor->containing_type();
257   // When using Java enum style, an enum's class name contains the enum name.
258   // Use the standard ToJavaName translation.
259   if (params.java_enum_style()) {
260     return ToJavaName(params, descriptor->name(), true, parent,
261                       descriptor->file());
262   }
263   // Otherwise the enum members are accessed from the enclosing class.
264   if (parent != NULL) {
265     return ClassName(params, parent);
266   } else {
267     return ClassName(params, descriptor->file());
268   }
269 }
270 
FieldConstantName(const FieldDescriptor * field)271 string FieldConstantName(const FieldDescriptor *field) {
272   string name = field->name() + "_FIELD_NUMBER";
273   UpperString(&name);
274   return name;
275 }
276 
FieldDefaultConstantName(const FieldDescriptor * field)277 string FieldDefaultConstantName(const FieldDescriptor *field) {
278   return "_" + RenameJavaKeywords(UnderscoresToCamelCase(field)) + "Default";
279 }
280 
PrintFieldComment(io::Printer * printer,const FieldDescriptor * field)281 void PrintFieldComment(io::Printer* printer, const FieldDescriptor* field) {
282   // We don't want to print group bodies so we cut off after the first line
283   // (the second line for extensions).
284   string def = field->DebugString();
285   string::size_type first_line_end = def.find_first_of('\n');
286   printer->Print("// $def$\n",
287     "def", def.substr(0, first_line_end));
288   if (field->is_extension()) {
289     string::size_type second_line_start = first_line_end + 1;
290     string::size_type second_line_length =
291         def.find('\n', second_line_start) - second_line_start;
292     printer->Print("// $def$\n",
293       "def", def.substr(second_line_start, second_line_length));
294   }
295 }
296 
GetJavaType(FieldDescriptor::Type field_type)297 JavaType GetJavaType(FieldDescriptor::Type field_type) {
298   switch (field_type) {
299     case FieldDescriptor::TYPE_INT32:
300     case FieldDescriptor::TYPE_UINT32:
301     case FieldDescriptor::TYPE_SINT32:
302     case FieldDescriptor::TYPE_FIXED32:
303     case FieldDescriptor::TYPE_SFIXED32:
304       return JAVATYPE_INT;
305 
306     case FieldDescriptor::TYPE_INT64:
307     case FieldDescriptor::TYPE_UINT64:
308     case FieldDescriptor::TYPE_SINT64:
309     case FieldDescriptor::TYPE_FIXED64:
310     case FieldDescriptor::TYPE_SFIXED64:
311       return JAVATYPE_LONG;
312 
313     case FieldDescriptor::TYPE_FLOAT:
314       return JAVATYPE_FLOAT;
315 
316     case FieldDescriptor::TYPE_DOUBLE:
317       return JAVATYPE_DOUBLE;
318 
319     case FieldDescriptor::TYPE_BOOL:
320       return JAVATYPE_BOOLEAN;
321 
322     case FieldDescriptor::TYPE_STRING:
323       return JAVATYPE_STRING;
324 
325     case FieldDescriptor::TYPE_BYTES:
326       return JAVATYPE_BYTES;
327 
328     case FieldDescriptor::TYPE_ENUM:
329       return JAVATYPE_ENUM;
330 
331     case FieldDescriptor::TYPE_GROUP:
332     case FieldDescriptor::TYPE_MESSAGE:
333       return JAVATYPE_MESSAGE;
334 
335     // No default because we want the compiler to complain if any new
336     // types are added.
337   }
338 
339   GOOGLE_LOG(FATAL) << "Can't get here.";
340   return JAVATYPE_INT;
341 }
342 
PrimitiveTypeName(JavaType type)343 string PrimitiveTypeName(JavaType type) {
344   switch (type) {
345     case JAVATYPE_INT    : return "int";
346     case JAVATYPE_LONG   : return "long";
347     case JAVATYPE_FLOAT  : return "float";
348     case JAVATYPE_DOUBLE : return "double";
349     case JAVATYPE_BOOLEAN: return "boolean";
350     case JAVATYPE_STRING : return "java.lang.String";
351     case JAVATYPE_BYTES  : return "byte[]";
352     case JAVATYPE_ENUM   : return "int";
353     case JAVATYPE_MESSAGE: return "";
354 
355     // No default because we want the compiler to complain if any new
356     // JavaTypes are added.
357   }
358 
359   GOOGLE_LOG(FATAL) << "Can't get here.";
360   return "";
361 }
362 
BoxedPrimitiveTypeName(JavaType type)363 string BoxedPrimitiveTypeName(JavaType type) {
364   switch (type) {
365     case JAVATYPE_INT    : return "java.lang.Integer";
366     case JAVATYPE_LONG   : return "java.lang.Long";
367     case JAVATYPE_FLOAT  : return "java.lang.Float";
368     case JAVATYPE_DOUBLE : return "java.lang.Double";
369     case JAVATYPE_BOOLEAN: return "java.lang.Boolean";
370     case JAVATYPE_STRING : return "java.lang.String";
371     case JAVATYPE_BYTES  : return "byte[]";
372     case JAVATYPE_ENUM   : return "java.lang.Integer";
373     case JAVATYPE_MESSAGE: return "";
374 
375     // No default because we want the compiler to complain if any new
376     // JavaTypes are added.
377   }
378 
379   GOOGLE_LOG(FATAL) << "Can't get here.";
380   return "";
381 }
382 
EmptyArrayName(const Params & params,const FieldDescriptor * field)383 string EmptyArrayName(const Params& params, const FieldDescriptor* field) {
384   switch (GetJavaType(field)) {
385     case JAVATYPE_INT    : return "com.google.protobuf.nano.WireFormatNano.EMPTY_INT_ARRAY";
386     case JAVATYPE_LONG   : return "com.google.protobuf.nano.WireFormatNano.EMPTY_LONG_ARRAY";
387     case JAVATYPE_FLOAT  : return "com.google.protobuf.nano.WireFormatNano.EMPTY_FLOAT_ARRAY";
388     case JAVATYPE_DOUBLE : return "com.google.protobuf.nano.WireFormatNano.EMPTY_DOUBLE_ARRAY";
389     case JAVATYPE_BOOLEAN: return "com.google.protobuf.nano.WireFormatNano.EMPTY_BOOLEAN_ARRAY";
390     case JAVATYPE_STRING : return "com.google.protobuf.nano.WireFormatNano.EMPTY_STRING_ARRAY";
391     case JAVATYPE_BYTES  : return "com.google.protobuf.nano.WireFormatNano.EMPTY_BYTES_ARRAY";
392     case JAVATYPE_ENUM   : return "com.google.protobuf.nano.WireFormatNano.EMPTY_INT_ARRAY";
393     case JAVATYPE_MESSAGE: return ClassName(params, field->message_type()) + ".EMPTY_ARRAY";
394 
395     // No default because we want the compiler to complain if any new
396     // JavaTypes are added.
397   }
398 
399   GOOGLE_LOG(FATAL) << "Can't get here.";
400   return "";
401 }
402 
DefaultValue(const Params & params,const FieldDescriptor * field)403 string DefaultValue(const Params& params, const FieldDescriptor* field) {
404   if (field->label() == FieldDescriptor::LABEL_REPEATED) {
405     return EmptyArrayName(params, field);
406   }
407 
408   if (params.use_reference_types_for_primitives()) {
409     if (params.reftypes_primitive_enums()
410           && field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
411       return "Integer.MIN_VALUE";
412     }
413     return "null";
414   }
415 
416   // Switch on cpp_type since we need to know which default_value_* method
417   // of FieldDescriptor to call.
418   switch (field->cpp_type()) {
419     case FieldDescriptor::CPPTYPE_INT32:
420       return SimpleItoa(field->default_value_int32());
421     case FieldDescriptor::CPPTYPE_UINT32:
422       // Need to print as a signed int since Java has no unsigned.
423       return SimpleItoa(static_cast<int32>(field->default_value_uint32()));
424     case FieldDescriptor::CPPTYPE_INT64:
425       return SimpleItoa(field->default_value_int64()) + "L";
426     case FieldDescriptor::CPPTYPE_UINT64:
427       return SimpleItoa(static_cast<int64>(field->default_value_uint64())) +
428              "L";
429     case FieldDescriptor::CPPTYPE_DOUBLE: {
430       double value = field->default_value_double();
431       if (value == numeric_limits<double>::infinity()) {
432         return "Double.POSITIVE_INFINITY";
433       } else if (value == -numeric_limits<double>::infinity()) {
434         return "Double.NEGATIVE_INFINITY";
435       } else if (value != value) {
436         return "Double.NaN";
437       } else {
438         return SimpleDtoa(value) + "D";
439       }
440     }
441     case FieldDescriptor::CPPTYPE_FLOAT: {
442       float value = field->default_value_float();
443       if (value == numeric_limits<float>::infinity()) {
444         return "Float.POSITIVE_INFINITY";
445       } else if (value == -numeric_limits<float>::infinity()) {
446         return "Float.NEGATIVE_INFINITY";
447       } else if (value != value) {
448         return "Float.NaN";
449       } else {
450         return SimpleFtoa(value) + "F";
451       }
452     }
453     case FieldDescriptor::CPPTYPE_BOOL:
454       return field->default_value_bool() ? "true" : "false";
455     case FieldDescriptor::CPPTYPE_STRING:
456       if (!field->default_value_string().empty()) {
457         // Point it to the static final in the generated code.
458         return FieldDefaultConstantName(field);
459       } else {
460         if (field->type() == FieldDescriptor::TYPE_BYTES) {
461           return "com.google.protobuf.nano.WireFormatNano.EMPTY_BYTES";
462         } else {
463           return "\"\"";
464         }
465       }
466 
467     case FieldDescriptor::CPPTYPE_ENUM:
468       return ClassName(params, field->enum_type()) + "." +
469              RenameJavaKeywords(field->default_value_enum()->name());
470 
471     case FieldDescriptor::CPPTYPE_MESSAGE:
472       return "null";
473 
474     // No default because we want the compiler to complain if any new
475     // types are added.
476   }
477 
478   GOOGLE_LOG(FATAL) << "Can't get here.";
479   return "";
480 }
481 
482 
483 static const char* kBitMasks[] = {
484   "0x00000001",
485   "0x00000002",
486   "0x00000004",
487   "0x00000008",
488   "0x00000010",
489   "0x00000020",
490   "0x00000040",
491   "0x00000080",
492 
493   "0x00000100",
494   "0x00000200",
495   "0x00000400",
496   "0x00000800",
497   "0x00001000",
498   "0x00002000",
499   "0x00004000",
500   "0x00008000",
501 
502   "0x00010000",
503   "0x00020000",
504   "0x00040000",
505   "0x00080000",
506   "0x00100000",
507   "0x00200000",
508   "0x00400000",
509   "0x00800000",
510 
511   "0x01000000",
512   "0x02000000",
513   "0x04000000",
514   "0x08000000",
515   "0x10000000",
516   "0x20000000",
517   "0x40000000",
518   "0x80000000",
519 };
520 
GetBitFieldName(int index)521 string GetBitFieldName(int index) {
522   string var_name = "bitField";
523   var_name += SimpleItoa(index);
524   var_name += "_";
525   return var_name;
526 }
527 
GetBitFieldNameForBit(int bit_index)528 string GetBitFieldNameForBit(int bit_index) {
529   return GetBitFieldName(bit_index / 32);
530 }
531 
GenerateGetBit(int bit_index)532 string GenerateGetBit(int bit_index) {
533   string var_name = GetBitFieldNameForBit(bit_index);
534   int bit_in_var_index = bit_index % 32;
535 
536   string mask = kBitMasks[bit_in_var_index];
537   string result = "((" + var_name + " & " + mask + ") != 0)";
538   return result;
539 }
540 
GenerateSetBit(int bit_index)541 string GenerateSetBit(int bit_index) {
542   string var_name = GetBitFieldNameForBit(bit_index);
543   int bit_in_var_index = bit_index % 32;
544 
545   string mask = kBitMasks[bit_in_var_index];
546   string result = var_name + " |= " + mask;
547   return result;
548 }
549 
GenerateClearBit(int bit_index)550 string GenerateClearBit(int bit_index) {
551   string var_name = GetBitFieldNameForBit(bit_index);
552   int bit_in_var_index = bit_index % 32;
553 
554   string mask = kBitMasks[bit_in_var_index];
555   string result = var_name + " = (" + var_name + " & ~" + mask + ")";
556   return result;
557 }
558 
GenerateDifferentBit(int bit_index)559 string GenerateDifferentBit(int bit_index) {
560   string var_name = GetBitFieldNameForBit(bit_index);
561   int bit_in_var_index = bit_index % 32;
562 
563   string mask = kBitMasks[bit_in_var_index];
564   string result = "((" + var_name + " & " + mask
565       + ") != (other." + var_name + " & " + mask + "))";
566   return result;
567 }
568 
SetBitOperationVariables(const string name,int bitIndex,map<string,string> * variables)569 void SetBitOperationVariables(const string name,
570     int bitIndex, map<string, string>* variables) {
571   (*variables)["get_" + name] = GenerateGetBit(bitIndex);
572   (*variables)["set_" + name] = GenerateSetBit(bitIndex);
573   (*variables)["clear_" + name] = GenerateClearBit(bitIndex);
574   (*variables)["different_" + name] = GenerateDifferentBit(bitIndex);
575 }
576 
HasMapField(const Descriptor * descriptor)577 bool HasMapField(const Descriptor* descriptor) {
578   for (int i = 0; i < descriptor->field_count(); ++i) {
579     const FieldDescriptor* field = descriptor->field(i);
580     if (field->type() == FieldDescriptor::TYPE_MESSAGE &&
581         IsMapEntry(field->message_type())) {
582       return true;
583     }
584   }
585   return false;
586 }
587 
588 }  // namespace javanano
589 }  // namespace compiler
590 }  // namespace protobuf
591 }  // namespace google
592