Skip to content

Commit

Permalink
Methods in fluent interfaces are considered impure
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrejmirtes committed Feb 19, 2024
1 parent a018f1e commit b026126
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 0 deletions.
5 changes: 5 additions & 0 deletions src/Reflection/Annotations/AnnotationMethodReflection.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use PHPStan\TrinaryLogic;
use PHPStan\Type\Generic\TemplateTypeMap;
use PHPStan\Type\MixedType;
use PHPStan\Type\ThisType;
use PHPStan\Type\Type;

class AnnotationMethodReflection implements ExtendedMethodReflection
Expand Down Expand Up @@ -122,6 +123,10 @@ public function hasSideEffects(): TrinaryLogic
return TrinaryLogic::createYes();
}

if ((new ThisType($this->declaringClass))->isSuperTypeOf($this->returnType)->yes()) {
return TrinaryLogic::createYes();
}

return TrinaryLogic::createMaybe();
}

Expand Down
5 changes: 5 additions & 0 deletions src/Reflection/Php/PhpMethodReflection.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
use PHPStan\Type\MixedType;
use PHPStan\Type\ObjectWithoutClassType;
use PHPStan\Type\StringType;
use PHPStan\Type\ThisType;
use PHPStan\Type\Type;
use PHPStan\Type\TypehintHelper;
use PHPStan\Type\VoidType;
Expand Down Expand Up @@ -430,6 +431,10 @@ public function hasSideEffects(): TrinaryLogic
return TrinaryLogic::createFromBoolean(!$this->isPure);
}

if ((new ThisType($this->declaringClass))->isSuperTypeOf($this->getReturnType())->yes()) {
return TrinaryLogic::createYes();
}

return TrinaryLogic::createMaybe();
}

Expand Down
29 changes: 29 additions & 0 deletions tests/PHPStan/Analyser/data/impure-method.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

use function PHPStan\Testing\assertType;

/**
* @method $this phpDocReturnThis()
*/
class Foo
{

Expand All @@ -15,6 +18,14 @@ public function voidMethod(): void
$this->fooProp = rand(0, 1);
}

/**
* @return $this
*/
public function returnsThis()
{
$this->fooProp = rand(0, 1);
}

public function ordinaryMethod(): int
{
return 1;
Expand Down Expand Up @@ -51,6 +62,24 @@ public function doFoo(): void
assertType('int', $this->fooProp);
}

public function doFluent(): void
{
$this->fooProp = 1;
assertType('1', $this->fooProp);

$this->returnsThis();
assertType('int', $this->fooProp);
}

public function doFluent2(): void
{
$this->fooProp = 1;
assertType('1', $this->fooProp);

$this->phpDocReturnThis();
assertType('int', $this->fooProp);
}

public function doBar(): void
{
$this->fooProp = 1;
Expand Down

0 comments on commit b026126

Please sign in to comment.