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