Updated Rector to commit f254215a5ac2877d4fb99dbf7f7ab44c070f1333

f254215a5a [Scope] Fix resolve Scope from fluent call (#5743)
This commit is contained in:
Tomas Votruba 2024-03-26 19:25:47 +00:00
parent 014254f0df
commit 045db2fd56
11 changed files with 153 additions and 76 deletions

View File

@ -19,12 +19,12 @@ final class VersionResolver
* @api
* @var string
*/
public const PACKAGE_VERSION = '83046fcc340c19fc65bc09db25bbc018b01d6f30';
public const PACKAGE_VERSION = 'f254215a5ac2877d4fb99dbf7f7ab44c070f1333';
/**
* @api
* @var string
*/
public const RELEASE_DATE = '2024-03-26 10:26:04';
public const RELEASE_DATE = '2024-03-27 02:23:32';
/**
* @var int
*/

View File

@ -123,7 +123,7 @@ final class CustomRuleCommand extends Command
$this->symfonyStyle->warning('No <testsuites> element found in ' . $phpunitFilePath . '. Rector could not add the rector test suite to it');
return;
}
$phpunitXML = $this->updatePHPUnitXMLFile($domDocument, $testsuitesElement, $phpunitFilePath);
$phpunitXML = $this->updatePHPUnitXMLFile($domDocument, $testsuitesElement);
FileSystem::write($phpunitFilePath, $phpunitXML, null);
$this->symfonyStyle->success('We also update ' . $phpunitFilePath . ", to add a rector test suite.\n You can run the rector tests by running: phpunit --testsuite rector");
}
@ -146,7 +146,7 @@ final class CustomRuleCommand extends Command
}
return \false;
}
private function updatePHPUnitXMLFile(DOMDocument $domDocument, DOMElement $testsuitesElement, string $phpunitFilePath) : string
private function updatePHPUnitXMLFile(DOMDocument $domDocument, DOMElement $testsuitesElement) : string
{
$domElement = $domDocument->createElement('testsuite');
$domElement->setAttribute('name', 'rector');

View File

@ -59,7 +59,7 @@ final class ExprScopeFromStmtNodeVisitor extends NodeVisitorAbstract
if (!$node instanceof Expr) {
return null;
}
if ($node->getAttribute(AttributeKey::EXPRESSION_DEPTH) < 2 && $node->getAttribute(AttributeKey::IS_ARG_VALUE) !== \true) {
if ($this->shouldSkipExpr($node)) {
return null;
}
$scope = $node->getAttribute(AttributeKey::SCOPE);
@ -75,4 +75,8 @@ final class ExprScopeFromStmtNodeVisitor extends NodeVisitorAbstract
}
return null;
}
private function shouldSkipExpr(Expr $expr) : bool
{
return $expr->getAttribute(AttributeKey::EXPRESSION_DEPTH) < 2 && $expr->getAttribute(AttributeKey::IS_ARG_VALUE) !== \true && $expr->getAttribute(AttributeKey::IS_PARAM_VAR) === \true;
}
}

View File

