Skip to content

C#: add option and code generation for null reference types #16240

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/google/protobuf/compiler/csharp/csharp_generator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
12 changes: 8 additions & 4 deletions src/google/protobuf/compiler/csharp/csharp_message.cc
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ void MessageGenerator::Generate(io::Printer* printer) {
absl::flat_hash_map<absl::string_view, std::string> 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);
Expand Down Expand Up @@ -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())) {
Expand Down Expand Up @@ -419,16 +421,17 @@ void MessageGenerator::GenerateFreezingCode(io::Printer* printer) {}
void MessageGenerator::GenerateFrameworkMethods(io::Printer* printer) {
absl::flat_hash_map<absl::string_view, std::string> 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"
Expand Down Expand Up @@ -586,9 +589,10 @@ void MessageGenerator::GenerateMergingMethods(io::Printer* printer) {
// for code size.
absl::flat_hash_map<absl::string_view, std::string> 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"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand All @@ -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"
Expand Down
6 changes: 5 additions & 1 deletion src/google/protobuf/compiler/csharp/csharp_options.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 "".
Expand All @@ -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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: extra space at start (could fix after merging).

// Defaults to false
bool enable_nullable_reference_types;
};

} // namespace csharp
Expand Down
11 changes: 10 additions & 1 deletion src/google/protobuf/compiler/csharp/csharp_reflection_class.cc
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,16 @@ void ReflectionClassGenerator::WriteIntroduction(io::Printer* printer) {
"// <auto-generated>\n"
"// Generated by the protocol buffer compiler. DO NOT EDIT!\n"
"// source: $file_name$\n"
"// </auto-generated>\n"
"// </auto-generated>\n",
"file_name", file_->name());

if (this->options()->enable_nullable_reference_types) {
printer->Print(
"#nullable enable annotations\n",
"file_name", file_->name());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need this line, as we're not using the file_name variable anywhere. (It doesn't do any harm though, so we could merge and then fix.)

}

printer->Print(
"#pragma warning disable 1591, 0612, 3021, 8981\n"
"#region Designer generated code\n"
"\n"
Expand Down
Loading