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#include <google/protobuf/wire_format.h>
40#include <google/protobuf/wire_format_lite.h>
41
42#include <google/protobuf/compiler/csharp/csharp_doc_comment.h>
43#include <google/protobuf/compiler/csharp/csharp_helpers.h>
44#include <google/protobuf/compiler/csharp/csharp_message_field.h>
45#include <google/protobuf/compiler/csharp/csharp_options.h>
46
47namespace google {
48namespace protobuf {
49namespace compiler {
50namespace csharp {
51
52MessageFieldGenerator::MessageFieldGenerator(const FieldDescriptor* descriptor,
53 int presenceIndex,
54 const Options *options)
55 : FieldGeneratorBase(descriptor, presenceIndex, options) {
56 if (!SupportsPresenceApi(descriptor: descriptor_)) {
57 variables_["has_property_check"] = name() + "_ != null";
58 variables_["has_not_property_check"] = name() + "_ == null";
59 }
60}
61
62MessageFieldGenerator::~MessageFieldGenerator() {
63
64}
65
66void MessageFieldGenerator::GenerateMembers(io::Printer* printer) {
67 printer->Print(
68 variables: variables_,
69 text: "private $type_name$ $name$_;\n");
70 WritePropertyDocComment(printer, field: descriptor_);
71 AddPublicMemberAttributes(printer);
72 printer->Print(
73 variables: variables_,
74 text: "$access_level$ $type_name$ $property_name$ {\n"
75 " get { return $name$_; }\n"
76 " set {\n"
77 " $name$_ = value;\n"
78 " }\n"
79 "}\n");
80 if (SupportsPresenceApi(descriptor: descriptor_)) {
81 printer->Print(
82 variables: variables_,
83 text: "/// <summary>Gets whether the $descriptor_name$ field is set</summary>\n");
84 AddPublicMemberAttributes(printer);
85 printer->Print(
86 variables: variables_,
87 text: "$access_level$ bool Has$property_name$ {\n"
88 " get { return $name$_ != null; }\n"
89 "}\n");
90 printer->Print(
91 variables: variables_,
92 text: "/// <summary>Clears the value of the $descriptor_name$ field</summary>\n");
93 AddPublicMemberAttributes(printer);
94 printer->Print(
95 variables: variables_,
96 text: "$access_level$ void Clear$property_name$() {\n"
97 " $name$_ = null;\n"
98 "}\n");
99 }
100}
101
102void MessageFieldGenerator::GenerateMergingCode(io::Printer* printer) {
103 printer->Print(
104 variables: variables_,
105 text: "if (other.$has_property_check$) {\n"
106 " if ($has_not_property_check$) {\n"
107 " $property_name$ = new $type_name$();\n"
108 " }\n"
109 " $property_name$.MergeFrom(other.$property_name$);\n"
110 "}\n");
111}
112
113void MessageFieldGenerator::GenerateParsingCode(io::Printer* printer) {
114 printer->Print(
115 variables: variables_,
116 text: "if ($has_not_property_check$) {\n"
117 " $property_name$ = new $type_name$();\n"
118 "}\n");
119 if (descriptor_->type() == FieldDescriptor::Type::TYPE_MESSAGE) {
120 printer->Print(variables: variables_, text: "input.ReadMessage($property_name$);\n");
121 } else {
122 printer->Print(variables: variables_, text: "input.ReadGroup($property_name$);\n");
123 }
124}
125
126void MessageFieldGenerator::GenerateSerializationCode(io::Printer* printer) {
127 if (descriptor_->type() == FieldDescriptor::Type::TYPE_MESSAGE) {
128 printer->Print(
129 variables: variables_,
130 text: "if ($has_property_check$) {\n"
131 " output.WriteRawTag($tag_bytes$);\n"
132 " output.WriteMessage($property_name$);\n"
133 "}\n");
134 } else {
135 printer->Print(
136 variables: variables_,
137 text: "if ($has_property_check$) {\n"
138 " output.WriteRawTag($tag_bytes$);\n"
139 " output.WriteGroup($property_name$);\n"
140 " output.WriteRawTag($end_tag_bytes$);\n"
141 "}\n");
142 }
143}
144
145void MessageFieldGenerator::GenerateSerializedSizeCode(io::Printer* printer) {
146 if (descriptor_->type() == FieldDescriptor::Type::TYPE_MESSAGE) {
147 printer->Print(
148 variables: variables_,
149 text: "if ($has_property_check$) {\n"
150 " size += $tag_size$ + pb::CodedOutputStream.ComputeMessageSize($property_name$);\n"
151 "}\n");
152 } else {
153 printer->Print(
154 variables: variables_,
155 text: "if ($has_property_check$) {\n"
156 " size += $tag_size$ + pb::CodedOutputStream.ComputeGroupSize($property_name$);\n"
157 "}\n");
158 }
159}
160
161void MessageFieldGenerator::WriteHash(io::Printer* printer) {
162 printer->Print(
163 variables: variables_,
164 text: "if ($has_property_check$) hash ^= $property_name$.GetHashCode();\n");
165}
166void MessageFieldGenerator::WriteEquals(io::Printer* printer) {
167 printer->Print(
168 variables: variables_,
169 text: "if (!object.Equals($property_name$, other.$property_name$)) return false;\n");
170}
171void MessageFieldGenerator::WriteToString(io::Printer* printer) {
172 variables_["field_name"] = GetFieldName(descriptor: descriptor_);
173 printer->Print(
174 variables: variables_,
175 text: "PrintField(\"$field_name$\", has$property_name$, $name$_, writer);\n");
176}
177void MessageFieldGenerator::GenerateExtensionCode(io::Printer* printer) {
178 WritePropertyDocComment(printer, field: descriptor_);
179 AddDeprecatedFlag(printer);
180 printer->Print(
181 variables: variables_,
182 text: "$access_level$ static readonly pb::Extension<$extended_type$, $type_name$> $property_name$ =\n"
183 " new pb::Extension<$extended_type$, $type_name$>($number$, ");
184 GenerateCodecCode(printer);
185 printer->Print(text: ");\n");
186}
187void MessageFieldGenerator::GenerateCloningCode(io::Printer* printer) {
188 printer->Print(variables: variables_,
189 text: "$name$_ = other.$has_property_check$ ? other.$name$_.Clone() : null;\n");
190}
191
192void MessageFieldGenerator::GenerateFreezingCode(io::Printer* printer) {
193}
194
195void MessageFieldGenerator::GenerateCodecCode(io::Printer* printer) {
196 if (descriptor_->type() == FieldDescriptor::Type::TYPE_MESSAGE) {
197 printer->Print(
198 variables: variables_,
199 text: "pb::FieldCodec.ForMessage($tag$, $type_name$.Parser)");
200 } else {
201 printer->Print(
202 variables: variables_,
203 text: "pb::FieldCodec.ForGroup($tag$, $end_tag$, $type_name$.Parser)");
204 }
205}
206
207MessageOneofFieldGenerator::MessageOneofFieldGenerator(
208 const FieldDescriptor* descriptor,
209 int presenceIndex,
210 const Options *options)
211 : MessageFieldGenerator(descriptor, presenceIndex, options) {
212 SetCommonOneofFieldVariables(&variables_);
213}
214
215MessageOneofFieldGenerator::~MessageOneofFieldGenerator() {
216
217}
218
219void MessageOneofFieldGenerator::GenerateMembers(io::Printer* printer) {
220 WritePropertyDocComment(printer, field: descriptor_);
221 AddPublicMemberAttributes(printer);
222 printer->Print(
223 variables: variables_,
224 text: "$access_level$ $type_name$ $property_name$ {\n"
225 " get { return $has_property_check$ ? ($type_name$) $oneof_name$_ : null; }\n"
226 " set {\n"
227 " $oneof_name$_ = value;\n"
228 " $oneof_name$Case_ = value == null ? $oneof_property_name$OneofCase.None : $oneof_property_name$OneofCase.$oneof_case_name$;\n"
229 " }\n"
230 "}\n");
231 if (SupportsPresenceApi(descriptor: descriptor_)) {
232 printer->Print(
233 variables: variables_,
234 text: "/// <summary>Gets whether the \"$descriptor_name$\" field is set</summary>\n");
235 AddPublicMemberAttributes(printer);
236 printer->Print(
237 variables: variables_,
238 text: "$access_level$ bool Has$property_name$ {\n"
239 " get { return $oneof_name$Case_ == $oneof_property_name$OneofCase.$oneof_case_name$; }\n"
240 "}\n");
241 printer->Print(
242 variables: variables_,
243 text: "/// <summary> Clears the value of the oneof if it's currently set to \"$descriptor_name$\" </summary>\n");
244 AddPublicMemberAttributes(printer);
245 printer->Print(
246 variables: variables_,
247 text: "$access_level$ void Clear$property_name$() {\n"
248 " if ($has_property_check$) {\n"
249 " Clear$oneof_property_name$();\n"
250 " }\n"
251 "}\n");
252 }
253}
254
255void MessageOneofFieldGenerator::GenerateMergingCode(io::Printer* printer) {
256 printer->Print(variables: variables_,
257 text: "if ($property_name$ == null) {\n"
258 " $property_name$ = new $type_name$();\n"
259 "}\n"
260 "$property_name$.MergeFrom(other.$property_name$);\n");
261}
262
263void MessageOneofFieldGenerator::GenerateParsingCode(io::Printer* printer) {
264 // TODO(jonskeet): We may be able to do better than this
265 printer->Print(
266 variables: variables_,
267 text: "$type_name$ subBuilder = new $type_name$();\n"
268 "if ($has_property_check$) {\n"
269 " subBuilder.MergeFrom($property_name$);\n"
270 "}\n");
271 if (descriptor_->type() == FieldDescriptor::Type::TYPE_MESSAGE) {
272 printer->Print(text: "input.ReadMessage(subBuilder);\n");
273 } else {
274 printer->Print(text: "input.ReadGroup(subBuilder);\n");
275 }
276 printer->Print(variables: variables_, text: "$property_name$ = subBuilder;\n");
277}
278
279void MessageOneofFieldGenerator::WriteToString(io::Printer* printer) {
280 printer->Print(
281 variables: variables_,
282 text: "PrintField(\"$descriptor_name$\", $has_property_check$, $oneof_name$_, writer);\n");
283}
284
285void MessageOneofFieldGenerator::GenerateCloningCode(io::Printer* printer) {
286 printer->Print(variables: variables_,
287 text: "$property_name$ = other.$property_name$.Clone();\n");
288}
289
290} // namespace csharp
291} // namespace compiler
292} // namespace protobuf
293} // namespace google
294