-
-
Notifications
You must be signed in to change notification settings - Fork 760
feat(lint): new rule: no parameters only used in recursion #7926
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
feat(lint): new rule: no parameters only used in recursion #7926
Conversation
Add initial scaffolding for the noParametersOnlyUsedInRecursion nursery rule. This includes the rule structure, options, configuration integration, and test directory setup.
Implement the core detection logic for the noParametersOnlyUsedInRecursion rule. The rule now detects parameters that are only used in recursive calls and have no other usage in the function body. Key features: - Skips parameters starting with underscore (intentionally unused) - Skips TypeScript signatures - Detects recursive calls in named functions, arrow functions, and methods - Only reports when ALL parameter references are in recursive calls - Adds comprehensive test cases for valid and invalid scenarios
…tic operations Improve the noParametersOnlyUsedInRecursion rule to trace parameters through safe operations including binary arithmetic, unary operations, parenthesized expressions, and static member access. This prevents false positives when parameters are used in expressions like `n - 1`, `!flag`, or `b * 2 + 1` within recursive calls. The rule now correctly identifies: - Parameters used in arithmetic expressions (a + 1, n - step) - Parameters in unary operations (!flag, -n) - Parameters accessed through field access (obj.field) - Parameters in parenthesized expressions Updated tests include new invalid cases that should trigger the rule and valid cases that should not.
Enhanced noParametersOnlyUsedInRecursion rule with automatic fix capability that removes unused recursive parameters. Added Clippy attribution and improved documentation with additional examples for object methods.
Replace .map().unwrap_or(false) patterns with is_some_and() to address clippy::map_unwrap_or lints. Also convert one if-let pattern to use let-chains for improved readability and to satisfy clippy suggestions.
Add changeset documenting the new noParametersOnlyUsedInRecursion lint rule that detects function parameters exclusively used in recursive calls.
🦋 Changeset detectedLatest commit: 7beb492 The changes in this PR will be included in the next version bump. This PR includes changesets to release 13 packages
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 |
CodSpeed Performance ReportMerging #7926 will not alter performanceComparing Summary
Footnotes
|
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.
The new rule creates changes down the array because the linter rules should stay alphabatized/ordered
|
I believe the slowdown in these cases could be the result of needed to walk the AST to determine if recursion is present. I can try to come up with a test to prove that. Since this appears to be the first rule to detect recursion, is there a need to disclose that these types of rules can be inherently slower? For reference, here is the source of the algorithm used by |
WalkthroughAdds a new JavaScript lint rule Suggested reviewers
Pre-merge checks and finishing touches✅ Passed checks (5 passed)
✨ Finishing touches🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
✅ Files skipped from review due to trivial changes (1)
⏰ 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). (15)
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. 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.
Actionable comments posted: 1
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (8)
crates/biome_configuration/src/analyzer/linter/rules.rsis excluded by!**/rules.rsand included by**crates/biome_diagnostics_categories/src/categories.rsis excluded by!**/categories.rsand included by**crates/biome_js_analyze/src/lint/nursery.rsis excluded by!**/nursery.rsand included by**crates/biome_js_analyze/tests/specs/nursery/noParametersOnlyUsedInRecursion/invalid.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noParametersOnlyUsedInRecursion/invalidWithFix.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noParametersOnlyUsedInRecursion/valid.js.snapis excluded by!**/*.snapand included by**packages/@biomejs/backend-jsonrpc/src/workspace.tsis excluded by!**/backend-jsonrpc/src/workspace.tsand included by**packages/@biomejs/biome/configuration_schema.jsonis excluded by!**/configuration_schema.jsonand included by**
📒 Files selected for processing (7)
.changeset/no-parameters-only-used-in-recursion.md(1 hunks)crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noParametersOnlyUsedInRecursion/invalid.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noParametersOnlyUsedInRecursion/invalidWithFix.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noParametersOnlyUsedInRecursion/valid.js(1 hunks)crates/biome_rule_options/src/lib.rs(1 hunks)crates/biome_rule_options/src/no_parameters_only_used_in_recursion.rs(1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{rs,toml}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Format Rust and TOML files before committing (e.g., via
just f)
Files:
crates/biome_rule_options/src/lib.rscrates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rscrates/biome_rule_options/src/no_parameters_only_used_in_recursion.rs
**/*.rs
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Document rules, assists, and their options with inline rustdoc in the Rust source
Files:
crates/biome_rule_options/src/lib.rscrates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rscrates/biome_rule_options/src/no_parameters_only_used_in_recursion.rs
.changeset/*.md
📄 CodeRabbit inference engine (CONTRIBUTING.md)
.changeset/*.md: In changeset files, only use #### or ##### headers
Changesets should describe user-facing changes; internal-only changes do not need changesets
Use past tense for what you did in the changeset description and present tense for current behavior
For bug fixes, start the changeset description with a link to the issue (e.g., Fixed #1234: ...)
When referencing a rule or assist in a changeset, include a link to the rule/assist page on the website
Include a code block in the changeset when applicable to illustrate the change
End every sentence in a changeset with a full stop (.)
Files:
.changeset/no-parameters-only-used-in-recursion.md
🧠 Learnings (22)
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/biome_rule_options/lib/**/*.rs : Place per-rule options types in biome_rule_options crate under lib/, one file per rule
Applied to files:
crates/biome_rule_options/src/lib.rscrates/biome_rule_options/src/no_parameters_only_used_in_recursion.rs
📚 Learning: 2025-10-15T09:23:33.055Z
Learnt from: CR
PR: biomejs/biome#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/**/*.rs : Do not copy or clone data between module graph entries (including behind Arc). Each module must avoid holding duplicated data from another module to enable simple invalidation.
Applied to files:
crates/biome_rule_options/src/lib.rs
📚 Learning: 2025-10-15T09:23:33.055Z
Learnt from: CR
PR: biomejs/biome#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_rule_options/src/lib.rscrates/biome_rule_options/src/no_parameters_only_used_in_recursion.rs
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/biome_rule_options/lib/**/*.rs : Derive Serialize, Deserialize, and Deserializable for rule options; add #[serde(rename_all = "camelCase", deny_unknown_fields, default)]
Applied to files:
crates/biome_rule_options/src/lib.rscrates/biome_rule_options/src/no_parameters_only_used_in_recursion.rs
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/lint/nursery/**/*.rs : Place all new rules in the nursery group
Applied to files:
crates/biome_rule_options/src/lib.rscrates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/biome_rule_options/lib/**/*.rs : When schema feature is enabled, derive schemars::JsonSchema for options and related enums
Applied to files:
crates/biome_rule_options/src/lib.rscrates/biome_rule_options/src/no_parameters_only_used_in_recursion.rs
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/biome_rule_options/lib/**/*.rs : Prefer Box<[Box<str>]> over Vec<String> for options string lists to reduce memory usage
Applied to files:
crates/biome_rule_options/src/lib.rs
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : Use options/full_options/use_options code block modifiers as specified to demonstrate configuration in docs; keep modifier order consistent
Applied to files:
crates/biome_rule_options/src/lib.rscrates/biome_rule_options/src/no_parameters_only_used_in_recursion.rs
📚 Learning: 2025-10-15T09:23:33.055Z
Learnt from: CR
PR: biomejs/biome#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 : Do not cache results of full inference; module replacements would stale such caches.
Applied to files:
crates/biome_rule_options/src/lib.rs
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : In declare_lint_rule! macros, set version: "next"
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : Rule names should use no<Concept> when forbidding a single concept (e.g., noDebugger)
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : Rule documentation: first paragraph must be a single line summary
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : Use rule_category! macro to reference the diagnostic category created by declare_lint_rule!
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : When banning globals (e.g., console), check semantic model to avoid flagging locally shadowed variables
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : Set the language field in declare_lint_rule! to the most appropriate dialect (js/jsx/ts/tsx)
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : Provide informative diagnostics: explain what the error is, why it triggers, and what to do (prefer a code action or a note)
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : Rule names should use use<Concept> when mandating a single concept (e.g., useValidLang)
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : If a rule provides a code action, add fix_kind to declare_lint_rule! (FixKind::Safe or ::Unsafe)
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/tests/specs/**/{invalid*,valid*}.* : Name snapshot test files with invalid* and valid* prefixes to indicate reported vs non-reported cases
Applied to files:
crates/biome_js_analyze/tests/specs/nursery/noParametersOnlyUsedInRecursion/valid.jscrates/biome_js_analyze/tests/specs/nursery/noParametersOnlyUsedInRecursion/invalid.js
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : Set associated type Options of the rule to the concrete options type from biome_rule_options when options exist; otherwise use ()
Applied to files:
crates/biome_rule_options/src/no_parameters_only_used_in_recursion.rs
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/tests/specs/**/*.jsonc : .jsonc snapshot test files must contain an array of code strings and are interpreted as script (no ESM import/export)
Applied to files:
crates/biome_js_analyze/tests/specs/nursery/noParametersOnlyUsedInRecursion/invalid.jscrates/biome_js_analyze/tests/specs/nursery/noParametersOnlyUsedInRecursion/invalidWithFix.js
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : Documentation must include a ## Examples section with ### Invalid before ### Valid
Applied to files:
crates/biome_js_analyze/tests/specs/nursery/noParametersOnlyUsedInRecursion/invalid.js
🧬 Code graph analysis (2)
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs (2)
crates/biome_js_analyze/tests/specs/nursery/noParametersOnlyUsedInRecursion/invalid.js (1)
obj(46-51)crates/biome_rowan/src/ast/mod.rs (1)
cast_ref(142-151)
crates/biome_rule_options/src/no_parameters_only_used_in_recursion.rs (1)
packages/@biomejs/backend-jsonrpc/src/workspace.ts (1)
NoParametersOnlyUsedInRecursionOptions(8306-8306)
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs
Show resolved
Hide resolved
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs
Outdated
Show resolved
Hide resolved
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs
Outdated
Show resolved
Hide resolved
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs
Outdated
Show resolved
Hide resolved
| parent_function: &AnyJsParameterParentFunction, | ||
| ) -> bool { | ||
| // Check if this node matches our parent function by comparing text ranges | ||
| node.text_trimmed_range() == parent_function.syntax().text_trimmed_range() |
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.
nit: pretty sure you could just compare the syntax nodes directly?
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.
Yes, true
…sion Add name extraction for arrow functions to support recursive calls. The rule now detects named arrow functions (e.g., `const foo = () => ...`) and properly analyzes their parameters for recursive-only usage.
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.
Actionable comments posted: 1
🧹 Nitpick comments (3)
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs (3)
204-235: Replace.to_string()withTokenTextfor better performance.Heap allocations on lines 211, 216, 222, and 228 can be avoided by returning
TokenTextinstead ofString. This function should returnOption<TokenText>(or similar) to eliminate unnecessary allocations during analysis.Apply this pattern:
-fn get_function_name(parent_function: &AnyJsParameterParentFunction) -> Option<String> { +fn get_function_name(parent_function: &AnyJsParameterParentFunction) -> Option<biome_rowan::TokenText> { match parent_function { AnyJsParameterParentFunction::JsFunctionDeclaration(decl) => decl .id() .ok() .and_then(|any_binding| any_binding.as_js_identifier_binding().cloned()) - .and_then(|id| id.name_token().ok()) - .map(|t| t.text_trimmed().to_string()), + .and_then(|id| id.name_token().ok().map(|t| t.text_trimmed())),Note: Update call sites accordingly to work with
TokenTextinstead of&str.
237-275: Arrow function name extraction looks good.This properly walks the AST to find the binding name for recursive arrow detection. The
.to_string()allocation on line 264 should be addressed when refactoringget_function_nameto returnTokenText.
381-387: Consider comparing syntax nodes directly.Instead of comparing text ranges, you could compare the nodes themselves for cleaner code:
fn is_function_boundary( node: &biome_rowan::SyntaxNode<biome_js_syntax::JsLanguage>, parent_function: &AnyJsParameterParentFunction, ) -> bool { - // Check if this node matches our parent function by comparing text ranges - node.text_trimmed_range() == parent_function.syntax().text_trimmed_range() + node == parent_function.syntax() }
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
crates/biome_js_analyze/tests/specs/nursery/noParametersOnlyUsedInRecursion/invalid.js.snapis excluded by!**/*.snapand included by**
📒 Files selected for processing (1)
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs(1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{rs,toml}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Format Rust and TOML files before committing (e.g., via
just f)
Files:
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs
**/*.rs
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Document rules, assists, and their options with inline rustdoc in the Rust source
Files:
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs
🧠 Learnings (12)
📓 Common learnings
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : When banning globals (e.g., console), check semantic model to avoid flagging locally shadowed variables
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : Set associated type Options of the rule to the concrete options type from biome_rule_options when options exist; otherwise use ()
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : Rule names should use no<Concept> when forbidding a single concept (e.g., noDebugger)
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : If a rule provides a code action, add fix_kind to declare_lint_rule! (FixKind::Safe or ::Unsafe)
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/biome_rule_options/lib/**/*.rs : Place per-rule options types in biome_rule_options crate under lib/, one file per rule
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : Rule documentation: first paragraph must be a single line summary
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : Set the language field in declare_lint_rule! to the most appropriate dialect (js/jsx/ts/tsx)
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/lint/nursery/**/*.rs : Place all new rules in the nursery group
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : In declare_lint_rule! macros, set version: "next"
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : Use rule_category! macro to reference the diagnostic category created by declare_lint_rule!
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/lint/nursery/**/*.rs : Place all new rules in the nursery group
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : In declare_lint_rule! macros, set version: "next"
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : When banning globals (e.g., console), check semantic model to avoid flagging locally shadowed variables
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : Use rule_category! macro to reference the diagnostic category created by declare_lint_rule!
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : Rule documentation: first paragraph must be a single line summary
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : Set the language field in declare_lint_rule! to the most appropriate dialect (js/jsx/ts/tsx)
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : Rule names should use no<Concept> when forbidding a single concept (e.g., noDebugger)
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : Provide informative diagnostics: explain what the error is, why it triggers, and what to do (prefer a code action or a note)
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : When using semantic/control-flow services with Ast queries, ensure the rule runs in a phase where the services exist (e.g., use Semantic<> or custom visitor in proper phase)
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/complexity/**/*.rs : Rules in complexity group must have severity: warn or info (prefer info if unsure)
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs
📚 Learning: 2025-09-12T08:06:16.650Z
Learnt from: ematipico
PR: biomejs/biome#7410
File: crates/biome_js_analyze/src/lint/nursery/no_jsx_props_bind.rs:103-149
Timestamp: 2025-09-12T08:06:16.650Z
Learning: In Biome AST traversal, `ancestors().skip(1)` is a reasonable pattern to skip the current node and prevent false positives when searching for ancestor nodes of the same kind.
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 (3)
packages/@biomejs/backend-jsonrpc/src/workspace.ts (2)
FixKind(8002-8002)Severity(9355-9355)crates/biome_rowan/src/ast/mod.rs (1)
cast_ref(142-151)crates/biome_js_analyze/tests/specs/nursery/noParametersOnlyUsedInRecursion/invalid.js (1)
obj(46-51)
⏰ 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). (13)
- GitHub Check: Check JS Files
- GitHub Check: Test (depot-ubuntu-24.04-arm-16)
- GitHub Check: Test (depot-windows-2022-16)
- GitHub Check: Lint project (depot-ubuntu-24.04-arm-16)
- GitHub Check: Check Dependencies
- GitHub Check: Lint project (depot-windows-2022)
- GitHub Check: Documentation
- GitHub Check: Bench (biome_configuration)
- GitHub Check: autofix
- GitHub Check: Bench (biome_js_formatter)
- GitHub Check: Bench (biome_js_analyze)
- GitHub Check: Bench (biome_js_parser)
- GitHub Check: Test Node.js API
🔇 Additional comments (9)
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs (9)
1-13: LGTM!The imports are appropriate for this rule implementation.
14-81: LGTM!Rule declaration follows conventions: version "next", appropriate severity, unsafe fix kind, and clear documentation with examples.
83-189: LGTM!The rule implementation correctly identifies parameters used only in recursion, provides clear diagnostics, and offers an appropriate unsafe fix.
191-202: LGTM!Correctly extracts the parent function from formal and rest parameters.
277-290: LGTM!Clean helper function for identifying function boundaries.
292-308: LGTM!Appropriately skips TypeScript signature types, consistent with existing rules.
310-349: LGTM!Correctly detects recursive calls including
this.method()patterns, and properly uses.omit_parentheses()to handle wrapped expressions.
351-379: LGTM!Properly uses an iterative approach to walk the AST, avoiding stack overflow concerns.
434-467: Logic is sound, depends ontraces_to_parameterfix.This function correctly identifies recursive calls that use the parameter. Once the unbounded recursion in
traces_to_parameteris addressed, this will be robust. The conservative handling of spread arguments is appropriate.
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs
Show resolved
Hide resolved
- Use TokenText instead of String for function names to reduce allocations - Replace text range comparison with direct node comparison in is_function_boundary - Convert traces_to_parameter from recursive to iterative worklist approach to prevent stack overflow
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.
Actionable comments posted: 1
🧹 Nitpick comments (2)
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs (2)
389-445: Consider tracing through logical and conditional operators.Whilst the iterative worklist approach nicely addresses stack overflow concerns,
traces_to_parametercurrently doesn't trace through logical operators (&&,||,??) or conditional expressions (?:). This makes the rule more conservative but may miss legitimate recursive-only usage patterns.Example additions to the worklist loop:
// Logical expressions: a && b, a || b, a ?? b if let Some(logical) = current_expr.as_js_logical_expression() { if let Ok(left) = logical.left() { to_check.push(left); } if let Ok(right) = logical.right() { to_check.push(right); } continue; } // Conditional expressions: cond ? a : b if let Some(cond) = current_expr.as_js_conditional_expression() { if let Ok(cons) = cond.consequent() { to_check.push(cons); } if let Ok(alt) = cond.alternate() { to_check.push(alt); } continue; }
310-349: Optionally handle computed members and optional chaining in recursive calls.
is_recursive_callcurrently recognisesfoo()andthis.foo()but notthis?.foo()(optional chaining) orthis[name]()(computed member). Whilst less common, these patterns do represent valid recursion.To handle optional chaining:
// After checking JsStaticMemberExpression, add: if let Some(member) = expr.as_js_computed_member_expression() { let is_this_call = member .object() .ok() .is_some_and(|obj| obj.as_js_this_expression().is_some()); if is_this_call { // For computed members, we'd need to evaluate if the computed // expression resolves to the function name (complex) // Conservative: skip for now or handle string literals only } }For optional chaining, you'd need to unwrap the optional chain before checking the member expression.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs(1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{rs,toml}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Format Rust and TOML files before committing (e.g., via
just f)
Files:
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs
**/*.rs
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Document rules, assists, and their options with inline rustdoc in the Rust source
Files:
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs
🧠 Learnings (12)
📓 Common learnings
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : When banning globals (e.g., console), check semantic model to avoid flagging locally shadowed variables
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : Set associated type Options of the rule to the concrete options type from biome_rule_options when options exist; otherwise use ()
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : Rule names should use no<Concept> when forbidding a single concept (e.g., noDebugger)
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : If a rule provides a code action, add fix_kind to declare_lint_rule! (FixKind::Safe or ::Unsafe)
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/biome_rule_options/lib/**/*.rs : Place per-rule options types in biome_rule_options crate under lib/, one file per rule
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : Set the language field in declare_lint_rule! to the most appropriate dialect (js/jsx/ts/tsx)
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : In declare_lint_rule! macros, set version: "next"
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/lint/nursery/**/*.rs : Place all new rules in the nursery group
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : Rule documentation: first paragraph must be a single line summary
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : Use rule_category! macro to reference the diagnostic category created by declare_lint_rule!
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/lint/nursery/**/*.rs : Place all new rules in the nursery group
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : In declare_lint_rule! macros, set version: "next"
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : When banning globals (e.g., console), check semantic model to avoid flagging locally shadowed variables
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : Rule documentation: first paragraph must be a single line summary
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : Use rule_category! macro to reference the diagnostic category created by declare_lint_rule!
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : Set the language field in declare_lint_rule! to the most appropriate dialect (js/jsx/ts/tsx)
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : Rule names should use no<Concept> when forbidding a single concept (e.g., noDebugger)
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : Provide informative diagnostics: explain what the error is, why it triggers, and what to do (prefer a code action or a note)
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/complexity/**/*.rs : Rules in complexity group must have severity: warn or info (prefer info if unsure)
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : When using semantic/control-flow services with Ast queries, ensure the rule runs in a phase where the services exist (e.g., use Semantic<> or custom visitor in proper phase)
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs
📚 Learning: 2025-09-12T08:06:16.650Z
Learnt from: ematipico
PR: biomejs/biome#7410
File: crates/biome_js_analyze/src/lint/nursery/no_jsx_props_bind.rs:103-149
Timestamp: 2025-09-12T08:06:16.650Z
Learning: In Biome AST traversal, `ancestors().skip(1)` is a reasonable pattern to skip the current node and prevent false positives when searching for ancestor nodes of the same kind.
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(142-151)crates/biome_js_analyze/tests/specs/nursery/noParametersOnlyUsedInRecursion/invalid.js (1)
obj(46-51)
⏰ 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). (14)
- GitHub Check: Test (depot-ubuntu-24.04-arm-16)
- GitHub Check: Lint project (depot-windows-2022)
- GitHub Check: Test (depot-windows-2022-16)
- GitHub Check: Lint project (depot-ubuntu-24.04-arm-16)
- GitHub Check: Documentation
- GitHub Check: Check Dependencies
- GitHub Check: End-to-end tests
- GitHub Check: Check JS Files
- GitHub Check: autofix
- GitHub Check: Bench (biome_configuration)
- GitHub Check: Bench (biome_js_parser)
- GitHub Check: Test Node.js API
- GitHub Check: Bench (biome_js_analyze)
- GitHub Check: Bench (biome_js_formatter)
🔇 Additional comments (2)
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs (2)
14-81: LGTM!Rule declaration follows all conventions: proper metadata, clear documentation with examples, and appropriate severity/fix kind.
83-189: LGTM!The rule implementation correctly leverages the semantic model to classify parameter references and only triggers when all references occur within recursive calls. The unsafe fix appropriately prefixes the parameter with an underscore.
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs
Show resolved
Hide resolved
…ecursion Add support for detecting recursive arrow functions defined via assignment expressions (e.g., foo = (n) => ...). The rule now extracts the function name from the left-hand side of assignment expressions to properly track recursive calls.
|
I think these comments are worth addressing as well
|
Add support for logical AND (&&), OR (||), and nullish coalescing (??) operators when detecting parameters only used in recursive calls. The rule now correctly identifies parameters that flow through logical operations but are never used meaningfully in the function body.
…Recursion Add support for detecting parameters used only in recursion when they appear in conditional expressions (ternary operator: cond ? a : b). The rule now checks all three parts: test, consequent, and alternate. Added test cases for: - Parameter in consequent position - Parameter in alternate position - Parameter in test condition - Nested conditional expressions
…etersOnlyUsedInRecursion Add support for detecting recursive calls through: - Optional chaining (this?.method()) - Computed member expressions (this["method"]) - Combined optional chaining with computed members (this?.["method"]) The implementation handles string literal property access conservatively, only matching when the computed member is a string literal that matches the function name.
…in noParametersOnlyUsedInRecursion Add documentation examples demonstrating the rule catching parameters only used in recursion with logical operators and optional chaining.
Replace nested if-let statements with let-chain pattern for better readability in computed member name checking.
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
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.
Actionable comments posted: 0
🧹 Nitpick comments (1)
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs (1)
512-516: Minor: Consider adding explicit continue for consistency.The static member access branch doesn't have an explicit
continuestatement unlike the other branches (lines 471, 483, 498, 507). Whilst functionally correct, adding one would match the established pattern.if let Some(member_expr) = current_expr.as_js_static_member_expression() && let Ok(obj) = member_expr.object() { to_check.push(obj); + continue; }
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs(1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{rs,toml}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Format Rust and TOML files before committing (e.g., via
just f)
Files:
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs
**/*.rs
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Document rules, assists, and their options with inline rustdoc in the Rust source
Files:
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs
🧠 Learnings (12)
📓 Common learnings
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : When banning globals (e.g., console), check semantic model to avoid flagging locally shadowed variables
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : Rule names should use no<Concept> when forbidding a single concept (e.g., noDebugger)
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : If a rule provides a code action, add fix_kind to declare_lint_rule! (FixKind::Safe or ::Unsafe)
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/lint/nursery/**/*.rs : Place all new rules in the nursery group
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : Set associated type Options of the rule to the concrete options type from biome_rule_options when options exist; otherwise use ()
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : In declare_lint_rule! macros, set version: "next"
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/complexity/**/*.rs : Rules in complexity group must have severity: warn or info (prefer info if unsure)
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/biome_rule_options/lib/**/*.rs : Place per-rule options types in biome_rule_options crate under lib/, one file per rule
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : Rule documentation: first paragraph must be a single line summary
Learnt from: CR
PR: biomejs/biome#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.
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/lint/nursery/**/*.rs : Place all new rules in the nursery group
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : In declare_lint_rule! macros, set version: "next"
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : Rule documentation: first paragraph must be a single line summary
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : When banning globals (e.g., console), check semantic model to avoid flagging locally shadowed variables
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : Set the language field in declare_lint_rule! to the most appropriate dialect (js/jsx/ts/tsx)
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : Rule names should use no<Concept> when forbidding a single concept (e.g., noDebugger)
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : Use rule_category! macro to reference the diagnostic category created by declare_lint_rule!
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : Provide informative diagnostics: explain what the error is, why it triggers, and what to do (prefer a code action or a note)
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/complexity/**/*.rs : Rules in complexity group must have severity: warn or info (prefer info if unsure)
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : When using semantic/control-flow services with Ast queries, ensure the rule runs in a phase where the services exist (e.g., use Semantic<> or custom visitor in proper phase)
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs
📚 Learning: 2025-09-12T08:06:16.650Z
Learnt from: ematipico
PR: biomejs/biome#7410
File: crates/biome_js_analyze/src/lint/nursery/no_jsx_props_bind.rs:103-149
Timestamp: 2025-09-12T08:06:16.650Z
Learning: In Biome AST traversal, `ancestors().skip(1)` is a reasonable pattern to skip the current node and prevent false positives when searching for ancestor nodes of the same kind.
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs
🔇 Additional comments (6)
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs (6)
14-97: Solid rule declaration and documentation.The metadata follows Biome conventions correctly, and the documentation provides clear examples. Well done on the thorough examples covering various recursion patterns.
99-205: Core rule logic is well-structured.The classification approach (counting recursive vs non-recursive references) is correct, and the delegation to
noUnusedFunctionParametersfor truly unused parameters is sensible. The action implementation properly uses the mutation API.
207-336: Helper functions handle function identification correctly.The arrow function name extraction now properly handles both variable declarators and assignment expressions with appropriate boundary checking. Good work addressing the previous feedback.
474-499: Excellent expansion of tracing coverage.Adding logical operators and conditional expressions addresses the feedback from the PR objectives perfectly. This catches more legitimate recursive-only usage patterns.
441-559: Parameter tracing implementation is robust.The iterative worklist approach avoids recursion depth issues, and the comprehensive handling of expression types ensures accurate detection. Good work on the previous refactoring.
338-401: Original review comment is incorrect.The optional chaining detection is already working correctly. The test fixtures confirm that
this?.count()andthis?.["count"]()are both being detected and flagged as expected. The snapshot output shows diagnostics firing for all three optional chaining test cases (lines 699–713, 730–744, and 792–806). The implementation'sas_js_static_member_expression()andas_js_computed_member_expression()methods properly capture optional chains as written in the comments—no special unwrapping required.
dyc3
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.
Great work! just a couple more housekeeping things
crates/biome_js_analyze/src/lint/nursery/no_parameters_only_used_in_recursion.rs
Show resolved
Hide resolved
Co-authored-by: Carson McManus <[email protected]>
ematipico
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.
Hey @matanshavit
Thank you for implementing this rule. It's a pity that the PR was merged, could you make another one and address my comments?
The problem with this AI thing is that it doesn't fully understand the code base.
Our CST is particular and it contains lot of Result<> the APIs. That's because our parser is recoverable, so some nodes might be buggy while some others don't. As a result, when writing linting rules, it's totally fine writing things like ok()?, and as a side effect, it's expected to have methods that return Option<T>.
Could you please address that with another PR, so the code is inline with the source code of the other rules? Thank you
| /// A parameter that is only passed to recursive calls is effectively unused | ||
| /// and can be removed or replaced with a constant, simplifying the function. | ||
| /// | ||
| /// This rule is inspired by Rust Clippy's `only_used_in_recursion` lint. |
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.
Please remove, it's not needed
| fn is_function_like(node: &biome_rowan::SyntaxNode<biome_js_syntax::JsLanguage>) -> bool { | ||
| use biome_js_syntax::JsSyntaxKind::*; | ||
| matches!( | ||
| node.kind(), | ||
| JS_FUNCTION_DECLARATION | ||
| | JS_FUNCTION_EXPRESSION | ||
| | JS_ARROW_FUNCTION_EXPRESSION | ||
| | JS_METHOD_CLASS_MEMBER | ||
| | JS_METHOD_OBJECT_MEMBER | ||
| | JS_CONSTRUCTOR_CLASS_MEMBER | ||
| ) | ||
| } |
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.
We already have a node called AnyFunctionLike. See if you can see it instead
| for ancestor in arrow_syntax.ancestors() { | ||
| // Skip the arrow function node itself | ||
| if ancestor == *arrow_syntax { | ||
| continue; | ||
| } |
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.
You can remove the first if by using ancestors().skip(1)
| ) | ||
| } | ||
|
|
||
| fn is_function_signature(parent_function: &AnyJsParameterParentFunction) -> bool { |
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.
Can you please add some docstrings?
| ) | ||
| } | ||
|
|
||
| fn is_recursive_call(call: &JsCallExpression, function_name: Option<&TokenText>) -> bool { |
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.
Can you please document this method, especially the business logic behind it? Also, document what function_name is, and why we need to pass it.
Also, lines 343-345 don't make sense. Let's just pass a TokenText. Let the caller take care of it
| false | ||
| } | ||
|
|
||
| /// Enhanced version that checks if any argument traces to parameters |
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.
Enhanced version of what exactly? Can you please reword the docs and explain the business logic?
| /// Enhanced version that checks if any argument traces to parameters | ||
| fn is_recursive_call_with_param_usage( | ||
| call: &JsCallExpression, | ||
| function_name: Option<&TokenText>, |
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.
Still, it doesn't make sense to provide an optional function name
| } | ||
|
|
||
| // Get function name for recursion detection | ||
| let function_name = get_function_name(&parent_function); |
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.
Here you should use the try operator ?
| // Get all references to this parameter | ||
| let all_refs: Vec<_> = binding.all_references(model).collect(); | ||
|
|
||
| // If no references, let noUnusedFunctionParameters handle it | ||
| if all_refs.is_empty() { | ||
| return None; | ||
| } |
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 isn't optimal because you allocate a vector even though you don't need to. all_references returns an interator, and if there aren't elements, the loop at line 141 doesn't trigger.
Can you remove the allocation?
| function_name: Option<&TokenText>, | ||
| parent_function: &AnyJsParameterParentFunction, | ||
| param_name: &str, | ||
| ) -> bool { |
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 function should return Option<bool>, as well as all the other functions that follow. This will have a chain effect on all other functions, but it removes all the let else return that you have in the code, which can be changed using ok()?.
|
Yes, I can definitely address you comments. Let's not close the issue until the code is cleaned up. |
Co-authored-by: Carson McManus <[email protected]>
Notice of AI/LLM Use
The code and natural language in this PR was written primarily with Claude Code, including researching the codebase, planning the changes, writing the code, and creating the pull request.
As the human creating this pull request, I take full responsibility for its contents.
See CONTRIBUTING.md#ai-assistance-notice for more information
Summary
Implements a new lint rule
noParametersOnlyUsedInRecursionthat detects function parameters exclusively used in recursive calls. These parameters are effectively unused and can be removed to simplify function signatures.Implementation: The rule is inspired by Rust Clippy's
only_used_in_recursionlint and adapted for TypeScript. It analyzes function parameters using Biome's semantic model and AST traversal to:Example:
Handles:
n - 1,acc * n)this.method()syntaxDoes not handle:
Actions provided:
Fixes: #6484
Changeset: A changeset has been created documenting this as a
minorchange with the new rule addition.Test Plan
Automated Tests
crates/biome_js_analyze/tests/specs/nursery/noParametersOnlyUsedInRecursion/:Invalid cases (should trigger diagnostics):
factorial(n, acc)whereaccis unusedfn(a, b, c)withbandconly in recursioncountdown(n - step, step)negate(n - 1, !flag)this.count(n - 1, acc)in class methodsValid cases (should NOT trigger):
Fix tests:
Docs
sourcesmetadataThe rule is in the nursery group and will appear in generated documentation with the next release.