mirror of
https://github.com/danog/psalm.git
synced 2024-11-30 04:39:00 +01:00
Fix #1039 by invalidating all use users
This commit is contained in:
parent
00b51627cc
commit
1d77b61ff9
@ -335,8 +335,10 @@ abstract class ClassLikeChecker extends SourceChecker implements StatementsSourc
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getFQCLNFromNameObject(PhpParser\Node\Name $class_name, Aliases $aliases)
|
||||
{
|
||||
public static function getFQCLNFromNameObject(
|
||||
PhpParser\Node\Name $class_name,
|
||||
Aliases $aliases
|
||||
) {
|
||||
/** @var string|null */
|
||||
$resolved_name = $class_name->getAttribute('resolvedName');
|
||||
|
||||
|
@ -43,9 +43,21 @@ class NewChecker extends \Psalm\Checker\Statements\Expression\CallChecker
|
||||
|
||||
if ($stmt->class instanceof PhpParser\Node\Name) {
|
||||
if (!in_array(strtolower($stmt->class->parts[0]), ['self', 'static', 'parent'], true)) {
|
||||
$aliases = $statements_checker->getAliases();
|
||||
|
||||
if ($context->calling_method_id
|
||||
&& !$stmt->class instanceof PhpParser\Node\Name\FullyQualified
|
||||
&& isset($aliases->uses[strtolower($stmt->class->parts[0])])
|
||||
) {
|
||||
$codebase->file_reference_provider->addReferenceToClassMethod(
|
||||
$context->calling_method_id,
|
||||
'use:' . $stmt->class->parts[0] . ':' . \md5($statements_checker->getFilePath())
|
||||
);
|
||||
}
|
||||
|
||||
$fq_class_name = ClassLikeChecker::getFQCLNFromNameObject(
|
||||
$stmt->class,
|
||||
$statements_checker->getAliases()
|
||||
$aliases
|
||||
);
|
||||
|
||||
if ($context->check_classes) {
|
||||
|
@ -174,9 +174,21 @@ class StaticCallChecker extends \Psalm\Checker\Statements\Expression\CallChecker
|
||||
return null;
|
||||
}
|
||||
} elseif ($context->check_classes) {
|
||||
$aliases = $statements_checker->getAliases();
|
||||
|
||||
if ($context->calling_method_id
|
||||
&& !$stmt->class instanceof PhpParser\Node\Name\FullyQualified
|
||||
&& isset($aliases->uses[strtolower($stmt->class->parts[0])])
|
||||
) {
|
||||
$codebase->file_reference_provider->addReferenceToClassMethod(
|
||||
$context->calling_method_id,
|
||||
'use:' . $stmt->class->parts[0] . ':' . \md5($statements_checker->getFilePath())
|
||||
);
|
||||
}
|
||||
|
||||
$fq_class_name = ClassLikeChecker::getFQCLNFromNameObject(
|
||||
$stmt->class,
|
||||
$statements_checker->getAliases()
|
||||
$aliases
|
||||
);
|
||||
|
||||
if ($context->isPhantomClass($fq_class_name)) {
|
||||
|
@ -563,9 +563,21 @@ class PropertyFetchChecker
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
$aliases = $statements_checker->getAliases();
|
||||
|
||||
if ($context->calling_method_id
|
||||
&& !$stmt->class instanceof PhpParser\Node\Name\FullyQualified
|
||||
&& isset($aliases->uses[strtolower($stmt->class->parts[0])])
|
||||
) {
|
||||
$codebase->file_reference_provider->addReferenceToClassMethod(
|
||||
$context->calling_method_id,
|
||||
'use:' . $stmt->class->parts[0] . ':' . \md5($statements_checker->getFilePath())
|
||||
);
|
||||
}
|
||||
|
||||
$fq_class_name = ClassLikeChecker::getFQCLNFromNameObject(
|
||||
$stmt->class,
|
||||
$statements_checker->getAliases()
|
||||
$aliases
|
||||
);
|
||||
|
||||
if ($context->isPhantomClass($fq_class_name)) {
|
||||
|
@ -99,6 +99,20 @@ class FileStatementsDiffer extends AstDiffer
|
||||
$add_or_delete = array_merge($add_or_delete, $class_keep[2]);
|
||||
$diff_map = array_merge($diff_map, $class_keep[3]);
|
||||
}
|
||||
} elseif ($diff_elem->type === DiffElem::TYPE_REMOVE) {
|
||||
if ($diff_elem->old instanceof PhpParser\Node\Stmt\Use_
|
||||
|| $diff_elem->old instanceof PhpParser\Node\Stmt\GroupUse
|
||||
) {
|
||||
foreach ($diff_elem->old->uses as $use) {
|
||||
if ($use->alias) {
|
||||
$add_or_delete[] = 'use:' . (string) $use->alias;
|
||||
} else {
|
||||
$name_parts = $use->name->parts;
|
||||
|
||||
$add_or_delete[] = 'use:' . end($name_parts);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -82,6 +82,20 @@ class NamespaceStatementsDiffer extends AstDiffer
|
||||
$add_or_delete = array_merge($add_or_delete, $class_keep[2]);
|
||||
$diff_map = array_merge($diff_map, $class_keep[3]);
|
||||
}
|
||||
} elseif ($diff_elem->type === DiffElem::TYPE_REMOVE) {
|
||||
if ($diff_elem->old instanceof PhpParser\Node\Stmt\Use_
|
||||
|| $diff_elem->old instanceof PhpParser\Node\Stmt\GroupUse
|
||||
) {
|
||||
foreach ($diff_elem->old->uses as $use) {
|
||||
if ($use->alias) {
|
||||
$add_or_delete[] = 'use:' . (string) $use->alias;
|
||||
} else {
|
||||
$name_parts = $use->name->parts;
|
||||
|
||||
$add_or_delete[] = 'use:' . end($name_parts);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -169,6 +169,19 @@ class StatementsProvider
|
||||
array_flip($unchanged_signature_members)
|
||||
);
|
||||
|
||||
$file_path_hash = \md5($file_path);
|
||||
|
||||
$changed_members = array_map(
|
||||
function (string $key) use ($file_path_hash) : string {
|
||||
if (substr($key, 0, 4) === 'use:') {
|
||||
return $key . ':' . $file_path_hash;
|
||||
}
|
||||
|
||||
return $key;
|
||||
},
|
||||
$changed_members
|
||||
);
|
||||
|
||||
$changed_members = array_map(
|
||||
/**
|
||||
* @param int $_
|
||||
|
@ -1349,6 +1349,30 @@ class FileDiffTest extends TestCase
|
||||
[],
|
||||
[]
|
||||
],
|
||||
'removeUse' => [
|
||||
'<?php
|
||||
namespace Foo;
|
||||
|
||||
use Exception;
|
||||
|
||||
class A {
|
||||
public function foo() : void {
|
||||
throw new Exception();
|
||||
}
|
||||
}',
|
||||
'<?php
|
||||
namespace Foo;
|
||||
|
||||
class A {
|
||||
public function foo() : void {
|
||||
throw new Exception();
|
||||
}
|
||||
}',
|
||||
['foo\a::foo'],
|
||||
[],
|
||||
['use:Exception'],
|
||||
[[-36, -2]]
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -472,6 +472,212 @@ class TemporaryUpdateTest extends \Psalm\Tests\TestCase
|
||||
],
|
||||
'error_positions' => [[120], [120]],
|
||||
],
|
||||
'removeUseShouldInvalidate' => [
|
||||
[
|
||||
[
|
||||
getcwd() . DIRECTORY_SEPARATOR . 'A.php' => '<?php
|
||||
namespace Foo;
|
||||
|
||||
use Exception;
|
||||
|
||||
class A {
|
||||
public function foo() : void {
|
||||
throw new Exception();
|
||||
}
|
||||
}',
|
||||
],
|
||||
[
|
||||
getcwd() . DIRECTORY_SEPARATOR . 'A.php' => '<?php
|
||||
namespace Foo;
|
||||
|
||||
class A {
|
||||
public function foo() : void {
|
||||
throw new Exception();
|
||||
}
|
||||
}',
|
||||
],
|
||||
],
|
||||
'error_positions' => [[], [197]],
|
||||
],
|
||||
'removeGroupUseShouldInvalidate' => [
|
||||
[
|
||||
[
|
||||
getcwd() . DIRECTORY_SEPARATOR . 'A.php' => '<?php
|
||||
namespace Foo;
|
||||
|
||||
use PhpParser\{Error};
|
||||
|
||||
class A {
|
||||
public function foo() : void {
|
||||
throw new Error("bad", 5);
|
||||
}
|
||||
}',
|
||||
],
|
||||
[
|
||||
getcwd() . DIRECTORY_SEPARATOR . 'A.php' => '<?php
|
||||
namespace Foo;
|
||||
|
||||
class A {
|
||||
public function foo() : void {
|
||||
throw new Error("bad", 5);
|
||||
}
|
||||
}',
|
||||
],
|
||||
],
|
||||
'error_positions' => [[], [197]],
|
||||
],
|
||||
'removeUseWithAliasShouldInvalidate' => [
|
||||
[
|
||||
[
|
||||
getcwd() . DIRECTORY_SEPARATOR . 'A.php' => '<?php
|
||||
namespace Foo;
|
||||
|
||||
use Exception as E;
|
||||
|
||||
class A {
|
||||
public function foo() : void {
|
||||
throw new E();
|
||||
}
|
||||
}',
|
||||
],
|
||||
[
|
||||
getcwd() . DIRECTORY_SEPARATOR . 'A.php' => '<?php
|
||||
namespace Foo;
|
||||
|
||||
class A {
|
||||
public function foo() : void {
|
||||
throw new E();
|
||||
}
|
||||
}',
|
||||
],
|
||||
],
|
||||
'error_positions' => [[], [197]],
|
||||
],
|
||||
'removeGroupUseWithAliasShouldInvalidate' => [
|
||||
[
|
||||
[
|
||||
getcwd() . DIRECTORY_SEPARATOR . 'A.php' => '<?php
|
||||
namespace Foo;
|
||||
|
||||
use PhpParser\{Error as E};
|
||||
|
||||
class A {
|
||||
public function foo() : void {
|
||||
throw new E("bad", 5);
|
||||
}
|
||||
}',
|
||||
],
|
||||
[
|
||||
getcwd() . DIRECTORY_SEPARATOR . 'A.php' => '<?php
|
||||
namespace Foo;
|
||||
|
||||
class A {
|
||||
public function foo() : void {
|
||||
throw new E("bad", 5);
|
||||
}
|
||||
}',
|
||||
],
|
||||
],
|
||||
'error_positions' => [[], [197]],
|
||||
],
|
||||
'removeUseShouldInvalidateNoNamespace' => [
|
||||
[
|
||||
[
|
||||
getcwd() . DIRECTORY_SEPARATOR . 'A.php' => '<?php
|
||||
use PhpParser\Node\Name;
|
||||
|
||||
class A {
|
||||
public function foo() : void {
|
||||
new Name("Martin");
|
||||
}
|
||||
}',
|
||||
],
|
||||
[
|
||||
getcwd() . DIRECTORY_SEPARATOR . 'A.php' => '<?php
|
||||
class A {
|
||||
public function foo() : void {
|
||||
new Name("Martin");
|
||||
}
|
||||
}',
|
||||
],
|
||||
],
|
||||
'error_positions' => [[], [147]],
|
||||
],
|
||||
'removeGroupUseShouldInvalidateNoNamespace' => [
|
||||
[
|
||||
[
|
||||
getcwd() . DIRECTORY_SEPARATOR . 'A.php' => '<?php
|
||||
namespace Foo;
|
||||
|
||||
use PhpParser\{Error};
|
||||
|
||||
class A {
|
||||
public function foo() : void {
|
||||
throw new Error("bad", 5);
|
||||
}
|
||||
}',
|
||||
],
|
||||
[
|
||||
getcwd() . DIRECTORY_SEPARATOR . 'A.php' => '<?php
|
||||
namespace Foo;
|
||||
|
||||
class A {
|
||||
public function foo() : void {
|
||||
throw new Error("bad", 5);
|
||||
}
|
||||
}',
|
||||
],
|
||||
],
|
||||
'error_positions' => [[], [197]],
|
||||
],
|
||||
'removeUseWithAliasShouldInvalidateNoNamespace' => [
|
||||
[
|
||||
[
|
||||
getcwd() . DIRECTORY_SEPARATOR . 'A.php' => '<?php
|
||||
use Exception as E;
|
||||
|
||||
class A {
|
||||
public function foo() : void {
|
||||
throw new E();
|
||||
}
|
||||
}',
|
||||
],
|
||||
[
|
||||
getcwd() . DIRECTORY_SEPARATOR . 'A.php' => '<?php
|
||||
class A {
|
||||
public function foo() : void {
|
||||
throw new E();
|
||||
}
|
||||
}',
|
||||
],
|
||||
],
|
||||
'error_positions' => [[], [153]],
|
||||
],
|
||||
'removeGroupUseWithAliasShouldInvalidateNoNamespace' => [
|
||||
[
|
||||
[
|
||||
getcwd() . DIRECTORY_SEPARATOR . 'A.php' => '<?php
|
||||
use PhpParser\{Error as E};
|
||||
|
||||
class A {
|
||||
public function foo() : void {
|
||||
throw new E("bad", 5);
|
||||
}
|
||||
}',
|
||||
],
|
||||
[
|
||||
getcwd() . DIRECTORY_SEPARATOR . 'A.php' => '<?php
|
||||
namespace Foo;
|
||||
|
||||
class A {
|
||||
public function foo() : void {
|
||||
throw new E("bad", 5);
|
||||
}
|
||||
}',
|
||||
],
|
||||
],
|
||||
'error_positions' => [[], [197]],
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user