Skip to content

Commit 5a0b989

Browse files
committed
feat improve for flag & non-empty-string
1 parent 48c714d commit 5a0b989

File tree

2 files changed

+74
-48
lines changed

2 files changed

+74
-48
lines changed

src/Type/Php/PregSplitDynamicReturnTypeExtension.php

Lines changed: 39 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use PHPStan\TrinaryLogic;
99
use PHPStan\Type\Accessory\AccessoryArrayListType;
1010
use PHPStan\Type\Accessory\AccessoryNonEmptyStringType;
11+
use PHPStan\Type\Accessory\NonEmptyArrayType;
1112
use PHPStan\Type\ArrayType;
1213
use PHPStan\Type\BitwiseFlagHelper;
1314
use PHPStan\Type\Constant\ConstantArrayType;
@@ -92,29 +93,49 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection,
9293
$stringType = new StringType();
9394
}
9495

95-
if ($flagArg !== null && $this->bitwiseFlagAnalyser->bitwiseOrContainsConstant($flagArg->value, $scope, 'PREG_SPLIT_OFFSET_CAPTURE')->yes()) {
96-
$type = new ArrayType(
97-
new IntegerType(),
98-
new ConstantArrayType([new ConstantIntegerType(0), new ConstantIntegerType(1)], [$stringType, IntegerRangeType::fromInterval(0, null)], [2], [], TrinaryLogic::createYes()),
99-
);
100-
return TypeUtils::toBenevolentUnion(
101-
TypeCombinator::union(
102-
TypeCombinator::intersect($type, new AccessoryArrayListType()),
103-
new ConstantBooleanType(false)
104-
)
105-
);
96+
$capturedArrayType = new ConstantArrayType(
97+
[
98+
new ConstantIntegerType(0),
99+
new ConstantIntegerType(1)], [$stringType, IntegerRangeType::fromInterval(0, null)
100+
],
101+
[2],
102+
[],
103+
TrinaryLogic::createYes()
104+
);
105+
$valueType = $stringType;
106+
if ($flagArg !== null) {
107+
$flagState = $this->bitwiseFlagAnalyser->bitwiseOrContainsConstant($flagArg->value, $scope, 'PREG_SPLIT_OFFSET_CAPTURE');
108+
if ($flagState->yes()) {
109+
return TypeUtils::toBenevolentUnion(
110+
TypeCombinator::union(
111+
TypeCombinator::intersect(
112+
new ArrayType(new IntegerType(), $capturedArrayType),
113+
new AccessoryArrayListType()
114+
),
115+
new ConstantBooleanType(false)
116+
)
117+
);
118+
}
119+
if ($flagState->maybe()) {
120+
$valueType = TypeCombinator::union(new StringType(), $capturedArrayType);
121+
}
106122
}
107123

108-
if ($flagArg !== null && $this->bitwiseFlagAnalyser->bitwiseOrContainsConstant($flagArg->value, $scope, 'PREG_SPLIT_NO_EMPTY')->yes()) {
109-
return TypeUtils::toBenevolentUnion(
110-
TypeCombinator::union(
111-
TypeCombinator::intersect(new ArrayType(new MixedType(), $stringType), new AccessoryArrayListType()),
112-
new ConstantBooleanType(false)
113-
)
124+
$arrayType = TypeCombinator::intersect(new ArrayType(new MixedType(), $valueType), new AccessoryArrayListType());
125+
if ($subjectType->isNonEmptyString()->yes()) {
126+
$arrayType = TypeCombinator::intersect(
127+
$arrayType,
128+
new NonEmptyArrayType(),
129+
new AccessoryArrayListType(),
114130
);
115131
}
116132

117-
return null;
133+
return TypeUtils::toBenevolentUnion(
134+
TypeCombinator::union(
135+
$arrayType,
136+
new ConstantBooleanType(false)
137+
)
138+
);
118139
}
119140

120141
$resultTypes = [];

tests/PHPStan/Analyser/nsrt/preg_split.php

Lines changed: 35 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,41 @@
66

77
class HelloWorld
88
{
9+
public function doFoo()
10+
{
11+
assertType('*ERROR*', preg_split('/[0-9a]', '1-2-3'));
12+
assertType("array{''}", preg_split('/-/', ''));
13+
assertType("array{}", preg_split('/-/', '', -1, PREG_SPLIT_NO_EMPTY));
14+
assertType("array{array{'', 0}}", preg_split('/-/', '', -1, PREG_SPLIT_OFFSET_CAPTURE));
15+
assertType("array{}", preg_split('/-/', '', -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_OFFSET_CAPTURE));
16+
assertType("array{'1', '2', '3'}", preg_split('/-/', '1-2-3'));
17+
assertType("array{'1', '2', '3'}", preg_split('/-/', '1-2-3', -1, PREG_SPLIT_NO_EMPTY));
18+
assertType("array{'1', '3'}", preg_split('/-/', '1--3', -1, PREG_SPLIT_NO_EMPTY));
19+
assertType("array{array{'1', 0}, array{'2', 2}, array{'3', 4}}", preg_split('/-/', '1-2-3', -1, PREG_SPLIT_OFFSET_CAPTURE));
20+
assertType("array{array{'1', 0}, array{'2', 2}, array{'3', 4}}", preg_split('/-/', '1-2-3', -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_OFFSET_CAPTURE));
21+
assertType("array{array{'1', 0}, array{'', 2}, array{'3', 3}}", preg_split('/-/', '1--3', -1, PREG_SPLIT_OFFSET_CAPTURE));
22+
assertType("array{array{'1', 0}, array{'3', 3}}", preg_split('/-/', '1--3', -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_OFFSET_CAPTURE));
23+
}
24+
25+
/**
26+
* @param non-empty-string $nonEmptySubject
27+
*/
28+
public function doWithVariables(string $pattern, string $subject, string $nonEmptySubject, int $offset, int $flags): void
29+
{
30+
assertType('(list<array{string, int<0, max>}|string>|false)', preg_split($pattern, $subject, $offset, $flags));
31+
assertType('(list<array{string, int<0, max>}|string>|false)', preg_split("//", $subject, $offset, $flags));
32+
33+
assertType('(non-empty-list<array{string, int<0, max>}|string>|false)', preg_split($pattern, $nonEmptySubject, $offset, $flags));
34+
assertType('(non-empty-list<array{string, int<0, max>}|string>|false)', preg_split("//", $nonEmptySubject, $offset, $flags));
35+
36+
assertType('(non-empty-list<string>|false)', preg_split("//", $nonEmptySubject));
37+
38+
assertType('(non-empty-list<array{string, int<0, max>}|string>|false)', preg_split($pattern, "1-2-3", $offset, $flags));
39+
assertType('(list<array{string, int<0, max>}|string>|false)', preg_split($pattern, $subject, -1, $flags));
40+
assertType('(list<non-empty-string>|false)', preg_split($pattern, $subject, $offset, PREG_SPLIT_NO_EMPTY));
41+
assertType('(list<array{string, int<0, max>}>|false)', preg_split($pattern, $subject, $offset, PREG_SPLIT_OFFSET_CAPTURE));
42+
}
43+
944
/**
1045
* @param string $pattern
1146
* @param string $subject
@@ -36,34 +71,4 @@ public static function dynamicFlags($pattern, $subject, $limit = -1)
3671

3772
assertType('(list<array{string, int<0, max>}>|false)', preg_split($pattern, $subject, $limit, $flags));
3873
}
39-
40-
public function doFoo()
41-
{
42-
assertType('*ERROR*', preg_split('/[0-9a]', '1-2-3'));
43-
assertType("array{''}", preg_split('/-/', ''));
44-
assertType("array{'1', '2', '3'}", preg_split('/-/', '1-2-3'));
45-
assertType("array{'1', '2', '3'}", preg_split('/-/', '1-2-3', -1, PREG_SPLIT_NO_EMPTY));
46-
assertType("array{'1', '3'}", preg_split('/-/', '1--3', -1, PREG_SPLIT_NO_EMPTY));
47-
assertType("array{array{'1', 0}, array{'2', 2}, array{'3', 4}}", preg_split('/-/', '1-2-3', -1, PREG_SPLIT_OFFSET_CAPTURE));
48-
assertType("array{array{'1', 0}, array{'2', 2}, array{'3', 4}}", preg_split('/-/', '1-2-3', -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_OFFSET_CAPTURE));
49-
assertType("array{array{'1', 0}, array{'', 2}, array{'3', 3}}", preg_split('/-/', '1--3', -1, PREG_SPLIT_OFFSET_CAPTURE));
50-
assertType("array{array{'1', 0}, array{'3', 3}}", preg_split('/-/', '1--3', -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_OFFSET_CAPTURE));
51-
}
52-
53-
/**
54-
* @param non-empty-string $nonEmptySubject
55-
*/
56-
public function doWithVariables(string $pattern, string $subject, string $nonEmptySubject, int $offset, int $flags): void
57-
{
58-
assertType('(list<array{string, int<0, max>}|string>|false)', preg_split($pattern, $subject, $offset, $flags));
59-
assertType('(list<array{string, int<0, max>}|string>|false)', preg_split("//", $subject, $offset, $flags));
60-
61-
assertType('(list<array{string, int<0, max>}|string>|false)', preg_split($pattern, $nonEmptySubject, $offset, $flags));
62-
assertType('(list<array{string, int<0, max>}|string>|false)', preg_split("//", $nonEmptySubject, $offset, $flags));
63-
64-
assertType('(list<array{string, int<0, max>}|string>|false)', preg_split($pattern, "1-2-3", $offset, $flags));
65-
assertType('(list<array{string, int<0, max>}|string>|false)', preg_split($pattern, $subject, -1, $flags));
66-
assertType('(list<non-empty-string>|false)', preg_split($pattern, $subject, $offset, PREG_SPLIT_NO_EMPTY));
67-
assertType('(list<array{string, int<0, max>}>|false)', preg_split($pattern, $subject, $offset, PREG_SPLIT_OFFSET_CAPTURE));
68-
}
6974
}

0 commit comments

Comments
 (0)