| 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 | |
| 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_primitive_field.h> |
| 44 | |
| 45 | namespace google { |
| 46 | namespace protobuf { |
| 47 | namespace compiler { |
| 48 | namespace csharp { |
| 49 | |
| 50 | PrimitiveFieldGenerator::PrimitiveFieldGenerator( |
| 51 | const FieldDescriptor* descriptor, int presenceIndex, const Options *options) |
| 52 | : FieldGeneratorBase(descriptor, presenceIndex, options) { |
| 53 | // TODO(jonskeet): Make this cleaner... |
| 54 | is_value_type = descriptor->type() != FieldDescriptor::TYPE_STRING |
| 55 | && descriptor->type() != FieldDescriptor::TYPE_BYTES; |
| 56 | if (!is_value_type && !SupportsPresenceApi(descriptor: descriptor_)) { |
| 57 | variables_["has_property_check" ] = variables_["property_name" ] + ".Length != 0" ; |
| 58 | variables_["other_has_property_check" ] = "other." + variables_["property_name" ] + ".Length != 0" ; |
| 59 | } |
| 60 | } |
| 61 | |
| 62 | PrimitiveFieldGenerator::~PrimitiveFieldGenerator() { |
| 63 | } |
| 64 | |
| 65 | void PrimitiveFieldGenerator::GenerateMembers(io::Printer* printer) { |
| 66 | |
| 67 | // Note: in multiple places, this code assumes that all fields |
| 68 | // that support presence are either nullable, or use a presence field bit. |
| 69 | // Fields which are oneof members are not generated here; they're generated in PrimitiveOneofFieldGenerator below. |
| 70 | // Extensions are not generated here either. |
| 71 | |
| 72 | |
| 73 | // Proto2 allows different default values to be specified. These are retained |
| 74 | // via static fields. They don't particularly need to be, but we don't need |
| 75 | // to change that. In Proto3 the default value we don't generate these |
| 76 | // fields, just using the literal instead. |
| 77 | if (IsProto2(descriptor: descriptor_->file())) { |
| 78 | // Note: "private readonly static" isn't as idiomatic as |
| 79 | // "private static readonly", but changing this now would create a lot of |
| 80 | // churn in generated code with near-to-zero benefit. |
| 81 | printer->Print( |
| 82 | variables: variables_, |
| 83 | text: "private readonly static $type_name$ $property_name$DefaultValue = $default_value$;\n\n" ); |
| 84 | variables_["default_value_access" ] = |
| 85 | variables_["property_name" ] + "DefaultValue" ; |
| 86 | } else { |
| 87 | variables_["default_value_access" ] = variables_["default_value" ]; |
| 88 | } |
| 89 | |
| 90 | // Declare the field itself. |
| 91 | printer->Print( |
| 92 | variables: variables_, |
| 93 | text: "private $type_name$ $name_def_message$;\n" ); |
| 94 | |
| 95 | WritePropertyDocComment(printer, field: descriptor_); |
| 96 | AddPublicMemberAttributes(printer); |
| 97 | |
| 98 | // Most of the work is done in the property: |
| 99 | // Declare the property itself (the same for all options) |
| 100 | printer->Print(variables: variables_, text: "$access_level$ $type_name$ $property_name$ {\n" ); |
| 101 | |
| 102 | // Specify the "getter", which may need to check for a presence field. |
| 103 | if (SupportsPresenceApi(descriptor: descriptor_)) { |
| 104 | if (IsNullable(descriptor: descriptor_)) { |
| 105 | printer->Print( |
| 106 | variables: variables_, |
| 107 | text: " get { return $name$_ ?? $default_value_access$; }\n" ); |
| 108 | } else { |
| 109 | printer->Print( |
| 110 | variables: variables_, |
| 111 | // Note: it's possible that this could be rewritten as a |
| 112 | // conditional ?: expression, but there's no significant benefit |
| 113 | // to changing it. |
| 114 | text: " get { if ($has_field_check$) { return $name$_; } else { return $default_value_access$; } }\n" ); |
| 115 | } |
| 116 | } else { |
| 117 | printer->Print( |
| 118 | variables: variables_, |
| 119 | text: " get { return $name$_; }\n" ); |
| 120 | } |
| 121 | |
| 122 | // Specify the "setter", which may need to set a field bit as well as the |
| 123 | // value. |
| 124 | printer->Print(text: " set {\n" ); |
| 125 | if (presenceIndex_ != -1) { |
| 126 | printer->Print( |
| 127 | variables: variables_, |
| 128 | text: " $set_has_field$;\n" ); |
| 129 | } |
| 130 | if (is_value_type) { |
| 131 | printer->Print( |
| 132 | variables: variables_, |
| 133 | text: " $name$_ = value;\n" ); |
| 134 | } else { |
| 135 | printer->Print( |
| 136 | variables: variables_, |
| 137 | text: " $name$_ = pb::ProtoPreconditions.CheckNotNull(value, \"value\");\n" ); |
| 138 | } |
| 139 | printer->Print( |
| 140 | text: " }\n" |
| 141 | "}\n" ); |
| 142 | |
| 143 | // The "HasFoo" property, where required. |
| 144 | if (SupportsPresenceApi(descriptor: descriptor_)) { |
| 145 | printer->Print(variables: variables_, |
| 146 | text: "/// <summary>Gets whether the \"$descriptor_name$\" field is set</summary>\n" ); |
| 147 | AddPublicMemberAttributes(printer); |
| 148 | printer->Print( |
| 149 | variables: variables_, |
| 150 | text: "$access_level$ bool Has$property_name$ {\n" |
| 151 | " get { return " ); |
| 152 | if (IsNullable(descriptor: descriptor_)) { |
| 153 | printer->Print( |
| 154 | variables: variables_, |
| 155 | text: "$name$_ != null; }\n}\n" ); |
| 156 | } else { |
| 157 | printer->Print( |
| 158 | variables: variables_, |
| 159 | text: "$has_field_check$; }\n}\n" ); |
| 160 | } |
| 161 | } |
| 162 | |
| 163 | // The "ClearFoo" method, where required. |
| 164 | if (SupportsPresenceApi(descriptor: descriptor_)) { |
| 165 | printer->Print(variables: variables_, |
| 166 | text: "/// <summary>Clears the value of the \"$descriptor_name$\" field</summary>\n" ); |
| 167 | AddPublicMemberAttributes(printer); |
| 168 | printer->Print( |
| 169 | variables: variables_, |
| 170 | text: "$access_level$ void Clear$property_name$() {\n" ); |
| 171 | if (IsNullable(descriptor: descriptor_)) { |
| 172 | printer->Print(variables: variables_, text: " $name$_ = null;\n" ); |
| 173 | } else { |
| 174 | printer->Print(variables: variables_, text: " $clear_has_field$;\n" ); |
| 175 | } |
| 176 | printer->Print(text: "}\n" ); |
| 177 | } |
| 178 | } |
| 179 | |
| 180 | void PrimitiveFieldGenerator::GenerateMergingCode(io::Printer* printer) { |
| 181 | printer->Print( |
| 182 | variables: variables_, |
| 183 | text: "if ($other_has_property_check$) {\n" |
| 184 | " $property_name$ = other.$property_name$;\n" |
| 185 | "}\n" ); |
| 186 | } |
| 187 | |
| 188 | void PrimitiveFieldGenerator::GenerateParsingCode(io::Printer* printer) { |
| 189 | // Note: invoke the property setter rather than writing straight to the field, |
| 190 | // so that we can normalize "null to empty" for strings and bytes. |
| 191 | printer->Print( |
| 192 | variables: variables_, |
| 193 | text: "$property_name$ = input.Read$capitalized_type_name$();\n" ); |
| 194 | } |
| 195 | |
| 196 | void PrimitiveFieldGenerator::GenerateSerializationCode(io::Printer* printer) { |
| 197 | printer->Print( |
| 198 | variables: variables_, |
| 199 | text: "if ($has_property_check$) {\n" |
| 200 | " output.WriteRawTag($tag_bytes$);\n" |
| 201 | " output.Write$capitalized_type_name$($property_name$);\n" |
| 202 | "}\n" ); |
| 203 | } |
| 204 | |
| 205 | void PrimitiveFieldGenerator::GenerateSerializedSizeCode(io::Printer* printer) { |
| 206 | printer->Print( |
| 207 | variables: variables_, |
| 208 | text: "if ($has_property_check$) {\n" ); |
| 209 | printer->Indent(); |
| 210 | int fixedSize = GetFixedSize(type: descriptor_->type()); |
| 211 | if (fixedSize == -1) { |
| 212 | printer->Print( |
| 213 | variables: variables_, |
| 214 | text: "size += $tag_size$ + pb::CodedOutputStream.Compute$capitalized_type_name$Size($property_name$);\n" ); |
| 215 | } else { |
| 216 | printer->Print( |
| 217 | text: "size += $tag_size$ + $fixed_size$;\n" , |
| 218 | args: "fixed_size" , args: StrCat(a: fixedSize), |
| 219 | args: "tag_size" , args: variables_["tag_size" ]); |
| 220 | } |
| 221 | printer->Outdent(); |
| 222 | printer->Print(text: "}\n" ); |
| 223 | } |
| 224 | |
| 225 | void PrimitiveFieldGenerator::WriteHash(io::Printer* printer) { |
| 226 | const char *text = "if ($has_property_check$) hash ^= $property_name$.GetHashCode();\n" ; |
| 227 | if (descriptor_->type() == FieldDescriptor::TYPE_FLOAT) { |
| 228 | text = "if ($has_property_check$) hash ^= pbc::ProtobufEqualityComparers.BitwiseSingleEqualityComparer.GetHashCode($property_name$);\n" ; |
| 229 | } else if (descriptor_->type() == FieldDescriptor::TYPE_DOUBLE) { |
| 230 | text = "if ($has_property_check$) hash ^= pbc::ProtobufEqualityComparers.BitwiseDoubleEqualityComparer.GetHashCode($property_name$);\n" ; |
| 231 | } |
| 232 | printer->Print(variables: variables_, text); |
| 233 | } |
| 234 | void PrimitiveFieldGenerator::WriteEquals(io::Printer* printer) { |
| 235 | const char *text = "if ($property_name$ != other.$property_name$) return false;\n" ; |
| 236 | if (descriptor_->type() == FieldDescriptor::TYPE_FLOAT) { |
| 237 | text = "if (!pbc::ProtobufEqualityComparers.BitwiseSingleEqualityComparer.Equals($property_name$, other.$property_name$)) return false;\n" ; |
| 238 | } else if (descriptor_->type() == FieldDescriptor::TYPE_DOUBLE) { |
| 239 | text = "if (!pbc::ProtobufEqualityComparers.BitwiseDoubleEqualityComparer.Equals($property_name$, other.$property_name$)) return false;\n" ; |
| 240 | } |
| 241 | printer->Print(variables: variables_, text); |
| 242 | } |
| 243 | void PrimitiveFieldGenerator::WriteToString(io::Printer* printer) { |
| 244 | printer->Print( |
| 245 | variables: variables_, |
| 246 | text: "PrintField(\"$descriptor_name$\", $has_property_check$, $property_name$, writer);\n" ); |
| 247 | } |
| 248 | |
| 249 | void PrimitiveFieldGenerator::GenerateCloningCode(io::Printer* printer) { |
| 250 | printer->Print(variables: variables_, |
| 251 | text: "$name$_ = other.$name$_;\n" ); |
| 252 | } |
| 253 | |
| 254 | void PrimitiveFieldGenerator::GenerateCodecCode(io::Printer* printer) { |
| 255 | printer->Print( |
| 256 | variables: variables_, |
| 257 | text: "pb::FieldCodec.For$capitalized_type_name$($tag$, $default_value$)" ); |
| 258 | } |
| 259 | |
| 260 | void PrimitiveFieldGenerator::GenerateExtensionCode(io::Printer* printer) { |
| 261 | WritePropertyDocComment(printer, field: descriptor_); |
| 262 | AddDeprecatedFlag(printer); |
| 263 | printer->Print( |
| 264 | variables: variables_, |
| 265 | text: "$access_level$ static readonly pb::Extension<$extended_type$, $type_name$> $property_name$ =\n" |
| 266 | " new pb::Extension<$extended_type$, $type_name$>($number$, " ); |
| 267 | GenerateCodecCode(printer); |
| 268 | printer->Print(text: ");\n" ); |
| 269 | } |
| 270 | |
| 271 | PrimitiveOneofFieldGenerator::PrimitiveOneofFieldGenerator( |
| 272 | const FieldDescriptor* descriptor, int presenceIndex, const Options *options) |
| 273 | : PrimitiveFieldGenerator(descriptor, presenceIndex, options) { |
| 274 | SetCommonOneofFieldVariables(&variables_); |
| 275 | } |
| 276 | |
| 277 | PrimitiveOneofFieldGenerator::~PrimitiveOneofFieldGenerator() { |
| 278 | } |
| 279 | |
| 280 | void PrimitiveOneofFieldGenerator::GenerateMembers(io::Printer* printer) { |
| 281 | WritePropertyDocComment(printer, field: descriptor_); |
| 282 | AddPublicMemberAttributes(printer); |
| 283 | printer->Print( |
| 284 | variables: variables_, |
| 285 | text: "$access_level$ $type_name$ $property_name$ {\n" |
| 286 | " get { return $has_property_check$ ? ($type_name$) $oneof_name$_ : $default_value$; }\n" |
| 287 | " set {\n" ); |
| 288 | if (is_value_type) { |
| 289 | printer->Print( |
| 290 | variables: variables_, |
| 291 | text: " $oneof_name$_ = value;\n" ); |
| 292 | } else { |
| 293 | printer->Print( |
| 294 | variables: variables_, |
| 295 | text: " $oneof_name$_ = pb::ProtoPreconditions.CheckNotNull(value, \"value\");\n" ); |
| 296 | } |
| 297 | printer->Print( |
| 298 | variables: variables_, |
| 299 | text: " $oneof_name$Case_ = $oneof_property_name$OneofCase.$oneof_case_name$;\n" |
| 300 | " }\n" |
| 301 | "}\n" ); |
| 302 | if (SupportsPresenceApi(descriptor: descriptor_)) { |
| 303 | printer->Print( |
| 304 | variables: variables_, |
| 305 | text: "/// <summary>Gets whether the \"$descriptor_name$\" field is set</summary>\n" ); |
| 306 | AddPublicMemberAttributes(printer); |
| 307 | printer->Print( |
| 308 | variables: variables_, |
| 309 | text: "$access_level$ bool Has$property_name$ {\n" |
| 310 | " get { return $oneof_name$Case_ == $oneof_property_name$OneofCase.$oneof_case_name$; }\n" |
| 311 | "}\n" ); |
| 312 | printer->Print( |
| 313 | variables: variables_, |
| 314 | text: "/// <summary> Clears the value of the oneof if it's currently set to \"$descriptor_name$\" </summary>\n" ); |
| 315 | AddPublicMemberAttributes(printer); |
| 316 | printer->Print( |
| 317 | variables: variables_, |
| 318 | text: "$access_level$ void Clear$property_name$() {\n" |
| 319 | " if ($has_property_check$) {\n" |
| 320 | " Clear$oneof_property_name$();\n" |
| 321 | " }\n" |
| 322 | "}\n" ); |
| 323 | } |
| 324 | } |
| 325 | |
| 326 | void PrimitiveOneofFieldGenerator::GenerateMergingCode(io::Printer* printer) { |
| 327 | printer->Print(variables: variables_, text: "$property_name$ = other.$property_name$;\n" ); |
| 328 | } |
| 329 | |
| 330 | void PrimitiveOneofFieldGenerator::WriteToString(io::Printer* printer) { |
| 331 | printer->Print(variables: variables_, |
| 332 | text: "PrintField(\"$descriptor_name$\", $has_property_check$, $oneof_name$_, writer);\n" ); |
| 333 | } |
| 334 | |
| 335 | void PrimitiveOneofFieldGenerator::GenerateParsingCode(io::Printer* printer) { |
| 336 | printer->Print( |
| 337 | variables: variables_, |
| 338 | text: "$property_name$ = input.Read$capitalized_type_name$();\n" ); |
| 339 | } |
| 340 | |
| 341 | void PrimitiveOneofFieldGenerator::GenerateCloningCode(io::Printer* printer) { |
| 342 | printer->Print(variables: variables_, |
| 343 | text: "$property_name$ = other.$property_name$;\n" ); |
| 344 | } |
| 345 | |
| 346 | } // namespace csharp |
| 347 | } // namespace compiler |
| 348 | } // namespace protobuf |
| 349 | } // namespace google |
| 350 | |