PHPStan reports wrongly a method as deprecated, because the overwriting method from a trait is not detected
pl-github opened this issue · 10 comments
Bug report
I am using phpstan in combination with phpstan-deprecation-rules and getting false-positives in my test classes since a deprecation annotation has been added to PHPUnit.
The code detecting deprecations in phpstan-deprecation-rules looks good:
$classReflection = $this->reflectionProvider->getClass($referencedClass);
$methodReflection = $classReflection->getMethod($methodName, $scope);
if (!$methodReflection->isDeprecated()->yes()) {
continue;
}
But the $methodReflection is pointing to the method defined in the (TestCase) base class instead of the overwriting method in the ProphecyTrait.
To reproduce this issue easily, I have created a minimal setup.
source file to check
<?php
declare(strict_types=1);
trait MyTrait
{
protected function prophesize(): void
{
echo 'Trait';
}
}
abstract class MyBaseClass
{
/** @deprecated Use MyTrait::prophesize() */
protected function prophesize(): void
{
echo 'Base';
}
}
final class MyClass extends MyBaseClass
{
use MyTrait;
public function callProphesize(): void
{
$this->prophesize(); // wrongly detected deprecation
}
}
phpstan.neon
parameters:
level: max
paths:
- src
includes:
- %rootDir%/../../phpstan/phpstan-deprecation-rules/rules.neon
Expected output
I am expectiong that the $methodReflection variable is pointing to MyTrait::prophesize() so that $methodReflection->isDeprecated()->yes() returns false and no deprecation is detected by phpstan-deprecation-rules.
Did PHPStan help you today? Did it make you happy in any way?
phpstan is a great tool that helps a lot in daily work.
This bug report is missing a link to reproduction at phpstan.org/try.
It will most likely be closed after manual review.
From some very basic debugging, I think this may be an issue in \PHPStan\Reflection\Php\PhpClassReflectionExtension::createMethod in how it finds the phpdoc for a trait method.
As a workaround, you can do the following:
use PHPUnit\Framework\TestCase;
use Prophecy\PhpUnit\ProphecyTrait;
class Test extends TestCase {
use ProphecyTrait {
prophesize as traitProphesize;
}
public function test(): void {
$this->traitProphesize(...);
}
}I tried your workaround, and effectively, all errors about deprecation of prophesize have disappeared.
But, now I have a lot of error about reveal.
$this->a = $this->traitProphesize(A::class);
$this->b = new B($this->a->reveal());With this code, I have this error
Parameter #1 $exception of class B constructor expects A, object given.
I don't know why this happened, but using prophesize from Trait I have not this error but the deprecation error, and if I use the traitProphesize I have this error.
Am I missing something ?
NB : in fact, we also run phpstan in our tests, I think it's not really necessary.
Other than adding this to phpstan's config, I would love to see how we can better solve this.
- # Ignore Prophesize deprecation bug: https://github.com/phpstan/phpstan-deprecation-rules/issues/76
message: '#^Call to deprecated method prophesize\(\) of class Usabilla\\Testing\\ProphecyTestCase#'
path: tests
I do not know how this might help, since we can not enable plugins like phpstan-deprecation-rules in phpstan.org/try, but here you go.
So how is the status on fixing this?
According to https://phpstan.org/writing-php-code/phpdocs-basics#deprecations the way to fix this should be to add @not-deprecated to the trait method. A quick test seems to confirm this.
A regression test would be nice because trait is nontrivial case.
@Khartir To be sure I understand your point correctly.
The solution to fix the deprecation in PHPUnit is to add the @not-deprecated annotation in the Prophecy-PHPUnit package?
@pl-github Yes. PHPStan merges deprecations from parent classes unless told not to by @not-deprecated.
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.