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
47 namespace google {
48 namespace protobuf {
49 namespace compiler {
50 namespace csharp {
51
MessageFieldGenerator(const FieldDescriptor * descriptor,int presenceIndex,const Options * options)52 MessageFieldGenerator::MessageFieldGenerator(const FieldDescriptor* descriptor,
53 int presenceIndex,
54 const Options *options)
55 : FieldGeneratorBase(descriptor, presenceIndex, options) {
56 if (!IsProto2(descriptor_->file())) {
57 variables_["has_property_check"] = name() + "_ != null";
58 variables_["has_not_property_check"] = name() + "_ == null";
59 }
60 }
61
~MessageFieldGenerator()62 MessageFieldGenerator::~MessageFieldGenerator() {
63
64 }
65
GenerateMembers(io::Printer * printer)66 void MessageFieldGenerator::GenerateMembers(io::Printer* printer) {
67 printer->Print(
68 variables_,
69 "private $type_name$ $name$_;\n");
70 WritePropertyDocComment(printer, descriptor_);
71 AddPublicMemberAttributes(printer);
72 printer->Print(
73 variables_,
74 "$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 (IsProto2(descriptor_->file())) {
81 printer->Print(
82 variables_,
83 "/// <summary>Gets whether the $descriptor_name$ field is set</summary>\n");
84 AddPublicMemberAttributes(printer);
85 printer->Print(
86 variables_,
87 "$access_level$ bool Has$property_name$ {\n"
88 " get { return $name$_ != null; }\n"
89 "}\n");
90 printer->Print(
91 variables_,
92 "/// <summary>Clears the value of the $descriptor_name$ field</summary>\n");
93 AddPublicMemberAttributes(printer);
94 printer->Print(
95 variables_,
96 "$access_level$ void Clear$property_name$() {\n"
97 " $name$_ = null;\n"
98 "}\n");
99 }
100 }
101
GenerateMergingCode(io::Printer * printer)102 void MessageFieldGenerator::GenerateMergingCode(io::Printer* printer) {
103 printer->Print(
104 variables_,
105 "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
GenerateParsingCode(io::Printer * printer)113 void MessageFieldGenerator::GenerateParsingCode(io::Printer* printer) {
114 printer->Print(
115 variables_,
116 "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_, "input.ReadMessage($property_name$);\n");
121 } else {
122 printer->Print(variables_, "input.ReadGroup($property_name$);\n");
123 }
124 }
125
GenerateSerializationCode(io::Printer * printer)126 void MessageFieldGenerator::GenerateSerializationCode(io::Printer* printer) {
127 if (descriptor_->type() == FieldDescriptor::Type::TYPE_MESSAGE) {
128 printer->Print(
129 variables_,
130 "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_,
137 "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
GenerateSerializedSizeCode(io::Printer * printer)145 void MessageFieldGenerator::GenerateSerializedSizeCode(io::Printer* printer) {
146 if (descriptor_->type() == FieldDescriptor::Type::TYPE_MESSAGE) {
147 printer->Print(
148 variables_,
149 "if ($has_property_check$) {\n"
150 " size += $tag_size$ + pb::CodedOutputStream.ComputeMessageSize($property_name$);\n"
151 "}\n");
152 } else {
153 printer->Print(
154 variables_,
155 "if ($has_property_check$) {\n"
156 " size += $tag_size$ + pb::CodedOutputStream.ComputeGroupSize($property_name$);\n"
157 "}\n");
158 }
159 }
160
WriteHash(io::Printer * printer)161 void MessageFieldGenerator::WriteHash(io::Printer* printer) {
162 printer->Print(
163 variables_,
164 "if ($has_property_check$) hash ^= $property_name$.GetHashCode();\n");
165 }
WriteEquals(io::Printer * printer)166 void MessageFieldGenerator::WriteEquals(io::Printer* printer) {
167 printer->Print(
168 variables_,
169 "if (!object.Equals($property_name$, other.$property_name$)) return false;\n");
170 }
WriteToString(io::Printer * printer)171 void MessageFieldGenerator::WriteToString(io::Printer* printer) {
172 variables_["field_name"] = GetFieldName(descriptor_);
173 printer->Print(
174 variables_,
175 "PrintField(\"$field_name$\", has$property_name$, $name$_, writer);\n");
176 }
GenerateExtensionCode(io::Printer * printer)177 void MessageFieldGenerator::GenerateExtensionCode(io::Printer* printer) {
178 WritePropertyDocComment(printer, descriptor_);
179 AddDeprecatedFlag(printer);
180 printer->Print(
181 variables_,
182 "$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(");\n");
186 }
GenerateCloningCode(io::Printer * printer)187 void MessageFieldGenerator::GenerateCloningCode(io::Printer* printer) {
188 printer->Print(variables_,
189 "$name$_ = other.$has_property_check$ ? other.$name$_.Clone() : null;\n");
190 }
191
GenerateFreezingCode(io::Printer * printer)192 void MessageFieldGenerator::GenerateFreezingCode(io::Printer* printer) {
193 }
194
GenerateCodecCode(io::Printer * printer)195 void MessageFieldGenerator::GenerateCodecCode(io::Printer* printer) {
196 if (descriptor_->type() == FieldDescriptor::Type::TYPE_MESSAGE) {
197 printer->Print(
198 variables_,
199 "pb::FieldCodec.ForMessage($tag$, $type_name$.Parser)");
200 } else {
201 printer->Print(
202 variables_,
203 "pb::FieldCodec.ForGroup($tag$, $end_tag$, $type_name$.Parser)");
204 }
205 }
206
MessageOneofFieldGenerator(const FieldDescriptor * descriptor,int presenceIndex,const Options * options)207 MessageOneofFieldGenerator::MessageOneofFieldGenerator(
208 const FieldDescriptor* descriptor,
209 int presenceIndex,
210 const Options *options)
211 : MessageFieldGenerator(descriptor, presenceIndex, options) {
212 SetCommonOneofFieldVariables(&variables_);
213 }
214
~MessageOneofFieldGenerator()215 MessageOneofFieldGenerator::~MessageOneofFieldGenerator() {
216
217 }
218
GenerateMembers(io::Printer * printer)219 void MessageOneofFieldGenerator::GenerateMembers(io::Printer* printer) {
220 WritePropertyDocComment(printer, descriptor_);
221 AddPublicMemberAttributes(printer);
222 printer->Print(
223 variables_,
224 "$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.$property_name$;\n"
229 " }\n"
230 "}\n");
231 if (IsProto2(descriptor_->file())) {
232 printer->Print(
233 variables_,
234 "/// <summary>Gets whether the \"$descriptor_name$\" field is set</summary>\n");
235 AddPublicMemberAttributes(printer);
236 printer->Print(
237 variables_,
238 "$access_level$ bool Has$property_name$ {\n"
239 " get { return $oneof_name$Case_ == $oneof_property_name$OneofCase.$property_name$; }\n"
240 "}\n");
241 printer->Print(
242 variables_,
243 "/// <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_,
247 "$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
GenerateMergingCode(io::Printer * printer)255 void MessageOneofFieldGenerator::GenerateMergingCode(io::Printer* printer) {
256 printer->Print(variables_,
257 "if ($property_name$ == null) {\n"
258 " $property_name$ = new $type_name$();\n"
259 "}\n"
260 "$property_name$.MergeFrom(other.$property_name$);\n");
261 }
262
GenerateParsingCode(io::Printer * printer)263 void MessageOneofFieldGenerator::GenerateParsingCode(io::Printer* printer) {
264 // TODO(jonskeet): We may be able to do better than this
265 printer->Print(
266 variables_,
267 "$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("input.ReadMessage(subBuilder);\n");
273 } else {
274 printer->Print("input.ReadGroup(subBuilder);\n");
275 }
276 printer->Print(variables_, "$property_name$ = subBuilder;\n");
277 }
278
WriteToString(io::Printer * printer)279 void MessageOneofFieldGenerator::WriteToString(io::Printer* printer) {
280 printer->Print(
281 variables_,
282 "PrintField(\"$descriptor_name$\", $has_property_check$, $oneof_name$_, writer);\n");
283 }
284
GenerateCloningCode(io::Printer * printer)285 void MessageOneofFieldGenerator::GenerateCloningCode(io::Printer* printer) {
286 printer->Print(variables_,
287 "$property_name$ = other.$property_name$.Clone();\n");
288 }
289
290 } // namespace csharp
291 } // namespace compiler
292 } // namespace protobuf
293 } // namespace google
294