Skip to content

Commit 1557ae1

Browse files
committed
Finalize
1 parent 3f1446e commit 1557ae1

16 files changed

+403
-604
lines changed

psalm-baseline.xml

+36-6
Original file line numberDiff line numberDiff line change
@@ -1367,19 +1367,49 @@
13671367
<code><![CDATA[$this->type_description]]></code>
13681368
</RiskyTruthyFalsyComparison>
13691369
</file>
1370+
<file src="src/Psalm/Internal/Fork/ForkContext.php">
1371+
<InternalClass>
1372+
<code><![CDATA[new ContextChannel($ipcChannel)]]></code>
1373+
<code><![CDATA[new ExitFailure($exception)]]></code>
1374+
<code><![CDATA[new ExitFailure($exception)]]></code>
1375+
<code><![CDATA[new ExitSuccess($returnValue instanceof Future ? $returnValue->await() : $returnValue)]]></code>
1376+
</InternalClass>
1377+
<InternalMethod>
1378+
<code><![CDATA[getResult]]></code>
1379+
<code><![CDATA[new ContextChannel($ipcChannel)]]></code>
1380+
<code><![CDATA[new ExitFailure($exception)]]></code>
1381+
<code><![CDATA[new ExitFailure($exception)]]></code>
1382+
<code><![CDATA[new ExitSuccess($returnValue instanceof Future ? $returnValue->await() : $returnValue)]]></code>
1383+
</InternalMethod>
1384+
<MixedAssignment>
1385+
<code><![CDATA[$callable]]></code>
1386+
<code><![CDATA[$returnValue]]></code>
1387+
</MixedAssignment>
1388+
<MixedFunctionCall>
1389+
<code><![CDATA[$callable(new ContextChannel($ipcChannel))]]></code>
1390+
</MixedFunctionCall>
1391+
<MixedReturnStatement>
1392+
<code><![CDATA[$data->getResult()]]></code>
1393+
</MixedReturnStatement>
1394+
<UnusedVariable>
1395+
<code><![CDATA[$argc]]></code>
1396+
</UnusedVariable>
1397+
</file>
13701398
<file src="src/Psalm/Internal/Fork/Pool.php">
1371-
<PossiblyFalseArgument>
1372-
<code><![CDATA[$buffer]]></code>
1373-
</PossiblyFalseArgument>
1374-
<RiskyTruthyFalsyComparison>
1375-
<code><![CDATA[!$sockets]]></code>
1376-
</RiskyTruthyFalsyComparison>
1399+
<ArgumentTypeCoercion>
1400+
<code><![CDATA[$this->childConnectTimeout]]></code>
1401+
</ArgumentTypeCoercion>
13771402
</file>
13781403
<file src="src/Psalm/Internal/Fork/PsalmRestarter.php">
13791404
<RiskyTruthyFalsyComparison>
13801405
<code><![CDATA[$this->tmpIni]]></code>
13811406
</RiskyTruthyFalsyComparison>
13821407
</file>
1408+
<file src="src/Psalm/Internal/Fork/ScannerTask.php">
1409+
<PossiblyUnusedMethod>
1410+
<code><![CDATA[__construct]]></code>
1411+
</PossiblyUnusedMethod>
1412+
</file>
13831413
<file src="src/Psalm/Internal/LanguageServer/Client/Progress/LegacyProgress.php">
13841414
<RiskyTruthyFalsyComparison>
13851415
<code><![CDATA[empty($message)]]></code>

src/Psalm/Config.php

-8
Original file line numberDiff line numberDiff line change
@@ -1394,14 +1394,6 @@ private static function fromXmlAndPaths(
13941394
return $config;
13951395
}
13961396

