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/compiler/plugin.h>
35 #include <google/protobuf/descriptor.h>
36 #include <google/protobuf/descriptor.pb.h>
37 #include <google/protobuf/io/printer.h>
38 #include <google/protobuf/io/zero_copy_stream.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_wrapper_field.h>
44
45 namespace google {
46 namespace protobuf {
47 namespace compiler {
48 namespace csharp {
49
WrapperFieldGenerator(const FieldDescriptor * descriptor,int fieldOrdinal,const Options * options)50 WrapperFieldGenerator::WrapperFieldGenerator(const FieldDescriptor* descriptor,
51 int fieldOrdinal, const Options *options)
52 : FieldGeneratorBase(descriptor, fieldOrdinal, options) {
53 variables_["has_property_check"] = name() + "_ != null";
54 variables_["has_not_property_check"] = name() + "_ == null";
55 const FieldDescriptor* wrapped_field = descriptor->message_type()->field(0);
56 is_value_type = wrapped_field->type() != FieldDescriptor::TYPE_STRING &&
57 wrapped_field->type() != FieldDescriptor::TYPE_BYTES;
58 if (is_value_type) {
59 variables_["nonnullable_type_name"] = type_name(wrapped_field);
60 }
61 }
62
~WrapperFieldGenerator()63 WrapperFieldGenerator::~WrapperFieldGenerator() {
64 }
65
GenerateMembers(io::Printer * printer)66 void WrapperFieldGenerator::GenerateMembers(io::Printer* printer) {
67 printer->Print(
68 variables_,
69 "private static readonly pb::FieldCodec<$type_name$> _single_$name$_codec = ");
70 GenerateCodecCode(printer);
71 printer->Print(
72 variables_,
73 ";\n"
74 "private $type_name$ $name$_;\n");
75 WritePropertyDocComment(printer, descriptor_);
76 AddDeprecatedFlag(printer);
77 printer->Print(
78 variables_,
79 "$access_level$ $type_name$ $property_name$ {\n"
80 " get { return $name$_; }\n"
81 " set {\n"
82 " $name$_ = value;\n"
83 " }\n"
84 "}\n");
85 }
86
GenerateMergingCode(io::Printer * printer)87 void WrapperFieldGenerator::GenerateMergingCode(io::Printer* printer) {
88 printer->Print(
89 variables_,
90 "if (other.$has_property_check$) {\n"
91 " if ($has_not_property_check$ || other.$property_name$ != $default_value$) {\n"
92 " $property_name$ = other.$property_name$;\n"
93 " }\n"
94 "}\n");
95 }
96
GenerateParsingCode(io::Printer * printer)97 void WrapperFieldGenerator::GenerateParsingCode(io::Printer* printer) {
98 printer->Print(
99 variables_,
100 "$type_name$ value = _single_$name$_codec.Read(input);\n"
101 "if ($has_not_property_check$ || value != $default_value$) {\n"
102 " $property_name$ = value;\n"
103 "}\n");
104 }
105
GenerateSerializationCode(io::Printer * printer)106 void WrapperFieldGenerator::GenerateSerializationCode(io::Printer* printer) {
107 printer->Print(
108 variables_,
109 "if ($has_property_check$) {\n"
110 " _single_$name$_codec.WriteTagAndValue(output, $property_name$);\n"
111 "}\n");
112 }
113
GenerateSerializedSizeCode(io::Printer * printer)114 void WrapperFieldGenerator::GenerateSerializedSizeCode(io::Printer* printer) {
115 printer->Print(
116 variables_,
117 "if ($has_property_check$) {\n"
118 " size += _single_$name$_codec.CalculateSizeWithTag($property_name$);\n"
119 "}\n");
120 }
121
WriteHash(io::Printer * printer)122 void WrapperFieldGenerator::WriteHash(io::Printer* printer) {
123 printer->Print(
124 variables_,
125 "if ($has_property_check$) hash ^= $property_name$.GetHashCode();\n");
126 }
127
WriteEquals(io::Printer * printer)128 void WrapperFieldGenerator::WriteEquals(io::Printer* printer) {
129 printer->Print(
130 variables_,
131 "if ($property_name$ != other.$property_name$) return false;\n");
132 }
133
WriteToString(io::Printer * printer)134 void WrapperFieldGenerator::WriteToString(io::Printer* printer) {
135 // TODO: Implement if we ever actually need it...
136 }
137
GenerateCloningCode(io::Printer * printer)138 void WrapperFieldGenerator::GenerateCloningCode(io::Printer* printer) {
139 printer->Print(variables_,
140 "$property_name$ = other.$property_name$;\n");
141 }
142
GenerateCodecCode(io::Printer * printer)143 void WrapperFieldGenerator::GenerateCodecCode(io::Printer* printer) {
144 if (is_value_type) {
145 printer->Print(
146 variables_,
147 "pb::FieldCodec.ForStructWrapper<$nonnullable_type_name$>($tag$)");
148 } else {
149 printer->Print(
150 variables_,
151 "pb::FieldCodec.ForClassWrapper<$type_name$>($tag$)");
152 }
153 }
154
WrapperOneofFieldGenerator(const FieldDescriptor * descriptor,int fieldOrdinal,const Options * options)155 WrapperOneofFieldGenerator::WrapperOneofFieldGenerator(
156 const FieldDescriptor* descriptor, int fieldOrdinal, const Options *options)
157 : WrapperFieldGenerator(descriptor, fieldOrdinal, options) {
158 SetCommonOneofFieldVariables(&variables_);
159 }
160
~WrapperOneofFieldGenerator()161 WrapperOneofFieldGenerator::~WrapperOneofFieldGenerator() {
162 }
163
GenerateMembers(io::Printer * printer)164 void WrapperOneofFieldGenerator::GenerateMembers(io::Printer* printer) {
165 // Note: deliberately _oneof_$name$_codec, not _$oneof_name$_codec... we have one codec per field.
166 printer->Print(
167 variables_,
168 "private static readonly pb::FieldCodec<$type_name$> _oneof_$name$_codec = ");
169 GenerateCodecCode(printer);
170 printer->Print(";\n");
171 WritePropertyDocComment(printer, descriptor_);
172 AddDeprecatedFlag(printer);
173 printer->Print(
174 variables_,
175 "$access_level$ $type_name$ $property_name$ {\n"
176 " get { return $has_property_check$ ? ($type_name$) $oneof_name$_ : ($type_name$) null; }\n"
177 " set {\n"
178 " $oneof_name$_ = value;\n"
179 " $oneof_name$Case_ = value == null ? $oneof_property_name$OneofCase.None : $oneof_property_name$OneofCase.$property_name$;\n"
180 " }\n"
181 "}\n");
182 }
183
GenerateParsingCode(io::Printer * printer)184 void WrapperOneofFieldGenerator::GenerateParsingCode(io::Printer* printer) {
185 printer->Print(
186 variables_,
187 "$property_name$ = _oneof_$name$_codec.Read(input);\n");
188 }
189
GenerateSerializationCode(io::Printer * printer)190 void WrapperOneofFieldGenerator::GenerateSerializationCode(io::Printer* printer) {
191 // TODO: I suspect this is wrong...
192 printer->Print(
193 variables_,
194 "if ($has_property_check$) {\n"
195 " _oneof_$name$_codec.WriteTagAndValue(output, ($type_name$) $oneof_name$_);\n"
196 "}\n");
197 }
198
GenerateSerializedSizeCode(io::Printer * printer)199 void WrapperOneofFieldGenerator::GenerateSerializedSizeCode(io::Printer* printer) {
200 // TODO: I suspect this is wrong...
201 printer->Print(
202 variables_,
203 "if ($has_property_check$) {\n"
204 " size += _oneof_$name$_codec.CalculateSizeWithTag($property_name$);\n"
205 "}\n");
206 }
207
208 } // namespace csharp
209 } // namespace compiler
210 } // namespace protobuf
211 } // namespace google
212