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
45namespace google {
46namespace protobuf {
47namespace compiler {
48namespace csharp {
49
50WrapperFieldGenerator::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
63WrapperFieldGenerator::~WrapperFieldGenerator() {
64}
65
66void 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
87void 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
97void 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
106void 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
114void 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
122void WrapperFieldGenerator::WriteHash(io::Printer* printer) {
123  printer->Print(
124    variables_,
125    "if ($has_property_check$) hash ^= $property_name$.GetHashCode();\n");
126}
127
128void WrapperFieldGenerator::WriteEquals(io::Printer* printer) {
129  printer->Print(
130    variables_,
131    "if ($property_name$ != other.$property_name$) return false;\n");
132}
133
134void WrapperFieldGenerator::WriteToString(io::Printer* printer) {
135  // TODO: Implement if we ever actually need it...
136}
137
138void WrapperFieldGenerator::GenerateCloningCode(io::Printer* printer) {
139  printer->Print(variables_,
140    "$property_name$ = other.$property_name$;\n");
141}
142
143void 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
155WrapperOneofFieldGenerator::WrapperOneofFieldGenerator(
156    const FieldDescriptor* descriptor, int fieldOrdinal, const Options *options)
157    : WrapperFieldGenerator(descriptor, fieldOrdinal, options) {
158    SetCommonOneofFieldVariables(&variables_);
159}
160
161WrapperOneofFieldGenerator::~WrapperOneofFieldGenerator() {
162}
163
164void 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
184void WrapperOneofFieldGenerator::GenerateParsingCode(io::Printer* printer) {
185  printer->Print(
186    variables_,
187    "$property_name$ = _oneof_$name$_codec.Read(input);\n");
188}
189
190void 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
199void 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