Skip to content

Commit 9a36e8a

Browse files
committed
fix
1 parent 31e3a4c commit 9a36e8a

File tree

3 files changed

+58
-2
lines changed

3 files changed

+58
-2
lines changed

src/NodeCollector/NodeAnalyzer/ArrayCallableMethodMatcher.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,9 @@ public function match(
7272
return null;
7373
}
7474

75-
if ($array->getAttribute(AttributeKey::IS_ARG_VALUE) === true) {
75+
if ($array->getAttribute(AttributeKey::IS_ARG_VALUE) === true && (bool) $array->getAttribute(
76+
AttributeKey::IS_ARG_VALUE_CALLABLE
77+
) === false) {
7678
return null;
7779
}
7880

src/NodeTypeResolver/Node/AttributeKey.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,4 +166,6 @@ final class AttributeKey
166166
public const string HAS_CLOSURE_WITH_VARIADIC_ARGS = 'has_closure_with_variadic_args';
167167

168168
public const string IS_IN_TRY_BLOCK = 'is_in_try_block';
169+
170+
public const string IS_ARG_VALUE_CALLABLE = 'is_arg_value_callable';
169171
}

src/PhpParser/NodeVisitor/ContextNodeVisitor.php

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use PhpParser\Node\Expr\Array_;
1111
use PhpParser\Node\Expr\ArrayDimFetch;
1212
use PhpParser\Node\Expr\BinaryOp\BooleanAnd;
13+
use PhpParser\Node\Expr\CallLike;
1314
use PhpParser\Node\Expr\Closure;
1415
use PhpParser\Node\Expr\Isset_;
1516
use PhpParser\Node\Expr\PostDec;
@@ -19,6 +20,7 @@
1920
use PhpParser\Node\Expr\PropertyFetch;
2021
use PhpParser\Node\Expr\StaticPropertyFetch;
2122
use PhpParser\Node\Expr\Variable;
23+
use PhpParser\Node\Identifier;
2224
use PhpParser\Node\Name\FullyQualified;
2325
use PhpParser\Node\Param;
2426
use PhpParser\Node\Stmt\Break_;
@@ -36,15 +38,22 @@
3638
use PhpParser\Node\Stmt\While_;
3739
use PhpParser\NodeVisitor;
3840
use PhpParser\NodeVisitorAbstract;
41+
use PHPStan\Analyser\Scope;
42+
use PHPStan\Reflection\FunctionReflection;
43+
use PHPStan\Reflection\MethodReflection;
44+
use PHPStan\Type\ArrayType;
3945
use Rector\Contract\PhpParser\DecoratingNodeVisitorInterface;
4046
use Rector\NodeTypeResolver\Node\AttributeKey;
47+
use Rector\NodeTypeResolver\PHPStan\ParametersAcceptorSelectorVariantsWrapper;
4148
use Rector\PhpDocParser\NodeTraverser\SimpleCallableNodeTraverser;
4249
use Rector\PhpParser\NodeTraverser\SimpleNodeTraverser;
50+
use Rector\Reflection\ReflectionResolver;
4351

4452
final class ContextNodeVisitor extends NodeVisitorAbstract implements DecoratingNodeVisitorInterface
4553
{
4654
public function __construct(
47-
private readonly SimpleCallableNodeTraverser $simpleCallableNodeTraverser
55+
private readonly SimpleCallableNodeTraverser $simpleCallableNodeTraverser,
56+
private readonly ReflectionResolver $reflectionResolver
4857
) {
4958
}
5059

@@ -92,6 +101,49 @@ public function enterNode(Node $node): ?Node
92101
return null;
93102
}
94103

104+
if ($node instanceof CallLike && ! $node->isFirstClassCallable()) {
105+
$functionReflection = $this->reflectionResolver->resolveFunctionLikeReflectionFromCall($node);
106+
if (! $functionReflection instanceof FunctionReflection && ! $functionReflection instanceof MethodReflection) {
107+
return null;
108+
}
109+
110+
$scope = $node->getAttribute(AttributeKey::SCOPE);
111+
if (! $scope instanceof Scope) {
112+
return null;
113+
}
114+
115+
$parametersAcceptor = ParametersAcceptorSelectorVariantsWrapper::select(
116+
$functionReflection,
117+
$node,
118+
$scope
119+
);
120+
121+
$args = $node->getArgs();
122+
foreach ($parametersAcceptor->getParameters() as $key => $parameterReflection) {
123+
// also process maybe callable
124+
if ($parameterReflection->getType()->isCallable()->no()) {
125+
continue;
126+
}
127+
128+
if ($parameterReflection->getType() instanceof ArrayType) {
129+
continue;
130+
}
131+
132+
// based on name
133+
foreach ($args as $arg) {
134+
if ($arg->name instanceof Identifier && $parameterReflection->getName() === $arg->name->toString()) {
135+
$arg->value->setAttribute(AttributeKey::IS_ARG_VALUE_CALLABLE, true);
136+
continue 2;
137+
}
138+
}
139+
140+
// based on key
141+
if (isset($args[$key])) {
142+
$args[$key]->value->setAttribute(AttributeKey::IS_ARG_VALUE_CALLABLE, true);
143+
}
144+
}
145+
}
146+
95147
if ($node instanceof Arg) {
96148
$node->value->setAttribute(AttributeKey::IS_ARG_VALUE, true);
97149
return null;

0 commit comments

Comments
 (0)