Edit File: PregReplaceCallbackClosureTypeExtension.php
<?php declare(strict_types=1); namespace Composer\Pcre\PHPStan; use Composer\Pcre\Preg; use Composer\Pcre\Regex; use PhpParser\Node\Expr\StaticCall; use PHPStan\Analyser\Scope; use PHPStan\Reflection\MethodReflection; use PHPStan\Reflection\Native\NativeParameterReflection; use PHPStan\Reflection\ParameterReflection; use PHPStan\TrinaryLogic; use PHPStan\Type\ClosureType; use PHPStan\Type\Constant\ConstantArrayType; use PHPStan\Type\Php\RegexArrayShapeMatcher; use PHPStan\Type\StaticMethodParameterClosureTypeExtension; use PHPStan\Type\StringType; use PHPStan\Type\TypeCombinator; use PHPStan\Type\Type; final class PregReplaceCallbackClosureTypeExtension implements StaticMethodParameterClosureTypeExtension { /** * @var RegexArrayShapeMatcher */ private $regexShapeMatcher; public function __construct(RegexArrayShapeMatcher $regexShapeMatcher) { $this->regexShapeMatcher = $regexShapeMatcher; } public function isStaticMethodSupported(MethodReflection $methodReflection, ParameterReflection $parameter): bool { return in_array($methodReflection->getDeclaringClass()->getName(), [Preg::class, Regex::class], true) && in_array($methodReflection->getName(), ['replaceCallback', 'replaceCallbackStrictGroups'], true) && $parameter->getName() === 'replacement'; } public function getTypeFromStaticMethodCall(MethodReflection $methodReflection, StaticCall $methodCall, ParameterReflection $parameter, Scope $scope): ?Type { $args = $methodCall->getArgs(); $patternArg = $args[0] ?? null; $flagsArg = $args[5] ?? null; if ( $patternArg === null ) { return null; } $flagsType = PregMatchFlags::getType($flagsArg, $scope); $matchesType = $this->regexShapeMatcher->matchExpr($patternArg->value, $flagsType, TrinaryLogic::createYes(), $scope); if ($matchesType === null) { return null; } if ($methodReflection->getName() === 'replaceCallbackStrictGroups' && count($matchesType->getConstantArrays()) === 1) { $matchesType = $matchesType->getConstantArrays()[0]; $matchesType = new ConstantArrayType( $matchesType->getKeyTypes(), array_map(static function (Type $valueType): Type { if (count($valueType->getConstantArrays()) === 1) { $valueTypeArray = $valueType->getConstantArrays()[0]; return new ConstantArrayType( $valueTypeArray->getKeyTypes(), array_map(static function (Type $valueType): Type { return TypeCombinator::removeNull($valueType); }, $valueTypeArray->getValueTypes()), $valueTypeArray->getNextAutoIndexes(), [], $valueTypeArray->isList() ); } return TypeCombinator::removeNull($valueType); }, $matchesType->getValueTypes()), $matchesType->getNextAutoIndexes(), [], $matchesType->isList() ); } return new ClosureType( [ new NativeParameterReflection($parameter->getName(), $parameter->isOptional(), $matchesType, $parameter->passedByReference(), $parameter->isVariadic(), $parameter->getDefaultValue()), ], new StringType() ); } }
Back to File Manager