Skip to content

Commit

Permalink
Merge pull request #196 from Roave/feature/#4-reuse-scanned-symbols
Browse files Browse the repository at this point in the history
Rewrote plugin so that it does only reload mutated code, instead of re-analyzing whole codebase
  • Loading branch information
Ocramius authored Dec 30, 2022
2 parents 7a600f5 + 99b61ae commit 3724bbe
Show file tree
Hide file tree
Showing 7 changed files with 369 additions and 156 deletions.
34 changes: 16 additions & 18 deletions bin/roave-infection-static-analysis-plugin
Original file line number Diff line number Diff line change
Expand Up @@ -63,27 +63,25 @@ use function var_export;
$arguments = $_SERVER['argv'] ?? [];
[$arguments, $configuration] = CliUtility::extractArgument($arguments, 'psalm-config');

$makeAnalyzer = static function () use ($configuration, $projectPath): ProjectAnalyzer {
RuntimeCaches::clearAll();

$configuration = $configuration ?? $projectPath;
if (is_file($configuration)) {
$config = Config::loadFromXMLFile($configuration, $projectPath);
} else {
$config = Config::getConfigForPath($configuration, $projectPath);
}
RuntimeCaches::clearAll();

$config->setIncludeCollector(new IncludeCollector());
$configuration = $configuration ?? $projectPath;

return new ProjectAnalyzer(
$config,
new Providers(new FileProvider()),
new ReportOptions()
);
};
if (is_file($configuration)) {
$config = Config::loadFromXMLFile($configuration, $projectPath);
} else {
$config = Config::getConfigForPath($configuration, $projectPath);
}

$config->setIncludeCollector(new IncludeCollector());

(new Application(Bootstrapper::bootstrap(
Container::create(),
new RunStaticAnalysisAgainstMutant($makeAnalyzer)
)))->run(new ArgvInput($arguments));
new RunStaticAnalysisAgainstMutant(new ProjectAnalyzer(
$config,
new Providers(new FileProvider()),
new ReportOptions()
))
)))
->run(new ArgvInput($arguments));
})();
1 change: 1 addition & 0 deletions phpcs.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,6 @@
<rule ref="Doctrine">
<!-- properties in psalm config do not use camel-case naming -->
<exclude name="Squiz.NamingConventions.ValidVariableName.NotCamelCaps"/>
<exclude name="Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps"/>
</rule>
</ruleset>
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Psalm\Internal\Analyzer\ProjectAnalyzer;

use function array_key_exists;
use function count;

/**
* @internal
Expand All @@ -16,34 +17,44 @@
*/
class RunStaticAnalysisAgainstMutant
{
/** @var callable(): ProjectAnalyzer */
private $makeFreshAnalyzer;

/**
* Psalm has a lot of state in it, so we need a "fresh psalm" at each analysis - that's why
* a callable factory is injected
*
* @see https://github.com/vimeo/psalm/issues/4117
*
* @param callable(): ProjectAnalyzer $makeFreshAnalyzer
*/
public function __construct(callable $makeFreshAnalyzer)
private bool $alreadyVisitedStubs = false;

public function __construct(private ProjectAnalyzer $projectAnalyzer)
{
$this->makeFreshAnalyzer = $makeFreshAnalyzer;
}

public function isMutantStillValidAccordingToStaticAnalysis(Mutant $mutant): bool
{
$path = $mutant->getFilePath();
$projectAnalyzer = ($this->makeFreshAnalyzer)();
$path = $mutant->getFilePath();
$paths = [$mutant->getFilePath()];
$codebase = $this->projectAnalyzer->getCodebase();

$codebase->invalidateInformationForFile(
$mutant->getMutation()
->getOriginalFilePath(),
);

$codebase->addFilesToAnalyze([$path => $path]);
$codebase->scanFiles();

$projectAnalyzer->checkFile($path);
if (! $this->alreadyVisitedStubs) {
$codebase->config->visitPreloadedStubFiles($codebase);
$codebase->config->visitStubFiles($codebase);
$codebase->config->visitComposerAutoloadFiles($this->projectAnalyzer);

return ! array_key_exists(
$this->alreadyVisitedStubs = true;
}

$codebase->reloadFiles($this->projectAnalyzer, $paths);
$codebase->analyzer->analyzeFiles($this->projectAnalyzer, count($paths), false);

$mutationValid = ! array_key_exists(
$path,
$projectAnalyzer->getCodebase()
->file_reference_provider
->getExistingIssues(),
$codebase->file_reference_provider->getExistingIssues(),
);

$codebase->invalidateInformationForFile($path);

return $mutationValid;
}
}
11 changes: 11 additions & 0 deletions test/asset/MutableProjectStub/psalm.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0"?>
<psalm
xmlns="https://getpsalm.org/schema/config"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://getpsalm.org/schema/config ../../../vendor/vimeo/psalm/config.xsd"
name="Static analysis stubs verifying that stub mutations are not picked up"
>
<projectFiles>
<directory name="."/>
</projectFiles>
</psalm>
5 changes: 5 additions & 0 deletions test/asset/PreloadClassStub/Stub.phpstub
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?php

namespace Roave\InfectionStaticAnalysisAsset\PreloadClassStub;

interface Stub {}
15 changes: 15 additions & 0 deletions test/asset/PreloadClassStub/psalm.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?xml version="1.0"?>
<psalm
xmlns="https://getpsalm.org/schema/config"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://getpsalm.org/schema/config ../../../vendor/vimeo/psalm/config.xsd"
name="Static analysis stubs verifying that stub configuration is picked up"
>
<stubs>
<file name="Stub.phpstub" preloadClasses="true"/>
</stubs>

<projectFiles>
<directory name="."/>
</projectFiles>
</psalm>
Loading

0 comments on commit 3724bbe

Please sign in to comment.