1
0
mirror of https://github.com/danog/psalm.git synced 2025-01-21 21:31:13 +01:00

Fix #5297 - be more sensitive to additions and deletions in language server mode

This commit is contained in:
Matt Brown 2021-02-28 01:36:06 -05:00
parent 7db742dee3
commit ad82c93edb
10 changed files with 322 additions and 107 deletions

View File

@ -576,11 +576,6 @@ class Analyzer
$i = 0;
foreach ($this->files_to_analyze as $file_path => $_) {
// Remove all current maps for the file, so new analysis doesn't
// only append to existing data.
unset($this->reference_map[$file_path]);
unset($this->type_map[$file_path]);
unset($this->argument_map[$file_path]);
$analysis_worker($i, $file_path);
++$i;
@ -614,6 +609,7 @@ class Analyzer
$errored_files = $statements_provider->getErrors();
$diff_map = $statements_provider->getDiffMap();
$deletion_ranges = $statements_provider->getDeletionRanges();
$method_references_to_class_members
= $file_reference_provider->getAllMethodReferencesToClassMembers();
@ -774,7 +770,7 @@ class Analyzer
}
}
$this->shiftFileOffsets($diff_map);
$this->shiftFileOffsets($diff_map, $deletion_ranges);
foreach ($this->files_to_analyze as $file_path) {
$file_reference_provider->clearExistingIssuesForFile($file_path);
@ -876,9 +872,9 @@ class Analyzer
/**
* @param array<string, array<int, array{int, int, int, int}>> $diff_map
*
* @param array<string, array<int, array{int, int}>> $deletion_ranges
*/
public function shiftFileOffsets(array $diff_map): void
public function shiftFileOffsets(array $diff_map, array $deletion_ranges): void
{
foreach ($this->existing_issues as $file_path => &$file_issues) {
if (!isset($this->analyzed_methods[$file_path])) {
@ -886,39 +882,36 @@ class Analyzer
}
$file_diff_map = $diff_map[$file_path] ?? [];
$file_deletion_ranges = $deletion_ranges[$file_path] ?? [];
if (!$file_diff_map) {
continue;
}
$first_diff_offset = $file_diff_map[0][0];
$last_diff_offset = $file_diff_map[count($file_diff_map) - 1][1];
foreach ($file_issues as $i => &$issue_data) {
if ($issue_data->to < $first_diff_offset || $issue_data->from > $last_diff_offset) {
unset($file_issues[$i]);
continue;
}
$matched = false;
foreach ($file_diff_map as [$from, $to, $file_offset, $line_offset]) {
if ($issue_data->from >= $from
&& $issue_data->from <= $to
&& !$matched
) {
$issue_data->from += $file_offset;
$issue_data->to += $file_offset;
$issue_data->snippet_from += $file_offset;
$issue_data->snippet_to += $file_offset;
$issue_data->line_from += $line_offset;
$issue_data->line_to += $line_offset;
$matched = true;
if ($file_deletion_ranges) {
foreach ($file_issues as $i => &$issue_data) {
foreach ($file_deletion_ranges as [$from, $to]) {
if ($issue_data->from >= $from
&& $issue_data->from <= $to
) {
unset($file_issues[$i]);
break;
}
}
}
}
if (!$matched) {
unset($file_issues[$i]);
if ($file_diff_map) {
foreach ($file_issues as $issue_data) {
foreach ($file_diff_map as [$from, $to, $file_offset, $line_offset]) {
if ($issue_data->from >= $from
&& $issue_data->from <= $to
) {
$issue_data->from += $file_offset;
$issue_data->to += $file_offset;
$issue_data->snippet_from += $file_offset;
$issue_data->snippet_to += $file_offset;
$issue_data->line_from += $line_offset;
$issue_data->line_to += $line_offset;
break;
}
}
}
}
}
@ -930,26 +923,29 @@ class Analyzer
}
$file_diff_map = $diff_map[$file_path] ?? [];
$file_deletion_ranges = $deletion_ranges[$file_path] ?? [];
if (!$file_diff_map) {
continue;
if ($file_deletion_ranges) {
foreach ($reference_map as $reference_from => $_) {
foreach ($file_deletion_ranges as [$from, $to]) {
if ($reference_from >= $from && $reference_from <= $to) {
unset($reference_map[$reference_from]);
break;
}
}
}
}
$first_diff_offset = $file_diff_map[0][0];
$last_diff_offset = $file_diff_map[count($file_diff_map) - 1][1];
foreach ($reference_map as $reference_from => [$reference_to, $tag]) {
if ($reference_to < $first_diff_offset || $reference_from > $last_diff_offset) {
continue;
}
foreach ($file_diff_map as [$from, $to, $file_offset]) {
if ($reference_from >= $from && $reference_from <= $to) {
unset($reference_map[$reference_from]);
$reference_map[$reference_from += $file_offset] = [
$reference_to += $file_offset,
$tag,
];
if ($file_diff_map) {
foreach ($reference_map as $reference_from => [$reference_to, $tag]) {
foreach ($file_diff_map as [$from, $to, $file_offset]) {
if ($reference_from >= $from && $reference_from <= $to) {
unset($reference_map[$reference_from]);
$reference_map[$reference_from += $file_offset] = [
$reference_to += $file_offset,
$tag,
];
}
}
}
}
@ -962,26 +958,29 @@ class Analyzer
}
$file_diff_map = $diff_map[$file_path] ?? [];
$file_deletion_ranges = $deletion_ranges[$file_path] ?? [];
if (!$file_diff_map) {
continue;
if ($file_deletion_ranges) {
foreach ($type_map as $type_from => $_) {
foreach ($file_deletion_ranges as [$from, $to]) {
if ($type_from >= $from && $type_from <= $to) {
unset($type_map[$type_from]);
break;
}
}
}
}
$first_diff_offset = $file_diff_map[0][0];
$last_diff_offset = $file_diff_map[count($file_diff_map) - 1][1];
foreach ($type_map as $type_from => [$type_to, $tag]) {
if ($type_to < $first_diff_offset || $type_from > $last_diff_offset) {
continue;
}
foreach ($file_diff_map as [$from, $to, $file_offset]) {
if ($type_from >= $from && $type_from <= $to) {
unset($type_map[$type_from]);
$type_map[$type_from += $file_offset] = [
$type_to += $file_offset,
$tag,
];
if ($file_diff_map) {
foreach ($type_map as $type_from => [$type_to, $tag]) {
foreach ($file_diff_map as [$from, $to, $file_offset]) {
if ($type_from >= $from && $type_from <= $to) {
unset($type_map[$type_from]);
$type_map[$type_from += $file_offset] = [
$type_to += $file_offset,
$tag,
];
}
}
}
}
@ -994,27 +993,30 @@ class Analyzer
}
$file_diff_map = $diff_map[$file_path] ?? [];
$file_deletion_ranges = $deletion_ranges[$file_path] ?? [];
if (!$file_diff_map) {
continue;
if ($file_deletion_ranges) {
foreach ($argument_map as $argument_from => $_) {
foreach ($file_deletion_ranges as [$from, $to]) {
if ($argument_from >= $from && $argument_from <= $to) {
unset($argument_map[$argument_from]);
break;
}
}
}
}
$first_diff_offset = $file_diff_map[0][0];
$last_diff_offset = $file_diff_map[count($file_diff_map) - 1][1];
foreach ($argument_map as $argument_from => [$argument_to, $method_id, $argument_number]) {
if ($argument_to < $first_diff_offset || $argument_from > $last_diff_offset) {
continue;
}
foreach ($file_diff_map as [$from, $to, $file_offset]) {
if ($argument_from >= $from && $argument_from <= $to) {
unset($argument_map[$argument_from]);
$argument_map[$argument_from += $file_offset] = [
$argument_to += $file_offset,
$method_id,
$argument_number,
];
if ($file_diff_map) {
foreach ($argument_map as $argument_from => [$argument_to, $method_id, $argument_number]) {
foreach ($file_diff_map as [$from, $to, $file_offset]) {
if ($argument_from >= $from && $argument_from <= $to) {
unset($argument_map[$argument_from]);
$argument_map[$argument_from += $file_offset] = [
$argument_to += $file_offset,
$method_id,
$argument_number,
];
}
}
}
}

View File

@ -54,7 +54,8 @@ use function substr;
* issues:array<string, list<IssueData>>,
* changed_members:array<string, array<string, bool>>,
* unchanged_signature_members:array<string, array<string, bool>>,
* diff_map:array<string, array<int, array{0:int, 1:int, 2:int, 3:int}>>,
* diff_map:array<string, array<int, array{int, int, int, int}>>,
* deletion_ranges:array<string, array<int, array{int, int}>>,
* errors:array<string, bool>,
* classlike_storage:array<string, \Psalm\Storage\ClassLikeStorage>,
* file_storage:array<lowercase-string, \Psalm\Storage\FileStorage>,
@ -381,6 +382,7 @@ class Scanner
'changed_members' => $statements_provider->getChangedMembers(),
'unchanged_signature_members' => $statements_provider->getUnchangedSignatureMembers(),
'diff_map' => $statements_provider->getDiffMap(),
'deletion_ranges' => $statements_provider->getDeletionRanges(),
'errors' => $statements_provider->getErrors(),
'classlike_storage' => $codebase->classlike_storage_provider->getAll(),
'file_storage' => $codebase->file_storage_provider->getAll(),
@ -410,6 +412,9 @@ class Scanner
$this->codebase->statements_provider->addDiffMap(
$pool_data['diff_map']
);
$this->codebase->statements_provider->addDeletionRanges(
$pool_data['deletion_ranges']
);
$this->codebase->statements_provider->addErrors($pool_data['errors']);
if ($this->codebase->taint_flow_graph && $pool_data['taint_data']) {

View File

@ -24,7 +24,8 @@ class ClassStatementsDiffer extends AstDiffer
* 0: list<string>,
* 1: list<string>,
* 2: list<string>,
* 3: array<int, array{0: int, 1: int, 2: int, 3: int}>
* 3: array<int, array{int, int, int, int}>,
* 4: list<array{int, int}>
* }
*/
public static function diff(string $name, array $a, array $b, string $a_code, string $b_code): array
@ -187,6 +188,7 @@ class ClassStatementsDiffer extends AstDiffer
$keep = [];
$keep_signature = [];
$add_or_delete = [];
$deletion_ranges = [];
foreach ($diff as $diff_elem) {
if ($diff_elem->type === DiffElem::TYPE_KEEP) {
@ -214,7 +216,7 @@ class ClassStatementsDiffer extends AstDiffer
}
}
} elseif ($diff_elem->type === DiffElem::TYPE_REMOVE || $diff_elem->type === DiffElem::TYPE_ADD) {
/** @psalm-suppress MixedAssignment */
/** @var PhpParser\Node */
$affected_elem = $diff_elem->type === DiffElem::TYPE_REMOVE ? $diff_elem->old : $diff_elem->new;
if ($affected_elem instanceof PhpParser\Node\Stmt\ClassMethod) {
$add_or_delete[] = strtolower($name) . '::' . strtolower((string) $affected_elem->name);
@ -231,10 +233,23 @@ class ClassStatementsDiffer extends AstDiffer
$add_or_delete[] = strtolower($name . '&' . (string) $trait->getAttribute('resolvedName'));
}
}
if ($diff_elem->type === DiffElem::TYPE_REMOVE) {
if ($doc = $affected_elem->getDocComment()) {
$start = $doc->getStartFilePos();
} else {
$start = (int)$affected_elem->getAttribute('startFilePos');
}
$deletion_ranges[] = [
$start,
(int)$affected_elem->getAttribute('endFilePos')
];
}
}
}
/** @var array<int, array{0: int, 1: int, 2: int, 3: int}> $diff_map */
return [$keep, $keep_signature, $add_or_delete, $diff_map];
/** @var array<int, array{int, int, int, int}> $diff_map */
return [$keep, $keep_signature, $add_or_delete, $diff_map, $deletion_ranges];
}
}

View File

@ -21,7 +21,8 @@ class FileStatementsDiffer extends AstDiffer
* 0: list<string>,
* 1: list<string>,
* 2: list<string>,
* 3: list<array{0: int, 1: int, 2: int, 3: int}>
* 3: list<array{int, int, int, int}>,
* 4: list<array{int, int}>
* }
*/
public static function diff(array $a, array $b, string $a_code, string $b_code): array
@ -85,6 +86,7 @@ class FileStatementsDiffer extends AstDiffer
$keep_signature = [];
$add_or_delete = [];
$diff_map = [];
$deletion_ranges = [];
foreach ($diff as $diff_elem) {
if ($diff_elem->type === DiffElem::TYPE_KEEP) {
@ -103,6 +105,7 @@ class FileStatementsDiffer extends AstDiffer
$keep_signature = array_merge($keep_signature, $namespace_keep[1]);
$add_or_delete = array_merge($add_or_delete, $namespace_keep[2]);
$diff_map = array_merge($diff_map, $namespace_keep[3]);
$deletion_ranges = array_merge($deletion_ranges, $namespace_keep[4]);
} elseif (($diff_elem->old instanceof PhpParser\Node\Stmt\Class_
&& $diff_elem->new instanceof PhpParser\Node\Stmt\Class_)
|| ($diff_elem->old instanceof PhpParser\Node\Stmt\Interface_
@ -122,6 +125,7 @@ class FileStatementsDiffer extends AstDiffer
$keep_signature = array_merge($keep_signature, $class_keep[1]);
$add_or_delete = array_merge($add_or_delete, $class_keep[2]);
$diff_map = array_merge($diff_map, $class_keep[3]);
$deletion_ranges = array_merge($deletion_ranges, $class_keep[4]);
}
} elseif ($diff_elem->type === DiffElem::TYPE_REMOVE) {
if ($diff_elem->old instanceof PhpParser\Node\Stmt\Use_
@ -136,6 +140,19 @@ class FileStatementsDiffer extends AstDiffer
$add_or_delete[] = 'use:' . end($name_parts);
}
}
} elseif ($diff_elem->old instanceof PhpParser\Node
&& !$diff_elem->old instanceof PhpParser\Node\Stmt\Namespace_
) {
if ($doc = $diff_elem->old->getDocComment()) {
$start = $doc->getStartFilePos();
} else {
$start = (int)$diff_elem->old->getAttribute('startFilePos');
}
$deletion_ranges[] = [
$start,
(int)$diff_elem->old->getAttribute('endFilePos')
];
}
} elseif ($diff_elem->type === DiffElem::TYPE_ADD) {
if ($diff_elem->new instanceof PhpParser\Node\Stmt\Use_
@ -154,6 +171,6 @@ class FileStatementsDiffer extends AstDiffer
}
}
return [$keep, $keep_signature, $add_or_delete, $diff_map];
return [$keep, $keep_signature, $add_or_delete, $diff_map, $deletion_ranges];
}
}

View File

@ -21,7 +21,8 @@ class NamespaceStatementsDiffer extends AstDiffer
* 0: list<string>,
* 1: list<string>,
* 2: list<string>,
* 3: list<array{0: int, 1: int, 2: int, 3: int}>
* 3: list<array{int, int, int, int}>,
* 4: list<array{int, int}>
* }
*/
public static function diff(string $name, array $a, array $b, string $a_code, string $b_code): array
@ -86,6 +87,7 @@ class NamespaceStatementsDiffer extends AstDiffer
$keep_signature = [];
$add_or_delete = [];
$diff_map = [];
$deletion_ranges = [];
foreach ($diff as $diff_elem) {
if ($diff_elem->type === DiffElem::TYPE_KEEP) {
@ -108,6 +110,7 @@ class NamespaceStatementsDiffer extends AstDiffer
$keep_signature = array_merge($keep_signature, $class_keep[1]);
$add_or_delete = array_merge($add_or_delete, $class_keep[2]);
$diff_map = array_merge($diff_map, $class_keep[3]);
$deletion_ranges = array_merge($deletion_ranges, $class_keep[4]);
}
} elseif ($diff_elem->type === DiffElem::TYPE_REMOVE) {
if ($diff_elem->old instanceof PhpParser\Node\Stmt\Use_
@ -140,6 +143,6 @@ class NamespaceStatementsDiffer extends AstDiffer
}
}
return [$keep, $keep_signature, $add_or_delete, $diff_map];
return [$keep, $keep_signature, $add_or_delete, $diff_map, $deletion_ranges];
}
}

View File

@ -17,7 +17,7 @@ use function substr_count;
*/
class PartialParserVisitor extends PhpParser\NodeVisitorAbstract
{
/** @var array<int, array{0: int, 1: int, 2: int, 3: int, 4:int}> */
/** @var array<int, array{int, int, int, int, int}> */
private $offset_map;
/** @var bool */
@ -41,7 +41,7 @@ class PartialParserVisitor extends PhpParser\NodeVisitorAbstract
/** @var PhpParser\ErrorHandler\Collecting */
private $error_handler;
/** @param array<int, array{0: int, 1: int, 2: int, 3: int, 4:int}> $offset_map */
/** @param array<int, array{int, int, int, int, int}> $offset_map */
public function __construct(
PhpParser\Parser $parser,
PhpParser\ErrorHandler\Collecting $error_handler,

View File

@ -37,7 +37,7 @@ class SimpleNameResolver extends NodeVisitorAbstract
* namespacedName attribute, as usual.)
*
* @param ErrorHandler $errorHandler Error handler
* @param array<int, array{0: int, 1: int, 2: int, 3: int}> $offset_map
* @param array<int, array{int, int, int, int}> $offset_map
*/
public function __construct(ErrorHandler $errorHandler, ?array $offset_map = null)
{

View File

@ -61,10 +61,15 @@ class StatementsProvider
private $errors = [];
/**
* @var array<string, array<int, array{0: int, 1: int, 2: int, 3: int}>>
* @var array<string, array<int, array{int, int, int, int}>>
*/
private $diff_map = [];
/**
* @var array<string, array<int, array{int, int}>>
*/
private $deletion_ranges = [];
/**
* @var PhpParser\Lexer|null
*/
@ -185,7 +190,7 @@ class StatementsProvider
);
if ($existing_file_contents && $existing_statements && (!$has_errors || $stmts)) {
[$unchanged_members, $unchanged_signature_members, $changed_members, $diff_map]
[$unchanged_members, $unchanged_signature_members, $changed_members, $diff_map, $deletion_ranges]
= \Psalm\Internal\Diff\FileStatementsDiffer::diff(
$existing_statements,
$stmts,
@ -270,6 +275,7 @@ class StatementsProvider
}
$this->diff_map[$file_path] = $diff_map;
$this->deletion_ranges[$file_path] = $deletion_ranges;
} elseif ($has_errors && !$stmts) {
$this->errors[$file_path] = true;
}
@ -282,6 +288,7 @@ class StatementsProvider
} else {
$from_cache = true;
$this->diff_map[$file_path] = [];
$this->deletion_ranges[$file_path] = [];
}
$this->parser_cache_provider->saveStatementsToCache($file_path, $file_content_hash, $stmts, $from_cache);
@ -349,10 +356,14 @@ class StatementsProvider
if (!isset($this->diff_map[$file_path])) {
$this->diff_map[$file_path] = [];
}
if (!isset($this->deletion_ranges[$file_path])) {
$this->deletion_ranges[$file_path] = [];
}
}
/**
* @return array<string, array<int, array{0: int, 1: int, 2: int, 3: int}>>
* @return array<string, array<int, array{int, int, int, int}>>
*/
public function getDiffMap(): array
{
@ -360,7 +371,15 @@ class StatementsProvider
}
/**
* @param array<string, array<int, array{0: int, 1: int, 2: int, 3: int}>> $diff_map
* @return array<string, array<int, array{int, int}>>
*/
public function getDeletionRanges(): array
{
return $this->deletion_ranges;
}
/**
* @param array<string, array<int, array{int, int, int, int}>> $diff_map
*
*/
public function addDiffMap(array $diff_map): void
@ -368,12 +387,22 @@ class StatementsProvider
$this->diff_map = array_merge($diff_map, $this->diff_map);
}
/**
* @param array<string, array<int, array{int, int}>> $deletion_ranges
*
*/
public function addDeletionRanges(array $deletion_ranges): void
{
$this->deletion_ranges = array_merge($deletion_ranges, $this->deletion_ranges);
}
public function resetDiffs(): void
{
$this->changed_members = [];
$this->unchanged_members = [];
$this->unchanged_signature_members = [];
$this->diff_map = [];
$this->deletion_ranges = [];
}
/**

View File

@ -22,7 +22,8 @@ class FileDiffTest extends TestCase
array $same_methods,
array $same_signatures,
array $changed_methods,
array $diff_map_offsets
array $diff_map_offsets,
array $deletion_ranges
): void {
if (strpos($this->getTestName(), 'SKIPPED-') !== false) {
$this->markTestSkipped();
@ -65,6 +66,8 @@ class FileDiffTest extends TestCase
);
$this->assertSame($diff_map_offsets, $found_offsets);
$this->assertSame($deletion_ranges, $diff[4]);
}
/**
@ -199,7 +202,7 @@ class FileDiffTest extends TestCase
}
/**
* @return array<string,array{string,string,string[],string[],string[],array<array-key,array{int,int}>}>
* @return array<string,array{string,string,string[],string[],string[],array<array-key,array{int,int}>,list<array{int,int}>}>
*/
public function getChanges(): array
{
@ -239,6 +242,7 @@ class FileDiffTest extends TestCase
[],
[],
[[0, 0], [0, 0], [0, 0], [0, 0]],
[],
],
'sameFileWithDoubleDocblocks' => [
'<?php
@ -293,6 +297,7 @@ class FileDiffTest extends TestCase
[],
[],
[[0, 0], [0, 0], [0, 0], [0, 0]],
[],
],
'lineChanges' => [
'<?php
@ -334,6 +339,7 @@ class FileDiffTest extends TestCase
[],
[],
[[1, 1], [2, 2], [2, 2], [5, 5]],
[],
],
'simpleBodyChangeWithoutSignatureChange' => [
'<?php
@ -362,6 +368,7 @@ class FileDiffTest extends TestCase
['foo\a::foo'],
[],
[[1, 0]],
[],
],
'simpleBodyChangesWithoutSignatureChange' => [
'<?php
@ -391,6 +398,7 @@ class FileDiffTest extends TestCase
['foo\a::foo'],
[],
[[32, 1]],
[],
],
'simpleBodyChangeWithSignatureChange' => [
'<?php
@ -419,6 +427,7 @@ class FileDiffTest extends TestCase
[],
['foo\a::bar', 'foo\a::bar'],
[[0, 0]],
[[182, 258]],
],
'propertyChange' => [
'<?php
@ -437,6 +446,7 @@ class FileDiffTest extends TestCase
[],
['foo\a::$a', 'foo\a::$b'],
[],
[[84, 93]],
],
'propertyDefaultChange' => [
'<?php
@ -455,6 +465,7 @@ class FileDiffTest extends TestCase
['foo\a::$a'],
[],
[],
[],
],
'propertyDefaultAddition' => [
'<?php
@ -473,6 +484,7 @@ class FileDiffTest extends TestCase
['foo\a::$a'],
[],
[],
[],
],
'propertySignatureChange' => [
'<?php
@ -493,6 +505,7 @@ class FileDiffTest extends TestCase
[],
['foo\a::$a', 'foo\a::$a'],
[],
[[84, 133]],
],
'propertyStaticChange' => [
'<?php
@ -513,6 +526,7 @@ class FileDiffTest extends TestCase
[],
['foo\a::$a', 'foo\a::$a'],
[],
[[84, 140]],
],
'propertyVisibilityChange' => [
'<?php
@ -533,6 +547,7 @@ class FileDiffTest extends TestCase
[],
['foo\a::$a', 'foo\a::$a'],
[],
[[84, 133]],
],
'addDocblockToFirst' => [
'<?php
@ -564,6 +579,7 @@ class FileDiffTest extends TestCase
[],
['foo\a::foo', 'foo\a::foo'],
[[84, 3]],
[[84, 160]],
],
'addDocblockToSecond' => [
'<?php
@ -595,6 +611,7 @@ class FileDiffTest extends TestCase
[],
['foo\a::bar', 'foo\a::bar'],
[[0, 0]],
[[182, 258]],
],
'removeDocblock' => [
'<?php
@ -626,6 +643,7 @@ class FileDiffTest extends TestCase
[],
['foo\a::bar', 'foo\a::bar'],
[[0, 0]],
[[182, 342]],
],
'changeDocblock' => [
'<?php
@ -660,6 +678,7 @@ class FileDiffTest extends TestCase
[],
['foo\a::bar', 'foo\a::bar'],
[[0, 0]],
[[182, 344]],
],
'changeMethodVisibility' => [
'<?php
@ -688,6 +707,7 @@ class FileDiffTest extends TestCase
[],
['foo\a::bar', 'foo\a::bar'],
[[0, 0]],
[[182, 258]],
],
'removeFunctionAtEnd' => [
'<?php
@ -737,6 +757,7 @@ class FileDiffTest extends TestCase
[],
['foo\a::bat'],
[[0, 0], [0, 0]],
[[450, 610]],
],
'addSpaceInFunction' => [
'<?php
@ -811,6 +832,7 @@ class FileDiffTest extends TestCase
['foo\a::bar'],
[],
[[0, 0], [4, 4]],
[],
],
'removeSpaceInFunction' => [
'<?php
@ -885,6 +907,7 @@ class FileDiffTest extends TestCase
['foo\a::bar'],
[],
[[0, 0], [-4, -4]],
[],
],
'removeFunctionAtBeginning' => [
'<?php
@ -916,6 +939,7 @@ class FileDiffTest extends TestCase
[],
['foo\a::foo'],
[[-98, -3], [-98, -3]],
[[84, 160]],
],
'removeFunctionInMiddle' => [
'<?php
@ -947,6 +971,7 @@ class FileDiffTest extends TestCase
[],
['foo\a::bar'],
[[0, 0], [-98, -3]],
[[182, 258]],
],
'changeNamespace' => [
'<?php
@ -972,6 +997,7 @@ class FileDiffTest extends TestCase
[],
[],
[],
[],
],
'removeNamespace' => [
'<?php
@ -995,6 +1021,7 @@ class FileDiffTest extends TestCase
[],
[],
[],
[],
],
'newFunctionAtEnd' => [
'<?php
@ -1044,6 +1071,7 @@ class FileDiffTest extends TestCase
[],
['foo\a::bat'],
[[0, 0], [0, 0]],
[],
],
'newFunctionAtBeginning' => [
'<?php
@ -1093,6 +1121,7 @@ class FileDiffTest extends TestCase
[],
['foo\a::bat'],
[[183, 7], [183, 7]],
[],
],
'newFunctionInMiddle' => [
'<?php
@ -1142,6 +1171,7 @@ class FileDiffTest extends TestCase
[],
['foo\a::bat'],
[[0, 0], [183, 7]],
[],
],
'removeAdditionalComments' => [
'<?php
@ -1191,6 +1221,7 @@ class FileDiffTest extends TestCase
[],
['use:D', 'use:E', 'foo\a::foo', 'foo\a::bar', 'foo\a::foo', 'foo\a::bar'],
[],
[[84, 304], [327, 547]],
],
'SKIPPED-whiteSpaceOnly' => [
'<?php
@ -1221,6 +1252,7 @@ class FileDiffTest extends TestCase
[],
[],
[],
[],
],
'changeDeclaredMethodId' => [
'<?php
@ -1255,6 +1287,7 @@ class FileDiffTest extends TestCase
[],
['foo\b::__construct', 'foo\b::bar'],
[[0, 0], [0, 0], [120, 2]],
[],
],
'sameTrait' => [
'<?php
@ -1291,6 +1324,7 @@ class FileDiffTest extends TestCase
[],
[],
[[0, 0], [0, 0], [0, 0], [0, 0]],
[],
],
'traitPropertyChange' => [
'<?php
@ -1309,6 +1343,7 @@ class FileDiffTest extends TestCase
[],
['foo\t::$a', 'foo\t::$b'],
[],
[[84, 93]],
],
'traitMethodReturnTypeChange' => [
'<?php
@ -1339,6 +1374,7 @@ class FileDiffTest extends TestCase
[],
['foo\t::barbar', 'foo\t::barbar'],
[[-9, 0]],
[[96, 199]],
],
'removeManyArguments' => [
'<?php
@ -1374,6 +1410,7 @@ class FileDiffTest extends TestCase
['foo\c::barbar'],
[],
[[-36, -1]],
[],
],
'docblockTwiceOver' => [
'<?php
@ -1424,6 +1461,7 @@ class FileDiffTest extends TestCase
[],
['bar\foo::b'],
[[0, 0], [229, 8]],
[],
],
'removeStatementsAbove' => [
'<?php
@ -1473,6 +1511,7 @@ class FileDiffTest extends TestCase
],
[],
[],
[],
],
'removeUse' => [
'<?php
@ -1497,6 +1536,7 @@ class FileDiffTest extends TestCase
[],
['use:Exception'],
[[-36, -2]],
[],
],
'addDocblockToFirstFunctionStatement' => [
'<?php
@ -1526,6 +1566,7 @@ class FileDiffTest extends TestCase
['foo\c::foo'],
[],
[],
[],
],
'vimeoDiff' => [
'<?php
@ -1596,6 +1637,7 @@ class FileDiffTest extends TestCase
[],
['c\a::foo', 'c\a::bar', 'c\a::zap', 'c\a::top', 'c\a::rot', 'c\a::bar'],
[],
[[124, 405], [432, 711], [738, 1016], [1043, 1284]],
],
'noUseChange' => [
'<?php
@ -1634,6 +1676,7 @@ class FileDiffTest extends TestCase
['a\c::foo'],
[],
[],
[],
],
'diffMultipleBadDocblocks' => [
'<?php
@ -1708,6 +1751,7 @@ class FileDiffTest extends TestCase
[],
['foo\a::foo', 'foo\a::bar', 'foo\a::foo', 'foo\a::bar'],
[[-6, 0]],
[[116, 428], [455, 756]],
],
];
}

View File

@ -100,4 +100,104 @@ class FileMapTest extends \Psalm\Tests\TestCase
$type_map
);
}
public function testMapIsUpdatedAfterEditingMethod(): void
{
$codebase = $this->project_analyzer->getCodebase();
$codebase->diff_methods = true;
$config = $codebase->config;
$config->throw_exception = false;
$this->addFile(
'somefile.php',
'<?php
namespace Foo;
class A {
public function first(\DateTimeImmutable $d) : void {
echo $d->format("Y");
echo "\n";
}
public function second(\DateTimeImmutable $d) : void {
echo $d->format("Y");
}
}'
);
$codebase->file_provider->openFile('somefile.php');
$codebase->addFilesToAnalyze(['somefile.php' => 'somefile.php']);
$codebase->scanFiles();
$codebase->analyzer->analyzeFiles($this->project_analyzer, 1, false);
[$before] = $codebase->analyzer->getMapsForFile('somefile.php');
$codebase->addTemporaryFileChanges(
'somefile.php',
'<?php
namespace Foo;
class A {
public function first(\DateTimeImmutable $d) : void {
echo $d->format("Y");
echo "\n";
}
public function second(\DateTimeImmutable $d) : void {
echo $d->format("Y");
}
}'
);
$codebase->reloadFiles($this->project_analyzer, ['somefile.php']);
$codebase->analyzer->analyzeFiles($this->project_analyzer, 1, false);
[$after] = $codebase->analyzer->getMapsForFile('somefile.php');
$this->assertCount(\count($before), $after);
}
public function testMapIsUpdatedAfterDeletingMethod(): void
{
$codebase = $this->project_analyzer->getCodebase();
$codebase->diff_methods = true;
$config = $codebase->config;
$config->throw_exception = false;
$this->addFile(
'somefile.php',
'<?php
namespace Foo;
class A {
public function first(\DateTimeImmutable $d) : void {
echo $d->format("Y");
echo "\n";
}
public function second(\DateTimeImmutable $d) : void {
echo $d->format("Y");
}
}'
);
$codebase->file_provider->openFile('somefile.php');
$codebase->addFilesToAnalyze(['somefile.php' => 'somefile.php']);
$codebase->scanFiles();
$codebase->analyzer->analyzeFiles($this->project_analyzer, 1, false);
$this->assertCount(8, $codebase->analyzer->getMapsForFile('somefile.php')[0]);
$codebase->addTemporaryFileChanges(
'somefile.php',
'<?php
namespace Foo;
class A {
public function second(\DateTimeImmutable $d) : void {
echo $d->format("Y");
}
}'
);
$codebase->reloadFiles($this->project_analyzer, ['somefile.php']);
$codebase->analyzer->analyzeFiles($this->project_analyzer, 1, false);
$this->assertCount(4, $codebase->analyzer->getMapsForFile('somefile.php')[0]);
}
}