diff --git a/packages/PHPStanStaticTypeMapper/PHPStanStaticTypeMapper.php b/packages/PHPStanStaticTypeMapper/PHPStanStaticTypeMapper.php index 980dd30ed63..ff627e0475a 100644 --- a/packages/PHPStanStaticTypeMapper/PHPStanStaticTypeMapper.php +++ b/packages/PHPStanStaticTypeMapper/PHPStanStaticTypeMapper.php @@ -7,8 +7,6 @@ use PhpParser\Node\ComplexType; use PhpParser\Node\Name; use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode; use PHPStan\PhpDocParser\Ast\Type\TypeNode; -use PHPStan\Type\Accessory\AccessoryLiteralStringType; -use PHPStan\Type\Accessory\AccessoryNumericStringType; use PHPStan\Type\Accessory\HasMethodType; use PHPStan\Type\ConditionalType; use PHPStan\Type\Type; diff --git a/rules/Php55/RegexMatcher.php b/rules/Php55/RegexMatcher.php index 77949328814..74f5439b348 100644 --- a/rules/Php55/RegexMatcher.php +++ b/rules/Php55/RegexMatcher.php @@ -20,6 +20,11 @@ final class RegexMatcher * @see https://regex101.com/r/2NWVwT/1 */ private const LETTER_SUFFIX_REGEX = '#(?\\w+)$#'; + /** + * @var string[] + * @see https://www.php.net/manual/en/reference.pcre.pattern.modifiers.php + */ + private const ALL_MODIFIERS_VALUES = ['i', 'm', 's', 'x', 'e', 'A', 'D', 'S', 'U', 'X', 'J', 'u']; /** * @readonly * @var \Rector\Core\PhpParser\Node\Value\ValueResolver @@ -40,12 +45,26 @@ final class RegexMatcher return null; } $delimiter = $pattern[0]; - /** @var string $modifiers */ - $modifiers = Strings::after($pattern, $delimiter, -1); - if (\strpos($modifiers, 'e') === \false) { - return null; + switch ($delimiter) { + case '(': + $delimiter = ')'; + break; + case '{': + $delimiter = '}'; + break; + case '[': + $delimiter = ']'; + break; + case '<': + $delimiter = '>'; + break; + default: + $delimiter = $delimiter; + break; } - if (\in_array($pattern[\strlen($pattern) - 1], [')', '}', ']', '>'], \true)) { + /** @var string $modifiers */ + $modifiers = $this->resolveModifiers((string) Strings::after($pattern, $delimiter, -1)); + if (\strpos($modifiers, 'e') === \false) { return null; } $patternWithoutE = $this->createPatternWithoutE($pattern, $delimiter, $modifiers); @@ -56,6 +75,18 @@ final class RegexMatcher } return null; } + private function resolveModifiers(string $modifiersCandidate) : string + { + $modifiers = ''; + for ($modifierIndex = 0; $modifierIndex < \strlen($modifiersCandidate); ++$modifierIndex) { + if (!\in_array($modifiersCandidate[$modifierIndex], self::ALL_MODIFIERS_VALUES, \true)) { + $modifiers = ''; + continue; + } + $modifiers .= $modifiersCandidate[$modifierIndex]; + } + return $modifiers; + } private function createPatternWithoutE(string $pattern, string $delimiter, string $modifiers) : string { $modifiersWithoutE = Strings::replace($modifiers, '#e#', ''); diff --git a/src/Application/VersionResolver.php b/src/Application/VersionResolver.php index f8a6ad91c70..ca71a43e67c 100644 --- a/src/Application/VersionResolver.php +++ b/src/Application/VersionResolver.php @@ -17,12 +17,12 @@ final class VersionResolver * @api * @var string */ - public const PACKAGE_VERSION = '139c19cbdf666ce3df7dea712faaf84772f19051'; + public const PACKAGE_VERSION = '16647397cc155594371858f316bd82e9dd436117'; /** * @api * @var string */ - public const RELEASE_DATE = '2022-12-03 06:56:33'; + public const RELEASE_DATE = '2022-12-03 10:18:24'; /** * @var int */ diff --git a/src/PhpParser/Parser/InlineCodeParser.php b/src/PhpParser/Parser/InlineCodeParser.php index 2ec641baf20..3cc6742752c 100644 --- a/src/PhpParser/Parser/InlineCodeParser.php +++ b/src/PhpParser/Parser/InlineCodeParser.php @@ -11,6 +11,7 @@ use PhpParser\Node\Scalar\Encapsed; use PhpParser\Node\Scalar\String_; use PhpParser\Node\Stmt; use Rector\Core\Contract\PhpParser\NodePrinterInterface; +use Rector\Core\PhpParser\Node\Value\ValueResolver; use Rector\Core\Util\StringUtils; use Rector\NodeTypeResolver\NodeScopeAndMetadataDecorator; final class InlineCodeParser @@ -60,11 +61,17 @@ final class InlineCodeParser * @var \Rector\Core\PhpParser\Parser\SimplePhpParser */ private $simplePhpParser; - public function __construct(NodePrinterInterface $nodePrinter, NodeScopeAndMetadataDecorator $nodeScopeAndMetadataDecorator, \Rector\Core\PhpParser\Parser\SimplePhpParser $simplePhpParser) + /** + * @readonly + * @var \Rector\Core\PhpParser\Node\Value\ValueResolver + */ + private $valueResolver; + public function __construct(NodePrinterInterface $nodePrinter, NodeScopeAndMetadataDecorator $nodeScopeAndMetadataDecorator, \Rector\Core\PhpParser\Parser\SimplePhpParser $simplePhpParser, ValueResolver $valueResolver) { $this->nodePrinter = $nodePrinter; $this->nodeScopeAndMetadataDecorator = $nodeScopeAndMetadataDecorator; $this->simplePhpParser = $simplePhpParser; + $this->valueResolver = $valueResolver; } /** * @return Stmt[] @@ -93,11 +100,18 @@ final class InlineCodeParser } if ($expr instanceof Encapsed) { // remove " - $expr = \trim($this->nodePrinter->print($expr), '""'); + $printedExpr = \trim($this->nodePrinter->print($expr), '""'); + /** + * Encapsed "$eval_links" is printed as {$eval_links} → use its value when possible + */ + if (\strncmp($printedExpr, '{', \strlen('{')) === 0 && \substr_compare($printedExpr, '}', -\strlen('}')) === 0 && \count($expr->parts) === 1) { + $currentPart = \current($expr->parts); + $printedExpr = (string) $this->valueResolver->getValue($currentPart); + } // use \$ → $ - $expr = Strings::replace($expr, self::PRESLASHED_DOLLAR_REGEX, '$'); + $printedExpr = Strings::replace($printedExpr, self::PRESLASHED_DOLLAR_REGEX, '$'); // use \'{$...}\' → $... - return Strings::replace($expr, self::CURLY_BRACKET_WRAPPER_REGEX, '$1'); + return Strings::replace($printedExpr, self::CURLY_BRACKET_WRAPPER_REGEX, '$1'); } if ($expr instanceof Concat) { $string = $this->stringify($expr->left) . $this->stringify($expr->right); diff --git a/vendor/autoload.php b/vendor/autoload.php index 9b8dd12b12a..bcd463d5aee 100644 --- a/vendor/autoload.php +++ b/vendor/autoload.php @@ -22,4 +22,4 @@ if (PHP_VERSION_ID < 50600) { require_once __DIR__ . '/composer/autoload_real.php'; -return ComposerAutoloaderInit11fda1c87505eda717f408f0caeff073::getLoader(); +return ComposerAutoloaderInitfb3cd2e4ffdaf03a65f03a570a71d9ba::getLoader(); diff --git a/vendor/composer/autoload_real.php b/vendor/composer/autoload_real.php index 3a76fca1385..95896cfe776 100644 --- a/vendor/composer/autoload_real.php +++ b/vendor/composer/autoload_real.php @@ -2,7 +2,7 @@ // autoload_real.php @generated by Composer -class ComposerAutoloaderInit11fda1c87505eda717f408f0caeff073 +class ComposerAutoloaderInitfb3cd2e4ffdaf03a65f03a570a71d9ba { private static $loader; @@ -22,19 +22,19 @@ class ComposerAutoloaderInit11fda1c87505eda717f408f0caeff073 return self::$loader; } - spl_autoload_register(array('ComposerAutoloaderInit11fda1c87505eda717f408f0caeff073', 'loadClassLoader'), true, true); + spl_autoload_register(array('ComposerAutoloaderInitfb3cd2e4ffdaf03a65f03a570a71d9ba', 'loadClassLoader'), true, true); self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__)); - spl_autoload_unregister(array('ComposerAutoloaderInit11fda1c87505eda717f408f0caeff073', 'loadClassLoader')); + spl_autoload_unregister(array('ComposerAutoloaderInitfb3cd2e4ffdaf03a65f03a570a71d9ba', 'loadClassLoader')); require __DIR__ . '/autoload_static.php'; - call_user_func(\Composer\Autoload\ComposerStaticInit11fda1c87505eda717f408f0caeff073::getInitializer($loader)); + call_user_func(\Composer\Autoload\ComposerStaticInitfb3cd2e4ffdaf03a65f03a570a71d9ba::getInitializer($loader)); $loader->setClassMapAuthoritative(true); $loader->register(true); - $includeFiles = \Composer\Autoload\ComposerStaticInit11fda1c87505eda717f408f0caeff073::$files; + $includeFiles = \Composer\Autoload\ComposerStaticInitfb3cd2e4ffdaf03a65f03a570a71d9ba::$files; foreach ($includeFiles as $fileIdentifier => $file) { - composerRequire11fda1c87505eda717f408f0caeff073($fileIdentifier, $file); + composerRequirefb3cd2e4ffdaf03a65f03a570a71d9ba($fileIdentifier, $file); } return $loader; @@ -46,7 +46,7 @@ class ComposerAutoloaderInit11fda1c87505eda717f408f0caeff073 * @param string $file * @return void */ -function composerRequire11fda1c87505eda717f408f0caeff073($fileIdentifier, $file) +function composerRequirefb3cd2e4ffdaf03a65f03a570a71d9ba($fileIdentifier, $file) { if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php index 99f71414c03..f1628cc5f68 100644 --- a/vendor/composer/autoload_static.php +++ b/vendor/composer/autoload_static.php @@ -4,7 +4,7 @@ namespace Composer\Autoload; -class ComposerStaticInit11fda1c87505eda717f408f0caeff073 +class ComposerStaticInitfb3cd2e4ffdaf03a65f03a570a71d9ba { public static $files = array ( 'ad155f8f1cf0d418fe49e248db8c661b' => __DIR__ . '/..' . '/react/promise/src/functions_include.php', @@ -3023,9 +3023,9 @@ class ComposerStaticInit11fda1c87505eda717f408f0caeff073 public static function getInitializer(ClassLoader $loader) { return \Closure::bind(function () use ($loader) { - $loader->prefixLengthsPsr4 = ComposerStaticInit11fda1c87505eda717f408f0caeff073::$prefixLengthsPsr4; - $loader->prefixDirsPsr4 = ComposerStaticInit11fda1c87505eda717f408f0caeff073::$prefixDirsPsr4; - $loader->classMap = ComposerStaticInit11fda1c87505eda717f408f0caeff073::$classMap; + $loader->prefixLengthsPsr4 = ComposerStaticInitfb3cd2e4ffdaf03a65f03a570a71d9ba::$prefixLengthsPsr4; + $loader->prefixDirsPsr4 = ComposerStaticInitfb3cd2e4ffdaf03a65f03a570a71d9ba::$prefixDirsPsr4; + $loader->classMap = ComposerStaticInitfb3cd2e4ffdaf03a65f03a570a71d9ba::$classMap; }, null, ClassLoader::class); }