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