Skip to content

Create AddNonNullTypes code fixer#30098

Closed
jcouv wants to merge 7 commits intodotnet:features/NullableReferenceTypesfrom
jcouv:add-nnt
Closed

Create AddNonNullTypes code fixer#30098
jcouv wants to merge 7 commits intodotnet:features/NullableReferenceTypesfrom
jcouv:add-nnt

Conversation

@jcouv
Copy link
Member

@jcouv jcouv commented Sep 22, 2018

This is a first take. The goal is to give users a convenient path into nullable feature (start using nullable-related syntax, we offer to turn the feature on).

image

Some things that are not handled yet:

  • if you already have [NonNullTypes(false)] then we should flip it to true instead
  • we should also offer to add [module: NonNullTypes] (but we'll need to decide which file to put it in, or whether to inject it via msbuild/GenerateAssemblyInfo instead)
  • should we add using System.Runtime.CompilerServices; instead?

(Filed follow-up issue #30099)

@jcouv jcouv added Area-IDE PR For Personal Review Only The PR doesn’t require anyone other than the developer to review it. Feature - Nullable Reference Types Nullable Reference Types labels Sep 22, 2018
@jcouv jcouv added this to the 16.0 milestone Sep 22, 2018
@jcouv jcouv self-assigned this Sep 22, 2018
@jcouv jcouv requested a review from a team as a code owner September 22, 2018 05:16
@jcouv jcouv force-pushed the add-nnt branch 2 times, most recently from ef2dcad to 0d8d37e Compare September 22, 2018 15:45
Copy link
Contributor

@Therzok Therzok Sep 22, 2018

Choose a reason for hiding this comment

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

Typo'ed NonNull #Resolved

Copy link
Member Author

@jcouv jcouv Sep 22, 2018

Choose a reason for hiding this comment

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

Thanks! Fixed #Resolved

Copy link
Contributor

@CyrusNajmabadi CyrusNajmabadi Sep 22, 2018

Choose a reason for hiding this comment

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

why not? #Closed

Copy link
Member Author

@jcouv jcouv Sep 22, 2018

Choose a reason for hiding this comment

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

I don't think that's very useful. Most likely you should use a module-level attribute instead for such cases.
Also, I suspect it's not trivial to implement properly.
The cost/benefit combination makes it low priority at the moment (we're trying to address blockers before preview 1). #Closed

Copy link
Contributor

@CyrusNajmabadi CyrusNajmabadi Sep 22, 2018

Choose a reason for hiding this comment

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

I'll leave it to you to decide the right design. However:

Also, I suspect it's not trivial to implement properly.

This should be very trivial. Basically, you derive from SyntaxEditorBasedCodeFixProvider, and implement FixAll. Your fixall will wlak all your diagnostics and get the unique set of TypeDecls to fix. Then it will just walk all of those and add attributes like you do today.

#Closed

Copy link
Member Author

@jcouv jcouv Sep 22, 2018

Choose a reason for hiding this comment

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

Yes, that'd be the core, but what about FixAll across documents (partial type scenarios)?
SyntaxEditorBasedCodeFixProvider seems to work on a document basis. #Closed

Copy link
Contributor

@CyrusNajmabadi CyrusNajmabadi Sep 22, 2018

Choose a reason for hiding this comment

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

Hrmm... i'm a bit skeptical that that's an important enough scenario to care about. It seems fine to just place the attribute on the differnet parts :)

That said, if this is important enogh for you, an easy fix is to simply pass along the FixAllState object (or the FixAllScope) with SyntaxEditorBasedFixAllProvider.FixAllAsync. Then, if it's not 'document' you simply only fix the TypeDecl if it is considered the 'first part' of the partial type. #Closed

Copy link
Member Author

@jcouv jcouv Sep 24, 2018

Choose a reason for hiding this comment

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

If we went with the brute force approach, the fixer would produce errors in cases involving partial types (the attribute can't be specified multiple times).

If we try a more tricky approach, I'm concerned that we would produce fewer attributes than required to fix the warnings: the scenario is that you have a partial class where the 'first part' doesn't involve any nullable notations (thus no warnings), and some other part does.
Maybe there is a way to share state across documents when doing such a FixAll? That would solve the problem.

Just to give options labels:

  1. no FixAll
  2. brute-force FixAll (per document, handle type nesting)
  3. partial-aware FixAll (prefer 'first part', per document, handle type nesting)
  4. cross-document FixAll #Closed

Copy link
Contributor

@CyrusNajmabadi CyrusNajmabadi Sep 24, 2018

Choose a reason for hiding this comment

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

Or just fix this part:

(the attribute can't be specified multiple times).

I personally get super frustrated with these types of attributes because now i have to deal with that :) #Closed

Copy link
Contributor

@CyrusNajmabadi CyrusNajmabadi Sep 24, 2018

Choose a reason for hiding this comment

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

the scenario is that you have a partial class where the 'first part' doesn't involve any nullable notations (thus no warnings), and some other part does.

Gotcha. An interesting case to be sure. It does feel like we could expose a more flexibly entrypoint in SyntaxEditorBasedCodeFixProvider. One where you got to handle all the diagnostics at once, instead of us handling each document one at a time, having you only fixup that document. #Closed

Copy link
Contributor

@CyrusNajmabadi CyrusNajmabadi Sep 22, 2018

Choose a reason for hiding this comment

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

this keeps syntax trees alive. preferable to not do that. #Closed

Copy link
Member Author

@jcouv jcouv Sep 22, 2018

Choose a reason for hiding this comment

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

Fixed. Also fixed HideBase which I had modeled after. #Closed

@jcouv jcouv removed the PR For Personal Review Only The PR doesn’t require anyone other than the developer to review it. label Sep 22, 2018
@jcouv
Copy link
Member Author

jcouv commented Sep 24, 2018

@dotnet/roslyn-ide for review. Thanks #Resolved

1 similar comment
@jcouv
Copy link
Member Author

jcouv commented Sep 26, 2018

@dotnet/roslyn-ide for review. Thanks #Resolved

@jcouv
Copy link
Member Author

jcouv commented Sep 28, 2018

@dotnet/roslyn-ide for review (simple fixer). Thanks #Resolved

Copy link
Member

@jasonmalinowski jasonmalinowski left a comment

Choose a reason for hiding this comment

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

Looks like there's some missing tests and one possible functional bug. Great start though.

Copy link
Member

@jasonmalinowski jasonmalinowski Sep 28, 2018

Choose a reason for hiding this comment

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

So this is a bug then? It seems we should have this assert the correct behavior and then skip the test with a Skip attribute, rather than assert "wrong" behavior? #Resolved

Copy link
Member Author

@jcouv jcouv Sep 29, 2018

Choose a reason for hiding this comment

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

Skipping tests risks that we forget unskipping.
The comment is there to clarify that the expectation is "wrong". #Resolved

Copy link
Member

@jasonmalinowski jasonmalinowski Oct 1, 2018

Choose a reason for hiding this comment

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

Skipped tests that aren't unskipped we can tool to catch automatically, this we can't. Please just use a skip and have it assert the right thing. #Resolved

Copy link
Member Author

Choose a reason for hiding this comment

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

The "right thing" is not yet decided, as explained in the comment and the linked issue. Two options:

  • not trigger
  • toggle to true

I don't think this PR should depend on figuring out the design for some future work.

Copy link
Member

@jasonmalinowski jasonmalinowski Sep 28, 2018

Choose a reason for hiding this comment

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

"NonNullTYpes" has a typo. #Resolved

Copy link
Member

@jasonmalinowski jasonmalinowski Sep 28, 2018

Choose a reason for hiding this comment

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

Should be indented a bit farther. #Resolved

@jcouv
Copy link
Member Author

jcouv commented Oct 2, 2018

@jasonmalinowski All feedback addressed, except the request to skip a test (because the "right" behavior is pending some design). #Resolved

= ImmutableArray.Create(CS8632, CS8629);

public CSharpAddNonNullTypesCodeFixProvider()
: base(supportsFixAll: false)
Copy link
Contributor

Choose a reason for hiding this comment

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

:'(

<value>Hide base member</value>
</data>
<data name="Add_NonNullTypes_attribute" xml:space="preserve">
<value>Add NonNullTypes attribute</value>
Copy link
Contributor

@CyrusNajmabadi CyrusNajmabadi Oct 3, 2018

Choose a reason for hiding this comment

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

Nit: would probably look better as Add [NonNullTypes] attribute #Pending

using System.Threading;
using System;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.Editing;
Copy link
Contributor

@CyrusNajmabadi CyrusNajmabadi Oct 3, 2018

Choose a reason for hiding this comment

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

ordering. #Pending

private class MyCodeAction : CodeAction.DocumentChangeAction
{
public MyCodeAction(Func<CancellationToken, Task<Document>> createChangedDocument)
: base(CSharpFeaturesResources.Hide_base_member, createChangedDocument)
Copy link
Contributor

@CyrusNajmabadi CyrusNajmabadi Oct 3, 2018

Choose a reason for hiding this comment

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

dumb question... why was this rolled into this PR? #Resolved

Copy link
Member Author

@jcouv jcouv Oct 3, 2018

Choose a reason for hiding this comment

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

Earlier in this PR, you pointed out bad pattern (holding onto objects) which I had picked up from that fixer. #Resolved

if (containingType == null)
{
return;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

this is somewhat busted in that we have already registered the fix, but now it doesn't do anything in this case. Unless we're guaranteeing that this diagnostic will always be reported inside a type-decl, then we need to change tings slightly. specifically, the RegisterCodeFixesAsync method needs to check if we're in a containing-type first, before registering teh fix.

@@ -42,7 +51,25 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
return;
Copy link
Contributor

Choose a reason for hiding this comment

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

same issue here. but this seems to be a different feature. so it's buggy that feature was written that way.

@jcouv jcouv added Blocked PR For Personal Review Only The PR doesn’t require anyone other than the developer to review it. labels Oct 5, 2018
@jcouv
Copy link
Member Author

jcouv commented Oct 5, 2018

I'm going to hold-off this PR, as we're going to switch to a directive method to turn the feature on.

@CyrusNajmabadi
Copy link
Contributor

Directive approach seems far saner. does this mean no concerns about attribute circularity?

@jcouv
Copy link
Member Author

jcouv commented Oct 5, 2018

@CyrusNajmabadi Yes. Cycles are a key motivation for switching to directive.
Also, there is the scenario of controlling nullability in aliases: using alias = List<string>;

@CyrusNajmabadi
Copy link
Contributor

Loveit!

@jcouv
Copy link
Member Author

jcouv commented Feb 23, 2019

Closing because we don't use the NonNullTypes attribute any longer. We use #nullable enable or a project-level setting. I'll add a fixer once the project-level setting is available via project-system.

@jcouv jcouv closed this Feb 23, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area-IDE Blocked Feature - Nullable Reference Types Nullable Reference Types Feature Request PR For Personal Review Only The PR doesn’t require anyone other than the developer to review it.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants