diff --git a/composer.json b/composer.json index 14771e8..e1b293d 100644 --- a/composer.json +++ b/composer.json @@ -15,6 +15,7 @@ "thecodingmachine/safe": "^1.0 || ^2.0" }, "require-dev": { + "nikic/php-parser": "^4", "phpunit/phpunit": "^9.6", "php-coveralls/php-coveralls": "^2.1", "squizlabs/php_codesniffer": "^3.4" diff --git a/src/Rules/UseSafeFunctionsRule.php b/src/Rules/UseSafeFunctionsRule.php index d649184..8ba50ac 100644 --- a/src/Rules/UseSafeFunctionsRule.php +++ b/src/Rules/UseSafeFunctionsRule.php @@ -19,6 +19,11 @@ */ class UseSafeFunctionsRule implements Rule { + /** + * @see JSON_THROW_ON_ERROR + */ + const JSON_THROW_ON_ERROR = 4194304; + public function getNodeType(): string { return Node\Expr\FuncCall::class; @@ -33,18 +38,18 @@ public function processNode(Node $node, Scope $scope): array $unsafeFunctions = FunctionListLoader::getFunctionList(); if (isset($unsafeFunctions[$functionName])) { - if ( - $functionName === "json_decode" - && $this->argValueIncludeJSONTHROWONERROR($node->getArgs()[3] ?? null) - ) { - return []; - } + if (! $node->isFirstClassCallable()) { + if ($functionName === "json_decode" + && $this->argValueIncludeJSONTHROWONERROR($node->getArgs()[3] ?? null) + ) { + return []; + } - if ( - $functionName === "json_encode" - && $this->argValueIncludeJSONTHROWONERROR($node->getArgs()[1] ?? null) - ) { - return []; + if ($functionName === "json_encode" + && $this->argValueIncludeJSONTHROWONERROR($node->getArgs()[1] ?? null) + ) { + return []; + } } return [new SafeFunctionRuleError($node->name, $node->getStartLine())]; @@ -77,8 +82,7 @@ private function argValueIncludeJSONTHROWONERROR(?Arg $arg): bool } return in_array(true, array_map(function ($element) { - // JSON_THROW_ON_ERROR == 4194304 - return ($element & 4194304) == 4194304; + return ($element & self::JSON_THROW_ON_ERROR) == self::JSON_THROW_ON_ERROR; }, array_filter($options, function ($element) { return is_int($element); })), true); diff --git a/src/Type/Php/ReplaceSafeFunctionsDynamicReturnTypeExtension.php b/src/Type/Php/ReplaceSafeFunctionsDynamicReturnTypeExtension.php index 02711e1..fe1ae33 100644 --- a/src/Type/Php/ReplaceSafeFunctionsDynamicReturnTypeExtension.php +++ b/src/Type/Php/ReplaceSafeFunctionsDynamicReturnTypeExtension.php @@ -56,22 +56,17 @@ private function getPreliminarilyResolvedTypeFromFunctionCall( Scope $scope ): Type { $argumentPosition = $this->functions[$functionReflection->getName()]; - $defaultReturnType = ParametersAcceptorSelector::selectFromArgs( - $scope, - $functionCall->getArgs(), - $functionReflection->getVariants() - ) + + $args = $functionCall->getArgs(); + $variants = $functionReflection->getVariants(); + $defaultReturnType = ParametersAcceptorSelector::selectFromArgs($scope, $args, $variants) ->getReturnType(); - - if (count($functionCall->args) <= $argumentPosition) { - return $defaultReturnType; - } - $subjectArgument = $functionCall->args[$argumentPosition]; - if (!$subjectArgument instanceof Arg) { + if (count($args) <= $argumentPosition) { return $defaultReturnType; } - + + $subjectArgument = $args[$argumentPosition]; $subjectArgumentType = $scope->getType($subjectArgument->value); $mixedType = new MixedType(); if ($subjectArgumentType->isSuperTypeOf($mixedType)->yes()) {