Skip to content

Commit d814855

Browse files
Introduce StrrevFunctionReturnTypeExtension
1 parent a2c0946 commit d814855

File tree

3 files changed

+123
-0
lines changed

3 files changed

+123
-0
lines changed

Diff for: conf/config.neon

+5
Original file line numberDiff line numberDiff line change
@@ -1774,6 +1774,11 @@ services:
17741774
tags:
17751775
- phpstan.broker.dynamicFunctionReturnTypeExtension
17761776

1777+
-
1778+
class: PHPStan\Type\Php\StrrevFunctionReturnTypeExtension
1779+
tags:
1780+
- phpstan.broker.dynamicFunctionReturnTypeExtension
1781+
17771782
-
17781783
class: PHPStan\Type\Php\SubstrDynamicReturnTypeExtension
17791784
tags:

Diff for: src/Type/Php/StrrevFunctionReturnTypeExtension.php

+81
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Type\Php;
4+
5+
use Nette\Utils\Strings;
6+
use PhpParser\Node\Expr\FuncCall;
7+
use PHPStan\Analyser\Scope;
8+
use PHPStan\Reflection\FunctionReflection;
9+
use PHPStan\Type\Accessory\AccessoryLiteralStringType;
10+
use PHPStan\Type\Accessory\AccessoryLowercaseStringType;
11+
use PHPStan\Type\Accessory\AccessoryNonEmptyStringType;
12+
use PHPStan\Type\Accessory\AccessoryNonFalsyStringType;
13+
use PHPStan\Type\Accessory\AccessoryNumericStringType;
14+
use PHPStan\Type\Accessory\AccessoryUppercaseStringType;
15+
use PHPStan\Type\Constant\ConstantIntegerType;
16+
use PHPStan\Type\Constant\ConstantStringType;
17+
use PHPStan\Type\DynamicFunctionReturnTypeExtension;
18+
use PHPStan\Type\IntegerRangeType;
19+
use PHPStan\Type\IntersectionType;
20+
use PHPStan\Type\NeverType;
21+
use PHPStan\Type\StringType;
22+
use PHPStan\Type\Type;
23+
use PHPStan\Type\TypeCombinator;
24+
25+
use function count;
26+
use function str_repeat;
27+
use function strlen;
28+
29+
final class StrrevFunctionReturnTypeExtension implements DynamicFunctionReturnTypeExtension
30+
{
31+
32+
public function isFunctionSupported(FunctionReflection $functionReflection): bool
33+
{
34+
return $functionReflection->getName() === 'strrev';
35+
}
36+
37+
public function getTypeFromFunctionCall(
38+
FunctionReflection $functionReflection,
39+
FuncCall $functionCall,
40+
Scope $scope,
41+
): ?Type
42+
{
43+
$args = $functionCall->getArgs();
44+
if (count($args) < 1) {
45+
return new StringType();
46+
}
47+
48+
$inputType = $scope->getType($args[0]->value);
49+
$constantStrings = $inputType->getConstantStrings();
50+
if (count($constantStrings) > 0) {
51+
$resultTypes = [];
52+
foreach ($constantStrings as $constantString) {
53+
$resultTypes[] = new ConstantStringType(strrev($constantString->getValue()));
54+
}
55+
56+
return TypeCombinator::union(...$resultTypes);
57+
}
58+
59+
$accessoryTypes = [];
60+
if ($inputType->isNonFalsyString()->yes()) {
61+
$accessoryTypes[] = new AccessoryNonFalsyStringType();
62+
} elseif ($inputType->isNonEmptyString()->yes()) {
63+
$accessoryTypes[] = new AccessoryNonEmptyStringType();
64+
}
65+
if ($inputType->isLowercaseString()->yes()) {
66+
$accessoryTypes[] = new AccessoryLowercaseStringType();
67+
}
68+
if ($inputType->isUppercaseString()->yes()) {
69+
$accessoryTypes[] = new AccessoryUppercaseStringType();
70+
}
71+
72+
if (count($accessoryTypes) > 0) {
73+
$accessoryTypes[] = new StringType();
74+
75+
return new IntersectionType($accessoryTypes);
76+
}
77+
78+
return new StringType();
79+
}
80+
81+
}

Diff for: tests/PHPStan/Analyser/nsrt/strrev.php

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
3+
namespace Strrev;
4+
5+
use function PHPStan\Testing\assertType;
6+
7+
class Foo
8+
{
9+
/**
10+
* @param string $string
11+
* @param non-empty-string $nonEmptyString
12+
* @param non-falsy-string $nonFalsyString
13+
* @param numeric-string $numericString
14+
* @param lowercase-string $lowercaseString
15+
* @param uppercase-string $uppercaseString
16+
* @param 'foo'|'bar' $constantStrings
17+
*
18+
* @return void
19+
*/
20+
public function test(
21+
string $string,
22+
string $nonEmptyString,
23+
string $nonFalsyString,
24+
string $numericString,
25+
string $lowercaseString,
26+
string $uppercaseString,
27+
string $constantStrings,
28+
) {
29+
assertType('string', strrev($string));
30+
assertType('non-empty-string', strrev($nonEmptyString));
31+
assertType('non-falsy-string', strrev($nonFalsyString));
32+
assertType('non-empty-string', strrev($numericString));
33+
assertType('lowercase-string', strrev($lowercaseString));
34+
assertType('uppercase-string', strrev($uppercaseString));
35+
assertType("'oof'|'rab'", strrev($constantStrings));
36+
}
37+
}

0 commit comments

Comments
 (0)