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 // Helper functions for generating ObjectiveC code.
9
10 #ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_HELPERS_H__
11 #define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_HELPERS_H__
12
13 #include <string>
14 #include <vector>
15
16 #include "absl/strings/str_cat.h"
17 #include "absl/strings/string_view.h"
18 #include "google/protobuf/compiler/objectivec/options.h"
19 #include "google/protobuf/descriptor.h"
20 #include "google/protobuf/descriptor.pb.h"
21 #include "google/protobuf/io/printer.h"
22
23 namespace google {
24 namespace protobuf {
25 namespace compiler {
26 namespace objectivec {
27
28 // Escape C++ trigraphs by escaping question marks to "\?".
29 std::string EscapeTrigraphs(absl::string_view to_escape);
30
31 // Returns true if the extension field is a custom option.
32 // https://protobuf.dev/programming-guides/proto2/#customoptions
33 bool ExtensionIsCustomOption(const FieldDescriptor* extension_field);
34
35 enum ObjectiveCType {
36 OBJECTIVECTYPE_INT32,
37 OBJECTIVECTYPE_UINT32,
38 OBJECTIVECTYPE_INT64,
39 OBJECTIVECTYPE_UINT64,
40 OBJECTIVECTYPE_FLOAT,
41 OBJECTIVECTYPE_DOUBLE,
42 OBJECTIVECTYPE_BOOLEAN,
43 OBJECTIVECTYPE_STRING,
44 OBJECTIVECTYPE_DATA,
45 OBJECTIVECTYPE_ENUM,
46 OBJECTIVECTYPE_MESSAGE
47 };
48
49 enum FlagType {
50 FLAGTYPE_DESCRIPTOR_INITIALIZATION,
51 FLAGTYPE_EXTENSION,
52 FLAGTYPE_FIELD
53 };
54
55 std::string GetCapitalizedType(const FieldDescriptor* field);
56
57 ObjectiveCType GetObjectiveCType(FieldDescriptor::Type field_type);
58
GetObjectiveCType(const FieldDescriptor * field)59 inline ObjectiveCType GetObjectiveCType(const FieldDescriptor* field) {
60 return GetObjectiveCType(field->type());
61 }
62
IsPrimitiveType(const FieldDescriptor * field)63 inline bool IsPrimitiveType(const FieldDescriptor* field) {
64 ObjectiveCType type = GetObjectiveCType(field);
65 switch (type) {
66 case OBJECTIVECTYPE_INT32:
67 case OBJECTIVECTYPE_UINT32:
68 case OBJECTIVECTYPE_INT64:
69 case OBJECTIVECTYPE_UINT64:
70 case OBJECTIVECTYPE_FLOAT:
71 case OBJECTIVECTYPE_DOUBLE:
72 case OBJECTIVECTYPE_BOOLEAN:
73 case OBJECTIVECTYPE_ENUM:
74 return true;
75 break;
76 default:
77 return false;
78 }
79 }
80
IsReferenceType(const FieldDescriptor * field)81 inline bool IsReferenceType(const FieldDescriptor* field) {
82 return !IsPrimitiveType(field);
83 }
84
85 std::string GPBGenericValueFieldName(const FieldDescriptor* field);
86 std::string DefaultValue(const FieldDescriptor* field);
87
88 std::string BuildFlagsString(FlagType type,
89 const std::vector<std::string>& strings);
90
91 // Returns a symbol that can be used in C code to refer to an Objective-C
92 // class without initializing the class.
93 std::string ObjCClass(absl::string_view class_name);
94
95 // Declares an Objective-C class without initializing the class so that it can
96 // be referred to by ObjCClass.
97 std::string ObjCClassDeclaration(absl::string_view class_name);
98
99 // Flag to control the behavior of `EmitCommentsString`.
100 enum CommentStringFlags : unsigned int {
101 kCommentStringFlags_None = 0,
102 // Add a newline before the comment.
103 kCommentStringFlags_AddLeadingNewline = 1 << 1,
104 // Force a multiline comment even if only 1 line.
105 kCommentStringFlags_ForceMultiline = 1 << 2,
106 };
107
108 // Emits HeaderDoc/appledoc style comments out of the comments in the .proto
109 // file.
110 void EmitCommentsString(io::Printer* printer, const GenerationOptions& opts,
111 const SourceLocation& location,
112 CommentStringFlags flags = kCommentStringFlags_None);
113
114 // Emits HeaderDoc/appledoc style comments out of the comments in the .proto
115 // file.
116 template <class TDescriptor>
117 void EmitCommentsString(io::Printer* printer, const GenerationOptions& opts,
118 const TDescriptor* descriptor,
119 CommentStringFlags flags = kCommentStringFlags_None) {
120 SourceLocation location;
121 if (descriptor->GetSourceLocation(&location)) {
122 EmitCommentsString(printer, opts, location, flags);
123 }
124 }
125
126 template <class TDescriptor>
127 std::string GetOptionalDeprecatedAttribute(
128 const TDescriptor* descriptor, const FileDescriptor* file = nullptr) {
129 bool isDeprecated = descriptor->options().deprecated();
130 // The file is only passed when checking Messages & Enums, so those types
131 // get tagged. At the moment, it doesn't seem to make sense to tag every
132 // field or enum value with when the file is deprecated.
133 bool isFileLevelDeprecation = false;
134 if (!isDeprecated && file) {
135 isFileLevelDeprecation = file->options().deprecated();
136 isDeprecated = isFileLevelDeprecation;
137 }
138 if (isDeprecated) {
139 std::string message;
140 const FileDescriptor* sourceFile = descriptor->file();
141 if (isFileLevelDeprecation) {
142 message = absl::StrCat(sourceFile->name(), " is deprecated.");
143 } else {
144 message = absl::StrCat(descriptor->full_name(), " is deprecated (see ",
145 sourceFile->name(), ").");
146 }
147
148 return absl::StrCat("GPB_DEPRECATED_MSG(\"", message, "\")");
149 } else {
150 return "";
151 }
152 }
153
154 // Helpers to identify the WellKnownType files/messages that get an Objective-C
155 // category within the runtime to add helpers.
156 bool HasWKTWithObjCCategory(const FileDescriptor* file);
157 bool IsWKTWithObjCCategory(const Descriptor* descriptor);
158
159 } // namespace objectivec
160 } // namespace compiler
161 } // namespace protobuf
162 } // namespace google
163
164 #endif // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_HELPERS_H__
165