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#include <google/protobuf/stubs/strutil.h>
40
41#include <google/protobuf/compiler/csharp/csharp_doc_comment.h>
42#include <google/protobuf/compiler/csharp/csharp_helpers.h>
43#include <google/protobuf/compiler/csharp/csharp_options.h>
44#include <google/protobuf/compiler/csharp/csharp_primitive_field.h>
45
46namespace google {
47namespace protobuf {
48namespace compiler {
49namespace csharp {
50
51PrimitiveFieldGenerator::PrimitiveFieldGenerator(
52    const FieldDescriptor* descriptor, int fieldOrdinal, const Options *options)
53    : FieldGeneratorBase(descriptor, fieldOrdinal, options) {
54  // TODO(jonskeet): Make this cleaner...
55  is_value_type = descriptor->type() != FieldDescriptor::TYPE_STRING
56      && descriptor->type() != FieldDescriptor::TYPE_BYTES;
57  if (!is_value_type) {
58    variables_["has_property_check"] = variables_["property_name"] + ".Length != 0";
59    variables_["other_has_property_check"] = "other." + variables_["property_name"] + ".Length != 0";
60  }
61}
62
63PrimitiveFieldGenerator::~PrimitiveFieldGenerator() {
64}
65
66void PrimitiveFieldGenerator::GenerateMembers(io::Printer* printer) {
67  // TODO(jonskeet): Work out whether we want to prevent the fields from ever being
68  // null, or whether we just handle it, in the cases of bytes and string.
69  // (Basically, should null-handling code be in the getter or the setter?)
70  printer->Print(
71    variables_,
72    "private $type_name$ $name_def_message$;\n");
73  WritePropertyDocComment(printer, descriptor_);
74  AddDeprecatedFlag(printer);
75  printer->Print(
76    variables_,
77    "$access_level$ $type_name$ $property_name$ {\n"
78    "  get { return $name$_; }\n"
79    "  set {\n");
80  if (is_value_type) {
81    printer->Print(
82      variables_,
83      "    $name$_ = value;\n");
84  } else {
85    printer->Print(
86      variables_,
87      "    $name$_ = pb::ProtoPreconditions.CheckNotNull(value, \"value\");\n");
88  }
89  printer->Print(
90    "  }\n"
91    "}\n");
92}
93
94void PrimitiveFieldGenerator::GenerateMergingCode(io::Printer* printer) {
95  printer->Print(
96    variables_,
97    "if ($other_has_property_check$) {\n"
98    "  $property_name$ = other.$property_name$;\n"
99    "}\n");
100}
101
102void PrimitiveFieldGenerator::GenerateParsingCode(io::Printer* printer) {
103  // Note: invoke the property setter rather than writing straight to the field,
104  // so that we can normalize "null to empty" for strings and bytes.
105  printer->Print(
106    variables_,
107    "$property_name$ = input.Read$capitalized_type_name$();\n");
108}
109
110void PrimitiveFieldGenerator::GenerateSerializationCode(io::Printer* printer) {
111  printer->Print(
112    variables_,
113    "if ($has_property_check$) {\n"
114    "  output.WriteRawTag($tag_bytes$);\n"
115    "  output.Write$capitalized_type_name$($property_name$);\n"
116    "}\n");
117}
118
119void PrimitiveFieldGenerator::GenerateSerializedSizeCode(io::Printer* printer) {
120  printer->Print(
121    variables_,
122    "if ($has_property_check$) {\n");
123  printer->Indent();
124  int fixedSize = GetFixedSize(descriptor_->type());
125  if (fixedSize == -1) {
126    printer->Print(
127      variables_,
128      "size += $tag_size$ + pb::CodedOutputStream.Compute$capitalized_type_name$Size($property_name$);\n");
129  } else {
130    printer->Print(
131      "size += $tag_size$ + $fixed_size$;\n",
132      "fixed_size", SimpleItoa(fixedSize),
133      "tag_size", variables_["tag_size"]);
134  }
135  printer->Outdent();
136  printer->Print("}\n");
137}
138
139void PrimitiveFieldGenerator::WriteHash(io::Printer* printer) {
140  printer->Print(
141    variables_,
142    "if ($has_property_check$) hash ^= $property_name$.GetHashCode();\n");
143}
144void PrimitiveFieldGenerator::WriteEquals(io::Printer* printer) {
145  printer->Print(
146    variables_,
147    "if ($property_name$ != other.$property_name$) return false;\n");
148}
149void PrimitiveFieldGenerator::WriteToString(io::Printer* printer) {
150  printer->Print(
151    variables_,
152    "PrintField(\"$descriptor_name$\", $has_property_check$, $property_name$, writer);\n");
153}
154
155void PrimitiveFieldGenerator::GenerateCloningCode(io::Printer* printer) {
156  printer->Print(variables_,
157    "$name$_ = other.$name$_;\n");
158}
159
160void PrimitiveFieldGenerator::GenerateCodecCode(io::Printer* printer) {
161  printer->Print(
162    variables_,
163    "pb::FieldCodec.For$capitalized_type_name$($tag$)");
164}
165
166PrimitiveOneofFieldGenerator::PrimitiveOneofFieldGenerator(
167    const FieldDescriptor* descriptor, int fieldOrdinal, const Options *options)
168    : PrimitiveFieldGenerator(descriptor, fieldOrdinal, options) {
169  SetCommonOneofFieldVariables(&variables_);
170}
171
172PrimitiveOneofFieldGenerator::~PrimitiveOneofFieldGenerator() {
173}
174
175void PrimitiveOneofFieldGenerator::GenerateMembers(io::Printer* printer) {
176  WritePropertyDocComment(printer, descriptor_);
177  AddDeprecatedFlag(printer);
178  printer->Print(
179    variables_,
180    "$access_level$ $type_name$ $property_name$ {\n"
181    "  get { return $has_property_check$ ? ($type_name$) $oneof_name$_ : $default_value$; }\n"
182    "  set {\n");
183    if (is_value_type) {
184      printer->Print(
185        variables_,
186        "    $oneof_name$_ = value;\n");
187    } else {
188      printer->Print(
189        variables_,
190        "    $oneof_name$_ = pb::ProtoPreconditions.CheckNotNull(value, \"value\");\n");
191    }
192    printer->Print(
193      variables_,
194      "    $oneof_name$Case_ = $oneof_property_name$OneofCase.$property_name$;\n"
195      "  }\n"
196      "}\n");
197}
198
199void PrimitiveOneofFieldGenerator::WriteToString(io::Printer* printer) {
200  printer->Print(variables_,
201    "PrintField(\"$descriptor_name$\", $has_property_check$, $oneof_name$_, writer);\n");
202}
203
204void PrimitiveOneofFieldGenerator::GenerateParsingCode(io::Printer* printer) {
205    printer->Print(
206      variables_,
207      "$property_name$ = input.Read$capitalized_type_name$();\n");
208}
209
210void PrimitiveOneofFieldGenerator::GenerateCloningCode(io::Printer* printer) {
211  printer->Print(variables_,
212    "$property_name$ = other.$property_name$;\n");
213}
214
215}  // namespace csharp
216}  // namespace compiler
217}  // namespace protobuf
218}  // namespace google
219