Skip to content

Commit

Permalink
Fix static magic method pureness not being inherited from traits
Browse files Browse the repository at this point in the history
vimeo#10385 "broke" this by propagating pseudo static methods from traits to using classes.
`AtomicStaticCallAnalyzer` was then not capable of dealing with this, because now these static pseudo methods actually exist.

As long as the methods from traits aren't actually transferred to the using class, it seems right that the logic in `AtomicStaticCallAnalyzer` uses `::getDeclaringMethodId()` instead of `::getAppearingMethodId()` for this purpose.
  • Loading branch information
tscni committed Nov 29, 2023
1 parent 982f95c commit 4f458b4
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -566,12 +566,12 @@ private static function handleNamedCall(
true,
$context->insideUse(),
)) {
$callstatic_appearing_id = $codebase->methods->getAppearingMethodId($callstatic_id);
assert($callstatic_appearing_id !== null);
$callstatic_declaring_id = $codebase->methods->getDeclaringMethodId($callstatic_id);
assert($callstatic_declaring_id !== null);
$callstatic_pure = false;
$callstatic_mutation_free = false;
if ($codebase->methods->hasStorage($callstatic_appearing_id)) {
$callstatic_storage = $codebase->methods->getStorage($callstatic_appearing_id);
if ($codebase->methods->hasStorage($callstatic_declaring_id)) {
$callstatic_storage = $codebase->methods->getStorage($callstatic_declaring_id);
$callstatic_pure = $callstatic_storage->pure;
$callstatic_mutation_free = $callstatic_storage->mutation_free;
}
Expand Down
75 changes: 75 additions & 0 deletions tests/PureAnnotationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,81 @@ function gimmeFoo(): MyEnum
return MyEnum::FOO();
}',
],
'pureThroughCallStaticInTrait' => [
'code' => '<?php
/**
* @method static static foo()
*/
trait TestTrait {
/** @psalm-pure */
public static function __callStatic(string $name, array $params): static
{
throw new BadMethodCallException("not implemented");
}
}
class Test {
use TestTrait;
}
/** @psalm-pure */
function gimmeFoo(): Test
{
return Test::foo();
}',
],
'pureThroughCallStaticInNestedTrait' => [
'code' => '<?php
/**
* @method static static foo()
*/
trait InnerTestTrait {
/** @psalm-pure */
public static function __callStatic(string $name, array $params): static
{
throw new BadMethodCallException("not implemented");
}
}
trait TestTrait {
use InnerTestTrait;
}
class Test {
use TestTrait;
}
/** @psalm-pure */
function gimmeFoo(): Test
{
return Test::foo();
}',
],
'pureThroughAliasedCallStaticInTrait' => [
'code' => '<?php
/**
* @method static static foo()
*/
trait TestTrait {
/** @psalm-pure */
public static function toBeCallStatic(string $name, array $params): static
{
throw new BadMethodCallException("not implemented");
}
}
class Test {
use TestTrait {
TestTrait::toBeCallStatic as __callStatic;
}
}
/** @psalm-pure */
function gimmeFoo(): Test
{
return Test::foo();
}',
],
'dontCrashWhileCheckingPurityOnCallStaticInATrait' => [
'code' => '<?php
/**
Expand Down

0 comments on commit 4f458b4

Please sign in to comment.