Skip to content

Commit

Permalink
Handle FuncCall nodes that represent first class callables
Browse files Browse the repository at this point in the history
  • Loading branch information
spawnia committed Nov 25, 2024
1 parent ccd3d55 commit abaeae5
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 25 deletions.
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
30 changes: 17 additions & 13 deletions src/Rules/UseSafeFunctionsRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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())];
Expand Down Expand Up @@ -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);
Expand Down
19 changes: 7 additions & 12 deletions src/Type/Php/ReplaceSafeFunctionsDynamicReturnTypeExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -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()) {
Expand Down

0 comments on commit abaeae5

Please sign in to comment.