• 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 && !IsProto2(descriptor_->file())) {
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   // TODO(jonskeet): Work out whether we want to prevent the fields from ever being
67   // null, or whether we just handle it, in the cases of bytes and string.
68   // (Basically, should null-handling code be in the getter or the setter?)
69   if (IsProto2(descriptor_->file())) {
70     printer->Print(
71       variables_,
72       "private readonly static $type_name$ $property_name$DefaultValue = $default_value$;\n\n");
73   }
74 
75   printer->Print(
76     variables_,
77     "private $type_name$ $name_def_message$;\n");
78 
79   WritePropertyDocComment(printer, descriptor_);
80   AddPublicMemberAttributes(printer);
81   if (IsProto2(descriptor_->file())) {
82     if (presenceIndex_ == -1) {
83       printer->Print(
84         variables_,
85         "$access_level$ $type_name$ $property_name$ {\n"
86         "  get { return $name$_ ?? $property_name$DefaultValue; }\n"
87         "  set {\n");
88     } else {
89       printer->Print(
90         variables_,
91         "$access_level$ $type_name$ $property_name$ {\n"
92         "  get { if ($has_field_check$) { return $name$_; } else { return $property_name$DefaultValue; } }\n"
93         "  set {\n");
94     }
95   } else {
96     printer->Print(
97       variables_,
98       "$access_level$ $type_name$ $property_name$ {\n"
99       "  get { return $name$_; }\n"
100       "  set {\n");
101   }
102   if (presenceIndex_ != -1) {
103     printer->Print(
104       variables_,
105       "    $set_has_field$;\n");
106   }
107   if (is_value_type) {
108     printer->Print(
109       variables_,
110       "    $name$_ = value;\n");
111   } else {
112     printer->Print(
113       variables_,
114       "    $name$_ = pb::ProtoPreconditions.CheckNotNull(value, \"value\");\n");
115   }
116   printer->Print(
117     "  }\n"
118     "}\n");
119   if (IsProto2(descriptor_->file())) {
120     printer->Print(variables_, "/// <summary>Gets whether the \"$descriptor_name$\" field is set</summary>\n");
121     AddPublicMemberAttributes(printer);
122     printer->Print(
123       variables_,
124       "$access_level$ bool Has$property_name$ {\n"
125       "  get { return ");
126     if (IsNullable(descriptor_)) {
127       printer->Print(
128         variables_,
129         "$name$_ != null; }\n}\n");
130     } else {
131       printer->Print(
132         variables_,
133         "$has_field_check$; }\n}\n");
134     }
135   }
136   if (IsProto2(descriptor_->file())) {
137     printer->Print(variables_, "/// <summary>Clears the value of the \"$descriptor_name$\" field</summary>\n");
138     AddPublicMemberAttributes(printer);
139     printer->Print(
140       variables_,
141       "$access_level$ void Clear$property_name$() {\n");
142     if (IsNullable(descriptor_)) {
143       printer->Print(variables_, "  $name$_ = null;\n");
144     } else {
145       printer->Print(variables_, "  $clear_has_field$;\n");
146     }
147     printer->Print("}\n");
148   }
149 }
150 
GenerateMergingCode(io::Printer * printer)151 void PrimitiveFieldGenerator::GenerateMergingCode(io::Printer* printer) {
152   printer->Print(
153     variables_,
154     "if ($other_has_property_check$) {\n"
155     "  $property_name$ = other.$property_name$;\n"
156     "}\n");
157 }
158 
GenerateParsingCode(io::Printer * printer)159 void PrimitiveFieldGenerator::GenerateParsingCode(io::Printer* printer) {
160   // Note: invoke the property setter rather than writing straight to the field,
161   // so that we can normalize "null to empty" for strings and bytes.
162   printer->Print(
163     variables_,
164     "$property_name$ = input.Read$capitalized_type_name$();\n");
165 }
166 
GenerateSerializationCode(io::Printer * printer)167 void PrimitiveFieldGenerator::GenerateSerializationCode(io::Printer* printer) {
168   printer->Print(
169     variables_,
170     "if ($has_property_check$) {\n"
171     "  output.WriteRawTag($tag_bytes$);\n"
172     "  output.Write$capitalized_type_name$($property_name$);\n"
173     "}\n");
174 }
175 
GenerateSerializedSizeCode(io::Printer * printer)176 void PrimitiveFieldGenerator::GenerateSerializedSizeCode(io::Printer* printer) {
177   printer->Print(
178     variables_,
179     "if ($has_property_check$) {\n");
180   printer->Indent();
181   int fixedSize = GetFixedSize(descriptor_->type());
182   if (fixedSize == -1) {
183     printer->Print(
184       variables_,
185       "size += $tag_size$ + pb::CodedOutputStream.Compute$capitalized_type_name$Size($property_name$);\n");
186   } else {
187     printer->Print(
188       "size += $tag_size$ + $fixed_size$;\n",
189       "fixed_size", StrCat(fixedSize),
190       "tag_size", variables_["tag_size"]);
191   }
192   printer->Outdent();
193   printer->Print("}\n");
194 }
195 
WriteHash(io::Printer * printer)196 void PrimitiveFieldGenerator::WriteHash(io::Printer* printer) {
197   const char *text = "if ($has_property_check$) hash ^= $property_name$.GetHashCode();\n";
198   if (descriptor_->type() == FieldDescriptor::TYPE_FLOAT) {
199     text = "if ($has_property_check$) hash ^= pbc::ProtobufEqualityComparers.BitwiseSingleEqualityComparer.GetHashCode($property_name$);\n";
200   } else if (descriptor_->type() == FieldDescriptor::TYPE_DOUBLE) {
201     text = "if ($has_property_check$) hash ^= pbc::ProtobufEqualityComparers.BitwiseDoubleEqualityComparer.GetHashCode($property_name$);\n";
202   }
203 	printer->Print(variables_, text);
204 }
WriteEquals(io::Printer * printer)205 void PrimitiveFieldGenerator::WriteEquals(io::Printer* printer) {
206   const char *text = "if ($property_name$ != other.$property_name$) return false;\n";
207   if (descriptor_->type() == FieldDescriptor::TYPE_FLOAT) {
208     text = "if (!pbc::ProtobufEqualityComparers.BitwiseSingleEqualityComparer.Equals($property_name$, other.$property_name$)) return false;\n";
209   } else if (descriptor_->type() == FieldDescriptor::TYPE_DOUBLE) {
210     text = "if (!pbc::ProtobufEqualityComparers.BitwiseDoubleEqualityComparer.Equals($property_name$, other.$property_name$)) return false;\n";
211   }
212   printer->Print(variables_, text);
213 }
WriteToString(io::Printer * printer)214 void PrimitiveFieldGenerator::WriteToString(io::Printer* printer) {
215   printer->Print(
216     variables_,
217     "PrintField(\"$descriptor_name$\", $has_property_check$, $property_name$, writer);\n");
218 }
219 
GenerateCloningCode(io::Printer * printer)220 void PrimitiveFieldGenerator::GenerateCloningCode(io::Printer* printer) {
221   printer->Print(variables_,
222     "$name$_ = other.$name$_;\n");
223 }
224 
GenerateCodecCode(io::Printer * printer)225 void PrimitiveFieldGenerator::GenerateCodecCode(io::Printer* printer) {
226   printer->Print(
227     variables_,
228     "pb::FieldCodec.For$capitalized_type_name$($tag$, $default_value$)");
229 }
230 
GenerateExtensionCode(io::Printer * printer)231 void PrimitiveFieldGenerator::GenerateExtensionCode(io::Printer* printer) {
232   WritePropertyDocComment(printer, descriptor_);
233   AddDeprecatedFlag(printer);
234   printer->Print(
235     variables_,
236     "$access_level$ static readonly pb::Extension<$extended_type$, $type_name$> $property_name$ =\n"
237     "  new pb::Extension<$extended_type$, $type_name$>($number$, ");
238   GenerateCodecCode(printer);
239   printer->Print(");\n");
240 }
241 
PrimitiveOneofFieldGenerator(const FieldDescriptor * descriptor,int presenceIndex,const Options * options)242 PrimitiveOneofFieldGenerator::PrimitiveOneofFieldGenerator(
243     const FieldDescriptor* descriptor, int presenceIndex, const Options *options)
244     : PrimitiveFieldGenerator(descriptor, presenceIndex, options) {
245   SetCommonOneofFieldVariables(&variables_);
246 }
247 
~PrimitiveOneofFieldGenerator()248 PrimitiveOneofFieldGenerator::~PrimitiveOneofFieldGenerator() {
249 }
250 
GenerateMembers(io::Printer * printer)251 void PrimitiveOneofFieldGenerator::GenerateMembers(io::Printer* printer) {
252   WritePropertyDocComment(printer, descriptor_);
253   AddPublicMemberAttributes(printer);
254   printer->Print(
255     variables_,
256     "$access_level$ $type_name$ $property_name$ {\n"
257     "  get { return $has_property_check$ ? ($type_name$) $oneof_name$_ : $default_value$; }\n"
258     "  set {\n");
259   if (is_value_type) {
260     printer->Print(
261       variables_,
262       "    $oneof_name$_ = value;\n");
263   } else {
264     printer->Print(
265       variables_,
266       "    $oneof_name$_ = pb::ProtoPreconditions.CheckNotNull(value, \"value\");\n");
267   }
268   printer->Print(
269     variables_,
270     "    $oneof_name$Case_ = $oneof_property_name$OneofCase.$property_name$;\n"
271     "  }\n"
272     "}\n");
273   if (IsProto2(descriptor_->file())) {
274     printer->Print(
275       variables_,
276       "/// <summary>Gets whether the \"$descriptor_name$\" field is set</summary>\n");
277     AddPublicMemberAttributes(printer);
278     printer->Print(
279       variables_,
280       "$access_level$ bool Has$property_name$ {\n"
281       "  get { return $oneof_name$Case_ == $oneof_property_name$OneofCase.$property_name$; }\n"
282       "}\n");
283     printer->Print(
284       variables_,
285       "/// <summary> Clears the value of the oneof if it's currently set to \"$descriptor_name$\" </summary>\n");
286     AddPublicMemberAttributes(printer);
287     printer->Print(
288       variables_,
289       "$access_level$ void Clear$property_name$() {\n"
290       "  if ($has_property_check$) {\n"
291       "    Clear$oneof_property_name$();\n"
292       "  }\n"
293       "}\n");
294   }
295 }
296 
GenerateMergingCode(io::Printer * printer)297 void PrimitiveOneofFieldGenerator::GenerateMergingCode(io::Printer* printer) {
298   printer->Print(variables_, "$property_name$ = other.$property_name$;\n");
299 }
300 
WriteToString(io::Printer * printer)301 void PrimitiveOneofFieldGenerator::WriteToString(io::Printer* printer) {
302   printer->Print(variables_,
303     "PrintField(\"$descriptor_name$\", $has_property_check$, $oneof_name$_, writer);\n");
304 }
305 
GenerateParsingCode(io::Printer * printer)306 void PrimitiveOneofFieldGenerator::GenerateParsingCode(io::Printer* printer) {
307     printer->Print(
308       variables_,
309       "$property_name$ = input.Read$capitalized_type_name$();\n");
310 }
311 
GenerateCloningCode(io::Printer * printer)312 void PrimitiveOneofFieldGenerator::GenerateCloningCode(io::Printer* printer) {
313   printer->Print(variables_,
314     "$property_name$ = other.$property_name$;\n");
315 }
316 
317 }  // namespace csharp
318 }  // namespace compiler
319 }  // namespace protobuf
320 }  // namespace google
321