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