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
45namespace google {
46namespace protobuf {
47namespace compiler {
48namespace javanano {
49
50const char kThickSeparator[] =
51  "// ===================================================================\n";
52const char kThinSeparator[] =
53  "// -------------------------------------------------------------------\n";
54
55class RenameKeywords {
56 private:
57  hash_set<string> java_keywords_set_;
58
59 public:
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)
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
95static RenameKeywords sRenameKeywords;
96
97namespace {
98
99const char* kDefaultPackage = "";
100
101const 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
112string 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
145string UnderscoresToCamelCase(const FieldDescriptor* field) {
146  return UnderscoresToCamelCaseImpl(FieldName(field), false);
147}
148
149string UnderscoresToCapitalizedCamelCase(const FieldDescriptor* field) {
150  return UnderscoresToCamelCaseImpl(FieldName(field), true);
151}
152
153string UnderscoresToCamelCase(const MethodDescriptor* method) {
154  return UnderscoresToCamelCaseImpl(method->name(), false);
155}
156
157string RenameJavaKeywords(const string& input) {
158  return sRenameKeywords.RenameJavaKeywordsImpl(input);
159}
160
161string StripProto(const string& filename) {
162  if (HasSuffixString(filename, ".protodevel")) {
163    return StripSuffixString(filename, ".protodevel");
164  } else {
165    return StripSuffixString(filename, ".proto");
166  }
167}
168
169string FileClassName(const Params& params, const FileDescriptor* file) {
170  if (params.has_java_outer_classname(file->name())) {
171    return params.java_outer_classname(file->name());
172  } else {
173    // Use the filename itself with underscores removed
174    // and a CamelCase style name.
175    string basename;
176    string::size_type last_slash = file->name().find_last_of('/');
177    if (last_slash == string::npos) {
178      basename = file->name();
179    } else {
180      basename = file->name().substr(last_slash + 1);
181    }
182    return UnderscoresToCamelCaseImpl(StripProto(basename), true);
183  }
184}
185
186string FileJavaPackage(const Params& params, const FileDescriptor* file) {
187  if (params.has_java_package(file->name())) {
188    return params.java_package(file->name());
189  } else {
190    string result = kDefaultPackage;
191    if (!file->package().empty()) {
192      if (!result.empty()) result += '.';
193      result += file->package();
194    }
195    return result;
196  }
197}
198
199bool IsOuterClassNeeded(const Params& params, const FileDescriptor* file) {
200  // If java_multiple_files is false, the outer class is always needed.
201  if (!params.java_multiple_files(file->name())) {
202    return true;
203  }
204
205  // File-scope extensions need the outer class as the scope.
206  if (file->extension_count() != 0) {
207    return true;
208  }
209
210  // If container interfaces are not generated, file-scope enums need the
211  // outer class as the scope.
212  if (file->enum_type_count() != 0 && !params.java_enum_style()) {
213    return true;
214  }
215
216  return false;
217}
218
219string ToJavaName(const Params& params, const string& name, bool is_class,
220    const Descriptor* parent, const FileDescriptor* file) {
221  string result;
222  if (parent != NULL) {
223    result.append(ClassName(params, parent));
224  } else if (is_class && params.java_multiple_files(file->name())) {
225    result.append(FileJavaPackage(params, file));
226  } else {
227    result.append(ClassName(params, file));
228  }
229  if (!result.empty()) result.append(1, '.');
230  result.append(RenameJavaKeywords(name));
231  return result;
232}
233
234string ClassName(const Params& params, const FileDescriptor* descriptor) {
235  string result = FileJavaPackage(params, descriptor);
236  if (!result.empty()) result += '.';
237  result += FileClassName(params, descriptor);
238  return result;
239}
240
241string ClassName(const Params& params, const EnumDescriptor* descriptor) {
242  const Descriptor* parent = descriptor->containing_type();
243  // When using Java enum style, an enum's class name contains the enum name.
244  // Use the standard ToJavaName translation.
245  if (params.java_enum_style()) {
246    return ToJavaName(params, descriptor->name(), true, parent,
247                      descriptor->file());
248  }
249  // Otherwise the enum members are accessed from the enclosing class.
250  if (parent != NULL) {
251    return ClassName(params, parent);
252  } else {
253    return ClassName(params, descriptor->file());
254  }
255}
256
257string FieldConstantName(const FieldDescriptor *field) {
258  string name = field->name() + "_FIELD_NUMBER";
259  UpperString(&name);
260  return name;
261}
262
263string FieldDefaultConstantName(const FieldDescriptor *field) {
264  return "_" + RenameJavaKeywords(UnderscoresToCamelCase(field)) + "Default";
265}
266
267void PrintFieldComment(io::Printer* printer, const FieldDescriptor* field) {
268  // We don't want to print group bodies so we cut off after the first line
269  // (the second line for extensions).
270  string def = field->DebugString();
271  string::size_type first_line_end = def.find_first_of('\n');
272  printer->Print("// $def$\n",
273    "def", def.substr(0, first_line_end));
274  if (field->is_extension()) {
275    string::size_type second_line_start = first_line_end + 1;
276    string::size_type second_line_length =
277        def.find('\n', second_line_start) - second_line_start;
278    printer->Print("// $def$\n",
279      "def", def.substr(second_line_start, second_line_length));
280  }
281}
282
283JavaType GetJavaType(FieldDescriptor::Type field_type) {
284  switch (field_type) {
285    case FieldDescriptor::TYPE_INT32:
286    case FieldDescriptor::TYPE_UINT32:
287    case FieldDescriptor::TYPE_SINT32:
288    case FieldDescriptor::TYPE_FIXED32:
289    case FieldDescriptor::TYPE_SFIXED32:
290      return JAVATYPE_INT;
291
292    case FieldDescriptor::TYPE_INT64:
293    case FieldDescriptor::TYPE_UINT64:
294    case FieldDescriptor::TYPE_SINT64:
295    case FieldDescriptor::TYPE_FIXED64:
296    case FieldDescriptor::TYPE_SFIXED64:
297      return JAVATYPE_LONG;
298
299    case FieldDescriptor::TYPE_FLOAT:
300      return JAVATYPE_FLOAT;
301
302    case FieldDescriptor::TYPE_DOUBLE:
303      return JAVATYPE_DOUBLE;
304
305    case FieldDescriptor::TYPE_BOOL:
306      return JAVATYPE_BOOLEAN;
307
308    case FieldDescriptor::TYPE_STRING:
309      return JAVATYPE_STRING;
310
311    case FieldDescriptor::TYPE_BYTES:
312      return JAVATYPE_BYTES;
313
314    case FieldDescriptor::TYPE_ENUM:
315      return JAVATYPE_ENUM;
316
317    case FieldDescriptor::TYPE_GROUP:
318    case FieldDescriptor::TYPE_MESSAGE:
319      return JAVATYPE_MESSAGE;
320
321    // No default because we want the compiler to complain if any new
322    // types are added.
323  }
324
325  GOOGLE_LOG(FATAL) << "Can't get here.";
326  return JAVATYPE_INT;
327}
328
329string PrimitiveTypeName(JavaType type) {
330  switch (type) {
331    case JAVATYPE_INT    : return "int";
332    case JAVATYPE_LONG   : return "long";
333    case JAVATYPE_FLOAT  : return "float";
334    case JAVATYPE_DOUBLE : return "double";
335    case JAVATYPE_BOOLEAN: return "boolean";
336    case JAVATYPE_STRING : return "java.lang.String";
337    case JAVATYPE_BYTES  : return "byte[]";
338    case JAVATYPE_ENUM   : return "int";
339    case JAVATYPE_MESSAGE: return "";
340
341    // No default because we want the compiler to complain if any new
342    // JavaTypes are added.
343  }
344
345  GOOGLE_LOG(FATAL) << "Can't get here.";
346  return "";
347}
348
349string BoxedPrimitiveTypeName(JavaType type) {
350  switch (type) {
351    case JAVATYPE_INT    : return "java.lang.Integer";
352    case JAVATYPE_LONG   : return "java.lang.Long";
353    case JAVATYPE_FLOAT  : return "java.lang.Float";
354    case JAVATYPE_DOUBLE : return "java.lang.Double";
355    case JAVATYPE_BOOLEAN: return "java.lang.Boolean";
356    case JAVATYPE_STRING : return "java.lang.String";
357    case JAVATYPE_BYTES  : return "byte[]";
358    case JAVATYPE_ENUM   : return "java.lang.Integer";
359    case JAVATYPE_MESSAGE: return "";
360
361    // No default because we want the compiler to complain if any new
362    // JavaTypes are added.
363  }
364
365  GOOGLE_LOG(FATAL) << "Can't get here.";
366  return "";
367}
368
369string EmptyArrayName(const Params& params, const FieldDescriptor* field) {
370  switch (GetJavaType(field)) {
371    case JAVATYPE_INT    : return "com.google.protobuf.nano.WireFormatNano.EMPTY_INT_ARRAY";
372    case JAVATYPE_LONG   : return "com.google.protobuf.nano.WireFormatNano.EMPTY_LONG_ARRAY";
373    case JAVATYPE_FLOAT  : return "com.google.protobuf.nano.WireFormatNano.EMPTY_FLOAT_ARRAY";
374    case JAVATYPE_DOUBLE : return "com.google.protobuf.nano.WireFormatNano.EMPTY_DOUBLE_ARRAY";
375    case JAVATYPE_BOOLEAN: return "com.google.protobuf.nano.WireFormatNano.EMPTY_BOOLEAN_ARRAY";
376    case JAVATYPE_STRING : return "com.google.protobuf.nano.WireFormatNano.EMPTY_STRING_ARRAY";
377    case JAVATYPE_BYTES  : return "com.google.protobuf.nano.WireFormatNano.EMPTY_BYTES_ARRAY";
378    case JAVATYPE_ENUM   : return "com.google.protobuf.nano.WireFormatNano.EMPTY_INT_ARRAY";
379    case JAVATYPE_MESSAGE: return ClassName(params, field->message_type()) + ".EMPTY_ARRAY";
380
381    // No default because we want the compiler to complain if any new
382    // JavaTypes are added.
383  }
384
385  GOOGLE_LOG(FATAL) << "Can't get here.";
386  return "";
387}
388
389string DefaultValue(const Params& params, const FieldDescriptor* field) {
390  if (field->label() == FieldDescriptor::LABEL_REPEATED) {
391    return EmptyArrayName(params, field);
392  }
393
394  if (params.use_reference_types_for_primitives()) {
395    if (params.reftypes_primitive_enums()
396          && field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
397      return "Integer.MIN_VALUE";
398    }
399    return "null";
400  }
401
402  // Switch on cpp_type since we need to know which default_value_* method
403  // of FieldDescriptor to call.
404  switch (field->cpp_type()) {
405    case FieldDescriptor::CPPTYPE_INT32:
406      return SimpleItoa(field->default_value_int32());
407    case FieldDescriptor::CPPTYPE_UINT32:
408      // Need to print as a signed int since Java has no unsigned.
409      return SimpleItoa(static_cast<int32>(field->default_value_uint32()));
410    case FieldDescriptor::CPPTYPE_INT64:
411      return SimpleItoa(field->default_value_int64()) + "L";
412    case FieldDescriptor::CPPTYPE_UINT64:
413      return SimpleItoa(static_cast<int64>(field->default_value_uint64())) +
414             "L";
415    case FieldDescriptor::CPPTYPE_DOUBLE: {
416      double value = field->default_value_double();
417      if (value == numeric_limits<double>::infinity()) {
418        return "Double.POSITIVE_INFINITY";
419      } else if (value == -numeric_limits<double>::infinity()) {
420        return "Double.NEGATIVE_INFINITY";
421      } else if (value != value) {
422        return "Double.NaN";
423      } else {
424        return SimpleDtoa(value) + "D";
425      }
426    }
427    case FieldDescriptor::CPPTYPE_FLOAT: {
428      float value = field->default_value_float();
429      if (value == numeric_limits<float>::infinity()) {
430        return "Float.POSITIVE_INFINITY";
431      } else if (value == -numeric_limits<float>::infinity()) {
432        return "Float.NEGATIVE_INFINITY";
433      } else if (value != value) {
434        return "Float.NaN";
435      } else {
436        return SimpleFtoa(value) + "F";
437      }
438    }
439    case FieldDescriptor::CPPTYPE_BOOL:
440      return field->default_value_bool() ? "true" : "false";
441    case FieldDescriptor::CPPTYPE_STRING:
442      if (!field->default_value_string().empty()) {
443        // Point it to the static final in the generated code.
444        return FieldDefaultConstantName(field);
445      } else {
446        if (field->type() == FieldDescriptor::TYPE_BYTES) {
447          return "com.google.protobuf.nano.WireFormatNano.EMPTY_BYTES";
448        } else {
449          return "\"\"";
450        }
451      }
452
453    case FieldDescriptor::CPPTYPE_ENUM:
454      return ClassName(params, field->enum_type()) + "." +
455             RenameJavaKeywords(field->default_value_enum()->name());
456
457    case FieldDescriptor::CPPTYPE_MESSAGE:
458      return "null";
459
460    // No default because we want the compiler to complain if any new
461    // types are added.
462  }
463
464  GOOGLE_LOG(FATAL) << "Can't get here.";
465  return "";
466}
467
468
469static const char* kBitMasks[] = {
470  "0x00000001",
471  "0x00000002",
472  "0x00000004",
473  "0x00000008",
474  "0x00000010",
475  "0x00000020",
476  "0x00000040",
477  "0x00000080",
478
479  "0x00000100",
480  "0x00000200",
481  "0x00000400",
482  "0x00000800",
483  "0x00001000",
484  "0x00002000",
485  "0x00004000",
486  "0x00008000",
487
488  "0x00010000",
489  "0x00020000",
490  "0x00040000",
491  "0x00080000",
492  "0x00100000",
493  "0x00200000",
494  "0x00400000",
495  "0x00800000",
496
497  "0x01000000",
498  "0x02000000",
499  "0x04000000",
500  "0x08000000",
501  "0x10000000",
502  "0x20000000",
503  "0x40000000",
504  "0x80000000",
505};
506
507string GetBitFieldName(int index) {
508  string var_name = "bitField";
509  var_name += SimpleItoa(index);
510  var_name += "_";
511  return var_name;
512}
513
514string GetBitFieldNameForBit(int bit_index) {
515  return GetBitFieldName(bit_index / 32);
516}
517
518string GenerateGetBit(int bit_index) {
519  string var_name = GetBitFieldNameForBit(bit_index);
520  int bit_in_var_index = bit_index % 32;
521
522  string mask = kBitMasks[bit_in_var_index];
523  string result = "((" + var_name + " & " + mask + ") != 0)";
524  return result;
525}
526
527string GenerateSetBit(int bit_index) {
528  string var_name = GetBitFieldNameForBit(bit_index);
529  int bit_in_var_index = bit_index % 32;
530
531  string mask = kBitMasks[bit_in_var_index];
532  string result = var_name + " |= " + mask;
533  return result;
534}
535
536string GenerateClearBit(int bit_index) {
537  string var_name = GetBitFieldNameForBit(bit_index);
538  int bit_in_var_index = bit_index % 32;
539
540  string mask = kBitMasks[bit_in_var_index];
541  string result = var_name + " = (" + var_name + " & ~" + mask + ")";
542  return result;
543}
544
545string GenerateDifferentBit(int bit_index) {
546  string var_name = GetBitFieldNameForBit(bit_index);
547  int bit_in_var_index = bit_index % 32;
548
549  string mask = kBitMasks[bit_in_var_index];
550  string result = "((" + var_name + " & " + mask
551      + ") != (other." + var_name + " & " + mask + "))";
552  return result;
553}
554
555void SetBitOperationVariables(const string name,
556    int bitIndex, map<string, string>* variables) {
557  (*variables)["get_" + name] = GenerateGetBit(bitIndex);
558  (*variables)["set_" + name] = GenerateSetBit(bitIndex);
559  (*variables)["clear_" + name] = GenerateClearBit(bitIndex);
560  (*variables)["different_" + name] = GenerateDifferentBit(bitIndex);
561}
562
563}  // namespace javanano
564}  // namespace compiler
565}  // namespace protobuf
566}  // namespace google
567