• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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