Skip to content

Conversation

@yuxincs
Copy link
Contributor

@yuxincs yuxincs commented Mar 11, 2025

In our hook.ReplaceConditional we have support for replacing a conditional with another since we know it has certain implications. E.g., errors.As(..., &targetErr) actually means errors.As(..., &targetErr) && targetErr != nil.

This PR adds support for cases where the value is stored in the init part of the if statement, e.g., if ok := errors.As(...); ok { ... }.

Note that the handling is limited: we simply check the last node within the current block. This would lead to missing cases like if ok := errors.As(...); dummy && ok { ... } since it would be canonicalized to if dummy { if ok { ... } }, and we won't find the definition of ok within the current block anymore (it would work if ok is actually placed at the beginning, e.g., if ok && dummy {...}.

This is weird, but it is the simplest way to implement such support for now (and we assume it would be a common case to place ok as the first component of the expression anyways).

A more general handling to get the latest declaration with the help of SSA analyzer will be done in follow-up PR.

@coderabbitai
Copy link

coderabbitai bot commented Mar 11, 2025

Walkthrough

This pull request modifies the replaceConditional method in the preprocessor to enhance the logic for extracting call expressions by analyzing both the last and second-to-last nodes in a block. Additionally, it introduces new case labels in the errorsAs function to improve handling of specific scenarios involving short assignments in if statements. No public API changes were made.

Changes

File Path Change Summary
assertion/function/preprocess/cfg.go Expanded logic in replaceConditional to extract call expressions from assignments by checking the last and second-to-last nodes for proper identifier matching.
testdata/.../trustedfuncs.go Added new case labels in errorsAs to enhance handling of short assignment scenarios in if statements without changing existing functionality.

Sequence Diagram(s)

sequenceDiagram
    participant P as Preprocessor
    participant B as Block Nodes
    participant A as Assignment Checker

    P->>B: Retrieve last node
    alt Last node is a call expression
        B-->>P: Return call expression
    else Last node is not a call expression
        P->>B: Retrieve second-to-last node
        B-->>P: Return assignment statement
        P->>A: Compare LHS of assignment with last node identifier
        alt Identifiers match
            A-->>P: Extract call expression from RHS
            P-->>B: Use extracted call expression
        else
            A-->>P: No valid call expression found
        end
    end
Loading

Poem

I’m a rabbit on a coding spree,
Hopping through logic with glee,
Checking nodes, both last and near,
Tests on errors bring cheer,
In the forest of code I roam,
New paths make our logic home.
🐇💻

✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
testdata/src/go.uber.org/trustedfunc/trustedfuncs.go (1)

1004-1034: Comprehensive test cases for short variable declarations.

The new test cases effectively validate the implementation for different scenarios:

  1. Basic short assignment in if statement
  2. Short assignment with OR condition
  3. Short assignment with AND condition (both orderings)

These cover the key cases mentioned in the PR objectives, including identifying the limitation with the dummy && ok case. The comment about the false positive in the last test case aligns with the acknowledged limitation in the PR summary.

One minor note: there's a duplicate case name "short assignment in if statement with AND condition" on lines 1019 and 1026. While it doesn't affect functionality, it might be worth renaming one for clarity.

-case "short assignment in if statement with AND condition":
+case "short assignment in if statement with reversed AND condition":
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b5f6271 and 2d05a4f.

