Check whether the argument at `arg_offset` is a simple variable whose name (without `$`) matches the parameter name, making a hint redundant. Also suppresses hints when the argument is a property access or method call whose trailing identifier matches the parameter name: `foo($this->needle)` for param `$needle`.
(param_name: &str, content: &str, arg_offset: u32)
| 390 | /// call whose trailing identifier matches the parameter name: |
| 391 | /// `foo($this->needle)` for param `$needle`. |
| 392 | fn should_suppress_hint(param_name: &str, content: &str, arg_offset: u32) -> bool { |
| 393 | let rest = &content[arg_offset as usize..]; |
| 394 | |
| 395 | // Case 1: Simple variable `$paramName`. |
| 396 | if let Some(var_rest) = rest.strip_prefix('$') { |
| 397 | let var_name: String = var_rest |
| 398 | .chars() |
| 399 | .take_while(|c| c.is_alphanumeric() || *c == '_') |
| 400 | .collect(); |
| 401 | if eq_ignore_case_snake(&var_name, param_name) { |
| 402 | return true; |
| 403 | } |
| 404 | } |
| 405 | |
| 406 | // Case 2: The argument text ends with `->paramName` or `?->paramName`. |
| 407 | // Find the end of this argument (next comma or closing paren at depth 0). |
| 408 | let arg_text = extract_argument_text(rest); |
| 409 | if let Some(trailing) = extract_trailing_identifier(arg_text) |
| 410 | && eq_ignore_case_snake(trailing, param_name) |
| 411 | { |
| 412 | return true; |
| 413 | } |
| 414 | |
| 415 | // Case 3: Boolean/null literals matching the parameter name pattern. |
| 416 | // `foo(true)` for param `$enabled`, `foo(null)` for param `$default`. |
| 417 | let trimmed = arg_text.trim(); |
| 418 | if matches!( |
| 419 | trimmed, |
| 420 | "true" | "false" | "null" | "TRUE" | "FALSE" | "NULL" |
| 421 | ) { |
| 422 | return false; |
| 423 | } |
| 424 | |
| 425 | // Case 4: String literal whose content matches param name. |
| 426 | // `foo('needle')` for param `$needle`. |
| 427 | if (trimmed.starts_with('\'') || trimmed.starts_with('"')) && trimmed.len() >= 2 { |
| 428 | let quote = trimmed.as_bytes()[0]; |
| 429 | if trimmed.as_bytes().last() == Some("e) { |
| 430 | let inner = &trimmed[1..trimmed.len() - 1]; |
| 431 | if eq_ignore_case_snake(inner, param_name) { |
| 432 | return true; |
| 433 | } |
| 434 | } |
| 435 | } |
| 436 | |
| 437 | false |
| 438 | } |
| 439 | |
| 440 | /// Extract the argument text up to the next top-level comma or closing |
| 441 | /// paren, respecting nesting of `()`, `[]`, and `{}`. |
no test coverage detected