-
Notifications
You must be signed in to change notification settings - Fork 36
Commit
…tch()` based on pattern
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
<?php declare(strict_types = 1); | ||
|
||
namespace PHPStan\Type\Nette; | ||
|
||
use Nette\Utils\Strings; | ||
use PhpParser\Node\Expr\StaticCall; | ||
use PHPStan\Analyser\Scope; | ||
use PHPStan\Reflection\MethodReflection; | ||
use PHPStan\TrinaryLogic; | ||
use PHPStan\Type\DynamicStaticMethodReturnTypeExtension; | ||
use PHPStan\Type\NullType; | ||
use PHPStan\Type\Php\RegexArrayShapeMatcher; | ||
use PHPStan\Type\Type; | ||
use PHPStan\Type\TypeCombinator; | ||
|
||
class StringsMatchDynamicReturnTypeExtension implements DynamicStaticMethodReturnTypeExtension | ||
{ | ||
|
||
/** @var RegexArrayShapeMatcher */ | ||
private $regexArrayShapeMatcher; | ||
|
||
public function __construct(RegexArrayShapeMatcher $regexArrayShapeMatcher) | ||
{ | ||
$this->regexArrayShapeMatcher = $regexArrayShapeMatcher; | ||
} | ||
|
||
public function getClass(): string | ||
{ | ||
return Strings::class; | ||
} | ||
|
||
public function isStaticMethodSupported(MethodReflection $methodReflection): bool | ||
{ | ||
return $methodReflection->getName() === 'match'; | ||
} | ||
|
||
public function getTypeFromStaticMethodCall(MethodReflection $methodReflection, StaticCall $methodCall, Scope $scope): ?Type | ||
{ | ||
$args = $methodCall->getArgs(); | ||
$patternArg = $args[1] ?? null; | ||
if ($patternArg === null) { | ||
return null; | ||
} | ||
|
||
$patternType = $scope->getType($patternArg->value); | ||
$flagsArg = $args[2] ?? null; | ||
$flagsType = null; | ||
if ($flagsArg !== null) { | ||
$flagsType = $scope->getType($flagsArg->value); | ||
} | ||
|
||
$arrayShape = $this->regexArrayShapeMatcher->matchType($patternType, $flagsType, TrinaryLogic::createYes()); | ||
if ($arrayShape === null) { | ||
return null; | ||
} | ||
|
||
return TypeCombinator::union($arrayShape, new NullType()); | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
<?php declare(strict_types = 1); | ||
|
||
namespace PHPStan\Type\Nette; | ||
|
||
use PHPStan\Testing\TypeInferenceTestCase; | ||
|
||
class StringsMatchDynamicReturnTypeExtensionTest extends TypeInferenceTestCase | ||
{ | ||
|
||
/** | ||
* @return iterable<string, mixed[]> | ||
*/ | ||
public function dataFileAsserts(): iterable | ||
{ | ||
yield from $this->gatherAssertTypes(__DIR__ . '/data/strings-match.php'); | ||
Check failure on line 15 in tests/Type/Nette/StringsMatchDynamicReturnTypeExtensionTest.php GitHub Actions / PHPStan (7.2, lowest)
Check failure on line 15 in tests/Type/Nette/StringsMatchDynamicReturnTypeExtensionTest.php GitHub Actions / PHPStan (7.3, lowest)
Check failure on line 15 in tests/Type/Nette/StringsMatchDynamicReturnTypeExtensionTest.php GitHub Actions / PHPStan (7.4, lowest)
Check failure on line 15 in tests/Type/Nette/StringsMatchDynamicReturnTypeExtensionTest.php GitHub Actions / PHPStan (8.0, lowest)
Check failure on line 15 in tests/Type/Nette/StringsMatchDynamicReturnTypeExtensionTest.php GitHub Actions / PHPStan (8.1, lowest)
|
||
} | ||
|
||
/** | ||
* @dataProvider dataFileAsserts | ||
* @param mixed ...$args | ||
*/ | ||
public function testFileAsserts( | ||
string $assertType, | ||
string $file, | ||
...$args | ||
): void | ||
{ | ||
$this->assertFileAsserts($assertType, $file, ...$args); | ||
} | ||
|
||
public static function getAdditionalConfigFiles(): array | ||
{ | ||
return [ | ||
'phar://' . __DIR__ . '/../../../vendor/phpstan/phpstan/phpstan.phar/conf/bleedingEdge.neon', | ||
__DIR__ . '/phpstan.neon', | ||
]; | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
<?php | ||
|
||
namespace StringsMatch; | ||
|
||
use Nette\Utils\Strings; | ||
use function PHPStan\Testing\assertType; | ||
use const PREG_OFFSET_CAPTURE; | ||
|
||
function (string $s): void { | ||
$result = Strings::match($s, '/%env\((.*)\:.*\)%/U'); | ||
assertType('array{string, string}|null', $result); | ||
|
||
$result = Strings::match($s, '/%env\((.*)\:.*\)%/U'); | ||
assertType('array{string, string}|null', $result); | ||
|
||
$result = Strings::match($s, '/(foo)(bar)(baz)/', PREG_OFFSET_CAPTURE); | ||
assertType('array{array{string, int<0, max>}, array{string, int<0, max>}, array{string, int<0, max>}, array{string, int<0, max>}}|null', $result); | ||
|
||
$result = Strings::match($s, '/(foo)(bar)(baz)/'); | ||
assertType('array{string, string, string, string}|null', $result); | ||
}; |