Skip to content

Commit ee9d8d2

Browse files
committed
Narrow string type when ctype_* functions return true
1 parent 745d02b commit ee9d8d2

File tree

3 files changed

+203
-0
lines changed

3 files changed

+203
-0
lines changed

conf/config.neon

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ parameters:
144144
- ../stubs/file.stub
145145
- ../stubs/stream_socket_client.stub
146146
- ../stubs/stream_socket_server.stub
147+
- ../stubs/ctype.stub
147148
earlyTerminatingMethodCalls: []
148149
earlyTerminatingFunctionCalls: []
149150
resultCachePath: %tmpDir%/resultCache.php

stubs/ctype.stub

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php
2+
3+
/**
4+
* @phpstan-assert-if-true =($text is string ? non-empty-string : int) $text
5+
*/
6+
function ctype_alnum(mixed $text): bool {}
7+
8+
/**
9+
* @phpstan-assert-if-true =($text is string ? non-falsy-string : int) $text
10+
*/
11+
function ctype_alpha(mixed $text): bool {}
12+
13+
/**
14+
* @phpstan-assert-if-true =($text is string ? non-falsy-string : int) $text
15+
*/
16+
function ctype_cntrl(mixed $text): bool {}
17+
18+
/**
19+
* @phpstan-assert-if-true =($text is string ? non-falsy-string : int) $text
20+
*/
21+
function ctype_lower(mixed $text): bool {}
22+
23+
/**
24+
* @phpstan-assert-if-true =($text is string ? non-empty-string : int) $text
25+
*/
26+
function ctype_graph(mixed $text): bool {}
27+
28+
/**
29+
* @phpstan-assert-if-true =($text is string ? non-empty-string : int) $text
30+
*/
31+
function ctype_print(mixed $text): bool {}
32+
33+
/**
34+
* @phpstan-assert-if-true =($text is string ? non-falsy-string : int) $text
35+
*/
36+
function ctype_punct(mixed $text): bool {}
37+
38+
/**
39+
* @phpstan-assert-if-true =($text is string ? non-falsy-string : int) $text
40+
*/
41+
function ctype_space(mixed $text): bool {}
42+
43+
/**
44+
* @phpstan-assert-if-true =($text is string ? non-falsy-string : int) $text
45+
*/
46+
function ctype_upper(mixed $text): bool {}
47+
48+
/**
49+
* @phpstan-assert-if-true =($text is string ? non-empty-string : int) $text
50+
*/
51+
function ctype_xdigit(mixed $text): bool {}
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Ctype;
6+
7+
use function ctype_alnum;
8+
use function ctype_alpha;
9+
use function ctype_cntrl;
10+
use function ctype_graph;
11+
use function ctype_lower;
12+
use function ctype_print;
13+
use function ctype_punct;
14+
use function ctype_space;
15+
use function ctype_upper;
16+
use function ctype_xdigit;
17+
use function PHPStan\Testing\assertType;
18+
19+
function test(string $str): void
20+
{
21+
// functions asserting non-falsy-string
22+
23+
if (ctype_alpha($str)) {
24+
assertType('non-falsy-string', $str);
25+
} else {
26+
assertType('string', $str);
27+
}
28+
29+
if (ctype_cntrl($str)) {
30+
assertType('non-falsy-string', $str);
31+
} else {
32+
assertType('string', $str);
33+
}
34+
35+
if (ctype_lower($str)) {
36+
assertType('non-falsy-string', $str);
37+
} else {
38+
assertType('string', $str);
39+
}
40+
41+
if (ctype_upper($str)) {
42+
assertType('non-falsy-string', $str);
43+
} else {
44+
assertType('string', $str);
45+
}
46+
47+
if (ctype_punct($str)) {
48+
assertType('non-falsy-string', $str);
49+
} else {
50+
assertType('string', $str);
51+
}
52+
53+
if (ctype_space($str)) {
54+
assertType('non-falsy-string', $str);
55+
} else {
56+
assertType('string', $str);
57+
}
58+
59+
// functions asserting non-empty-string
60+
// ctype_digit is tested in another file
61+
62+
if (ctype_alnum($str)) {
63+
assertType('non-empty-string', $str);
64+
} else {
65+
assertType('string', $str);
66+
}
67+
68+
if (ctype_graph($str)) {
69+
assertType('non-empty-string', $str);
70+
} else {
71+
assertType('string', $str);
72+
}
73+
74+
if (ctype_print($str)) {
75+
assertType('non-empty-string', $str);
76+
} else {
77+
assertType('string', $str);
78+
}
79+
80+
if (ctype_xdigit($str)) {
81+
assertType('non-empty-string', $str);
82+
} else {
83+
assertType('string', $str);
84+
}
85+
}
86+
87+
function testInt(int $int): void
88+
{
89+
if (ctype_alpha($int)) {
90+
assertType('int', $int);
91+
} else {
92+
assertType('int', $int);
93+
}
94+
95+
if (ctype_cntrl($int)) {
96+
assertType('int', $int);
97+
} else {
98+
assertType('int', $int);
99+
}
100+
101+
if (ctype_lower($int)) {
102+
assertType('int', $int);
103+
} else {
104+
assertType('int', $int);
105+
}
106+
107+
if (ctype_upper($int)) {
108+
assertType('int', $int);
109+
} else {
110+
assertType('int', $int);
111+
}
112+
113+
if (ctype_punct($int)) {
114+
assertType('int', $int);
115+
} else {
116+
assertType('int', $int);
117+
}
118+
119+
if (ctype_space($int)) {
120+
assertType('int', $int);
121+
} else {
122+
assertType('int', $int);
123+
}
124+
125+
// functions asserting non-empty-string
126+
// ctype_digit is tested in another file
127+
128+
if (ctype_alnum($int)) {
129+
assertType('int', $int);
130+
} else {
131+
assertType('int', $int);
132+
}
133+
134+
if (ctype_graph($int)) {
135+
assertType('int', $int);
136+
} else {
137+
assertType('int', $int);
138+
}
139+
140+
if (ctype_print($int)) {
141+
assertType('int', $int);
142+
} else {
143+
assertType('int', $int);
144+
}
145+
146+
if (ctype_xdigit($int)) {
147+
assertType('int', $int);
148+
} else {
149+
assertType('int', $int);
150+
}
151+
}

0 commit comments

Comments
 (0)