1397-
/**
1398-
* @psalm-suppress PropertyTypeCoercion
1399-
* @internal */
1400-
public static function setInstance(self $config): void
1401-
{
1402-
self::$instance = $config;
1403-
}
1404-
14051397
public static function getInstance(): Config
14061398
{
14071399
if (self::$instance) {

src/Psalm/Internal/Analyzer/ProjectAnalyzer.php

+2
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,9 @@ public function __construct(
199199
Providers $providers,
200200
public ?ReportOptions $stdout_report_options = null,
201201
public array $generated_report_options = [],
202+
/** @var int<1, max> */
202203
public int $threads = 1,
204+
/** @var int<1, max> */
203205
public int $scanThreads = 1,
204206
?Progress $progress = null,
205207
?Codebase $codebase = null,

src/Psalm/Internal/Cli/Psalm.php

+4-2
Original file line numberDiff line numberDiff line change
@@ -419,11 +419,12 @@ public static function run(array $argv): void
419419
}
420420
}
421421

422+
/** @return int<1, max> */
422423
public static function getThreads(array $options, Config $config, bool $in_ci, bool $for_scan): int
423424
{
424425
if ($for_scan) {
425426
if (isset($options['scanThreads'])) {
426-
$threads = (int)$options['scanThreads'];
427+
$threads = max(1, (int)$options['scanThreads']);
427428
} elseif (isset($options['debug']) || $in_ci) {
428429
$threads = 1;
429430
} elseif ($config->scan_threads) {
@@ -433,7 +434,7 @@ public static function getThreads(array $options, Config $config, bool $in_ci, b
433434
}
434435
} else {
435436
if (isset($options['threads'])) {
436-
$threads = (int)$options['threads'];
437+
$threads = max(1, (int)$options['threads']);
437438
} elseif (isset($options['debug']) || $in_ci) {
438439
$threads = 1;
439440
} elseif ($config->threads) {
@@ -991,6 +992,7 @@ private static function restart(array $options, int $threads, int $scanThreads,
991992

992993
$overcommit = null;
993994
try {
995+
/** @psalm-suppress RiskyTruthyFalsyComparison */
994996
$overcommit = trim(file_get_contents('/proc/sys/vm/overcommit_memory') ?: '');
995997
} catch (Throwable) {
996998
}

src/Psalm/Internal/Codebase/Analyzer.php

+29-75
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use Psalm\Internal\FileManipulation\FileManipulationBuffer;
1818
use Psalm\Internal\FileManipulation\FunctionDocblockManipulator;
1919
use Psalm\Internal\FileManipulation\PropertyDocblockManipulator;
20+
use Psalm\Internal\Fork\AnalyzerTask;
2021
use Psalm\Internal\Fork\InitAnalyzerTask;
2122
use Psalm\Internal\Fork\Pool;
2223
use Psalm\Internal\Fork\ShutdownAnalyzerTask;
@@ -37,7 +38,6 @@
3738
use function count;
3839
use function explode;
3940
use function implode;
40-
use function intdiv;
4141
use function ksort;
4242
use function number_format;
4343
use function pathinfo;
@@ -300,60 +300,22 @@ private function doAnalysis(ProjectAnalyzer $project_analyzer, int $pool_size):
300300

301301
$codebase = $project_analyzer->getCodebase();
302302

303-
$task_done_closure = $this->taskDoneClosure(...);
303+
$task_done_closure = $this->progress->taskDone(...);
304304

305305
if ($pool_size > 1 && count($this->files_to_analyze) > $pool_size) {
306-
$shuffle_count = $pool_size + 1;
307-
308-
$file_paths = array_values($this->files_to_analyze);
309-
310-
$count = count($file_paths);
311-
/** @var int<0, max> */
312-
$middle = intdiv($count, $shuffle_count);
313-
$remainder = $count % $shuffle_count;
314-
315-
$new_file_paths = [];
316-
317-
for ($i = 0; $i < $shuffle_count; $i++) {
318-
for ($j = 0; $j < $middle; $j++) {
319-
if ($j * $shuffle_count + $i < $count) {
320-
$new_file_paths[] = $file_paths[$j * $shuffle_count + $i];
321-
}
322-
}
323-
324-
if ($remainder) {
325-
$new_file_paths[] = $file_paths[$middle * $shuffle_count + $remainder - 1];
326-
$remainder--;
327-
}
328-
}
329-
330-
$process_file_paths = [];
331-
332-
$i = 0;
333-
334-
foreach ($new_file_paths as $file_path) {
335-
$process_file_paths[$i % $pool_size][] = $file_path;
336-
++$i;
337-
}
338-
339306
// Run analysis one file at a time, splitting the set of
340307
// files up among a given number of child processes.
341308
$pool = new Pool(
342-
$this->config,
343-
$process_file_paths,
344-
InitAnalyzerTask::runStatic(...),
345-
fn(int $_, string $file_path) => self::analysisWorker($this->config, $this->progress, $file_path),
346-
ShutdownAnalyzerTask::getPoolData(...),
347-
$task_done_closure,
309+
$pool_size,
310+
$project_analyzer->progress,
348311
);
349312

350313
$this->progress->debug('Forking analysis' . "\n");
351314

352315
// Wait for all tasks to complete and collect the results.
353-
/**
354-
* @var array<int, WorkerData>
355-
*/
356-
$forked_pool_data = $pool->wait();
316+
$pool->runAll(new InitAnalyzerTask);
317+
$pool->run($this->files_to_analyze, AnalyzerTask::class, $task_done_closure);
318+
$forked_pool_data = $pool->runAll(new ShutdownAnalyzerTask);
357319

358320
$this->progress->debug('Collecting forked analysis results' . "\n");
359321

@@ -467,10 +429,7 @@ private function doAnalysis(ProjectAnalyzer $project_analyzer, int $pool_size):
467429
}
468430
} else {
469431
foreach ($this->files_to_analyze as $file_path => $_) {
470-
self::analysisWorker($this->config, $this->progress, $file_path);
471-
472-
$issues = IssueBuffer::getIssuesDataForFile($file_path);
473-
$task_done_closure($issues);
432+
$task_done_closure(self::analysisWorker($this->config, $this->progress, $file_path));
474433
}
475434
}
476435
}
@@ -1500,41 +1459,22 @@ public function isMethodAlreadyAnalyzed(string $file_path, string $method_id, bo
15001459
return isset($this->analyzed_methods[$file_path][$method_id]);
15011460
}
15021461

1503-
/**
1504-
* @param list<IssueData> $issues
1505-
*/
1506-
private function taskDoneClosure(array $issues): void
1507-
{
1508-
$has_error = false;
1509-
$has_info = false;
1510-
1511-
foreach ($issues as $issue) {
1512-
switch ($issue->severity) {
1513-
case IssueData::SEVERITY_INFO:
1514-
$has_info = true;
1515-
break;
1516-
default:
1517-
$has_error = true;
1518-
break;
1519-
}
1520-
}
1521-
1522-
$this->progress->taskDone($has_error ? 2 : ($has_info ? 1 : 0));
1523-
}
1524-
15251462
/**
15261463
* @internal
1527-
* @return list<IssueData>
15281464
*/
1529-
public static function analysisWorker(Config $config, Progress $progress, string $file_path): array
1465+
public static function analysisWorker(Config $config, Progress $progress, string $file_path): int
15301466
{
15311467
$extension = pathinfo($file_path, PATHINFO_EXTENSION);
15321468

15331469
$file_name = $config->shortenFileName($file_path);
15341470

15351471
$filetype_analyzers = $config->getFiletypeAnalyzers();
15361472
if (isset($filetype_analyzers[$extension])) {
1537-
$file_analyzer = new $filetype_analyzers[$extension](ProjectAnalyzer::getInstance(), $file_path, $file_name);
1473+
$file_analyzer = new $filetype_analyzers[$extension](
1474+
ProjectAnalyzer::getInstance(),
1475+
$file_path,
1476+
$file_name
1477+
);
15381478
} else {
15391479
$file_analyzer = new FileAnalyzer(ProjectAnalyzer::getInstance(), $file_path, $file_name);
15401480
}
@@ -1546,6 +1486,20 @@ public static function analysisWorker(Config $config, Progress $progress, string
15461486
$file_analyzer->clearSourceBeforeDestruction();
15471487
unset($file_analyzer);
15481488

1549-
return IssueBuffer::getIssuesDataForFile($file_path);
1489+
$has_error = false;
1490+
$has_info = false;
1491+
1492+
foreach (IssueBuffer::getIssuesDataForFile($file_path) as $issue) {
1493+
switch ($issue->severity) {
1494+
case IssueData::SEVERITY_INFO:
1495+
$has_info = true;
1496+
break;
1497+
default:
1498+
$has_error = true;
1499+
break;
1500+
}
1501+
}
1502+
1503+
return $has_error ? 2 : ($has_info ? 1 : 0);
15501504
}
15511505
}

src/Psalm/Internal/Codebase/Scanner.php

+10-19
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use Psalm\Internal\ErrorHandler;
1111
use Psalm\Internal\Fork\InitScannerTask;
1212
use Psalm\Internal\Fork\Pool;
13+
use Psalm\Internal\Fork\ScannerTask;
1314
use Psalm\Internal\Fork\ShutdownScannerTask;
1415
use Psalm\Internal\Provider\FileProvider;
1516
use Psalm\Internal\Provider\FileReferenceProvider;
@@ -291,42 +292,32 @@ private function scanFilePaths(int $pool_size): bool
291292
}
292293

293294
if (!$this->is_forked && $pool_size > 1 && count($files_to_scan) > 512) {
294-
$pool_size = ceil(min($pool_size, count($files_to_scan) / 256));
295+
$pool_size = (int) ceil(min($pool_size, count($files_to_scan) / 256));
295296
} else {
296297
$pool_size = 1;
297298
}
298299

299300
$this->progress->expand(count($files_to_scan));
300301
if ($pool_size > 1) {
301-
$process_file_paths = [];
302-
303-
$i = 0;
304-
305-
foreach ($files_to_scan as $file_path) {
306-
$process_file_paths[$i % $pool_size][] = $file_path;
307-
++$i;
308-
}
309-
310302
$this->progress->debug('Forking process for scanning' . PHP_EOL);
311303

312304
// Run scanning one file at a time, splitting the set of
313305
// files up among a given number of child processes.
314306
$pool = new Pool(
315-
$this->config,
316-
$process_file_paths,
317-
InitScannerTask::runStatic(...),
318-
$this->scanAPath(...),
319-
ShutdownScannerTask::getPoolData(...),
320-
function (): void {
321-
$this->progress->taskDone(0);
322-
},
307+
$pool_size,
308+
$this->progress,
323309
);
324310

311+
$pool->runAll(new InitScannerTask);
312+
$pool->run($files_to_scan, ScannerTask::class, function (): void {
313+
$this->progress->taskDone(0);
314+
});
315+
325316
// Wait for all tasks to complete and collect the results.
326317
/**
327318
* @var array<int, PoolData>
328319
*/
329-
$forked_pool_data = $pool->wait();
320+
$forked_pool_data = $pool->runAll(new ShutdownScannerTask);
330321

331322
foreach ($forked_pool_data as $pool_data) {
332323
IssueBuffer::addIssues($pool_data['issues']);

src/Psalm/Internal/Fork/AnalyzerTask.php

+6-2
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,17 @@
1010
use Psalm\Internal\Analyzer\ProjectAnalyzer;
1111
use Psalm\Internal\Codebase\Analyzer;
1212

13-
/** @internal */
13+
/**
14+
* @internal
15+
* @implements Task<int, void, void>
16+
*/
1417
final class AnalyzerTask implements Task
1518
{
19+
/** @psalm-suppress PossiblyUnusedMethod */
1620
public function __construct(private string $file)
1721
{
1822
}
19-
public function run(Channel $channel, Cancellation $cancellation): mixed
23+
public function run(Channel $channel, Cancellation $cancellation): int
2024
{
2125
$pa = ProjectAnalyzer::getInstance();
2226
return Analyzer::analysisWorker($pa->getConfig(), $pa->progress, $this->file);

0 commit comments

Comments
 (0)