Skip to content

Detect function variadic-ness within top-level function_exists() #3370

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Sep 3, 2024

Conversation

staabm
Copy link
Contributor

@staabm staabm commented Aug 28, 2024

@staabm staabm marked this pull request as ready for review August 28, 2024 17:17
@phpstan-bot
Copy link
Collaborator

This pull request has been marked as ready for review.

Copy link
Member

@ondrejmirtes ondrejmirtes left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like this code is too complicated. We could simply traverse through everything similarly to how we do here:

if ($node instanceof Node) {
$callbackResult = $nodeCallback($node);
if ($callbackResult === self::SKIP_NODE) {
return;
}
foreach ($node->getSubNodeNames() as $subNodeName) {
$subNode = $node->{$subNodeName};
$this->processNodes($subNode, $nodeCallback, $endNodeCallback);
}
$endNodeCallback($node, $callbackResult);
} elseif (is_array($node)) {
foreach ($node as $subNode) {
$this->processNodes($subNode, $nodeCallback, $endNodeCallback);
}
}

What's more important to also solve here is to answer the question: What if we find the same function multiple times? Is it enough if one of them is variadic, or all of them need to be variadic?

Also we might find multiple functions and some of them might be variadic natively (...$params) and some only through func_get_args(). The code needs to account for that.

And last but not least, do not forget to bump the version in the cache key here :)

@staabm
Copy link
Contributor Author

staabm commented Aug 30, 2024

I feel like this code is too complicated

from the pre-existing code I got the impression its on purpose filtering only the smallest possible AST, therefore I went with this ugly if-else analysis. adjusted it now to analyze the whole AST.

Also we might find multiple functions and some of them might be variadic natively (...$params) and some only through func_get_args(). The code needs to account for that.

I added tests for the cases, I think it works as expected now.

And last but not least, do not forget to bump the version in the cache key here :)

great catch

if ($node instanceof Function_) {
$functionName = (string) $node->namespacedName;

if ($functionName === $this->reflection->getName()) {
return $this->functionCallStatementFinder->findFunctionCallInStatements(ParametersAcceptor::VARIADIC_FUNCTIONS, $node->getStmts()) !== null;
return TrinaryLogic::createFromBoolean($this->functionCallStatementFinder->findFunctionCallInStatements(ParametersAcceptor::VARIADIC_FUNCTIONS, $node->getStmts()) !== null);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I'm missing looking at Param::$variadic here. Now it looks like it treats function foo($bar) { } and function foo(...$bar) { } the same and passes the function as variadic in either case. I think it should be more strict.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

native variadic is already checked in the outer scope.

for native variadic we don't call into callsFuncGetArgs at all

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can have a situation when $isNativelyVariadic = $this->reflection->isVariadic(); returns false and still one of the function declarations in the file might have function foo(...$bar) .

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please reproduce this situation and fix it, thanks.

Copy link
Contributor Author

@staabm staabm Sep 3, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was not able to reproduce it initially because of the caching involved.

After temporarily using different cache keys locally the case was showing up :-)

@ondrejmirtes
Copy link
Member

Alright, this works for me :) Thank you!

@ondrejmirtes ondrejmirtes merged commit 0ee67d5 into phpstan:1.12.x Sep 3, 2024
488 of 499 checks passed
@staabm staabm deleted the bug11559 branch September 3, 2024 07:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Stubs not working in combination with function_exists() func_get_args
3 participants