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