Skip to content

Commit 47dd35c

Browse files
committed
Merge remote-tracking branch 'origin/master' into fix_empty_list_assertions
2 parents d504ad6 + 0ba7380 commit 47dd35c

15 files changed

+199
-85
lines changed

UPGRADING.md

+16
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,22 @@
22

33
## Changed
44

5+
- [BC] The `startScanningFiles`, `startAnalyzingFiles`, `startAlteringFiles` of `Psalm\Progress\Progress` and subclasses were removed and replaced with a new `startPhase` method, taking a `Psalm\Progress\Phase` enum case.
6+
7+
- [BC] The `start` method was removed, use `expand`, instead; the progress is reset to 0 when changing the current phase.
8+
9+
- [BC] Method `doesTerminalSupportUtf8` of class `Psalm\Progress\Progress` became final
10+
11+
- [BC] Method debug() of class Psalm\Progress\Progress changed from concrete to abstract
12+
13+
- [BC] Method alterFileDone() of class Psalm\Progress\Progress changed from concrete to abstract
14+
15+
- [BC] Method expand() of class Psalm\Progress\Progress changed from concrete to abstract
16+
17+
- [BC] Method taskDone() of class Psalm\Progress\Progress changed from concrete to abstract
18+
19+
- [BC] Method finish() of class Psalm\Progress\Progress changed from concrete to abstract
20+
521
- [BC] The return type of Psalm\Type::getListAtomic() changed from Psalm\Type\Atomic\TKeyedArray to the non-covariant Psalm\Type\Atomic\TKeyedArray|Psalm\Type\Atomic\TArray
622

723
- [BC] The return type of Psalm\Type::getListAtomic() changed from Psalm\Type\Atomic\TKeyedArray to Psalm\Type\Atomic\TKeyedArray|Psalm\Type\Atomic\TArray

src/Psalm/Internal/Analyzer/ProjectAnalyzer.php

+9-8
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
use Psalm\Issue\UnusedProperty;
4848
use Psalm\Issue\UnusedVariable;
4949
use Psalm\Plugin\EventHandler\Event\AfterCodebasePopulatedEvent;
50+
use Psalm\Progress\Phase;
5051
use Psalm\Progress\Progress;
5152
use Psalm\Progress\VoidProgress;
5253
use Psalm\Report;
@@ -461,7 +462,7 @@ public function check(string $base_dir, bool $is_diff = false): void
461462
}
462463

463464
$this->progress->write($this->generatePHPVersionMessage());
464-
$this->progress->startScanningFiles();
465+
$this->progress->startPhase(Phase::SCAN);
465466

466467
$diff_no_files = false;
467468

@@ -519,7 +520,7 @@ public function check(string $base_dir, bool $is_diff = false): void
519520
$this->config->eventDispatcher->dispatchAfterCodebasePopulated($event);
520521
}
521522

522-
$this->progress->startAnalyzingFiles();
523+
$this->progress->startPhase(Phase::ANALYSIS);
523524