📒 Files selected for processing (2)
  • assertion/function/preprocess/cfg.go (1 hunks)
  • testdata/src/go.uber.org/trustedfunc/trustedfuncs.go (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: Test (1.24.x)
  • GitHub Check: Test (1.23.x)
  • GitHub Check: Run
🔇 Additional comments (1)
assertion/function/preprocess/cfg.go (1)

189-220: Enhanced handling of short variable declarations in conditionals.

The implementation now correctly handles cases where a variable is defined in the initialization part of an if statement (e.g., if ok := errors.As(...); ok { ... }). The approach is to check if the second-to-last node is an assignment whose left-hand side matches the identifier used in the condition.

This change addresses the PR's primary objective and improves error handling scenarios that use this pattern.

@codecov
Copy link

codecov bot commented Mar 11, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 88.18%. Comparing base (808dce5) to head (c35f9f6).
Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #311      +/-   ##
==========================================
+ Coverage   88.16%   88.18%   +0.01%     
==========================================
  Files          67       67              
  Lines       10395    10411      +16     
==========================================
+ Hits         9165     9181      +16     
  Misses       1051     1051              
  Partials      179      179              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@github-actions
Copy link

github-actions bot commented Mar 11, 2025

Golden Test

Note

✅ NilAway errors reported on standard libraries are identical.

3460 errors on base branch (main, 808dce5)
3460 errors on test branch (2244b11)

@yuxincs yuxincs force-pushed the yuxincs/handle-ok-case branch from 614479a to 320e87d Compare March 12, 2025 02:50
@yuxincs yuxincs force-pushed the yuxincs/handle-ok-case branch from 320e87d to c35f9f6 Compare March 12, 2025 02:51
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
assertion/function/preprocess/cfg.go (1)

205-212: Consider prioritizing the SSA-based implementation in a future PR.

The current approach has limitations with handling nested conditions like if dummy && ok {...} where ok is defined in a short assignment. Your comment correctly identifies this limitation, but using SSA would provide a more robust solution.

Using the SSA analyzer would allow tracking variable definitions more accurately, regardless of where they appear in the control flow, which would eliminate this class of false positives.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 614479a and c35f9f6.

📒 Files selected for processing (2)
  • assertion/function/preprocess/cfg.go (1 hunks)
  • testdata/src/go.uber.org/trustedfunc/trustedfuncs.go (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: Test (1.24.x)
  • GitHub Check: Test (1.23.x)
  • GitHub Check: Run
🔇 Additional comments (6)
assertion/function/preprocess/cfg.go (3)

191-228: Good implementation for handling short assignments in if conditions.

The implementation correctly handles scenarios like if ok := errors.As(...); ok { ... } by checking if the last node is an identifier and then looking at the second-to-last node for an assignment statement. The detailed comments explain the approach and its limitations clearly.


213-226: Thorough validation of the assignment structure.

The code correctly validates various aspects of the assignment statement: ensuring it's an actual assignment, has exactly one left-hand and right-hand expression, confirms the left side is an identifier, and verifies the identifier name matches the one in the condition.


230-230: Good null check placement.

Moving the call == nil check to after the switch statement is appropriate since the call could now be extracted from either a direct call expression or from an assignment.

testdata/src/go.uber.org/trustedfunc/trustedfuncs.go (3)

1004-1010: Great test case for basic short assignment in if statement.

This test case verifies the core functionality being added in this PR - handling ok variable that's defined in a short assignment within an if statement.


1011-1017: Good test coverage for OR conditions.

Testing the scenario with an OR condition is important as it confirms the expected behavior where the dereference is flagged as unsafe when using an OR with the result of errors.As.


1018-1024: Good test coverage for AND conditions with ok first.

This test case correctly verifies that when ok is the first operand in an AND condition, the execution guarantees that ok is true before evaluating the second operand, which means variables guarded by errors.As are properly tracked.

Comment on lines +1025 to +1033
case "short assignment in if statement with AND condition (dummy && ok)":
var exitErr *exec.ExitError
var nilError error
if ok := errors.As(nilError, &exitErr); dummy && ok {
// The following is an FP: since the `dummy && ok` is canonicalized to `if dummy { if ok { } }`,
// our current handling fails to find the `ok := errors.As(...)` call at the end of the block.
print(*exitErr) //want "unassigned variable `exitErr` dereferenced"
print(ok)
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Well-documented false positive case.

This test case clearly documents the current limitation where the implementation fails to track the ok variable when it's the second operand in an AND condition. The comment explaining why this is a false positive is very helpful.

The current implementation doesn't handle the case where ok is the second operand in an AND condition because the canonical form turns it into a nested if structure, making it harder to track the variable definition. This is a known limitation that would be addressed by the planned SSA-based implementation.

@yuxincs yuxincs merged commit a24fa07 into main Mar 12, 2025
9 checks passed
@yuxincs yuxincs deleted the yuxincs/handle-ok-case branch March 12, 2025 03:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants