Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 2e88651

Browse files
committed
Refactor code into StrlenTypeSpecifyingExtension
1 parent d916b3f commit 2e88651

File tree

4 files changed

+75
-29
lines changed

4 files changed

+75
-29
lines changed

‎conf/config.neon‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1721,6 +1721,11 @@ services:
17211721
tags:
17221722
- phpstan.broker.dynamicFunctionReturnTypeExtension
17231723

1724+
-
1725+
class: PHPStan\Type\Php\StrlenTypeSpecifyingExtension
1726+
tags:
1727+
- phpstan.typeSpecifier.functionTypeSpecifyingExtension
1728+
17241729
-
17251730
class: PHPStan\Type\Php\StrlenFunctionReturnTypeExtension
17261731
tags:

‎src/Analyser/TypeSpecifier.php‎

Lines changed: 1 addition & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -331,31 +331,6 @@ public function specifyTypesInCondition(
331331
}
332332
}
333333

334-
if (
335-
!$context->null()
336-
&& $expr->right instanceof FuncCall
337-
&& count($expr->right->getArgs()) === 1
338-
&& $expr->right->name instanceof Name
339-
&& in_array(strtolower((string) $expr->right->name), ['strlen', 'mb_strlen'], true)
340-
&& $leftType->isInteger()->yes()
341-
) {
342-
if (
343-
$context->true() && (IntegerRangeType::createAllGreaterThanOrEqualTo(1 - $offset)->isSuperTypeOf($leftType)->yes())
344-
|| ($context->false() && (new ConstantIntegerType(1 - $offset))->isSuperTypeOf($leftType)->yes())
345-
) {
346-
$argType = $scope->getType($expr->right->getArgs()[0]->value);
347-
if ($argType->isString()->yes()) {
348-
$accessory = new AccessoryNonEmptyStringType();
349-
350-
if (IntegerRangeType::createAllGreaterThanOrEqualTo(2 - $offset)->isSuperTypeOf($leftType)->yes()) {
351-
$accessory = new AccessoryNonFalsyStringType();
352-
}
353-
354-
$result = $result->unionWith($this->create($expr->right->getArgs()[0]->value, $accessory, $context, $scope)->setRootExpr($expr));
355-
}
356-
}
357-
}
358-
359334
if ($leftType instanceof ConstantIntegerType) {
360335
if ($expr->right instanceof Expr\PostInc) {
361336
$result = $result->unionWith($this->createRangeTypes(
@@ -453,10 +428,9 @@ public function specifyTypesInCondition(
453428

454429
if (
455430
!$context->null()
456-
&& $expr->left instanceof Node\Scalar
457431
&& $expr->right instanceof Expr\FuncCall
458432
&& $expr->right->name instanceof Name
459-
&& in_array(strtolower((string) $expr->right->name), ['preg_match'], true)
433+
&& in_array(strtolower((string) $expr->right->name), ['preg_match', 'strlen', 'mb_strlen'], true)
460434
) {
461435
if (!$scope instanceof MutatingScope) {
462436
throw new ShouldNotHappenException();
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Type\Php;
4+
5+
use PhpParser\Node\Expr\FuncCall;
6+
use PHPStan\Analyser\Scope;
7+
use PHPStan\Analyser\SpecifiedTypes;
8+
use PHPStan\Analyser\TypeSpecifier;
9+
use PHPStan\Analyser\TypeSpecifierAwareExtension;
10+
use PHPStan\Analyser\TypeSpecifierContext;
11+
use PHPStan\Reflection\FunctionReflection;
12+
use PHPStan\Type\Accessory\AccessoryNonEmptyStringType;
13+
use PHPStan\Type\Accessory\AccessoryNonFalsyStringType;
14+
use PHPStan\Type\Constant\ConstantIntegerType;
15+
use PHPStan\Type\FunctionTypeSpecifyingExtension;
16+
use PHPStan\Type\IntegerRangeType;
17+
use function count;
18+
use function in_array;
19+
use function strtolower;
20+
21+
final class StrlenTypeSpecifyingExtension implements FunctionTypeSpecifyingExtension, TypeSpecifierAwareExtension
22+
{
23+
24+
private TypeSpecifier $typeSpecifier;
25+
26+
public function setTypeSpecifier(TypeSpecifier $typeSpecifier): void
27+
{
28+
$this->typeSpecifier = $typeSpecifier;
29+
}
30+
31+
public function isFunctionSupported(FunctionReflection $functionReflection, FuncCall $node, TypeSpecifierContext $context): bool
32+
{
33+
return in_array(strtolower($functionReflection->getName()), ['strlen', 'mb_strlen'], true) && !$context->null();
34+
}
35+
36+
public function specifyTypes(FunctionReflection $functionReflection, FuncCall $node, Scope $scope, TypeSpecifierContext $context): SpecifiedTypes
37+
{
38+
$args = $node->getArgs();
39+
if (
40+
count($args) < 1
41+
|| $context->getReturnType() === null
42+
) {
43+
return new SpecifiedTypes();
44+
}
45+
46+
$argType = $scope->getType($args[0]->value);
47+
if (!$argType->isString()->yes()) {
48+
return new SpecifiedTypes();
49+
}
50+
51+
$returnType = $context->getReturnType();
52+
if (
53+
$context->true() && IntegerRangeType::createAllGreaterThanOrEqualTo(1)->isSuperTypeOf($returnType)->yes()
54+
|| ($context->false() && (new ConstantIntegerType(0))->isSuperTypeOf($returnType)->yes())
55+
) {
56+
$accessory = new AccessoryNonEmptyStringType();
57+
if (IntegerRangeType::createAllGreaterThanOrEqualTo(2)->isSuperTypeOf($returnType)->yes()) {
58+
$accessory = new AccessoryNonFalsyStringType();
59+
}
60+
61+
return $this->typeSpecifier->create($args[0]->value, $accessory, $context, $scope)->setRootExpr($node);
62+
}
63+
64+
return new SpecifiedTypes();
65+
}
66+
67+
}

‎tests/PHPStan/Analyser/nsrt/narrow-cast.php‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77
/** @param array<mixed> $arr */
88
function doFoo(string $x, array $arr): void {
99
if ((bool) strlen($x)) {
10-
assertType('string', $x);// could be non-empty-string
10+
assertType('non-empty-string', $x);
1111
} else {
12-
assertType('string', $x);
12+
assertType("''", $x);
1313
}
1414
assertType('string', $x);
1515

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /