Skip to content

Commit 3fad412

Browse files
staabmondrejmirtes
authored andcommitted
Extract RegexExpressionHelper
1 parent 65f9b8c commit 3fad412

File tree

3 files changed

+74
-51
lines changed

3 files changed

+74
-51
lines changed

conf/config.neon

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1491,6 +1491,9 @@ services:
14911491
-
14921492
class: PHPStan\Type\Php\RegexArrayShapeMatcher
14931493

1494+
-
1495+
class: PHPStan\Type\Php\RegexExpressionHelper
1496+
14941497
-
14951498
class: PHPStan\Type\Php\ReflectionClassConstructorThrowTypeExtension
14961499
tags:

src/Type/Php/RegexArrayShapeMatcher.php

Lines changed: 2 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,8 @@
1010
use Nette\Utils\RegexpException;
1111
use Nette\Utils\Strings;
1212
use PhpParser\Node\Expr;
13-
use PhpParser\Node\Name;
1413
use PHPStan\Analyser\Scope;
1514
use PHPStan\Php\PhpVersion;
16-
use PHPStan\Reflection\InitializerExprTypeResolver;
1715
use PHPStan\ShouldNotHappenException;
1816
use PHPStan\TrinaryLogic;
1917
use PHPStan\Type\Accessory\AccessoryNonEmptyStringType;
@@ -56,7 +54,7 @@ final class RegexArrayShapeMatcher
5654

5755
public function __construct(
5856
private PhpVersion $phpVersion,
59-
private InitializerExprTypeResolver $initializerExprTypeResolver,
57+
private RegexExpressionHelper $regexExpressionHelper,
6058
)
6159
{
6260
}
@@ -712,57 +710,10 @@ private function getLiteralValue(TreeNode $node): ?string
712710
private function getPatternType(Expr $patternExpr, Scope $scope): Type
713711
{
714712
if ($patternExpr instanceof Expr\BinaryOp\Concat) {
715-
return $this->resolvePatternConcat($patternExpr, $scope);
713+
return $this->regexExpressionHelper->resolvePatternConcat($patternExpr, $scope);
716714
}
717715

718716
return $scope->getType($patternExpr);
719717
}
720718

721-
/**
722-
* Ignores preg_quote() calls in the concatenation as these are not relevant for array-shape matching.
723-
*
724-
* This assumption only works for the ArrayShapeMatcher therefore it is not implemented for the common case in Scope.
725-
*
726-
* see https://github.com/phpstan/phpstan-src/pull/3233#discussion_r1676938085
727-
*/
728-
private function resolvePatternConcat(Expr\BinaryOp\Concat $concat, Scope $scope): Type
729-
{
730-
$resolver = new class($scope) {
731-
732-
public function __construct(private Scope $scope)
733-
{
734-
}
735-
736-
public function resolve(Expr $expr): Type
737-
{
738-
if (
739-
$expr instanceof Expr\FuncCall
740-
&& $expr->name instanceof Name
741-
&& $expr->name->toLowerString() === 'preg_quote'
742-
) {
743-
return new ConstantStringType('');
744-
}
745-
746-
if ($expr instanceof Expr\BinaryOp\Concat) {
747-
$left = $this->resolve($expr->left);
748-
$right = $this->resolve($expr->right);
749-
750-
$strings = [];
751-
foreach ($left->toString()->getConstantStrings() as $leftString) {
752-
foreach ($right->toString()->getConstantStrings() as $rightString) {
753-
$strings[] = new ConstantStringType($leftString->getValue() . $rightString->getValue());
754-
}
755-
}
756-
757-
return TypeCombinator::union(...$strings);
758-
}
759-
760-
return $this->scope->getType($expr);
761-
}
762-
763-
};
764-
765-
return $this->initializerExprTypeResolver->getConcatType($concat->left, $concat->right, static fn (Expr $expr): Type => $resolver->resolve($expr));
766-
}
767-
768719
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Type\Php;
4+
5+
use PhpParser\Node\Expr;
6+
use PhpParser\Node\Name;
7+
use PHPStan\Analyser\Scope;
8+
use PHPStan\Reflection\InitializerExprTypeResolver;
9+
use PHPStan\Type\Constant\ConstantStringType;
10+
use PHPStan\Type\Type;
11+
use PHPStan\Type\TypeCombinator;
12+
13+
final class RegexExpressionHelper
14+
{
15+
16+
public function __construct(
17+
private InitializerExprTypeResolver $initializerExprTypeResolver,
18+
)
19+
{
20+
}
21+
22+
/**
23+
* Ignores preg_quote() calls in the concatenation as these are not relevant for array-shape matching.
24+
*
25+
* This assumption only works for the ArrayShapeMatcher therefore it is not implemented for the common case in Scope.
26+
*
27+
* see https://github.com/phpstan/phpstan-src/pull/3233#discussion_r1676938085
28+
*/
29+
public function resolvePatternConcat(Expr\BinaryOp\Concat $concat, Scope $scope): Type
30+
{
31+
$resolver = new class($scope) {
32+
33+
public function __construct(private Scope $scope)
34+
{
35+
}
36+
37+
public function resolve(Expr $expr): Type
38+
{
39+
if (
40+
$expr instanceof Expr\FuncCall
41+
&& $expr->name instanceof Name
42+
&& $expr->name->toLowerString() === 'preg_quote'
43+
) {
44+
return new ConstantStringType('');
45+
}
46+
47+
if ($expr instanceof Expr\BinaryOp\Concat) {
48+
$left = $this->resolve($expr->left);
49+
$right = $this->resolve($expr->right);
50+
51+
$strings = [];
52+
foreach ($left->toString()->getConstantStrings() as $leftString) {
53+
foreach ($right->toString()->getConstantStrings() as $rightString) {
54+
$strings[] = new ConstantStringType($leftString->getValue() . $rightString->getValue());
55+
}
56+
}
57+
58+
return TypeCombinator::union(...$strings);
59+
}
60+
61+
return $this->scope->getType($expr);
62+
}
63+
64+
};
65+
66+
return $this->initializerExprTypeResolver->getConcatType($concat->left, $concat->right, static fn (Expr $expr): Type => $resolver->resolve($expr));
67+
}
68+
69+
}

0 commit comments

Comments
 (0)