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/csharp/csharp_primitive_field.h"
9
10 #include <sstream>
11 #include <string>
12 #include <utility>
13
14 #include "google/protobuf/compiler/code_generator.h"
15 #include "absl/strings/str_cat.h"
16 #include "google/protobuf/compiler/csharp/csharp_doc_comment.h"
17 #include "google/protobuf/compiler/csharp/csharp_helpers.h"
18 #include "google/protobuf/compiler/csharp/csharp_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 csharp {
27
PrimitiveFieldGenerator(const FieldDescriptor * descriptor,int presenceIndex,const Options * options)28 PrimitiveFieldGenerator::PrimitiveFieldGenerator(
29 const FieldDescriptor* descriptor, int presenceIndex, const Options *options)
30 : FieldGeneratorBase(descriptor, presenceIndex, options) {
31 // TODO: Make this cleaner...
32 is_value_type = descriptor->type() != FieldDescriptor::TYPE_STRING
33 && descriptor->type() != FieldDescriptor::TYPE_BYTES;
34 if (!is_value_type && !SupportsPresenceApi(descriptor_)) {
35 std::string property_name = variables_["property_name"];
36 variables_["has_property_check"] =
37 absl::StrCat(property_name, ".Length != 0");
38 variables_["other_has_property_check"] =
39 absl::StrCat("other.", property_name, ".Length != 0");
40 }
41 }
42
~PrimitiveFieldGenerator()43 PrimitiveFieldGenerator::~PrimitiveFieldGenerator() {
44 }
45
GenerateMembers(io::Printer * printer)46 void PrimitiveFieldGenerator::GenerateMembers(io::Printer* printer) {
47 // Note: in multiple places, this code assumes that all fields
48 // that support presence are either nullable, or use a presence field bit.
49 // Fields which are oneof members are not generated here; they're generated in PrimitiveOneofFieldGenerator below.
50 // Extensions are not generated here either.
51
52 // Explicit presence allows different default values to be specified. These
53 // are retained via static fields. They don't particularly need to be, but we
54 // don't need to change that. Under implicit presence we don't use static
55 // fields for default values and just use the literals instead.
56 if (descriptor_->has_presence()) {
57 // Note: "private readonly static" isn't as idiomatic as
58 // "private static readonly", but changing this now would create a lot of
59 // churn in generated code with near-to-zero benefit.
60 printer->Print(
61 variables_,
62 "private readonly static $type_name$ $property_name$DefaultValue = $default_value$;\n\n");
63 std::string property_name = variables_["property_name"];
64 variables_["default_value_access"] =
65 absl::StrCat(property_name, "DefaultValue");
66 } else {
67 std::string default_value = variables_["default_value"];
68 variables_["default_value_access"] = std::move(default_value);
69 }
70
71 // Declare the field itself.
72 printer->Print(
73 variables_,
74 "private $type_name$ $name_def_message$;\n");
75
76 WritePropertyDocComment(printer, options(), descriptor_);
77 AddPublicMemberAttributes(printer);
78
79 // Most of the work is done in the property:
80 // Declare the property itself (the same for all options)
81 printer->Print(variables_, "$access_level$ $type_name$ $property_name$ {\n");
82
83 // Specify the "getter", which may need to check for a presence field.
84 if (SupportsPresenceApi(descriptor_)) {
85 if (IsNullable(descriptor_)) {
86 printer->Print(
87 variables_,
88 " get { return $name$_ ?? $default_value_access$; }\n");
89 } else {
90 printer->Print(
91 variables_,
92 // Note: it's possible that this could be rewritten as a
93 // conditional ?: expression, but there's no significant benefit
94 // to changing it.
95 " get { if ($has_field_check$) { return $name$_; } else { return $default_value_access$; } }\n");
96 }
97 } else {
98 printer->Print(
99 variables_,
100 " get { return $name$_; }\n");
101 }
102
103 // Specify the "setter", which may need to set a field bit as well as the
104 // value.
105 printer->Print(" set {\n");
106 if (presenceIndex_ != -1) {
107 printer->Print(
108 variables_,
109 " $set_has_field$;\n");
110 }
111 if (is_value_type) {
112 printer->Print(
113 variables_,
114 " $name$_ = value;\n");
115 } else {
116 printer->Print(
117 variables_,
118 " $name$_ = pb::ProtoPreconditions.CheckNotNull(value, \"value\");\n");
119 }
120 printer->Print(
121 " }\n"
122 "}\n");
123
124 // The "HasFoo" property, where required.
125 if (SupportsPresenceApi(descriptor_)) {
126 printer->Print(variables_,
127 "/// <summary>Gets whether the \"$descriptor_name$\" field is set</summary>\n");
128 AddPublicMemberAttributes(printer);
129 printer->Print(
130 variables_,
131 "$access_level$ bool Has$property_name$ {\n"
132 " get { return ");
133 if (IsNullable(descriptor_)) {
134 printer->Print(
135 variables_,
136 "$name$_ != null; }\n}\n");
137 } else {
138 printer->Print(
139 variables_,
140 "$has_field_check$; }\n}\n");
141 }
142 }
143
144 // The "ClearFoo" method, where required.
145 if (SupportsPresenceApi(descriptor_)) {
146 printer->Print(variables_,
147 "/// <summary>Clears the value of the \"$descriptor_name$\" field</summary>\n");
148 AddPublicMemberAttributes(printer);
149 printer->Print(
150 variables_,
151 "$access_level$ void Clear$property_name$() {\n");
152 if (IsNullable(descriptor_)) {
153 printer->Print(variables_, " $name$_ = null;\n");
154 } else {
155 printer->Print(variables_, " $clear_has_field$;\n");
156 }
157 printer->Print("}\n");
158 }
159 }
160
GenerateMergingCode(io::Printer * printer)161 void PrimitiveFieldGenerator::GenerateMergingCode(io::Printer* printer) {
162 printer->Print(
163 variables_,
164 "if ($other_has_property_check$) {\n"
165 " $property_name$ = other.$property_name$;\n"
166 "}\n");
167 }
168
GenerateParsingCode(io::Printer * printer)169 void PrimitiveFieldGenerator::GenerateParsingCode(io::Printer* printer) {
170 // Note: invoke the property setter rather than writing straight to the field,
171 // so that we can normalize "null to empty" for strings and bytes.
172 printer->Print(
173 variables_,
174 "$property_name$ = input.Read$capitalized_type_name$();\n");
175 }
176
GenerateSerializationCode(io::Printer * printer)177 void PrimitiveFieldGenerator::GenerateSerializationCode(io::Printer* printer) {
178 printer->Print(
179 variables_,
180 "if ($has_property_check$) {\n"
181 " output.WriteRawTag($tag_bytes$);\n"
182 " output.Write$capitalized_type_name$($property_name$);\n"
183 "}\n");
184 }
185
GenerateSerializedSizeCode(io::Printer * printer)186 void PrimitiveFieldGenerator::GenerateSerializedSizeCode(io::Printer* printer) {
187 printer->Print(
188 variables_,
189 "if ($has_property_check$) {\n");
190 printer->Indent();
191 int fixedSize = GetFixedSize(descriptor_->type());
192 if (fixedSize == -1) {
193 printer->Print(
194 variables_,
195 "size += $tag_size$ + pb::CodedOutputStream.Compute$capitalized_type_name$Size($property_name$);\n");
196 } else {
197 printer->Print(
198 "size += $tag_size$ + $fixed_size$;\n",
199 "fixed_size", absl::StrCat(fixedSize),
200 "tag_size", variables_["tag_size"]);
201 }
202 printer->Outdent();
203 printer->Print("}\n");
204 }
205
WriteHash(io::Printer * printer)206 void PrimitiveFieldGenerator::WriteHash(io::Printer* printer) {
207 const char *text = "if ($has_property_check$) hash ^= $property_name$.GetHashCode();\n";
208 if (descriptor_->type() == FieldDescriptor::TYPE_FLOAT) {
209 text = "if ($has_property_check$) hash ^= pbc::ProtobufEqualityComparers.BitwiseSingleEqualityComparer.GetHashCode($property_name$);\n";
210 } else if (descriptor_->type() == FieldDescriptor::TYPE_DOUBLE) {
211 text = "if ($has_property_check$) hash ^= pbc::ProtobufEqualityComparers.BitwiseDoubleEqualityComparer.GetHashCode($property_name$);\n";
212 }
213 printer->Print(variables_, text);
214 }
WriteEquals(io::Printer * printer)215 void PrimitiveFieldGenerator::WriteEquals(io::Printer* printer) {
216 const char *text = "if ($property_name$ != other.$property_name$) return false;\n";
217 if (descriptor_->type() == FieldDescriptor::TYPE_FLOAT) {
218 text = "if (!pbc::ProtobufEqualityComparers.BitwiseSingleEqualityComparer.Equals($property_name$, other.$property_name$)) return false;\n";
219 } else if (descriptor_->type() == FieldDescriptor::TYPE_DOUBLE) {
220 text = "if (!pbc::ProtobufEqualityComparers.BitwiseDoubleEqualityComparer.Equals($property_name$, other.$property_name$)) return false;\n";
221 }
222 printer->Print(variables_, text);
223 }
WriteToString(io::Printer * printer)224 void PrimitiveFieldGenerator::WriteToString(io::Printer* printer) {
225 printer->Print(
226 variables_,
227 "PrintField(\"$descriptor_name$\", $has_property_check$, $property_name$, writer);\n");
228 }
229
GenerateCloningCode(io::Printer * printer)230 void PrimitiveFieldGenerator::GenerateCloningCode(io::Printer* printer) {
231 printer->Print(variables_,
232 "$name$_ = other.$name$_;\n");
233 }
234
GenerateCodecCode(io::Printer * printer)235 void PrimitiveFieldGenerator::GenerateCodecCode(io::Printer* printer) {
236 printer->Print(
237 variables_,
238 "pb::FieldCodec.For$capitalized_type_name$($tag$, $default_value$)");
239 }
240
GenerateExtensionCode(io::Printer * printer)241 void PrimitiveFieldGenerator::GenerateExtensionCode(io::Printer* printer) {
242 WritePropertyDocComment(printer, options(), descriptor_);
243 AddDeprecatedFlag(printer);
244 printer->Print(
245 variables_,
246 "$access_level$ static readonly pb::Extension<$extended_type$, $type_name$> $property_name$ =\n"
247 " new pb::Extension<$extended_type$, $type_name$>($number$, ");
248 GenerateCodecCode(printer);
249 printer->Print(");\n");
250 }
251
PrimitiveOneofFieldGenerator(const FieldDescriptor * descriptor,int presenceIndex,const Options * options)252 PrimitiveOneofFieldGenerator::PrimitiveOneofFieldGenerator(
253 const FieldDescriptor* descriptor, int presenceIndex, const Options *options)
254 : PrimitiveFieldGenerator(descriptor, presenceIndex, options) {
255 SetCommonOneofFieldVariables(&variables_);
256 }
257
~PrimitiveOneofFieldGenerator()258 PrimitiveOneofFieldGenerator::~PrimitiveOneofFieldGenerator() {
259 }
260
GenerateMembers(io::Printer * printer)261 void PrimitiveOneofFieldGenerator::GenerateMembers(io::Printer* printer) {
262 WritePropertyDocComment(printer, options(), descriptor_);
263 AddPublicMemberAttributes(printer);
264 printer->Print(
265 variables_,
266 "$access_level$ $type_name$ $property_name$ {\n"
267 " get { return $has_property_check$ ? ($type_name$) $oneof_name$_ : $default_value$; }\n"
268 " set {\n");
269 if (is_value_type) {
270 printer->Print(
271 variables_,
272 " $oneof_name$_ = value;\n");
273 } else {
274 printer->Print(
275 variables_,
276 " $oneof_name$_ = pb::ProtoPreconditions.CheckNotNull(value, \"value\");\n");
277 }
278 printer->Print(
279 variables_,
280 " $oneof_name$Case_ = $oneof_property_name$OneofCase.$oneof_case_name$;\n"
281 " }\n"
282 "}\n");
283 if (SupportsPresenceApi(descriptor_)) {
284 printer->Print(
285 variables_,
286 "/// <summary>Gets whether the \"$descriptor_name$\" field is set</summary>\n");
287 AddPublicMemberAttributes(printer);
288 printer->Print(
289 variables_,
290 "$access_level$ bool Has$property_name$ {\n"
291 " get { return $oneof_name$Case_ == $oneof_property_name$OneofCase.$oneof_case_name$; }\n"
292 "}\n");
293 printer->Print(
294 variables_,
295 "/// <summary> Clears the value of the oneof if it's currently set to \"$descriptor_name$\" </summary>\n");
296 AddPublicMemberAttributes(printer);
297 printer->Print(
298 variables_,
299 "$access_level$ void Clear$property_name$() {\n"
300 " if ($has_property_check$) {\n"
301 " Clear$oneof_property_name$();\n"
302 " }\n"
303 "}\n");
304 }
305 }
306
GenerateMergingCode(io::Printer * printer)307 void PrimitiveOneofFieldGenerator::GenerateMergingCode(io::Printer* printer) {
308 printer->Print(variables_, "$property_name$ = other.$property_name$;\n");
309 }
310
WriteToString(io::Printer * printer)311 void PrimitiveOneofFieldGenerator::WriteToString(io::Printer* printer) {
312 printer->Print(variables_,
313 "PrintField(\"$descriptor_name$\", $has_property_check$, $oneof_name$_, writer);\n");
314 }
315
GenerateParsingCode(io::Printer * printer)316 void PrimitiveOneofFieldGenerator::GenerateParsingCode(io::Printer* printer) {
317 printer->Print(
318 variables_,
319 "$property_name$ = input.Read$capitalized_type_name$();\n");
320 }
321
GenerateCloningCode(io::Printer * printer)322 void PrimitiveOneofFieldGenerator::GenerateCloningCode(io::Printer* printer) {
323 printer->Print(variables_,
324 "$property_name$ = other.$property_name$;\n");
325 }
326
327 } // namespace csharp
328 } // namespace compiler
329 } // namespace protobuf
330 } // namespace google
331