mirror of
https://github.com/danog/psalm.git
synced 2024-11-30 04:39:00 +01:00
Track more changes and invalidate more methods
This commit is contained in:
parent
89c04ec1ae
commit
1d26332d77
@ -181,8 +181,9 @@ class Analyzer
|
||||
|
||||
$statements_provider = $project_checker->codebase->statements_provider;
|
||||
|
||||
$unchanged_methods = $statements_provider->getUnchangedMembers();
|
||||
$unchanged_signature_methods = $statements_provider->getUnchangedSignatureMembers();
|
||||
$unchanged_members = $statements_provider->getUnchangedMembers();
|
||||
$changed_members = $statements_provider->getChangedMembers();
|
||||
$unchanged_signature_members = $statements_provider->getUnchangedSignatureMembers();
|
||||
$diff_map = $statements_provider->getDiffMap();
|
||||
|
||||
$method_map = [];
|
||||
@ -193,25 +194,28 @@ class Analyzer
|
||||
}
|
||||
}
|
||||
|
||||
$all_referencing_methods = \Psalm\Provider\FileReferenceProvider::getMethodsReferencing();
|
||||
|
||||
$newly_invalidated_methods = [];
|
||||
|
||||
foreach ($changed_members as $file_changed_members) {
|
||||
foreach ($file_changed_members as $member_id => $_) {
|
||||
if (isset($all_referencing_methods[$member_id])) {
|
||||
$newly_invalidated_methods = array_merge($all_referencing_methods[$member_id]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->correct_methods as $file_path => $correct_methods) {
|
||||
foreach ($correct_methods as $correct_method_id => $_) {
|
||||
if (isset($unchanged_methods[$file_path])
|
||||
&& !isset($unchanged_methods[$file_path][$correct_method_id])
|
||||
if (isset($newly_invalidated_methods[$correct_method_id])) {
|
||||
unset($this->correct_methods[$file_path][$correct_method_id]);
|
||||
}
|
||||
|
||||
if (isset($unchanged_members[$file_path])
|
||||
&& !isset($unchanged_members[$file_path][$correct_method_id])
|
||||
) {
|
||||
unset($this->correct_methods[$file_path][$correct_method_id]);
|
||||
|
||||
if (!isset($unchanged_signature_methods[$file_path][$correct_method_id])) {
|
||||
$referencing_methods = \Psalm\Provider\FileReferenceProvider::getMethodsReferencingClassMember(
|
||||
$correct_method_id
|
||||
);
|
||||
|
||||
foreach ($referencing_methods as $method_id => $_) {
|
||||
if (isset($method_map[$method_id])) {
|
||||
$method_file_path = $method_map[$method_id];
|
||||
unset($this->correct_methods[$method_file_path][$method_id]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,12 @@ class ClassStatementsDiffer extends Differ
|
||||
* @param PhpParser\Node\Stmt[] $a
|
||||
* @param PhpParser\Node\Stmt[] $b New array
|
||||
*
|
||||
* @return array{0:array<int, string>, 1:array<int, string>, 2: array<int, array{0: int, 1: int, 2: int, 3: int}>}
|
||||
* @return array{
|
||||
* 0: array<int, string>,
|
||||
*. 1: array<int, string>,
|
||||
* 2: array<int, string>,
|
||||
* 3: array<int, array{0: int, 1: int, 2: int, 3: int}>
|
||||
* }
|
||||
*/
|
||||
public static function diff(string $name, array $a, array $b, string $a_code, string $b_code)
|
||||
{
|
||||
@ -94,6 +99,17 @@ class ClassStatementsDiffer extends Differ
|
||||
$signature_change = $signature_change
|
||||
|| substr($a_code, $a_start, $a_stmts_start - $a_start)
|
||||
!== substr($b_code, $b_start, $b_stmts_start - $b_start);
|
||||
} elseif ($a instanceof PhpParser\Node\Stmt\Property && $b instanceof PhpParser\Node\Stmt\Property) {
|
||||
if (count($a->props) !== 1 || count($b->props) !== 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((string) $a->props[0]->name !== (string) $b->props[0]->name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$body_change = substr($a_code, $a_comments_end, $a_end - $a_comments_end)
|
||||
!== substr($b_code, $b_comments_end, $b_end - $b_comments_end);
|
||||
} else {
|
||||
$signature_change = true;
|
||||
}
|
||||
@ -114,6 +130,7 @@ class ClassStatementsDiffer extends Differ
|
||||
|
||||
$keep = [];
|
||||
$keep_signature = [];
|
||||
$delete = [];
|
||||
|
||||
foreach ($diff as $diff_elem) {
|
||||
if ($diff_elem->type === DiffElem::TYPE_KEEP) {
|
||||
@ -136,9 +153,21 @@ class ClassStatementsDiffer extends Differ
|
||||
$keep_signature[] = strtolower($name) . '::$' . $prop->name;
|
||||
}
|
||||
}
|
||||
} elseif ($diff_elem->type === DiffElem::TYPE_REMOVE) {
|
||||
if ($diff_elem->old instanceof PhpParser\Node\Stmt\ClassMethod) {
|
||||
$delete[] = strtolower($name) . '::' . strtolower((string) $diff_elem->old->name);
|
||||
} elseif ($diff_elem->old instanceof PhpParser\Node\Stmt\Property) {
|
||||
foreach ($diff_elem->old->props as $prop) {
|
||||
$delete[] = strtolower($name) . '::$' . $prop->name;
|
||||
}
|
||||
} elseif ($diff_elem->old instanceof PhpParser\Node\Stmt\ClassConst) {
|
||||
foreach ($diff_elem->old->consts as $const) {
|
||||
$delete[] = strtolower($name) . '::' . $const->name;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return [$keep, $keep_signature, $diff_map];
|
||||
return [$keep, $keep_signature, $delete, $diff_map];
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,12 @@ class FileStatementsDiffer extends Differ
|
||||
* @param PhpParser\Node\Stmt[] $a
|
||||
* @param PhpParser\Node\Stmt[] $b New array
|
||||
*
|
||||
* @return array{0:array<int, string>, 1:array<int, string>, 2: array<int, array{0: int, 1: int, 2: int, 3: int}>}
|
||||
* @return array{
|
||||
* 0: array<int, string>,
|
||||
*. 1: array<int, string>,
|
||||
* 2: array<int, string>,
|
||||
* 3: array<int, array{0: int, 1: int, 2: int, 3: int}>
|
||||
* }
|
||||
*/
|
||||
public static function diff(array $a, array $b, string $a_code, string $b_code)
|
||||
{
|
||||
@ -47,6 +52,7 @@ class FileStatementsDiffer extends Differ
|
||||
|
||||
$keep = [];
|
||||
$keep_signature = [];
|
||||
$delete = [];
|
||||
$diff_map = [];
|
||||
|
||||
foreach ($diff as $diff_elem) {
|
||||
@ -64,7 +70,8 @@ class FileStatementsDiffer extends Differ
|
||||
|
||||
$keep = array_merge($keep, $namespace_keep[0]);
|
||||
$keep_signature = array_merge($keep_signature, $namespace_keep[1]);
|
||||
$diff_map = array_merge($diff_map, $namespace_keep[2]);
|
||||
$delete = array_merge($delete, $namespace_keep[2]);
|
||||
$diff_map = array_merge($diff_map, $namespace_keep[3]);
|
||||
} 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_
|
||||
@ -80,11 +87,12 @@ class FileStatementsDiffer extends Differ
|
||||
|
||||
$keep = array_merge($keep, $class_keep[0]);
|
||||
$keep_signature = array_merge($keep_signature, $class_keep[1]);
|
||||
$diff_map = array_merge($diff_map, $class_keep[2]);
|
||||
$delete = array_merge($delete, $class_keep[2]);
|
||||
$diff_map = array_merge($diff_map, $class_keep[3]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [$keep, $keep_signature, $diff_map];
|
||||
return [$keep, $keep_signature, $delete, $diff_map];
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,12 @@ class NamespaceStatementsDiffer extends Differ
|
||||
* @param PhpParser\Node\Stmt[] $a
|
||||
* @param PhpParser\Node\Stmt[] $b New array
|
||||
*
|
||||
* @return array{0:array<int, string>, 1:array<int, string>, 2: array<int, array{0: int, 1: int, 2: int, 3: int}>}
|
||||
* @return array{
|
||||
* 0: array<int, string>,
|
||||
*. 1: array<int, string>,
|
||||
* 2: array<int, string>,
|
||||
* 3: array<int, array{0: int, 1: int, 2: int, 3: int}>
|
||||
* }
|
||||
*/
|
||||
public static function diff(string $name, array $a, array $b, string $a_code, string $b_code)
|
||||
{
|
||||
@ -44,6 +49,7 @@ class NamespaceStatementsDiffer extends Differ
|
||||
|
||||
$keep = [];
|
||||
$keep_signature = [];
|
||||
$delete = [];
|
||||
$diff_map = [];
|
||||
|
||||
foreach ($diff as $diff_elem) {
|
||||
@ -63,11 +69,12 @@ class NamespaceStatementsDiffer extends Differ
|
||||
|
||||
$keep = array_merge($keep, $class_keep[0]);
|
||||
$keep_signature = array_merge($keep_signature, $class_keep[1]);
|
||||
$diff_map = array_merge($diff_map, $class_keep[2]);
|
||||
$delete = array_merge($delete, $class_keep[2]);
|
||||
$diff_map = array_merge($diff_map, $class_keep[3]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [$keep, $keep_signature, $diff_map];
|
||||
return [$keep, $keep_signature, $delete, $diff_map];
|
||||
}
|
||||
}
|
||||
|
@ -229,13 +229,11 @@ class FileReferenceProvider
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $member_id
|
||||
*
|
||||
* @return array<string, bool>
|
||||
* @return array<string, array<string, bool>>
|
||||
*/
|
||||
public static function getMethodsReferencingClassMember($member_id)
|
||||
public static function getMethodsReferencing()
|
||||
{
|
||||
return isset(self::$class_method_references[$member_id]) ? self::$class_method_references[$member_id] : [];
|
||||
return self::$class_method_references;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -35,6 +35,11 @@ class StatementsProvider
|
||||
*/
|
||||
private $unchanged_signature_members = [];
|
||||
|
||||
/**
|
||||
* @var array<string, array<string, bool>>
|
||||
*/
|
||||
private $changed_members = [];
|
||||
|
||||
/**
|
||||
* @var array<string, array<int, array{0: int, 1: int, 2: int, 3: int}>>
|
||||
*/
|
||||
@ -98,7 +103,7 @@ class StatementsProvider
|
||||
$existing_statements = $this->cache_provider->loadExistingStatementsFromCache($file_cache_key);
|
||||
|
||||
if ($existing_statements) {
|
||||
list($unchanged_members, $unchanged_signature_members, $diff_map)
|
||||
list($unchanged_members, $unchanged_signature_members, $changed_members, $diff_map)
|
||||
= \Psalm\Diff\FileStatementsDiffer::diff(
|
||||
$existing_statements,
|
||||
$stmts,
|
||||
@ -120,6 +125,13 @@ class StatementsProvider
|
||||
array_flip($unchanged_signature_members)
|
||||
);
|
||||
|
||||
$changed_members = array_map(
|
||||
function (int $_) : bool {
|
||||
return true;
|
||||
},
|
||||
array_flip($changed_members)
|
||||
);
|
||||
|
||||
if (isset($this->unchanged_members[$file_path])) {
|
||||
$this->unchanged_members[$file_path] = array_intersect_key(
|
||||
$this->unchanged_members[$file_path],
|
||||
@ -138,6 +150,15 @@ class StatementsProvider
|
||||
$this->unchanged_signature_members[$file_path] = $unchanged_signature_members;
|
||||
}
|
||||
|
||||
if (isset($this->changed_members[$file_path])) {
|
||||
$this->changed_members[$file_path] = array_merge(
|
||||
$this->changed_members[$file_path],
|
||||
$changed_members
|
||||
);
|
||||
} else {
|
||||
$this->changed_members[$file_path] = $changed_members;
|
||||
}
|
||||
|
||||
$this->diff_map[$file_path] = $diff_map;
|
||||
}
|
||||
}
|
||||
@ -174,6 +195,14 @@ class StatementsProvider
|
||||
return $this->unchanged_signature_members;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, array<string, bool>>
|
||||
*/
|
||||
public function getChangedMembers()
|
||||
{
|
||||
return $this->changed_members;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $file_path
|
||||
* @return void
|
||||
|
@ -12,8 +12,14 @@ class FileDiffTest extends TestCase
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testCode(string $a, string $b, array $same_methods, array $same_signatures, array $diff_map_offsets)
|
||||
{
|
||||
public function testCode(
|
||||
string $a,
|
||||
string $b,
|
||||
array $same_methods,
|
||||
array $same_signatures,
|
||||
array $changed_methods,
|
||||
array $diff_map_offsets
|
||||
) {
|
||||
if (strpos($this->getTestName(), 'SKIPPED-') !== false) {
|
||||
$this->markTestSkipped();
|
||||
}
|
||||
@ -33,7 +39,12 @@ class FileDiffTest extends TestCase
|
||||
$diff[1]
|
||||
);
|
||||
|
||||
$this->assertSame(count($diff_map_offsets), count($diff[2]));
|
||||
$this->assertSame(
|
||||
$changed_methods,
|
||||
$diff[2]
|
||||
);
|
||||
|
||||
$this->assertSame(count($diff_map_offsets), count($diff[3]));
|
||||
|
||||
$found_offsets = array_map(
|
||||
/**
|
||||
@ -44,7 +55,7 @@ class FileDiffTest extends TestCase
|
||||
function (array $arr) {
|
||||
return [$arr[2], $arr[3]];
|
||||
},
|
||||
$diff[2]
|
||||
$diff[3]
|
||||
);
|
||||
|
||||
$this->assertSame($diff_map_offsets, $found_offsets);
|
||||
@ -89,6 +100,7 @@ class FileDiffTest extends TestCase
|
||||
}',
|
||||
['foo\a::$aB', 'foo\a::F', 'foo\a::foo', 'foo\a::bar'],
|
||||
[],
|
||||
[],
|
||||
[[0, 0], [0, 0], [0, 0], [0, 0]]
|
||||
],
|
||||
'lineChanges' => [
|
||||
@ -129,6 +141,7 @@ class FileDiffTest extends TestCase
|
||||
}',
|
||||
['foo\a::$aB', 'foo\a::F', 'foo\a::foo', 'foo\a::bar'],
|
||||
[],
|
||||
[],
|
||||
[[1, 1], [2, 2], [2, 2], [5, 5]]
|
||||
],
|
||||
'simpleBodyChange' => [
|
||||
@ -156,6 +169,7 @@ class FileDiffTest extends TestCase
|
||||
}',
|
||||
['foo\a::bar'],
|
||||
['foo\a::foo'],
|
||||
[],
|
||||
[[1, 0]]
|
||||
],
|
||||
'simpleBodyChangeWithSignatureChange' => [
|
||||
@ -183,6 +197,7 @@ class FileDiffTest extends TestCase
|
||||
}',
|
||||
['foo\a::foo'],
|
||||
[],
|
||||
['foo\a::bar'],
|
||||
[[0, 0]]
|
||||
],
|
||||
'propertyChange' => [
|
||||
@ -200,6 +215,7 @@ class FileDiffTest extends TestCase
|
||||
}',
|
||||
[],
|
||||
[],
|
||||
['foo\a::$a'],
|
||||
[]
|
||||
],
|
||||
'propertyDefaultChange' => [
|
||||
@ -216,6 +232,7 @@ class FileDiffTest extends TestCase
|
||||
public $a = 2;
|
||||
}',
|
||||
[],
|
||||
['foo\a::$a'],
|
||||
[],
|
||||
[]
|
||||
],
|
||||
@ -233,6 +250,7 @@ class FileDiffTest extends TestCase
|
||||
public $a = 2;
|
||||
}',
|
||||
[],
|
||||
['foo\a::$a'],
|
||||
[],
|
||||
[]
|
||||
],
|
||||
@ -253,6 +271,7 @@ class FileDiffTest extends TestCase
|
||||
}',
|
||||
[],
|
||||
[],
|
||||
['foo\a::$a'],
|
||||
[]
|
||||
],
|
||||
'addDocblockToFirst' => [
|
||||
@ -283,6 +302,7 @@ class FileDiffTest extends TestCase
|
||||
}',
|
||||
['foo\a::bar'],
|
||||
[],
|
||||
['foo\a::foo'],
|
||||
[[84, 3]]
|
||||
],
|
||||
'addDocblockToSecond' => [
|
||||
@ -313,6 +333,7 @@ class FileDiffTest extends TestCase
|
||||
}',
|
||||
['foo\a::foo'],
|
||||
[],
|
||||
['foo\a::bar'],
|
||||
[[0, 0]]
|
||||
],
|
||||
'removeDocblock' => [
|
||||
@ -343,6 +364,7 @@ class FileDiffTest extends TestCase
|
||||
}',
|
||||
['foo\a::foo'],
|
||||
[],
|
||||
['foo\a::bar'],
|
||||
[[0, 0]]
|
||||
],
|
||||
'changeDocblock' => [
|
||||
@ -376,6 +398,7 @@ class FileDiffTest extends TestCase
|
||||
}',
|
||||
['foo\a::foo'],
|
||||
[],
|
||||
['foo\a::bar'],
|
||||
[[0, 0]]
|
||||
],
|
||||
'removeFunctionAtEnd' => [
|
||||
@ -406,6 +429,7 @@ class FileDiffTest extends TestCase
|
||||
}',
|
||||
['foo\a::foo', 'foo\a::bar'],
|
||||
[],
|
||||
['foo\a::bat'],
|
||||
[[0, 0], [0, 0]]
|
||||
],
|
||||
'removeFunctionAtBeginning' => [
|
||||
@ -436,6 +460,7 @@ class FileDiffTest extends TestCase
|
||||
}',
|
||||
['foo\a::bar', 'foo\a::bat'],
|
||||
[],
|
||||
['foo\a::foo'],
|
||||
[[-98, -3], [-98, -3]]
|
||||
],
|
||||
'removeFunctionInMiddle' => [
|
||||
@ -466,6 +491,7 @@ class FileDiffTest extends TestCase
|
||||
}',
|
||||
['foo\a::foo', 'foo\a::bat'],
|
||||
[],
|
||||
['foo\a::bar'],
|
||||
[[0, 0], [-98, -3]],
|
||||
],
|
||||
'changeNamespace' => [
|
||||
@ -490,6 +516,7 @@ class FileDiffTest extends TestCase
|
||||
}',
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[]
|
||||
],
|
||||
'removeNamespace' => [
|
||||
@ -512,6 +539,7 @@ class FileDiffTest extends TestCase
|
||||
}',
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[]
|
||||
],
|
||||
'newFunctionAtEnd' => [
|
||||
@ -542,6 +570,7 @@ class FileDiffTest extends TestCase
|
||||
}',
|
||||
['foo\a::foo', 'foo\a::bar'],
|
||||
[],
|
||||
[],
|
||||
[[0, 0], [0, 0]]
|
||||
],
|
||||
'newFunctionAtBeginning' => [
|
||||
@ -572,6 +601,7 @@ class FileDiffTest extends TestCase
|
||||
}',
|
||||
['foo\a::foo', 'foo\a::bar'],
|
||||
[],
|
||||
[],
|
||||
[[98, 3], [98, 3]]
|
||||
],
|
||||
'newFunctionInMiddle' => [
|
||||
@ -602,6 +632,7 @@ class FileDiffTest extends TestCase
|
||||
}',
|
||||
['foo\a::foo', 'foo\a::bar'],
|
||||
[],
|
||||
[],
|
||||
[[0, 0], [98, 3]]
|
||||
],
|
||||
'SKIPPED-whiteSpaceOnly' => [
|
||||
@ -631,6 +662,7 @@ class FileDiffTest extends TestCase
|
||||
}',
|
||||
['foo\a::foo', 'foo\a::bar'],
|
||||
[],
|
||||
[],
|
||||
[]
|
||||
],
|
||||
'changeDeclaredMethodId' => [
|
||||
@ -664,6 +696,7 @@ class FileDiffTest extends TestCase
|
||||
class C extends B { }',
|
||||
['foo\a::__construct', 'foo\a::bar', 'foo\b::bat'],
|
||||
[],
|
||||
[],
|
||||
[[0, 0], [0, 0], [120, 2]]
|
||||
],
|
||||
];
|
||||
|
Loading…
Reference in New Issue
Block a user