Skip to content

Commit fae4e23

Browse files
committed
Fix uninitialized properties
1 parent b6b0057 commit fae4e23

File tree

3 files changed

+112
-6
lines changed

3 files changed

+112
-6
lines changed

src/Node/ClassPropertiesNode.php

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -256,9 +256,14 @@ private function getMethodsCalledFromConstructor(
256256
$calledOnType = $callScope->resolveTypeByName($methodCallNode->class);
257257
}
258258

259+
$inMethod = $callScope->getFunction();
260+
if (!$inMethod instanceof MethodReflection) {
261+
continue;
262+
}
263+
259264
$methodName = $methodCallNode->name->toString();
260265
if (array_key_exists($methodName, $initializedProperties)) {
261-
foreach ($this->getInitializedProperties($callScope, $initialInitializedProperties) as $propertyName => $isInitialized) {
266+
foreach ($this->getInitializedProperties($callScope, $initializedProperties[$inMethod->getName()] ?? $initialInitializedProperties) as $propertyName => $isInitialized) {
262267
$initializedProperties[$methodName][$propertyName] = $initializedProperties[$methodName][$propertyName]->and($isInitialized);
263268
}
264269
continue;
@@ -270,14 +275,10 @@ private function getMethodsCalledFromConstructor(
270275
if ($methodReflection->getDeclaringClass()->getName() !== $classReflection->getName()) {
271276
continue;
272277
}
273-
$inMethod = $callScope->getFunction();
274-
if (!$inMethod instanceof MethodReflection) {
275-
continue;
276-
}
277278
if (!in_array($inMethod->getName(), $methods, true)) {
278279
continue;
279280
}
280-
$initializedProperties[$methodName] = $this->getInitializedProperties($callScope, $initialInitializedProperties);
281+
$initializedProperties[$methodName] = $this->getInitializedProperties($callScope, $initializedProperties[$inMethod->getName()] ?? $initialInitializedProperties);
281282
$methods[] = $methodName;
282283
}
283284

tests/PHPStan/Rules/Properties/UninitializedPropertyRuleTest.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,4 +135,9 @@ public function testAdditionalConstructorsExtension(): void
135135
]);
136136
}
137137

138+
public function testEfabricaLatteBug(): void
139+
{
140+
$this->analyse([__DIR__ . '/data/efabrica-latte-bug.php'], []);
141+
}
142+
138143
}
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
<?php // lint >= 7.4
2+
3+
namespace EfabricaLatteBug;
4+
5+
use Nette\Utils\Finder;
6+
use PHPStan\File\FileExcluder;
7+
use SplFileInfo;
8+
9+
final class AnalysedTemplatesRegistry
10+
{
11+
private FileExcluder $fileExcluder;
12+
13+
/** @var string[] */
14+
private array $analysedPaths = [];
15+
16+
private bool $reportUnanalysedTemplates;
17+
18+
/** @var array<string, bool> */
19+
private array $templateFiles = [];
20+
21+
/**
22+
* @param string[] $analysedPaths
23+
*/
24+
public function __construct(FileExcluder $fileExcluder, array $analysedPaths, bool $reportUnanalysedTemplates)
25+
{
26+
$this->fileExcluder = $fileExcluder;
27+
$this->analysedPaths = $analysedPaths;
28+
$this->reportUnanalysedTemplates = $reportUnanalysedTemplates;
29+
foreach ($this->getExistingTemplates() as $file) {
30+
$this->templateFiles[$file] = false;
31+
}
32+
}
33+
34+
public function isExcludedFromAnalysing(string $path): bool
35+
{
36+
return $this->fileExcluder->isExcludedFromAnalysing($path);
37+
}
38+
39+
public function templateAnalysed(string $path): void
40+
{
41+
$path = realpath($path) ?: $path;
42+
$this->templateFiles[$path] = true;
43+
}
44+
45+
/**
46+
* @return string[]
47+
*/
48+
public function getExistingTemplates(): array
49+
{
50+
$files = [];
51+
foreach ($this->analysedPaths as $analysedPath) {
52+
if (!is_dir($analysedPath)) {
53+
continue;
54+
}
55+
/** @var SplFileInfo $file */
56+
foreach (Finder::findFiles('*.latte')->from($analysedPath) as $file) {
57+
$filePath = (string)$file;
58+
if ($this->isExcludedFromAnalysing($filePath)) {
59+
continue;
60+
}
61+
$files[] = $filePath;
62+
}
63+
}
64+
$files = array_unique($files);
65+
sort($files);
66+
return $files;
67+
}
68+
69+
/**
70+
* @return string[]
71+
*/
72+
public function getAnalysedTemplates(): array
73+
{
74+
return array_keys(array_filter($this->templateFiles, function (bool $val) {
75+
return $val;
76+
}));
77+
}
78+
79+
/**
80+
* @return string[]
81+
*/
82+
public function getUnanalysedTemplates(): array
83+
{
84+
return array_keys(array_filter($this->templateFiles, function (bool $val) {
85+
return !$val;
86+
}));
87+
}
88+
89+
/**
90+
* @return string[]
91+
*/
92+
public function getReportedUnanalysedTemplates(): array
93+
{
94+
if ($this->reportUnanalysedTemplates) {
95+
return $this->getUnanalysedTemplates();
96+
} else {
97+
return [];
98+
}
99+
}
100+
}

0 commit comments

Comments
 (0)