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 (IsProto2(descriptor_->file())) {
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 printer->Print(
118 variables_,
119 "$type_name$ value = _single_$name$_codec.Read(input);\n"
120 "if ($has_not_property_check$ || value != $default_value$) {\n"
121 " $property_name$ = value;\n"
122 "}\n");
123 }
124
GenerateSerializationCode(io::Printer * printer)125 void WrapperFieldGenerator::GenerateSerializationCode(io::Printer* printer) {
126 printer->Print(
127 variables_,
128 "if ($has_property_check$) {\n"
129 " _single_$name$_codec.WriteTagAndValue(output, $property_name$);\n"
130 "}\n");
131 }
132
GenerateSerializedSizeCode(io::Printer * printer)133 void WrapperFieldGenerator::GenerateSerializedSizeCode(io::Printer* printer) {
134 printer->Print(
135 variables_,
136 "if ($has_property_check$) {\n"
137 " size += _single_$name$_codec.CalculateSizeWithTag($property_name$);\n"
138 "}\n");
139 }
140
WriteHash(io::Printer * printer)141 void WrapperFieldGenerator::WriteHash(io::Printer* printer) {
142 const char *text = "if ($has_property_check$) hash ^= $property_name$.GetHashCode();\n";
143 if (descriptor_->message_type()->field(0)->type() == FieldDescriptor::TYPE_FLOAT) {
144 text = "if ($has_property_check$) hash ^= pbc::ProtobufEqualityComparers.BitwiseNullableSingleEqualityComparer.GetHashCode($property_name$);\n";
145 }
146 else if (descriptor_->message_type()->field(0)->type() == FieldDescriptor::TYPE_DOUBLE) {
147 text = "if ($has_property_check$) hash ^= pbc::ProtobufEqualityComparers.BitwiseNullableDoubleEqualityComparer.GetHashCode($property_name$);\n";
148 }
149 printer->Print(variables_, text);
150 }
151
WriteEquals(io::Printer * printer)152 void WrapperFieldGenerator::WriteEquals(io::Printer* printer) {
153 const char *text = "if ($property_name$ != other.$property_name$) return false;\n";
154 if (descriptor_->message_type()->field(0)->type() == FieldDescriptor::TYPE_FLOAT) {
155 text = "if (!pbc::ProtobufEqualityComparers.BitwiseNullableSingleEqualityComparer.Equals($property_name$, other.$property_name$)) return false;\n";
156 }
157 else if (descriptor_->message_type()->field(0)->type() == FieldDescriptor::TYPE_DOUBLE) {
158 text = "if (!pbc::ProtobufEqualityComparers.BitwiseNullableDoubleEqualityComparer.Equals($property_name$, other.$property_name$)) return false;\n";
159 }
160 printer->Print(variables_, text);
161 }
162
WriteToString(io::Printer * printer)163 void WrapperFieldGenerator::WriteToString(io::Printer* printer) {
164 // TODO: Implement if we ever actually need it...
165 }
166
GenerateCloningCode(io::Printer * printer)167 void WrapperFieldGenerator::GenerateCloningCode(io::Printer* printer) {
168 printer->Print(variables_,
169 "$property_name$ = other.$property_name$;\n");
170 }
171
GenerateCodecCode(io::Printer * printer)172 void WrapperFieldGenerator::GenerateCodecCode(io::Printer* printer) {
173 if (is_value_type) {
174 printer->Print(
175 variables_,
176 "pb::FieldCodec.ForStructWrapper<$nonnullable_type_name$>($tag$)");
177 } else {
178 printer->Print(
179 variables_,
180 "pb::FieldCodec.ForClassWrapper<$type_name$>($tag$)");
181 }
182 }
183
GenerateExtensionCode(io::Printer * printer)184 void WrapperFieldGenerator::GenerateExtensionCode(io::Printer* printer) {
185 WritePropertyDocComment(printer, descriptor_);
186 AddDeprecatedFlag(printer);
187 printer->Print(
188 variables_,
189 "$access_level$ static readonly pb::Extension<$extended_type$, $type_name$> $property_name$ =\n"
190 " new pb::Extension<$extended_type$, $type_name$>($number$, ");
191 GenerateCodecCode(printer);
192 printer->Print(");\n");
193 }
194
WrapperOneofFieldGenerator(const FieldDescriptor * descriptor,int presenceIndex,const Options * options)195 WrapperOneofFieldGenerator::WrapperOneofFieldGenerator(
196 const FieldDescriptor* descriptor, int presenceIndex, const Options *options)
197 : WrapperFieldGenerator(descriptor, presenceIndex, options) {
198 SetCommonOneofFieldVariables(&variables_);
199 }
200
~WrapperOneofFieldGenerator()201 WrapperOneofFieldGenerator::~WrapperOneofFieldGenerator() {
202 }
203
GenerateMembers(io::Printer * printer)204 void WrapperOneofFieldGenerator::GenerateMembers(io::Printer* printer) {
205 // Note: deliberately _oneof_$name$_codec, not _$oneof_name$_codec... we have one codec per field.
206 printer->Print(
207 variables_,
208 "private static readonly pb::FieldCodec<$type_name$> _oneof_$name$_codec = ");
209 GenerateCodecCode(printer);
210 printer->Print(";\n");
211 WritePropertyDocComment(printer, descriptor_);
212 AddPublicMemberAttributes(printer);
213 printer->Print(
214 variables_,
215 "$access_level$ $type_name$ $property_name$ {\n"
216 " get { return $has_property_check$ ? ($type_name$) $oneof_name$_ : ($type_name$) null; }\n"
217 " set {\n"
218 " $oneof_name$_ = value;\n"
219 " $oneof_name$Case_ = value == null ? $oneof_property_name$OneofCase.None : $oneof_property_name$OneofCase.$property_name$;\n"
220 " }\n"
221 "}\n");
222 if (IsProto2(descriptor_->file())) {
223 printer->Print(
224 variables_,
225 "/// <summary>Gets whether the \"$descriptor_name$\" field is set</summary>\n");
226 AddPublicMemberAttributes(printer);
227 printer->Print(
228 variables_,
229 "$access_level$ bool Has$property_name$ {\n"
230 " get { return $oneof_name$Case_ == $oneof_property_name$OneofCase.$property_name$; }\n"
231 "}\n");
232 printer->Print(
233 variables_,
234 "/// <summary> Clears the value of the oneof if it's currently set to \"$descriptor_name$\" </summary>\n");
235 AddPublicMemberAttributes(printer);
236 printer->Print(
237 variables_,
238 "$access_level$ void Clear$property_name$() {\n"
239 " if ($has_property_check$) {\n"
240 " Clear$oneof_property_name$();\n"
241 " }\n"
242 "}\n");
243 }
244 }
245
GenerateMergingCode(io::Printer * printer)246 void WrapperOneofFieldGenerator::GenerateMergingCode(io::Printer* printer) {
247 printer->Print(variables_, "$property_name$ = other.$property_name$;\n");
248 }
249
GenerateParsingCode(io::Printer * printer)250 void WrapperOneofFieldGenerator::GenerateParsingCode(io::Printer* printer) {
251 printer->Print(
252 variables_,
253 "$property_name$ = _oneof_$name$_codec.Read(input);\n");
254 }
255
GenerateSerializationCode(io::Printer * printer)256 void WrapperOneofFieldGenerator::GenerateSerializationCode(io::Printer* printer) {
257 // TODO: I suspect this is wrong...
258 printer->Print(
259 variables_,
260 "if ($has_property_check$) {\n"
261 " _oneof_$name$_codec.WriteTagAndValue(output, ($type_name$) $oneof_name$_);\n"
262 "}\n");
263 }
264
GenerateSerializedSizeCode(io::Printer * printer)265 void WrapperOneofFieldGenerator::GenerateSerializedSizeCode(io::Printer* printer) {
266 // TODO: I suspect this is wrong...
267 printer->Print(
268 variables_,
269 "if ($has_property_check$) {\n"
270 " size += _oneof_$name$_codec.CalculateSizeWithTag($property_name$);\n"
271 "}\n");
272 }
273
274 } // namespace csharp
275 } // namespace compiler
276 } // namespace protobuf
277 } // namespace google
278