Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@matanshavit
Copy link
Contributor

@matanshavit matanshavit commented Nov 6, 2025

Summary

Compare function bindings in addition to names for recursion detection. This prevents false positives when a method has the same name as an outer function but calls the outer function (not itself). Fixes #8004
related - #7970 refactors and additional comments that were requested for the rule file

AI assistance notice

This PR was written primarily by Claude Code, with changes from the author. As the human author, I have reviewed the code thoroughly and take full responsibility for its contents.

Test Plan

Added a valid test and snapshot for the example shown in the issue. The test fails without the production change, confirming the issue, and passes after the production file change, confirming the solution.

Docs

Doc comment on new method for function bindings

…detection

Compare function bindings in addition to names for recursion detection.
This prevents false positives when a method has the same
name as an outer function but calls the outer function (not itself).
@changeset-bot
Copy link

changeset-bot bot commented Nov 6, 2025

🦋 Changeset detected

Latest commit: a83d962

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 13 packages
Name Type
@biomejs/biome Patch
@biomejs/cli-win32-x64 Patch
@biomejs/cli-win32-arm64 Patch
@biomejs/cli-darwin-x64 Patch
@biomejs/cli-darwin-arm64 Patch
@biomejs/cli-linux-x64 Patch
@biomejs/cli-linux-arm64 Patch
@biomejs/cli-linux-x64-musl Patch
@biomejs/cli-linux-arm64-musl Patch
@biomejs/wasm-web Patch
@biomejs/wasm-bundler Patch
@biomejs/wasm-nodejs Patch
@biomejs/backend-jsonrpc Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions github-actions bot added A-Linter Area: linter L-JavaScript Language: JavaScript and super languages labels Nov 6, 2025
@codspeed-hq
Copy link

codspeed-hq bot commented Nov 6, 2025

CodSpeed Performance Report

Merging #8026 will not alter performance

Comparing matanshavit:fix/is-recursive-call (a83d962) with main (aa55c8d)1

Summary

✅ 53 untouched
⏩ 100 skipped2

Footnotes

  1. No successful run was found on main (96f3e77) during the generation of this report, so aa55c8d was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

  2. 100 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@matanshavit matanshavit marked this pull request as ready for review November 6, 2025 16:16
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 6, 2025

Walkthrough

The PR updates the noParametersOnlyUsedInRecursion lint to use the semantic model and binding comparison for recursion detection. It adds get_function_binding(parent_function, model), threads model and an optional parent_function_binding through recursion-analysis helpers, and updates signatures and call sites for is_recursive_call, is_reference_in_recursive_call, and is_recursive_call_with_param_usage. Tests were extended with a non-recursive helper case and a separately declared recursive arrow function (bar). A changeset documents the behavioural fix.

Possibly related PRs

Suggested reviewers

  • ematipico

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main fix: comparing bindings for recursion detection in the noParametersOnlyUsedInRecursion rule.
Description check ✅ Passed The description directly addresses the changeset, explaining the binding-comparison fix for false positives and referencing the related issue #8004.
Linked Issues check ✅ Passed The changes implement binding-aware recursion detection as required by #8004, comparing function bindings to prevent false positives and include tests.
Out of Scope Changes check ✅ Passed All changes are scoped to the recursion detection logic, test cases, and changeset—no out-of-scope modifications detected.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 274fb96 and a83d962.