@ -227,17 +227,17 @@
},
{
"name": "composer\/xdebug-handler",
"version": "3.0.3",
"version_normalized": "3.0.3.0",
"version": "3.0.4",
"version_normalized": "3.0.4.0",
"source": {
"type": "git",
"url": "https:\/\/github.com\/composer\/xdebug-handler.git",
"reference": "ced299686f41dce890debac69273b47ffe98a40c"
"reference": "4f988f8fdf580d53bdb2d1278fe93d1ed5462255"
},
"dist": {
"type": "zip",
"url": "https:\/\/api.github.com\/repos\/composer\/xdebug-handler\/zipball\/ced299686f41dce890debac69273b47ffe98a40c",
"reference": "ced299686f41dce890debac69273b47ffe98a40c",
"url": "https:\/\/api.github.com\/repos\/composer\/xdebug-handler\/zipball\/4f988f8fdf580d53bdb2d1278fe93d1ed5462255",
"reference": "4f988f8fdf580d53bdb2d1278fe93d1ed5462255",
"shasum": ""
},
"require": {
@ -248,9 +248,9 @@
"require-dev": {
"phpstan\/phpstan": "^1.0",
"phpstan\/phpstan-strict-rules": "^1.1",
"symfony\/phpunit-bridge": "^6.0"
"phpunit\/phpunit": "^8.5 || ^9.6 || ^10.5"
},
"time": "2022-02-25T21:32:43+00:00",
"time": "2024-03-26T18:29:49+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
@ -274,9 +274,9 @@
"performance"
],
"support": {
"irc": "irc:\/\/irc.freenode.org\/composer",
"irc": "ircs:\/\/irc.libera.chat:6697\/composer",
"issues": "https:\/\/github.com\/composer\/xdebug-handler\/issues",
"source": "https:\/\/github.com\/composer\/xdebug-handler\/tree\/3.0.3"
"source": "https:\/\/github.com\/composer\/xdebug-handler\/tree\/3.0.4"
},
"funding": [
{

File diff suppressed because one or more lines are too long

View File

@ -1,5 +1,9 @@
## [Unreleased]
## [3.0.4] - 2024-03-26
* Added: Functional tests.
* Fixed: Incompatibility with PHPUnit 10.
## [3.0.3] - 2022-02-25
* Added: support for composer/pcre versions 2 and 3.
@ -108,7 +112,8 @@
* Break: the following class was renamed:
- `Composer\XdebugHandler` -> `Composer\XdebugHandler\XdebugHandler`
[Unreleased]: https://github.com/composer/xdebug-handler/compare/3.0.3...HEAD
[Unreleased]: https://github.com/composer/xdebug-handler/compare/3.0.4...HEAD
[3.0.3]: https://github.com/composer/xdebug-handler/compare/3.0.3...3.0.4
[3.0.2]: https://github.com/composer/xdebug-handler/compare/3.0.2...3.0.3
[3.0.2]: https://github.com/composer/xdebug-handler/compare/3.0.1...3.0.2
[3.0.1]: https://github.com/composer/xdebug-handler/compare/3.0.0...3.0.1

View File

@ -51,6 +51,7 @@ The constructor takes a single parameter, `$envPrefix`, which is upper-cased and
* [Process configuration](#process-configuration)
* [Troubleshooting](#troubleshooting)
* [Extending the library](#extending-the-library)
* [Examples](#examples)
### How it works
@ -64,6 +65,8 @@ A temporary ini file is created from the loaded (and scanned) ini files, with an
* The application runs and exits.
* The main process exits with the exit code from the restarted process.
See [Examples](#examples) for further information.
#### Signal handling
Asynchronous signal handling is automatically enabled if the pcntl extension is loaded. `SIGINT` is set to `SIG_IGN` in the parent
process and restored to `SIG_DFL` in the restarted process (if no other handler has been set).
@ -74,7 +77,7 @@ From PHP 7.4 on Windows, `CTRL+C` and `CTRL+BREAK` handling is automatically ena
There are a few things to be aware of when running inside a restarted process.
* Extensions set on the command-line will not be loaded.
* Ini file locations will be reported as per the restart - see [getAllIniFiles()](#getallinifiles).
* Ini file locations will be reported as per the restart - see [getAllIniFiles()](#getallinifiles-array).
* Php sub-processes may be loaded with Xdebug enabled - see [Process configuration](#process-configuration).
### Helper methods
@ -200,12 +203,12 @@ Uses environment variables to remove Xdebug from the new process and persist the
>_If the new process calls a PHP sub-process, Xdebug will not be loaded in that sub-process._
This strategy can be used in the restart by calling [setPersistent()](#setpersistent).
This strategy can be used in the restart by calling [setPersistent()](#setpersistent-self).
#### Sub-processes
The `PhpConfig` helper class makes it easy to invoke a PHP sub-process (with or without Xdebug loaded), regardless of whether there has been a restart.
Each of its methods returns an array of PHP options (to add to the command-line) and sets up the environment for the required strategy. The [getRestartSettings()](#getrestartsettings) method is used internally.
Each of its methods returns an array of PHP options (to add to the command-line) and sets up the environment for the required strategy. The [getRestartSettings()](#getrestartsettings-array) method is used internally.
* `useOriginal()` - Xdebug will be loaded in the new process.
* `useStandard()` - Xdebug will **not** be loaded in the new process - see [standard settings](#standard-settings).
@ -245,7 +248,7 @@ The API is defined by classes and their accessible elements that are not annotat
By default the process will restart if Xdebug is loaded and not running with `xdebug.mode=off`. Extending this method allows an application to decide, by returning a boolean (or equivalent) value.
It is only called if `MYAPP_ALLOW_XDEBUG` is empty, so it will not be called in the restarted process (where this variable contains internal data), or if the restart has been overridden.
Note that the [setMainScript()](#setmainscriptscript) and [setPersistent()](#setpersistent) setters can be used here, if required.
Note that the [setMainScript()](#setmainscriptstring-script-self) and [setPersistent()](#setpersistent-self) setters can be used here, if required.
#### _restart(array $command): void_
An application can extend this to modify the temporary ini file, its location given in the `tmpIni` property. New settings can be safely appended to the end of the data, which is `PHP_EOL` terminated.
@ -294,5 +297,9 @@ class MyRestarter extends XdebugHandler
}
```
### Examples
The `tests\App` directory contains command-line scripts that demonstrate the internal workings in a variety of scenarios.
See [Functional Test Scripts](./tests/App/README.md).
## License
composer/xdebug-handler is licensed under the MIT License, see the LICENSE file for details.

View File

@ -14,7 +14,7 @@
}
],
"support": {
"irc": "irc:\/\/irc.freenode.org\/composer",
"irc": "ircs:\/\/irc.libera.chat:6697\/composer",
"issues": "https:\/\/github.com\/composer\/xdebug-handler\/issues"
},
"require": {
@ -23,9 +23,9 @@
"composer\/pcre": "^1 || ^2 || ^3"
},
"require-dev": {
"symfony\/phpunit-bridge": "^6.0",
"phpstan\/phpstan": "^1.0",
"phpstan\/phpstan-strict-rules": "^1.1"
"phpstan\/phpstan-strict-rules": "^1.1",
"phpunit\/phpunit": "^8.5 || ^9.6 || ^10.5"
},
"autoload": {
"psr-4": {
@ -38,7 +38,7 @@
}
},
"scripts": {
"test": "@php vendor\/bin\/simple-phpunit",
"test": "@php vendor\/bin\/phpunit",
"phpstan": "@php vendor\/bin\/phpstan analyse"
}
}

View File

@ -36,6 +36,7 @@ class Process
}
$quote = \strpbrk($arg, " \t") !== \false || $arg === '';
$arg = Preg::replace('/(\\\\*)"/', '$1$1\\"', $arg, -1, $dquotes);
$dquotes = (bool) $dquotes;
if ($meta) {
$meta = $dquotes || Preg::isMatch('/%[^%]+%/', $arg);
if (!$meta) {

View File

@ -69,12 +69,32 @@ class Status
public function report(string $op, ?string $data) : void
{
if ($this->logger !== null || $this->debug) {
$callable = [$this, 'report' . $op];
if (!\is_callable($callable)) {
throw new \InvalidArgumentException('Unknown op handler: ' . $op);
$param = (string) $data;
switch ($op) {
case self::CHECK:
$this->reportCheck($param);
break;
case self::ERROR:
$this->reportError($param);
break;
case self::INFO:
$this->reportInfo($param);
break;
case self::NORESTART:
$this->reportNoRestart();
break;
case self::RESTART:
$this->reportRestart();
break;
case self::RESTARTED:
$this->reportRestarted();
break;
case self::RESTARTING:
$this->reportRestarting($param);
break;
default:
throw new \InvalidArgumentException('Unknown op handler: ' . $op);
}
$params = $data !== null ? [$data] : [];
\call_user_func_array($callable, $params);
}
}
/**
@ -154,7 +174,7 @@ class Status
{
$text = \sprintf('Process restarting (%s)', $this->getEnvAllow());
$this->output($text);
$text = 'Running ' . $command;
$text = 'Running: ' . $command;
$this->output($text);
}
/**

View File

@ -116,8 +116,8 @@ class XdebugHandler
if (!(bool) $envArgs[0] && $this->requiresRestart(self::$xdebugActive)) {
// Restart required
$this->notify(Status::RESTART);
if ($this->prepareRestart()) {
$command = $this->getCommand();
$command = $this->prepareRestart();
if ($command !== null) {
$this->restart($command);
}
return;
@ -147,9 +147,9 @@ class XdebugHandler
* Returns an array of php.ini locations with at least one entry
*
* The equivalent of calling php_ini_loaded_file then php_ini_scanned_files.
* The loaded ini location is the first entry and may be empty.
* The loaded ini location is the first entry and may be an empty string.
*
* @return string[]
* @return non-empty-list<string>
*/
public static function getAllIniFiles() : array
{
@ -212,7 +212,7 @@ class XdebugHandler
/**
* Allows an extending class to access the tmpIni
*
* @param string[] $command *
* @param non-empty-list<string> $command
*/
protected function restart(array $command) : void
{
@ -221,22 +221,24 @@ class XdebugHandler
/**
* Executes the restarted command then deletes the tmp ini
*
* @param string[] $command
* @param non-empty-list<string> $command
* @phpstan-return never
*/
private function doRestart(array $command) : void
{
$this->tryEnableSignals();
$this->notify(Status::RESTARTING, \implode(' ', $command));
if (\PHP_VERSION_ID >= 70400) {
$cmd = $command;
$displayCmd = \sprintf('[%s]', \implode(', ', $cmd));
} else {
$cmd = Process::escapeShellCommand($command);
if (\defined('PHP_WINDOWS_VERSION_BUILD')) {
// Outer quotes required on cmd string below PHP 8
$cmd = '"' . $cmd . '"';
}
$displayCmd = $cmd;
}
$this->tryEnableSignals();
$this->notify(Status::RESTARTING, $displayCmd);
$process = \proc_open(\is_array($cmd) ? \implode(' ', \array_map('escapeshellarg', $cmd)) : $cmd, [], $pipes);
if (\is_resource($process)) {
$exitCode = \proc_close($process);
@ -256,46 +258,63 @@ class XdebugHandler
exit($exitCode);
}
/**
* Returns true if everything was written for the restart
* Returns the command line array if everything was written for the restart
*
* If any of the following fails (however unlikely) we must return false to
* stop potential recursion:
* - tmp ini file creation
* - environment variable creation
*
* @return non-empty-list<string>|null
*/
private function prepareRestart() : bool
private function prepareRestart() : ?array
{
if (!$this->cli) {
$this->notify(Status::ERROR, 'Unsupported SAPI: ' . \PHP_SAPI);
return null;
}
if (($argv = $this->checkServerArgv()) === null) {
$this->notify(Status::ERROR, '$_SERVER[argv] is not as expected');
return null;
}
if (!$this->checkConfiguration($info)) {
$this->notify(Status::ERROR, $info);
return null;
}
$mainScript = (string) $this->script;
if (!$this->checkMainScript($mainScript, $argv)) {
$this->notify(Status::ERROR, 'Unable to access main script: ' . $mainScript);
return null;
}
$tmpDir = \sys_get_temp_dir();
$iniError = 'Unable to create temp ini file at: ' . $tmpDir;
if (($tmpfile = @\tempnam($tmpDir, '')) === \false) {
$this->notify(Status::ERROR, $iniError);
return null;
}
$error = null;
$iniFiles = self::getAllIniFiles();
$scannedInis = \count($iniFiles) > 1;
$tmpDir = \sys_get_temp_dir();
if (!$this->cli) {
$error = 'Unsupported SAPI: ' . \PHP_SAPI;
} elseif (!$this->checkConfiguration($info)) {
$error = $info;
} elseif (!$this->checkMainScript()) {
$error = 'Unable to access main script: ' . $this->script;
} elseif (!$this->writeTmpIni($iniFiles, $tmpDir, $error)) {
$error = $error !== null ? $error : 'Unable to create temp ini file at: ' . $tmpDir;
} elseif (!$this->setEnvironment($scannedInis, $iniFiles)) {
$error = 'Unable to set environment variables';
if (!$this->writeTmpIni($tmpfile, $iniFiles, $error)) {
$this->notify(Status::ERROR, $error ?? $iniError);
@\unlink($tmpfile);
return null;
}
if ($error !== null) {
$this->notify(Status::ERROR, $error);
if (!$this->setEnvironment($scannedInis, $iniFiles, $tmpfile)) {
$this->notify(Status::ERROR, 'Unable to set environment variables');
@\unlink($tmpfile);
return null;
}
return $error === null;
$this->tmpIni = $tmpfile;
return $this->getCommand($argv, $tmpfile, $mainScript);
}
/**
* Returns true if the tmp ini file was written
*
* @param string[] $iniFiles All ini files used in the current process
* @param non-empty-list<string> $iniFiles All ini files used in the current process
*/
private function writeTmpIni(array $iniFiles, string $tmpDir, ?string &$error) : bool
private function writeTmpIni(string $tmpFile, array $iniFiles, ?string &$error) : bool
{
if (($tmpfile = @\tempnam($tmpDir, '')) === \false) {
return \false;
}
$this->tmpIni = $tmpfile;
// $iniFiles has at least one item and it may be empty
if ($iniFiles[0] === '') {
\array_shift($iniFiles);
@ -310,7 +329,7 @@ class XdebugHandler
return \false;
}
// Check and remove directives after HOST and PATH sections
if (Preg::isMatchWithOffsets($sectionRegex, $data, $matches, \PREG_OFFSET_CAPTURE)) {
if (Preg::isMatchWithOffsets($sectionRegex, $data, $matches)) {
$data = \substr($data, 0, $matches[0][1]);
}
$content .= Preg::replace($xdebugRegex, ';$1', $data) . \PHP_EOL;
@ -325,31 +344,32 @@ class XdebugHandler
$content .= $this->mergeLoadedConfig($loaded, $config);
// Work-around for https://bugs.php.net/bug.php?id=75932
$content .= 'opcache.enable_cli=0' . \PHP_EOL;
return (bool) @\file_put_contents($this->tmpIni, $content);
return (bool) @\file_put_contents($tmpFile, $content);
}
/**
* Returns the command line arguments for the restart
*
* @return string[]
* @param non-empty-list<string> $argv
* @return non-empty-list<string>
*/
private function getCommand() : array
private function getCommand(array $argv, string $tmpIni, string $mainScript) : array
{
$php = [\PHP_BINARY];
$args = \array_slice($_SERVER['argv'], 1);
$args = \array_slice($argv, 1);
if (!$this->persistent) {
// Use command-line options
\array_push($php, '-n', '-c', $this->tmpIni);
\array_push($php, '-n', '-c', $tmpIni);
}
return \array_merge($php, [$this->script], $args);
return \array_merge($php, [$mainScript], $args);
}
/**
* Returns true if the restart environment variables were set
*
* No need to update $_SERVER since this is set in the restarted process.
*
* @param string[] $iniFiles All ini files used in the current process
* @param non-empty-list<string> $iniFiles All ini files used in the current process
*/
private function setEnvironment(bool $scannedInis, array $iniFiles) : bool
private function setEnvironment(bool $scannedInis, array $iniFiles, string $tmpIni) : bool
{
$scanDir = \getenv('PHP_INI_SCAN_DIR');
$phprc = \getenv('PHPRC');
@ -359,7 +379,7 @@ class XdebugHandler
}
if ($this->persistent) {
// Use the environment to persist the settings
if (!\putenv('PHP_INI_SCAN_DIR=') || !\putenv('PHPRC=' . $this->tmpIni)) {
if (!\putenv('PHP_INI_SCAN_DIR=') || !\putenv('PHPRC=' . $tmpIni)) {
return \false;
}
}
@ -398,28 +418,30 @@ class XdebugHandler
}
/**
* Returns true if the script name can be used
*
* @param non-empty-list<string> $argv
*/
private function checkMainScript() : bool
private function checkMainScript(string &$mainScript, array $argv) : bool
{
if ($this->script !== null) {
if ($mainScript !== '') {
// Allow an application to set -- for standard input
return \file_exists($this->script) || '--' === $this->script;
return \file_exists($mainScript) || '--' === $mainScript;
}
if (\file_exists($this->script = $_SERVER['argv'][0])) {
if (\file_exists($mainScript = $argv[0])) {
return \true;
}
// Use a backtrace to resolve Phar and chdir issues.
$trace = \debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS);
$main = \end($trace);
if ($main !== \false && isset($main['file'])) {
return \file_exists($this->script = $main['file']);
return \file_exists($mainScript = $main['file']);
}
return \false;
}
/**
* Adds restart settings to the environment
*
* @param string[] $envArgs
* @param non-empty-list<string> $envArgs
*/
private function setEnvRestartSettings(array $envArgs) : void
{
@ -498,6 +520,24 @@ class XdebugHandler
});
}
}
/**
* Returns $_SERVER['argv'] if it is as expected
*
* @return non-empty-list<string>|null
*/
private function checkServerArgv() : ?array
{
$result = [];
if (isset($_SERVER['argv']) && \is_array($_SERVER['argv'])) {
foreach ($_SERVER['argv'] as $value) {
if (!\is_string($value)) {
return null;
}
$result[] = $value;
}
}
return \count($result) > 0 ? $result : null;
}
/**
* Sets static properties $xdebugActive, $xdebugVersion and $xdebugMode
*/