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

Conversation

tonydnewell
Copy link
Contributor

This replaces the closed PR #13218

It adds an option for generating C# code that handles null reference types.
See https://github.com/grpc/proposal/blob/master/L110-csharp-nullable-reference-types.md

Further work could be done to:

  • add tests to check the generated code is as expected - there doesn't appear to be these kind of tests for other code generation
  • change #nullable enable annotations to #nullable enable - but this requires further codegen changes
    • to annotate handling calling the Google.Protobuf.Reflection API that doesn't yet handle null reference types
    • to handle types such as string and bytes that use null to indicate presence

@tonydnewell
Copy link
Contributor Author

The code generated by this PR may be good enough - however to be able to change #nullable enable annotations to #nullable enable the following needs to be addressed:

  • Calling Google.Protobuf.Reflection.GeneratedClrTypeInfo()
    GeneratedClrTypeInfo() doesn’t support NRT, thus need to add null forgiving operator in some calls: e.g. new pbr::GeneratedClrTypeInfo[] { !null, }

  • Checking for null in message fields uses the field name for the check but the property name to get the value
    e.g. in the generated GetHashCode() this idiom is used: if (someMessge_ != null) hash ^= SomeMessage.GetHashCode();
    Similar in MergeFrom().

  • Optional message, string, and bytes fields need to be declared as nullable otherwise the constructor won't compile

  • oneof fields need to be declared nullable
    code accessing those fields needs to be annotated or errors suppressed, e.g.

    public int OneInt {
      get { return HasOneInt ? (int) myOneofField_ : 0; } // Error CS8605 unboxing null value
      set {
        myOneofField_ = value;
        myOneofFieldCase_ = MyOneofFieldOneofCase.OneInt;
      }
    }

@tonydnewell tonydnewell marked this pull request as ready for review June 24, 2024 09:27
@tonydnewell tonydnewell requested a review from a team as a code owner June 24, 2024 09:27
@tonydnewell tonydnewell requested review from jskeet and removed request for a team June 24, 2024 09:27
@JasonLunn JasonLunn added c# wait for user action 🅰️ safe for tests Mark a commit as safe to run presubmits over labels Oct 10, 2024
@github-actions github-actions bot removed the 🅰️ safe for tests Mark a commit as safe to run presubmits over label Oct 10, 2024
@jskeet
Copy link
Contributor

jskeet commented Oct 11, 2024

@tonydnewell Sorry for not reviewing this for a while - is this now done and complete, ready for review and possible merging?

@tonydnewell
Copy link
Contributor Author

@tonydnewell Sorry for not reviewing this for a while - is this now done and complete, ready for review and possible merging?

It is ready. However my contract has now ended so I'll only be able to fix any problems on an ad hoc basis.

@jskeet
Copy link
Contributor

jskeet commented Oct 14, 2024

@tonydnewell Sorry for not reviewing this for a while - is this now done and complete, ready for review and possible merging?

It is ready. However my contract has now ended so I'll only be able to fix any problems on an ad hoc basis.

Righto - if I spot anything, I could quite possibly fix it myself instead. Will attempt to find headspace to review this soon. Thanks!

@jskeet
Copy link
Contributor

jskeet commented Oct 14, 2024

(It's actually much shorter than I'd have expected, so it might not be too hard to review after all...)

Copy link
Contributor

@jskeet jskeet left a comment

Choose a reason for hiding this comment

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

I think this looks mostly fine - but I don't see anything to handle the wrapper types for string and ByteString. I think those properties would need to be nullable as well.

@tonydnewell is that a change you think you'd be able to get to in spare time, or would you like me to try to get this merged and then do a fast-follow change for that?

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.)

@@ -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).

@Falco20019
Copy link
Contributor

@tonydnewell Is there anything I can do to help get traction on this?

@jskeet
Copy link
Contributor

jskeet commented Jan 16, 2025

I suspect the next step is mine - it's a matter of finding the time.

@Falco20019
Copy link
Contributor

Falco20019 commented Feb 6, 2025

@JasonLunn I think we can close this one in favor of the extended one. If you want to keep it until the other is handled, I added close-keywords to my PR instead :)

@JasonLunn
Copy link
Contributor

@JasonLunn I think we can close this one in favor of the extended one. If you want to keep it until the other is handled, I added close-keywords to my PR instead :)

Yes let's keep this one open until the other merges.

@JasonLunn
Copy link
Contributor

Marking this blocked until we make a decision on #20242

copybara-service bot pushed a commit that referenced this pull request Mar 4, 2025
This replaces the abandoned #16240 and should address the open points mentioned.

This will fix #6632 and close #16240

Closes #20242

COPYBARA_INTEGRATE_REVIEW=#20242 from Falco20019:csharp-nrt-option 538f02f
FUTURE_COPYBARA_INTEGRATE_REVIEW=#20242 from Falco20019:csharp-nrt-option 538f02f
PiperOrigin-RevId: 733464986
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants