diff --git a/src/Analyser/ArgumentsNormalizer.php b/src/Analyser/ArgumentsNormalizer.php index 7d5cf5718f8..a0cddf48586 100644 --- a/src/Analyser/ArgumentsNormalizer.php +++ b/src/Analyser/ArgumentsNormalizer.php @@ -293,6 +293,23 @@ public static function reorderNewArguments( ); } + /** + * The argument bound to the parameter at $position named $name: the + * positional argument at that index or the one passed by that name. + * + * @param Arg[] $args + */ + public static function getArgByPositionOrName(array $args, int $position, string $name): ?Arg + { + foreach ($args as $i => $arg) { + if ($arg->name === null ? $i === $position : $arg->name->toString() === $name) { + return $arg; + } + } + + return null; + } + /** * @param Arg[] $callArgs * @return ?list diff --git a/src/Parser/ArrayFilterArgVisitor.php b/src/Parser/ArrayFilterArgVisitor.php index 09b11ff3ad6..5469f7f598e 100644 --- a/src/Parser/ArrayFilterArgVisitor.php +++ b/src/Parser/ArrayFilterArgVisitor.php @@ -5,6 +5,7 @@ use Override; use PhpParser\Node; use PhpParser\NodeVisitorAbstract; +use PHPStan\Analyser\ArgumentsNormalizer; use PHPStan\DependencyInjection\AutowiredService; use PHPStan\Turbo\ShadowedByTurboExtension; @@ -21,9 +22,9 @@ public function enterNode(Node $node): ?Node if ($node instanceof Node\Expr\FuncCall && $node->name instanceof Node\Name && !$node->isFirstClassCallable()) { $functionName = $node->name->toLowerString(); if ($functionName === 'array_filter') { - $args = $node->getArgs(); - if (isset($args[0])) { - $args[0]->setAttribute(self::ATTRIBUTE_NAME, true); + $arg = ArgumentsNormalizer::getArgByPositionOrName($node->getArgs(), 0, 'array'); + if ($arg !== null) { + $arg->setAttribute(self::ATTRIBUTE_NAME, true); } } } diff --git a/src/Parser/ArrayFindArgVisitor.php b/src/Parser/ArrayFindArgVisitor.php index ca52b483b72..3cd765d49af 100644 --- a/src/Parser/ArrayFindArgVisitor.php +++ b/src/Parser/ArrayFindArgVisitor.php @@ -5,6 +5,7 @@ use Override; use PhpParser\Node; use PhpParser\NodeVisitorAbstract; +use PHPStan\Analyser\ArgumentsNormalizer; use PHPStan\DependencyInjection\AutowiredService; use PHPStan\Turbo\ShadowedByTurboExtension; use function in_array; @@ -22,9 +23,9 @@ public function enterNode(Node $node): ?Node if ($node instanceof Node\Expr\FuncCall && $node->name instanceof Node\Name && !$node->isFirstClassCallable()) { $functionName = $node->name->toLowerString(); if (in_array($functionName, ['array_all', 'array_any', 'array_find', 'array_find_key'], true)) { - $args = $node->getArgs(); - if (isset($args[0])) { - $args[0]->setAttribute(self::ATTRIBUTE_NAME, true); + $arg = ArgumentsNormalizer::getArgByPositionOrName($node->getArgs(), 0, 'array'); + if ($arg !== null) { + $arg->setAttribute(self::ATTRIBUTE_NAME, true); } } } diff --git a/src/Parser/ArrayMapArgVisitor.php b/src/Parser/ArrayMapArgVisitor.php index b0b35180d63..91449e93e9c 100644 --- a/src/Parser/ArrayMapArgVisitor.php +++ b/src/Parser/ArrayMapArgVisitor.php @@ -5,9 +5,9 @@ use Override; use PhpParser\Node; use PhpParser\NodeVisitorAbstract; +use PHPStan\Analyser\ArgumentsNormalizer; use PHPStan\DependencyInjection\AutowiredService; use PHPStan\Turbo\ShadowedByTurboExtension; -use function array_slice; use function count; #[AutowiredService] @@ -35,11 +35,9 @@ public function enterNode(Node $node): ?Node $arrayArgs[] = $arg; } - if (isset($args[0])) { - $slicedArgs = array_slice($args, 1); - if (count($slicedArgs) > 0) { - $args[0]->value->setAttribute(self::ATTRIBUTE_NAME, $arrayArgs); - } + $callbackArg = ArgumentsNormalizer::getArgByPositionOrName($args, 0, 'callback'); + if ($callbackArg !== null && count($arrayArgs) > 0) { + $callbackArg->value->setAttribute(self::ATTRIBUTE_NAME, $arrayArgs); } } } diff --git a/src/Parser/ArrayWalkArgVisitor.php b/src/Parser/ArrayWalkArgVisitor.php index 0cc945a67a0..a4351efa1c2 100644 --- a/src/Parser/ArrayWalkArgVisitor.php +++ b/src/Parser/ArrayWalkArgVisitor.php @@ -5,6 +5,7 @@ use Override; use PhpParser\Node; use PhpParser\NodeVisitorAbstract; +use PHPStan\Analyser\ArgumentsNormalizer; use PHPStan\DependencyInjection\AutowiredService; use PHPStan\Turbo\ShadowedByTurboExtension; @@ -21,9 +22,9 @@ public function enterNode(Node $node): ?Node if ($node instanceof Node\Expr\FuncCall && $node->name instanceof Node\Name && !$node->isFirstClassCallable()) { $functionName = $node->name->toLowerString(); if ($functionName === 'array_walk') { - $args = $node->getArgs(); - if (isset($args[0])) { - $args[0]->setAttribute(self::ATTRIBUTE_NAME, true); + $arg = ArgumentsNormalizer::getArgByPositionOrName($node->getArgs(), 0, 'array'); + if ($arg !== null) { + $arg->setAttribute(self::ATTRIBUTE_NAME, true); } } } diff --git a/src/Parser/CurlSetOptArgVisitor.php b/src/Parser/CurlSetOptArgVisitor.php index 748adc8b14e..8dc3395ab80 100644 --- a/src/Parser/CurlSetOptArgVisitor.php +++ b/src/Parser/CurlSetOptArgVisitor.php @@ -5,6 +5,7 @@ use Override; use PhpParser\Node; use PhpParser\NodeVisitorAbstract; +use PHPStan\Analyser\ArgumentsNormalizer; use PHPStan\DependencyInjection\AutowiredService; use PHPStan\Turbo\ShadowedByTurboExtension; @@ -21,9 +22,9 @@ public function enterNode(Node $node): ?Node if ($node instanceof Node\Expr\FuncCall && $node->name instanceof Node\Name && !$node->isFirstClassCallable()) { $functionName = $node->name->toLowerString(); if ($functionName === 'curl_setopt') { - $args = $node->getArgs(); - if (isset($args[0])) { - $args[0]->setAttribute(self::ATTRIBUTE_NAME, true); + $arg = ArgumentsNormalizer::getArgByPositionOrName($node->getArgs(), 0, 'handle'); + if ($arg !== null) { + $arg->setAttribute(self::ATTRIBUTE_NAME, true); } } } diff --git a/src/Parser/CurlSetOptArrayArgVisitor.php b/src/Parser/CurlSetOptArrayArgVisitor.php index 694fc983632..aa22a3801eb 100644 --- a/src/Parser/CurlSetOptArrayArgVisitor.php +++ b/src/Parser/CurlSetOptArrayArgVisitor.php @@ -5,6 +5,7 @@ use Override; use PhpParser\Node; use PhpParser\NodeVisitorAbstract; +use PHPStan\Analyser\ArgumentsNormalizer; use PHPStan\DependencyInjection\AutowiredService; use PHPStan\Turbo\ShadowedByTurboExtension; @@ -21,9 +22,9 @@ public function enterNode(Node $node): ?Node if ($node instanceof Node\Expr\FuncCall && $node->name instanceof Node\Name && !$node->isFirstClassCallable()) { $functionName = $node->name->toLowerString(); if ($functionName === 'curl_setopt_array') { - $args = $node->getArgs(); - if (isset($args[1])) { - $args[1]->setAttribute(self::ATTRIBUTE_NAME, true); + $arg = ArgumentsNormalizer::getArgByPositionOrName($node->getArgs(), 1, 'options'); + if ($arg !== null) { + $arg->setAttribute(self::ATTRIBUTE_NAME, true); } } } diff --git a/src/Reflection/ParametersAcceptorSelector.php b/src/Reflection/ParametersAcceptorSelector.php index 22c137ede82..9ba397b4041 100644 --- a/src/Reflection/ParametersAcceptorSelector.php +++ b/src/Reflection/ParametersAcceptorSelector.php @@ -178,6 +178,31 @@ public static function selectFromArgs( return self::selectFromTypes($types, $parametersAcceptors, $unpack); } + /** + * The intrinsic overrides read sibling arguments by their parameter + * position, so named arguments are put in signature order first. + * + * @param Node\Arg[] $args + * @return Node\Arg[] + */ + private static function reorderIntrinsicArgs(array $args, ParametersAcceptor $parametersAcceptor): array + { + foreach ($args as $arg) { + if ($arg->name === null) { + continue; + } + + $reorderedArgs = ArgumentsNormalizer::reorderArgs($parametersAcceptor, array_values($args)); + if ($reorderedArgs === null || count($reorderedArgs) === 0) { + return $args; + } + + return $reorderedArgs; + } + + return $args; + } + /** * @internal * @param Node\Arg[] $args @@ -204,7 +229,8 @@ public static function applyIntrinsicArgOverrides( count($args) > 0 && count($parametersAcceptors) > 0 ) { - $arrayMapArgs = $args[0]->value->getAttribute(ArrayMapArgVisitor::ATTRIBUTE_NAME); + $positionalArgs = self::reorderIntrinsicArgs($args, $namedArgumentsVariants[0] ?? $parametersAcceptors[0]); + $arrayMapArgs = $positionalArgs[0]->value->getAttribute(ArrayMapArgVisitor::ATTRIBUTE_NAME); if ($arrayMapArgs !== null) { $callbackParameters = []; $nativeCallbackParameters = []; @@ -252,8 +278,8 @@ public static function applyIntrinsicArgOverrides( } } - if (count($args) >= 3 && (bool) $args[0]->getAttribute(CurlSetOptArgVisitor::ATTRIBUTE_NAME)) { - $optType = ($typeGetter)($args[1]->value); + if (count($positionalArgs) >= 3 && (bool) $positionalArgs[0]->getAttribute(CurlSetOptArgVisitor::ATTRIBUTE_NAME)) { + $optType = ($typeGetter)($positionalArgs[1]->value); $valueTypes = []; foreach ($optType->getConstantScalarValues() as $scalarValue) { @@ -296,8 +322,8 @@ public static function applyIntrinsicArgOverrides( } } - if (count($args) >= 2 && (bool) $args[1]->getAttribute(CurlSetOptArrayArgVisitor::ATTRIBUTE_NAME)) { - $optArrayType = ($typeGetter)($args[1]->value); + if (count($positionalArgs) >= 2 && (bool) $positionalArgs[1]->getAttribute(CurlSetOptArrayArgVisitor::ATTRIBUTE_NAME)) { + $optArrayType = ($typeGetter)($positionalArgs[1]->value); $hasTypes = false; $builder = ConstantArrayTypeBuilder::createEmpty(); @@ -348,27 +374,27 @@ public static function applyIntrinsicArgOverrides( } } - if ((bool) $args[0]->getAttribute(ArrayFilterArgVisitor::ATTRIBUTE_NAME)) { + if ((bool) $positionalArgs[0]->getAttribute(ArrayFilterArgVisitor::ATTRIBUTE_NAME)) { $arrayFilterParameters = null; $nativeArrayFilterParameters = null; - if (isset($args[2])) { - $mode = ($typeGetter)($args[2]->value); + if (isset($positionalArgs[2])) { + $mode = ($typeGetter)($positionalArgs[2]->value); if ($mode instanceof ConstantIntegerType) { if ($mode->getValue() === ARRAY_FILTER_USE_KEY) { $arrayFilterParameters = [ - new DummyParameter('key', ($iterableKeyTypeGetter)(($typeGetter)($args[0]->value)), optional: false, passedByReference: PassedByReference::createNo(), variadic: false, defaultValue: null), + new DummyParameter('key', ($iterableKeyTypeGetter)(($typeGetter)($positionalArgs[0]->value)), optional: false, passedByReference: PassedByReference::createNo(), variadic: false, defaultValue: null), ]; $nativeArrayFilterParameters = [ - new DummyParameter('key', ($iterableKeyTypeGetter)(($nativeTypeGetter)($args[0]->value)), optional: false, passedByReference: PassedByReference::createNo(), variadic: false, defaultValue: null), + new DummyParameter('key', ($iterableKeyTypeGetter)(($nativeTypeGetter)($positionalArgs[0]->value)), optional: false, passedByReference: PassedByReference::createNo(), variadic: false, defaultValue: null), ]; } elseif ($mode->getValue() === ARRAY_FILTER_USE_BOTH) { $arrayFilterParameters = [ - new DummyParameter('item', ($iterableValueTypeGetter)(($typeGetter)($args[0]->value)), optional: false, passedByReference: PassedByReference::createNo(), variadic: false, defaultValue: null), - new DummyParameter('key', ($iterableKeyTypeGetter)(($typeGetter)($args[0]->value)), optional: false, passedByReference: PassedByReference::createNo(), variadic: false, defaultValue: null), + new DummyParameter('item', ($iterableValueTypeGetter)(($typeGetter)($positionalArgs[0]->value)), optional: false, passedByReference: PassedByReference::createNo(), variadic: false, defaultValue: null), + new DummyParameter('key', ($iterableKeyTypeGetter)(($typeGetter)($positionalArgs[0]->value)), optional: false, passedByReference: PassedByReference::createNo(), variadic: false, defaultValue: null), ]; $nativeArrayFilterParameters = [ - new DummyParameter('item', ($iterableValueTypeGetter)(($nativeTypeGetter)($args[0]->value)), optional: false, passedByReference: PassedByReference::createNo(), variadic: false, defaultValue: null), - new DummyParameter('key', ($iterableKeyTypeGetter)(($nativeTypeGetter)($args[0]->value)), optional: false, passedByReference: PassedByReference::createNo(), variadic: false, defaultValue: null), + new DummyParameter('item', ($iterableValueTypeGetter)(($nativeTypeGetter)($positionalArgs[0]->value)), optional: false, passedByReference: PassedByReference::createNo(), variadic: false, defaultValue: null), + new DummyParameter('key', ($iterableKeyTypeGetter)(($nativeTypeGetter)($positionalArgs[0]->value)), optional: false, passedByReference: PassedByReference::createNo(), variadic: false, defaultValue: null), ]; } } @@ -377,7 +403,7 @@ public static function applyIntrinsicArgOverrides( $acceptor = $parametersAcceptors[0]; $parameters = $acceptor->getParameters(); if (isset($parameters[1])) { - $arrayArgType = ($typeGetter)($args[0]->value); + $arrayArgType = ($typeGetter)($positionalArgs[0]->value); $callableType = new UnionType([ new CallableType( $arrayFilterParameters ?? [ @@ -388,7 +414,7 @@ public static function applyIntrinsicArgOverrides( ), new NullType(), ]); - $nativeArrayArgType = ($nativeTypeGetter)($args[0]->value); + $nativeArrayArgType = ($nativeTypeGetter)($positionalArgs[0]->value); $nativeCallableType = new UnionType([ new CallableType( $nativeArrayFilterParameters ?? [ @@ -433,9 +459,9 @@ public static function applyIntrinsicArgOverrides( ]; } - if ((bool) $args[0]->getAttribute(ArrayWalkArgVisitor::ATTRIBUTE_NAME)) { - $arrayArgType = ($typeGetter)($args[0]->value); - $nativeArrayArgType = ($nativeTypeGetter)($args[0]->value); + if ((bool) $positionalArgs[0]->getAttribute(ArrayWalkArgVisitor::ATTRIBUTE_NAME)) { + $arrayArgType = ($typeGetter)($positionalArgs[0]->value); + $nativeArrayArgType = ($nativeTypeGetter)($positionalArgs[0]->value); $arrayWalkParameters = [ new DummyParameter('item', ($iterableValueTypeGetter)($arrayArgType), optional: false, passedByReference: PassedByReference::createReadsArgument(), variadic: false, defaultValue: null), new DummyParameter('key', ($iterableKeyTypeGetter)($arrayArgType), optional: false, passedByReference: PassedByReference::createNo(), variadic: false, defaultValue: null), @@ -444,9 +470,9 @@ public static function applyIntrinsicArgOverrides( new DummyParameter('item', ($iterableValueTypeGetter)($nativeArrayArgType), optional: false, passedByReference: PassedByReference::createReadsArgument(), variadic: false, defaultValue: null), new DummyParameter('key', ($iterableKeyTypeGetter)($nativeArrayArgType), optional: false, passedByReference: PassedByReference::createNo(), variadic: false, defaultValue: null), ]; - if (isset($args[2])) { - $arrayWalkParameters[] = new DummyParameter('arg', ($typeGetter)($args[2]->value), optional: false, passedByReference: PassedByReference::createNo(), variadic: false, defaultValue: null); - $nativeArrayWalkParameters[] = new DummyParameter('arg', ($nativeTypeGetter)($args[2]->value), optional: false, passedByReference: PassedByReference::createNo(), variadic: false, defaultValue: null); + if (isset($positionalArgs[2])) { + $arrayWalkParameters[] = new DummyParameter('arg', ($typeGetter)($positionalArgs[2]->value), optional: false, passedByReference: PassedByReference::createNo(), variadic: false, defaultValue: null); + $nativeArrayWalkParameters[] = new DummyParameter('arg', ($nativeTypeGetter)($positionalArgs[2]->value), optional: false, passedByReference: PassedByReference::createNo(), variadic: false, defaultValue: null); } $acceptor = $parametersAcceptors[0]; @@ -459,11 +485,11 @@ public static function applyIntrinsicArgOverrides( } } - if ((bool) $args[0]->getAttribute(ArrayFindArgVisitor::ATTRIBUTE_NAME)) { + if ((bool) $positionalArgs[0]->getAttribute(ArrayFindArgVisitor::ATTRIBUTE_NAME)) { $acceptor = $parametersAcceptors[0]; $parameters = $acceptor->getParameters(); if (isset($parameters[1])) { - $argType = ($typeGetter)($args[0]->value); + $argType = ($typeGetter)($positionalArgs[0]->value); $callableType = new CallableType( [ new DummyParameter('value', ($iterableValueTypeGetter)($argType), optional: false, passedByReference: PassedByReference::createNo(), variadic: false, defaultValue: null), @@ -472,7 +498,7 @@ public static function applyIntrinsicArgOverrides( new BooleanType(), false, ); - $nativeArgType = ($nativeTypeGetter)($args[0]->value); + $nativeArgType = ($nativeTypeGetter)($positionalArgs[0]->value); $nativeCallableType = new CallableType( [ new DummyParameter('value', ($iterableValueTypeGetter)($nativeArgType), optional: false, passedByReference: PassedByReference::createNo(), variadic: false, defaultValue: null), diff --git a/src/Type/Php/ArrayFilterParameterClosureTypeExtension.php b/src/Type/Php/ArrayFilterParameterClosureTypeExtension.php index cbad3124f83..ba77be46aac 100644 --- a/src/Type/Php/ArrayFilterParameterClosureTypeExtension.php +++ b/src/Type/Php/ArrayFilterParameterClosureTypeExtension.php @@ -3,6 +3,7 @@ namespace PHPStan\Type\Php; use PhpParser\Node\Expr\FuncCall; +use PHPStan\Analyser\ArgumentsNormalizer; use PHPStan\Analyser\Scope; use PHPStan\DependencyInjection\AutowiredService; use PHPStan\Reflection\FunctionReflection; @@ -28,7 +29,7 @@ public function isFunctionSupported(FunctionReflection $functionReflection, Para public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, ParameterReflection $parameter, Scope $scope): ?Type { - $args = $functionCall->getArgs(); + $args = ArgumentsNormalizer::reorderArgs($functionReflection->getNamedArgumentsVariants()[0] ?? $functionReflection->getVariants()[0], $functionCall->getArgs()) ?? []; if (!isset($args[0])) { return null; } diff --git a/src/Type/Php/ArrayFindParameterClosureTypeExtension.php b/src/Type/Php/ArrayFindParameterClosureTypeExtension.php index e99a0e87368..71d6218c3d9 100644 --- a/src/Type/Php/ArrayFindParameterClosureTypeExtension.php +++ b/src/Type/Php/ArrayFindParameterClosureTypeExtension.php @@ -3,6 +3,7 @@ namespace PHPStan\Type\Php; use PhpParser\Node\Expr\FuncCall; +use PHPStan\Analyser\ArgumentsNormalizer; use PHPStan\Analyser\Scope; use PHPStan\DependencyInjection\AutowiredService; use PHPStan\Reflection\FunctionReflection; @@ -27,7 +28,7 @@ public function isFunctionSupported(FunctionReflection $functionReflection, Para public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, ParameterReflection $parameter, Scope $scope): ?Type { - $args = $functionCall->getArgs(); + $args = ArgumentsNormalizer::reorderArgs($functionReflection->getNamedArgumentsVariants()[0] ?? $functionReflection->getVariants()[0], $functionCall->getArgs()) ?? []; if (!isset($args[0])) { return null; } diff --git a/src/Type/Php/ArrayMapParameterClosureTypeExtension.php b/src/Type/Php/ArrayMapParameterClosureTypeExtension.php index 6ae1c8198a0..60b06686f54 100644 --- a/src/Type/Php/ArrayMapParameterClosureTypeExtension.php +++ b/src/Type/Php/ArrayMapParameterClosureTypeExtension.php @@ -3,6 +3,7 @@ namespace PHPStan\Type\Php; use PhpParser\Node\Expr\FuncCall; +use PHPStan\Analyser\ArgumentsNormalizer; use PHPStan\Analyser\Scope; use PHPStan\DependencyInjection\AutowiredService; use PHPStan\Reflection\FunctionReflection; @@ -26,7 +27,7 @@ public function isFunctionSupported(FunctionReflection $functionReflection, Para public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, ParameterReflection $parameter, Scope $scope): ?Type { - $args = $functionCall->getArgs(); + $args = ArgumentsNormalizer::reorderArgs($functionReflection->getNamedArgumentsVariants()[0] ?? $functionReflection->getVariants()[0], $functionCall->getArgs()) ?? []; if (count($args) < 2) { return null; } diff --git a/src/Type/Php/ArrayWalkParameterClosureTypeExtension.php b/src/Type/Php/ArrayWalkParameterClosureTypeExtension.php index 4ddf25ab94f..7447244c237 100644 --- a/src/Type/Php/ArrayWalkParameterClosureTypeExtension.php +++ b/src/Type/Php/ArrayWalkParameterClosureTypeExtension.php @@ -3,6 +3,7 @@ namespace PHPStan\Type\Php; use PhpParser\Node\Expr\FuncCall; +use PHPStan\Analyser\ArgumentsNormalizer; use PHPStan\Analyser\Scope; use PHPStan\DependencyInjection\AutowiredService; use PHPStan\Reflection\FunctionReflection; @@ -25,7 +26,7 @@ public function isFunctionSupported(FunctionReflection $functionReflection, Para public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, ParameterReflection $parameter, Scope $scope): ?Type { - $args = $functionCall->getArgs(); + $args = ArgumentsNormalizer::reorderArgs($functionReflection->getNamedArgumentsVariants()[0] ?? $functionReflection->getVariants()[0], $functionCall->getArgs()) ?? []; if (!isset($args[0])) { return null; } diff --git a/src/Type/Php/PregReplaceCallbackClosureTypeExtension.php b/src/Type/Php/PregReplaceCallbackClosureTypeExtension.php index 1be24ff645f..039471f96c1 100644 --- a/src/Type/Php/PregReplaceCallbackClosureTypeExtension.php +++ b/src/Type/Php/PregReplaceCallbackClosureTypeExtension.php @@ -3,6 +3,7 @@ namespace PHPStan\Type\Php; use PhpParser\Node\Expr\FuncCall; +use PHPStan\Analyser\ArgumentsNormalizer; use PHPStan\Analyser\Scope; use PHPStan\DependencyInjection\AutowiredService; use PHPStan\Reflection\FunctionReflection; @@ -31,7 +32,7 @@ public function isFunctionSupported(FunctionReflection $functionReflection, Para public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, ParameterReflection $parameter, Scope $scope): ?Type { - $args = $functionCall->getArgs(); + $args = ArgumentsNormalizer::reorderArgs($functionReflection->getNamedArgumentsVariants()[0] ?? $functionReflection->getVariants()[0], $functionCall->getArgs()) ?? []; $patternArg = $args[0] ?? null; $flagsArg = $args[5] ?? null; diff --git a/tests/PHPStan/Analyser/ArgumentsNormalizerTest.php b/tests/PHPStan/Analyser/ArgumentsNormalizerTest.php index a9226fc3131..53e7c2a8886 100644 --- a/tests/PHPStan/Analyser/ArgumentsNormalizerTest.php +++ b/tests/PHPStan/Analyser/ArgumentsNormalizerTest.php @@ -392,4 +392,63 @@ public function testReorderInvalid( $this->assertNull($normalized); } + public static function dataGetArgByPositionOrName(): iterable + { + // no arguments + yield [[], 0, 'array', null]; + + // positional argument at the position + yield [[null, null], 0, 'array', 0]; + yield [[null, null], 1, 'callback', 1]; + + // fewer positional arguments than the position + yield [[null], 1, 'callback', null]; + + // named argument written in signature order + yield [['array', 'callback'], 0, 'array', 0]; + + // named argument written in a different order + yield [['callback', 'array'], 0, 'array', 1]; + yield [['mode', 'callback', 'array'], 0, 'array', 2]; + + // positional arguments followed by the named one + yield [[null, 'mode', 'callback'], 1, 'callback', 2]; + + // named argument at the position is bound to a different parameter + yield [['callback'], 0, 'array', null]; + yield [[null, 'mode'], 1, 'callback', null]; + + // argument names are case-sensitive + yield [['Array'], 0, 'array', null]; + + // negative position never matches a positional argument + yield [[null, null], -1, 'array', null]; + yield [[null, 'array'], -1, 'array', 1]; + } + + /** + * @param list $argumentNames + */ + #[DataProvider('dataGetArgByPositionOrName')] + public function testGetArgByPositionOrName( + array $argumentNames, + int $position, + string $name, + ?int $expectedIndex, + ): void + { + $arguments = []; + foreach ($argumentNames as $argumentName) { + $arguments[] = new Arg(new TypeExpr(new MixedType()), name: $argumentName === null ? null : new Identifier($argumentName)); + } + + $arg = ArgumentsNormalizer::getArgByPositionOrName($arguments, $position, $name); + if ($expectedIndex === null) { + $this->assertNull($arg); + return; + } + + $this->assertSame($arguments[$expectedIndex], $arg); + } + } diff --git a/tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php b/tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php index 21bfded33dc..58ff3e22f60 100644 --- a/tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php +++ b/tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php @@ -3369,6 +3369,46 @@ public function testBug15432(): void ]); } + #[RequiresPhp('>= 8.4.0')] + public function testBug15195(): void + { + $this->analyse([__DIR__ . '/data/bug-15195.php'], [ + [ + 'Parameter $callback of function array_filter expects (callable(int, string): bool)|null, Closure(string, int): bool given.', + 29, + ], + [ + 'Parameter $callback of function array_walk expects callable(int, string): mixed, Closure(string, int): void given.', + 38, + ], + [ + 'Parameter $callback of function array_walk expects callable(int, string, 1): mixed, Closure(int, string, string): void given.', + 40, + ], + [ + 'Parameter $callback of function array_find expects callable(int, string): bool, Closure(string, int): bool given.', + 49, + ], + [ + 'Parameter $callback of function array_map expects (callable(string): mixed)|null, Closure(int): int given.', + 61, + ], + [ + 'Parameter $value of function curl_setopt expects non-empty-string, 1 given.', + 67, + ], + [ + 'Parameter $value of function curl_setopt expects non-empty-string, 1 given.', + 68, + ], + [ + 'Parameter $options of function curl_setopt_array expects array{10002: non-empty-string}, array{10002: 1} given.', + 70, + 'Offset 10002 (non-empty-string) does not accept type 1.', + ], + ]); + } + public function testBug15487(): void { $this->checkExplicitMixed = true; diff --git a/tests/PHPStan/Rules/Functions/data/bug-15195.php b/tests/PHPStan/Rules/Functions/data/bug-15195.php new file mode 100644 index 00000000000..7072e6a07c7 --- /dev/null +++ b/tests/PHPStan/Rules/Functions/data/bug-15195.php @@ -0,0 +1,71 @@ += 8.4 + +namespace Bug15195; + +/** + * @param list $arr + */ +function foo( + array $arr, +): void { + $arr1 = array_filter( + array: $arr, + callback: static fn(string $s): bool => $s !== '', + ); + + $arr2 = array_filter( + callback: static fn(string $s): bool => $s !== '', + array: $arr, + ); +} + +/** + * @param array $map + */ +function arrayFilterMode(array $map): void +{ + array_filter(mode: ARRAY_FILTER_USE_KEY, callback: static fn (string $k): bool => $k !== '', array: $map); + array_filter($map, mode: ARRAY_FILTER_USE_BOTH, callback: static fn (int $v, string $k): bool => $k !== ''); + array_filter($map, mode: ARRAY_FILTER_USE_BOTH, callback: static fn (string $v, int $k): bool => $k !== 0); +} + +/** + * @param array $map + */ +function arrayWalk(array $map): void +{ + array_walk(callback: static function (int $v, string $k): void {}, array: $map); + array_walk(callback: static function (string $v, int $k): void {}, array: $map); + array_walk(arg: 1, callback: static function (int $v, string $k, int $arg): void {}, array: $map); + array_walk(arg: 1, callback: static function (int $v, string $k, string $arg): void {}, array: $map); +} + +/** + * @param array $map + */ +function arrayFind(array $map): void +{ + array_find(callback: static fn (int $v, string $k): bool => $v > 0, array: $map); + array_find(callback: static fn (string $v, int $k): bool => $k > 0, array: $map); + array_find_key(callback: static fn (int $v, string $k): bool => $v > 0, array: $map); + array_any(callback: static fn (int $v, string $k): bool => $v > 0, array: $map); + array_all(callback: static fn (int $v, string $k): bool => $v > 0, array: $map); +} + +/** + * @param list $arr + */ +function arrayMap(array $arr): void +{ + array_map(array: $arr, callback: static fn (string $s): string => $s); + array_map(array: $arr, callback: static fn (int $s): int => $s); +} + +function curlSetOpt(\CurlHandle $h): void +{ + curl_setopt(value: 'https://example.com', option: CURLOPT_URL, handle: $h); + curl_setopt(value: 1, option: CURLOPT_URL, handle: $h); + curl_setopt($h, value: 1, option: CURLOPT_URL); + curl_setopt_array(options: [CURLOPT_URL => 'https://example.com'], handle: $h); + curl_setopt_array(options: [CURLOPT_URL => 1], handle: $h); +} diff --git a/turbo-ext/src/ArgumentsNormalizer.cpp b/turbo-ext/src/ArgumentsNormalizer.cpp index 10d4513e85f..8ab0753d140 100644 --- a/turbo-ext/src/ArgumentsNormalizer.cpp +++ b/turbo-ext/src/ArgumentsNormalizer.cpp @@ -24,6 +24,7 @@ namespace sigs = ptdecl::ArgumentsNormalizer::sig; #include "Engine.h" #include "ParameterValues.h" #include "AcceptorValues.h" +#include "ParserVisitors.h" zend_class_entry *pt_ce_arguments_normalizer = nullptr; @@ -871,6 +872,20 @@ PT_MINIT_REGISTRATION(pt_register_arguments_normalizer) PT_RETURN_VAL(ArgumentsNormalizer::reorderArgs(parametersAcceptor, callArgs)); }); + cls.method(sigs::getArgByPositionOrName, [](INTERNAL_FUNCTION_PARAMETERS) { + zval *args; + zend_long position; + zend_string *name; + ZEND_PARSE_PARAMETERS_START(3, 3) + Z_PARAM_ARRAY(args) + Z_PARAM_LONG(position) + Z_PARAM_STR(name) + ZEND_PARSE_PARAMETERS_END(); + zend_object *arg = phpstanturbo::visitors::argForParameter(args, (zend_ulong) position, ZSTR_VAL(name), ZSTR_LEN(name)); + if (arg == NULL) RETURN_NULL(); + RETURN_OBJ_COPY(arg); + }); + cls.shadow(&pt_ce_arguments_normalizer); } diff --git a/turbo-ext/src/ArrayFilterArgVisitor.cpp b/turbo-ext/src/ArrayFilterArgVisitor.cpp index 330c04a8e18..ca811a3a375 100644 --- a/turbo-ext/src/ArrayFilterArgVisitor.cpp +++ b/turbo-ext/src/ArrayFilterArgVisitor.cpp @@ -40,7 +40,7 @@ class ArrayFilterArgVisitor zend_string *functionName = visitors::plainFuncCallName(node, call, nameProp, &args); if (functionName == NULL) return !EG(exception); if (!(visitors::lowerEquals(functionName, "array_filter"))) return true; - zend_object *arg = visitors::argAt(args, 0); + zend_object *arg = visitors::argForParameter(args, 0, "array"); if (arg != NULL) { visitors::setAttributeTrue(arg, pt_array_filter_arg_attribute_str); } diff --git a/turbo-ext/src/ArrayFindArgVisitor.cpp b/turbo-ext/src/ArrayFindArgVisitor.cpp index 8e51e7097c9..0d46e7d7d63 100644 --- a/turbo-ext/src/ArrayFindArgVisitor.cpp +++ b/turbo-ext/src/ArrayFindArgVisitor.cpp @@ -45,7 +45,7 @@ class ArrayFindArgVisitor || visitors::lowerEquals(functionName, "array_find_key"))) { return true; } - zend_object *arg = visitors::argAt(args, 0); + zend_object *arg = visitors::argForParameter(args, 0, "array"); if (arg != NULL) { visitors::setAttributeTrue(arg, pt_array_find_arg_attribute_str); } diff --git a/turbo-ext/src/ArrayMapArgVisitor.cpp b/turbo-ext/src/ArrayMapArgVisitor.cpp index fd983c2eedd..1ef31035ca9 100644 --- a/turbo-ext/src/ArrayMapArgVisitor.cpp +++ b/turbo-ext/src/ArrayMapArgVisitor.cpp @@ -62,10 +62,10 @@ class ArrayMapArgVisitor arrayArgs.push(arg); } - /* isset($args[0]) && count(array_slice($args, 1)) > 0 */ - zend_object *firstArg = visitors::argAt(args, 0); - if (firstArg == NULL || zend_hash_num_elements(Z_ARRVAL_P(args)) <= 1) return true; - zval *value = argValueProp.of(firstArg); + /* ArgumentsNormalizer::getArgByPositionOrName($args, 0, 'callback') */ + zend_object *callbackArg = visitors::argForParameter(args, 0, "callback"); + if (callbackArg == NULL || zend_hash_num_elements(arrayArgs.table()) == 0) return true; + zval *value = argValueProp.of(callbackArg); if (value == NULL || Z_TYPE_P(value) != IS_OBJECT) return true; visitors::setAttribute(Z_OBJ_P(value), pt_array_map_arg_attribute_str, arrayArgs.raw()); return true; diff --git a/turbo-ext/src/ArrayWalkArgVisitor.cpp b/turbo-ext/src/ArrayWalkArgVisitor.cpp index 6dfdff94568..1693a77349f 100644 --- a/turbo-ext/src/ArrayWalkArgVisitor.cpp +++ b/turbo-ext/src/ArrayWalkArgVisitor.cpp @@ -40,7 +40,7 @@ class ArrayWalkArgVisitor zend_string *functionName = visitors::plainFuncCallName(node, call, nameProp, &args); if (functionName == NULL) return !EG(exception); if (!(visitors::lowerEquals(functionName, "array_walk"))) return true; - zend_object *arg = visitors::argAt(args, 0); + zend_object *arg = visitors::argForParameter(args, 0, "array"); if (arg != NULL) { visitors::setAttributeTrue(arg, pt_array_walk_arg_attribute_str); } diff --git a/turbo-ext/src/CurlSetOptArgVisitor.cpp b/turbo-ext/src/CurlSetOptArgVisitor.cpp index 316a5f8f1f5..2691a9bcbaa 100644 --- a/turbo-ext/src/CurlSetOptArgVisitor.cpp +++ b/turbo-ext/src/CurlSetOptArgVisitor.cpp @@ -40,7 +40,7 @@ class CurlSetOptArgVisitor zend_string *functionName = visitors::plainFuncCallName(node, call, nameProp, &args); if (functionName == NULL) return !EG(exception); if (!(visitors::lowerEquals(functionName, "curl_setopt"))) return true; - zend_object *arg = visitors::argAt(args, 0); + zend_object *arg = visitors::argForParameter(args, 0, "handle"); if (arg != NULL) { visitors::setAttributeTrue(arg, pt_curl_set_opt_arg_attribute_str); } diff --git a/turbo-ext/src/CurlSetOptArrayArgVisitor.cpp b/turbo-ext/src/CurlSetOptArrayArgVisitor.cpp index efc304e9ce4..652e87ad281 100644 --- a/turbo-ext/src/CurlSetOptArrayArgVisitor.cpp +++ b/turbo-ext/src/CurlSetOptArrayArgVisitor.cpp @@ -40,7 +40,7 @@ class CurlSetOptArrayArgVisitor zend_string *functionName = visitors::plainFuncCallName(node, call, nameProp, &args); if (functionName == NULL) return !EG(exception); if (!(visitors::lowerEquals(functionName, "curl_setopt_array"))) return true; - zend_object *arg = visitors::argAt(args, 1); + zend_object *arg = visitors::argForParameter(args, 1, "options"); if (arg != NULL) { visitors::setAttributeTrue(arg, pt_curl_set_opt_array_arg_attribute_str); } diff --git a/turbo-ext/src/ParametersAcceptorSelector.cpp b/turbo-ext/src/ParametersAcceptorSelector.cpp index c1869f628bd..b75a5d87bfa 100644 --- a/turbo-ext/src/ParametersAcceptorSelector.cpp +++ b/turbo-ext/src/ParametersAcceptorSelector.cpp @@ -1895,6 +1895,30 @@ class ParametersAcceptorSelector } public: + /* Mirrors reorderIntrinsicArgs(); UNDEF = pending exception */ + static zv::Val reorderIntrinsicArgs(zval *argsZv, zval *parametersAcceptor) + { + for (zv::ArrayEntry entry : zv::ArrRef(argsZv)) { + zv::Val nameHold; + zval *name = readProperty(pt_pas_arg_name_site, entry.value().deref().raw(), PT_LC("name"), nameHold); + if (UNEXPECTED(name == NULL)) return zv::Val(); + if (Z_TYPE_P(name) == IS_NULL) continue; + + zv::Arr values = zv::Arr::create(zend_hash_num_elements(Z_ARRVAL_P(argsZv))); + for (zv::ArrayEntry valueEntry : zv::ArrRef(argsZv)) { + values.push(zv::Ref(valueEntry.value().deref().raw())); + } + zv::Val reorderedArgs = pt_arguments_normalizer_reorder_args(parametersAcceptor, values.raw()); + if (UNEXPECTED(reorderedArgs.isUndef())) return zv::Val(); + if (Z_TYPE_P(reorderedArgs.raw()) != IS_ARRAY || zend_hash_num_elements(Z_ARRVAL_P(reorderedArgs.raw())) == 0) { + return zv::Val::copyOf(zv::Ref(argsZv)); + } + return reorderedArgs; + } + + return zv::Val::copyOf(zv::Ref(argsZv)); + } + /* Mirrors applyIntrinsicArgOverrides() */ static zv::Val applyIntrinsicArgOverrides(zval *argsZv, zval *parametersAcceptorsZv, zval *namedArgumentsVariants, zval *scope, const Getters &getters) { @@ -1902,26 +1926,39 @@ class ParametersAcceptorSelector zv::Val parametersAcceptors = zv::Val::copyOf(zv::Ref(parametersAcceptorsZv)); if (zend_hash_num_elements(args) == 0 || zend_hash_num_elements(Z_ARRVAL_P(parametersAcceptorsZv)) == 0) return parametersAcceptors; - zval *firstArg = argAt(args, 0); - if (UNEXPECTED(firstArg == NULL)) return zv::Val(); + /* $namedArgumentsVariants[0] ?? $parametersAcceptors[0] */ + zval *reorderAcceptor = NULL; + if (namedArgumentsVariants != NULL && Z_TYPE_P(namedArgumentsVariants) == IS_ARRAY) { + reorderAcceptor = zend_hash_index_find(Z_ARRVAL_P(namedArgumentsVariants), 0); + if (reorderAcceptor != NULL && Z_TYPE_P(reorderAcceptor) == IS_NULL) reorderAcceptor = NULL; + } + if (reorderAcceptor == NULL) { + reorderAcceptor = readIndex(Z_ARRVAL_P(parametersAcceptorsZv), 0); + if (UNEXPECTED(reorderAcceptor == NULL)) return zv::Val(); + } + zv::Val positionalArgsHold = reorderIntrinsicArgs(argsZv, reorderAcceptor); + if (UNEXPECTED(positionalArgsHold.isUndef())) return zv::Val(); + HashTable *positionalArgs = Z_ARRVAL_P(positionalArgsHold.raw()); + zval *firstPositionalArg = argAt(positionalArgs, 0); + if (UNEXPECTED(firstPositionalArg == NULL)) return zv::Val(); { zv::Val valueHold; - zval *firstValue = argValueOf(firstArg, valueHold); + zval *firstValue = argValueOf(firstPositionalArg, valueHold); if (UNEXPECTED(firstValue == NULL)) return zv::Val(); zval *arrayMapArgs = NULL; if (UNEXPECTED(!getAttribute(firstValue, pt_pas_array_map_args, arrayMapArgs))) return zv::Val(); if (arrayMapArgs != NULL && UNEXPECTED(!applyArrayMap(parametersAcceptors, arrayMapArgs, getters))) return zv::Val(); } - if (zend_hash_num_elements(args) >= 3) { + if (zend_hash_num_elements(positionalArgs) >= 3) { zval *isCurlSetOptArg = NULL; - if (UNEXPECTED(!getAttribute(firstArg, pt_pas_curl_set_opt_arg, isCurlSetOptArg))) return zv::Val(); - if (isCurlSetOptArg != NULL && zend_is_true(isCurlSetOptArg) && UNEXPECTED(!applyCurlSetOpt(parametersAcceptors, args, getters))) return zv::Val(); + if (UNEXPECTED(!getAttribute(firstPositionalArg, pt_pas_curl_set_opt_arg, isCurlSetOptArg))) return zv::Val(); + if (isCurlSetOptArg != NULL && zend_is_true(isCurlSetOptArg) && UNEXPECTED(!applyCurlSetOpt(parametersAcceptors, positionalArgs, getters))) return zv::Val(); } - if (zend_hash_num_elements(args) >= 2) { - zval *secondArg = argAt(args, 1); + if (zend_hash_num_elements(positionalArgs) >= 2) { + zval *secondArg = argAt(positionalArgs, 1); if (UNEXPECTED(secondArg == NULL)) return zv::Val(); zval *isCurlSetOptArrayArg = NULL; if (UNEXPECTED(!getAttribute(secondArg, pt_pas_curl_set_opt_array_arg, isCurlSetOptArrayArg))) return zv::Val(); @@ -1930,10 +1967,13 @@ class ParametersAcceptorSelector { zval *isArrayFilterArg = NULL; - if (UNEXPECTED(!getAttribute(firstArg, pt_pas_array_filter_arg, isArrayFilterArg))) return zv::Val(); - if (isArrayFilterArg != NULL && zend_is_true(isArrayFilterArg) && UNEXPECTED(!applyArrayFilter(parametersAcceptors, args, firstArg, getters))) return zv::Val(); + if (UNEXPECTED(!getAttribute(firstPositionalArg, pt_pas_array_filter_arg, isArrayFilterArg))) return zv::Val(); + if (isArrayFilterArg != NULL && zend_is_true(isArrayFilterArg) && UNEXPECTED(!applyArrayFilter(parametersAcceptors, positionalArgs, firstPositionalArg, getters))) return zv::Val(); } + zval *firstArg = argAt(args, 0); + if (UNEXPECTED(firstArg == NULL)) return zv::Val(); + if (zend_hash_num_elements(args) <= 2) { zval *isImplodeArg = NULL; if (UNEXPECTED(!getAttribute(firstArg, pt_pas_implode_arg, isImplodeArg))) return zv::Val(); @@ -1942,14 +1982,14 @@ class ParametersAcceptorSelector { zval *isArrayWalkArg = NULL; - if (UNEXPECTED(!getAttribute(firstArg, pt_pas_array_walk_arg, isArrayWalkArg))) return zv::Val(); - if (isArrayWalkArg != NULL && zend_is_true(isArrayWalkArg) && UNEXPECTED(!applyArrayWalk(parametersAcceptors, args, firstArg, getters))) return zv::Val(); + if (UNEXPECTED(!getAttribute(firstPositionalArg, pt_pas_array_walk_arg, isArrayWalkArg))) return zv::Val(); + if (isArrayWalkArg != NULL && zend_is_true(isArrayWalkArg) && UNEXPECTED(!applyArrayWalk(parametersAcceptors, positionalArgs, firstPositionalArg, getters))) return zv::Val(); } { zval *isArrayFindArg = NULL; - if (UNEXPECTED(!getAttribute(firstArg, pt_pas_array_find_arg, isArrayFindArg))) return zv::Val(); - if (isArrayFindArg != NULL && zend_is_true(isArrayFindArg) && UNEXPECTED(!applyArrayFind(parametersAcceptors, firstArg, getters))) return zv::Val(); + if (UNEXPECTED(!getAttribute(firstPositionalArg, pt_pas_array_find_arg, isArrayFindArg))) return zv::Val(); + if (isArrayFindArg != NULL && zend_is_true(isArrayFindArg) && UNEXPECTED(!applyArrayFind(parametersAcceptors, firstPositionalArg, getters))) return zv::Val(); } { diff --git a/turbo-ext/src/ParserVisitors.h b/turbo-ext/src/ParserVisitors.h index 0afa679b7c5..bfc1d4d066f 100644 --- a/turbo-ext/src/ParserVisitors.h +++ b/turbo-ext/src/ParserVisitors.h @@ -228,6 +228,38 @@ inline zend_string *plainFuncCallName(zend_object *node, FuncCallProps &props, N return nameString(callee, nameProp); } +/* + * The argument bound to the parameter at `position` named `name` — the + * positional argument at that index or the one passed by that name. Mirrors + * ArgumentsNormalizer::getArgByPositionOrName(). NULL when no argument is + * bound to it. + */ +inline zend_object *argForParameter(zval *args, zend_ulong position, const char *name, size_t nameLen) +{ + static NodeProp argNameProp = PT_NODE_PROP(PT_CLASS_ARG, "name"); + static NodeProp identifierProp = PT_IDENTIFIER_PROP; + + if (args == NULL || Z_TYPE_P(args) != IS_ARRAY) return NULL; + for (auto entry : zv::ArrRef(args)) { + zv::Ref arg = entry.value().deref(); + if (!arg.isObject()) continue; + zval *argName = argNameProp.of(arg.asObject()); + if (argName != NULL && Z_TYPE_P(argName) == IS_OBJECT) { + zend_string *argNameString = nameString(Z_OBJ_P(argName), identifierProp); + if (argNameString != NULL && zend_string_equals_cstr(argNameString, name, nameLen)) return arg.asObject(); + continue; + } + if (entry.stringKeyOrNull() == NULL && entry.indexKey() == position) return arg.asObject(); + } + return NULL; +} + +template +inline zend_object *argForParameter(zval *args, zend_ulong position, const char (&name)[N]) +{ + return argForParameter(args, position, name, N - 1); +} + } // namespace visitors } // namespace phpstanturbo diff --git a/turbo-ext/src/generated/ArgumentsNormalizer.h b/turbo-ext/src/generated/ArgumentsNormalizer.h index 7f83a84e4c6..874cf083aa6 100644 --- a/turbo-ext/src/generated/ArgumentsNormalizer.h +++ b/turbo-ext/src/generated/ArgumentsNormalizer.h @@ -43,11 +43,16 @@ inline constexpr char strings[] = "new\0" /* 386 */ "PhpParser\\Node\\Expr\\New_\0" /* 390 */ "reorderNewArguments\0" /* 415 */ - "callArgs\0" /* 435 */ - "reorderArgs\0" /* 444 */ - "node\0" /* 456 */ - "PhpParser\\Node\0" /* 461 */ - "attributesWithoutPrintedForm"; /* 476 */ + "args\0" /* 435 */ + "position\0" /* 440 */ + "name\0" /* 449 */ + "PhpParser\\Node\\Arg\0" /* 454 */ + "getArgByPositionOrName\0" /* 473 */ + "callArgs\0" /* 496 */ + "reorderArgs\0" /* 505 */ + "node\0" /* 517 */ + "PhpParser\\Node\0" /* 522 */ + "attributesWithoutPrintedForm"; /* 537 */ inline constexpr reg::PackedArg args[] = { reg::packed(0, 0, 17), /* reorderCallUserFuncArguments $callUserFuncCall */ reg::packed(46, 0, 52), /* reorderCallUserFuncArguments $scope */ @@ -67,10 +72,14 @@ inline constexpr reg::PackedArg args[] = { reg::packed(161, 0, 180), /* reorderNewArguments $parametersAcceptor */ reg::packed(386, 0, 390), /* reorderNewArguments $new */ reg::packed(75, MAY_BE_NULL, 390), /* reorderNewArguments return */ + reg::packed(435, MAY_BE_ARRAY), /* getArgByPositionOrName $args */ + reg::packed(440, MAY_BE_LONG), /* getArgByPositionOrName $position */ + reg::packed(449, MAY_BE_STRING), /* getArgByPositionOrName $name */ + reg::packed(75, MAY_BE_NULL, 454), /* getArgByPositionOrName return */ reg::packed(161, 0, 180), /* reorderArgs $parametersAcceptor */ - reg::packed(435, MAY_BE_ARRAY), /* reorderArgs $callArgs */ + reg::packed(496, MAY_BE_ARRAY), /* reorderArgs $callArgs */ reg::packed(75, MAY_BE_NULL | MAY_BE_ARRAY), /* reorderArgs return */ - reg::packed(456, 0, 461), /* attributesWithoutPrintedForm $node */ + reg::packed(517, 0, 522), /* attributesWithoutPrintedForm $node */ reg::packed(75, MAY_BE_ARRAY), /* attributesWithoutPrintedForm return */ }; using Sig = reg::Sig; @@ -84,8 +93,9 @@ inline constexpr sigtab::Sig reorderFuncArguments = { { 231 /* reorderFuncArgume inline constexpr sigtab::Sig reorderMethodArguments = { { 294 /* reorderMethodArguments */, 2, 9, 2, 11, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC } }; inline constexpr sigtab::Sig reorderStaticCallArguments = { { 359 /* reorderStaticCallArguments */, 2, 12, 2, 14, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC } }; inline constexpr sigtab::Sig reorderNewArguments = { { 415 /* reorderNewArguments */, 2, 15, 2, 17, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC } }; -inline constexpr sigtab::Sig reorderArgs = { { 444 /* reorderArgs */, 2, 18, 2, 20, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC } }; -inline constexpr sigtab::Sig attributesWithoutPrintedForm = { { 476 /* attributesWithoutPrintedForm */, 1, 21, 1, 22, ZEND_ACC_PRIVATE | ZEND_ACC_STATIC } }; +inline constexpr sigtab::Sig getArgByPositionOrName = { { 473 /* getArgByPositionOrName */, 3, 18, 3, 21, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC } }; +inline constexpr sigtab::Sig reorderArgs = { { 505 /* reorderArgs */, 2, 22, 2, 24, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC } }; +inline constexpr sigtab::Sig attributesWithoutPrintedForm = { { 537 /* attributesWithoutPrintedForm */, 1, 25, 1, 26, ZEND_ACC_PRIVATE | ZEND_ACC_STATIC } }; } // namespace sig } // namespace ptdecl::ArgumentsNormalizer diff --git a/turbo-ext/src/generated/ParametersAcceptorSelector.h b/turbo-ext/src/generated/ParametersAcceptorSelector.h index 08ecf32d636..50737785939 100644 --- a/turbo-ext/src/generated/ParametersAcceptorSelector.h +++ b/turbo-ext/src/generated/ParametersAcceptorSelector.h @@ -31,79 +31,84 @@ inline constexpr char strings[] = "\0" /* 82 */ "PHPStan\\Reflection\\ParametersAcceptor\0" /* 83 */ "selectFromArgs\0" /* 121 */ - "typeGetter\0" /* 136 */ - "Closure\0" /* 147 */ - "nativeTypeGetter\0" /* 155 */ - "iterableValueTypeGetter\0" /* 172 */ - "iterableKeyTypeGetter\0" /* 196 */ - "applyIntrinsicArgOverrides\0" /* 218 */ - "acceptor\0" /* 245 */ - "hasAcceptorTemplateOrLateResolvableType\0" /* 254 */ - "hasAcceptorTemplateOrLateResolvableParameterType\0" /* 294 */ - "types\0" /* 343 */ - "unpack\0" /* 349 */ - "selectFromTypes\0" /* 356 */ - "variants\0" /* 372 */ - "combineVariantsForNormalization\0" /* 381 */ - "acceptors\0" /* 413 */ - "PHPStan\\Reflection\\ExtendedParametersAcceptor\0" /* 423 */ - "combineAcceptors\0" /* 469 */ - "wrapAcceptor\0" /* 486 */ - "parameter\0" /* 499 */ - "PHPStan\\Reflection\\ParameterReflection\0" /* 509 */ - "PHPStan\\Reflection\\ExtendedParameterReflection\0" /* 548 */ - "wrapParameter\0" /* 595 */ - "curlOpt\0" /* 609 */ - "PHPStan\\Type\\Type\0" /* 617 */ - "getCurlOptValueType\0" /* 635 */ - "original\0" /* 655 */ - "type\0" /* 664 */ - "nativeType\0" /* 669 */ - "PHPStan\\Reflection\\Php\\ExtendedDummyParameter\0" /* 680 */ - "overrideParameterType\0" /* 726 */ - "parameters\0" /* 748 */ - "overrideAcceptorParameters"; /* 759 */ + "parametersAcceptor\0" /* 136 */ + "reorderIntrinsicArgs\0" /* 155 */ + "typeGetter\0" /* 176 */ + "Closure\0" /* 187 */ + "nativeTypeGetter\0" /* 195 */ + "iterableValueTypeGetter\0" /* 212 */ + "iterableKeyTypeGetter\0" /* 236 */ + "applyIntrinsicArgOverrides\0" /* 258 */ + "acceptor\0" /* 285 */ + "hasAcceptorTemplateOrLateResolvableType\0" /* 294 */ + "hasAcceptorTemplateOrLateResolvableParameterType\0" /* 334 */ + "types\0" /* 383 */ + "unpack\0" /* 389 */ + "selectFromTypes\0" /* 396 */ + "variants\0" /* 412 */ + "combineVariantsForNormalization\0" /* 421 */ + "acceptors\0" /* 453 */ + "PHPStan\\Reflection\\ExtendedParametersAcceptor\0" /* 463 */ + "combineAcceptors\0" /* 509 */ + "wrapAcceptor\0" /* 526 */ + "parameter\0" /* 539 */ + "PHPStan\\Reflection\\ParameterReflection\0" /* 549 */ + "PHPStan\\Reflection\\ExtendedParameterReflection\0" /* 588 */ + "wrapParameter\0" /* 635 */ + "curlOpt\0" /* 649 */ + "PHPStan\\Type\\Type\0" /* 657 */ + "getCurlOptValueType\0" /* 675 */ + "original\0" /* 695 */ + "type\0" /* 704 */ + "nativeType\0" /* 709 */ + "PHPStan\\Reflection\\Php\\ExtendedDummyParameter\0" /* 720 */ + "overrideParameterType\0" /* 766 */ + "parameters\0" /* 788 */ + "overrideAcceptorParameters"; /* 799 */ inline constexpr reg::PackedArg args[] = { reg::packed(0, 0, 6), /* selectFromArgs $scope */ reg::packed(29, MAY_BE_ARRAY), /* selectFromArgs $args */ reg::packed(34, MAY_BE_ARRAY), /* selectFromArgs $parametersAcceptors */ reg::packed(54, MAY_BE_NULL | MAY_BE_ARRAY, reg::NoString, false, false, 77), /* selectFromArgs $namedArgumentsVariants */ reg::packed(82, 0, 83), /* selectFromArgs return */ + reg::packed(29, MAY_BE_ARRAY), /* reorderIntrinsicArgs $args */ + reg::packed(136, 0, 83), /* reorderIntrinsicArgs $parametersAcceptor */ + reg::packed(82, MAY_BE_ARRAY), /* reorderIntrinsicArgs return */ reg::packed(29, MAY_BE_ARRAY), /* applyIntrinsicArgOverrides $args */ reg::packed(34, MAY_BE_ARRAY), /* applyIntrinsicArgOverrides $parametersAcceptors */ reg::packed(54, MAY_BE_NULL | MAY_BE_ARRAY), /* applyIntrinsicArgOverrides $namedArgumentsVariants */ reg::packed(0, 0, 6), /* applyIntrinsicArgOverrides $scope */ - reg::packed(136, 0, 147), /* applyIntrinsicArgOverrides $typeGetter */ - reg::packed(155, 0, 147), /* applyIntrinsicArgOverrides $nativeTypeGetter */ - reg::packed(172, 0, 147), /* applyIntrinsicArgOverrides $iterableValueTypeGetter */ - reg::packed(196, 0, 147), /* applyIntrinsicArgOverrides $iterableKeyTypeGetter */ + reg::packed(176, 0, 187), /* applyIntrinsicArgOverrides $typeGetter */ + reg::packed(195, 0, 187), /* applyIntrinsicArgOverrides $nativeTypeGetter */ + reg::packed(212, 0, 187), /* applyIntrinsicArgOverrides $iterableValueTypeGetter */ + reg::packed(236, 0, 187), /* applyIntrinsicArgOverrides $iterableKeyTypeGetter */ reg::packed(82, MAY_BE_ARRAY), /* applyIntrinsicArgOverrides return */ - reg::packed(245, 0, 83), /* hasAcceptorTemplateOrLateResolvableType $acceptor */ + reg::packed(285, 0, 83), /* hasAcceptorTemplateOrLateResolvableType $acceptor */ reg::packed(82, MAY_BE_BOOL), /* hasAcceptorTemplateOrLateResolvableType return */ - reg::packed(245, 0, 83), /* hasAcceptorTemplateOrLateResolvableParameterType $acceptor */ + reg::packed(285, 0, 83), /* hasAcceptorTemplateOrLateResolvableParameterType $acceptor */ reg::packed(82, MAY_BE_BOOL), /* hasAcceptorTemplateOrLateResolvableParameterType return */ - reg::packed(343, MAY_BE_ARRAY), /* selectFromTypes $types */ + reg::packed(383, MAY_BE_ARRAY), /* selectFromTypes $types */ reg::packed(34, MAY_BE_ARRAY), /* selectFromTypes $parametersAcceptors */ - reg::packed(349, MAY_BE_BOOL), /* selectFromTypes $unpack */ + reg::packed(389, MAY_BE_BOOL), /* selectFromTypes $unpack */ reg::packed(82, 0, 83), /* selectFromTypes return */ reg::packed(29, MAY_BE_ARRAY), /* combineVariantsForNormalization $args */ - reg::packed(372, MAY_BE_ARRAY), /* combineVariantsForNormalization $variants */ + reg::packed(412, MAY_BE_ARRAY), /* combineVariantsForNormalization $variants */ reg::packed(54, MAY_BE_NULL | MAY_BE_ARRAY), /* combineVariantsForNormalization $namedArgumentsVariants */ reg::packed(82, 0, 83), /* combineVariantsForNormalization return */ - reg::packed(413, MAY_BE_ARRAY), /* combineAcceptors $acceptors */ - reg::packed(82, 0, 423), /* combineAcceptors return */ - reg::packed(245, 0, 83), /* wrapAcceptor $acceptor */ - reg::packed(82, 0, 423), /* wrapAcceptor return */ - reg::packed(499, 0, 509), /* wrapParameter $parameter */ - reg::packed(82, 0, 548), /* wrapParameter return */ - reg::packed(609, MAY_BE_LONG), /* getCurlOptValueType $curlOpt */ - reg::packed(82, MAY_BE_NULL, 617), /* getCurlOptValueType return */ - reg::packed(655, 0, 509), /* overrideParameterType $original */ - reg::packed(664, 0, 617), /* overrideParameterType $type */ - reg::packed(669, 0, 617), /* overrideParameterType $nativeType */ - reg::packed(82, 0, 680), /* overrideParameterType return */ - reg::packed(245, 0, 83), /* overrideAcceptorParameters $acceptor */ - reg::packed(748, MAY_BE_ARRAY), /* overrideAcceptorParameters $parameters */ + reg::packed(453, MAY_BE_ARRAY), /* combineAcceptors $acceptors */ + reg::packed(82, 0, 463), /* combineAcceptors return */ + reg::packed(285, 0, 83), /* wrapAcceptor $acceptor */ + reg::packed(82, 0, 463), /* wrapAcceptor return */ + reg::packed(539, 0, 549), /* wrapParameter $parameter */ + reg::packed(82, 0, 588), /* wrapParameter return */ + reg::packed(649, MAY_BE_LONG), /* getCurlOptValueType $curlOpt */ + reg::packed(82, MAY_BE_NULL, 657), /* getCurlOptValueType return */ + reg::packed(695, 0, 549), /* overrideParameterType $original */ + reg::packed(704, 0, 657), /* overrideParameterType $type */ + reg::packed(709, 0, 657), /* overrideParameterType $nativeType */ + reg::packed(82, 0, 720), /* overrideParameterType return */ + reg::packed(285, 0, 83), /* overrideAcceptorParameters $acceptor */ + reg::packed(788, MAY_BE_ARRAY), /* overrideAcceptorParameters $parameters */ reg::packed(82, 0, 83), /* overrideAcceptorParameters return */ }; using Sig = reg::Sig; @@ -112,17 +117,18 @@ using Sig = reg::Sig; /* the signatures of the methods the class declares itself (a used trait's are in the trait's header) */ namespace sig { inline constexpr sigtab::Sig selectFromArgs = { { 121 /* selectFromArgs */, 3, 0, 4, 4, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC } }; -inline constexpr sigtab::Sig applyIntrinsicArgOverrides = { { 218 /* applyIntrinsicArgOverrides */, 8, 5, 8, 13, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC } }; -inline constexpr sigtab::Sig hasAcceptorTemplateOrLateResolvableType = { { 254 /* hasAcceptorTemplateOrLateResolvableType */, 1, 14, 1, 15, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC } }; -inline constexpr sigtab::Sig hasAcceptorTemplateOrLateResolvableParameterType = { { 294 /* hasAcceptorTemplateOrLateResolvableParameterType */, 1, 16, 1, 17, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC } }; -inline constexpr sigtab::Sig selectFromTypes = { { 356 /* selectFromTypes */, 3, 18, 3, 21, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC } }; -inline constexpr sigtab::Sig combineVariantsForNormalization = { { 381 /* combineVariantsForNormalization */, 3, 22, 3, 25, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC } }; -inline constexpr sigtab::Sig combineAcceptors = { { 469 /* combineAcceptors */, 1, 26, 1, 27, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC } }; -inline constexpr sigtab::Sig wrapAcceptor = { { 486 /* wrapAcceptor */, 1, 28, 1, 29, ZEND_ACC_PRIVATE | ZEND_ACC_STATIC } }; -inline constexpr sigtab::Sig wrapParameter = { { 595 /* wrapParameter */, 1, 30, 1, 31, ZEND_ACC_PRIVATE | ZEND_ACC_STATIC } }; -inline constexpr sigtab::Sig getCurlOptValueType = { { 635 /* getCurlOptValueType */, 1, 32, 1, 33, ZEND_ACC_PRIVATE | ZEND_ACC_STATIC } }; -inline constexpr sigtab::Sig overrideParameterType = { { 726 /* overrideParameterType */, 3, 34, 3, 37, ZEND_ACC_PRIVATE | ZEND_ACC_STATIC } }; -inline constexpr sigtab::Sig overrideAcceptorParameters = { { 759 /* overrideAcceptorParameters */, 2, 38, 2, 40, ZEND_ACC_PRIVATE | ZEND_ACC_STATIC } }; +inline constexpr sigtab::Sig reorderIntrinsicArgs = { { 155 /* reorderIntrinsicArgs */, 2, 5, 2, 7, ZEND_ACC_PRIVATE | ZEND_ACC_STATIC } }; +inline constexpr sigtab::Sig applyIntrinsicArgOverrides = { { 258 /* applyIntrinsicArgOverrides */, 8, 8, 8, 16, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC } }; +inline constexpr sigtab::Sig hasAcceptorTemplateOrLateResolvableType = { { 294 /* hasAcceptorTemplateOrLateResolvableType */, 1, 17, 1, 18, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC } }; +inline constexpr sigtab::Sig hasAcceptorTemplateOrLateResolvableParameterType = { { 334 /* hasAcceptorTemplateOrLateResolvableParameterType */, 1, 19, 1, 20, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC } }; +inline constexpr sigtab::Sig selectFromTypes = { { 396 /* selectFromTypes */, 3, 21, 3, 24, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC } }; +inline constexpr sigtab::Sig combineVariantsForNormalization = { { 421 /* combineVariantsForNormalization */, 3, 25, 3, 28, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC } }; +inline constexpr sigtab::Sig combineAcceptors = { { 509 /* combineAcceptors */, 1, 29, 1, 30, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC } }; +inline constexpr sigtab::Sig wrapAcceptor = { { 526 /* wrapAcceptor */, 1, 31, 1, 32, ZEND_ACC_PRIVATE | ZEND_ACC_STATIC } }; +inline constexpr sigtab::Sig wrapParameter = { { 635 /* wrapParameter */, 1, 33, 1, 34, ZEND_ACC_PRIVATE | ZEND_ACC_STATIC } }; +inline constexpr sigtab::Sig getCurlOptValueType = { { 675 /* getCurlOptValueType */, 1, 35, 1, 36, ZEND_ACC_PRIVATE | ZEND_ACC_STATIC } }; +inline constexpr sigtab::Sig overrideParameterType = { { 766 /* overrideParameterType */, 3, 37, 3, 40, ZEND_ACC_PRIVATE | ZEND_ACC_STATIC } }; +inline constexpr sigtab::Sig overrideAcceptorParameters = { { 799 /* overrideAcceptorParameters */, 2, 41, 2, 43, ZEND_ACC_PRIVATE | ZEND_ACC_STATIC } }; } // namespace sig } // namespace ptdecl::ParametersAcceptorSelector