524525
$this->codebase->analyzer->analyzeFiles(
525526
$this,
@@ -875,15 +876,15 @@ public function checkDir(string $dir_name): void
875876
$this->checkDirWithConfig($dir_name, $this->config, true);
876877

877878
$this->progress->write($this->generatePHPVersionMessage());
878-
$this->progress->startScanningFiles();
879+
$this->progress->startPhase(Phase::SCAN);
879880

880881
$this->config->initializePlugins($this);
881882

882883
$this->codebase->scanFiles($this->scanThreads);
883884

884885
$this->config->visitStubFiles($this->codebase, $this->progress);
885886

886-
$this->progress->startAnalyzingFiles();
887+
$this->progress->startPhase(Phase::ANALYSIS);
887888

888889
$this->codebase->analyzer->analyzeFiles(
889890
$this,
@@ -975,15 +976,15 @@ public function checkFile(string $file_path): void
975976
$this->file_reference_provider->loadReferenceCache();
976977

977978
$this->progress->write($this->generatePHPVersionMessage());
978-
$this->progress->startScanningFiles();
979+
$this->progress->startPhase(Phase::SCAN);
979980

980981
$this->config->initializePlugins($this);
981982

982983
$this->codebase->scanFiles($this->scanThreads);
983984

984985
$this->config->visitStubFiles($this->codebase, $this->progress);
985986

986-
$this->progress->startAnalyzingFiles();
987+
$this->progress->startPhase(Phase::ANALYSIS);
987988

988989
$this->codebase->analyzer->analyzeFiles(
989990
$this,
@@ -999,7 +1000,7 @@ public function checkFile(string $file_path): void
9991000
public function checkPaths(array $paths_to_check): void
10001001
{
10011002
$this->progress->write($this->generatePHPVersionMessage());
1002-
$this->progress->startScanningFiles();
1003+
$this->progress->startPhase(Phase::SCAN);
10031004

10041005
$this->config->visitPreloadedStubFiles($this->codebase, $this->progress);
10051006
$this->visitAutoloadFiles();
@@ -1031,7 +1032,7 @@ public function checkPaths(array $paths_to_check): void
10311032

10321033
$this->config->eventDispatcher->dispatchAfterCodebasePopulated($event);
10331034

1034-
$this->progress->startAnalyzingFiles();
1035+
$this->progress->startPhase(Phase::ANALYSIS);
10351036

10361037
$this->codebase->analyzer->analyzeFiles(
10371038
$this,

src/Psalm/Internal/Cli/Psalm.php

+4
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
use Psalm\Exception\ConfigException;
1414
use Psalm\Internal\Analyzer\ProjectAnalyzer;
1515
use Psalm\Internal\CliUtils;
16+
use Psalm\Internal\Codebase\InternalCallMapHandler;
1617
use Psalm\Internal\Codebase\ReferenceMapGenerator;
1718
use Psalm\Internal\Composer;
1819
use Psalm\Internal\ErrorHandler;
@@ -389,6 +390,9 @@ public static function run(array $argv): void
389390
$config->addPluginPath($plugin_path);
390391
}
391392

393+
// Prime cache
394+
InternalCallMapHandler::getCallMap();
395+
392396
if ($paths_to_check === null) {
393397
$project_analyzer->check($current_dir, $is_diff);
394398
} elseif ($paths_to_check) {

src/Psalm/Internal/Codebase/Analyzer.php

+4-3
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
use Psalm\Internal\Provider\FileProvider;
2626
use Psalm\Internal\Provider\FileStorageProvider;
2727
use Psalm\IssueBuffer;
28+
use Psalm\Progress\Phase;
2829
use Psalm\Progress\Progress;
2930
use Psalm\Type;
3031
use Psalm\Type\Union;
@@ -247,7 +248,7 @@ public function analyzeFiles(
247248
$scanned_files = $codebase->scanner->getScannedFiles();
248249

249250
if ($codebase->taint_flow_graph) {
250-
$codebase->taint_flow_graph->connectSinksAndSources();
251+
$codebase->taint_flow_graph->connectSinksAndSources($codebase->progress);
251252
}
252253

253254
$this->progress->finish();
@@ -280,7 +281,7 @@ public function analyzeFiles(
280281
}
281282

282283
if ($alter_code) {
283-
$this->progress->startAlteringFiles();
284+
$this->progress->startPhase(Phase::ALTERING);
284285

285286
$project_analyzer->prepareMigration();
286287

@@ -296,7 +297,7 @@ public function analyzeFiles(
296297

297298
private function doAnalysis(ProjectAnalyzer $project_analyzer, int $pool_size): void
298299
{
299-
$this->progress->start(count($this->files_to_analyze));
300+
$this->progress->expand(count($this->files_to_analyze));
300301

301302
ksort($this->files_to_analyze);
302303

src/Psalm/Internal/Codebase/TaintFlowGraph.php

+8-1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
use Psalm\Issue\TaintedUserSecret;
3232
use Psalm\Issue\TaintedXpath;
3333
use Psalm\IssueBuffer;
34+
use Psalm\Progress\Phase;
35+
use Psalm\Progress\Progress;
3436
use Psalm\Type\TaintKind;
3537

3638
use function array_diff;
@@ -202,8 +204,10 @@ public function getIssueTrace(DataFlowNode $source): array
202204
return [$node];
203205
}
204206

205-
public function connectSinksAndSources(): void
207+
public function connectSinksAndSources(Progress $progress): void
206208
{
209+
$progress->startPhase(Phase::TAINT_GRAPH_RESOLUTION);
210+
207211
$visited_source_ids = [];
208212

209213
$sources = $this->sources;
@@ -217,6 +221,7 @@ public function connectSinksAndSources(): void
217221
$new_sources = [];
218222

219223
ksort($sources);
224+
$progress->expand(count($sources));
220225

221226
foreach ($sources as $source) {
222227
$source_taints = $source->taints;
@@ -234,6 +239,8 @@ public function connectSinksAndSources(): void
234239
$visited_source_ids,
235240
)];
236241
}
242+
243+
$progress->taskDone(0);
237244
}
238245

239246
$sources = $new_sources;

src/Psalm/Internal/LanguageServer/Progress.php

+26
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
namespace Psalm\Internal\LanguageServer;
66

77
use Override;
8+
use Psalm\Progress\Phase;
89
use Psalm\Progress\Progress as Base;
910

1011
use function str_replace;
@@ -30,6 +31,31 @@ public function debug(string $message): void
3031
}
3132
}
3233

34+
#[Override]
35+
public function startPhase(Phase $phase): void
36+
{
37+
}
38+
39+
#[Override]
40+
public function alterFileDone(string $file_name): void
41+
{
42+
}
43+
44+
#[Override]
45+
public function expand(int $number_of_tasks): void
46+
{
47+
}
48+
49+
#[Override]
50+
public function taskDone(int $level): void
51+
{
52+
}
53+
54+
#[Override]
55+
public function finish(): void
56+
{
57+
}
58+
3359
#[Override]
3460
public function write(string $message): void
3561
{

src/Psalm/Internal/Preloader.php

+6-3
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@
44

55
namespace Psalm\Internal;
66

7+
use Psalm\Progress\Phase;
78
use Psalm\Progress\Progress;
89

910
use function class_exists;
1011

11-
use const PHP_EOL;
12+
use function count;
1213

1314
/** @internal */
1415
final class Preloader
@@ -21,13 +22,15 @@ public static function preload(?Progress $progress = null, bool $hasJit = false)
2122
}
2223

2324
if ($hasJit) {
24-
$progress?->write("JIT compilation in progress... ");
25+
$progress?->startPhase(Phase::JIT_COMPILATION);
26+
$progress?->expand(count(PreloaderList::CLASSES)+1);
2527
}
2628
foreach (PreloaderList::CLASSES as $class) {
29+
$progress?->taskDone(0);
2730
class_exists($class);
2831
}
2932
if ($hasJit) {
30-
$progress?->write("Done.".PHP_EOL.PHP_EOL);
33+
$progress?->finish();
3134
}
3235
self::$preloaded = true;
3336
}

src/Psalm/Progress/DebugProgress.php

+15-6
Original file line numberDiff line numberDiff line change
@@ -25,21 +25,30 @@ public function debug(string $message): void
2525
}
2626

2727
#[Override]
28-
public function startScanningFiles(): void
28+
public function startPhase(Phase $phase): void
29+
{
30+
$this->write(match ($phase) {
31+
Phase::SCAN => "\nScanning files...\n\n",
32+
Phase::ANALYSIS => "\nAnalyzing files...\n",
33+
Phase::ALTERING => "\nUpdating files...\n",
34+
Phase::TAINT_GRAPH_RESOLUTION => "\nResolving taint graph...\n",
35+
Phase::JIT_COMPILATION => "\nJIT compilation in progress...\n",
36+
});
37+
}
38+
39+
#[Override]
40+
public function expand(int $number_of_tasks): void
2941
{
30-
$this->write("\n" . 'Scanning files...' . "\n\n");
3142
}
3243

3344
#[Override]
34-
public function startAnalyzingFiles(): void
45+
public function taskDone(int $level): void
3546
{
36-
$this->write("\n" . 'Analyzing files...' . "\n");
3747
}
3848

3949
#[Override]
40-
public function startAlteringFiles(): void
50+
public function finish(): void
4151
{
42-
$this->write('Updating files...' . "\n");
4352
}
4453

4554
#[Override]

src/Psalm/Progress/DefaultProgress.php

+17-15
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66

77
use Override;
88

9+
use function hrtime;
910
use function max;
10-
use function microtime;
1111
use function str_repeat;
1212
use function strlen;
1313

@@ -17,32 +17,35 @@ class DefaultProgress extends LongProgress
1717

1818
// Update the progress bar at most once per 0.1 seconds.
1919
// This reduces flickering and reduces the amount of time spent writing to STDERR and updating the terminal.
20-
private const PROGRESS_BAR_SAMPLE_INTERVAL = 0.1;
20+
private const PROGRESS_BAR_SAMPLE_INTERVAL_NANOSECONDS = 100_000_000;
2121

22-
/** @var float the last time when the progress bar UI was updated */
23-
private float $previous_update_time = 0.0;
22+
/** the last time when the progress bar UI was updated (seconds) */
23+
private int $previous_update_seconds = 0;
24+
25+
/** the last time when the progress bar UI was updated (nanoseconds) */
26+
private int $previous_update_nseconds = 0;
2427

2528
#[Override]
2629
public function taskDone(int $level): void
2730
{
2831
if ($this->fixed_size && $this->number_of_tasks > self::TOO_MANY_FILES) {
2932
++$this->progress;
3033

31-
// Source for rate limiting:
32-
// https://github.com/phan/phan/blob/9a788581ee1a4e1c35bebf89c435fd8a238c1d17/src/Phan/CLI.php
33-
$time = microtime(true);
34+
[$seconds, $nseconds] = hrtime();
3435

3536
// If not enough time has elapsed, then don't update the progress bar.
3637
// Making the update frequency based on time (instead of the number of files)
3738
// prevents the terminal from rapidly flickering while processing small/empty files,
3839
// and reduces the time spent writing to stderr.
39-
if ($time - $this->previous_update_time < self::PROGRESS_BAR_SAMPLE_INTERVAL) {
40-
// Make sure to output the section for 100% completion regardless of limits, to avoid confusion.
41-
if ($this->progress !== $this->number_of_tasks) {
42-
return;
43-
}
40+
// Make sure to output the section for 100% completion regardless of limits, to avoid confusion.
41+
if ($seconds === $this->previous_update_seconds
42+
&& ($nseconds - $this->previous_update_nseconds < self::PROGRESS_BAR_SAMPLE_INTERVAL_NANOSECONDS)
43+
&& $this->progress !== $this->number_of_tasks
44+
) {
45+
return;
4446
}
45-
$this->previous_update_time = $time;
47+
$this->previous_update_seconds = $seconds;
48+
$this->previous_update_nseconds = $nseconds;
4649

4750
$inner_progress = self::renderInnerProgressBar(
4851
self::NUMBER_OF_COLUMNS,
@@ -103,8 +106,7 @@ public function finish(): void
103106
{
104107
if ($this->number_of_tasks > self::TOO_MANY_FILES) {
105108
$this->write(str_repeat(' ', self::NUMBER_OF_COLUMNS + strlen($this->getOverview()) + 1) . "\r");
106-
} else {
107-
parent::finish();
108109
}
110+
parent::finish();
109111
}
110112
}

0 commit comments

Comments
 (0)