Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
51 changes: 51 additions & 0 deletions .github/workflows/e2e-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,57 @@ jobs:
OUTPUT=$(../bashunit assert exit_code "1" "../../bin/phpstan -vvv")
echo "$OUTPUT"
../bashunit assert contains 'Result cache restored.' "$OUTPUT"
- script: |
cd e2e/result-cache-collected-data-rules
OUTPUT=$(../bashunit assert exit_code "1" "../../bin/phpstan analyse -vv --error-format raw")
echo "$OUTPUT"
../bashunit assert contains 'Caller.php:10:Call to function ResultCacheCollectedDataRules\pure() on a separate line has no effect.' "$OUTPUT"
# Nothing changed, so every rule on CollectedDataNode reuses its errors from the result cache.
OUTPUT=$(../bashunit assert exit_code "1" "../../bin/phpstan analyse -vv --error-format raw")
echo "$OUTPUT"
../bashunit assert contains 'Caller.php:10:Call to function ResultCacheCollectedDataRules\pure() on a separate line has no effect.' "$OUTPUT"
echo "$OUTPUT" | grep -E 'Result cache reused the errors of ([0-9]+) of \1 rules on collected data\.'
../bashunit assert contains 'Result cache was not rewritten because it is unchanged.' "$OUTPUT"
# src/Other.php is analysed again, but what it collects stays the same.
echo '// changed' >> src/Other.php
OUTPUT=$(../bashunit assert exit_code "1" "../../bin/phpstan analyse -vv --error-format raw")
echo "$OUTPUT"
../bashunit assert contains 'Result cache restored. 1 file will be reanalysed.' "$OUTPUT"
../bashunit assert contains 'Caller.php:10:Call to function ResultCacheCollectedDataRules\pure() on a separate line has no effect.' "$OUTPUT"
echo "$OUTPUT" | grep -E 'Result cache reused the errors of ([0-9]+) of \1 rules on collected data\.'
# Removing the call changes what src/Caller.php collects, so the rule runs again and the error goes away.
sed -i 's/^\t\tpure();$//' src/Caller.php
OUTPUT=$(../bashunit assert exit_code "0" "../../bin/phpstan analyse -vv --error-format raw")
echo "$OUTPUT"
../bashunit assert not_contains 'on a separate line has no effect' "$OUTPUT"
- script: |
cd e2e/result-cache-collected-data-rules-tracking
composer install
OUTPUT=$(../bashunit assert exit_code "1" "../../bin/phpstan analyse -vv --error-format raw")
echo "$OUTPUT"
../bashunit assert contains 'Controller.php:15:View about not found.' "$OUTPUT"
OUTPUT=$(../bashunit assert exit_code "1" "../../bin/phpstan analyse -vv --error-format raw")
echo "$OUTPUT"
echo "$OUTPUT" | grep -E 'Result cache reused the errors of ([0-9]+) of \1 rules on collected data\.'
# The rule tracks the views directory, so a new view runs it again.
printf 'about\n' > views/about.txt
OUTPUT=$(../bashunit assert exit_code "0" "../../bin/phpstan analyse -vv --error-format raw")
echo "$OUTPUT"
../bashunit assert not_contains 'View about not found.' "$OUTPUT"
rm views/about.txt
OUTPUT=$(../bashunit assert exit_code "1" "../../bin/phpstan analyse -vv --error-format raw")
echo "$OUTPUT"
../bashunit assert contains 'Controller.php:15:View about not found.' "$OUTPUT"
# The rule tracks the file of ignored views too.
printf 'about\n' > ignored-views.txt
OUTPUT=$(../bashunit assert exit_code "0" "../../bin/phpstan analyse -vv --error-format raw")
echo "$OUTPUT"
../bashunit assert not_contains 'View about not found.' "$OUTPUT"
# And the class of extra views, which is not analysed.
sed -i "s/'contact'/'nothing'/" lib/ExtraViews.php
OUTPUT=$(../bashunit assert exit_code "1" "../../bin/phpstan analyse -vv --error-format raw")
echo "$OUTPUT"
../bashunit assert contains 'Controller.php:20:View contact not found.' "$OUTPUT"
- script: |
cd e2e/bug-14514
composer install
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ e2e/bashunit
/e2e/result-cache-moved-tmpdir/tmp-a
/e2e/result-cache-moved-tmpdir/tmp-b
/e2e/result-cache-stale-objects/tmp
/e2e/result-cache-collected-data-rules/tmp
/e2e/result-cache-collected-data-rules-tracking/tmp
/e2e/result-cache-truncated/tmp
/e2e/result-cache-worker-count/tmp
e2e/restart-manager/probe.log
Expand Down
1 change: 1 addition & 0 deletions conf/bleedingEdge.neon
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,4 @@ parameters:
backedEnumFromParameterType: true
unusedVariable: true
unusedParameters: true
reuseCollectedDataRuleErrors: true
1 change: 1 addition & 0 deletions conf/config.neon
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ parameters:
backedEnumFromParameterType: false
unusedVariable: false
unusedParameters: false
reuseCollectedDataRuleErrors: false
fileExtensions:
- php
checkAdvancedIsset: false
Expand Down
1 change: 1 addition & 0 deletions conf/parametersSchema.neon
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ parametersSchema:
backedEnumFromParameterType: bool()
unusedVariable: bool()
unusedParameters: bool()
reuseCollectedDataRuleErrors: bool()
])
fileExtensions: listOf(string())
checkAdvancedIsset: bool()
Expand Down
1 change: 1 addition & 0 deletions e2e/result-cache-collected-data-rules-tracking/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/vendor
5 changes: 5 additions & 0 deletions e2e/result-cache-collected-data-rules-tracking/composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"autoload-dev": {
"classmap": ["extension/"]
}
}
18 changes: 18 additions & 0 deletions e2e/result-cache-collected-data-rules-tracking/composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php declare(strict_types = 1);

