Skip to content

False positive method.unusedParameter for a parameter read only in a catch around new of a class whose constructor has no @throws #15396

Description

@janatjak

Bug report

Since 2.3.0 (bleeding edge), a parameter of a private method that is only read inside a catch block wrapping new Foo() is reported as unused:

Method Bar::readOnlyInCatch() has an unused parameter $param. [method.unusedParameter]

This happens when the constructor of Foo has no @throws tag (so the throw point is implicit via exceptions.implicitThrows: true). At the same time no catch.neverThrown is reported for the same catch, so PHPStan knows the new can throw: the two analyses disagree. Adding @throws to the constructor makes the report disappear. Wrapping a method call instead of new (a method without @throws as well) is fine.

Cause, as far as I can tell: NewHandler::getConstructorThrowPoint() creates the implicit throw point on the synthetic StaticCall it builds for the throw type extensions, not on the New_ expression like the explicit throw points. The synthetic node has no file positions, so VariableFlowBuilder::throws() drops it and the variable liveness analysis behind UnusedMethodParametersRule treats the catch body as unreachable. TryCatchHandler works with the throw points directly, which is why CatchWithUnthrownExceptionRule is consistent with the runtime behaviour.

Fix: phpstan/phpstan-src#6687

Code snippet that reproduces the problem

https://phpstan.org/r/4a23c702-6f19-45cb-ad89-1db12330a9bb

Expected output

No errors.

Did PHPStan help you today? Did it make you happy in any way?

It did: the new unused-parameter rule already pointed at a leftover parameter in our codebase on the first run. This one was the only false positive.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions