• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc.  All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file or at
6 // https://developers.google.com/open-source/licenses/bsd
7 
8 #include "google/protobuf/compiler/objectivec/helpers.h"
9 
10 #include <climits>
11 #include <cstddef>
12 #include <cstdint>
13 #include <string>
14 #include <vector>
15 
16 #include "absl/log/absl_check.h"
17 #include "absl/log/absl_log.h"
18 #include "absl/strings/ascii.h"
19 #include "absl/strings/escaping.h"
20 #include "absl/strings/match.h"
21 #include "absl/strings/str_cat.h"
22 #include "absl/strings/str_replace.h"
23 #include "absl/strings/str_split.h"
24 #include "absl/strings/string_view.h"
25 #include "absl/strings/strip.h"
26 #include "google/protobuf/compiler/objectivec/names.h"
27 #include "google/protobuf/compiler/objectivec/options.h"
28 #include "google/protobuf/descriptor.h"
29 #include "google/protobuf/io/strtod.h"
30 #include "google/protobuf/stubs/common.h"
31 
32 // NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some
33 // error cases, so it seems to be ok to use as a back door for errors.
34 
35 namespace google {
36 namespace protobuf {
37 namespace compiler {
38 namespace objectivec {
39 
EscapeTrigraphs(absl::string_view to_escape)40 std::string EscapeTrigraphs(absl::string_view to_escape) {
41   return absl::StrReplaceAll(to_escape, {{"?", "\\?"}});
42 }
43 
44 namespace {
45 
GetZeroEnumNameForFlagType(const FlagType flag_type)46 std::string GetZeroEnumNameForFlagType(const FlagType flag_type) {
47   switch (flag_type) {
48     case FLAGTYPE_DESCRIPTOR_INITIALIZATION:
49       return "GPBDescriptorInitializationFlag_None";
50     case FLAGTYPE_EXTENSION:
51       return "GPBExtensionNone";
52     case FLAGTYPE_FIELD:
53       return "GPBFieldNone";
54     default:
55       ABSL_LOG(FATAL) << "Can't get here.";
56       return "0";
57   }
58 }
59 
GetEnumNameForFlagType(const FlagType flag_type)60 std::string GetEnumNameForFlagType(const FlagType flag_type) {
61   switch (flag_type) {
62     case FLAGTYPE_DESCRIPTOR_INITIALIZATION:
63       return "GPBDescriptorInitializationFlags";
64     case FLAGTYPE_EXTENSION:
65       return "GPBExtensionOptions";
66     case FLAGTYPE_FIELD:
67       return "GPBFieldFlags";
68     default:
69       ABSL_LOG(FATAL) << "Can't get here.";
70       return std::string();
71   }
72 }
73 
HandleExtremeFloatingPoint(std::string val,bool add_float_suffix)74 std::string HandleExtremeFloatingPoint(std::string val, bool add_float_suffix) {
75   if (val == "nan") {
76     return "NAN";
77   } else if (val == "inf") {
78     return "INFINITY";
79   } else if (val == "-inf") {
80     return "-INFINITY";
81   } else {
82     // float strings with ., e or E need to have f appended
83     if (add_float_suffix &&
84         (absl::StrContains(val, '.') || absl::StrContains(val, 'e') ||
85          absl::StrContains(val, 'E'))) {
86       return absl::StrCat(val, "f");
87     }
88     return val;
89   }
90 }
91 
92 const char* kDescriptorProtoName = "google/protobuf/descriptor.proto";
93 
94 }  // namespace
95 
ExtensionIsCustomOption(const FieldDescriptor * extension_field)96 bool ExtensionIsCustomOption(const FieldDescriptor* extension_field) {
97   return extension_field->containing_type()->file()->name() ==
98          kDescriptorProtoName;
99 }
100 
GetCapitalizedType(const FieldDescriptor * field)101 std::string GetCapitalizedType(const FieldDescriptor* field) {
102   switch (field->type()) {
103     case FieldDescriptor::TYPE_INT32:
104       return "Int32";
105     case FieldDescriptor::TYPE_UINT32:
106       return "UInt32";
107     case FieldDescriptor::TYPE_SINT32:
108       return "SInt32";
109     case FieldDescriptor::TYPE_FIXED32:
110       return "Fixed32";
111     case FieldDescriptor::TYPE_SFIXED32:
112       return "SFixed32";
113     case FieldDescriptor::TYPE_INT64:
114       return "Int64";
115     case FieldDescriptor::TYPE_UINT64:
116       return "UInt64";
117     case FieldDescriptor::TYPE_SINT64:
118       return "SInt64";
119     case FieldDescriptor::TYPE_FIXED64:
120       return "Fixed64";
121     case FieldDescriptor::TYPE_SFIXED64:
122       return "SFixed64";
123     case FieldDescriptor::TYPE_FLOAT:
124       return "Float";
125     case FieldDescriptor::TYPE_DOUBLE:
126       return "Double";
127     case FieldDescriptor::TYPE_BOOL:
128       return "Bool";
129     case FieldDescriptor::TYPE_STRING:
130       return "String";
131     case FieldDescriptor::TYPE_BYTES:
132       return "Bytes";
133     case FieldDescriptor::TYPE_ENUM:
134       return "Enum";
135     case FieldDescriptor::TYPE_GROUP:
136       return "Group";
137     case FieldDescriptor::TYPE_MESSAGE:
138       return "Message";
139   }
140 
141   // Some compilers report reaching end of function even though all cases of
142   // the enum are handed in the switch.
143   ABSL_LOG(FATAL) << "Can't get here.";
144   return std::string();
145 }
146 
GetObjectiveCType(FieldDescriptor::Type field_type)147 ObjectiveCType GetObjectiveCType(FieldDescriptor::Type field_type) {
148   switch (field_type) {
149     case FieldDescriptor::TYPE_INT32:
150     case FieldDescriptor::TYPE_SINT32:
151     case FieldDescriptor::TYPE_SFIXED32:
152       return OBJECTIVECTYPE_INT32;
153 
154     case FieldDescriptor::TYPE_UINT32:
155     case FieldDescriptor::TYPE_FIXED32:
156       return OBJECTIVECTYPE_UINT32;
157 
158     case FieldDescriptor::TYPE_INT64:
159     case FieldDescriptor::TYPE_SINT64:
160     case FieldDescriptor::TYPE_SFIXED64:
161       return OBJECTIVECTYPE_INT64;
162 
163     case FieldDescriptor::TYPE_UINT64:
164     case FieldDescriptor::TYPE_FIXED64:
165       return OBJECTIVECTYPE_UINT64;
166 
167     case FieldDescriptor::TYPE_FLOAT:
168       return OBJECTIVECTYPE_FLOAT;
169 
170     case FieldDescriptor::TYPE_DOUBLE:
171       return OBJECTIVECTYPE_DOUBLE;
172 
173     case FieldDescriptor::TYPE_BOOL:
174       return OBJECTIVECTYPE_BOOLEAN;
175 
176     case FieldDescriptor::TYPE_STRING:
177       return OBJECTIVECTYPE_STRING;
178 
179     case FieldDescriptor::TYPE_BYTES:
180       return OBJECTIVECTYPE_DATA;
181 
182     case FieldDescriptor::TYPE_ENUM:
183       return OBJECTIVECTYPE_ENUM;
184 
185     case FieldDescriptor::TYPE_GROUP:
186     case FieldDescriptor::TYPE_MESSAGE:
187       return OBJECTIVECTYPE_MESSAGE;
188   }
189 
190   // Some compilers report reaching end of function even though all cases of
191   // the enum are handed in the switch.
192   ABSL_LOG(FATAL) << "Can't get here.";
193   return OBJECTIVECTYPE_INT32;
194 }
195 
GPBGenericValueFieldName(const FieldDescriptor * field)196 std::string GPBGenericValueFieldName(const FieldDescriptor* field) {
197   // Returns the field within the GPBGenericValue union to use for the given
198   // field.
199   if (field->is_repeated()) {
200     return "valueMessage";
201   }
202   switch (field->cpp_type()) {
203     case FieldDescriptor::CPPTYPE_INT32:
204       return "valueInt32";
205     case FieldDescriptor::CPPTYPE_UINT32:
206       return "valueUInt32";
207     case FieldDescriptor::CPPTYPE_INT64:
208       return "valueInt64";
209     case FieldDescriptor::CPPTYPE_UINT64:
210       return "valueUInt64";
211     case FieldDescriptor::CPPTYPE_FLOAT:
212       return "valueFloat";
213     case FieldDescriptor::CPPTYPE_DOUBLE:
214       return "valueDouble";
215     case FieldDescriptor::CPPTYPE_BOOL:
216       return "valueBool";
217     case FieldDescriptor::CPPTYPE_STRING:
218       if (field->type() == FieldDescriptor::TYPE_BYTES) {
219         return "valueData";
220       } else {
221         return "valueString";
222       }
223     case FieldDescriptor::CPPTYPE_ENUM:
224       return "valueEnum";
225     case FieldDescriptor::CPPTYPE_MESSAGE:
226       return "valueMessage";
227   }
228 
229   // Some compilers report reaching end of function even though all cases of
230   // the enum are handed in the switch.
231   ABSL_LOG(FATAL) << "Can't get here.";
232   return std::string();
233 }
234 
DefaultValue(const FieldDescriptor * field)235 std::string DefaultValue(const FieldDescriptor* field) {
236   // Repeated fields don't have defaults.
237   if (field->is_repeated()) {
238     return "nil";
239   }
240 
241   // Switch on cpp_type since we need to know which default_value_* method
242   // of FieldDescriptor to call.
243   switch (field->cpp_type()) {
244     case FieldDescriptor::CPPTYPE_INT32:
245       // gcc and llvm reject the decimal form of kint32min and kint64min.
246       if (field->default_value_int32() == INT_MIN) {
247         return "-0x80000000";
248       }
249       return absl::StrCat(field->default_value_int32());
250     case FieldDescriptor::CPPTYPE_UINT32:
251       return absl::StrCat(field->default_value_uint32(), "U");
252     case FieldDescriptor::CPPTYPE_INT64:
253       // gcc and llvm reject the decimal form of kint32min and kint64min.
254       if (field->default_value_int64() == LLONG_MIN) {
255         return "-0x8000000000000000LL";
256       }
257       return absl::StrCat(field->default_value_int64(), "LL");
258     case FieldDescriptor::CPPTYPE_UINT64:
259       return absl::StrCat(field->default_value_uint64(), "ULL");
260     case FieldDescriptor::CPPTYPE_DOUBLE:
261       return HandleExtremeFloatingPoint(
262           io::SimpleDtoa(field->default_value_double()), false);
263     case FieldDescriptor::CPPTYPE_FLOAT:
264       return HandleExtremeFloatingPoint(
265           io::SimpleFtoa(field->default_value_float()), true);
266     case FieldDescriptor::CPPTYPE_BOOL:
267       return field->default_value_bool() ? "YES" : "NO";
268     case FieldDescriptor::CPPTYPE_STRING: {
269       const bool has_default_value = field->has_default_value();
270       absl::string_view default_string = field->default_value_string();
271       if (!has_default_value || default_string.empty()) {
272         // If the field is defined as being the empty string,
273         // then we will just assign to nil, as the empty string is the
274         // default for both strings and data.
275         return "nil";
276       }
277       if (field->type() == FieldDescriptor::TYPE_BYTES) {
278         // We want constant fields in our data structures so we can
279         // declare them as static. To achieve this we cheat and stuff
280         // a escaped c string (prefixed with a length) into the data
281         // field, and cast it to an (NSData*) so it will compile.
282         // The runtime library knows how to handle it.
283 
284         // Must convert to a standard byte order for packing length into
285         // a cstring.
286         uint32_t length = ghtonl(default_string.length());
287         std::string bytes((const char*)&length, sizeof(length));
288         absl::StrAppend(&bytes, default_string);
289         return absl::StrCat("(NSData*)\"",
290                             EscapeTrigraphs(absl::CEscape(bytes)), "\"");
291       } else {
292         return absl::StrCat(
293             "@\"", EscapeTrigraphs(absl::CEscape(default_string)), "\"");
294       }
295     }
296     case FieldDescriptor::CPPTYPE_ENUM:
297       return EnumValueName(field->default_value_enum());
298     case FieldDescriptor::CPPTYPE_MESSAGE:
299       return "nil";
300   }
301 
302   // Some compilers report reaching end of function even though all cases of
303   // the enum are handed in the switch.
304   ABSL_LOG(FATAL) << "Can't get here.";
305   return std::string();
306 }
307 
BuildFlagsString(FlagType flag_type,const std::vector<std::string> & strings)308 std::string BuildFlagsString(FlagType flag_type,
309                              const std::vector<std::string>& strings) {
310   if (strings.empty()) {
311     return GetZeroEnumNameForFlagType(flag_type);
312   } else if (strings.size() == 1) {
313     return strings[0];
314   }
315   std::string string =
316       absl::StrCat("(", GetEnumNameForFlagType(flag_type), ")(");
317   for (size_t i = 0; i != strings.size(); ++i) {
318     if (i > 0) {
319       string.append(" | ");
320     }
321     string.append(strings[i]);
322   }
323   string.append(")");
324   return string;
325 }
326 
ObjCClass(absl::string_view class_name)327 std::string ObjCClass(absl::string_view class_name) {
328   return absl::StrCat("GPBObjCClass(", class_name, ")");
329 }
330 
ObjCClassDeclaration(absl::string_view class_name)331 std::string ObjCClassDeclaration(absl::string_view class_name) {
332   return absl::StrCat("GPBObjCClassDeclaration(", class_name, ");");
333 }
334 
EmitCommentsString(io::Printer * printer,const GenerationOptions & opts,const SourceLocation & location,CommentStringFlags flags)335 void EmitCommentsString(io::Printer* printer, const GenerationOptions& opts,
336                         const SourceLocation& location,
337                         CommentStringFlags flags) {
338   if (opts.experimental_strip_nonfunctional_codegen) {
339     // Comments are inherently non-functional, and may change subtly on
340     // transformations.
341     return;
342   }
343   absl::string_view comments = location.leading_comments.empty()
344                                    ? location.trailing_comments
345                                    : location.leading_comments;
346   std::vector<absl::string_view> raw_lines(
347       absl::StrSplit(comments, '\n', absl::AllowEmpty()));
348   while (!raw_lines.empty() && raw_lines.back().empty()) {
349     raw_lines.pop_back();
350   }
351   if (raw_lines.empty()) {
352     return;
353   }
354 
355   std::vector<std::string> lines;
356   lines.reserve(raw_lines.size());
357   for (absl::string_view l : raw_lines) {
358     lines.push_back(absl::StrReplaceAll(
359         // Strip any trailing whitespace to avoid any warnings on the generated
360         // code; but only strip one leading white space as that tends to be
361         // carried over from the .proto file, and we don't want extra spaces,
362         // the formatting below will ensure there is a space.
363         // NOTE: There could be >1 leading whitespace if the .proto file has
364         // formatted comments (see the WKTs), so we maintain any additional
365         // leading whitespace.
366         absl::StripTrailingAsciiWhitespace(absl::StripPrefix(l, " ")),
367         {// HeaderDoc and appledoc use '\' and '@' for markers; escape them.
368          {"\\", "\\\\"},
369          {"@", "\\@"},
370          // Decouple / from * to not have inline comments inside comments.
371          {"/*", "/\\*"},
372          {"*/", "*\\/"}}));
373   }
374 
375   if (flags & kCommentStringFlags_AddLeadingNewline) {
376     printer->Emit("\n");
377   }
378 
379   if ((flags & kCommentStringFlags_ForceMultiline) == 0 && lines.size() == 1) {
380     printer->Emit({{"text", lines[0]}}, R"(
381       /** $text$ */
382     )");
383     return;
384   }
385 
386   printer->Emit(
387       {
388           {"lines",
389            [&] {
390              for (absl::string_view line : lines) {
391                printer->Emit({{"text", line}}, R"(
392                 *$ text$
393               )");
394              }
395            }},
396       },
397       R"(
398         /**
399          $lines$
400          **/
401       )");
402 }
403 
HasWKTWithObjCCategory(const FileDescriptor * file)404 bool HasWKTWithObjCCategory(const FileDescriptor* file) {
405   // We don't check the name prefix or proto package because some files
406   // (descriptor.proto), aren't shipped generated by the library, so this
407   // seems to be the safest way to only catch the ones shipped.
408   const absl::string_view name = file->name();
409   if (name == "google/protobuf/any.proto" ||
410       name == "google/protobuf/duration.proto" ||
411       name == "google/protobuf/timestamp.proto") {
412     ABSL_DCHECK(IsProtobufLibraryBundledProtoFile(file));
413     return true;
414   }
415   return false;
416 }
417 
IsWKTWithObjCCategory(const Descriptor * descriptor)418 bool IsWKTWithObjCCategory(const Descriptor* descriptor) {
419   if (!HasWKTWithObjCCategory(descriptor->file())) {
420     return false;
421   }
422   const absl::string_view full_name = descriptor->full_name();
423   if (full_name == "google.protobuf.Any" ||
424       full_name == "google.protobuf.Duration" ||
425       full_name == "google.protobuf.Timestamp") {
426     return true;
427   }
428   return false;
429 }
430 
431 }  // namespace objectivec
432 }  // namespace compiler
433 }  // namespace protobuf
434 }  // namespace google
435