Skip to content

Conversation

@Rekkonnect
Copy link
Contributor

Closes #72907

@Rekkonnect Rekkonnect requested a review from a team as a code owner April 6, 2024 22:26
@ghost ghost added Area-Compilers untriaged Issues and PRs which have not yet been triaged by a lead labels Apr 6, 2024
@dotnet-policy-service dotnet-policy-service bot added the Community The pull request was submitted by a contributor who is not a Microsoft employee. label Apr 6, 2024
Rekkonnect and others added 2 commits April 7, 2024 13:52
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;
Copy link
Contributor

@AlekseyTs AlekseyTs Apr 12, 2024

Choose a reason for hiding this comment

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

SyntaxKind.DefineDirectiveTrivia or SyntaxKind.UndefDirectiveTrivia

Are these using IdentifierNameSyntax to refer to preprocessing symbol? #Closed

Copy link
Contributor Author

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())))
Copy link
Contributor

@AlekseyTs AlekseyTs Apr 12, 2024

Choose a reason for hiding this comment

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

node.Ancestors().Any(n => isPreprocessorDirectiveAcceptingPreprocessingSymbols(n.Kind()))

I think it would be good to make this condition stronger and verify that the IdentifierNameSyntax is actually coming from expression part of the directive. #Closed

Copy link
Contributor

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.

Copy link
Contributor Author

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.

Copy link
Contributor

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:

  1. Get node's parent, but do not ascend out of trivia
  2. if parent is IfDirectiveTriviaSyntax _if , return node == _if.Condition
  3. if parent is ElifDirectiveTrivia _elif , return node == _elif.Condition
  4. If parent is ExpressionSyntax, let node be parent and repeat from step 1.
  5. return false

Copy link
Contributor

@AlekseyTs AlekseyTs Oct 30, 2025

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/ ElifDirectiveTriviaSyntax and the starting node is within IfDirectiveTriviaSyntax.Condition/ ElifDirectiveTriviaSyntax.Condition.

@AlekseyTs
Copy link
Contributor

AlekseyTs commented Apr 12, 2024

Done with review pass (commit 3) #Closed

@Rekkonnect
Copy link
Contributor Author

@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)
Copy link
Contributor

@AlekseyTs AlekseyTs Oct 30, 2025

Choose a reason for hiding this comment

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

if (nameSyntaxToBind is null)

This makes the test fragile. Someone can make a mistake on the previous statement and the test will silently stop testing the target scenario. Since the API takes IdentifierNameSyntax, we are not really interested in calling this method for other situations. #Closed

Copy link
Contributor Author

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()
Copy link
Contributor

@AlekseyTs AlekseyTs Oct 30, 2025

Choose a reason for hiding this comment

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

GetPreprocessingSymbolInfoOnUnrelatedDirective

It looks like no tests were added for positive scenarios #Closed

Copy link
Contributor Author

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

@AlekseyTs
Copy link
Contributor

AlekseyTs commented Oct 30, 2025

Done with review pass (commit 5) #Closed

@Rekkonnect
Copy link
Contributor Author

@AlekseyTs changed the test, ptal

@AlekseyTs
Copy link
Contributor

AlekseyTs commented Nov 3, 2025

Done with review pass (commit 6). It looks like #72910 (comment) thread is still active. #Closed

@Rekkonnect
Copy link
Contributor Author

It looks to me like it's outdated, the code currently actually checks whether the expression node is within the condition of the if/elif statements

@AlekseyTs
Copy link
Contributor

AlekseyTs commented Nov 3, 2025

It looks to me like it's outdated, the code currently actually checks whether the expression node is within the condition of the if/elif statements

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

@Rekkonnect
Copy link
Contributor Author

Changed the code, could you ptal? @AlekseyTs

return false;
}

return isPreprocessingSymbolIdentifierContainer(parentNode.Parent);
Copy link
Contributor

@AlekseyTs AlekseyTs Nov 5, 2025

Choose a reason for hiding this comment

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

return isPreprocessingSymbolIdentifierContainer(parentNode.Parent);

It looks like we could use a while loop instead of a recursion. #Closed


return PreprocessingSymbolInfo.None;

bool isPreprocessingSymbolIdentifierContainer(SyntaxNode parentNode)
Copy link
Contributor

@AlekseyTs AlekseyTs Nov 5, 2025

Choose a reason for hiding this comment

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

isPreprocessingSymbolIdentifierContainer

"isPossiblePreprocessingSymbolReference"? #Closed


return PreprocessingSymbolInfo.None;

bool isPreprocessingSymbolIdentifierContainer(SyntaxNode parentNode)
Copy link
Contributor

@AlekseyTs AlekseyTs Nov 5, 2025

Choose a reason for hiding this comment

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

SyntaxNode parentNode

Consider passing IdentifierNameSyntax node instead and using a loop through the Parent chain instead of a recursion. #Closed

@AlekseyTs
Copy link
Contributor

AlekseyTs commented Nov 5, 2025

Done with review pass (commit 7) #Closed

@Rekkonnect
Copy link
Contributor Author

Applied suggestions, ptal

Copy link
Contributor

@AlekseyTs AlekseyTs left a comment

Choose a reason for hiding this comment

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

LGTM (commit 8)

@AlekseyTs
Copy link
Contributor

@dotnet/roslyn-compiler For a second review

@AlekseyTs AlekseyTs requested a review from a team November 6, 2025 14:14
@AlekseyTs
Copy link
Contributor

@dotnet/roslyn-compiler For a second review on a community PR

2 similar comments
@AlekseyTs
Copy link
Contributor

@dotnet/roslyn-compiler For a second review on a community PR

@AlekseyTs
Copy link
Contributor

@dotnet/roslyn-compiler For a second review on a community PR

Comment on lines +4873 to +4898
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;
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
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;

Copy link
Member

@CyrusNajmabadi CyrusNajmabadi left a 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.

@AlekseyTs AlekseyTs merged commit 5afb7a1 into dotnet:main Nov 11, 2025
25 checks passed
@dotnet-policy-service dotnet-policy-service bot modified the milestones: Backlog, Next Nov 11, 2025
@AlekseyTs
Copy link
Contributor

@Rekkonnect Thanks for the contribution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area-Compilers Community The pull request was submitted by a contributor who is not a Microsoft employee. untriaged Issues and PRs which have not yet been triaged by a lead

Projects

None yet

Development

Successfully merging this pull request may close these issues.

GetPreprocessingSymbolInfo returns info when inside #pragma warning directive

4 participants