mirror of
https://github.com/danog/psalm.git
synced 2024-11-30 04:39:00 +01:00
Allow instance method renaming, too
This commit is contained in:
parent
7f86e3cdc5
commit
2439a9f6a0
@ -180,7 +180,12 @@ class Codebase
|
||||
/**
|
||||
* @var array<string, string>
|
||||
*/
|
||||
public $method_migrations = [];
|
||||
public $methods_to_move = [];
|
||||
|
||||
/**
|
||||
* @var array<string, string>
|
||||
*/
|
||||
public $methods_to_rename = [];
|
||||
|
||||
/**
|
||||
* @var array<string, string>
|
||||
|
@ -361,11 +361,11 @@ abstract class FunctionLikeAnalyzer extends SourceAnalyzer implements Statements
|
||||
|
||||
$check_stmts = true;
|
||||
|
||||
if ($codebase->method_migrations
|
||||
if ($codebase->methods_to_move
|
||||
&& $context->calling_method_id
|
||||
&& isset($codebase->method_migrations[strtolower($context->calling_method_id)])
|
||||
&& isset($codebase->methods_to_move[strtolower($context->calling_method_id)])
|
||||
) {
|
||||
$destination_method_id = $codebase->method_migrations[strtolower($context->calling_method_id)];
|
||||
$destination_method_id = $codebase->methods_to_move[strtolower($context->calling_method_id)];
|
||||
|
||||
foreach ($this->function->params as $param) {
|
||||
$param_name_node = null;
|
||||
@ -480,6 +480,25 @@ abstract class FunctionLikeAnalyzer extends SourceAnalyzer implements Statements
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($codebase->methods_to_rename as $original_method_id => $new_method_name) {
|
||||
if ($this->function instanceof ClassMethod
|
||||
&& strtolower($this->getMethodId()) === $original_method_id
|
||||
) {
|
||||
$file_manipulations = [
|
||||
new \Psalm\FileManipulation(
|
||||
(int) $this->function->name->getAttribute('startFilePos'),
|
||||
(int) $this->function->name->getAttribute('endFilePos') + 1,
|
||||
$new_method_name
|
||||
)
|
||||
];
|
||||
|
||||
\Psalm\Internal\FileManipulation\FileManipulationBuffer::add(
|
||||
$this->getFilePath(),
|
||||
$file_manipulations
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($params as $offset => $function_param) {
|
||||
$signature_type = $function_param->signature_type;
|
||||
$signature_type_location = $function_param->signature_type_location;
|
||||
|
@ -530,7 +530,7 @@ class ProjectAnalyzer
|
||||
throw new \UnexpectedValueException('Should not be checking references');
|
||||
}
|
||||
|
||||
$this->codebase->classlikes->refactorMethods(
|
||||
$this->codebase->classlikes->moveMethods(
|
||||
$this->codebase->methods,
|
||||
$this->progress
|
||||
);
|
||||
|
@ -120,14 +120,14 @@ class AssignmentAnalyzer
|
||||
$statements_analyzer->getSuppressedIssues()
|
||||
);
|
||||
|
||||
if ($codebase->method_migrations
|
||||
if ($codebase->methods_to_move
|
||||
&& $context->calling_method_id
|
||||
&& isset($codebase->method_migrations[strtolower($context->calling_method_id)])
|
||||
&& isset($codebase->methods_to_move[strtolower($context->calling_method_id)])
|
||||
&& $var_comment->type_start
|
||||
&& $var_comment->type_end
|
||||
&& $var_comment->line_number
|
||||
) {
|
||||
$destination_method_id = $codebase->method_migrations[strtolower($context->calling_method_id)];
|
||||
$destination_method_id = $codebase->methods_to_move[strtolower($context->calling_method_id)];
|
||||
|
||||
$codebase->classlikes->airliftDocblockType(
|
||||
$var_comment_type,
|
||||
|
@ -1175,6 +1175,27 @@ class MethodCallAnalyzer extends \Psalm\Internal\Analyzer\Statements\Expression\
|
||||
}
|
||||
}
|
||||
|
||||
if ($codebase->methods_to_rename) {
|
||||
$declaring_method_id = $codebase->methods->getDeclaringMethodId($method_id);
|
||||
|
||||
foreach ($codebase->methods_to_rename as $original_method_id => $new_method_name) {
|
||||
if ($declaring_method_id && strtolower($declaring_method_id) === $original_method_id) {
|
||||
$file_manipulations = [
|
||||
new \Psalm\FileManipulation(
|
||||
(int) $stmt->name->getAttribute('startFilePos'),
|
||||
(int) $stmt->name->getAttribute('endFilePos') + 1,
|
||||
$new_method_name
|
||||
)
|
||||
];
|
||||
|
||||
\Psalm\Internal\FileManipulation\FileManipulationBuffer::add(
|
||||
$statements_analyzer->getFilePath(),
|
||||
$file_manipulations
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($config->after_method_checks) {
|
||||
$file_manipulations = [];
|
||||
|
||||
|
@ -247,11 +247,11 @@ class NewAnalyzer extends \Psalm\Internal\Analyzer\Statements\Expression\CallAna
|
||||
|
||||
if ($fq_class_name) {
|
||||
if ($stmt->class instanceof PhpParser\Node\Name
|
||||
&& $codebase->method_migrations
|
||||
&& $codebase->methods_to_move
|
||||
&& $context->calling_method_id
|
||||
&& isset($codebase->method_migrations[strtolower($context->calling_method_id)])
|
||||
&& isset($codebase->methods_to_move[strtolower($context->calling_method_id)])
|
||||
) {
|
||||
$destination_method_id = $codebase->method_migrations[strtolower($context->calling_method_id)];
|
||||
$destination_method_id = $codebase->methods_to_move[strtolower($context->calling_method_id)];
|
||||
|
||||
$codebase->classlikes->airliftClassLikeReference(
|
||||
$fq_class_name,
|
||||
|
@ -831,20 +831,23 @@ class StaticCallAnalyzer extends \Psalm\Internal\Analyzer\Statements\Expression\
|
||||
&& $stmt->class instanceof PhpParser\Node\Name
|
||||
) {
|
||||
$new_method_id = substr($transformation, 0, -4);
|
||||
list($old_declaring_fq_class_name) = explode('::', $declaring_method_id);
|
||||
list($new_fq_class_name, $new_method_name) = explode('::', $new_method_id);
|
||||
|
||||
$file_manipulations = [];
|
||||
|
||||
$file_manipulations[] = new \Psalm\FileManipulation(
|
||||
(int) $stmt->class->getAttribute('startFilePos'),
|
||||
(int) $stmt->class->getAttribute('endFilePos') + 1,
|
||||
Type::getStringFromFQCLN(
|
||||
$new_fq_class_name,
|
||||
$statements_analyzer->getNamespace(),
|
||||
$statements_analyzer->getAliasedClassesFlipped(),
|
||||
null
|
||||
)
|
||||
);
|
||||
if (strtolower($new_fq_class_name) !== strtolower($old_declaring_fq_class_name)) {
|
||||
$file_manipulations[] = new \Psalm\FileManipulation(
|
||||
(int) $stmt->class->getAttribute('startFilePos'),
|
||||
(int) $stmt->class->getAttribute('endFilePos') + 1,
|
||||
Type::getStringFromFQCLN(
|
||||
$new_fq_class_name,
|
||||
$statements_analyzer->getNamespace(),
|
||||
$statements_analyzer->getAliasedClassesFlipped(),
|
||||
null
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$file_manipulations[] = new \Psalm\FileManipulation(
|
||||
(int) $stmt->name->getAttribute('startFilePos'),
|
||||
@ -860,11 +863,11 @@ class StaticCallAnalyzer extends \Psalm\Internal\Analyzer\Statements\Expression\
|
||||
}
|
||||
|
||||
if (!$moved_call
|
||||
&& $codebase->method_migrations
|
||||
&& $codebase->methods_to_move
|
||||
&& $context->calling_method_id
|
||||
&& isset($codebase->method_migrations[strtolower($context->calling_method_id)])
|
||||
&& isset($codebase->methods_to_move[strtolower($context->calling_method_id)])
|
||||
) {
|
||||
$destination_method_id = $codebase->method_migrations[strtolower($context->calling_method_id)];
|
||||
$destination_method_id = $codebase->methods_to_move[strtolower($context->calling_method_id)];
|
||||
|
||||
$codebase->classlikes->airliftClassLikeReference(
|
||||
$fq_class_name,
|
||||
|
@ -140,11 +140,11 @@ class ConstFetchAnalyzer
|
||||
}
|
||||
}
|
||||
|
||||
if ($codebase->method_migrations
|
||||
if ($codebase->methods_to_move
|
||||
&& $context->calling_method_id
|
||||
&& isset($codebase->method_migrations[strtolower($context->calling_method_id)])
|
||||
&& isset($codebase->methods_to_move[strtolower($context->calling_method_id)])
|
||||
) {
|
||||
$destination_method_id = $codebase->method_migrations[strtolower($context->calling_method_id)];
|
||||
$destination_method_id = $codebase->methods_to_move[strtolower($context->calling_method_id)];
|
||||
|
||||
$codebase->classlikes->airliftClassLikeReference(
|
||||
$fq_class_name,
|
||||
|
@ -74,14 +74,14 @@ class ReturnAnalyzer
|
||||
$statements_analyzer->getParentFQCLN()
|
||||
);
|
||||
|
||||
if ($codebase->method_migrations
|
||||
if ($codebase->methods_to_move
|
||||
&& $context->calling_method_id
|
||||
&& isset($codebase->method_migrations[strtolower($context->calling_method_id)])
|
||||
&& isset($codebase->methods_to_move[strtolower($context->calling_method_id)])
|
||||
&& $var_comment->type_start
|
||||
&& $var_comment->type_end
|
||||
&& $var_comment->line_number
|
||||
) {
|
||||
$destination_method_id = $codebase->method_migrations[strtolower($context->calling_method_id)];
|
||||
$destination_method_id = $codebase->methods_to_move[strtolower($context->calling_method_id)];
|
||||
|
||||
$codebase->classlikes->airliftDocblockType(
|
||||
$comment_type,
|
||||
|
@ -950,15 +950,15 @@ class StatementsAnalyzer extends SourceAnalyzer implements StatementsSource
|
||||
$this->getSuppressedIssues()
|
||||
);
|
||||
|
||||
if ($codebase->method_migrations
|
||||
if ($codebase->methods_to_move
|
||||
&& $context->calling_method_id
|
||||
&& isset($codebase->method_migrations[strtolower($context->calling_method_id)])
|
||||
&& isset($codebase->methods_to_move[strtolower($context->calling_method_id)])
|
||||
&& $var_comment->type_start
|
||||
&& $var_comment->type_end
|
||||
&& $var_comment->line_number
|
||||
) {
|
||||
$destination_method_id
|
||||
= $codebase->method_migrations[strtolower($context->calling_method_id)];
|
||||
= $codebase->methods_to_move[strtolower($context->calling_method_id)];
|
||||
|
||||
$codebase->classlikes->airliftDocblockType(
|
||||
$var_comment_type,
|
||||
|
@ -708,7 +708,7 @@ class ClassLikes
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function refactorMethods(Methods $methods, Progress $progress = null)
|
||||
public function moveMethods(Methods $methods, Progress $progress = null)
|
||||
{
|
||||
if ($progress === null) {
|
||||
$progress = new VoidProgress();
|
||||
@ -717,7 +717,7 @@ class ClassLikes
|
||||
$project_analyzer = \Psalm\Internal\Analyzer\ProjectAnalyzer::getInstance();
|
||||
$codebase = $project_analyzer->getCodebase();
|
||||
|
||||
if (!$codebase->method_migrations) {
|
||||
if (!$codebase->methods_to_move) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -725,7 +725,7 @@ class ClassLikes
|
||||
|
||||
$code_migrations = [];
|
||||
|
||||
foreach ($codebase->method_migrations as $original => $eventual) {
|
||||
foreach ($codebase->methods_to_move as $original => $eventual) {
|
||||
try {
|
||||
$original_method_storage = $methods->getStorage($original);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
|
@ -166,10 +166,6 @@ function getArguments() : array
|
||||
continue;
|
||||
}
|
||||
|
||||
if (substr($input_path, 0, 2) === '--' && strlen($input_path) > 2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$filtered_input_paths[] = $input_path;
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,7 @@ $args = array_slice($argv, 1);
|
||||
$valid_short_options = ['f:', 'm', 'h', 'r:'];
|
||||
$valid_long_options = [
|
||||
'help', 'debug', 'config:', 'root:',
|
||||
'threads:',
|
||||
'threads:', 'move:', 'into:', 'rename:', 'to:',
|
||||
];
|
||||
|
||||
// get options from command line
|
||||
@ -99,8 +99,22 @@ Options:
|
||||
-r, --root
|
||||
If running Psalm globally you'll need to specify a project root. Defaults to cwd
|
||||
|
||||
--threads=INT
|
||||
--threads=auto
|
||||
If greater than one, Psalm will run analysis on multiple threads, speeding things up.
|
||||
By default
|
||||
|
||||
--move "[Identifier]" --into "[Class]"
|
||||
Moves the specified item into the class. More than one item can be moved into a class
|
||||
by passing a comma-separated list of values e.g.
|
||||
|
||||
--move "Ns\Foo::bar,Ns\Foo::baz" --into "Biz\Bang\DestinationClass"
|
||||
|
||||
--rename "[Identifier]" --to "[newName]"
|
||||
Renames a specfied item (e.g. method) and updates all references to it that Psalm can
|
||||
identify.
|
||||
|
||||
--move-and-rename "[Identifier]" --to "[NewIdentifier]"
|
||||
Moves the specified item to the destination with a new name
|
||||
|
||||
HELP;
|
||||
|
||||
@ -137,7 +151,98 @@ if ($path_to_config === false) {
|
||||
die('Could not resolve path to config ' . (string)$options['c'] . PHP_EOL);
|
||||
}
|
||||
|
||||
$args = getArguments();
|
||||
|
||||
$operation = null;
|
||||
$last_arg = null;
|
||||
|
||||
$to_move = [];
|
||||
$to_rename = [];
|
||||
|
||||
foreach ($args as $arg) {
|
||||
if ($arg === '--move') {
|
||||
$operation = 'move';
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($arg === '--into') {
|
||||
if ($operation !== 'move' || !$last_arg) {
|
||||
die('--into is not expected here' . PHP_EOL);
|
||||
}
|
||||
|
||||
$operation = 'move_into';
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($arg === '--rename') {
|
||||
$operation = 'rename';
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($arg === '--move-and-rename') {
|
||||
$operation = 'move_and_rename';
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($arg === '--to') {
|
||||
if (($operation !== 'rename' && $operation !== 'move_and_rename') || !$last_arg) {
|
||||
die('--to is not expected here' . PHP_EOL);
|
||||
}
|
||||
|
||||
if ($operation === 'rename') {
|
||||
$operation = 'rename_to';
|
||||
} else {
|
||||
$operation = 'move_and_rename_to';
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($arg[0] === '-') {
|
||||
$operation = null;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($operation === 'move_into' || $operation === 'rename_to' || $operation === 'move_and_rename_to') {
|
||||
if (!$last_arg) {
|
||||
die('Expecting a previous argument' . PHP_EOL);
|
||||
}
|
||||
|
||||
if ($operation === 'move_into') {
|
||||
$last_arg_parts = preg_split('/, ?/', $last_arg);
|
||||
|
||||
foreach ($last_arg_parts as $last_arg_part) {
|
||||
list(, $identifier_name) = explode('::', $last_arg_part);
|
||||
$to_move[strtolower($last_arg_part)] = $arg . '::' . $identifier_name;
|
||||
$to_rename[strtolower($last_arg_part) . '\((.*\))'] = $arg . '::' . $identifier_name . '($1)';
|
||||
}
|
||||
} elseif ($operation === 'move_and_rename_to') {
|
||||
$to_move[strtolower($last_arg)] = $arg;
|
||||
$to_rename[strtolower($last_arg) . '\((.*\))'] = $arg . '($1)';
|
||||
} else {
|
||||
$to_rename[strtolower($last_arg) . '\((.*\))'] = $arg . '($1)';
|
||||
}
|
||||
|
||||
$last_arg = null;
|
||||
$operation = null;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($operation === 'move' || $operation === 'rename') {
|
||||
$last_arg = $arg;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
die('Unexpected argument "' . $arg . '"' . PHP_EOL);
|
||||
}
|
||||
|
||||
if (!$to_move && !$to_rename) {
|
||||
die('No --move or --rename arguments supplied' . PHP_EOL);
|
||||
}
|
||||
|
||||
// initialise custom config, if passed
|
||||
// Initializing the config can be slow, so any UI logic should precede it, if possible
|
||||
if ($path_to_config) {
|
||||
$config = Config::loadFromXMLFile($path_to_config, $current_dir);
|
||||
} else {
|
||||
@ -146,7 +251,9 @@ if ($path_to_config) {
|
||||
|
||||
$config->setComposerClassLoader($first_autoloader);
|
||||
|
||||
$threads = isset($options['threads']) ? (int)$options['threads'] : 1;
|
||||
$threads = isset($options['threads'])
|
||||
? (int)$options['threads']
|
||||
: max(1, ProjectAnalyzer::getCpuCount() - 2);
|
||||
|
||||
$providers = new Psalm\Internal\Provider\Providers(
|
||||
new Psalm\Internal\Provider\FileProvider(),
|
||||
@ -172,16 +279,10 @@ $project_analyzer = new ProjectAnalyzer(
|
||||
|
||||
$config->visitComposerAutoloadFiles($project_analyzer);
|
||||
|
||||
$args = getArguments();
|
||||
|
||||
if (count($args) !== 3 || $args[1] !== 'into') {
|
||||
die('Expecting XXX into YYY' . PHP_EOL);
|
||||
}
|
||||
|
||||
$codebase = $project_analyzer->getCodebase();
|
||||
|
||||
$codebase->method_migrations = [strtolower($args[0]) => $args[2]];
|
||||
$codebase->call_transforms = [strtolower($args[0]) . '\((.*\))' => $args[2] . '($1)'];
|
||||
$codebase->methods_to_move = $to_move;
|
||||
$codebase->call_transforms = $to_rename;
|
||||
|
||||
$project_analyzer->refactorCodeAfterCompletion();
|
||||
|
||||
|
@ -24,7 +24,7 @@ class MoveMethodTest extends \Psalm\Tests\TestCase
|
||||
*
|
||||
* @param string $input_code
|
||||
* @param string $output_code
|
||||
* @param array<string, string> $method_migrations
|
||||
* @param array<string, string> $methods_to_move
|
||||
* @param array<string, string> $call_transforms
|
||||
*
|
||||
* @return void
|
||||
@ -32,7 +32,7 @@ class MoveMethodTest extends \Psalm\Tests\TestCase
|
||||
public function testValidCode(
|
||||
string $input_code,
|
||||
string $output_code,
|
||||
array $method_migrations,
|
||||
array $methods_to_move,
|
||||
array $call_transforms
|
||||
) {
|
||||
$test_name = $this->getTestName();
|
||||
@ -61,7 +61,7 @@ class MoveMethodTest extends \Psalm\Tests\TestCase
|
||||
|
||||
$codebase = $this->project_analyzer->getCodebase();
|
||||
|
||||
$codebase->method_migrations = $method_migrations;
|
||||
$codebase->methods_to_move = $methods_to_move;
|
||||
$codebase->call_transforms = $call_transforms;
|
||||
|
||||
$this->project_analyzer->refactorCodeAfterCompletion();
|
152
tests/FileManipulation/MethodRenameTest.php
Normal file
152
tests/FileManipulation/MethodRenameTest.php
Normal file
@ -0,0 +1,152 @@
|
||||
<?php
|
||||
namespace Psalm\Tests\FileManipulation;
|
||||
|
||||
use Psalm\Context;
|
||||
use Psalm\Internal\Analyzer\FileAnalyzer;
|
||||
use Psalm\Tests\Internal\Provider;
|
||||
use Psalm\Tests\TestConfig;
|
||||
|
||||
class MethodRenameTest extends \Psalm\Tests\TestCase
|
||||
{
|
||||
/** @var \Psalm\Internal\Analyzer\ProjectAnalyzer */
|
||||
protected $project_analyzer;
|
||||
|
||||
public function setUp() : void
|
||||
{
|
||||
FileAnalyzer::clearCache();
|
||||
\Psalm\Internal\FileManipulation\FunctionDocblockManipulator::clearCache();
|
||||
|
||||
$this->file_provider = new Provider\FakeFileProvider();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider providerValidCodeParse
|
||||
*
|
||||
* @param string $input_code
|
||||
* @param string $output_code
|
||||
* @param array<string, string> $methods_to_rename
|
||||
* @param array<string, string> $call_transforms
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testValidCode(
|
||||
string $input_code,
|
||||
string $output_code,
|
||||
array $methods_to_rename,
|
||||
array $call_transforms
|
||||
) {
|
||||
$test_name = $this->getTestName();
|
||||
if (strpos($test_name, 'SKIPPED-') !== false) {
|
||||
$this->markTestSkipped('Skipped due to a bug.');
|
||||
}
|
||||
|
||||
$config = new TestConfig();
|
||||
|
||||
$this->project_analyzer = new \Psalm\Internal\Analyzer\ProjectAnalyzer(
|
||||
$config,
|
||||
new \Psalm\Internal\Provider\Providers(
|
||||
$this->file_provider,
|
||||
new Provider\FakeParserCacheProvider()
|
||||
)
|
||||
);
|
||||
|
||||
$context = new Context();
|
||||
|
||||
$file_path = self::$src_dir_path . 'somefile.php';
|
||||
|
||||
$this->addFile(
|
||||
$file_path,
|
||||
$input_code
|
||||
);
|
||||
|
||||
$codebase = $this->project_analyzer->getCodebase();
|
||||
|
||||
$codebase->call_transforms = $call_transforms;
|
||||
$codebase->methods_to_rename = $methods_to_rename;
|
||||
|
||||
$this->project_analyzer->refactorCodeAfterCompletion();
|
||||
|
||||
$this->analyzeFile($file_path, $context);
|
||||
|
||||
$this->project_analyzer->prepareMigration();
|
||||
|
||||
$codebase->analyzer->updateFile($file_path, false);
|
||||
|
||||
$this->project_analyzer->migrateCode();
|
||||
|
||||
$this->assertSame($output_code, $codebase->getFileContents($file_path));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string,array{string,string,array<string, string>,array<string, string>}>
|
||||
*/
|
||||
public function providerValidCodeParse()
|
||||
{
|
||||
return [
|
||||
'renameMethod' => [
|
||||
'<?php
|
||||
namespace Ns;
|
||||
|
||||
use ArrayObject;
|
||||
|
||||
class A {
|
||||
/**
|
||||
* @return ArrayObject<int, int>
|
||||
*/
|
||||
public function Foo() {
|
||||
return new ArrayObject([self::C]);
|
||||
}
|
||||
|
||||
public function bat() {
|
||||
$this->foo();
|
||||
}
|
||||
}
|
||||
|
||||
class B extends A {
|
||||
public static function bar(A $a) : void {
|
||||
$a->Foo();
|
||||
|
||||
$this->foo();
|
||||
parent::foo();
|
||||
|
||||
foreach ($a->Foo() as $f) {}
|
||||
}
|
||||
}',
|
||||
'<?php
|
||||
namespace Ns;
|
||||
|
||||
use ArrayObject;
|
||||
|
||||
class A {
|
||||
/**
|
||||
* @return ArrayObject<int, int>
|
||||
*/
|
||||
public function Fedcba() {
|
||||
return new ArrayObject([self::C]);
|
||||
}
|
||||
|
||||
public function bat() {
|
||||
$this->Fedcba();
|
||||
}
|
||||
}
|
||||
|
||||
class B extends A {
|
||||
public static function bar(A $a) : void {
|
||||
$a->Fedcba();
|
||||
|
||||
$this->Fedcba();
|
||||
parent::Fedcba();
|
||||
|
||||
foreach ($a->Fedcba() as $f) {}
|
||||
}
|
||||
}',
|
||||
[
|
||||
'ns\a::foo' => 'Fedcba',
|
||||
],
|
||||
[
|
||||
'ns\a::foo\((.*\))' => 'Ns\A::Fedcba($1)',
|
||||
]
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user