namespace ResultCacheCollectedDataRulesTracking;

use PhpParser\Node;
use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Name;
use PhpParser\Node\Scalar\String_;
use PHPStan\Analyser\Scope;
use PHPStan\Collectors\Collector;

/**
* @implements Collector<FuncCall, array{string, int}>
*/
final class ViewCollector implements Collector
{

public function getNodeType(): string
{
return FuncCall::class;
}

public function processNode(Node $node, Scope $scope)
{
if (!$node->name instanceof Name || $node->name->toLowerString() !== 'view') {
return null;
}

$args = $node->getArgs();
if (!isset($args[0]) || !$args[0]->value instanceof String_) {
return null;
}

return [$args[0]->value->value, $node->getStartLine()];
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?php declare(strict_types = 1);

namespace ResultCacheCollectedDataRulesTracking;

use PhpParser\Node;
use PHPStan\Analyser\DependencyTracker;
use PHPStan\Analyser\Scope;
use PHPStan\Node\CollectedDataNode;
use PHPStan\Reflection\ReflectionProvider;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleErrorBuilder;
use function file;
use function in_array;
use function is_file;
use function sprintf;

/**
* Reports a view without a file in the views directory, unless the view is listed in a file of
* ignored views or is a constant of ExtraViews. None of them is analysed, so the rule declares
* all three.
*
* @implements Rule<CollectedDataNode>
*/
final class ViewRule implements Rule
{

public function __construct(
private ReflectionProvider $reflectionProvider,
private string $viewsDirectory,
private string $ignoredViewsFile,
)
{
}

public function getNodeType(): string
{
return CollectedDataNode::class;
}

/**
* @param Scope&DependencyTracker $scope
*/
public function processNode(Node $node, Scope $scope): array
{
$scope->trackDirectoryDependency($this->viewsDirectory, '*.txt');
$scope->trackFileDependency($this->ignoredViewsFile);
$scope->trackClassDependency(ExtraViews::class);

$ignoredViews = file($this->ignoredViewsFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
$extraViews = $this->reflectionProvider->getClass(ExtraViews::class)->getNativeReflection()->getConstants();
$errors = [];
foreach ($node->get(ViewCollector::class) as $file => $views) {
foreach ($views as [$view, $line]) {
if (is_file($this->viewsDirectory . '/' . $view . '.txt') || in_array($view, $ignoredViews, true) || in_array($view, $extraViews, true)) {
continue;
}

$errors[] = RuleErrorBuilder::message(sprintf('View %s not found.', $view))
->file($file)
->line($line)
->identifier('view.notFound')
->build();
}
}

return $errors;
}

}
Empty file.
10 changes: 10 additions & 0 deletions e2e/result-cache-collected-data-rules-tracking/lib/ExtraViews.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php declare(strict_types = 1);

namespace ResultCacheCollectedDataRulesTracking;

class ExtraViews
{

public const CONTACT = 'contact';

}
23 changes: 23 additions & 0 deletions e2e/result-cache-collected-data-rules-tracking/phpstan.neon
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
includes:
- ../../conf/bleedingEdge.neon

parameters:
level: 8
tmpDir: tmp
paths:
- src
scanDirectories:
- lib

services:
-
class: ResultCacheCollectedDataRulesTracking\ViewCollector
tags:
- phpstan.collector
-
class: ResultCacheCollectedDataRulesTracking\ViewRule
arguments:
viewsDirectory: %currentWorkingDirectory%/views
ignoredViewsFile: %currentWorkingDirectory%/ignored-views.txt
tags:
- phpstan.rules.rule
23 changes: 23 additions & 0 deletions e2e/result-cache-collected-data-rules-tracking/src/Controller.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php declare(strict_types = 1);

namespace ResultCacheCollectedDataRulesTracking;

class Controller
{

public function home(): string
{
return view('home');
}

public function about(): string
{
return view('about');
}

public function contact(): string
{
return view('contact');
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php declare(strict_types = 1);

namespace ResultCacheCollectedDataRulesTracking;

function view(string $name): string
{
return $name;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
home
8 changes: 8 additions & 0 deletions e2e/result-cache-collected-data-rules/phpstan.neon
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
includes:
- ../../conf/bleedingEdge.neon

parameters:
level: 8
tmpDir: tmp
paths:
- src
13 changes: 13 additions & 0 deletions e2e/result-cache-collected-data-rules/src/Caller.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php declare(strict_types = 1);

namespace ResultCacheCollectedDataRules;

class Caller
{

public function doFoo(): void
{
pure();
}

}
13 changes: 13 additions & 0 deletions e2e/result-cache-collected-data-rules/src/Other.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php declare(strict_types = 1);

namespace ResultCacheCollectedDataRules;

class Other
{

public function doBar(): int
{
return 1;
}

}
8 changes: 8 additions & 0 deletions e2e/result-cache-collected-data-rules/src/functions.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php declare(strict_types = 1);

namespace ResultCacheCollectedDataRules;

function pure(): int
{
return 1;
}
Loading
Loading