Updated Rector to commit 293eb9701e8035c7d1e57ba0627a637ad70c7c16

293eb9701e [Php81] Skip Doctrine Embeddable on ReadOnlyPropertyRector (#6411)
This commit is contained in:
Tomas Votruba 2024-11-06 13:32:10 +00:00
parent 53788ee425
commit 3b1df92a45
13 changed files with 306 additions and 40 deletions

View File

@ -19,12 +19,12 @@ final class VersionResolver
* @api
* @var string
*/
public const PACKAGE_VERSION = 'afe7c46c0387e27e1eae37cf76f8a3a4119a1d39';
public const PACKAGE_VERSION = '293eb9701e8035c7d1e57ba0627a637ad70c7c16';
/**
* @api
* @var string
*/
public const RELEASE_DATE = '2024-11-05 21:18:05';
public const RELEASE_DATE = '2024-11-06 20:29:42';
/**
* @var int
*/

View File

@ -92,7 +92,7 @@ final class PropertyManipulator
/**
* @var string[]|class-string<Table>[]
*/
private const DOCTRINE_PROPERTY_ANNOTATIONS = ['Doctrine\\ORM\\Mapping\\Entity', 'Doctrine\\ORM\\Mapping\\Table', 'Doctrine\\ORM\\Mapping\\MappedSuperclass'];
private const DOCTRINE_PROPERTY_ANNOTATIONS = ['Doctrine\\ORM\\Mapping\\Entity', 'Doctrine\\ORM\\Mapping\\Table', 'Doctrine\\ORM\\Mapping\\MappedSuperclass', 'Doctrine\\ORM\\Mapping\\Embeddable'];
public function __construct(\Rector\NodeManipulator\AssignManipulator $assignManipulator, BetterNodeFinder $betterNodeFinder, PhpDocInfoFactory $phpDocInfoFactory, PropertyFetchFinder $propertyFetchFinder, NodeNameResolver $nodeNameResolver, PhpAttributeAnalyzer $phpAttributeAnalyzer, NodeTypeResolver $nodeTypeResolver, PromotedPropertyResolver $promotedPropertyResolver, ConstructorAssignDetector $constructorAssignDetector, AstResolver $astResolver, PropertyFetchAnalyzer $propertyFetchAnalyzer)
{
$this->assignManipulator = $assignManipulator;

View File

@ -1742,9 +1742,11 @@ return array(
'Rector\\PHPUnit\\AnnotationsToAttributes\\Rector\\Class_\\AnnotationWithValueToAttributeRector' => $vendorDir . '/rector/rector-phpunit/rules/AnnotationsToAttributes/Rector/Class_/AnnotationWithValueToAttributeRector.php',
'Rector\\PHPUnit\\AnnotationsToAttributes\\Rector\\Class_\\CoversAnnotationWithValueToAttributeRector' => $vendorDir . '/rector/rector-phpunit/rules/AnnotationsToAttributes/Rector/Class_/CoversAnnotationWithValueToAttributeRector.php',
'Rector\\PHPUnit\\AnnotationsToAttributes\\Rector\\Class_\\TicketAnnotationToAttributeRector' => $vendorDir . '/rector/rector-phpunit/rules/AnnotationsToAttributes/Rector/Class_/TicketAnnotationToAttributeRector.php',
'Rector\\PHPUnit\\CodeQuality\\NodeAnalyser\\DoctrineEntityDocumentAnalyser' => $vendorDir . '/rector/rector-phpunit/rules/CodeQuality/NodeAnalyser/DoctrineEntityDocumentAnalyser.php',
'Rector\\PHPUnit\\CodeQuality\\NodeFactory\\NestedClosureAssertFactory' => $vendorDir . '/rector/rector-phpunit/rules/CodeQuality/NodeFactory/NestedClosureAssertFactory.php',
'Rector\\PHPUnit\\CodeQuality\\Rector\\ClassMethod\\CreateMockToAnonymousClassRector' => $vendorDir . '/rector/rector-phpunit/rules/CodeQuality/Rector/ClassMethod/CreateMockToAnonymousClassRector.php',
'Rector\\PHPUnit\\CodeQuality\\Rector\\ClassMethod\\DataProviderArrayItemsNewLinedRector' => $vendorDir . '/rector/rector-phpunit/rules/CodeQuality/Rector/ClassMethod/DataProviderArrayItemsNewLinedRector.php',
'Rector\\PHPUnit\\CodeQuality\\Rector\\ClassMethod\\EntityDocumentCreateMockToDirectNewRector' => $vendorDir . '/rector/rector-phpunit/rules/CodeQuality/Rector/ClassMethod/EntityDocumentCreateMockToDirectNewRector.php',
'Rector\\PHPUnit\\CodeQuality\\Rector\\ClassMethod\\RemoveEmptyTestMethodRector' => $vendorDir . '/rector/rector-phpunit/rules/CodeQuality/Rector/ClassMethod/RemoveEmptyTestMethodRector.php',
'Rector\\PHPUnit\\CodeQuality\\Rector\\ClassMethod\\ReplaceTestAnnotationWithPrefixedFunctionRector' => $vendorDir . '/rector/rector-phpunit/rules/CodeQuality/Rector/ClassMethod/ReplaceTestAnnotationWithPrefixedFunctionRector.php',
'Rector\\PHPUnit\\CodeQuality\\Rector\\ClassMethod\\ReplaceTestFunctionPrefixWithAttributeRector' => $vendorDir . '/rector/rector-phpunit/rules/CodeQuality/Rector/ClassMethod/ReplaceTestFunctionPrefixWithAttributeRector.php',

View File

@ -1961,9 +1961,11 @@ class ComposerStaticInit4d4c37b878ce01a3ff505ba7def6aac7
'Rector\\PHPUnit\\AnnotationsToAttributes\\Rector\\Class_\\AnnotationWithValueToAttributeRector' => __DIR__ . '/..' . '/rector/rector-phpunit/rules/AnnotationsToAttributes/Rector/Class_/AnnotationWithValueToAttributeRector.php',
'Rector\\PHPUnit\\AnnotationsToAttributes\\Rector\\Class_\\CoversAnnotationWithValueToAttributeRector' => __DIR__ . '/..' . '/rector/rector-phpunit/rules/AnnotationsToAttributes/Rector/Class_/CoversAnnotationWithValueToAttributeRector.php',
'Rector\\PHPUnit\\AnnotationsToAttributes\\Rector\\Class_\\TicketAnnotationToAttributeRector' => __DIR__ . '/..' . '/rector/rector-phpunit/rules/AnnotationsToAttributes/Rector/Class_/TicketAnnotationToAttributeRector.php',
'Rector\\PHPUnit\\CodeQuality\\NodeAnalyser\\DoctrineEntityDocumentAnalyser' => __DIR__ . '/..' . '/rector/rector-phpunit/rules/CodeQuality/NodeAnalyser/DoctrineEntityDocumentAnalyser.php',
'Rector\\PHPUnit\\CodeQuality\\NodeFactory\\NestedClosureAssertFactory' => __DIR__ . '/..' . '/rector/rector-phpunit/rules/CodeQuality/NodeFactory/NestedClosureAssertFactory.php',
'Rector\\PHPUnit\\CodeQuality\\Rector\\ClassMethod\\CreateMockToAnonymousClassRector' => __DIR__ . '/..' . '/rector/rector-phpunit/rules/CodeQuality/Rector/ClassMethod/CreateMockToAnonymousClassRector.php',
'Rector\\PHPUnit\\CodeQuality\\Rector\\ClassMethod\\DataProviderArrayItemsNewLinedRector' => __DIR__ . '/..' . '/rector/rector-phpunit/rules/CodeQuality/Rector/ClassMethod/DataProviderArrayItemsNewLinedRector.php',
'Rector\\PHPUnit\\CodeQuality\\Rector\\ClassMethod\\EntityDocumentCreateMockToDirectNewRector' => __DIR__ . '/..' . '/rector/rector-phpunit/rules/CodeQuality/Rector/ClassMethod/EntityDocumentCreateMockToDirectNewRector.php',
'Rector\\PHPUnit\\CodeQuality\\Rector\\ClassMethod\\RemoveEmptyTestMethodRector' => __DIR__ . '/..' . '/rector/rector-phpunit/rules/CodeQuality/Rector/ClassMethod/RemoveEmptyTestMethodRector.php',
'Rector\\PHPUnit\\CodeQuality\\Rector\\ClassMethod\\ReplaceTestAnnotationWithPrefixedFunctionRector' => __DIR__ . '/..' . '/rector/rector-phpunit/rules/CodeQuality/Rector/ClassMethod/ReplaceTestAnnotationWithPrefixedFunctionRector.php',
'Rector\\PHPUnit\\CodeQuality\\Rector\\ClassMethod\\ReplaceTestFunctionPrefixWithAttributeRector' => __DIR__ . '/..' . '/rector/rector-phpunit/rules/CodeQuality/Rector/ClassMethod/ReplaceTestFunctionPrefixWithAttributeRector.php',

View File

@ -1811,12 +1811,12 @@
"source": {
"type": "git",
"url": "https:\/\/github.com\/rectorphp\/rector-phpunit.git",
"reference": "eb0b69aa213ec7925264453770090ca4ca4bacaa"
"reference": "29536ff4bb1177f2d8eebda377eee05f2f386618"
},
"dist": {
"type": "zip",
"url": "https:\/\/api.github.com\/repos\/rectorphp\/rector-phpunit\/zipball\/eb0b69aa213ec7925264453770090ca4ca4bacaa",
"reference": "eb0b69aa213ec7925264453770090ca4ca4bacaa",
"url": "https:\/\/api.github.com\/repos\/rectorphp\/rector-phpunit\/zipball\/29536ff4bb1177f2d8eebda377eee05f2f386618",
"reference": "29536ff4bb1177f2d8eebda377eee05f2f386618",
"shasum": ""
},
"require": {
@ -1840,7 +1840,7 @@
"tomasvotruba\/class-leak": "^1.0",
"tracy\/tracy": "^2.10"
},
"time": "2024-11-05T22:55:54+00:00",
"time": "2024-11-06T08:24:44+00:00",
"default-branch": true,
"type": "rector-extension",
"extra": {
@ -2008,17 +2008,17 @@
},
{
"name": "symfony\/console",
"version": "v6.4.13",
"version_normalized": "6.4.13.0",
"version": "v6.4.14",
"version_normalized": "6.4.14.0",
"source": {
"type": "git",
"url": "https:\/\/github.com\/symfony\/console.git",
"reference": "f793dd5a7d9ae9923e35d0503d08ba734cec1d79"
"reference": "897c2441ed4eec8a8a2c37b943427d24dba3f26b"
},
"dist": {
"type": "zip",
"url": "https:\/\/api.github.com\/repos\/symfony\/console\/zipball\/f793dd5a7d9ae9923e35d0503d08ba734cec1d79",
"reference": "f793dd5a7d9ae9923e35d0503d08ba734cec1d79",
"url": "https:\/\/api.github.com\/repos\/symfony\/console\/zipball\/897c2441ed4eec8a8a2c37b943427d24dba3f26b",
"reference": "897c2441ed4eec8a8a2c37b943427d24dba3f26b",
"shasum": ""
},
"require": {
@ -2051,7 +2051,7 @@
"symfony\/stopwatch": "^5.4|^6.0|^7.0",
"symfony\/var-dumper": "^5.4|^6.0|^7.0"
},
"time": "2024-10-09T08:40:40+00:00",
"time": "2024-11-05T15:34:40+00:00",
"type": "library",
"extra": {
"patches_applied": [
@ -2090,7 +2090,7 @@
"terminal"
],
"support": {
"source": "https:\/\/github.com\/symfony\/console\/tree\/v6.4.13"
"source": "https:\/\/github.com\/symfony\/console\/tree\/v6.4.14"
},
"funding": [
{
@ -2399,23 +2399,23 @@
},
{
"name": "symfony\/process",
"version": "v6.4.13",
"version_normalized": "6.4.13.0",
"version": "v6.4.14",
"version_normalized": "6.4.14.0",
"source": {
"type": "git",
"url": "https:\/\/github.com\/symfony\/process.git",
"reference": "1f9f59b46880201629df3bd950fc5ae8c55b960f"
"reference": "25214adbb0996d18112548de20c281be9f27279f"
},
"dist": {
"type": "zip",
"url": "https:\/\/api.github.com\/repos\/symfony\/process\/zipball\/1f9f59b46880201629df3bd950fc5ae8c55b960f",
"reference": "1f9f59b46880201629df3bd950fc5ae8c55b960f",
"url": "https:\/\/api.github.com\/repos\/symfony\/process\/zipball\/25214adbb0996d18112548de20c281be9f27279f",
"reference": "25214adbb0996d18112548de20c281be9f27279f",
"shasum": ""
},
"require": {
"php": ">=8.1"
},
"time": "2024-09-25T14:18:03+00:00",
"time": "2024-11-06T09:25:01+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
@ -2443,7 +2443,7 @@
"description": "Executes commands in sub-processes",
"homepage": "https:\/\/symfony.com",
"support": {
"source": "https:\/\/github.com\/symfony\/process\/tree\/v6.4.13"
"source": "https:\/\/github.com\/symfony\/process\/tree\/v6.4.14"
},
"funding": [
{

File diff suppressed because one or more lines are too long

View File

@ -9,7 +9,7 @@ namespace Rector\RectorInstaller;
*/
final class GeneratedConfig
{
public const EXTENSIONS = array('rector/rector-doctrine' => array('install_path' => '/home/runner/work/rector-src/rector-src/rector-build/vendor/rector/rector-doctrine', 'relative_install_path' => '../../rector-doctrine', 'extra' => NULL, 'version' => 'dev-main e75008c'), 'rector/rector-downgrade-php' => array('install_path' => '/home/runner/work/rector-src/rector-src/rector-build/vendor/rector/rector-downgrade-php', 'relative_install_path' => '../../rector-downgrade-php', 'extra' => NULL, 'version' => 'dev-main d9cef57'), 'rector/rector-phpunit' => array('install_path' => '/home/runner/work/rector-src/rector-src/rector-build/vendor/rector/rector-phpunit', 'relative_install_path' => '../../rector-phpunit', 'extra' => NULL, 'version' => 'dev-main eb0b69a'), 'rector/rector-symfony' => array('install_path' => '/home/runner/work/rector-src/rector-src/rector-build/vendor/rector/rector-symfony', 'relative_install_path' => '../../rector-symfony', 'extra' => NULL, 'version' => 'dev-main 799b454'));
public const EXTENSIONS = array('rector/rector-doctrine' => array('install_path' => '/home/runner/work/rector-src/rector-src/rector-build/vendor/rector/rector-doctrine', 'relative_install_path' => '../../rector-doctrine', 'extra' => NULL, 'version' => 'dev-main e75008c'), 'rector/rector-downgrade-php' => array('install_path' => '/home/runner/work/rector-src/rector-src/rector-build/vendor/rector/rector-downgrade-php', 'relative_install_path' => '../../rector-downgrade-php', 'extra' => NULL, 'version' => 'dev-main d9cef57'), 'rector/rector-phpunit' => array('install_path' => '/home/runner/work/rector-src/rector-src/rector-build/vendor/rector/rector-phpunit', 'relative_install_path' => '../../rector-phpunit', 'extra' => NULL, 'version' => 'dev-main 29536ff'), 'rector/rector-symfony' => array('install_path' => '/home/runner/work/rector-src/rector-src/rector-build/vendor/rector/rector-symfony', 'relative_install_path' => '../../rector-symfony', 'extra' => NULL, 'version' => 'dev-main 799b454'));
private function __construct()
{
}

View File

@ -0,0 +1,28 @@
<?php
declare (strict_types=1);
namespace Rector\PHPUnit\CodeQuality\NodeAnalyser;
use PHPStan\PhpDoc\ResolvedPhpDocBlock;
use PHPStan\Reflection\ClassReflection;
final class DoctrineEntityDocumentAnalyser
{
/**
* @var string[]
*/
private const ENTITY_DOCBLOCK_MARKERS = ['@Document', '@ORM\\Document', '@Entity', '@ORM\\Entity'];
public function isEntityClass(ClassReflection $classReflection) : bool
{
$resolvedPhpDocBlock = $classReflection->getResolvedPhpDoc();
if (!$resolvedPhpDocBlock instanceof ResolvedPhpDocBlock) {
return \false;
}
foreach (self::ENTITY_DOCBLOCK_MARKERS as $entityDocBlockMarkers) {
if (\strpos($resolvedPhpDocBlock->getPhpDocString(), $entityDocBlockMarkers) !== \false) {
return \true;
}
}
// @todo apply attributes as well
return \false;
}
}

View File

@ -0,0 +1,223 @@
<?php
declare (strict_types=1);
namespace Rector\PHPUnit\CodeQuality\Rector\ClassMethod;
use PhpParser\Node;
use PhpParser\Node\Arg;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\New_;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Identifier;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Scalar\String_;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Expression;
use PhpParser\NodeFinder;
use PHPStan\Reflection\ReflectionProvider;
use Rector\Exception\ShouldNotHappenException;
use Rector\PhpParser\Node\Value\ValueResolver;
use Rector\PHPUnit\CodeQuality\NodeAnalyser\DoctrineEntityDocumentAnalyser;
use Rector\Rector\AbstractRector;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
/**
* @see \Rector\PHPUnit\Tests\CodeQuality\Rector\ClassMethod\EntityDocumentCreateMockToDirectNewRector\EntityDocumentCreateMockToDirectNewRectorTest
*/
final class EntityDocumentCreateMockToDirectNewRector extends AbstractRector
{
/**
* @readonly
* @var \Rector\PhpParser\Node\Value\ValueResolver
*/
private $valueResolver;
/**
* @readonly
* @var \PHPStan\Reflection\ReflectionProvider
*/
private $reflectionProvider;
/**
* @readonly
* @var \Rector\PHPUnit\CodeQuality\NodeAnalyser\DoctrineEntityDocumentAnalyser
*/
private $doctrineEntityDocumentAnalyser;
public function __construct(ValueResolver $valueResolver, ReflectionProvider $reflectionProvider, DoctrineEntityDocumentAnalyser $doctrineEntityDocumentAnalyser)
{
$this->valueResolver = $valueResolver;
$this->reflectionProvider = $reflectionProvider;
$this->doctrineEntityDocumentAnalyser = $doctrineEntityDocumentAnalyser;
}
public function getRuleDefinition() : RuleDefinition
{
return new RuleDefinition('Move from value object mocking, to direct use of value object', []);
}
/**
* @return array<class-string<Node>>
*/
public function getNodeTypes() : array
{
return [ClassMethod::class];
}
/**
* @param ClassMethod $node
*/
public function refactor(Node $node) : ?ClassMethod
{
if ($node->stmts === null) {
return null;
}
$mockedVariablesToTypes = $this->collectMockedVariableToTypeAndRefactorAssign($node);
if ($mockedVariablesToTypes === []) {
return null;
}
foreach ($mockedVariablesToTypes as $mockedVariableName => $mockedClass) {
foreach ($node->stmts as $key => $stmt) {
if (!$stmt instanceof Expression) {
continue;
}
if (!$stmt->expr instanceof MethodCall) {
continue;
}
$methodCall = $stmt->expr;
$onVariableMethodCall = $this->findMethodCallOnVariableNamed($methodCall, $mockedVariableName);
if (!$onVariableMethodCall instanceof Node) {
continue;
}
// 2. find $mock->method("name")
$methodName = $this->resolveMethodCallFirstArgValue($methodCall, 'method');
if (!\is_string($methodName)) {
throw new ShouldNotHappenException('Unable to resolve method name');
}
// is set method mocked? Just remove it
if (\strncmp($methodName, 'set', \strlen('set')) === 0) {
unset($node->stmts[$key]);
}
$methodName = $this->resolveMethodName($methodName, $mockedClass);
$willReturnExpr = $this->resolveMethodCallFirstArgValue($methodCall, 'willReturn');
if ($methodName && $willReturnExpr instanceof Expr) {
$stmt->expr = new MethodCall(new Variable($mockedVariableName), new Identifier($methodName), [new Arg($willReturnExpr)]);
}
}
}
// 3. replace value without "mock" in name
$mockedVariableNames = \array_keys($mockedVariablesToTypes);
$this->traverseNodesWithCallable($node, function (Node $node) use($mockedVariableNames) : ?Variable {
if (!$node instanceof Variable) {
return null;
}
if (!\is_string($node->name)) {
return null;
}
if (!\in_array($node->name, $mockedVariableNames)) {
return null;
}
return new Variable(\str_replace('Mock', '', $node->name));
});
return $node;
}
/**
* @return array<string, string>
*/
private function collectMockedVariableToTypeAndRefactorAssign(ClassMethod $classMethod) : array
{
if ($classMethod->stmts === null) {
return [];
}
$mockedVariablesToTypes = [];
foreach ($classMethod->stmts as $stmt) {
// find assign mock
if (!$stmt instanceof Expression) {
continue;
}
$stmtExpr = $stmt->expr;
if (!$stmtExpr instanceof Assign) {
continue;
}
/** @var Assign $assign */
$assign = $stmtExpr;
if (!$assign->expr instanceof MethodCall) {
continue;
}
$methodCall = $assign->expr;
if (!$this->isName($methodCall->name, 'createMock')) {
continue;
}
$firstArg = $methodCall->getArgs()[0];
$mockedClass = $this->valueResolver->getValue($firstArg->value);
if (!\is_string($mockedClass)) {
continue;
}
if (!$this->reflectionProvider->hasClass($mockedClass)) {
continue;
}
$mockClassReflection = $this->reflectionProvider->getClass($mockedClass);
if ($mockClassReflection->isAbstract()) {
continue;
}
if (!$this->doctrineEntityDocumentAnalyser->isEntityClass($mockClassReflection)) {
continue;
}
// ready to replace :)
$assign->expr = new New_(new FullyQualified($mockedClass));
$mockedVariableName = $this->getName($assign->var);
$mockedVariablesToTypes[$mockedVariableName] = $mockedClass;
}
return $mockedVariablesToTypes;
}
/**
* @return string|\PhpParser\Node\Expr|null
*/
private function resolveMethodCallFirstArgValue(MethodCall $methodCall, string $methodName)
{
$nodeFinder = new NodeFinder();
$methodNameMethodCall = $nodeFinder->findFirst($methodCall, function (Node $node) use($methodName) : bool {
if (!$node instanceof MethodCall) {
return \false;
}
return $this->isName($node->name, $methodName);
});
if (!$methodNameMethodCall instanceof MethodCall) {
return null;
}
$methodNameArg = $methodNameMethodCall->getArgs()[0];
if ($methodNameArg->value instanceof String_) {
return $methodNameArg->value->value;
}
return $methodNameArg->value;
}
private function resolveMethodName(string $methodName, string $mockedClass) : string
{
// guess the setter name
if (\strncmp($methodName, 'get', \strlen('get')) === 0) {
return 'set' . \ucfirst(\substr($methodName, 3));
}
if (\strncmp($methodName, 'is', \strlen('is')) === 0) {
$mockedClassReflection = $this->reflectionProvider->getClass($mockedClass);
$isSetterMethodNames = ['set' . \ucfirst($methodName), 'set' . \substr($methodName, 2)];
foreach ($isSetterMethodNames as $isSetterMethodName) {
if ($mockedClassReflection->hasMethod($isSetterMethodName)) {
return $isSetterMethodName;
}
}
}
return $methodName;
}
private function findMethodCallOnVariableNamed(MethodCall $methodCall, string $desiredVariableName) : ?MethodCall
{
$nodeFinder = new NodeFinder();
$foundMethodCall = $nodeFinder->findFirst($methodCall, function (Node $node) use($desiredVariableName) : bool {
if (!$node instanceof MethodCall) {
return \false;
}
if (!$node->var instanceof Variable) {
return \false;
}
return $this->isName($node->var, $desiredVariableName);
});
if (!$foundMethodCall instanceof MethodCall) {
return null;
}
return $foundMethodCall;
}
}

View File

@ -787,7 +787,7 @@ class Application implements ResetInterface
$len = 0;
}
if (\strpos($message, "@anonymous\x00") !== \false) {
$message = \preg_replace_callback('/[a-zA-Z_\\x7f-\\xff][\\\\a-zA-Z0-9_\\x7f-\\xff]*+@anonymous\\x00.*?\\.php(?:0x?|:[0-9]++\\$)[0-9a-fA-F]++/', function ($m) {
$message = \preg_replace_callback('/[a-zA-Z_\\x7f-\\xff][\\\\a-zA-Z0-9_\\x7f-\\xff]*+@anonymous\\x00.*?\\.php(?:0x?|:[0-9]++\\$)?[0-9a-fA-F]++/', function ($m) {
return \class_exists($m[0], \false) ? ((\get_parent_class($m[0]) ?: \key(\class_implements($m[0]))) ?: 'class') . '@anonymous' : $m[0];
}, $message);
}

View File

@ -18,10 +18,11 @@ namespace RectorPrefix202411\Symfony\Component\Process;
*/
class ExecutableFinder
{
private const CMD_BUILTINS = ['assoc', 'break', 'call', 'cd', 'chdir', 'cls', 'color', 'copy', 'date', 'del', 'dir', 'echo', 'endlocal', 'erase', 'exit', 'for', 'ftype', 'goto', 'help', 'if', 'label', 'md', 'mkdir', 'mklink', 'move', 'path', 'pause', 'popd', 'prompt', 'pushd', 'rd', 'rem', 'ren', 'rename', 'rmdir', 'set', 'setlocal', 'shift', 'start', 'time', 'title', 'type', 'ver', 'vol'];
/**
* @var mixed[]
*/
private $suffixes = ['.exe', '.bat', '.cmd', '.com'];
private $suffixes = [];
/**
* Replaces default suffixes of executable.
*
@ -49,14 +50,23 @@ class ExecutableFinder
*/
public function find(string $name, ?string $default = null, array $extraDirs = []) : ?string
{
// windows built-in commands that are present in cmd.exe should not be resolved using PATH as they do not exist as exes
if ('\\' === \DIRECTORY_SEPARATOR && \in_array(\strtolower($name), self::CMD_BUILTINS, \true)) {
return $name;
}
$dirs = \array_merge(\explode(\PATH_SEPARATOR, \getenv('PATH') ?: \getenv('Path')), $extraDirs);
$suffixes = [''];
$suffixes = [];
if ('\\' === \DIRECTORY_SEPARATOR) {
$pathExt = \getenv('PATHEXT');
$suffixes = \array_merge($pathExt ? \explode(\PATH_SEPARATOR, $pathExt) : $this->suffixes, $suffixes);
$suffixes = $this->suffixes;
$suffixes = \array_merge($suffixes, $pathExt ? \explode(\PATH_SEPARATOR, $pathExt) : ['.exe', '.bat', '.cmd', '.com']);
}
$suffixes = '' !== \pathinfo($name, \PATHINFO_EXTENSION) ? \array_merge([''], $suffixes) : \array_merge($suffixes, ['']);
foreach ($suffixes as $suffix) {
foreach ($dirs as $dir) {
if ('' === $dir) {
$dir = '.';
}
if (@\is_file($file = $dir . \DIRECTORY_SEPARATOR . $name . $suffix) && ('\\' === \DIRECTORY_SEPARATOR || @\is_executable($file))) {
return $file;
}
@ -65,8 +75,11 @@ class ExecutableFinder
}
}
}
$command = '\\' === \DIRECTORY_SEPARATOR ? 'where' : 'command -v --';
if (\function_exists('exec') && ($executablePath = \strtok(@\exec($command . ' ' . \escapeshellarg($name)), \PHP_EOL)) && @\is_executable($executablePath)) {
if ('\\' === \DIRECTORY_SEPARATOR || !\function_exists('exec') || \strlen($name) !== \strcspn($name, '/' . \DIRECTORY_SEPARATOR)) {
return $default;
}
$execResult = \exec('command -v -- ' . \escapeshellarg($name));
if (($executablePath = \substr($execResult, 0, \strpos($execResult, \PHP_EOL) ?: null)) && @\is_executable($executablePath)) {
return $executablePath;
}
return $default;

View File

@ -33,15 +33,8 @@ class PhpExecutableFinder
public function find(bool $includeArgs = \true)
{
if ($php = \getenv('PHP_BINARY')) {
if (!\is_executable($php)) {
$command = '\\' === \DIRECTORY_SEPARATOR ? 'where' : 'command -v --';
if (\function_exists('exec') && ($php = \strtok(\exec($command . ' ' . \escapeshellarg($php)), \PHP_EOL))) {
if (!\is_executable($php)) {
return \false;
}
} else {
return \false;
}
if (!\is_executable($php) && !($php = $this->executableFinder->find($php))) {
return \false;
}
if (@\is_dir($php)) {
return \false;

View File

@ -1394,7 +1394,12 @@ class Process implements \IteratorAggregate
$env[$var] = $value;
return $varCache[$m[0]] = '!' . $var . '!';
}, $cmd);
$cmd = 'cmd /V:ON /E:ON /D /C (' . \str_replace("\n", ' ', $cmd) . ')';
static $comSpec;
if (!$comSpec && ($comSpec = (new ExecutableFinder())->find('cmd.exe'))) {
// Escape according to CommandLineToArgvW rules
$comSpec = '"' . \preg_replace('{(\\\\*+)"}', '$1$1\\"', $comSpec) . '"';
}
$cmd = ($comSpec ?? 'cmd') . ' /V:ON /E:ON /D /C (' . \str_replace("\n", ' ', $cmd) . ')';
foreach ($this->processPipes->getFiles() as $offset => $filename) {
$cmd .= ' ' . $offset . '>"' . $filename . '"';
}
@ -1436,7 +1441,7 @@ class Process implements \IteratorAggregate
if (\strpos($argument, "\x00") !== \false) {
$argument = \str_replace("\x00", '?', $argument);
}
if (!\preg_match('/[\\/()%!^"<>&|\\s]/', $argument)) {
if (!\preg_match('/[()%!^"<>&|\\s]/', $argument)) {
return $argument;
}
$argument = \preg_replace('/(\\\\+)$/', '$1$1', $argument);