diff --git a/src/Rules/FunctionCallParametersCheck.php b/src/Rules/FunctionCallParametersCheck.php index 74ceec9c00..16c0938b06 100644 --- a/src/Rules/FunctionCallParametersCheck.php +++ b/src/Rules/FunctionCallParametersCheck.php @@ -89,6 +89,12 @@ public function check( string $namedArgumentMessage, ): array { + if ($funcCall instanceof Node\Expr\MethodCall || $funcCall instanceof Node\Expr\StaticCall || $funcCall instanceof Node\Expr\FuncCall) { + $funcCallLine = $funcCall->name->getStartLine(); + } else { + $funcCallLine = $funcCall->getStartLine(); + } + $functionParametersMinCount = 0; $functionParametersMaxCount = 0; foreach ($parametersAcceptor->getParameters() as $parameter) { @@ -225,7 +231,7 @@ public function check( if ($hasNamedArguments && !$scope->getPhpVersion()->supportsNamedArguments()->yes() && !(bool) $funcCall->getAttribute('isAttribute', false)) { $errors[] = RuleErrorBuilder::message('Named arguments are supported only on PHP 8.0 and later.') ->identifier('argument.namedNotSupported') - ->line($funcCall->getStartLine()) + ->line($funcCallLine) ->nonIgnorable() ->build(); } @@ -250,7 +256,7 @@ public function check( $functionParametersMinCount, )) ->identifier('arguments.count') - ->line($funcCall->getStartLine()) + ->line($funcCallLine) ->build(); } elseif ($functionParametersMaxCount === -1 && $invokedParametersCount < $functionParametersMinCount) { $errors[] = RuleErrorBuilder::message(sprintf( @@ -259,7 +265,7 @@ public function check( $functionParametersMinCount, )) ->identifier('arguments.count') - ->line($funcCall->getStartLine()) + ->line($funcCallLine) ->build(); } elseif ($functionParametersMaxCount !== -1) { $errors[] = RuleErrorBuilder::message(sprintf( @@ -269,7 +275,7 @@ public function check( $functionParametersMaxCount, )) ->identifier('arguments.count') - ->line($funcCall->getStartLine()) + ->line($funcCallLine) ->build(); } } @@ -282,11 +288,11 @@ public function check( ) { $errors[] = RuleErrorBuilder::message($voidReturnTypeUsed) ->identifier(sprintf('%s.void', $nodeType)) - ->line($funcCall->getStartLine()) + ->line($funcCallLine) ->build(); } - [$addedErrors, $argumentsWithParameters] = $this->processArguments($parametersAcceptor, $funcCall->getStartLine(), $isBuiltin, $arguments, $hasNamedArguments, $missingParameterMessage, $unknownParameterMessage); + [$addedErrors, $argumentsWithParameters] = $this->processArguments($parametersAcceptor, $funcCallLine, $isBuiltin, $arguments, $hasNamedArguments, $missingParameterMessage, $unknownParameterMessage); foreach ($addedErrors as $error) { $errors[] = $error; } @@ -528,7 +534,7 @@ static function (Type $type, callable $traverse) use (&$returnTemplateTypes): Ty $errors[] = RuleErrorBuilder::message(sprintf($unresolvableTemplateTypeMessage, $name)) ->identifier('argument.templateType') - ->line($funcCall->getStartLine()) + ->line($funcCallLine) ->tip('See: https://phpstan.org/blog/solving-phpstan-error-unable-to-resolve-template-type') ->build(); } @@ -540,7 +546,7 @@ static function (Type $type, callable $traverse) use (&$returnTemplateTypes): Ty ) { $errors[] = RuleErrorBuilder::message($unresolvableReturnTypeMessage) ->identifier(sprintf('%s.unresolvableReturnType', $nodeType)) - ->line($funcCall->getStartLine()) + ->line($funcCallLine) ->build(); } } diff --git a/tests/PHPStan/Rules/Methods/CallMethodsRuleTest.php b/tests/PHPStan/Rules/Methods/CallMethodsRuleTest.php index 0ab14fd52a..1c56de9b57 100644 --- a/tests/PHPStan/Rules/Methods/CallMethodsRuleTest.php +++ b/tests/PHPStan/Rules/Methods/CallMethodsRuleTest.php @@ -3853,4 +3853,29 @@ public function testBug13805(): void $this->analyse([__DIR__ . '/data/bug-13805.php'], []); } + public function testBug9820(): void + { + $this->checkThisOnly = false; + $this->checkNullables = true; + $this->checkUnionTypes = true; + $this->analyse([__DIR__ . '/data/bug-9820.php'], [ + [ + 'Method Bug9820\HelloWorld::x() invoked with 1 parameter, 0 required.', + 20, + ], + [ + 'Method Bug9820\HelloWorld::x() invoked with 1 parameter, 0 required.', + 27, + ], + [ + 'Method Bug9820\HelloWorld::x() invoked with 1 parameter, 0 required.', + 33, + ], + [ + 'Method Bug9820\HelloWorld::x() invoked with 1 parameter, 0 required.', + 40, + ], + ]); + } + } diff --git a/tests/PHPStan/Rules/Methods/data/bug-9820.php b/tests/PHPStan/Rules/Methods/data/bug-9820.php new file mode 100644 index 0000000000..3c1f819aaa --- /dev/null +++ b/tests/PHPStan/Rules/Methods/data/bug-9820.php @@ -0,0 +1,42 @@ += 8.0 + +declare(strict_types = 1); + +namespace Bug9820; + +class HelloWorld +{ + /** + * @return $this + */ + public function x(): static + { + return $this; + } + + public function test(): void + { + $this + ->x(1); + } + + public function test2(): void + { + $this + ->x() + ->x(1); + } + + public function test3(?self $selfOrNull): void + { + $selfOrNull + ?->x(1); + } + + public function test4(?self $selfOrNull): void + { + $selfOrNull + ?->x() + ?->x(1); + } +}