Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 2 additions & 25 deletions src/Rule/ForbidEnumInFunctionArgumentsRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,41 +18,26 @@
use function array_key_exists;
use function count;
use function implode;
use const SORT_REGULAR;

/**
* @template-implements Rule<FuncCall>
*/
class ForbidEnumInFunctionArgumentsRule implements Rule
{

private const ANY_ARGUMENT = -1;

private const REASON_IMPLICIT_TO_STRING = 'as the function causes implicit __toString conversion which is not supported for enums';
private const REASON_UNPREDICTABLE_RESULT = 'as the function causes unexpected results'; // https://3v4l.org/YtGVa
private const REASON_SKIPS_ENUMS = 'as the function will skip any enums and produce warning';

/**
* Function name -> [forbidden argument position, reason]]
*/
private const FUNCTION_MAP = [
'array_intersect' => [self::ANY_ARGUMENT, self::REASON_IMPLICIT_TO_STRING],
'array_intersect_assoc' => [self::ANY_ARGUMENT, self::REASON_IMPLICIT_TO_STRING],
'array_diff' => [self::ANY_ARGUMENT, self::REASON_IMPLICIT_TO_STRING],
'array_diff_assoc' => [self::ANY_ARGUMENT, self::REASON_IMPLICIT_TO_STRING],
'array_unique' => [0, self::REASON_IMPLICIT_TO_STRING],
'array_combine' => [0, self::REASON_IMPLICIT_TO_STRING],
'sort' => [0, self::REASON_UNPREDICTABLE_RESULT],
'asort' => [0, self::REASON_UNPREDICTABLE_RESULT],
'arsort' => [0, self::REASON_UNPREDICTABLE_RESULT],
'natsort' => [0, self::REASON_IMPLICIT_TO_STRING],
'natcasesort' => [0, self::REASON_IMPLICIT_TO_STRING],
'array_count_values' => [0, self::REASON_SKIPS_ENUMS],
'array_fill_keys' => [0, self::REASON_IMPLICIT_TO_STRING],
'array_flip' => [0, self::REASON_SKIPS_ENUMS],

// https://github.com/phpstan/phpstan/issues/11883
'array_product' => [0, self::REASON_UNPREDICTABLE_RESULT],
'array_sum' => [0, self::REASON_UNPREDICTABLE_RESULT],
'implode' => [1, self::REASON_IMPLICIT_TO_STRING],
];

private ReflectionProvider $reflectionProvider;
Expand Down Expand Up @@ -103,10 +88,6 @@ public function processNode(Node $node, Scope $scope): array
foreach ($funcCall->getArgs() as $position => $argument) {
$argumentType = $scope->getType($argument->value);

if ($functionName === 'array_unique' && $position === 1 && $argumentType->getConstantScalarValues() === [SORT_REGULAR]) {
return []; // this edgecase seems to be working fine
}

if (!$this->matchesPosition((int) $position, $forbiddenArgumentPosition)) {
continue;
}
Expand All @@ -130,10 +111,6 @@ public function processNode(Node $node, Scope $scope): array

private function matchesPosition(int $position, int $forbiddenArgumentPosition): bool
{
if ($forbiddenArgumentPosition === self::ANY_ARGUMENT) {
return true;
}

return $position === $forbiddenArgumentPosition;
}

Expand Down
24 changes: 12 additions & 12 deletions tests/Rule/data/ForbidEnumInFunctionArgumentsRule/code.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,23 +22,23 @@ public function testAllFunctions()
$enums2 = [SomeEnum::Bar];
$enums3 = [SomeEnum::Baz];

array_intersect($enums1, $enums2, $enums3); // error: Arguments 1, 2, 3 in array_intersect() cannot contain enum as the function causes implicit __toString conversion which is not supported for enums
array_intersect_assoc($enums1, $enums2, $enums3); // error: Arguments 1, 2, 3 in array_intersect_assoc() cannot contain enum as the function causes implicit __toString conversion which is not supported for enums
array_diff($enums1, $enums2, $enums3); // error: Arguments 1, 2, 3 in array_diff() cannot contain enum as the function causes implicit __toString conversion which is not supported for enums
array_diff_assoc($enums1, $enums2, $enums3); // error: Arguments 1, 2, 3 in array_diff_assoc() cannot contain enum as the function causes implicit __toString conversion which is not supported for enums
array_unique($enums1); // error: Argument 1 in array_unique() cannot contain enum as the function causes implicit __toString conversion which is not supported for enums
array_combine($enums2, $enums3); // error: Argument 1 in array_combine() cannot contain enum as the function causes implicit __toString conversion which is not supported for enums
array_intersect($enums1, $enums2, $enums3); // reported by native PHPStan
array_intersect_assoc($enums1, $enums2, $enums3); // reported by native PHPStan
array_diff($enums1, $enums2, $enums3); // reported by native PHPStan
array_diff_assoc($enums1, $enums2, $enums3); // reported by native PHPStan
array_unique($enums1); // reported by native PHPStan
array_combine($enums2, $enums3); // reported by native PHPStan
sort($enums1); // error: Argument 1 in sort() cannot contain enum as the function causes unexpected results
asort($enums1); // error: Argument 1 in asort() cannot contain enum as the function causes unexpected results
arsort($enums1); // error: Argument 1 in arsort() cannot contain enum as the function causes unexpected results
natsort($enums1); // error: Argument 1 in natsort() cannot contain enum as the function causes implicit __toString conversion which is not supported for enums
natcasesort($enums1); // error: Argument 1 in natcasesort() cannot contain enum as the function causes implicit __toString conversion which is not supported for enums
array_count_values($enums1); // error: Argument 1 in array_count_values() cannot contain enum as the function will skip any enums and produce warning
array_fill_keys($enums1, 1); // error: Argument 1 in array_fill_keys() cannot contain enum as the function causes implicit __toString conversion which is not supported for enums
array_flip($enums1); // error: Argument 1 in array_flip() cannot contain enum as the function will skip any enums and produce warning
natsort($enums1); // reported by native PHPStan
natcasesort($enums1); // reported by native PHPStan
array_count_values($enums1); // reported by native PHPStan
array_fill_keys($enums1, 1); // reported by native PHPStan
array_flip($enums1); // reported by native PHPStan
array_product($enums1); // error: Argument 1 in array_product() cannot contain enum as the function causes unexpected results
array_sum($enums1); // error: Argument 1 in array_sum() cannot contain enum as the function causes unexpected results
implode('', $enums1); // error: Argument 2 in implode() cannot contain enum as the function causes implicit __toString conversion which is not supported for enums
implode('', $enums1); // reported by native PHPStan
in_array(SomeEnum::Bar, $enums1);
}

Expand Down
Loading