diff --git a/src/google/protobuf/compiler/csharp/csharp_generator.cc b/src/google/protobuf/compiler/csharp/csharp_generator.cc index 0781cf810beb0..6418e61d395b0 100644 --- a/src/google/protobuf/compiler/csharp/csharp_generator.cc +++ b/src/google/protobuf/compiler/csharp/csharp_generator.cc @@ -59,6 +59,8 @@ bool Generator::Generate(const FileDescriptor* file, cli_options.serializable = true; } else if (options[i].first == "experimental_strip_nonfunctional_codegen") { cli_options.strip_nonfunctional_codegen = true; + } else if (options[i].first == "enable_nrt") { + cli_options.enable_nullable_reference_types = true; } else { *error = absl::StrCat("Unknown generator option: ", options[i].first); return false; diff --git a/src/google/protobuf/compiler/csharp/csharp_message.cc b/src/google/protobuf/compiler/csharp/csharp_message.cc index 9cc23761dc9f3..d5cb698e6e684 100644 --- a/src/google/protobuf/compiler/csharp/csharp_message.cc +++ b/src/google/protobuf/compiler/csharp/csharp_message.cc @@ -95,6 +95,7 @@ void MessageGenerator::Generate(io::Printer* printer) { absl::flat_hash_map vars; vars["class_name"] = class_name(); vars["access_level"] = class_access_level(); + vars["nrt_annotation"] = this->options()->enable_nullable_reference_types ? "?" : ""; WriteMessageDocComment(printer, options(), descriptor_); AddDeprecatedFlag(printer); @@ -122,7 +123,8 @@ void MessageGenerator::Generate(io::Printer* printer) { "private static readonly pb::MessageParser<$class_name$> _parser = new " "pb::MessageParser<$class_name$>(() => new $class_name$());\n"); - printer->Print("private pb::UnknownFieldSet _unknownFields;\n"); + printer->Print(vars, + "private pb::UnknownFieldSet$nrt_annotation$ _unknownFields;\n"); if (has_extension_ranges_) { if (IsDescriptorProto(descriptor_->file())) { @@ -419,16 +421,17 @@ void MessageGenerator::GenerateFreezingCode(io::Printer* printer) {} void MessageGenerator::GenerateFrameworkMethods(io::Printer* printer) { absl::flat_hash_map vars; vars["class_name"] = class_name(); + vars["nrt_annotation"] = this->options()->enable_nullable_reference_types ? "?" : ""; // Equality WriteGeneratedCodeAttributes(printer); printer->Print(vars, - "public override bool Equals(object other) {\n" + "public override bool Equals(object$nrt_annotation$ other) {\n" " return Equals(other as $class_name$);\n" "}\n\n"); WriteGeneratedCodeAttributes(printer); printer->Print(vars, - "public bool Equals($class_name$ other) {\n" + "public bool Equals($class_name$$nrt_annotation$ other) {\n" " if (ReferenceEquals(other, null)) {\n" " return false;\n" " }\n" @@ -586,9 +589,10 @@ void MessageGenerator::GenerateMergingMethods(io::Printer* printer) { // for code size. absl::flat_hash_map vars; vars["class_name"] = class_name(); + vars["nrt_annotation"] = this->options()->enable_nullable_reference_types ? "?" : ""; WriteGeneratedCodeAttributes(printer); - printer->Print(vars, "public void MergeFrom($class_name$ other) {\n"); + printer->Print(vars, "public void MergeFrom($class_name$$nrt_annotation$ other) {\n"); printer->Indent(); printer->Print( "if (other == null) {\n" diff --git a/src/google/protobuf/compiler/csharp/csharp_message_field.cc b/src/google/protobuf/compiler/csharp/csharp_message_field.cc index 165118b969f44..a2cdf8b4430d5 100644 --- a/src/google/protobuf/compiler/csharp/csharp_message_field.cc +++ b/src/google/protobuf/compiler/csharp/csharp_message_field.cc @@ -30,6 +30,7 @@ MessageFieldGenerator::MessageFieldGenerator(const FieldDescriptor* descriptor, variables_["has_property_check"] = absl::StrCat(name(), "_ != null"); variables_["has_not_property_check"] = absl::StrCat(name(), "_ == null"); } + variables_["nrt_annotation"] = this->options()->enable_nullable_reference_types ? "?" : ""; } MessageFieldGenerator::~MessageFieldGenerator() { @@ -44,7 +45,7 @@ void MessageFieldGenerator::GenerateMembers(io::Printer* printer) { AddPublicMemberAttributes(printer); printer->Print( variables_, - "$access_level$ $type_name$ $property_name$ {\n" + "$access_level$ $type_name$$nrt_annotation$ $property_name$ {\n" " get { return $name$_; }\n" " set {\n" " $name$_ = value;\n" diff --git a/src/google/protobuf/compiler/csharp/csharp_options.h b/src/google/protobuf/compiler/csharp/csharp_options.h index 4c034d53600a6..de93f90df90fe 100644 --- a/src/google/protobuf/compiler/csharp/csharp_options.h +++ b/src/google/protobuf/compiler/csharp/csharp_options.h @@ -23,7 +23,8 @@ struct Options { base_namespace_specified(false), internal_access(false), serializable(false), - strip_nonfunctional_codegen(false) {} + strip_nonfunctional_codegen(false), + enable_nullable_reference_types(false) {} // Extension of the generated file. Defaults to ".cs" std::string file_extension; // Base namespace to use to create directory hierarchy. Defaults to "". @@ -50,6 +51,9 @@ struct Options { bool serializable; // If true, strip out nonfunctional codegen. bool strip_nonfunctional_codegen; + // Whether the generated files support null reference types. + // Defaults to false + bool enable_nullable_reference_types; }; } // namespace csharp diff --git a/src/google/protobuf/compiler/csharp/csharp_reflection_class.cc b/src/google/protobuf/compiler/csharp/csharp_reflection_class.cc index 1e8d3f282558c..63e3fe6e64f49 100644 --- a/src/google/protobuf/compiler/csharp/csharp_reflection_class.cc +++ b/src/google/protobuf/compiler/csharp/csharp_reflection_class.cc @@ -105,7 +105,16 @@ void ReflectionClassGenerator::WriteIntroduction(io::Printer* printer) { "// \n" "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" "// source: $file_name$\n" - "// \n" + "// \n", + "file_name", file_->name()); + + if (this->options()->enable_nullable_reference_types) { + printer->Print( + "#nullable enable annotations\n", + "file_name", file_->name()); + } + + printer->Print( "#pragma warning disable 1591, 0612, 3021, 8981\n" "#region Designer generated code\n" "\n"