1
0
mirror of https://github.com/danog/psalm.git synced 2024-11-26 20:34:47 +01:00

Allow multiple class renames at once

This commit is contained in:
Brown 2019-06-10 17:09:34 -04:00
parent c21e9917fa
commit 45f2d986e6
3 changed files with 192 additions and 75 deletions

View File

@ -30,7 +30,9 @@ class FileManipulation
public function getKey() : string
{
return sha1($this->start . ':' . $this->insertion_text);
return $this->start === $this->end
? ($this->start . ':' . sha1($this->insertion_text))
: ($this->start . ':' . $this->end);
}
public function transform(string $existing_contents) : string

View File

@ -838,7 +838,7 @@ class ClassLikes
$source_classlike_storage->parent_class
);
$this->airliftDocblockType(
$this->airliftClassDefinedDocblockType(
$replace_type,
$destination_fq_class_name,
$source_property_storage->stmt_location->file_path,
@ -966,7 +966,6 @@ class ClassLikes
string $fq_class_name,
?string $calling_method_id
) : bool {
$calling_fq_class_name = $source->getFQCLN();
// if we're inside a moved class static method
@ -993,6 +992,79 @@ class ClassLikes
return true;
}
// if we're outside a moved class, but we're changing all references to a class
if (isset($codebase->class_transforms[strtolower($fq_class_name)])) {
$new_fq_class_name = $codebase->class_transforms[strtolower($fq_class_name)];
$file_manipulations = [];
if ($class_name_node instanceof PhpParser\Node\Identifier) {
$destination_parts = explode('\\', $new_fq_class_name);
$destination_class_name = array_pop($destination_parts);
$file_manipulations = [];
$file_manipulations[] = new \Psalm\FileManipulation(
(int) $class_name_node->getAttribute('startFilePos'),
(int) $class_name_node->getAttribute('endFilePos') + 1,
$destination_class_name
);
FileManipulationBuffer::add($source->getFilePath(), $file_manipulations);
return true;
}
$uses_flipped = $source->getAliasedClassesFlipped();
$uses_flipped_replaceable = $source->getAliasedClassesFlippedReplaceable();
$old_fq_class_name = strtolower($fq_class_name);
$migrated_source_fqcln = $calling_fq_class_name;
if ($calling_fq_class_name
&& isset($codebase->class_transforms[strtolower($calling_fq_class_name)])
) {
$migrated_source_fqcln = $codebase->class_transforms[strtolower($calling_fq_class_name)];
}
$source_namespace = $source->getNamespace();
if ($migrated_source_fqcln && $calling_fq_class_name !== $migrated_source_fqcln) {
$new_source_parts = explode('\\', $migrated_source_fqcln);
array_pop($new_source_parts);
$source_namespace = implode('\\', $new_source_parts);
}
if (isset($uses_flipped_replaceable[$old_fq_class_name])) {
$alias = $uses_flipped_replaceable[$old_fq_class_name];
unset($uses_flipped_replaceable[$old_fq_class_name]);
$old_class_name_parts = explode('\\', $old_fq_class_name);
$old_class_name = end($old_class_name_parts);
if (strtolower($old_class_name) === strtolower($alias)) {
$new_class_name_parts = explode('\\', $new_fq_class_name);
$new_class_name = end($new_class_name_parts);
$uses_flipped[strtolower($new_fq_class_name)] = $new_class_name;
} else {
$uses_flipped[strtolower($new_fq_class_name)] = $alias;
}
}
$file_manipulations[] = new \Psalm\FileManipulation(
(int) $class_name_node->getAttribute('startFilePos'),
(int) $class_name_node->getAttribute('endFilePos') + 1,
Type::getStringFromFQCLN(
$new_fq_class_name,
$source_namespace,
$uses_flipped,
$migrated_source_fqcln
)
);
FileManipulationBuffer::add($source->getFilePath(), $file_manipulations);
return true;
}
// if we're inside a moved class (could be a method, could be a property/class const default)
if ($codebase->classes_to_move
&& $calling_fq_class_name
@ -1028,46 +1100,6 @@ class ClassLikes
return true;
}
// if we're outside a moved class, but we're changing all references to a class
if (isset($codebase->class_transforms[strtolower($fq_class_name)])) {
$new_fq_class_name = $codebase->class_transforms[strtolower($fq_class_name)];
$file_manipulations = [];
$uses_flipped = $source->getAliasedClassesFlipped();
$uses_flipped_replaceable = $source->getAliasedClassesFlippedReplaceable();
$old_fq_class_name = strtolower($fq_class_name);
if (isset($uses_flipped_replaceable[$old_fq_class_name])) {
$alias = $uses_flipped_replaceable[$old_fq_class_name];
unset($uses_flipped_replaceable[$old_fq_class_name]);
$old_class_name_parts = explode('\\', $old_fq_class_name);
$old_class_name = end($old_class_name_parts);
if (strtolower($old_class_name) === strtolower($alias)) {
$new_class_name_parts = explode('\\', $new_fq_class_name);
$new_class_name = end($new_class_name_parts);
$uses_flipped[strtolower($new_fq_class_name)] = $new_class_name;
} else {
$uses_flipped[strtolower($new_fq_class_name)] = $alias;
}
}
$file_manipulations[] = new \Psalm\FileManipulation(
(int) $class_name_node->getAttribute('startFilePos'),
(int) $class_name_node->getAttribute('endFilePos') + 1,
Type::getStringFromFQCLN(
$new_fq_class_name,
$source->getNamespace(),
$uses_flipped,
$calling_fq_class_name
)
);
FileManipulationBuffer::add($source->getFilePath(), $file_manipulations);
return true;
}
return false;
}
@ -1078,7 +1110,6 @@ class ClassLikes
CodeLocation $type_location,
?string $calling_method_id
) : void {
$calling_fq_class_name = $source->getFQCLN();
$moved_type = false;
@ -1093,34 +1124,7 @@ class ClassLikes
$destination_class = explode('::', $codebase->methods_to_move[strtolower($calling_method_id)])[0];
$this->airliftDocblockType(
$type,
$destination_class,
$source->getFilePath(),
$bounds[0],
$bounds[1]
);
$moved_type = true;
}
// if we're inside a moved class (could be a method, could be a property/class const default)
if (!$moved_type
&& $codebase->classes_to_move
&& $calling_fq_class_name
&& isset($codebase->classes_to_move[strtolower($calling_fq_class_name)])
) {
$bounds = $type_location->getSelectionBounds();
$destination_class = $codebase->classes_to_move[strtolower($calling_fq_class_name)];
if ($type->containsClassLike(strtolower($calling_fq_class_name))) {
$type = clone $type;
$type->replaceClassLike(strtolower($calling_fq_class_name), $destination_class);
}
$this->airliftDocblockType(
$this->airliftClassDefinedDocblockType(
$type,
$destination_class,
$source->getFilePath(),
@ -1146,6 +1150,22 @@ class ClassLikes
$uses_flipped = $source->getAliasedClassesFlipped();
$uses_flipped_replaceable = $source->getAliasedClassesFlippedReplaceable();
$migrated_source_fqcln = $calling_fq_class_name;
if ($calling_fq_class_name
&& isset($codebase->class_transforms[strtolower($calling_fq_class_name)])
) {
$migrated_source_fqcln = $codebase->class_transforms[strtolower($calling_fq_class_name)];
}
$source_namespace = $source->getNamespace();
if ($migrated_source_fqcln && $calling_fq_class_name !== $migrated_source_fqcln) {
$new_source_parts = explode('\\', $migrated_source_fqcln);
array_pop($new_source_parts);
$source_namespace = implode('\\', $new_source_parts);
}
if (isset($uses_flipped_replaceable[$old_fq_class_name])) {
$alias = $uses_flipped_replaceable[$old_fq_class_name];
unset($uses_flipped_replaceable[$old_fq_class_name]);
@ -1164,9 +1184,9 @@ class ClassLikes
$bounds[0],
$bounds[1],
$type->toNamespacedString(
$source->getNamespace(),
$source_namespace,
$uses_flipped,
null,
$migrated_source_fqcln,
false
)
);
@ -1175,9 +1195,36 @@ class ClassLikes
$source->getFilePath(),
$file_manipulations
);
$moved_type = true;
}
}
}
// if we're inside a moved class (could be a method, could be a property/class const default)
if (!$moved_type
&& $codebase->classes_to_move
&& $calling_fq_class_name
&& isset($codebase->classes_to_move[strtolower($calling_fq_class_name)])
) {
$bounds = $type_location->getSelectionBounds();
$destination_class = $codebase->classes_to_move[strtolower($calling_fq_class_name)];
if ($type->containsClassLike(strtolower($calling_fq_class_name))) {
$type = clone $type;
$type->replaceClassLike(strtolower($calling_fq_class_name), $destination_class);
}
$this->airliftClassDefinedDocblockType(
$type,
$destination_class,
$source->getFilePath(),
$bounds[0],
$bounds[1]
);
}
}
public function airliftClassLikeReference(
@ -1215,7 +1262,7 @@ class ClassLikes
);
}
public function airliftDocblockType(
public function airliftClassDefinedDocblockType(
Type\Union $type,
string $destination_fq_class_name,
string $source_file_path,

View File

@ -419,6 +419,74 @@ class ClassMoveTest extends \Psalm\Tests\TestCase
'Bar\Bat' => 'Bar\Baz\Bahh',
]
],
'moveClassesIntoNamespace' => [
'<?php
namespace Foo {
class A {
/** @var ?B */
public $x = null;
/** @var ?A */
public $y = null;
/** @var A|B|C|null */
public $z = null;
}
}
namespace Foo {
class B {
/** @var ?A */
public $x = null;
/** @var ?B */
public $y = null;
/** @var A|B|C|null */
public $z = null;
}
}
namespace Foo {
class C {
/** @var ?A */
public $x = null;
/** @var ?B */
public $y = null;
}
}',
'<?php
namespace Bar\Baz {
class A {
/** @var null|B */
public $x = null;
/** @var null|self */
public $y = null;
/** @var null|self|B|\Foo\C */
public $z = null;
}
}
namespace Bar\Baz {
class B {
/** @var null|A */
public $x = null;
/** @var null|self */
public $y = null;
/** @var null|A|self|\Foo\C */
public $z = null;
}
}
namespace Foo {
class C {
/** @var null|\Bar\Baz\A */
public $x = null;
/** @var null|\Bar\Baz\B */
public $y = null;
}
}',
[
'Foo\A' => 'Bar\Baz\A',
'Foo\B' => 'Bar\Baz\B',
]
],
'moveClassDeeperIntoNamespaceAdjustUseWithAlias' => [
'<?php
namespace Foo {