Skip to content
Closed
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion src/Analyser/MutatingScope.php
Original file line number Diff line number Diff line change
Expand Up @@ -1574,7 +1574,7 @@ public function enterPropertyHook(

$realParameterTypes = $this->getRealParameterTypes($hook);

return $this->enterFunctionLike(
$scope = $this->enterFunctionLike(
new PhpMethodFromParserNodeReflection(
$this->getClassReflection(),
$hook,
Expand Down Expand Up @@ -1606,6 +1606,12 @@ public function enterPropertyHook(
),
true,
);

if ($hookName === 'set' && !$this->getClassReflection()->getNativeProperty($propertyName)->getNativeReflection()->hasDefaultValue()) {
$scope = $scope->invalidateExpression(new PropertyInitializationExpr($propertyName));
}

return $scope;
}

private function transformStaticType(Type $type): Type
Expand Down
13 changes: 13 additions & 0 deletions tests/PHPStan/Rules/Variables/IssetRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -526,6 +526,19 @@ public function testBug9503(): void
$this->analyse([__DIR__ . '/data/bug-9503.php'], []);
}

#[RequiresPhp('>= 8.4')]
public function testBug13473(): void
{
$this->treatPhpDocTypesAsCertain = true;

$this->analyse([__DIR__ . '/data/bug-13473.php'], [
[
'Property Bug13473\Bar::$bar in isset() is not nullable nor uninitialized.',
30,
],
]);
}

public function testBug14393(): void
{
$this->treatPhpDocTypesAsCertain = true;
Expand Down
41 changes: 41 additions & 0 deletions tests/PHPStan/Rules/Variables/data/bug-13473.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php // lint >= 8.4

declare(strict_types = 1);

namespace Bug13473;

class Foo {
private(set) int $bar {
get => $this->bar;
set(int $bar) {
if (isset($this->bar)) {
throw new \Exception('bar is set');
}
$this->bar = $bar;
}
}

public function __construct(int $bar)
{
$this->bar = $bar;
}
}

$foo = new Foo(10);

class Bar {
private(set) int $bar = 1 {
get => $this->bar;
set(int $bar) {
if (isset($this->bar)) {
throw new \Exception('bar is set');
}
$this->bar = $bar;
}
}

public function __construct(int $bar)
{
$this->bar = $bar;
}
}
Loading