-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Fix null refs when calling GetLocation() or GetDiagnostics() of freshly constructed syntax trivia
#81444
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
Fix null refs when calling GetLocation() or GetDiagnostics() of freshly constructed syntax trivia
#81444
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,6 +6,7 @@ | |
| using System.Collections.Generic; | ||
| using System.Diagnostics; | ||
| using System.Diagnostics.CodeAnalysis; | ||
| using System.Linq; | ||
| using System.Runtime.InteropServices; | ||
| using Microsoft.CodeAnalysis.Collections; | ||
| using Microsoft.CodeAnalysis.Text; | ||
|
|
@@ -409,8 +410,7 @@ public SyntaxTree? SyntaxTree | |
| /// </summary> | ||
| public Location GetLocation() | ||
| { | ||
| // https://github.com/dotnet/roslyn/issues/40773 | ||
| return this.SyntaxTree!.GetLocation(this.Span); | ||
| return this.SyntaxTree?.GetLocation(this.Span) ?? Location.None; | ||
| } | ||
|
|
||
| /// <summary> | ||
|
|
@@ -420,8 +420,23 @@ public Location GetLocation() | |
| /// </summary> | ||
| public IEnumerable<Diagnostic> GetDiagnostics() | ||
| { | ||
| // https://github.com/dotnet/roslyn/issues/40773 | ||
| return this.SyntaxTree!.GetDiagnostics(this); | ||
| if (UnderlyingNode is null) | ||
| { | ||
| return SpecializedCollections.EmptyEnumerable<Diagnostic>(); | ||
| } | ||
|
|
||
| if (this.SyntaxTree is { } syntaxTree) | ||
| { | ||
| return syntaxTree.GetDiagnostics(this); | ||
| } | ||
| else | ||
| { | ||
| var diagnostics = UnderlyingNode.GetDiagnostics(); | ||
|
|
||
| return diagnostics.Length == 0 | ||
| ? SpecializedCollections.EmptyEnumerable<Diagnostic>() | ||
| : diagnostics.Select(Diagnostic.Create); | ||
| } | ||
| } | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. any problem keeping the logic directly equivalent to SyntaxToken? like line for line. In other words, looking like:
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Where should we extract this logic? Is there a good existing helper class for such things?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. feels like it could all be on SyntaxTree. It just needs a GreenNode+pos to be able to operate.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The VB part also needs to know whether the node/token is in doc comments section, for which it walks the tree upwards from the given node, which is not available for green nodes. I mean we can extract the "getting diagnostic from the tree" part into a delegate, but that will make code more complex, introduce allocation of a delegate etc
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My primary feedback was really just to keep the code written the same way. It's ok to still have the duplicated impl.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My primary feedback was really just to keep the code written the same way. It's ok to still have the duplicated impl. |
||
|
|
||
| /// <summary> | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It feels like all individual code paths in this function should have dedicated code coverage. That should include both positive and negative outcomes, when applicable. Also, I have to admit, I am not an expert in this area, and, at the moment, I do not have a good idea about how expected implementation should actually look like. Therefore, it would be good to provide an explanation why this is the right implementation. If the logic was "copied" from some other place, it would be good to mention that as well. #Closed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When I copied this logic I was not able to come up with a test for the scenario where there is no syntax tree, but the underlying green node exists. After thinking about it for a while I managed to find the case: when parsing trivia via
SyntaxFactory.Parse[Leading|Trailing]Triviawe get precisely this scenario, so added tests for both branches (where we have diagnostics and where we don't)