-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Fix returning valid pp symbol info on unrelated preprocessor directives #72910
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
Conversation
Co-authored-by: Cyrus Najmabadi <cyrus.najmabadi@gmail.com>
| return PreprocessingSymbolInfo.None; | ||
|
|
||
| static bool isPreprocessorDirectiveAcceptingPreprocessingSymbols(SyntaxKind kind) | ||
| => kind is SyntaxKind.IfDirectiveTrivia or SyntaxKind.ElifDirectiveTrivia or SyntaxKind.DefineDirectiveTrivia or SyntaxKind.UndefDirectiveTrivia; |
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.
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.
No, these contain a SyntaxToken Name as the name of the preprocessing symbol
| CheckSyntaxNode(node); | ||
|
|
||
| if (node.Ancestors().Any(n => SyntaxFacts.IsPreprocessorDirective(n.Kind()))) | ||
| if (node.Ancestors().Any(n => isPreprocessorDirectiveAcceptingPreprocessingSymbols(n.Kind()))) |
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.
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.
This should come with additional testing, of course.
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.
I'm not sure on how to test this additional condition, the directive trivia only have Condition as the only expression that may contain the IdentifierNameSyntax that is evaluated.
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.
I'm not sure on how to test this additional condition,
I am thinking of a check like the following:
- Get node's
parent, but do not ascend out of trivia - if
parent is IfDirectiveTriviaSyntax _if, returnnode == _if.Condition - if
parent is ElifDirectiveTrivia _elif, returnnode == _elif.Condition - If
parentisExpressionSyntax, letnodebeparentand repeat from step 1. - return false
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.
If it is valid for IfDirectiveTriviaSyntax.Condition/ ElifDirectiveTriviaSyntax.Condition to contain non expression nodes, which are not trivia themselves, then perhaps the check could be something like:
- Ascend to the first directive, but do not ascend out of trivia
- Return true if the directive is
IfDirectiveTriviaSyntax/ElifDirectiveTriviaSyntaxand the starting node is withinIfDirectiveTriviaSyntax.Condition/ElifDirectiveTriviaSyntax.Condition.
src/Compilers/CSharp/Test/Symbol/Compilation/GetSemanticInfoTests.cs
Outdated
Show resolved
Hide resolved
|
Done with review pass (commit 3) #Closed |
|
@AlekseyTs could you ptal? |
| var position = sourceCode.IndexOf(substringToMatch, StringComparison.Ordinal); | ||
| var nameSyntaxToBind = tree.GetRoot().FindToken(position, findInsideTrivia: true).Parent as IdentifierNameSyntax; | ||
|
|
||
| if (nameSyntaxToBind is null) |
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.
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.
Changed to only test against IdentifierNameSyntax
| } | ||
|
|
||
| [Fact, WorkItem(72907, "https://github.com/dotnet/roslyn/issues/72907")] | ||
| public void GetPreprocessingSymbolInfoOnUnrelatedDirective() |
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.
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.
Other tests already cover the positive scenarios, that's why this test didn't focus on them. I will add the assertion for #define which we expect to return a non-null symbol
|
Done with review pass (commit 5) #Closed |
|
@AlekseyTs changed the test, ptal |
|
Done with review pass (commit 6). It looks like #72910 (comment) thread is still active. #Closed |
|
It looks to me like it's outdated, the code currently actually checks whether the expression node is within the condition of the |
I added comments to that thread several days ago, and I think they are still relevant. For example, the current check doesn't stop at the immediate containing directive. The behavior around ascending out of trivia is not clear as well. #Closed |
|
Changed the code, could you ptal? @AlekseyTs |
| return false; | ||
| } | ||
|
|
||
| return isPreprocessingSymbolIdentifierContainer(parentNode.Parent); |
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.
|
|
||
| return PreprocessingSymbolInfo.None; | ||
|
|
||
| bool isPreprocessingSymbolIdentifierContainer(SyntaxNode parentNode) |
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.
|
|
||
| return PreprocessingSymbolInfo.None; | ||
|
|
||
| bool isPreprocessingSymbolIdentifierContainer(SyntaxNode parentNode) |
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.
|
Done with review pass (commit 7) #Closed |
|
Applied suggestions, ptal |
AlekseyTs
left a comment
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.
LGTM (commit 8)
|
@dotnet/roslyn-compiler For a second review |
|
@dotnet/roslyn-compiler For a second review on a community PR |
2 similar comments
|
@dotnet/roslyn-compiler For a second review on a community PR |
|
@dotnet/roslyn-compiler For a second review on a community PR |
| var parentNode = node.Parent; | ||
| while (parentNode is not null) | ||
| { | ||
| var kind = parentNode.Kind(); | ||
| switch (kind) | ||
| { | ||
| case SyntaxKind.IfDirectiveTrivia: | ||
| { | ||
| var parentIf = (IfDirectiveTriviaSyntax)parentNode; | ||
| return parentIf.Condition.FullSpan.Contains(node.FullSpan); | ||
| } | ||
| case SyntaxKind.ElifDirectiveTrivia: | ||
| { | ||
| var parentElif = (ElifDirectiveTriviaSyntax)parentNode; | ||
| return parentElif.Condition.FullSpan.Contains(node.FullSpan); | ||
| } | ||
| } | ||
|
|
||
| if (SyntaxFacts.IsPreprocessorDirective(kind)) | ||
| { | ||
| return false; | ||
| } | ||
|
|
||
| parentNode = parentNode.Parent; | ||
| } | ||
| return false; |
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.
| var parentNode = node.Parent; | |
| while (parentNode is not null) | |
| { | |
| var kind = parentNode.Kind(); | |
| switch (kind) | |
| { | |
| case SyntaxKind.IfDirectiveTrivia: | |
| { | |
| var parentIf = (IfDirectiveTriviaSyntax)parentNode; | |
| return parentIf.Condition.FullSpan.Contains(node.FullSpan); | |
| } | |
| case SyntaxKind.ElifDirectiveTrivia: | |
| { | |
| var parentElif = (ElifDirectiveTriviaSyntax)parentNode; | |
| return parentElif.Condition.FullSpan.Contains(node.FullSpan); | |
| } | |
| } | |
| if (SyntaxFacts.IsPreprocessorDirective(kind)) | |
| { | |
| return false; | |
| } | |
| parentNode = parentNode.Parent; | |
| } | |
| return false; | |
| for (var parentNode = node.Parent; parentNode != null; parentNode = parentNode.Parent) | |
| { | |
| var kind = parentNode.Kind(); | |
| switch (kind) | |
| { | |
| case SyntaxKind.IfDirectiveTrivia: | |
| { | |
| var parentIf = (IfDirectiveTriviaSyntax)parentNode; | |
| return parentIf.Condition.FullSpan.Contains(node.FullSpan); | |
| } | |
| case SyntaxKind.ElifDirectiveTrivia: | |
| { | |
| var parentElif = (ElifDirectiveTriviaSyntax)parentNode; | |
| return parentElif.Condition.FullSpan.Contains(node.FullSpan); | |
| } | |
| } | |
| if (SyntaxFacts.IsPreprocessorDirective(kind)) | |
| { | |
| return false; | |
| } | |
| } | |
| return false; |
CyrusNajmabadi
left a comment
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.
approving. seems simpelr as a for-loop.
|
@Rekkonnect Thanks for the contribution. |
Closes #72907