Implement 'Enable nullable reference types' refactoring#57200
Implement 'Enable nullable reference types' refactoring#57200sharwell merged 12 commits intodotnet:mainfrom
Conversation
| var nullableDisableTrivia = SyntaxFactory.Trivia(SyntaxFactory.NullableDirectiveTrivia(SyntaxFactory.Token(SyntaxKind.DisableKeyword).WithPrependedLeadingTrivia(SyntaxFactory.ElasticSpace), isActive: true)); | ||
| var updatedRoot = root.ReplaceToken(firstToken, firstToken.WithLeadingTrivia(firstToken.LeadingTrivia.Add(nullableDisableTrivia).Add(newLine).Add(newLine))); | ||
|
|
||
| // TODO: remove all '#nullable disable' directives in code with no nullable types |
There was a problem hiding this comment.
💡 It may be sufficient to move this to a separate diagnostic analyzer/code fix, where it would be applicable both as a follow-up for this refactoring and as a helper for code that enabled nullable reference types through other strategies.
There was a problem hiding this comment.
what are the odds of this happening in practice? i'd guess either:
- very low
- only for very common/obvious syntactic forms (like enums)
Given this, i would instead only look for really obvious cases to remove. Beyond that, just leave in.
There was a problem hiding this comment.
➡️ For now, opting to not implement this. We can create a separate diagnostic analyzer in the future to point out redundant directives, and at that point leverage it in this refactoring to improve the results.
|
|
||
| // TODO: remove all '#nullable disable' directives in code with no nullable types | ||
|
|
||
| // TODO: remove all redundant directives |
There was a problem hiding this comment.
💡 It may be sufficient to move this to a separate diagnostic analyzer/code fix, where it would be applicable both as a follow-up for this refactoring and as a helper for code that enabled nullable reference types through other strategies.
There was a problem hiding this comment.
i would only look for the most basic case. Specifically, if the file now starts with #nullable enable and nothing else, then remove that. If there's any sort of multi-directive stuff going on, then leave it alone.
There was a problem hiding this comment.
➡️ This simplification is now implemented. Further identification of redundant #nullable directives can be implemented as a separate diagnostic analyzer.
34bfcb5 to
2214f8d
Compare
Files that already start with a '#nullable' directive do not need a second leading directive.
2214f8d to
1dc341d
Compare
...res/CSharp/Portable/CodeRefactorings/EnableNullable/EnableNullableCodeRefactoringProvider.cs
Outdated
Show resolved
Hide resolved
...res/CSharp/Portable/CodeRefactorings/EnableNullable/EnableNullableCodeRefactoringProvider.cs
Outdated
Show resolved
Hide resolved
...res/CSharp/Portable/CodeRefactorings/EnableNullable/EnableNullableCodeRefactoringProvider.cs
Outdated
Show resolved
Hide resolved
...res/CSharp/Portable/CodeRefactorings/EnableNullable/EnableNullableCodeRefactoringProvider.cs
Show resolved
Hide resolved
...res/CSharp/Portable/CodeRefactorings/EnableNullable/EnableNullableCodeRefactoringProvider.cs
Outdated
Show resolved
Hide resolved
...res/CSharp/Portable/CodeRefactorings/EnableNullable/EnableNullableCodeRefactoringProvider.cs
Show resolved
Hide resolved
...res/CSharp/Portable/CodeRefactorings/EnableNullable/EnableNullableCodeRefactoringProvider.cs
Outdated
Show resolved
Hide resolved
| if (originalNode.SettingToken.IsKind(SyntaxKind.EnableKeyword)) | ||
| { | ||
| return rewrittenNode.WithSettingToken(SyntaxFactory.Token(SyntaxKind.RestoreKeyword).WithTriviaFrom(rewrittenNode.SettingToken)); | ||
| } |
There was a problem hiding this comment.
something feels fishy here, though i can't quite put my finger on it. i think it's that disable doesn't change, while the other two rotate. i trust that this logic is correct? my feeble brain keeps getting confused by it :)
There was a problem hiding this comment.
💭 It's strange, but it seems to be correct. With Nullable Reference Types disabled, #nullable disable and #nullable restore have the same meaning.
...res/CSharp/Portable/CodeRefactorings/EnableNullable/EnableNullableCodeRefactoringProvider.cs
Outdated
Show resolved
Hide resolved
...res/CSharp/Portable/CodeRefactorings/EnableNullable/EnableNullableCodeRefactoringProvider.cs
Outdated
Show resolved
Hide resolved
...res/CSharp/Portable/CodeRefactorings/EnableNullable/EnableNullableCodeRefactoringProvider.cs
Outdated
Show resolved
Hide resolved
...res/CSharp/Portable/CodeRefactorings/EnableNullable/EnableNullableCodeRefactoringProvider.cs
Outdated
Show resolved
Hide resolved
| if (nextToken.IsKind(SyntaxKind.HashToken) && nextToken.Parent.IsKind(SyntaxKind.EndRegionDirectiveTrivia)) | ||
| { | ||
| firstToken = nextToken.Parent.GetLastToken(includeDirectives: true).GetNextToken(includeDirectives: true); | ||
| } |
There was a problem hiding this comment.
this seems fine. though perhaps it should be a loop? though i guess the change of having multiple empty regions in a row is so low as to be pointless :)
There was a problem hiding this comment.
💭 Yeah, the main goal here was to not mess up a known file header pattern.
5ab7769 to
98e6aca
Compare
|
Nice. Thanks! |
Fixes #52893
#nullabledirectiveScreenshots