Skip to content

Commit

Permalink
Fix uninitialized properties
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrejmirtes committed Jul 3, 2023
1 parent b6b0057 commit fae4e23
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 6 deletions.
13 changes: 7 additions & 6 deletions src/Node/ClassPropertiesNode.php
Original file line number Diff line number Diff line change
Expand Up @@ -256,9 +256,14 @@ private function getMethodsCalledFromConstructor(
$calledOnType = $callScope->resolveTypeByName($methodCallNode->class);
}

$inMethod = $callScope->getFunction();
if (!$inMethod instanceof MethodReflection) {
continue;
}

$methodName = $methodCallNode->name->toString();
if (array_key_exists($methodName, $initializedProperties)) {
foreach ($this->getInitializedProperties($callScope, $initialInitializedProperties) as $propertyName => $isInitialized) {
foreach ($this->getInitializedProperties($callScope, $initializedProperties[$inMethod->getName()] ?? $initialInitializedProperties) as $propertyName => $isInitialized) {
$initializedProperties[$methodName][$propertyName] = $initializedProperties[$methodName][$propertyName]->and($isInitialized);
}
continue;
Expand All @@ -270,14 +275,10 @@ private function getMethodsCalledFromConstructor(
if ($methodReflection->getDeclaringClass()->getName() !== $classReflection->getName()) {
continue;
}
$inMethod = $callScope->getFunction();
if (!$inMethod instanceof MethodReflection) {
continue;
}
if (!in_array($inMethod->getName(), $methods, true)) {
continue;
}
$initializedProperties[$methodName] = $this->getInitializedProperties($callScope, $initialInitializedProperties);
$initializedProperties[$methodName] = $this->getInitializedProperties($callScope, $initializedProperties[$inMethod->getName()] ?? $initialInitializedProperties);
$methods[] = $methodName;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,4 +135,9 @@ public function testAdditionalConstructorsExtension(): void
]);
}

public function testEfabricaLatteBug(): void
{
$this->analyse([__DIR__ . '/data/efabrica-latte-bug.php'], []);
}

}
100 changes: 100 additions & 0 deletions tests/PHPStan/Rules/Properties/data/efabrica-latte-bug.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
<?php // lint >= 7.4

namespace EfabricaLatteBug;

use Nette\Utils\Finder;
use PHPStan\File\FileExcluder;
use SplFileInfo;

final class AnalysedTemplatesRegistry
{
private FileExcluder $fileExcluder;

/** @var string[] */
private array $analysedPaths = [];

private bool $reportUnanalysedTemplates;

/** @var array<string, bool> */
private array $templateFiles = [];

/**
* @param string[] $analysedPaths
*/
public function __construct(FileExcluder $fileExcluder, array $analysedPaths, bool $reportUnanalysedTemplates)
{
$this->fileExcluder = $fileExcluder;
$this->analysedPaths = $analysedPaths;
$this->reportUnanalysedTemplates = $reportUnanalysedTemplates;
foreach ($this->getExistingTemplates() as $file) {
$this->templateFiles[$file] = false;
}
}

public function isExcludedFromAnalysing(string $path): bool
{
return $this->fileExcluder->isExcludedFromAnalysing($path);
}

public function templateAnalysed(string $path): void
{
$path = realpath($path) ?: $path;
$this->templateFiles[$path] = true;
}

/**
* @return string[]
*/
public function getExistingTemplates(): array
{
$files = [];
foreach ($this->analysedPaths as $analysedPath) {
if (!is_dir($analysedPath)) {
continue;
}
/** @var SplFileInfo $file */
foreach (Finder::findFiles('*.latte')->from($analysedPath) as $file) {
$filePath = (string)$file;
if ($this->isExcludedFromAnalysing($filePath)) {
continue;
}
$files[] = $filePath;
}
}
$files = array_unique($files);
sort($files);
return $files;
}

/**
* @return string[]
*/
public function getAnalysedTemplates(): array
{
return array_keys(array_filter($this->templateFiles, function (bool $val) {
return $val;
}));
}

/**
* @return string[]
*/
public function getUnanalysedTemplates(): array
{
return array_keys(array_filter($this->templateFiles, function (bool $val) {
return !$val;
}));
}

/**
* @return string[]
*/
public function getReportedUnanalysedTemplates(): array
{
if ($this->reportUnanalysedTemplates) {
return $this->getUnanalysedTemplates();
} else {
return [];
}
}
}

0 comments on commit fae4e23

Please sign in to comment.