Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,6 @@ parameters:
- rules/Php70/EregToPcreTransformer.php
- src/BetterPhpDocParser/PhpDocManipulator/PhpDocClassRenamer.php
- src/NodeTypeResolver/PHPStan/Type/TypeFactory.php
- rules/CodeQuality/Rector/Class_/InnerFunctionToPrivateMethodRector.php
- rules/CodeQuality/NodeAnalyzer/VariableDimFetchAssignResolver.php
- src/Parallel/Experimental/ExperimentalParallelFileProcessor.php

Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

160 changes: 8 additions & 152 deletions rules/CodeQuality/Rector/Class_/InnerFunctionToPrivateMethodRector.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,18 @@

namespace Rector\CodeQuality\Rector\Class_;

use PhpParser\Modifiers;
use PhpParser\Node;
use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\StaticCall;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Name;
use PhpParser\Node\Scalar\String_;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Function_;
use Rector\Configuration\Deprecation\Contract\DeprecatedInterface;
use Rector\Exception\ShouldNotHappenException;
use Rector\Rector\AbstractRector;
use Rector\RuleDoc\CodeSample\CodeSample;
use Rector\RuleDoc\RuleDefinition;

/**
* @see \Rector\Tests\CodeQuality\Rector\Class_\InnerFunctionToPrivateMethodRector\InnerFunctionToPrivateMethodRectorTest
* @deprecated This rule is deprecated, as moving an inner named function to a private method is a niche change that can alter behavior in undesired ways and needs a human check.
*/
final class InnerFunctionToPrivateMethodRector extends AbstractRector
final class InnerFunctionToPrivateMethodRector extends AbstractRector implements DeprecatedInterface
{
public function getRuleDefinition(): RuleDefinition
{
Expand Down Expand Up @@ -77,146 +70,9 @@ public function getNodeTypes(): array
*/
public function refactor(Node $node): ?Node
{
$existingMethodNames = array_map(
fn (ClassMethod $classMethod): string => $classMethod->name->toString(),
$node->getMethods()
);

$newClassMethods = [];

foreach ($node->getMethods() as $classMethod) {
$innerFunctions = $this->extractInnerFunctions($classMethod, $existingMethodNames);
if ($innerFunctions === []) {
continue;
}

$isStatic = $classMethod->isStatic();
$innerFunctionNames = array_map(
fn (Function_ $innerFunction): string => $innerFunction->name->toString(),
$innerFunctions
);

foreach ($innerFunctions as $innerFunction) {
$newClassMethod = $this->createPrivateMethod($innerFunction, $isStatic);
$this->rewriteCallsToMethod($newClassMethod, $innerFunctionNames, $isStatic);
$newClassMethods[] = $newClassMethod;
}

$this->rewriteCallsToMethod($classMethod, $innerFunctionNames, $isStatic);
}

if ($newClassMethods === []) {
return null;
}

$node->stmts = array_merge($node->stmts, $newClassMethods);

return $node;
}

/**
* @param string[] $existingMethodNames
* @return Function_[]
*/
private function extractInnerFunctions(ClassMethod $classMethod, array &$existingMethodNames): array
{
$innerFunctions = [];

foreach ($classMethod->stmts ?? [] as $key => $stmt) {
if (! $stmt instanceof Function_) {
continue;
}

$functionName = $stmt->name->toString();

// avoid collision with an already existing method
if (in_array($functionName, $existingMethodNames, true)) {
continue;
}

// avoid breaking string callables, e.g. usort($items, 'functionName')
if ($this->isReferencedAsStringCallable($classMethod, $functionName)) {
continue;
}

$existingMethodNames[] = $functionName;
$innerFunctions[] = $stmt;
unset($classMethod->stmts[$key]);
}

if ($innerFunctions !== []) {
$classMethod->stmts = array_values((array) $classMethod->stmts);
}

return $innerFunctions;
}

private function isReferencedAsStringCallable(ClassMethod $classMethod, string $functionName): bool
{
$isReferenced = false;

$this->traverseNodesWithCallable($classMethod->stmts ?? [], function (Node $node) use (
$functionName,
&$isReferenced
): null {
if ($node instanceof String_ && $node->value === $functionName) {
$isReferenced = true;
}

return null;
});

return $isReferenced;
}

private function createPrivateMethod(Function_ $innerFunction, bool $isStatic): ClassMethod
{
$flags = Modifiers::PRIVATE;
if ($isStatic) {
$flags |= Modifiers::STATIC;
}

$classMethod = new ClassMethod($innerFunction->name, [
'flags' => $flags,
'byRef' => $innerFunction->byRef,
'params' => $innerFunction->params,
'returnType' => $innerFunction->returnType,
'stmts' => $innerFunction->stmts,
'attrGroups' => $innerFunction->attrGroups,
]);

$this->mirrorComments($classMethod, $innerFunction);

return $classMethod;
}

/**
* @param string[] $innerFunctionNames
*/
private function rewriteCallsToMethod(ClassMethod $classMethod, array $innerFunctionNames, bool $isStatic): void
{
$this->traverseNodesWithCallable($classMethod->stmts ?? [], function (Node $node) use (
$innerFunctionNames,
$isStatic
): MethodCall|StaticCall|null {
if (! $node instanceof FuncCall) {
return null;
}

if (! $node->name instanceof Name) {
return null;
}

$functionName = $node->name->toString();
if (! in_array($functionName, $innerFunctionNames, true)) {
return null;
}

if ($isStatic) {
return new StaticCall(new Name('self'), $functionName, $node->args);
}

return new MethodCall(new Variable('this'), $functionName, $node->args);
});
throw new ShouldNotHappenException(sprintf(
'"%s" rule is deprecated, as it is a niche change that can alter behavior in undesired ways and needs a human check',
self::class
));
}
}
2 changes: 0 additions & 2 deletions src/Config/Level/CodeQualityLevel.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
use Rector\CodeQuality\Rector\Class_\CompleteDynamicPropertiesRector;
use Rector\CodeQuality\Rector\Class_\ConvertStaticToSelfRector;
use Rector\CodeQuality\Rector\Class_\InlineConstructorDefaultToPropertyRector;
use Rector\CodeQuality\Rector\Class_\InnerFunctionToPrivateMethodRector;
use Rector\CodeQuality\Rector\ClassConstFetch\VariableConstFetchToClassConstFetchRector;
use Rector\CodeQuality\Rector\ClassMethod\ExplicitReturnNullRector;
use Rector\CodeQuality\Rector\ClassMethod\InlineArrayReturnAssignRector;
Expand Down Expand Up @@ -110,7 +109,6 @@ final class CodeQualityLevel
ForeachToInArrayRector::class,
RepeatedOrEqualToInArrayRector::class,
RepeatedAndNotEqualToNotInArrayRector::class,
InnerFunctionToPrivateMethodRector::class,
SimplifyForeachToCoalescingRector::class,
SimplifyFuncGetArgsCountRector::class,
SimplifyInArrayValuesRector::class,
Expand Down
Loading