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