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
45 namespace google {
46 namespace protobuf {
47 namespace compiler {
48 namespace csharp {
49
PrimitiveFieldGenerator(const FieldDescriptor * descriptor,int presenceIndex,const Options * options)50 PrimitiveFieldGenerator::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_)) {
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
~PrimitiveFieldGenerator()62 PrimitiveFieldGenerator::~PrimitiveFieldGenerator() {
63 }
64
GenerateMembers(io::Printer * printer)65 void 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_->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_,
83 "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_,
93 "private $type_name$ $name_def_message$;\n");
94
95 WritePropertyDocComment(printer, 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_, "$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_)) {
104 if (IsNullable(descriptor_)) {
105 printer->Print(
106 variables_,
107 " get { return $name$_ ?? $default_value_access$; }\n");
108 } else {
109 printer->Print(
110 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 " get { if ($has_field_check$) { return $name$_; } else { return $default_value_access$; } }\n");
115 }
116 } else {
117 printer->Print(
118 variables_,
119 " 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(" set {\n");
125 if (presenceIndex_ != -1) {
126 printer->Print(
127 variables_,
128 " $set_has_field$;\n");
129 }
130 if (is_value_type) {
131 printer->Print(
132 variables_,
133 " $name$_ = value;\n");
134 } else {
135 printer->Print(
136 variables_,
137 " $name$_ = pb::ProtoPreconditions.CheckNotNull(value, \"value\");\n");
138 }
139 printer->Print(
140 " }\n"
141 "}\n");
142
143 // The "HasFoo" property, where required.
144 if (SupportsPresenceApi(descriptor_)) {
145 printer->Print(variables_,
146 "/// <summary>Gets whether the \"$descriptor_name$\" field is set</summary>\n");
147 AddPublicMemberAttributes(printer);
148 printer->Print(
149 variables_,
150 "$access_level$ bool Has$property_name$ {\n"
151 " get { return ");
152 if (IsNullable(descriptor_)) {
153 printer->Print(
154 variables_,
155 "$name$_ != null; }\n}\n");
156 } else {
157 printer->Print(
158 variables_,
159 "$has_field_check$; }\n}\n");
160 }
161 }
162
163 // The "ClearFoo" method, where required.
164 if (SupportsPresenceApi(descriptor_)) {
165 printer->Print(variables_,
166 "/// <summary>Clears the value of the \"$descriptor_name$\" field</summary>\n");
167 AddPublicMemberAttributes(printer);
168 printer->Print(
169 variables_,
170 "$access_level$ void Clear$property_name$() {\n");
171 if (IsNullable(descriptor_)) {
172 printer->Print(variables_, " $name$_ = null;\n");
173 } else {
174 printer->Print(variables_, " $clear_has_field$;\n");
175 }
176 printer->Print("}\n");
177 }
178 }
179
GenerateMergingCode(io::Printer * printer)180 void PrimitiveFieldGenerator::GenerateMergingCode(io::Printer* printer) {
181 printer->Print(
182 variables_,
183 "if ($other_has_property_check$) {\n"
184 " $property_name$ = other.$property_name$;\n"
185 "}\n");
186 }
187
GenerateParsingCode(io::Printer * printer)188 void 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_,
193 "$property_name$ = input.Read$capitalized_type_name$();\n");
194 }
195
GenerateSerializationCode(io::Printer * printer)196 void PrimitiveFieldGenerator::GenerateSerializationCode(io::Printer* printer) {
197 printer->Print(
198 variables_,
199 "if ($has_property_check$) {\n"
200 " output.WriteRawTag($tag_bytes$);\n"
201 " output.Write$capitalized_type_name$($property_name$);\n"
202 "}\n");
203 }
204
GenerateSerializedSizeCode(io::Printer * printer)205 void PrimitiveFieldGenerator::GenerateSerializedSizeCode(io::Printer* printer) {
206 printer->Print(
207 variables_,
208 "if ($has_property_check$) {\n");
209 printer->Indent();
210 int fixedSize = GetFixedSize(descriptor_->type());
211 if (fixedSize == -1) {
212 printer->Print(
213 variables_,
214 "size += $tag_size$ + pb::CodedOutputStream.Compute$capitalized_type_name$Size($property_name$);\n");
215 } else {
216 printer->Print(
217 "size += $tag_size$ + $fixed_size$;\n",
218 "fixed_size", StrCat(fixedSize),
219 "tag_size", variables_["tag_size"]);
220 }
221 printer->Outdent();
222 printer->Print("}\n");
223 }
224
WriteHash(io::Printer * printer)225 void 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_, text);
233 }
WriteEquals(io::Printer * printer)234 void 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_, text);
242 }
WriteToString(io::Printer * printer)243 void PrimitiveFieldGenerator::WriteToString(io::Printer* printer) {
244 printer->Print(
245 variables_,
246 "PrintField(\"$descriptor_name$\", $has_property_check$, $property_name$, writer);\n");
247 }
248
GenerateCloningCode(io::Printer * printer)249 void PrimitiveFieldGenerator::GenerateCloningCode(io::Printer* printer) {
250 printer->Print(variables_,
251 "$name$_ = other.$name$_;\n");
252 }
253
GenerateCodecCode(io::Printer * printer)254 void PrimitiveFieldGenerator::GenerateCodecCode(io::Printer* printer) {
255 printer->Print(
256 variables_,
257 "pb::FieldCodec.For$capitalized_type_name$($tag$, $default_value$)");
258 }
259
GenerateExtensionCode(io::Printer * printer)260 void PrimitiveFieldGenerator::GenerateExtensionCode(io::Printer* printer) {
261 WritePropertyDocComment(printer, descriptor_);
262 AddDeprecatedFlag(printer);
263 printer->Print(
264 variables_,
265 "$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(");\n");
269 }
270
PrimitiveOneofFieldGenerator(const FieldDescriptor * descriptor,int presenceIndex,const Options * options)271 PrimitiveOneofFieldGenerator::PrimitiveOneofFieldGenerator(
272 const FieldDescriptor* descriptor, int presenceIndex, const Options *options)
273 : PrimitiveFieldGenerator(descriptor, presenceIndex, options) {
274 SetCommonOneofFieldVariables(&variables_);
275 }
276
~PrimitiveOneofFieldGenerator()277 PrimitiveOneofFieldGenerator::~PrimitiveOneofFieldGenerator() {
278 }
279
GenerateMembers(io::Printer * printer)280 void PrimitiveOneofFieldGenerator::GenerateMembers(io::Printer* printer) {
281 WritePropertyDocComment(printer, descriptor_);
282 AddPublicMemberAttributes(printer);
283 printer->Print(
284 variables_,
285 "$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_,
291 " $oneof_name$_ = value;\n");
292 } else {
293 printer->Print(
294 variables_,
295 " $oneof_name$_ = pb::ProtoPreconditions.CheckNotNull(value, \"value\");\n");
296 }
297 printer->Print(
298 variables_,
299 " $oneof_name$Case_ = $oneof_property_name$OneofCase.$property_name$;\n"
300 " }\n"
301 "}\n");
302 if (SupportsPresenceApi(descriptor_)) {
303 printer->Print(
304 variables_,
305 "/// <summary>Gets whether the \"$descriptor_name$\" field is set</summary>\n");
306 AddPublicMemberAttributes(printer);
307 printer->Print(
308 variables_,
309 "$access_level$ bool Has$property_name$ {\n"
310 " get { return $oneof_name$Case_ == $oneof_property_name$OneofCase.$property_name$; }\n"
311 "}\n");
312 printer->Print(
313 variables_,
314 "/// <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_,
318 "$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
GenerateMergingCode(io::Printer * printer)326 void PrimitiveOneofFieldGenerator::GenerateMergingCode(io::Printer* printer) {
327 printer->Print(variables_, "$property_name$ = other.$property_name$;\n");
328 }
329
WriteToString(io::Printer * printer)330 void PrimitiveOneofFieldGenerator::WriteToString(io::Printer* printer) {
331 printer->Print(variables_,
332 "PrintField(\"$descriptor_name$\", $has_property_check$, $oneof_name$_, writer);\n");
333 }
334
GenerateParsingCode(io::Printer * printer)335 void PrimitiveOneofFieldGenerator::GenerateParsingCode(io::Printer* printer) {
336 printer->Print(
337 variables_,
338 "$property_name$ = input.Read$capitalized_type_name$();\n");
339 }
340
GenerateCloningCode(io::Printer * printer)341 void PrimitiveOneofFieldGenerator::GenerateCloningCode(io::Printer* printer) {
342 printer->Print(variables_,
343 "$property_name$ = other.$property_name$;\n");
344 }
345
346 } // namespace csharp
347 } // namespace compiler
348 } // namespace protobuf
349 } // namespace google
350