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 | |
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 && !SupportsPresenceApi(descriptor: descriptor_)) { |
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 | |
62 | PrimitiveFieldGenerator::~PrimitiveFieldGenerator() { |
63 | } |
64 | |
65 | void PrimitiveFieldGenerator::GenerateMembers(io::Printer* printer) { |
66 | |
67 | // Note: in multiple places, this code assumes that all fields |
68 | // that support presence are either nullable, or use a presence field bit. |
69 | // Fields which are oneof members are not generated here; they're generated in PrimitiveOneofFieldGenerator below. |
70 | // Extensions are not generated here either. |
71 | |
72 | |
73 | // Proto2 allows different default values to be specified. These are retained |
74 | // via static fields. They don't particularly need to be, but we don't need |
75 | // to change that. In Proto3 the default value we don't generate these |
76 | // fields, just using the literal instead. |
77 | if (IsProto2(descriptor: descriptor_->file())) { |
78 | // Note: "private readonly static" isn't as idiomatic as |
79 | // "private static readonly", but changing this now would create a lot of |
80 | // churn in generated code with near-to-zero benefit. |
81 | printer->Print( |
82 | variables: variables_, |
83 | text: "private readonly static $type_name$ $property_name$DefaultValue = $default_value$;\n\n" ); |
84 | variables_["default_value_access" ] = |
85 | variables_["property_name" ] + "DefaultValue" ; |
86 | } else { |
87 | variables_["default_value_access" ] = variables_["default_value" ]; |
88 | } |
89 | |
90 | // Declare the field itself. |
91 | printer->Print( |
92 | variables: variables_, |
93 | text: "private $type_name$ $name_def_message$;\n" ); |
94 | |
95 | WritePropertyDocComment(printer, field: descriptor_); |
96 | AddPublicMemberAttributes(printer); |
97 | |
98 | // Most of the work is done in the property: |
99 | // Declare the property itself (the same for all options) |
100 | printer->Print(variables: variables_, text: "$access_level$ $type_name$ $property_name$ {\n" ); |
101 | |
102 | // Specify the "getter", which may need to check for a presence field. |
103 | if (SupportsPresenceApi(descriptor: descriptor_)) { |
104 | if (IsNullable(descriptor: descriptor_)) { |
105 | printer->Print( |
106 | variables: variables_, |
107 | text: " get { return $name$_ ?? $default_value_access$; }\n" ); |
108 | } else { |
109 | printer->Print( |
110 | variables: variables_, |
111 | // Note: it's possible that this could be rewritten as a |
112 | // conditional ?: expression, but there's no significant benefit |
113 | // to changing it. |
114 | text: " get { if ($has_field_check$) { return $name$_; } else { return $default_value_access$; } }\n" ); |
115 | } |
116 | } else { |
117 | printer->Print( |
118 | variables: variables_, |
119 | text: " get { return $name$_; }\n" ); |
120 | } |
121 | |
122 | // Specify the "setter", which may need to set a field bit as well as the |
123 | // value. |
124 | printer->Print(text: " set {\n" ); |
125 | if (presenceIndex_ != -1) { |
126 | printer->Print( |
127 | variables: variables_, |
128 | text: " $set_has_field$;\n" ); |
129 | } |
130 | if (is_value_type) { |
131 | printer->Print( |
132 | variables: variables_, |
133 | text: " $name$_ = value;\n" ); |
134 | } else { |
135 | printer->Print( |
136 | variables: variables_, |
137 | text: " $name$_ = pb::ProtoPreconditions.CheckNotNull(value, \"value\");\n" ); |
138 | } |
139 | printer->Print( |
140 | text: " }\n" |
141 | "}\n" ); |
142 | |
143 | // The "HasFoo" property, where required. |
144 | if (SupportsPresenceApi(descriptor: descriptor_)) { |
145 | printer->Print(variables: variables_, |
146 | text: "/// <summary>Gets whether the \"$descriptor_name$\" field is set</summary>\n" ); |
147 | AddPublicMemberAttributes(printer); |
148 | printer->Print( |
149 | variables: variables_, |
150 | text: "$access_level$ bool Has$property_name$ {\n" |
151 | " get { return " ); |
152 | if (IsNullable(descriptor: descriptor_)) { |
153 | printer->Print( |
154 | variables: variables_, |
155 | text: "$name$_ != null; }\n}\n" ); |
156 | } else { |
157 | printer->Print( |
158 | variables: variables_, |
159 | text: "$has_field_check$; }\n}\n" ); |
160 | } |
161 | } |
162 | |
163 | // The "ClearFoo" method, where required. |
164 | if (SupportsPresenceApi(descriptor: descriptor_)) { |
165 | printer->Print(variables: variables_, |
166 | text: "/// <summary>Clears the value of the \"$descriptor_name$\" field</summary>\n" ); |
167 | AddPublicMemberAttributes(printer); |
168 | printer->Print( |
169 | variables: variables_, |
170 | text: "$access_level$ void Clear$property_name$() {\n" ); |
171 | if (IsNullable(descriptor: descriptor_)) { |
172 | printer->Print(variables: variables_, text: " $name$_ = null;\n" ); |
173 | } else { |
174 | printer->Print(variables: variables_, text: " $clear_has_field$;\n" ); |
175 | } |
176 | printer->Print(text: "}\n" ); |
177 | } |
178 | } |
179 | |
180 | void PrimitiveFieldGenerator::GenerateMergingCode(io::Printer* printer) { |
181 | printer->Print( |
182 | variables: variables_, |
183 | text: "if ($other_has_property_check$) {\n" |
184 | " $property_name$ = other.$property_name$;\n" |
185 | "}\n" ); |
186 | } |
187 | |
188 | void PrimitiveFieldGenerator::GenerateParsingCode(io::Printer* printer) { |
189 | // Note: invoke the property setter rather than writing straight to the field, |
190 | // so that we can normalize "null to empty" for strings and bytes. |
191 | printer->Print( |
192 | variables: variables_, |
193 | text: "$property_name$ = input.Read$capitalized_type_name$();\n" ); |
194 | } |
195 | |
196 | void PrimitiveFieldGenerator::GenerateSerializationCode(io::Printer* printer) { |
197 | printer->Print( |
198 | variables: variables_, |
199 | text: "if ($has_property_check$) {\n" |
200 | " output.WriteRawTag($tag_bytes$);\n" |
201 | " output.Write$capitalized_type_name$($property_name$);\n" |
202 | "}\n" ); |
203 | } |
204 | |
205 | void PrimitiveFieldGenerator::GenerateSerializedSizeCode(io::Printer* printer) { |
206 | printer->Print( |
207 | variables: variables_, |
208 | text: "if ($has_property_check$) {\n" ); |
209 | printer->Indent(); |
210 | int fixedSize = GetFixedSize(type: descriptor_->type()); |
211 | if (fixedSize == -1) { |
212 | printer->Print( |
213 | variables: variables_, |
214 | text: "size += $tag_size$ + pb::CodedOutputStream.Compute$capitalized_type_name$Size($property_name$);\n" ); |
215 | } else { |
216 | printer->Print( |
217 | text: "size += $tag_size$ + $fixed_size$;\n" , |
218 | args: "fixed_size" , args: StrCat(a: fixedSize), |
219 | args: "tag_size" , args: variables_["tag_size" ]); |
220 | } |
221 | printer->Outdent(); |
222 | printer->Print(text: "}\n" ); |
223 | } |
224 | |
225 | void PrimitiveFieldGenerator::WriteHash(io::Printer* printer) { |
226 | const char *text = "if ($has_property_check$) hash ^= $property_name$.GetHashCode();\n" ; |
227 | if (descriptor_->type() == FieldDescriptor::TYPE_FLOAT) { |
228 | text = "if ($has_property_check$) hash ^= pbc::ProtobufEqualityComparers.BitwiseSingleEqualityComparer.GetHashCode($property_name$);\n" ; |
229 | } else if (descriptor_->type() == FieldDescriptor::TYPE_DOUBLE) { |
230 | text = "if ($has_property_check$) hash ^= pbc::ProtobufEqualityComparers.BitwiseDoubleEqualityComparer.GetHashCode($property_name$);\n" ; |
231 | } |
232 | printer->Print(variables: variables_, text); |
233 | } |
234 | void PrimitiveFieldGenerator::WriteEquals(io::Printer* printer) { |
235 | const char *text = "if ($property_name$ != other.$property_name$) return false;\n" ; |
236 | if (descriptor_->type() == FieldDescriptor::TYPE_FLOAT) { |
237 | text = "if (!pbc::ProtobufEqualityComparers.BitwiseSingleEqualityComparer.Equals($property_name$, other.$property_name$)) return false;\n" ; |
238 | } else if (descriptor_->type() == FieldDescriptor::TYPE_DOUBLE) { |
239 | text = "if (!pbc::ProtobufEqualityComparers.BitwiseDoubleEqualityComparer.Equals($property_name$, other.$property_name$)) return false;\n" ; |
240 | } |
241 | printer->Print(variables: variables_, text); |
242 | } |
243 | void PrimitiveFieldGenerator::WriteToString(io::Printer* printer) { |
244 | printer->Print( |
245 | variables: variables_, |
246 | text: "PrintField(\"$descriptor_name$\", $has_property_check$, $property_name$, writer);\n" ); |
247 | } |
248 | |
249 | void PrimitiveFieldGenerator::GenerateCloningCode(io::Printer* printer) { |
250 | printer->Print(variables: variables_, |
251 | text: "$name$_ = other.$name$_;\n" ); |
252 | } |
253 | |
254 | void PrimitiveFieldGenerator::GenerateCodecCode(io::Printer* printer) { |
255 | printer->Print( |
256 | variables: variables_, |
257 | text: "pb::FieldCodec.For$capitalized_type_name$($tag$, $default_value$)" ); |
258 | } |
259 | |
260 | void PrimitiveFieldGenerator::GenerateExtensionCode(io::Printer* printer) { |
261 | WritePropertyDocComment(printer, field: descriptor_); |
262 | AddDeprecatedFlag(printer); |
263 | printer->Print( |
264 | variables: variables_, |
265 | text: "$access_level$ static readonly pb::Extension<$extended_type$, $type_name$> $property_name$ =\n" |
266 | " new pb::Extension<$extended_type$, $type_name$>($number$, " ); |
267 | GenerateCodecCode(printer); |
268 | printer->Print(text: ");\n" ); |
269 | } |
270 | |
271 | PrimitiveOneofFieldGenerator::PrimitiveOneofFieldGenerator( |
272 | const FieldDescriptor* descriptor, int presenceIndex, const Options *options) |
273 | : PrimitiveFieldGenerator(descriptor, presenceIndex, options) { |
274 | SetCommonOneofFieldVariables(&variables_); |
275 | } |
276 | |
277 | PrimitiveOneofFieldGenerator::~PrimitiveOneofFieldGenerator() { |
278 | } |
279 | |
280 | void PrimitiveOneofFieldGenerator::GenerateMembers(io::Printer* printer) { |
281 | WritePropertyDocComment(printer, field: descriptor_); |
282 | AddPublicMemberAttributes(printer); |
283 | printer->Print( |
284 | variables: variables_, |
285 | text: "$access_level$ $type_name$ $property_name$ {\n" |
286 | " get { return $has_property_check$ ? ($type_name$) $oneof_name$_ : $default_value$; }\n" |
287 | " set {\n" ); |
288 | if (is_value_type) { |
289 | printer->Print( |
290 | variables: variables_, |
291 | text: " $oneof_name$_ = value;\n" ); |
292 | } else { |
293 | printer->Print( |
294 | variables: variables_, |
295 | text: " $oneof_name$_ = pb::ProtoPreconditions.CheckNotNull(value, \"value\");\n" ); |
296 | } |
297 | printer->Print( |
298 | variables: variables_, |
299 | text: " $oneof_name$Case_ = $oneof_property_name$OneofCase.$oneof_case_name$;\n" |
300 | " }\n" |
301 | "}\n" ); |
302 | if (SupportsPresenceApi(descriptor: descriptor_)) { |
303 | printer->Print( |
304 | variables: variables_, |
305 | text: "/// <summary>Gets whether the \"$descriptor_name$\" field is set</summary>\n" ); |
306 | AddPublicMemberAttributes(printer); |
307 | printer->Print( |
308 | variables: variables_, |
309 | text: "$access_level$ bool Has$property_name$ {\n" |
310 | " get { return $oneof_name$Case_ == $oneof_property_name$OneofCase.$oneof_case_name$; }\n" |
311 | "}\n" ); |
312 | printer->Print( |
313 | variables: variables_, |
314 | text: "/// <summary> Clears the value of the oneof if it's currently set to \"$descriptor_name$\" </summary>\n" ); |
315 | AddPublicMemberAttributes(printer); |
316 | printer->Print( |
317 | variables: variables_, |
318 | text: "$access_level$ void Clear$property_name$() {\n" |
319 | " if ($has_property_check$) {\n" |
320 | " Clear$oneof_property_name$();\n" |
321 | " }\n" |
322 | "}\n" ); |
323 | } |
324 | } |
325 | |
326 | void PrimitiveOneofFieldGenerator::GenerateMergingCode(io::Printer* printer) { |
327 | printer->Print(variables: variables_, text: "$property_name$ = other.$property_name$;\n" ); |
328 | } |
329 | |
330 | void PrimitiveOneofFieldGenerator::WriteToString(io::Printer* printer) { |
331 | printer->Print(variables: variables_, |
332 | text: "PrintField(\"$descriptor_name$\", $has_property_check$, $oneof_name$_, writer);\n" ); |
333 | } |
334 | |
335 | void PrimitiveOneofFieldGenerator::GenerateParsingCode(io::Printer* printer) { |
336 | printer->Print( |
337 | variables: variables_, |
338 | text: "$property_name$ = input.Read$capitalized_type_name$();\n" ); |
339 | } |
340 | |
341 | void PrimitiveOneofFieldGenerator::GenerateCloningCode(io::Printer* printer) { |
342 | printer->Print(variables: variables_, |
343 | text: "$property_name$ = other.$property_name$;\n" ); |
344 | } |
345 | |
346 | } // namespace csharp |
347 | } // namespace compiler |
348 | } // namespace protobuf |
349 | } // namespace google |
350 | |