mirror of
https://github.com/rectorphp/rector.git
synced 2025-01-17 21:38:22 +01:00
commit
d337f6e6e7
@ -199,7 +199,7 @@
|
||||
"ecs check bin packages src tests utils compiler --fix --ansi",
|
||||
"ci/clean_trailing_spaces.sh"
|
||||
],
|
||||
"phpstan": "phpstan analyse packages src tests compiler/src --ansi",
|
||||
"phpstan": "phpstan analyse packages src tests compiler/src --ansi --error-format symplify",
|
||||
"changelog": [
|
||||
"changelog-linker dump-merges --in-categories",
|
||||
"changelog-linker link",
|
||||
|
@ -69,7 +69,7 @@ final class OriginalSpacingRestorer
|
||||
|
||||
if ($node instanceof DoctrineTagNodeInterface) {
|
||||
// give back "\s+\*" as well
|
||||
if (($i - 1) > $start) { // do not overlap to previous node
|
||||
if ($i - 1 > $start) { // do not overlap to previous node
|
||||
if (isset($tokens[$i - 1]) && $tokens[$i - 1][1] === Lexer::TOKEN_PHPDOC_EOL) {
|
||||
$previousTokenValue = $tokens[$i - 1][0];
|
||||
if (Strings::match($previousTokenValue, '#\s+\*#m')) {
|
||||
|
@ -63,9 +63,13 @@ PHP
|
||||
}
|
||||
|
||||
$functionName = $this->getValue($node->args[0]->value);
|
||||
if (! is_string($functionName)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$args = [];
|
||||
$args[] = new Arg($node->args[1]->value, false, true);
|
||||
|
||||
return $this->createFunction($functionName, $args);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\CodingStyle\Tests\Rector\FuncCall\CallUserFuncCallToVariadicRector\Fixture;
|
||||
|
||||
class SkipUnknownValue
|
||||
{
|
||||
public function run($name)
|
||||
{
|
||||
call_user_func_array($name, $items);
|
||||
}
|
||||
}
|
@ -651,7 +651,7 @@ final class NodeTypeResolver
|
||||
return $originalType;
|
||||
}
|
||||
|
||||
private function getScopeNode(Node $node): Node
|
||||
private function getScopeNode(Node $node): ?Node
|
||||
{
|
||||
return $node->getAttribute(AttributeKey::METHOD_NODE)
|
||||
?? $node->getAttribute(AttributeKey::FUNCTION_NODE)
|
||||
@ -665,6 +665,10 @@ final class NodeTypeResolver
|
||||
{
|
||||
$scope = $this->getScopeNode($variable);
|
||||
|
||||
if ($scope === null) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $this->betterNodeFinder->find((array) $scope->stmts, function (Node $node) use ($variable): bool {
|
||||
return $node instanceof Variable && $node->name === $variable->name;
|
||||
});
|
||||
|
@ -622,7 +622,8 @@ final class StaticTypeMapper
|
||||
|
||||
if ($typeNode instanceof GenericTypeNode) {
|
||||
if ($typeNode->type instanceof IdentifierTypeNode) {
|
||||
if ($typeNode->type->name === 'array') {
|
||||
$typeName = $typeNode->type->name;
|
||||
if (in_array($typeName, ['array', 'iterable'], true)) {
|
||||
$genericTypes = [];
|
||||
foreach ($typeNode->genericTypes as $genericTypeNode) {
|
||||
$genericTypes[] = $this->mapPHPStanPhpDocTypeNodeToPHPStanType($genericTypeNode, $node);
|
||||
@ -630,7 +631,11 @@ final class StaticTypeMapper
|
||||
|
||||
$genericType = $this->typeFactory->createMixedPassedOrUnionType($genericTypes);
|
||||
|
||||
return new ArrayType(new MixedType(), $genericType);
|
||||
if ($typeName === 'array') {
|
||||
return new ArrayType(new MixedType(), $genericType);
|
||||
}
|
||||
|
||||
return new IterableType(new MixedType(), $genericType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -132,7 +132,7 @@ PHP
|
||||
}
|
||||
|
||||
// simple check argument count fits to method required args
|
||||
if ((count($values) % $numberOfParameters) !== 0) {
|
||||
if (count($values) % $numberOfParameters !== 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -83,7 +83,7 @@ PHP
|
||||
unset($node->stmts[$key]);
|
||||
}
|
||||
|
||||
$node->stmts = array_merge($node->stmts, (array) $proccesed);
|
||||
$node->stmts = array_merge((array) $node->stmts, (array) $proccesed);
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
@ -118,6 +118,9 @@ final class NormalizeNamespaceByPSR4ComposerAutoloadRector extends AbstractRecto
|
||||
$psr4Autoloads = $this->psR4AutoloadPathsProvider->provide();
|
||||
|
||||
foreach ($psr4Autoloads as $namespace => $path) {
|
||||
// remove extra slash
|
||||
$path = rtrim($path, '/');
|
||||
|
||||
if (Strings::startsWith($smartFileInfo->getRelativeDirectoryPath(), $path)) {
|
||||
$expectedNamespace = $namespace . $this->resolveExtraNamespace($smartFileInfo, $path);
|
||||
|
||||
|
@ -6,6 +6,7 @@ namespace Rector\Php53\Rector\Ternary;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\Ternary;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
use Rector\Rector\AbstractRector;
|
||||
use Rector\RectorDefinition\CodeSample;
|
||||
use Rector\RectorDefinition\RectorDefinition;
|
||||
@ -55,6 +56,7 @@ PHP
|
||||
return null;
|
||||
}
|
||||
|
||||
$node->setAttribute(AttributeKey::ORIGINAL_NODE, null);
|
||||
$node->if = null;
|
||||
|
||||
return $node;
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\Php53\Tests\Rector\Ternary\TernaryToElvisRector\Fixture;
|
||||
|
||||
function elvis()
|
||||
{
|
||||
$value = $a ? $a : false;
|
||||
@ -9,6 +11,8 @@ function elvis()
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\Php53\Tests\Rector\Ternary\TernaryToElvisRector\Fixture;
|
||||
|
||||
function elvis()
|
||||
{
|
||||
$value = $a ?: false;
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\Php53\Tests\Rector\Ternary\TernaryToElvisRector\Fixture;
|
||||
|
||||
function elvisRemoveParenthesis()
|
||||
{
|
||||
$value = ($a - $b) ? ($a - $b) : $c;
|
||||
@ -9,9 +11,11 @@ function elvisRemoveParenthesis()
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\Php53\Tests\Rector\Ternary\TernaryToElvisRector\Fixture;
|
||||
|
||||
function elvisRemoveParenthesis()
|
||||
{
|
||||
$value = ($a - $b) ?: $c;
|
||||
$value = $a - $b ?: $c;
|
||||
}
|
||||
|
||||
?>
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\Php53\Tests\Rector\Ternary\TernaryToElvisRector\Fixture;
|
||||
|
||||
function elvisYolo()
|
||||
{
|
||||
1 ?: 2;
|
||||
|
@ -34,11 +34,6 @@ use Rector\RectorDefinition\RectorDefinition;
|
||||
*/
|
||||
final class AddDefaultValueForUndefinedVariableRector extends AbstractRector
|
||||
{
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
private $undefinedVariables = [];
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
@ -92,47 +87,14 @@ PHP
|
||||
public function refactor(Node $node): ?Node
|
||||
{
|
||||
$this->definedVariables = [];
|
||||
$this->undefinedVariables = [];
|
||||
|
||||
$this->traverseNodesWithCallable((array) $node->stmts, function (Node $node): ?int {
|
||||
// entering new scope - break!
|
||||
if ($node instanceof FunctionLike) {
|
||||
return NodeTraverser::STOP_TRAVERSAL;
|
||||
}
|
||||
|
||||
$this->collectDefinedVariablesFromForeach($node);
|
||||
|
||||
if (! $node instanceof Variable) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($this->shouldSkipVariable($node)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @var string $variableName */
|
||||
$variableName = $this->getName($node);
|
||||
|
||||
// defined 100 %
|
||||
/** @var Scope $nodeScope */
|
||||
$nodeScope = $node->getAttribute(AttributeKey::SCOPE);
|
||||
if ($nodeScope->hasVariableType($variableName)->yes()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$this->undefinedVariables[] = $variableName;
|
||||
|
||||
return null;
|
||||
});
|
||||
|
||||
if ($this->undefinedVariables === []) {
|
||||
$undefinedVariables = $this->collectUndefinedVariableScope($node);
|
||||
if ($undefinedVariables === []) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$this->undefinedVariables = array_unique($this->undefinedVariables);
|
||||
|
||||
$variablesInitiation = [];
|
||||
foreach ($this->undefinedVariables as $undefinedVariable) {
|
||||
foreach ($undefinedVariables as $undefinedVariable) {
|
||||
if (in_array($undefinedVariable, $this->definedVariables, true)) {
|
||||
continue;
|
||||
}
|
||||
@ -170,7 +132,6 @@ PHP
|
||||
private function shouldSkipVariable(Variable $variable): bool
|
||||
{
|
||||
$parentNode = $variable->getAttribute(AttributeKey::PARENT_NODE);
|
||||
|
||||
if ($parentNode instanceof Global_) {
|
||||
return true;
|
||||
}
|
||||
@ -188,21 +149,23 @@ PHP
|
||||
}
|
||||
|
||||
// list() = | [$values] = defines variables as null
|
||||
if ($parentNode instanceof Node) {
|
||||
$parentParentNode = $parentNode->getAttribute(AttributeKey::PARENT_NODE);
|
||||
if ($parentParentNode instanceof List_ || $parentParentNode instanceof Array_) {
|
||||
return true;
|
||||
}
|
||||
if ($this->isListAssign($parentNode)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/** @var Scope|null $nodeScope */
|
||||
$nodeScope = $variable->getAttribute(AttributeKey::SCOPE);
|
||||
|
||||
if ($nodeScope === null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$variableName = $this->getName($variable);
|
||||
|
||||
// skip $this, as probably in outer scope
|
||||
if ($variableName === 'this') {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $variableName === null;
|
||||
}
|
||||
|
||||
@ -218,4 +181,57 @@ PHP
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ClassMethod|Function_|Closure $node
|
||||
* @return string[]
|
||||
*/
|
||||
private function collectUndefinedVariableScope(Node $node): array
|
||||
{
|
||||
$undefinedVariables = [];
|
||||
$this->traverseNodesWithCallable((array) $node->stmts, function (Node $node) use (&$undefinedVariables): ?int {
|
||||
// entering new scope - break!
|
||||
if ($node instanceof FunctionLike) {
|
||||
return NodeTraverser::STOP_TRAVERSAL;
|
||||
}
|
||||
|
||||
$this->collectDefinedVariablesFromForeach($node);
|
||||
|
||||
if (! $node instanceof Variable) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($this->shouldSkipVariable($node)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @var string $variableName */
|
||||
$variableName = $this->getName($node);
|
||||
|
||||
// defined 100 %
|
||||
/** @var Scope $nodeScope */
|
||||
$nodeScope = $node->getAttribute(AttributeKey::SCOPE);
|
||||
if ($nodeScope->hasVariableType($variableName)->yes()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$undefinedVariables[] = $variableName;
|
||||
|
||||
return null;
|
||||
});
|
||||
|
||||
return array_unique($undefinedVariables);
|
||||
}
|
||||
|
||||
private function isListAssign(?Node $parentNode): bool
|
||||
{
|
||||
if ($parentNode instanceof Node) {
|
||||
$parentParentNode = $parentNode->getAttribute(AttributeKey::PARENT_NODE);
|
||||
if ($parentParentNode instanceof List_ || $parentParentNode instanceof Array_) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -11,5 +11,5 @@ $fn = function() {
|
||||
return $this->val;
|
||||
};
|
||||
|
||||
$closure = Closure::bind($fn, new SkipThisAssign(), 'SkipThisAssign');
|
||||
$closure = \Closure::bind($fn, new SkipThisAssign(), '\Rector\Php56\Tests\Rector\FunctionLike\AddDefaultValueForUndefinedVariableRector\Fixture\SkipThisAssign');
|
||||
echo $closure(), "\n";
|
||||
|
@ -68,10 +68,6 @@ PHP
|
||||
return null;
|
||||
}
|
||||
|
||||
if (! isset($node->args[0])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$countedNode = $node->args[0]->value;
|
||||
if ($this->isCountableType($countedNode)) {
|
||||
return null;
|
||||
@ -111,7 +107,14 @@ PHP
|
||||
}
|
||||
|
||||
$parentNode = $funcCall->getAttribute(AttributeKey::PARENT_NODE);
|
||||
if ($parentNode instanceof Ternary) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $parentNode instanceof Ternary;
|
||||
if (! isset($funcCall->args[0])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
includes:
|
||||
- 'utils/PHPStanExtensions/config/phpstan-extensions.neon'
|
||||
- 'vendor/symplify/phpstan-extensions/config/php.level.neon'
|
||||
- 'vendor/symplify/phpstan-extensions/config/symfony.level.neon'
|
||||
- 'vendor/symplify/phpstan-extensions/config/config.neon'
|
||||
- 'vendor/thecodingmachine/phpstan-strict-rules/phpstan-strict-rules.neon'
|
||||
|
||||
parameters:
|
||||
@ -224,3 +223,7 @@ parameters:
|
||||
|
||||
# phpstan compiler bug
|
||||
- '#Parameter \#1 \$docComment of method PhpParser\\Builder\\Property::setDocComment\(\) expects _HumbugBox(.*?)\\PhpParser\\Comment\\Doc\|string, PhpParser\\Comment\\Doc given#'
|
||||
|
||||
-
|
||||
message: '#Call to function in_array\(\) with arguments PhpParser\\Node\\Expr\\Variable, array\(\) and true will always evaluate to false#'
|
||||
path: packages/Php56/src/Rector/FunctionLike/AddDefaultValueForUndefinedVariableRector.php
|
||||
|
@ -1,3 +1,6 @@
|
||||
services:
|
||||
Rector\PSR4\Rector\Namespace_\NormalizeNamespaceByPSR4ComposerAutoloadRector: ~
|
||||
|
||||
parameters:
|
||||
exclude_paths:
|
||||
- "/Fixture/"
|
||||
|
@ -189,7 +189,7 @@ PHP
|
||||
|
||||
// clear following arguments
|
||||
$argumentCountToClear = count($before);
|
||||
for ($i = $position + 1; $i <= ($position + $argumentCountToClear); ++$i) {
|
||||
for ($i = $position + 1; $i <= $position + $argumentCountToClear; ++$i) {
|
||||
unset($argumentNodes[$i]);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user