📒 Files selected for processing (1)
  • .changeset/cute-moons-obey.md (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • .changeset/cute-moons-obey.md
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (12)
  • GitHub Check: Documentation
  • GitHub Check: Test (depot-windows-2022-16)
  • GitHub Check: End-to-end tests
  • GitHub Check: Check Dependencies
  • GitHub Check: Test (depot-ubuntu-24.04-arm-16)
  • GitHub Check: Lint project (depot-windows-2022)
  • GitHub Check: Lint project (depot-ubuntu-24.04-arm-16)
  • GitHub Check: Bench (biome_js_analyze)
  • GitHub Check: Test Node.js API
  • GitHub Check: Bench (biome_js_formatter)
  • GitHub Check: Bench (biome_js_parser)
  • GitHub Check: autofix

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@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

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 96f3e77 and fde87f3.

⛔ Files ignored due to path filters (1)
  • crates/biome_js_analyze/tests/specs/nursery/noParametersOnlyUsedInRecursion/valid.js.snap is excluded by !**/*.snap and included by **
📒 Files selected for processing (2)
  • crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs (8 hunks)
  • crates/biome_js_analyze/tests/specs/nursery/noParametersOnlyUsedInRecursion/valid.js (1 hunks)
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-10-15T09:23:33.055Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_js_type_info/CONTRIBUTING.md:0-0
Timestamp: 2025-10-15T09:23:33.055Z
Learning: Applies to crates/biome_js_type_info/src/{type_info,local_inference,resolver,flattening}.rs : Avoid recursive type structures and cross-module Arcs; represent links between types using TypeReference and TypeData::Reference.

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs
📚 Learning: 2025-10-15T09:23:33.055Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_js_type_info/CONTRIBUTING.md:0-0
Timestamp: 2025-10-15T09:23:33.055Z
Learning: Applies to crates/biome_js_type_info/biome_module_graph/src/js_module_info/collector.rs : Thin (module-level) inference should resolve local and global bindings to TypeReference::Resolved, mark imported bindings as TypeReference::Import, and fall back to TypeReference::Unknown if unresolved.

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs
📚 Learning: 2025-10-15T09:23:33.055Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_js_type_info/CONTRIBUTING.md:0-0
Timestamp: 2025-10-15T09:23:33.055Z
Learning: Applies to crates/biome_js_type_info/biome_module_graph/src/js_module_info/scoped_resolver.rs : Full inference must resolve TypeReference::Import across modules to TypeReference::Resolved when the target is available in the module graph.

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs
🧬 Code graph analysis (2)
crates/biome_js_analyze/tests/specs/nursery/noParametersOnlyUsedInRecursion/valid.js (1)
crates/biome_js_analyze/tests/specs/nursery/noParametersOnlyUsedInRecursion/invalid.js (1)
  • obj (46-51)
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs (1)
crates/biome_rowan/src/ast/mod.rs (1)
  • cast_ref (143-152)

return false;
}

// Try to resolve the binding of the reference
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
// Try to resolve the binding of the reference

Make sure you leave comments that are useful

// Try to resolve the binding of the reference
let called_binding = model.binding(&ref_id);

// Compare bindings
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
// Compare bindings

// Simple identifier: foo()
if let Some(ref_id) = expr.as_js_reference_identifier() {
return ref_id.name().ok().is_some_and(|n| n.text() == name.text());
// First check for a matching name
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
// First check for a matching name

@ematipico
Copy link
Member

Also, changeset is missing...

Copy link
Contributor

@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 (2)
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs (2)

258-310: Solid binding resolution logic.

The function correctly handles all function types, including the tricky arrow-function case by walking up ancestors. The binding comparison for assignments (lines 293-296) is well-explained.

One minor point: the comment at lines 293-296 is quite detailed. Whilst accurate, consider whether a more concise version might suffice—something like "Resolve assignment target to its binding via model.binding()."


324-328: Use skip(1) for consistency.

As noted in earlier feedback, this manual check can be replaced with skip(1) on the iterator, matching the approach in get_function_binding (line 276).

Apply this diff:

-    for ancestor in arrow_syntax.ancestors() {
-        // Skip the arrow function node itself
-        if ancestor == *arrow_syntax {
-            continue;
-        }
+    for ancestor in arrow_syntax.ancestors().skip(1) {
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 697987f and f740ac3.

📒 Files selected for processing (1)
  • crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs (8 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-10-15T09:23:33.055Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_js_type_info/CONTRIBUTING.md:0-0
Timestamp: 2025-10-15T09:23:33.055Z
Learning: Applies to crates/biome_js_type_info/src/{type_info,local_inference,resolver,flattening}.rs : Avoid recursive type structures and cross-module Arcs; represent links between types using TypeReference and TypeData::Reference.

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs
📚 Learning: 2025-10-15T09:23:33.055Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_js_type_info/CONTRIBUTING.md:0-0
Timestamp: 2025-10-15T09:23:33.055Z
Learning: Applies to crates/biome_js_type_info/biome_module_graph/src/js_module_info/collector.rs : Thin (module-level) inference should resolve local and global bindings to TypeReference::Resolved, mark imported bindings as TypeReference::Import, and fall back to TypeReference::Unknown if unresolved.

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs
🧬 Code graph analysis (1)
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs (2)
crates/biome_rowan/src/ast/mod.rs (1)
  • cast_ref (143-152)
crates/biome_js_formatter/src/utils/assignment_like.rs (1)
  • left (355-374)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Test Node.js API
  • GitHub Check: autofix
  • GitHub Check: Bench (biome_js_parser)
  • GitHub Check: Bench (biome_js_formatter)
  • GitHub Check: Bench (biome_js_analyze)
🔇 Additional comments (4)
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs (4)

129-131: LGTM!

Clean addition to retrieve the function binding for semantic comparison.


415-441: Excellent binding-aware recursion detection.

The four-case logic correctly addresses the false positive:

  • Case (None, Some) at lines 429-431 is the key fix, preventing methods from being flagged when they call outer functions sharing the same name.
  • The fallback to name comparison for (None, None) maintains backwards compatibility for method self-calls.

The early name check (lines 415-418) is a sensible optimisation.


492-514: Correct parameter threading.

The signature updates and call sites properly thread model and parent_function_binding through the recursion analysis chain.


624-632: Correct parameter threading.

The updated signature and call to is_recursive_call correctly pass the semantic context through.

@matanshavit matanshavit force-pushed the fix/is-recursive-call branch from 8930f0d to 4af7f8d Compare November 11, 2025 19:36
@ematipico ematipico merged commit f102661 into biomejs:main Nov 12, 2025
18 checks passed
@github-actions github-actions bot mentioned this pull request Nov 11, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-Linter Area: linter L-JavaScript Language: JavaScript and super languages

Projects

None yet

Development

Successfully merging this pull request may close these issues.

💅 noParametersOnlyUsedInRecursion false positives

3 participants