Skip to content

Commit

Permalink
Fix Slevomat CS in_array bug
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrejmirtes committed Apr 3, 2022
1 parent 5400b58 commit 0ae28f7
Show file tree
Hide file tree
Showing 3 changed files with 151 additions and 5 deletions.
2 changes: 1 addition & 1 deletion src/Rules/Comparison/ImpossibleCheckTypeHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ public function findSpecifiedType(
if ($isNeedleSupertype->maybe() || $isNeedleSupertype->yes()) {
foreach ($haystackArrayTypes as $haystackArrayType) {
foreach (TypeUtils::getConstantScalars($haystackArrayType->getIterableValueType()) as $constantScalarType) {
if ($needleType->isSuperTypeOf($constantScalarType)->yes()) {
if ($constantScalarType->isSuperTypeOf($needleType)->yes()) {
continue 2;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,10 +112,6 @@ public function testImpossibleCheckTypeFunctionCall(): void
'Call to function in_array() with arguments \'bar\'|\'foo\', array{\'baz\', \'lorem\'} and true will always evaluate to false.',
244,
],
[
'Call to function in_array() with arguments \'bar\'|\'foo\', array{\'foo\', \'bar\'} and true will always evaluate to true.',
248,
],
[
'Call to function in_array() with arguments \'foo\', array{\'foo\'} and true will always evaluate to true.',
252,
Expand Down Expand Up @@ -533,4 +529,11 @@ public function testBug5354(): void
$this->analyse([__DIR__ . '/data/bug-5354.php'], []);
}

public function testSlevomatCsInArrayBug(): void
{
$this->checkAlwaysTrueCheckTypeFunctionCall = true;
$this->treatPhpDocTypesAsCertain = true;
$this->analyse([__DIR__ . '/data/slevomat-cs-in-array.php'], []);
}

}
143 changes: 143 additions & 0 deletions tests/PHPStan/Rules/Comparison/data/slevomat-cs-in-array.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
<?php

namespace SlevomatCsInArray;

class Foo
{

private const GROUP_PUBLIC_CONSTANTS = 'public constants';
private const GROUP_PROTECTED_CONSTANTS = 'protected constants';
private const GROUP_PRIVATE_CONSTANTS = 'private constants';
private const GROUP_PUBLIC_PROPERTIES = 'public properties';
private const GROUP_PUBLIC_STATIC_PROPERTIES = 'public static properties';
private const GROUP_PROTECTED_PROPERTIES = 'protected properties';
private const GROUP_PROTECTED_STATIC_PROPERTIES = 'protected static properties';
private const GROUP_PRIVATE_PROPERTIES = 'private properties';
private const GROUP_PRIVATE_STATIC_PROPERTIES = 'private static properties';
private const GROUP_CONSTRUCTOR = 'constructor';
private const GROUP_STATIC_CONSTRUCTORS = 'static constructors';
private const GROUP_DESTRUCTOR = 'destructor';
private const GROUP_MAGIC_METHODS = 'magic methods';
private const GROUP_PUBLIC_METHODS = 'public methods';
private const GROUP_PUBLIC_ABSTRACT_METHODS = 'public abstract methods';
private const GROUP_PUBLIC_FINAL_METHODS = 'public final methods';
private const GROUP_PUBLIC_STATIC_METHODS = 'public static methods';
private const GROUP_PUBLIC_STATIC_ABSTRACT_METHODS = 'public static abstract methods';
private const GROUP_PUBLIC_STATIC_FINAL_METHODS = 'public static final methods';
private const GROUP_PROTECTED_METHODS = 'protected methods';
private const GROUP_PROTECTED_ABSTRACT_METHODS = 'protected abstract methods';
private const GROUP_PROTECTED_FINAL_METHODS = 'protected final methods';
private const GROUP_PROTECTED_STATIC_METHODS = 'protected static methods';
private const GROUP_PROTECTED_STATIC_ABSTRACT_METHODS = 'protected static abstract methods';
private const GROUP_PROTECTED_STATIC_FINAL_METHODS = 'protected static final methods';
private const GROUP_PRIVATE_METHODS = 'private methods';
private const GROUP_PRIVATE_STATIC_METHODS = 'private static methods';

private const GROUP_SHORTCUT_CONSTANTS = 'constants';
private const GROUP_SHORTCUT_PROPERTIES = 'properties';
private const GROUP_SHORTCUT_STATIC_PROPERTIES = 'static properties';
private const GROUP_SHORTCUT_METHODS = 'methods';
private const GROUP_SHORTCUT_PUBLIC_METHODS = 'all public methods';
private const GROUP_SHORTCUT_PROTECTED_METHODS = 'all protected methods';
private const GROUP_SHORTCUT_PRIVATE_METHODS = 'all private methods';
private const GROUP_SHORTCUT_STATIC_METHODS = 'static methods';
private const GROUP_SHORTCUT_ABSTRACT_METHODS = 'abstract methods';
private const GROUP_SHORTCUT_FINAL_METHODS = 'final methods';

private const SHORTCUTS = [
self::GROUP_SHORTCUT_CONSTANTS => [
self::GROUP_PUBLIC_CONSTANTS,
self::GROUP_PROTECTED_CONSTANTS,
self::GROUP_PRIVATE_CONSTANTS,
],
self::GROUP_SHORTCUT_STATIC_PROPERTIES => [
self::GROUP_PUBLIC_STATIC_PROPERTIES,
self::GROUP_PROTECTED_STATIC_PROPERTIES,
self::GROUP_PRIVATE_STATIC_PROPERTIES,
],
self::GROUP_SHORTCUT_PROPERTIES => [
self::GROUP_SHORTCUT_STATIC_PROPERTIES,
self::GROUP_PUBLIC_PROPERTIES,
self::GROUP_PROTECTED_PROPERTIES,
self::GROUP_PRIVATE_PROPERTIES,
],
self::GROUP_SHORTCUT_PUBLIC_METHODS => [
self::GROUP_PUBLIC_FINAL_METHODS,
self::GROUP_PUBLIC_STATIC_FINAL_METHODS,
self::GROUP_PUBLIC_ABSTRACT_METHODS,
self::GROUP_PUBLIC_STATIC_ABSTRACT_METHODS,
self::GROUP_PUBLIC_STATIC_METHODS,
self::GROUP_PUBLIC_METHODS,
],
self::GROUP_SHORTCUT_PROTECTED_METHODS => [
self::GROUP_PROTECTED_FINAL_METHODS,
self::GROUP_PROTECTED_STATIC_FINAL_METHODS,
self::GROUP_PROTECTED_ABSTRACT_METHODS,
self::GROUP_PROTECTED_STATIC_ABSTRACT_METHODS,
self::GROUP_PROTECTED_STATIC_METHODS,
self::GROUP_PROTECTED_METHODS,
],
self::GROUP_SHORTCUT_PRIVATE_METHODS => [
self::GROUP_PRIVATE_STATIC_METHODS,
self::GROUP_PRIVATE_METHODS,
],
self::GROUP_SHORTCUT_FINAL_METHODS => [
self::GROUP_PUBLIC_FINAL_METHODS,
self::GROUP_PROTECTED_FINAL_METHODS,
self::GROUP_PUBLIC_STATIC_FINAL_METHODS,
self::GROUP_PROTECTED_STATIC_FINAL_METHODS,
],
self::GROUP_SHORTCUT_ABSTRACT_METHODS => [
self::GROUP_PUBLIC_ABSTRACT_METHODS,
self::GROUP_PROTECTED_ABSTRACT_METHODS,
self::GROUP_PUBLIC_STATIC_ABSTRACT_METHODS,
self::GROUP_PROTECTED_STATIC_ABSTRACT_METHODS,
],
self::GROUP_SHORTCUT_STATIC_METHODS => [
self::GROUP_STATIC_CONSTRUCTORS,
self::GROUP_PUBLIC_STATIC_FINAL_METHODS,
self::GROUP_PROTECTED_STATIC_FINAL_METHODS,
self::GROUP_PUBLIC_STATIC_ABSTRACT_METHODS,
self::GROUP_PROTECTED_STATIC_ABSTRACT_METHODS,
self::GROUP_PUBLIC_STATIC_METHODS,
self::GROUP_PROTECTED_STATIC_METHODS,
self::GROUP_PRIVATE_STATIC_METHODS,
],
self::GROUP_SHORTCUT_METHODS => [
self::GROUP_SHORTCUT_FINAL_METHODS,
self::GROUP_SHORTCUT_ABSTRACT_METHODS,
self::GROUP_SHORTCUT_STATIC_METHODS,
self::GROUP_CONSTRUCTOR,
self::GROUP_DESTRUCTOR,
self::GROUP_PUBLIC_METHODS,
self::GROUP_PROTECTED_METHODS,
self::GROUP_PRIVATE_METHODS,
self::GROUP_MAGIC_METHODS,
],
];

/**
* @param array<int, string> $supportedGroups
* @return array<int, string>
*/
public function unpackShortcut(string $shortcut, array $supportedGroups): array
{
$groups = [];

foreach (self::SHORTCUTS[$shortcut] as $groupOrShortcut) {
if (in_array($groupOrShortcut, $supportedGroups, true)) {
$groups[] = $groupOrShortcut;
} elseif (
!array_key_exists($groupOrShortcut, self::SHORTCUTS)
&& in_array($groupOrShortcut, self::SHORTCUTS[self::GROUP_SHORTCUT_FINAL_METHODS], true)
) {
// Nothing
} else {
$groups = array_merge($groups, $this->unpackShortcut($groupOrShortcut, $supportedGroups));
}
}

return $groups;
}

}

0 comments on commit 0ae28f7

Please sign in to comment.