-
Notifications
You must be signed in to change notification settings - Fork 59
Support C#8 NRT (Nullable Reference Types) in generated code #183
Comments
To the extent that we can generate nullable ref annotated code regardless of the rest of the project, I think we should. But emitting the So IMO this is something each individual generator should do if it wants to. A generator that does not want to participate would need to shed the |
So let's consider a couple of scenarios for C#8 projects:
I'd like to state my goals:
I honestly believe we should somehow automatically handle legacy generators, like the suggested wrapping. For new generators, I really don't know which way to go. Generators using Roslyn API get nullability annotations on types they read from source code for free, but without On the other hand, generating nullable directives on pre-C#8+ projects is also bad(errors), so we need to know LangVersion. Requiring all generators that want to support nullability to have two execution paths, one for non-nullable and the other for nullable-enabled, also sounds like a bad idea. So maybe in the framework we should manage these, by stripping annotations when necessary (pre-C#8 langver)? So many questions, so little answers. |
IMO we shouldn't try to do (much) more magic than Roslyn would be willing to do. The only mandatory goal IMO is this: Make it possible to write generators that run properly in a C# 8 world. This includes intelligently adding/removing nullable annotations while generating source code. It also includes allowing the generator to look up the nullable setting for the project and source file from which code is being generated, and any other source file it may need. An optional stretch goal is make older generators Just Work. This seems to me to likely be a bug farm. We're giving the generators the
Why do you say that? We hand the generator the |
Agreed.
Definitely, I agree. We should probably have some guidance on that, though.
Yeah, so I think you have a point. Still, reading that made me think we should really have some guidance/samples on how to write code generation that behaves well both in non-nullable and nullable projects, and take into account that the project itself may be compiled using older Roslyn in the end step (like, 2.x version). I really have no idea how to do that, or where to start.
@AArnott We're building |
my "algorithm" checks if the nullable context for the annotated class is enabled. If it is, then the nullability is respected, otherwise not. |
you can find "the" reason here https://github.com/dotnet/roslyn/blob/70e158ba6c2c99bd3c3fc0754af0dbf82a6d353d/docs/features/nullable-reference-types.md#generated-code |
@amis92 I could not yet get the pain of the situation. Referring to this issue and to your comments in PR #190.
The That gist, like the pr #190, uses SemanticModel.GetNullableContext(Int32) to retrieve the state of "nullable" at the specific position within the "source". Based on this nullable state, the generator can opt-in for the nullability with the trivia "#nullable enable". Running the
Does this information helps? |
I investigated further public class MyClass
{
public string? Get() => null;
#nullable enable
public string? Get() => null;
#nullable disable
public string GetNonNull() => null;
} Retrieving the nullable context for the first |
@manne I think the point @amis92 made earlier is relevant here: you can't rely on the Nullable attribute from the Roslyn API today because we initialize Roslyn's Compilation based on a limited understanding of what is in the project file. Therefore when your generator interrogates the Roslyn API for whether nullability is active, you might be told 'no' when the answer is 'yes' because of something in the project file that we didn't tell Roslyn about. @amis92 The best way forward is probably to pass the entire compilation command line to our task and ask Roslyn to parse it to create the Compilation. VS itself does this to initialize their language service. |
@AArnott that'd be amazing, but I have no idea how to do that. 🤷♂️ |
Our targets could invoke the Csc task, and fetch the Passing in Then you can pass that command line string to our own task/tool so that it can ask the CSharpCompilation to parse it and initialize everything. We might want to use a "response file" approach instead of passing a huge string around, particularly since Windows as limitations of how long a command line can be. |
It was brought to my attention that generating code in NRT-enabled projects raises warnings.
Reference: amis92/RecordGenerator#110
From the issue linked above:
Looks like the dotnet team decided auto-generated code needs to explicitly opt-in into nullable reference types:
In a project with
this generates without issues and is actually usable, but the following compiler warning is listed for the generated file. One warning per line that uses
?
on a reference type.What can/should we do about it? We'll definitely need to get aware of the Nullable project property. What else can we do to simplify/enable nullable generated code?
The text was updated successfully, but these errors were encountered: