Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Oct 24, 2025

Fix IDE0031 false positive when #if DEBUG is used

  • Understand the codebase structure and locate the relevant files
  • Make AnalyzeIfStatement virtual in AbstractUseNullPropagationDiagnosticAnalyzer_IfStatement.cs
  • Override AnalyzeIfStatement in CSharpUseNullPropagationDiagnosticAnalyzer.cs to check for directives in block
  • Add tests for the fix to verify the behavior with #if DEBUG statements
  • Refine implementation to check entire block instead of just close brace
  • Request code review - No issues found
  • Run security checks - Passed
  • Update WorkItem references to correct issue number
  • Simplify implementation: move check to base class, remove virtual/override
  • Add test for single-statement if with preprocessor directives
  • Fix directive check to only examine statement body (not condition)

Summary

This PR fixes IDE0031 (Use null propagation) false positive when preprocessor directives like #if DEBUG are present in the body of an if statement.

The analyzer now checks if the statements that would be transformed contain any preprocessor directives. If directives are found in the statement body, the transformation is skipped to avoid incorrect code transformations where conditional compilation directives would be removed or execute unconditionally.

Changes

  1. Added directive check in base AnalyzeIfStatement method
  2. Check uses ContainsDirectives on the actual statements being transformed (not the entire if-statement)
  3. This allows transformations where directives are only in the condition, while blocking transformations where directives are in the body
  4. Added comprehensive tests covering various scenarios including single-statement if with directives

Fixes #65880


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

- Make AnalyzeIfStatement virtual in AbstractUseNullPropagationDiagnosticAnalyzer
- Override in CSharpUseNullPropagationDiagnosticAnalyzer to check for directives on block close brace
- Add tests for preprocessor directive scenarios

Co-authored-by: CyrusNajmabadi <4564579+CyrusNajmabadi@users.noreply.github.com>
This is more conservative and handles cases where directives appear anywhere in the block, not just at the end.

Co-authored-by: CyrusNajmabadi <4564579+CyrusNajmabadi@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix IDE0031 false positive with #if DEBUG usage Fix IDE0031 false positive when preprocessor directives are used in if blocks Oct 24, 2025
Copilot AI requested a review from CyrusNajmabadi October 24, 2025 14:01
Copilot finished work on behalf of CyrusNajmabadi October 24, 2025 14:01
""",
languageVersion: LanguageVersion.CSharp14);

[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/77777")]
Copy link
Member

Choose a reason for hiding this comment

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

@copilot fix all thsee workitems to be #65880

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updated all WorkItem attributes to reference issue #65880 in commit fb667db.

Comment on lines 79 to 83
if (ifStatement.Statement is BlockSyntax block)
{
if (block.ContainsDirectives)
return null;
}
Copy link
Member

Choose a reason for hiding this comment

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

@copilot actually you can just check if it .ContainsDirectives, regardless of whether or not it is a block. And that means this check can move into the base class, and you can avoid needing the virtual/override.

Also, please add a test where the if-statement doesn't have a block, but just a single-statement with a #if/#else/#endif..

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Moved the directive check to the base class and simplified the implementation in commit 2654915. The check now uses ifStatement.ContainsDirectives directly without needing virtual/override. Also added a test for single-statement if with #if/#else/#endif.

Co-authored-by: CyrusNajmabadi <4564579+CyrusNajmabadi@users.noreply.github.com>
- Remove virtual/override approach
- Check ContainsDirectives on if-statement directly in base class
- Add test for single-statement if with preprocessor directives

Co-authored-by: CyrusNajmabadi <4564579+CyrusNajmabadi@users.noreply.github.com>
Copilot AI changed the title Fix IDE0031 false positive when preprocessor directives are used in if blocks Fix IDE0031 false positive when preprocessor directives are used in if statements Oct 24, 2025
Copilot finished work on behalf of CyrusNajmabadi October 24, 2025 14:26
@CyrusNajmabadi CyrusNajmabadi marked this pull request as ready for review October 24, 2025 14:29
@CyrusNajmabadi CyrusNajmabadi requested a review from a team as a code owner October 24, 2025 14:29
@CyrusNajmabadi
Copy link
Member

@copilot looks like this broke a bunch of tests in UseNullPropagationTests. Take a look at what broke and what we were expecting to work from before. And use that to redo this PR with a correct fix that doesn't break existing working scenarios, btu blocks the new scenarios we want blocked.

…tement

The previous check was too broad - checking ifStatement.ContainsDirectives would fail for directives anywhere in the if-statement including the condition. Now we check only the statements that would be transformed (trueStatement and nullAssignmentOpt).

Co-authored-by: CyrusNajmabadi <4564579+CyrusNajmabadi@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Oct 24, 2025

@copilot looks like this broke a bunch of tests in UseNullPropagationTests. Take a look at what broke and what we were expecting to work from before. And use that to redo this PR with a correct fix ...

Fixed in commit ad5bc14. The issue was that the check was too broad - ifStatement.ContainsDirectives returns true for directives anywhere in the if-statement, including the condition. This broke tests where directives appeared in the condition but not the body.

Now the check only examines the statements that would actually be transformed (trueStatement and nullAssignmentOpt), allowing transformations where directives are only in the condition while still blocking transformations where directives are in the body.

Copilot finished work on behalf of CyrusNajmabadi October 24, 2025 15:21
@CyrusNajmabadi CyrusNajmabadi merged commit d9cbbf3 into main Oct 24, 2025
25 checks passed
@dotnet-policy-service dotnet-policy-service bot added this to the Next milestone Oct 24, 2025
@CyrusNajmabadi CyrusNajmabadi deleted the copilot/fix-ide0031-debug-handling branch October 24, 2025 18:31
333fred added a commit to 333fred/roslyn that referenced this pull request Oct 24, 2025
* upstream/main: (332 commits)
  Cache lambdas in analyzer driver (dotnet#80759)
  Add information for NuGet package version 4.14 (dotnet#80870)
  Add missing search keywords to VB Advanced options page
  Fix IDE0031 false positive when preprocessor directives are used in if statements (dotnet#80878)
  Use core compiler on netfx hosts with toolset package (dotnet#80631)
  Make string concat assert more precise (dotnet#80619)
  Extensions: address some diagnostic quality issues (dotnet#80827)
  Add note on traversal order for bound nodes (dotnet#80872)
  Ensure that locals at the top level of a constructor have the same safe-context as parameters (dotnet#80807)
  Fix handling of SymbolDisplayCompilerInternalOptions.UseArityForGenericTypes option for non-native symbol implementations (dotnet#80826)
  Update src/Analyzers/CSharp/Tests/UseCollectionInitializer/UseCollectionInitializerTests.cs
  Add IsValidContainingStatement check to prevent collection initializers in using declarations
  Add back old DocumentSpan constructor (dotnet#80864)
  Add tests verifying pointer types in type parameters require unsafe context (dotnet#80776)
  Add regression test for Interlocked.Exchange with nullable types (dotnet#80796)
  Add regression test for ParseAttributeArgumentList with invalid input (fixes dotnet#8699) (dotnet#80705)
  Add regression test for compiler crash with syntax error in indexer declaration (dotnet#80772)
  Add runtime NullReferenceException validation to foreach null iteration tests (dotnet#80839)
  Update MicrosoftBuildTasksCoreVersionForMetrics to 17.11.48 (dotnet#80812)
  Mark CS4009 error as a "build only" error. (dotnet#80698)
  ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

IDE0031 false positive when #if DEBUG is used

3 participants