Skip to content

Commit

Permalink
@mixin above classes with __callStatic() creates static methods
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrejmirtes committed Jul 21, 2020
1 parent acb9d70 commit aa38695
Show file tree
Hide file tree
Showing 4 changed files with 149 additions and 1 deletion.
94 changes: 94 additions & 0 deletions src/Reflection/Mixin/MixinMethodReflection.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
<?php declare(strict_types = 1);

namespace PHPStan\Reflection\Mixin;

use PHPStan\Reflection\ClassMemberReflection;
use PHPStan\Reflection\ClassReflection;
use PHPStan\Reflection\MethodReflection;
use PHPStan\TrinaryLogic;
use PHPStan\Type\Type;

class MixinMethodReflection implements MethodReflection
{

private MethodReflection $reflection;

private bool $static;

public function __construct(MethodReflection $reflection, bool $static)
{
$this->reflection = $reflection;
$this->static = $static;
}

public function getDeclaringClass(): ClassReflection
{
return $this->reflection->getDeclaringClass();
}

public function isStatic(): bool
{
return $this->static;
}

public function isPrivate(): bool
{
return $this->reflection->isPrivate();
}

public function isPublic(): bool
{
return $this->reflection->isPublic();
}

public function getDocComment(): ?string
{
return $this->reflection->getDocComment();
}

public function getName(): string
{
return $this->reflection->getName();
}

public function getPrototype(): ClassMemberReflection
{
return $this->reflection->getPrototype();
}

public function getVariants(): array
{
return $this->reflection->getVariants();
}

public function isDeprecated(): TrinaryLogic
{
return $this->reflection->isDeprecated();
}

public function getDeprecatedDescription(): ?string
{
return $this->reflection->getDeprecatedDescription();
}

public function isFinal(): TrinaryLogic
{
return $this->reflection->isFinal();
}

public function isInternal(): TrinaryLogic
{
return $this->reflection->isInternal();
}

public function getThrowType(): ?Type
{
return $this->reflection->getThrowType();
}

public function hasSideEffects(): TrinaryLogic
{
return $this->reflection->hasSideEffects();
}

}
12 changes: 11 additions & 1 deletion src/Reflection/Mixin/MixinMethodsClassReflectionExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,17 @@ private function findMethod(ClassReflection $classReflection, string $methodName
continue;
}

return $type->getMethod($methodName, new OutOfClassScope());
$method = $type->getMethod($methodName, new OutOfClassScope());
$static = $method->isStatic();
if (
!$static
&& $classReflection->hasNativeMethod('__callStatic')
&& !$classReflection->hasNativeMethod('__call')
) {
$static = true;
}

return new MixinMethodReflection($method, $static);
}

foreach ($classReflection->getParents() as $parentClass) {
Expand Down
11 changes: 11 additions & 0 deletions tests/PHPStan/Rules/Methods/CallStaticMethodsRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -362,4 +362,15 @@ public function testBug3448(): void
]);
}

public function testBug3641(): void
{
$this->checkThisOnly = false;
$this->analyse([__DIR__ . '/data/bug-3641.php'], [
[
'Static method Bug3641\Foo::bar() invoked with 1 parameter, 0 required.',
32,
],
]);
}

}
33 changes: 33 additions & 0 deletions tests/PHPStan/Rules/Methods/data/bug-3641.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

namespace Bug3641;

class Foo
{
public function bar(): int
{
return 5;
}
}

/**
* @mixin Foo
*/
class Bar
{
/**
* @param mixed[] $args
* @return mixed
*/
public static function __callStatic(string $method, $args)
{
$instance = new Foo;

return $instance->$method(...$args);
}
}

function (): void {
Bar::bar();
Bar::bar(1);
};

0 comments on commit aa38695

Please sign in to comment.