Skip to content

Fix DocBlockParamAllowDefaultValueSniff positional mismatch on partial @param lists#58

Merged
dereuromark merged 1 commit intomasterfrom
fix/docblock-param-partial-positional-match
Apr 13, 2026
Merged

Fix DocBlockParamAllowDefaultValueSniff positional mismatch on partial @param lists#58
dereuromark merged 1 commit intomasterfrom
fix/docblock-param-partial-positional-match

Conversation

@dereuromark
Copy link
Copy Markdown
Contributor

Summary

DocBlockParamAllowDefaultValueSniff matched docblock @param tags against the method signature by position (\$methodSignature[\$paramCount++]). When a docblock's @param list omitted intermediate parameters, positional indexing misaligned the comparison and the sniff produced false-positive "missing type" fixes.

Reproduction

/**
 * @param array<string, string> \$row
 * @param list<string> \$errors
 */
private function buildUnit(
    array \$row,
    int \$accountId,
    Property \$property,
    array &\$errors,
): EntityInterface {
}
  • Docblock has 2 @param tags: \$row, \$errors.
  • Signature has 4 params: \$row, \$accountId, \$property, \$errors.
  • Iterating docblock tag \$errors (count=1) mapped to signature slot 1, which is int \$accountId.
  • Sniff concluded \$errors was "missing type int" and rewrote list<string> \$errorslist<string>|int \$errors.
  • DocBlockParamTypeMismatchSniff (which correctly matches by name) then removed the bogus |int.
  • The two sniffs fought pass after pass until phpcbf bailed with FAILED TO FIX.

Fix

Build a \$signatureByName map keyed on the parameter variable name, parse each @param's \$valueNode first, then look up the matching signature entry by \$valueNode->parameterName. Partial or out-of-order docblocks now skip params they don't mention instead of misaligning them against the wrong signature slot.

Test

Added a regression fixture (partialDocBlock method in tests/_data/DocBlockParamAllowDefaultValue/before.php and after.php) that reproduces the infinite fixer loop on master and passes on this branch. Verified by stashing the sniff change and rerunning the test — it fails with the exact bad rewrite (list<string>|int \$errors).

Full suite (91 tests) still green.

…@param lists

When a docblock's @param list omitted intermediate parameters (e.g.
only documenting $row and $errors while skipping $accountId between
them), the sniff matched docblock tags against the method signature
by position. The second @param ($errors) was compared against
signature slot 1 ($accountId, int), producing a false-positive
"missing type int" fix that added `|int` to the documented type.
DocBlockParamTypeMismatchSniff correctly matched by name, removed
the `|int`, and the two sniffs entered an infinite fixer loop
until phpcbf bailed with "FAILED TO FIX".

Index the signature by parameter name and look up each @param by
the parsed valueNode->parameterName instead.
@dereuromark dereuromark merged commit be50a42 into master Apr 13, 2026
4 checks passed
@dereuromark dereuromark deleted the fix/docblock-param-partial-positional-match branch April 13, 2026 14:41
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.

1 participant