Skip to content

Commit 0ae28f7

Browse files
committed
Fix Slevomat CS in_array bug
1 parent 5400b58 commit 0ae28f7

File tree

3 files changed

+151
-5
lines changed

3 files changed

+151
-5
lines changed

src/Rules/Comparison/ImpossibleCheckTypeHelper.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ public function findSpecifiedType(
123123
if ($isNeedleSupertype->maybe() || $isNeedleSupertype->yes()) {
124124
foreach ($haystackArrayTypes as $haystackArrayType) {
125125
foreach (TypeUtils::getConstantScalars($haystackArrayType->getIterableValueType()) as $constantScalarType) {
126-
if ($needleType->isSuperTypeOf($constantScalarType)->yes()) {
126+
if ($constantScalarType->isSuperTypeOf($needleType)->yes()) {
127127
continue 2;
128128
}
129129
}

tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeFunctionCallRuleTest.php

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -112,10 +112,6 @@ public function testImpossibleCheckTypeFunctionCall(): void
112112
'Call to function in_array() with arguments \'bar\'|\'foo\', array{\'baz\', \'lorem\'} and true will always evaluate to false.',
113113
244,
114114
],
115-
[
116-
'Call to function in_array() with arguments \'bar\'|\'foo\', array{\'foo\', \'bar\'} and true will always evaluate to true.',
117-
248,
118-
],
119115
[
120116
'Call to function in_array() with arguments \'foo\', array{\'foo\'} and true will always evaluate to true.',
121117
252,
@@ -533,4 +529,11 @@ public function testBug5354(): void
533529
$this->analyse([__DIR__ . '/data/bug-5354.php'], []);
534530
}
535531

532+
public function testSlevomatCsInArrayBug(): void
533+
{
534+
$this->checkAlwaysTrueCheckTypeFunctionCall = true;
535+
$this->treatPhpDocTypesAsCertain = true;
536+
$this->analyse([__DIR__ . '/data/slevomat-cs-in-array.php'], []);
537+
}
538+
536539
}
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
<?php
2+
3+
namespace SlevomatCsInArray;
4+
5+
class Foo
6+
{
7+
8+
private const GROUP_PUBLIC_CONSTANTS = 'public constants';
9+
private const GROUP_PROTECTED_CONSTANTS = 'protected constants';
10+
private const GROUP_PRIVATE_CONSTANTS = 'private constants';
11+
private const GROUP_PUBLIC_PROPERTIES = 'public properties';
12+
private const GROUP_PUBLIC_STATIC_PROPERTIES = 'public static properties';
13+
private const GROUP_PROTECTED_PROPERTIES = 'protected properties';
14+
private const GROUP_PROTECTED_STATIC_PROPERTIES = 'protected static properties';
15+
private const GROUP_PRIVATE_PROPERTIES = 'private properties';
16+
private const GROUP_PRIVATE_STATIC_PROPERTIES = 'private static properties';
17+
private const GROUP_CONSTRUCTOR = 'constructor';
18+
private const GROUP_STATIC_CONSTRUCTORS = 'static constructors';
19+
private const GROUP_DESTRUCTOR = 'destructor';
20+
private const GROUP_MAGIC_METHODS = 'magic methods';
21+
private const GROUP_PUBLIC_METHODS = 'public methods';
22+
private const GROUP_PUBLIC_ABSTRACT_METHODS = 'public abstract methods';
23+
private const GROUP_PUBLIC_FINAL_METHODS = 'public final methods';
24+
private const GROUP_PUBLIC_STATIC_METHODS = 'public static methods';
25+
private const GROUP_PUBLIC_STATIC_ABSTRACT_METHODS = 'public static abstract methods';
26+
private const GROUP_PUBLIC_STATIC_FINAL_METHODS = 'public static final methods';
27+
private const GROUP_PROTECTED_METHODS = 'protected methods';
28+
private const GROUP_PROTECTED_ABSTRACT_METHODS = 'protected abstract methods';
29+
private const GROUP_PROTECTED_FINAL_METHODS = 'protected final methods';
30+
private const GROUP_PROTECTED_STATIC_METHODS = 'protected static methods';
31+
private const GROUP_PROTECTED_STATIC_ABSTRACT_METHODS = 'protected static abstract methods';
32+
private const GROUP_PROTECTED_STATIC_FINAL_METHODS = 'protected static final methods';
33+
private const GROUP_PRIVATE_METHODS = 'private methods';
34+
private const GROUP_PRIVATE_STATIC_METHODS = 'private static methods';
35+
36+
private const GROUP_SHORTCUT_CONSTANTS = 'constants';
37+
private const GROUP_SHORTCUT_PROPERTIES = 'properties';
38+
private const GROUP_SHORTCUT_STATIC_PROPERTIES = 'static properties';
39+
private const GROUP_SHORTCUT_METHODS = 'methods';
40+
private const GROUP_SHORTCUT_PUBLIC_METHODS = 'all public methods';
41+
private const GROUP_SHORTCUT_PROTECTED_METHODS = 'all protected methods';
42+
private const GROUP_SHORTCUT_PRIVATE_METHODS = 'all private methods';
43+
private const GROUP_SHORTCUT_STATIC_METHODS = 'static methods';
44+
private const GROUP_SHORTCUT_ABSTRACT_METHODS = 'abstract methods';
45+
private const GROUP_SHORTCUT_FINAL_METHODS = 'final methods';
46+
47+
private const SHORTCUTS = [
48+
self::GROUP_SHORTCUT_CONSTANTS => [
49+
self::GROUP_PUBLIC_CONSTANTS,
50+
self::GROUP_PROTECTED_CONSTANTS,
51+
self::GROUP_PRIVATE_CONSTANTS,
52+
],
53+
self::GROUP_SHORTCUT_STATIC_PROPERTIES => [
54+
self::GROUP_PUBLIC_STATIC_PROPERTIES,
55+
self::GROUP_PROTECTED_STATIC_PROPERTIES,
56+
self::GROUP_PRIVATE_STATIC_PROPERTIES,
57+
],
58+
self::GROUP_SHORTCUT_PROPERTIES => [
59+
self::GROUP_SHORTCUT_STATIC_PROPERTIES,
60+
self::GROUP_PUBLIC_PROPERTIES,
61+
self::GROUP_PROTECTED_PROPERTIES,
62+
self::GROUP_PRIVATE_PROPERTIES,
63+
],
64+
self::GROUP_SHORTCUT_PUBLIC_METHODS => [
65+
self::GROUP_PUBLIC_FINAL_METHODS,
66+
self::GROUP_PUBLIC_STATIC_FINAL_METHODS,
67+
self::GROUP_PUBLIC_ABSTRACT_METHODS,
68+
self::GROUP_PUBLIC_STATIC_ABSTRACT_METHODS,
69+
self::GROUP_PUBLIC_STATIC_METHODS,
70+
self::GROUP_PUBLIC_METHODS,
71+
],
72+
self::GROUP_SHORTCUT_PROTECTED_METHODS => [
73+
self::GROUP_PROTECTED_FINAL_METHODS,
74+
self::GROUP_PROTECTED_STATIC_FINAL_METHODS,
75+
self::GROUP_PROTECTED_ABSTRACT_METHODS,
76+
self::GROUP_PROTECTED_STATIC_ABSTRACT_METHODS,
77+
self::GROUP_PROTECTED_STATIC_METHODS,
78+
self::GROUP_PROTECTED_METHODS,
79+
],
80+
self::GROUP_SHORTCUT_PRIVATE_METHODS => [
81+
self::GROUP_PRIVATE_STATIC_METHODS,
82+
self::GROUP_PRIVATE_METHODS,
83+
],
84+
self::GROUP_SHORTCUT_FINAL_METHODS => [
85+
self::GROUP_PUBLIC_FINAL_METHODS,
86+
self::GROUP_PROTECTED_FINAL_METHODS,
87+
self::GROUP_PUBLIC_STATIC_FINAL_METHODS,
88+
self::GROUP_PROTECTED_STATIC_FINAL_METHODS,
89+
],
90+
self::GROUP_SHORTCUT_ABSTRACT_METHODS => [
91+
self::GROUP_PUBLIC_ABSTRACT_METHODS,
92+
self::GROUP_PROTECTED_ABSTRACT_METHODS,
93+
self::GROUP_PUBLIC_STATIC_ABSTRACT_METHODS,
94+
self::GROUP_PROTECTED_STATIC_ABSTRACT_METHODS,
95+
],
96+
self::GROUP_SHORTCUT_STATIC_METHODS => [
97+
self::GROUP_STATIC_CONSTRUCTORS,
98+
self::GROUP_PUBLIC_STATIC_FINAL_METHODS,
99+
self::GROUP_PROTECTED_STATIC_FINAL_METHODS,
100+
self::GROUP_PUBLIC_STATIC_ABSTRACT_METHODS,
101+
self::GROUP_PROTECTED_STATIC_ABSTRACT_METHODS,
102+
self::GROUP_PUBLIC_STATIC_METHODS,
103+
self::GROUP_PROTECTED_STATIC_METHODS,
104+
self::GROUP_PRIVATE_STATIC_METHODS,
105+
],
106+
self::GROUP_SHORTCUT_METHODS => [
107+
self::GROUP_SHORTCUT_FINAL_METHODS,
108+
self::GROUP_SHORTCUT_ABSTRACT_METHODS,
109+
self::GROUP_SHORTCUT_STATIC_METHODS,
110+
self::GROUP_CONSTRUCTOR,
111+
self::GROUP_DESTRUCTOR,
112+
self::GROUP_PUBLIC_METHODS,
113+
self::GROUP_PROTECTED_METHODS,
114+
self::GROUP_PRIVATE_METHODS,
115+
self::GROUP_MAGIC_METHODS,
116+
],
117+
];
118+
119+
/**
120+
* @param array<int, string> $supportedGroups
121+
* @return array<int, string>
122+
*/
123+
public function unpackShortcut(string $shortcut, array $supportedGroups): array
124+
{
125+
$groups = [];
126+
127+
foreach (self::SHORTCUTS[$shortcut] as $groupOrShortcut) {
128+
if (in_array($groupOrShortcut, $supportedGroups, true)) {
129+
$groups[] = $groupOrShortcut;
130+
} elseif (
131+
!array_key_exists($groupOrShortcut, self::SHORTCUTS)
132+
&& in_array($groupOrShortcut, self::SHORTCUTS[self::GROUP_SHORTCUT_FINAL_METHODS], true)
133+
) {
134+
// Nothing
135+
} else {
136+
$groups = array_merge($groups, $this->unpackShortcut($groupOrShortcut, $supportedGroups));
137+
}
138+
}
139+
140+
return $groups;
141+
}
142+
143+
}

0 commit comments

Comments
 (0)