1
0
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:
Brown 2018-09-26 17:54:08 -04:00 committed by Matthew Brown
parent 89c04ec1ae
commit 1d26332d77
7 changed files with 144 additions and 36 deletions

View File

@ -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]);
}
}
}
}
}
}

View File

@ -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];
}
}

View File

@ -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];
}
}

View File

@ -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];
}
}

View File

@ -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;
}
/**

View File

@ -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

View File

@ -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]]
],
];