• 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 
39 #include <google/protobuf/compiler/csharp/csharp_doc_comment.h>
40 #include <google/protobuf/compiler/csharp/csharp_helpers.h>
41 #include <google/protobuf/compiler/csharp/csharp_options.h>
42 #include <google/protobuf/compiler/csharp/csharp_wrapper_field.h>
43 
44 namespace google {
45 namespace protobuf {
46 namespace compiler {
47 namespace csharp {
48 
WrapperFieldGenerator(const FieldDescriptor * descriptor,int presenceIndex,const Options * options)49 WrapperFieldGenerator::WrapperFieldGenerator(const FieldDescriptor* descriptor,
50                                        int presenceIndex, const Options *options)
51     : FieldGeneratorBase(descriptor, presenceIndex, options) {
52   variables_["has_property_check"] = name() + "_ != null";
53   variables_["has_not_property_check"] = name() + "_ == null";
54   const FieldDescriptor* wrapped_field = descriptor->message_type()->field(0);
55   is_value_type = wrapped_field->type() != FieldDescriptor::TYPE_STRING &&
56       wrapped_field->type() != FieldDescriptor::TYPE_BYTES;
57   if (is_value_type) {
58     variables_["nonnullable_type_name"] = type_name(wrapped_field);
59   }
60 }
61 
~WrapperFieldGenerator()62 WrapperFieldGenerator::~WrapperFieldGenerator() {
63 }
64 
GenerateMembers(io::Printer * printer)65 void WrapperFieldGenerator::GenerateMembers(io::Printer* printer) {
66   printer->Print(
67         variables_,
68         "private static readonly pb::FieldCodec<$type_name$> _single_$name$_codec = ");
69   GenerateCodecCode(printer);
70   printer->Print(
71     variables_,
72     ";\n"
73     "private $type_name$ $name$_;\n");
74   WritePropertyDocComment(printer, descriptor_);
75   AddPublicMemberAttributes(printer);
76   printer->Print(
77     variables_,
78     "$access_level$ $type_name$ $property_name$ {\n"
79     "  get { return $name$_; }\n"
80     "  set {\n"
81     "    $name$_ = value;\n"
82     "  }\n"
83     "}\n\n");
84   if (SupportsPresenceApi(descriptor_)) {
85     printer->Print(
86       variables_,
87       "/// <summary>Gets whether the $descriptor_name$ field is set</summary>\n");
88     AddPublicMemberAttributes(printer);
89     printer->Print(
90       variables_,
91       "$access_level$ bool Has$property_name$ {\n"
92       "  get { return $name$_ != null; }\n"
93       "}\n\n");
94     printer->Print(
95       variables_,
96       "/// <summary>Clears the value of the $descriptor_name$ field</summary>\n");
97     AddPublicMemberAttributes(printer);
98     printer->Print(
99       variables_,
100       "$access_level$ void Clear$property_name$() {\n"
101       "  $name$_ = null;\n"
102       "}\n");
103   }
104 }
105 
GenerateMergingCode(io::Printer * printer)106 void WrapperFieldGenerator::GenerateMergingCode(io::Printer* printer) {
107   printer->Print(
108     variables_,
109     "if (other.$has_property_check$) {\n"
110     "  if ($has_not_property_check$ || other.$property_name$ != $default_value$) {\n"
111     "    $property_name$ = other.$property_name$;\n"
112     "  }\n"
113     "}\n");
114 }
115 
GenerateParsingCode(io::Printer * printer)116 void WrapperFieldGenerator::GenerateParsingCode(io::Printer* printer) {
117   GenerateParsingCode(printer, true);
118 }
119 
GenerateParsingCode(io::Printer * printer,bool use_parse_context)120 void WrapperFieldGenerator::GenerateParsingCode(io::Printer* printer, bool use_parse_context) {
121   printer->Print(
122     variables_,
123     use_parse_context
124     ? "$type_name$ value = _single_$name$_codec.Read(ref input);\n"
125       "if ($has_not_property_check$ || value != $default_value$) {\n"
126       "  $property_name$ = value;\n"
127       "}\n"
128     : "$type_name$ value = _single_$name$_codec.Read(input);\n"
129       "if ($has_not_property_check$ || value != $default_value$) {\n"
130       "  $property_name$ = value;\n"
131       "}\n");
132 }
133 
GenerateSerializationCode(io::Printer * printer)134 void WrapperFieldGenerator::GenerateSerializationCode(io::Printer* printer) {
135   GenerateSerializationCode(printer, true);
136 }
137 
GenerateSerializationCode(io::Printer * printer,bool use_write_context)138 void WrapperFieldGenerator::GenerateSerializationCode(io::Printer* printer, bool use_write_context) {
139   printer->Print(
140     variables_,
141     use_write_context
142     ? "if ($has_property_check$) {\n"
143       "  _single_$name$_codec.WriteTagAndValue(ref output, $property_name$);\n"
144       "}\n"
145     : "if ($has_property_check$) {\n"
146       "  _single_$name$_codec.WriteTagAndValue(output, $property_name$);\n"
147       "}\n");
148 }
149 
GenerateSerializedSizeCode(io::Printer * printer)150 void WrapperFieldGenerator::GenerateSerializedSizeCode(io::Printer* printer) {
151   printer->Print(
152     variables_,
153     "if ($has_property_check$) {\n"
154     "  size += _single_$name$_codec.CalculateSizeWithTag($property_name$);\n"
155     "}\n");
156 }
157 
WriteHash(io::Printer * printer)158 void WrapperFieldGenerator::WriteHash(io::Printer* printer) {
159   const char *text = "if ($has_property_check$) hash ^= $property_name$.GetHashCode();\n";
160   if (descriptor_->message_type()->field(0)->type() == FieldDescriptor::TYPE_FLOAT) {
161     text = "if ($has_property_check$) hash ^= pbc::ProtobufEqualityComparers.BitwiseNullableSingleEqualityComparer.GetHashCode($property_name$);\n";
162   }
163   else if (descriptor_->message_type()->field(0)->type() == FieldDescriptor::TYPE_DOUBLE) {
164     text = "if ($has_property_check$) hash ^= pbc::ProtobufEqualityComparers.BitwiseNullableDoubleEqualityComparer.GetHashCode($property_name$);\n";
165   }
166   printer->Print(variables_, text);
167 }
168 
WriteEquals(io::Printer * printer)169 void WrapperFieldGenerator::WriteEquals(io::Printer* printer) {
170   const char *text = "if ($property_name$ != other.$property_name$) return false;\n";
171   if (descriptor_->message_type()->field(0)->type() == FieldDescriptor::TYPE_FLOAT) {
172     text = "if (!pbc::ProtobufEqualityComparers.BitwiseNullableSingleEqualityComparer.Equals($property_name$, other.$property_name$)) return false;\n";
173   }
174   else if (descriptor_->message_type()->field(0)->type() == FieldDescriptor::TYPE_DOUBLE) {
175     text = "if (!pbc::ProtobufEqualityComparers.BitwiseNullableDoubleEqualityComparer.Equals($property_name$, other.$property_name$)) return false;\n";
176   }
177   printer->Print(variables_, text);
178 }
179 
WriteToString(io::Printer * printer)180 void WrapperFieldGenerator::WriteToString(io::Printer* printer) {
181   // TODO: Implement if we ever actually need it...
182 }
183 
GenerateCloningCode(io::Printer * printer)184 void WrapperFieldGenerator::GenerateCloningCode(io::Printer* printer) {
185   printer->Print(variables_,
186     "$property_name$ = other.$property_name$;\n");
187 }
188 
GenerateCodecCode(io::Printer * printer)189 void WrapperFieldGenerator::GenerateCodecCode(io::Printer* printer) {
190   if (is_value_type) {
191     printer->Print(
192       variables_,
193       "pb::FieldCodec.ForStructWrapper<$nonnullable_type_name$>($tag$)");
194   } else {
195     printer->Print(
196       variables_,
197       "pb::FieldCodec.ForClassWrapper<$type_name$>($tag$)");
198   }
199 }
200 
GenerateExtensionCode(io::Printer * printer)201 void WrapperFieldGenerator::GenerateExtensionCode(io::Printer* printer) {
202   WritePropertyDocComment(printer, descriptor_);
203   AddDeprecatedFlag(printer);
204   printer->Print(
205     variables_,
206     "$access_level$ static readonly pb::Extension<$extended_type$, $type_name$> $property_name$ =\n"
207     "  new pb::Extension<$extended_type$, $type_name$>($number$, ");
208   GenerateCodecCode(printer);
209   printer->Print(");\n");
210 }
211 
WrapperOneofFieldGenerator(const FieldDescriptor * descriptor,int presenceIndex,const Options * options)212 WrapperOneofFieldGenerator::WrapperOneofFieldGenerator(
213     const FieldDescriptor* descriptor, int presenceIndex, const Options *options)
214     : WrapperFieldGenerator(descriptor, presenceIndex, options) {
215     SetCommonOneofFieldVariables(&variables_);
216 }
217 
~WrapperOneofFieldGenerator()218 WrapperOneofFieldGenerator::~WrapperOneofFieldGenerator() {
219 }
220 
GenerateMembers(io::Printer * printer)221 void WrapperOneofFieldGenerator::GenerateMembers(io::Printer* printer) {
222   // Note: deliberately _oneof_$name$_codec, not _$oneof_name$_codec... we have one codec per field.
223   printer->Print(
224         variables_,
225         "private static readonly pb::FieldCodec<$type_name$> _oneof_$name$_codec = ");
226   GenerateCodecCode(printer);
227   printer->Print(";\n");
228   WritePropertyDocComment(printer, descriptor_);
229   AddPublicMemberAttributes(printer);
230   printer->Print(
231     variables_,
232     "$access_level$ $type_name$ $property_name$ {\n"
233     "  get { return $has_property_check$ ? ($type_name$) $oneof_name$_ : ($type_name$) null; }\n"
234     "  set {\n"
235     "    $oneof_name$_ = value;\n"
236     "    $oneof_name$Case_ = value == null ? $oneof_property_name$OneofCase.None : $oneof_property_name$OneofCase.$property_name$;\n"
237     "  }\n"
238     "}\n");
239   if (SupportsPresenceApi(descriptor_)) {
240     printer->Print(
241       variables_,
242       "/// <summary>Gets whether the \"$descriptor_name$\" field is set</summary>\n");
243     AddPublicMemberAttributes(printer);
244     printer->Print(
245       variables_,
246       "$access_level$ bool Has$property_name$ {\n"
247       "  get { return $oneof_name$Case_ == $oneof_property_name$OneofCase.$property_name$; }\n"
248       "}\n");
249     printer->Print(
250       variables_,
251       "/// <summary> Clears the value of the oneof if it's currently set to \"$descriptor_name$\" </summary>\n");
252     AddPublicMemberAttributes(printer);
253     printer->Print(
254       variables_,
255       "$access_level$ void Clear$property_name$() {\n"
256       "  if ($has_property_check$) {\n"
257       "    Clear$oneof_property_name$();\n"
258       "  }\n"
259       "}\n");
260   }
261 }
262 
GenerateMergingCode(io::Printer * printer)263 void WrapperOneofFieldGenerator::GenerateMergingCode(io::Printer* printer) {
264   printer->Print(variables_, "$property_name$ = other.$property_name$;\n");
265 }
266 
GenerateParsingCode(io::Printer * printer)267 void WrapperOneofFieldGenerator::GenerateParsingCode(io::Printer* printer) {
268   GenerateParsingCode(printer, true);
269 }
270 
GenerateParsingCode(io::Printer * printer,bool use_parse_context)271 void WrapperOneofFieldGenerator::GenerateParsingCode(io::Printer* printer, bool use_parse_context) {
272   printer->Print(
273     variables_,
274     use_parse_context
275     ? "$property_name$ = _oneof_$name$_codec.Read(ref input);\n"
276     : "$property_name$ = _oneof_$name$_codec.Read(input);\n");
277 }
278 
GenerateSerializationCode(io::Printer * printer)279 void WrapperOneofFieldGenerator::GenerateSerializationCode(io::Printer* printer) {
280   GenerateSerializationCode(printer, true);
281 }
282 
GenerateSerializationCode(io::Printer * printer,bool use_write_context)283 void WrapperOneofFieldGenerator::GenerateSerializationCode(io::Printer* printer, bool use_write_context) {
284   // TODO: I suspect this is wrong...
285   printer->Print(
286     variables_,
287     use_write_context
288     ? "if ($has_property_check$) {\n"
289       "  _oneof_$name$_codec.WriteTagAndValue(ref output, ($type_name$) $oneof_name$_);\n"
290       "}\n"
291     : "if ($has_property_check$) {\n"
292       "  _oneof_$name$_codec.WriteTagAndValue(output, ($type_name$) $oneof_name$_);\n"
293       "}\n");
294 }
295 
GenerateSerializedSizeCode(io::Printer * printer)296 void WrapperOneofFieldGenerator::GenerateSerializedSizeCode(io::Printer* printer) {
297   // TODO: I suspect this is wrong...
298   printer->Print(
299     variables_,
300     "if ($has_property_check$) {\n"
301     "  size += _oneof_$name$_codec.CalculateSizeWithTag($property_name$);\n"
302     "}\n");
303 }
304 
305 }  // namespace csharp
306 }  // namespace compiler
307 }  // namespace protobuf
308 }  // namespace google
309