pax_global_header00006660000000000000000000000064127161056000014510gustar00rootroot0000000000000052 comment=2e6a31b15fcbe091b6c9796e6fa4fb1c2fc5c768 php7cc-1.1.0/000077500000000000000000000000001271610560000126735ustar00rootroot00000000000000php7cc-1.1.0/.gitignore000066400000000000000000000000771271610560000146670ustar00rootroot00000000000000# Dependencies /vendor # Composer composer.lock composer.phar php7cc-1.1.0/.php_cs000066400000000000000000000005621271610560000141530ustar00rootroot00000000000000in(__DIR__) ->exclude(array( 'vendor', 'test/resource', )); $fixers = array( '-phpdoc_to_comment', '-concat_without_spaces', 'concat_with_spaces', 'newline_after_open_tag', ); return Symfony\CS\Config\Config::create() ->finder($finder) ->fixers($fixers) ;php7cc-1.1.0/.travis.yml000066400000000000000000000024251271610560000150070ustar00rootroot00000000000000language: php sudo: false cache: directories: - "$HOME/.composer/cache" php: - 5.3 - 5.4 - 5.5 - 5.6 - 7.0 env: - COMPOSER_FLAGS="--prefer-lowest" - COMPOSER_FLAGS="" install: - composer update $COMPOSER_FLAGS --no-interaction script: - "./vendor/bin/phpunit" before_deploy: - "composer require kherge/box:~2.5" - "composer update --prefer-lowest" - "./vendor/bin/box build" deploy: provider: releases api_key: secure: k+qvKnFTICcFZzx868c7IfM2fneyiA2F5RdDmFmTAhAulxAVnxnNcJBul4iBdZeE5UATaqK/Jydkj66safJZNdBz8z3yILf3redNamOO3np0TM9vo8QCjE+PMEOnDL5sY+7DgfEW3sApClRnWwqK0+X6UjPypktF6PfFMLVxqeXklTOxHuwn9JYmlTWb3CQYLOJ/dyDxPGMelDhHR4A0WD71J/8+XjJIm3zppJMae33b5FE7XavOT2d2LyDtfVjMMXxWys4a8W+Q5KkT+TrejD2J+zluB++eqNBH5hU+/jVq14qflI8gfQ1B/uZxMj1YbBfOTNpG/9oPdDJ7Yk2XspfzxbmzUtVccZt2iEQxAmoD1HJ9F2StWSdksUa2GGIhKuYi8iRK4r1UwOp98/wFmAURsDp0jbkkWdys3Pv4Jp8zLwZvqX0jT/T6F0hIaOBrS9408R+QQz0kZOQ6sLuBo0tt5v5lczg4DpsbkaXj+4RcTEbOl44s8sUdtAsoyLotT4a14kKteNtyS5rI155qFS3uNM+oTzpaor4Aa/bfbA9D2mBbOXblXWjvGqFlouHJPjwbFU+rRcCCZyG1hG+Vf4YVUEPnVvXLuecWeY7tMvNEQe5Ne5MzhBOS4+LlukcfbwLemBpD8w+SQkKd2wahGtE/x5YNTeSQo+AlDJnXx+c= file: php7cc.phar skip_cleanup: true on: repo: sstalle/php7cc php: 5.6 tags: true condition: "$COMPOSER_FLAGS = --prefer-lowest" php7cc-1.1.0/CHANGELOG.md000066400000000000000000000012101271610560000144760ustar00rootroot00000000000000## Version 1.1-dev * Added warning for setting cookies with empty names * Added color differentiation between error messages and warnings * Added the ```--level (-l)``` option to specify minimum reported issue level * Added the ```--relative-paths (-r)``` option to output file paths relative to checked directories * Added the ```--integer-size``` option to specify integer size of the target system * Fixed detection of non-lowercase function names ## Version 1.0.2 * Fixed notice in ```PHP4ConstructorVisitor``` caused by anonymous classes ## Version 1.0.1 * Fixed ```ReflectionException``` in ```ContainerBuilder::addVisitors``` on PHP 5.3.3 php7cc-1.1.0/CONTRIBUTING.md000066400000000000000000000101221271610560000151200ustar00rootroot00000000000000# Contributing First of all, **thank you** for contributing, **you are awesome**! This project uses the fork & pull model of development. This means that in order to contribute you need to submit a [pull request](https://help.github.com/articles/using-pull-requests/). For relatively small features, improvements and bug fixes ([example](https://github.com/sstalle/php7cc/commit/a9f40a363fab2b24506465f8849a82cb3542739a)), you can submit pull requests without prior discussion. If you are planning on doing something that requires a lot of changes and/or big refactoring ([example](https://github.com/sstalle/php7cc/commit/600f0f9848af1f5ab631114304e0683d512f532b)), please open an issue first so it can be thoroughly considered and examined. Here are a few rules to follow in order to ease code reviews and discussions before maintainers accept and merge your work: * [Follow the coding standards](#coding-standards) * [Run and update the tests](#running-and-updating-test-suite) * [Document your work](#documenting-your-work) Please [rebase your branch](http://git-scm.com/book/en/Git-Branching-Rebasing) before submitting your Pull Request. One may ask you to [squash your commits](http://gitready.com/advanced/2009/02/10/squashing-commits-with-rebase.html) too. This is used to "clean" your Pull Request before merging it (we don't want commits such as `fix tests`, `fix 2`, `fix 3`, etc.). ## Coding standards You MUST follow the [PSR-1](http://www.php-fig.org/psr/1/), [PSR-2](http://www.php-fig.org/psr/2/) and [Symfony Coding Standard](http://symfony.com/doc/current/contributing/code/standards.html) (the only exception is that you must add single spaces around the concatenation operator). If you don't know about any of them, you should really read the recommendations. To fix your code according to the project standards, you can run [PHP-CS-Fixer tool](http://cs.sensiolabs.org/) before commit: ```bash vendor/bin/php-cs-fixer fix . --config-file=.php_cs ``` ## Running and updating test suite * You MUST run the test suite. * You MUST write tests for PHP 7 compatibility errors. * You SHOULD write (or update) unit tests for any other non-trivial functionality. Test suite can be run using the following command: ```bash vendor/bin/phpunit ``` In most cases you should not write unit tests for compatibility violation checking visitors (like the ones found in ```src/NodeVisitor```). To test them, you should create a subfolder in ```test/resource``` folder and put a ```.test``` file in it. ```.test``` files have multiple sections separated by `-----`: 1. First section is the description of the test suite. It can also contain PHP version constraint. 2. Second section is the php code to be tested. It must be syntactically correct, unless it is an expression or a statement that had been correct in PHP 5 but is no longer correct in PHP 7. 3. Third section is a newline separated array of messages and errors that should be emitted for the code from the previous section. Errors are instances of \Exception and \ParseException that are thrown during the checks. If there should be no messages and no errors, just leave a blank like in this section. Please keep in mind that test suites are not isolated, so you may get messages from other checkers in your test suite. Second and third sections can be repeated one or more times. Some tests require a particular version of PHP. For example, the `yield` keyword had been introduced in PHP 5.5, and tests containing it cannot be run on the lower versions. To specify a version constraint for the test suite, add a new line of the following format to the first section: ``` PHP ``` Operator is one of the operators supported by `version_compare` function. Multiple space separated constraints can be specified. ## Documenting your work You SHOULD write documentation for the code you add. Also, please, write [commit messages that make sense](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html). While creating your Pull Request on GitHub, you MUST write a description which gives the context and/or explains why you are creating it. Thank you! php7cc-1.1.0/LICENSE000066400000000000000000000020631271610560000137010ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) 2015 sstalle Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. php7cc-1.1.0/README.md000066400000000000000000000125121271610560000141530ustar00rootroot00000000000000# PHP 7 Compatibility Checker(php7cc) #### Introduction php7cc is a command line tool designed to make migration from PHP 5.3-5.6 to PHP 7 easier. It searches for potentially troublesome statements in existing code and generates reports containing file names, line numbers and short problem descriptions. It does not automatically fix code to work with the new PHP version. #### What kind of problems does it detect? There are 2 types of issues reported by php7cc: 1. **Errors** that will definitely cause some kind of trouble (a fatal, a syntax error, a notice, etc.) on PHP 7. These are highlighted in red. 2. **Warnings** that may or may not lead to logical errors. For example, statements that are legal in both PHP 5 and PHP 7, but change their behaviour between versions fall into this category. Warnings are highlighted in yellow. A list of statements that may cause errors or warnings to be reported can be found in the [php-src repository](https://github.com/php/php-src/blob/PHP-7.0/UPGRADING). ***Although php7cc tries to detect as much problems as accurately as possible, sometimes 100% reliable detection is very hard to achieve. That's why you should also run a comprehensive test suite for the code you are going to migrate.*** # Prerequisites To run php7cc, you need php installed, minimum required version is 5.3.3. PHP 7 is supported, but files with syntax errors (for example, invalid numeric literals or invalid UTF-8 codepoint escape sequences) can't be processed. You will only get the warning message about the first syntax error for such files. You may also need [composer](https://getcomposer.org/) to install php7cc. # Installation #### Phar package You can download a phar package for any stable version from the Github [releases](https://github.com/sstalle/php7cc/releases) page. #### Composer (globally) Make sure you have composer installed. Then execute the following command: ```bash composer global require sstalle/php7cc ``` It is also recommended to add ```~/.composer/vendor/bin``` to your ```PATH``` environment variable: ```bash export PATH="$PATH:$HOME/.composer/vendor/bin" ``` This makes it possible to run php7cc by entering just the executable name. #### Composer (locally, per project) Make sure you have composer installed. Then execute the following command from your project directory: ```bash composer require sstalle/php7cc --dev ``` #### Docker image A docker image is available on [Docker Hub](https://hub.docker.com/r/ypereirareis/php7cc/) (contributed and maintained by [ypereirareis](https://github.com/ypereirareis)). # Usage Examples in this section assume that you have installed php7cc globally using composer and that you have added it's vendor binaries directory to your ```PATH```. If this is not the case, just substitute ```php7cc``` with the correct path to the binary of phar package. For local per project installation the executable will be located at ```/vendor/bin/php7cc```. #### Getting help To see the full list of available options, run: ```bash php7cc --help ``` #### Checking a single file or directory To check a file or a directory, pass its name as the first argument. Directories are checked recursively. So, to check a file you could run: ```bash php7cc /path/to/my/file.php ``` To check a directory: ```bash php7cc /path/to/my/directory/ ``` #### Specifying file extensions to check When checking a directory, you can also specify a comma-separated list of file extensions that should be checked. By default, only .php files are processed. For example, if you want to check .php, .inc and .lib files, you could run: ```bash php7cc --extensions=php,inc,lib /path/to/my/directory/ ``` #### Excluding file or directories You can specify a list of absolute or relative paths to exclude from checking. Relative paths are relative to the checked directories. So, if you want to exclude vendor and test directories, you could run: ```bash php7cc --except=vendor --except=/path/to/my/directory/test /path/to/my/directory/ ``` In this example, directories ```/path/to/my/directory/vendor```, ```/path/to/my/directory/test``` and their contents will not be checked. #### Specifying minimum issue level If you set a minimum issue level, only issues having that or higher severity level will be reported by `php7cc`. There are 3 issue levels: "info", "warning" and "error". "info" is reserved for future use and is the same as "warning". Example usage: ```bash php7cc --level=error /path/to/my/directory/ ``` Only errors, but not warnings will be shown in this case. # Troubleshooting #### Maximum function nesting level of 100/250/N reached, aborting! You should increase maximum function nesting level in your PHP or Xdebug config file like this: ```cfg xdebug.max_nesting_level = 1000 ``` #### Allowed memory size of N bytes exhausted You should increase amount of memory available to CLI PHP scripts or disable PHP memory limit. The latter can be done by setting the `memory_limit` PHP option to -1. This option can be set by editing `php.ini` or by passing a command-line argument to PHP executable like this: ```bash php -d memory_limit=-1 php7cc.php /path/to/my/directory ``` # Other useful links #### Contributing Please read the [contributing guidelines](CONTRIBUTING.md). #### Credits [The list of contributors](https://github.com/sstalle/php7cc/graphs/contributors) is available on the corresponding Github page. php7cc-1.1.0/bin/000077500000000000000000000000001271610560000134435ustar00rootroot00000000000000php7cc-1.1.0/bin/php7cc000066400000000000000000000000721271610560000145510ustar00rootroot00000000000000#!/usr/bin/env php run(); php7cc-1.1.0/box.json000066400000000000000000000013411271610560000143550ustar00rootroot00000000000000{ "chmod": "0755", "directories": [ "src", "bin" ], "finder": [ { "exclude": [ "mikey179", "phpunit", "phpspec", "phpdocumentor", "sebastian", "phpseclib", "fabpot", "phine", "justinrainbow", "herrera-io", "seld", "doctrine", "tedivm", "kherge" ], "in": [ "vendor" ] } ], "files": [ "LICENSE", "README.md", "vendor/phpseclib/phpseclib/phpseclib/Crypt/Random.php", "vendor/herrera-io/json/src/lib/json_version.php", "vendor/herrera-io/phar-update/src/lib/constants.php" ], "main": "bin/php7cc.php", "output": "php7cc.phar", "stub": true }php7cc-1.1.0/composer.json000066400000000000000000000012161271610560000154150ustar00rootroot00000000000000{ "name": "sstalle/php7cc", "type": "project", "description": "A command-line tool to check PHP 5.3 - 5.6 code compatibility with PHP 7", "license": "MIT", "autoload": { "psr-4": { "Sstalle\\php7cc\\": "src/" } }, "require": { "php": ">=5.3.3", "symfony/console": "~2.3 || ~3.0", "symfony/finder": "~2.3 || ~3.0", "pimple/pimple": "~3.0", "nikic/php-parser": "~1.4" }, "require-dev": { "phpunit/phpunit": "4.7.*", "mikey179/vfsStream": "~1.5", "fabpot/php-cs-fixer": "~1.10" }, "bin": [ "bin/php7cc" ], "extra": { "branch-alias": { "dev-master": "1.1-dev" } } } php7cc-1.1.0/phpunit.xml.dist000066400000000000000000000012761271610560000160540ustar00rootroot00000000000000 ./test/ php7cc-1.1.0/src/000077500000000000000000000000001271610560000134625ustar00rootroot00000000000000php7cc-1.1.0/src/AbstractBaseMessage.php000066400000000000000000000015441271610560000200420ustar00rootroot00000000000000rawText = $text; $this->line = $line; $this->text = $this->generateText(); } /** * @return string */ public function getRawText() { return $this->rawText; } /** * @return string */ public function getText() { return $this->text; } /** * @return int */ public function getLine() { return $this->line; } abstract protected function generateText(); } php7cc-1.1.0/src/CLIOutputInterface.php000066400000000000000000000003501271610560000176420ustar00rootroot00000000000000 null, Message::LEVEL_WARNING => 'yellow', Message::LEVEL_ERROR => 'red', ); /** * @var CLIOutputInterface */ protected $output; /** * @var StandardPrettyPrinter */ protected $prettyPrinter; /** * @var NodeStatementsRemover */ protected $nodeStatementsRemover; /** * @param CLIOutputInterface $output * @param StandardPrettyPrinter $prettyPrinter * @param NodeStatementsRemover $nodeStatementsRemover */ public function __construct( CLIOutputInterface $output, StandardPrettyPrinter $prettyPrinter, NodeStatementsRemover $nodeStatementsRemover ) { $this->output = $output; $this->prettyPrinter = $prettyPrinter; $this->nodeStatementsRemover = $nodeStatementsRemover; } /** * {@inheritdoc} */ public function printContext(ContextInterface $context) { $this->output->writeln(''); $this->output->writeln(sprintf('File: %s', $context->getCheckedResourceName())); foreach ($context->getMessages() as $message) { $this->output->writeln( $this->formatMessage($message) ); } foreach ($context->getErrors() as $error) { $this->output->writeln( sprintf( '> %s', $error->getText() ) ); } $this->output->writeln(''); } /** * {@inheritdoc} */ public function printMetadata(CheckMetadata $metadata) { $checkedFileCount = $metadata->getCheckedFileCount(); $elapsedTime = $metadata->getElapsedTime(); $this->output->writeln( sprintf( 'Checked %d file%s in %.3f second%s', $checkedFileCount, $checkedFileCount > 1 ? 's' : '', $elapsedTime, $elapsedTime > 1 ? 's' : '' ) ); } /** * @param Message $message * * @return string */ private function formatMessage(Message $message) { $nodes = $this->nodeStatementsRemover->removeInnerStatements($message->getNodes()); $prettyPrintedNodes = str_replace("\n", "\n ", $this->prettyPrinter->prettyPrint($nodes)); $text = $message->getRawText(); $color = self::$colors[$message->getLevel()]; if ($color) { $text = sprintf( '%s', $color, $text, $color ); } return sprintf( "> Line %s: %s\n %s", $message->getLine(), $text, $prettyPrintedNodes ); } } php7cc-1.1.0/src/CompatibilityViolation/000077500000000000000000000000001271610560000201605ustar00rootroot00000000000000php7cc-1.1.0/src/CompatibilityViolation/AbstractContext.php000066400000000000000000000017121271610560000240020ustar00rootroot00000000000000messages[] = $message; } /** * @return array|Message[] */ public function getMessages() { return $this->messages; } /** * {@inheritdoc} */ public function addError(CheckError $error) { $this->errors[] = $error; } /** * {@inheritdoc} */ public function getErrors() { return $this->errors; } /** * {@inheritdoc} */ public function hasMessagesOrErrors() { return $this->messages || $this->errors; } } php7cc-1.1.0/src/CompatibilityViolation/CheckMetadata.php000066400000000000000000000016531271610560000233540ustar00rootroot00000000000000startTime = microtime(true); } public function endCheck() { $this->endTime = microtime(true); } /** * @return float In seconds */ public function getElapsedTime() { $endTime = $this->endTime; if ($endTime === null) { $endTime = microtime(true); } return $endTime - $this->startTime; } /** * @return int */ public function getCheckedFileCount() { return $this->checkedFileCount; } public function incrementCheckedFileCount() { ++$this->checkedFileCount; } } php7cc-1.1.0/src/CompatibilityViolation/ContextInterface.php000066400000000000000000000013161271610560000241370ustar00rootroot00000000000000file = $file; $this->useRelativePaths = $useRelativePaths; } /** * @return SplFileInfo */ public function getFile() { return $this->file; } /** * {@inheritdoc} */ public function getCheckedResourceName() { $file = $this->getFile(); return $this->useRelativePaths ? $file->getRelativePathname() : $file->getRealPath(); } /** * {@inheritdoc} */ public function getCheckedCode() { return $this->getFile()->getContents(); } } php7cc-1.1.0/src/CompatibilityViolation/Message.php000066400000000000000000000020471271610560000222600ustar00rootroot00000000000000level = $level; $this->nodes = $nodes; } /** * @return int */ public function getLevel() { return $this->level; } /** * @return Node[] */ public function getNodes() { return $this->nodes; } protected function generateText() { return sprintf('Line %d. %s', $this->getLine(), $this->getRawText()); } } php7cc-1.1.0/src/CompatibilityViolation/StringContext.php000066400000000000000000000014071271610560000235060ustar00rootroot00000000000000checkedCode = $checkedCode; $this->checkedResourceName = $checkedResourceName; } /** * {@inheritdoc} */ public function getCheckedResourceName() { return $this->checkedResourceName; } /** * {@inheritdoc} */ public function getCheckedCode() { return $this->checkedCode; } } php7cc-1.1.0/src/ContextChecker.php000066400000000000000000000026211271610560000171050ustar00rootroot00000000000000parser = $parser; $this->lexer = $lexer; $this->traverser = $traverser; } /** * @param ContextInterface $context * * @return FileContext */ public function checkContext(ContextInterface $context) { try { $parsedStatements = $this->parser->parse($context->getCheckedCode()); $this->traverser->traverse($parsedStatements, $context, $this->lexer->getTokens()); } catch (\Exception $e) { $context->addError(new CheckError($e->getMessage())); } catch (\ParseException $e) { $context->addError(new CheckError($e->getMessage(), $e->getLine())); } } } php7cc-1.1.0/src/Error/000077500000000000000000000000001271610560000145535ustar00rootroot00000000000000php7cc-1.1.0/src/Error/CheckError.php000066400000000000000000000005711271610560000173160ustar00rootroot00000000000000getRawText(); if ($this->getLine()) { $text = sprintf('Line %d. %s', $this->getLine(), $text); } return $text . '. Processing aborted.'; } } php7cc-1.1.0/src/ExcludedPathCanonicalizer.php000066400000000000000000000026261271610560000212550ustar00rootroot00000000000000pathHelper = $pathHelper; } /** * Makes all excluded paths absolute. Non-existent paths are removed. * * @param string[] $checkedPaths * @param string[] $excludedPaths * * @return \string[] */ public function canonicalize(array $checkedPaths, array $excludedPaths) { $checkedDirectories = array_filter($checkedPaths, function ($path) { return is_dir($path); }); $canonicalizedPaths = array(); foreach ($excludedPaths as $path) { if (!$this->pathHelper->isDirectoryRelative($path) && ($canonicalizedPath = realpath($path))) { $canonicalizedPaths[] = $canonicalizedPath; } else { foreach ($checkedDirectories as $checkedDirectory) { $nestedExcludedDirectory = realpath(realpath($checkedDirectory) . DIRECTORY_SEPARATOR . $path); $nestedExcludedDirectory && $canonicalizedPaths[] = $nestedExcludedDirectory; } } } return $canonicalizedPaths; } } php7cc-1.1.0/src/Helper/000077500000000000000000000000001271610560000147015ustar00rootroot00000000000000php7cc-1.1.0/src/Helper/OSDetector.php000066400000000000000000000002261271610560000174250ustar00rootroot00000000000000osDetector = $osDetector; } /** * @return PathHelperInterface */ public function createPathHelper() { return $this->osDetector->isWindows() ? new WindowsPathHelper() : new UnixPathHelper(); } } php7cc-1.1.0/src/Helper/Path/PathHelperInterface.php000066400000000000000000000004641271610560000221670ustar00rootroot00000000000000isAbsolute($path); } } php7cc-1.1.0/src/Helper/Path/WindowsPathHelper.php000066400000000000000000000007461271610560000217240ustar00rootroot00000000000000isAbsolute($path) && preg_match('#^[a-zA-Z]\\:(?!\\\\)#', $path) === 0); } } php7cc-1.1.0/src/Helper/RegExp/000077500000000000000000000000001271610560000160735ustar00rootroot00000000000000php7cc-1.1.0/src/Helper/RegExp/RegExp.php000066400000000000000000000051041271610560000177760ustar00rootroot00000000000000 ')', '[' => ']', '{' => '}', '<' => '>', ); /** * @var string */ protected $startDelimiter; /** * @var string */ protected $endDelimiter; /** * @var string */ protected $expression; /** * @var string */ protected $modifiers; /** * @param string $startDelimiter * @param string $endDelimiter * @param string $expression * @param string $modifiers */ public function __construct($startDelimiter, $endDelimiter, $expression, $modifiers) { if (!$startDelimiter || !$endDelimiter) { throw new \InvalidArgumentException('Delimiter must not be empty'); } foreach (array($startDelimiter, $endDelimiter) as $delimiter) { if (preg_match('/[\\\\a-z0-9\s+]/', strtolower($delimiter)) === 1) { throw new \InvalidArgumentException(sprintf('Invalid delimiter %s used', $startDelimiter)); } } $hasPairedDelimiter = isset(static::$delimiterPairs[$startDelimiter]); if (($hasPairedDelimiter && static::$delimiterPairs[$startDelimiter] !== $endDelimiter) || (!$hasPairedDelimiter && $startDelimiter !== $endDelimiter) ) { throw new \InvalidArgumentException( sprintf('Start delimiter %s does not match end delimiter %s', $startDelimiter, $endDelimiter) ); } $this->startDelimiter = $startDelimiter; $this->endDelimiter = $endDelimiter; $this->expression = $expression; $this->modifiers = $modifiers; } /** * @return string */ public function getStartDelimiter() { return $this->startDelimiter; } /** * @return string */ public function getEndDelimiter() { return $this->endDelimiter; } /** * @return string */ public function getExpression() { return $this->expression; } /** * @return string */ public function getModifiers() { return $this->modifiers; } /** * @param string $modifier * * @return bool */ public function hasModifier($modifier) { return strpos($this->getModifiers(), $modifier) !== false; } /** * @return string */ public static function getDelimiterPairs() { return self::$delimiterPairs; } } php7cc-1.1.0/src/Helper/RegExp/RegExpParser.php000066400000000000000000000017011271610560000211520ustar00rootroot00000000000000setArguments(); return $inputDefinition; } /** * {@inheritdoc} */ protected function getCommandName(InputInterface $input) { return PHP7CCCommand::COMMAND_NAME; } /** * {@inheritdoc} */ protected function getDefaultCommands() { $defaultCommands = parent::getDefaultCommands(); $defaultCommands[] = new PHP7CCCommand(); return $defaultCommands; } } php7cc-1.1.0/src/Infrastructure/CLIOutputBridge.php000066400000000000000000000012431271610560000221600ustar00rootroot00000000000000output = $output; } /** * {@inheritdoc} */ public function write($string) { $this->output->write($string); } /** * {@inheritdoc} */ public function writeln($string) { $this->output->writeln($string); } } php7cc-1.1.0/src/Infrastructure/ContainerBuilder.php000066400000000000000000000246511271610560000224540ustar00rootroot00000000000000 array( 'class' => '\\Sstalle\\php7cc\\NodeVisitor\\RemovedFunctionCallVisitor', 'dependencies' => array('nodeAnalyzer.functionAnalyzer'), ), 'visitor.reservedClassName' => array( 'class' => '\\Sstalle\\php7cc\\NodeVisitor\\ReservedClassNameVisitor', 'dependencies' => array('nodeAnalyzer.functionAnalyzer'), ), 'visitor.duplicateFunctionParameter' => array( 'class' => '\\Sstalle\\php7cc\\NodeVisitor\\DuplicateFunctionParameterVisitor', ), 'visitor.list' => array( 'class' => '\\Sstalle\\php7cc\\NodeVisitor\\ListVisitor', ), 'visitor.globalVariableVariable' => array( 'class' => '\\Sstalle\\php7cc\\NodeVisitor\\GlobalVariableVariableVisitor', ), 'visitor.indirectVariableOrMethodAccess' => array( 'class' => '\\Sstalle\\php7cc\\NodeVisitor\\IndirectVariableOrMethodAccessVisitor', ), 'visitor.funcGetArgs' => array( 'class' => '\\Sstalle\\php7cc\\NodeVisitor\\FuncGetArgsVisitor', 'dependencies' => array('nodeAnalyzer.functionAnalyzer'), ), 'visitor.foreach' => array( 'class' => '\\Sstalle\\php7cc\\NodeVisitor\\ForeachVisitor', 'dependencies' => array('nodeAnalyzer.functionAnalyzer'), ), 'visitor.invalidOctalLiteral' => array( 'class' => '\\Sstalle\\php7cc\\NodeVisitor\\InvalidOctalLiteralVisitor', ), 'visitor.hexadecimalNumberString' => array( 'class' => '\\Sstalle\\php7cc\\NodeVisitor\\HexadecimalNumberStringVisitor', ), 'visitor.escapedUnicodeCodepoint' => array( 'class' => '\\Sstalle\\php7cc\\NodeVisitor\\EscapedUnicodeCodepointVisitor', ), 'visitor.arrayOrObjectValueAssignmentByReference' => array( 'class' => '\\Sstalle\\php7cc\\NodeVisitor\\ArrayOrObjectValueAssignmentByReferenceVisitor', ), self::BITWISE_SHIFT_VISITOR_ID => array( 'class' => '\\Sstalle\\php7cc\\NodeVisitor\\BitwiseShiftVisitor', 'arguments' => array(), ), 'visitor.newAssignmentByReference' => array( 'class' => '\\Sstalle\\php7cc\\NodeVisitor\\NewAssignmentByReferenceVisitor', ), 'visitor.httpRawPostData' => array( 'class' => '\\Sstalle\\php7cc\\NodeVisitor\\HTTPRawPostDataVisitor', ), 'visitor.pregReplaceEval' => array( 'class' => '\\Sstalle\\php7cc\\NodeVisitor\\PregReplaceEvalVisitor', 'dependencies' => array('regExpParser', 'nodeAnalyzer.functionAnalyzer'), ), 'visitor.yieldExpression' => array( 'class' => '\\Sstalle\\php7cc\\NodeVisitor\\YieldExpressionVisitor', ), 'visitor.yieldInExpressionContext' => array( 'class' => '\\Sstalle\\php7cc\\NodeVisitor\\YieldInExpressionContextVisitor', ), 'visitor.mktime' => array( 'class' => '\\Sstalle\\php7cc\\NodeVisitor\\MktimeVisitor', 'dependencies' => array('nodeAnalyzer.functionAnalyzer'), ), 'visitor.multipleSwitchDefaults' => array( 'class' => '\\Sstalle\\php7cc\\NodeVisitor\\MultipleSwitchDefaultsVisitor', ), 'visitor.passwordHashSalt' => array( 'class' => '\\Sstalle\\php7cc\\NodeVisitor\\PasswordHashSaltVisitor', 'dependencies' => array('nodeAnalyzer.functionAnalyzer'), ), 'visitor.newClass' => array( 'class' => '\\Sstalle\\php7cc\\NodeVisitor\\NewClassVisitor', ), 'visitor.php4Constructor' => array( 'class' => '\\Sstalle\\php7cc\\NodeVisitor\\PHP4ConstructorVisitor', ), 'visitor.namespacedNewFunction' => array( 'class' => '\\Sstalle\\php7cc\\NodeVisitor\\NamespacedNewFunctionVisitor', ), 'visitor.globalNewFunction' => array( 'class' => '\\Sstalle\\php7cc\\NodeVisitor\\GlobalNewFunctionVisitor', ), 'visitor.divisionModuloByZero' => array( 'class' => '\\Sstalle\\php7cc\\NodeVisitor\\DivisionModuloByZeroVisitor', ), 'visitor.sessionSetSaveHandler' => array( 'class' => '\\Sstalle\\php7cc\\NodeVisitor\\SessionSetSaveHandlerVisitor', 'dependencies' => array('nodeAnalyzer.functionAnalyzer'), ), 'visitor.setcookieEmptyName' => array( 'class' => '\\Sstalle\\php7cc\\NodeVisitor\\SetcookieEmptyNameVisitor', 'dependencies' => array('nodeAnalyzer.functionAnalyzer'), ), ); /** * @param OutputInterface $output * @param int $intSize * * @return Container */ public function buildContainer(OutputInterface $output, $intSize) { $this->checkerVisitors[static::BITWISE_SHIFT_VISITOR_ID]['arguments'][] = $intSize; $container = new Container(); $container['lexer'] = function () { return new ExtendedLexer(array( 'usedAttributes' => array( 'startLine', 'endLine', 'startTokenPos', 'endTokenPos', ), )); }; $container['parser'] = function ($c) { return new Parser($c['lexer']); }; $this->addVisitors($container); $visitors = $this->checkerVisitors; $container['traverser'] = function () { $traverser = new Traverser(false); // Resolve fully qualified name (class, interface, function, etc) to ease some process $traverser->addVisitor(new NameResolver()); return $traverser; }; $container['nodeVisitorResolver'] = function ($c) use ($visitors) { $visitorInstances = array(); foreach (array_keys($visitors) as $visitorServiceName) { $visitorInstances[] = $c[$visitorServiceName]; } return new Resolver($visitorInstances); }; $container['nodeAnalyzer.functionAnalyzer'] = function () { return new FunctionAnalyzer(); }; $container['contextChecker'] = function ($c) { return new ContextChecker($c['parser'], $c['lexer'], $c['traverser']); }; $container['output'] = function () use ($output) { return new CLIOutputBridge($output); }; $container['nodePrinter'] = function () { return new StandardPrettyPrinter(); }; $container['resultPrinter'] = function ($c) { return new CLIResultPrinter($c['output'], $c['nodePrinter'], $c['nodeStatementsRemover']); }; $container['pathChecker'] = function ($c) { return new PathChecker($c['contextChecker'], $c['resultPrinter']); }; $container['nodeStatementsRemover'] = function () { return new NodeStatementsRemover(); }; $container['pathTraversableFactory'] = function ($c) { return new PathTraversableFactory($c['excludedPathCanonicalizer']); }; $container['pathCheckExecutor'] = function ($c) { return new PathCheckExecutor($c['pathTraversableFactory'], $c['pathChecker'], $c['traverser'], $c['nodeVisitorResolver']); }; $container['excludedPathCanonicalizer'] = function ($c) { return new ExcludedPathCanonicalizer($c['pathHelper']); }; $container['osDetector'] = function () { return new OSDetector(); }; $container['pathHelperFactory'] = function ($c) { return new PathHelperFactory($c['osDetector']); }; $container['pathHelper'] = function ($c) { /** @var PathHelperFactory $pathHelperFactory */ $pathHelperFactory = $c['pathHelperFactory']; return $pathHelperFactory->createPathHelper(); }; $container['regExpParser'] = function () { return new RegExpParser(); }; return $container; } protected function addVisitors(Container $container) { foreach ($this->checkerVisitors as $visitorServiceName => $visitorParameters) { $container[$visitorServiceName] = function ($c) use ($visitorParameters) { $visitorDependencyServiceNames = isset($visitorParameters['dependencies']) ? $visitorParameters['dependencies'] : array(); $otherVisitorArguments = isset($visitorParameters['arguments']) ? $visitorParameters['arguments'] : array(); $visitorClassName = $visitorParameters['class']; if (!$visitorDependencyServiceNames && !$otherVisitorArguments) { /* This early return is required, because a ReflectionException is thrown * from ReflectionClass::newInstanceArgs for classes without constructors * on PHP 5.3.3 */ return new $visitorClassName(); } $visitorClassReflection = new \ReflectionClass($visitorClassName); $visitorDependencies = array(); foreach ($visitorDependencyServiceNames as $serviceName) { $visitorDependencies[] = $c[$serviceName]; } return $visitorClassReflection->newInstanceArgs( array_merge($visitorDependencies, $otherVisitorArguments) ); }; } } } php7cc-1.1.0/src/Infrastructure/PHP7CCCommand.php000066400000000000000000000112101271610560000214310ustar00rootroot00000000000000 Message::LEVEL_INFO, 'warning' => Message::LEVEL_WARNING, 'error' => Message::LEVEL_ERROR, ); /** * {@inheritdoc} */ protected function configure() { $this->setName(static::COMMAND_NAME) ->setDescription('Checks PHP 5.3 - 5.6 code for compatibility with PHP7') ->addArgument( static::PATHS_ARGUMENT_NAME, InputArgument::REQUIRED | InputArgument::IS_ARRAY, 'Which file or directory do you want to check?' )->addOption( static::EXTENSIONS_OPTION_NAME, 'e', InputOption::VALUE_OPTIONAL, 'Which file extensions do you want to check (separate multiple extensions with commas)?', 'php' )->addOption( static::EXCEPT_OPTION_NAME, 'x', InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'Excluded files and directories', array() )->addOption( static::MESSAGE_LEVEL_OPTION_NAME, 'l', InputOption::VALUE_REQUIRED, 'Only show messages having this or higher severity level (can be info, message or warning)', 'info' )->addOption( static::RELATIVE_PATHS_OPTION_NAME, 'r', InputOption::VALUE_NONE, 'Output paths relative to a checked directory instead of full paths to files' )->addOption( static::INT_SIZE_OPTION_NAME, null, InputOption::VALUE_REQUIRED, 'Target system\'s integer size in bits (needed for bitwise shift checks)', BitwiseShiftVisitor::MIN_INT_SIZE ); } /** * {@inheritdoc} */ protected function execute(InputInterface $input, OutputInterface $output) { $paths = $input->getArgument(static::PATHS_ARGUMENT_NAME); foreach ($paths as $path) { if (!is_file($path) && !is_dir($path)) { $output->writeln(sprintf('Path %s must be a file or a directory', $path)); return; } } $extensionsArgumentValue = $input->getOption(static::EXTENSIONS_OPTION_NAME); $extensions = explode(',', $extensionsArgumentValue); if (!is_array($extensions)) { $output->writeln( sprintf( 'Something went wrong while parsing file extensions you specified. ' . 'Check that %s is a comma-separated list of extensions', $extensionsArgumentValue ) ); return; } $messageLevelName = $input->getOption(static::MESSAGE_LEVEL_OPTION_NAME); if (!isset(static::$messageLevelMap[$messageLevelName])) { $output->writeln(sprintf('Unknown message level %s', $messageLevelName)); return; } $messageLevel = static::$messageLevelMap[$messageLevelName]; $intSize = (int) $input->getOption(static::INT_SIZE_OPTION_NAME); if ($intSize <= 0) { $output->writeln('Integer size must be greater than 0'); return; } $containerBuilder = new ContainerBuilder(); $container = $containerBuilder->buildContainer($output, $intSize); $checkSettings = new PathCheckSettings($paths, $extensions); $checkSettings->setExcludedPaths($input->getOption(static::EXCEPT_OPTION_NAME)); $checkSettings->setMessageLevel($messageLevel); $checkSettings->setUseRelativePaths($input->getOption(static::RELATIVE_PATHS_OPTION_NAME)); $container['pathCheckExecutor']->check($checkSettings); } } php7cc-1.1.0/src/Iterator/000077500000000000000000000000001271610560000152535ustar00rootroot00000000000000php7cc-1.1.0/src/Iterator/AbstractRecursiveFilterIterator.php000066400000000000000000000020571271610560000243030ustar00rootroot00000000000000getFlags(); if ($iteratorFlags & \RecursiveDirectoryIterator::CURRENT_AS_PATHNAME || $iteratorFlags & \RecursiveDirectoryIterator::CURRENT_AS_SELF ) { throw new \InvalidArgumentException( 'This iterator requires \RecursiveDirectoryIterator with CURRENT_AS_FILEINFO flag set' ); } if ($iteratorFlags & \RecursiveDirectoryIterator::KEY_AS_FILENAME) { throw new \InvalidArgumentException( 'This iterator requires \RecursiveDirectoryIterator with KEY_AS_PATHNAME flag set' ); } } parent::__construct($iterator); } } php7cc-1.1.0/src/Iterator/ExcludedPathFilteringRecursiveIterator.php000066400000000000000000000015171271610560000256100ustar00rootroot00000000000000excludedPaths = array_flip($excludedPaths); } /** * {@inheritdoc} */ public function accept() { return !isset($this->excludedPaths[realpath($this->key())]); } /** * {@inheritdoc} */ public function getChildren() { return new static($this->getInnerIterator()->getChildren(), array_flip($this->excludedPaths)); } } php7cc-1.1.0/src/Iterator/ExtensionFilteringRecursiveIterator.php000066400000000000000000000026561271610560000252170ustar00rootroot00000000000000allowedExtensions = $allowedExtensions; $this->alwaysAllowedFiles = array_flip($alwaysAllowedFiles); } /** * {@inheritdoc} */ public function accept() { $currentKey = $this->key(); $isFile = $currentKey && is_file($currentKey); if ($isFile && isset($this->alwaysAllowedFiles[realpath($currentKey)])) { return true; } return !$isFile || in_array(pathinfo($currentKey, PATHINFO_EXTENSION), $this->allowedExtensions); } /** * {@inheritdoc} */ public function getChildren() { return new static( $this->getInnerIterator()->getChildren(), $this->allowedExtensions, array_flip($this->alwaysAllowedFiles) ); } } php7cc-1.1.0/src/Iterator/FileDirectoryListRecursiveIterator.php000066400000000000000000000035571271610560000250000ustar00rootroot00000000000000data = $data; } /** * {@inheritdoc} */ public function current() { $fileName = realpath($this->data[$this->position]); return new SplFileInfo($fileName, '', basename($fileName)); } /** * {@inheritdoc} */ public function next() { ++$this->position; } /** * {@inheritdoc} */ public function key() { return $this->data[$this->position]; } /** * {@inheritdoc} */ public function valid() { return isset($this->data[$this->position]); } /** * {@inheritdoc} */ public function rewind() { $this->position = 0; } /** * {@inheritdoc} */ public function hasChildren() { return is_dir($this->data[$this->position]); } /** * {@inheritdoc} */ public function getChildren() { return new RecursiveDirectoryIterator( $this->data[$this->position], \RecursiveDirectoryIterator::KEY_AS_PATHNAME | \RecursiveDirectoryIterator::CURRENT_AS_FILEINFO | \RecursiveDirectoryIterator::SKIP_DOTS ); } } php7cc-1.1.0/src/Lexer/000077500000000000000000000000001271610560000145415ustar00rootroot00000000000000php7cc-1.1.0/src/Lexer/ExtendedLexer.php000066400000000000000000000017371271610560000200220ustar00rootroot00000000000000name instanceof Node\Name; if (!$isFunctionCallByStaticName) { return $isFunctionCallByStaticName; } $calledFunctionName = strtolower($node->name->toString()); return is_array($checkedFunctionName) ? isset($checkedFunctionName[$calledFunctionName]) : $calledFunctionName === $checkedFunctionName; } } php7cc-1.1.0/src/NodeStatementsRemover.php000066400000000000000000000013311271610560000204660ustar00rootroot00000000000000stmts = array(); } if ($node instanceof Node\Stmt\Switch_) { $node->cases = array(); } $resultNodes[] = $node; } return $resultNodes; } } php7cc-1.1.0/src/NodeTraverser/000077500000000000000000000000001271610560000162455ustar00rootroot00000000000000php7cc-1.1.0/src/NodeTraverser/Traverser.php000066400000000000000000000014771271610560000207440ustar00rootroot00000000000000visitors as $visitor) { if ($visitor instanceof VisitorInterface) { $visitor->initializeContext($context); $visitor->setTokenCollection($tokenCollection); } } } return parent::traverse($nodes); } } php7cc-1.1.0/src/NodeVisitor/000077500000000000000000000000001271610560000157275ustar00rootroot00000000000000php7cc-1.1.0/src/NodeVisitor/AbstractNewFunctionVisitor.php000066400000000000000000000026421271610560000237470ustar00rootroot00000000000000name)) && array_key_exists($lowerCasedFunction, self::$lowerCasedNewFunctions) && $this->accepts($node) ) { $this->addContextMessage($this->getMessageText(self::$lowerCasedNewFunctions[$lowerCasedFunction]), $node); } } /** * @param Node\Stmt\Function_ $node * * @return bool */ abstract protected function accepts(Node\Stmt\Function_ $node); /** * @param string $functionName * * @return string */ abstract protected function getMessageText($functionName); } php7cc-1.1.0/src/NodeVisitor/AbstractVisitor.php000066400000000000000000000023041271610560000215620ustar00rootroot00000000000000context = $context; } /** * {@inheritdoc} */ public function setTokenCollection(TokenCollection $tokenCollection) { $this->tokenCollection = $tokenCollection; } /** * {@inheritdoc} */ public function getLevel() { return static::LEVEL; } /** * @param string $text * @param Node $node */ protected function addContextMessage($text, Node $node) { $this->context->addMessage(new Message($text, $node->getAttribute('startLine'), $this->getLevel(), array($node))); } } php7cc-1.1.0/src/NodeVisitor/ArrayOrObjectValueAssignmentByReferenceVisitor.php000066400000000000000000000030501271610560000276640ustar00rootroot00000000000000checkArrayValueByReferenceCreation($node) || $this->checkObjectPropertyByReferenceCreation($node); } /** * @param Node\Expr\AssignRef $node * * @return bool */ protected function checkArrayValueByReferenceCreation(Node\Expr\AssignRef $node) { if ($node->var instanceof Node\Expr\ArrayDimFetch && $node->var->dim && $node->expr instanceof Node\Expr\ArrayDimFetch && $node->expr->dim ) { $this->addContextMessage( 'Possible array element creation during by-reference assignment', $node ); return true; } return false; } /** * @param Node\Expr\AssignRef $node * * @return bool */ protected function checkObjectPropertyByReferenceCreation(Node\Expr\AssignRef $node) { if ($node->var instanceof Node\Expr\PropertyFetch && $node->expr instanceof Node\Expr\PropertyFetch) { $this->addContextMessage( 'Possible object property creation during by-reference assignment', $node ); return true; } return false; } } php7cc-1.1.0/src/NodeVisitor/BitwiseShiftVisitor.php000066400000000000000000000026551271610560000224340ustar00rootroot00000000000000intSize = $intSize; } public function enterNode(Node $node) { $isLeftShift = $node instanceof Node\Expr\BinaryOp\ShiftLeft; $isRightShift = $node instanceof Node\Expr\BinaryOp\ShiftRight; if (!$isLeftShift && !$isRightShift) { return; } $rightOperand = $node->right; if ($rightOperand instanceof Node\Expr\UnaryMinus && $rightOperand->expr instanceof Node\Scalar\LNumber && $rightOperand->expr->value > 0 ) { $this->addContextMessage( 'Bitwise shift by a negative number', $node ); } elseif ($rightOperand instanceof Node\Scalar\LNumber && $rightOperand->value >= $this->intSize) { $this->addContextMessage( sprintf('Bitwise shift by %d bits', $rightOperand->value), $node ); } } } php7cc-1.1.0/src/NodeVisitor/DivisionModuloByZeroVisitor.php000066400000000000000000000015651271610560000241260ustar00rootroot00000000000000right : $node->expr; if ($divisor instanceof Node\Scalar\LNumber && $divisor->value == 0) { $this->addContextMessage( sprintf('%s by zero', $isDivision ? 'Division' : 'Modulo'), $node ); } } } php7cc-1.1.0/src/NodeVisitor/DuplicateFunctionParameterVisitor.php000066400000000000000000000017631271610560000253100ustar00rootroot00000000000000getParams() as $parameter) { $currentParameterName = $parameter->name; if (!isset($parametersNames[$currentParameterName])) { $parametersNames[$currentParameterName] = false; } elseif (!$parametersNames[$currentParameterName]) { $this->addContextMessage( sprintf('Duplicate function parameter name "%s"', $currentParameterName), $node ); $parametersNames[$currentParameterName] = true; } } } } php7cc-1.1.0/src/NodeVisitor/EscapedUnicodeCodepointVisitor.php000066400000000000000000000023641271610560000245450ustar00rootroot00000000000000getAttribute('isDoubleQuoted')) { $unquotedStringValue = substr($node->getAttribute('originalValue'), 1, -1); } elseif ($node->getAttribute('isHereDoc')) { // Skip T_START_HEREDOC, T_END_HEREDOC $unquotedStringValue = ''; foreach (range($node->getAttribute('startTokenPos') + 1, $node->getAttribute('endTokenPos') - 1) as $i) { $unquotedStringValue .= $this->tokenCollection->getTokenStringValueAt($i); } } if (!$unquotedStringValue) { return; } $matches = array(); if (preg_match('/((?addContextMessage( sprintf('Unicode codepoint escaping "%s" in a string', $matches[0]), $node ); } } } php7cc-1.1.0/src/NodeVisitor/ForeachVisitor.php000066400000000000000000000130161271610560000213700ustar00rootroot00000000000000functionAnalyzer = $functionAnalyzer; $this->foreachStack = new \SplStack(); $this->arrayPointerModifyingFunctions = array_flip($this->arrayPointerModifyingFunctions); $this->arrayModifyingFunctions = array_flip($this->arrayModifyingFunctions); } public function enterNode(Node $node) { if ($node instanceof Node\Stmt\Foreach_) { $this->checkNestedByReferenceForeach($node); $this->foreachStack->push($node); } elseif (!$this->foreachStack->isEmpty()) { $this->checkInternalArrayPointerAccessInByValueForeach($node); $this->checkArrayModificationByFunctionInByReferenceForeach($node); $this->checkAddingToArrayInByReferenceForeach($node); } } public function leaveNode(Node $node) { if ($node instanceof Node\Stmt\Foreach_) { $this->foreachStack->pop(); } } /** * @param Node $node */ protected function checkInternalArrayPointerAccessInByValueForeach(Node $node) { if ($this->hasFunctionCallWithForeachArgument($node, $this->arrayPointerModifyingFunctions, true)) { $this->addContextMessage( 'Possible internal array pointer access/modification in a by-value foreach loop', $node ); } } /** * @param Node $node */ protected function checkArrayModificationByFunctionInByReferenceForeach(Node $node) { if ($this->hasFunctionCallWithForeachArgument($node, $this->arrayModifyingFunctions, false)) { $this->addContextMessage( 'Possible array modification using internal function in a by-reference foreach loop', $node ); } } /** * @param Node $node * @param array $functions * @param null|bool $skippedByRefType Reference type (by value/by reference) to skip * * @return bool */ protected function hasFunctionCallWithForeachArgument(Node $node, array $functions, $skippedByRefType = null) { if (!$this->functionAnalyzer->isFunctionCallByStaticName($node, $functions)) { return false; } /** @var Node\Expr\FuncCall $node */ foreach ($node->args as $argument) { /** @var Node\Stmt\Foreach_ $foreach */ foreach ($this->foreachStack as $foreach) { if ($skippedByRefType !== null && $foreach->byRef === $skippedByRefType) { continue; } if ($argument->value instanceof Node\Expr\Variable && $argument->value->name === $this->getForeachVariableName($foreach) ) { return true; } } } return false; } /** * @param Node $node */ protected function checkAddingToArrayInByReferenceForeach(Node $node) { if (!($node instanceof Node\Expr\Assign || $node instanceof Node\Expr\AssignRef) || !$node->var instanceof Node\Expr\ArrayDimFetch || !$node->var->var instanceof Node\Expr\Variable ) { return; } /** @var Node\Stmt\Foreach_ $foreach */ foreach ($this->foreachStack as $foreach) { if (!$foreach->byRef) { continue; } if ($node->var->var->name === $this->getForeachVariableName($foreach)) { $this->addContextMessage( 'Possible adding to array on the last iteration of a by-reference foreach loop', $node ); } } } protected function checkNestedByReferenceForeach(Node\Stmt\Foreach_ $foreach) { if (!$foreach->byRef) { return; } /** @var Node\Stmt\Foreach_ $ancestorForeach */ foreach ($this->foreachStack as $ancestorForeach) { if ($ancestorForeach->byRef) { $this->addContextMessage( 'Nested by-reference foreach loop, make sure there is no iteration over the same array', $foreach ); return; } } } protected function getForeachVariableName(Node\Stmt\Foreach_ $foreach) { if ($foreach->expr instanceof Node\Expr\Variable) { return $foreach->expr->name; } elseif (($foreach->expr instanceof Node\Expr\Assign || $foreach->expr instanceof Node\Expr\AssignRef) && $foreach->expr->var instanceof Node\Expr\Variable ) { return $foreach->expr->var->name; } return; } } php7cc-1.1.0/src/NodeVisitor/FuncGetArgsVisitor.php000066400000000000000000000055021271610560000221720ustar00rootroot00000000000000functionAnalyzer = $functionAnalyzer; } public function beforeTraverse(array $nodes) { $this->argumentModificationStack = new \SplStack(); } public function enterNode(Node $node) { $isCurrentNodeFunctionLike = $node instanceof Node\FunctionLike; if ($isCurrentNodeFunctionLike || $this->argumentModificationStack->isEmpty() || !$this->argumentModificationStack->top() || !$this->functionAnalyzer->isFunctionCallByStaticName($node, array_flip(array('func_get_arg', 'func_get_args'))) ) { $isCurrentNodeFunctionLike && $this->argumentModificationStack->push(false); return; } /** @var Node\Expr\FuncCall $node */ $functionName = $node->name->toString(); $this->addContextMessage( sprintf('Function argument(s) returned by "%s" might have been modified', $functionName), $node ); } public function leaveNode(Node $node) { if ($this->argumentModificationStack->isEmpty()) { return; } if ($node instanceof Node\FunctionLike) { $this->argumentModificationStack->pop(); return; } foreach ($this->possiblyArgumentModifyingClasses as $class) { if ($node instanceof $class) { $this->argumentModificationStack->pop(); $this->argumentModificationStack->push(true); return; } } } } php7cc-1.1.0/src/NodeVisitor/GlobalNewFunctionVisitor.php000066400000000000000000000011401271610560000233740ustar00rootroot00000000000000namespacedName) && count($node->namespacedName->parts) == 1; } /** * {@inheritdoc} */ protected function getMessageText($functionName) { return sprintf('Cannot redeclare global function "%s"', $functionName); } } php7cc-1.1.0/src/NodeVisitor/GlobalVariableVariableVisitor.php000066400000000000000000000024271271610560000243410ustar00rootroot00000000000000vars as $globalVariable) { if (!( $globalVariable->name instanceof Node\Expr\PropertyFetch || $globalVariable->name instanceof Node\Expr\StaticPropertyFetch || $globalVariable->name instanceof Node\Expr\ArrayDimFetch ) ) { continue; } $startTokenPosition = $globalVariable->getAttribute('startTokenPos') + 1; $endTokenPosition = $globalVariable->getAttribute('endTokenPos'); if ($this->tokenCollection->isTokenEqualToOrPrecededBy($startTokenPosition, '{') && $this->tokenCollection->isTokenEqualToOrFollowedBy($endTokenPosition, '}') ) { continue; } $this->addContextMessage( 'Complex variable without curly braces in global keyword', $node ); } } } php7cc-1.1.0/src/NodeVisitor/HTTPRawPostDataVisitor.php000066400000000000000000000021431271610560000227110ustar00rootroot00000000000000name === static::HTTP_RAW_POST_DATA_VARIABLE_NAME; $isVariableAccessedThroughGlobals = $node instanceof Node\Expr\ArrayDimFetch && $node->var instanceof Node\Expr\Variable && $node->var->name == 'GLOBALS' && $node->dim instanceof Node\Scalar\String_ && $node->dim->value === static::HTTP_RAW_POST_DATA_VARIABLE_NAME; if ($isVariableAccessedByName || $isVariableAccessedThroughGlobals) { $this->addContextMessage( sprintf( 'Removed "%s" variable used', static::HTTP_RAW_POST_DATA_VARIABLE_NAME ), $node ); } } } php7cc-1.1.0/src/NodeVisitor/HexadecimalNumberStringVisitor.php000066400000000000000000000011031271610560000245570ustar00rootroot00000000000000value)) { $this->addContextMessage( 'String containing number in hexadecimal notation', $node ); } } } php7cc-1.1.0/src/NodeVisitor/IndirectVariableOrMethodAccessVisitor.php000066400000000000000000000020271271610560000260140ustar00rootroot00000000000000name instanceof Node\Expr\ArrayDimFetch ) { return; } $nodeName = $node->name; if ($this->tokenCollection->isTokenEqualToOrPrecededBy($nodeName->getAttribute('startTokenPos') - 1, '{') && $this->tokenCollection->isTokenEqualToOrFollowedBy($nodeName->getAttribute('endTokenPos') + 1, '}') ) { return; } $this->addContextMessage( 'Indirect variable, property or method access', $node ); } } php7cc-1.1.0/src/NodeVisitor/InvalidOctalLiteralVisitor.php000066400000000000000000000012231271610560000237040ustar00rootroot00000000000000getAttribute('originalValue', ''); if (preg_match('/^0[0-7]*[89]+/', $originalNumberValue)) { $this->addContextMessage( sprintf('Invalid octal literal %s', $originalNumberValue), $node ); } } } php7cc-1.1.0/src/NodeVisitor/ListVisitor.php000066400000000000000000000020351271610560000207330ustar00rootroot00000000000000vars as $var) { if ($var !== null) { $hasNonNullVar = true; break; } } if (!$hasNonNullVar) { $this->addContextMessage( 'Empty list assignment', $node ); } } if ($node instanceof Node\Expr\Assign && $node->var instanceof Node\Expr\List_ && ($node->expr instanceof Node\Scalar\String_ || $node->expr instanceof Node\Expr\Cast\String_) ) { $this->addContextMessage( 'list unpacking string', $node ); } } } php7cc-1.1.0/src/NodeVisitor/MktimeVisitor.php000066400000000000000000000021361271610560000212500ustar00rootroot00000000000000functionAnalyzer = $functionAnalyzer; $this->mktimeFamilyFunctions = array_flip($this->mktimeFamilyFunctions); } public function enterNode(Node $node) { if (!$this->functionAnalyzer->isFunctionCallByStaticName($node, $this->mktimeFamilyFunctions) || count($node->args) < 7 ) { return; } $this->addContextMessage( sprintf('Removed argument $is_dst used for function "%s"', $node->name->__toString()), $node ); } } php7cc-1.1.0/src/NodeVisitor/MultipleSwitchDefaultsVisitor.php000066400000000000000000000013331271610560000244650ustar00rootroot00000000000000cases as $case) { if ($case->cond === null) { ++$defaultCaseCount; } } if ($defaultCaseCount > 1) { $this->addContextMessage( 'Multiple default cases defined for the switch statement', $node ); } } } php7cc-1.1.0/src/NodeVisitor/NamespacedNewFunctionVisitor.php000066400000000000000000000012641271610560000242430ustar00rootroot00000000000000namespacedName) && count($node->namespacedName->parts) > 1; } /** * {@inheritdoc} */ protected function getMessageText($functionName) { return sprintf( 'Your namespaced function "%s" could replace the new global function added in PHP 7', $functionName ); } } php7cc-1.1.0/src/NodeVisitor/NewAssignmentByReferenceVisitor.php000066400000000000000000000010031271610560000247060ustar00rootroot00000000000000expr instanceof Node\Expr\New_) { $this->addContextMessage( 'Result of new is assigned by reference', $node ); } } } php7cc-1.1.0/src/NodeVisitor/NewClassVisitor.php000066400000000000000000000027011271610560000215370ustar00rootroot00000000000000namespacedName) // Property set by the NameResolver visitor && count($node->namespacedName->parts) === 1 && ($lowerCasedClassName = strtolower($node->name)) && array_key_exists($lowerCasedClassName, self::$lowerCasedNewClasses)) { $this->addContextMessage( sprintf( 'Class/trait/interface "%s" was added in the global namespace', self::$lowerCasedNewClasses[$lowerCasedClassName] ), $node ); } } } php7cc-1.1.0/src/NodeVisitor/PHP4ConstructorVisitor.php000066400000000000000000000031021271610560000227750ustar00rootroot00000000000000name; $hasPhp4Constructor = false; $hasPhp5Constructor = false; $php4ConstructorNode = null; // Anonymous class can't use php4 constructor by definition if (empty($currentClassName)) { return; } // Checks if class is namespaced (property namespacedName was set by the NameResolver visitor) if (count($node->namespacedName->parts) > 1) { return; } foreach ($node->stmts as $stmt) { // Check for constructors if ($stmt instanceof Node\Stmt\ClassMethod) { if ($stmt->name === '__construct') { $hasPhp5Constructor = true; } if ($stmt->name === $currentClassName) { $hasPhp4Constructor = true; $php4ConstructorNode = $stmt; } } } if ($hasPhp4Constructor && !$hasPhp5Constructor) { $this->addContextMessage( 'PHP 4 constructors are now deprecated', $php4ConstructorNode ); } } } } php7cc-1.1.0/src/NodeVisitor/PasswordHashSaltVisitor.php000066400000000000000000000030321271610560000232500ustar00rootroot00000000000000functionAnalyzer = $functionAnalyzer; } public function enterNode(Node $node) { if (!$this->functionAnalyzer->isFunctionCallByStaticName($node, array('password_hash' => true)) || !isset($node->args[static::PASSWORD_HASH_OPTIONS_ARGUMENT_INDEX]) || !($node->args[static::PASSWORD_HASH_OPTIONS_ARGUMENT_INDEX]->value instanceof Node\Expr\Array_) ) { return; } /** @var Node\Expr\Array_ $passwordHashOptions */ $passwordHashOptions = $node->args[static::PASSWORD_HASH_OPTIONS_ARGUMENT_INDEX]->value; /** @var $node Node\Expr\FuncCall */ foreach ($passwordHashOptions->items as $option) { if ($option->key instanceof Node\Scalar\String_ && $option->key->value === 'salt') { $this->addContextMessage( 'Deprecated option "salt" passed to password_hash function', $node ); break; } } } } php7cc-1.1.0/src/NodeVisitor/PregReplaceEvalVisitor.php000066400000000000000000000030211271610560000230150ustar00rootroot00000000000000regExpParser = $regExpParser; $this->functionAnalyzer = $functionAnalyzer; } public function enterNode(Node $node) { if (!$this->functionAnalyzer->isFunctionCallByStaticName($node, 'preg_replace')) { return; } /** @var Node\Expr\FuncCall $node */ $regExpPatternArgument = $node->args[0]; if (!$regExpPatternArgument->value instanceof Node\Scalar\String_) { return; } $regExp = $this->regExpParser->parse($regExpPatternArgument->value->value); if ($regExp->hasModifier(static::PREG_REPLACE_EVAL_MODIFIER)) { $this->addContextMessage( sprintf('Removed regular expression modifier "%s" used', static::PREG_REPLACE_EVAL_MODIFIER), $node ); } } } php7cc-1.1.0/src/NodeVisitor/RemovedFunctionCallVisitor.php000066400000000000000000000105531271610560000237270ustar00rootroot00000000000000functionAnalyzer = $functionAnalyzer; $this->removedFunctionNames = array_flip($this->removedFunctionNames); } public function enterNode(Node $node) { if (!$this->functionAnalyzer->isFunctionCallByStaticName($node, $this->removedFunctionNames)) { return; } /** @var Node\Expr\FuncCall $node */ $this->addContextMessage( sprintf('Removed function "%s" called', $node->name->toString()), $node ); } } php7cc-1.1.0/src/NodeVisitor/ReservedClassNameVisitor.php000066400000000000000000000051741271610560000233750ustar00rootroot00000000000000functionAnalyzer = $functionAnalyzer; $this->reservedNamesToMessagesMap = array_merge( array_fill_keys( $this->reservedClassNames, static::RESERVED_NAME_MESSAGE ), array_fill_keys( $this->futureReservedClassNames, static::FUTURE_RESERVED_NAME_MESSAGE ) ); } public function enterNode(Node $node) { $checkedName = ''; $usagePatternName = null; if ($node instanceof Node\Stmt\ClassLike) { $checkedName = $node->name; $usagePatternName = 'as a class, interface or trait name'; } elseif ($this->functionAnalyzer->isFunctionCallByStaticName($node, 'class_alias')) { /** @var Node\Expr\FuncCall $node */ $secondArgument = isset($node->args[1]) ? $node->args[1] : null; if (!$secondArgument || !$secondArgument->value instanceof Node\Scalar\String_) { return; } $checkedName = $secondArgument->value->value; $usagePatternName = 'as a class alias'; } elseif ($node instanceof Node\Stmt\UseUse) { $checkedName = $node->alias; $usagePatternName = 'as a use statement alias'; } $checkedName = strtolower($checkedName); if ($checkedName && isset($this->reservedNamesToMessagesMap[$checkedName])) { $this->addContextMessage( sprintf($this->reservedNamesToMessagesMap[$checkedName], $checkedName, $usagePatternName), $node ); } } } php7cc-1.1.0/src/NodeVisitor/Resolver.php000066400000000000000000000022001271610560000202330ustar00rootroot00000000000000addVisitor($visitor); } $this->level = $level; } /** * {@inheritdoc} */ public function resolve() { $level = $this->level; return array_values(array_filter($this->visitors, function (VisitorInterface $visitor) use ($level) { return $visitor->getLevel() >= $level; })); } /** * @param int $level */ public function setLevel($level) { $this->level = $level; } /** * @param VisitorInterface $visitor */ protected function addVisitor(VisitorInterface $visitor) { $this->visitors[] = $visitor; } } php7cc-1.1.0/src/NodeVisitor/ResolverInterface.php000066400000000000000000000003571271610560000220670ustar00rootroot00000000000000functionAnalyzer = $functionAnalyzer; } public function enterNode(Node $node) { if ($this->functionAnalyzer->isFunctionCallByStaticName($node, array('session_set_save_handler' => true))) { $this->addContextMessage( 'Check that callbacks that are passed to "session_set_save_handler" ' . 'and return false or -1 (if any) operate correctly', $node ); } } } php7cc-1.1.0/src/NodeVisitor/SetcookieEmptyNameVisitor.php000066400000000000000000000031701271610560000235660ustar00rootroot00000000000000 true, 'setrawcookie' => true, ); /** * @var FunctionAnalyzer */ protected $functionAnalyzer; /** * @param FunctionAnalyzer $functionAnalyzer */ public function __construct(FunctionAnalyzer $functionAnalyzer) { $this->functionAnalyzer = $functionAnalyzer; } public function enterNode(Node $node) { if (!$this->functionAnalyzer->isFunctionCallByStaticName($node, self::$setcookieFamilyFunctions)) { return; } /** @var Node\Expr\FuncCall $node */ $cookieNameArgumentValue = isset($node->args[0]) ? $node->args[0]->value : null; $isEmptyString = $cookieNameArgumentValue && $cookieNameArgumentValue instanceof Node\Scalar\String_ && $cookieNameArgumentValue->value === ''; $isEmptyConstant = $cookieNameArgumentValue && $cookieNameArgumentValue instanceof Node\Expr\ConstFetch && in_array(strtolower($cookieNameArgumentValue->name->toString()), array('null', 'false'), true); if ($isEmptyConstant || $isEmptyString) { $this->addContextMessage( sprintf('Function "%s" called with an empty cookie name', $node->name->toString()), $node ); } } } php7cc-1.1.0/src/NodeVisitor/VisitorInterface.php000066400000000000000000000010531271610560000217170ustar00rootroot00000000000000lowerPrecedenceExpressionClasses = array_flip($this->lowerPrecedenceExpressionClasses); } public function enterNode(Node $node) { if (!($node instanceof Node\Expr\Yield_ && $node->value && $node->value instanceof Node\Expr)) { return; } $valueClass = get_class($node->value); if (isset($this->lowerPrecedenceExpressionClasses[$valueClass])) { $this->addContextMessage( 'Yielding expression with precedence lower than "yield"', $node ); } } } php7cc-1.1.0/src/NodeVisitor/YieldInExpressionContextVisitor.php000066400000000000000000000026261271610560000250100ustar00rootroot00000000000000expressionStack = new \SplStack(); } public function enterNode(Node $node) { if ($node instanceof Node\Expr\Yield_) { $startTokenPosition = $node->getAttribute('startTokenPos'); $endTokenPosition = $node->getAttribute('endTokenPos'); if (!( $this->tokenCollection->isTokenPrecededBy($startTokenPosition, '(') && $this->tokenCollection->isTokenFollowedBy($endTokenPosition, ')') ) && !$this->expressionStack->isEmpty() ) { $this->addContextMessage( '"yield" usage in expression context', $this->expressionStack->top() ); } } elseif ($node instanceof Node\Expr) { $this->expressionStack->push($node); } } public function leaveNode(Node $node) { if (!$this->expressionStack->isEmpty() && $node === $this->expressionStack->top()) { $this->expressionStack->pop(); } } } php7cc-1.1.0/src/PathCheckExecutor.php000066400000000000000000000034031271610560000175440ustar00rootroot00000000000000pathTraversableFactory = $pathTraversableFactory; $this->pathChecker = $pathChecker; $this->traverser = $traverser; $this->visitorResolver = $visitorResolver; } /** * @param PathCheckSettings $checkSettings */ public function check(PathCheckSettings $checkSettings) { $this->visitorResolver->setLevel($checkSettings->getMessageLevel()); foreach ($this->visitorResolver->resolve() as $visitor) { $this->traverser->addVisitor($visitor); } $this->pathChecker->check( $this->pathTraversableFactory->createTraversable( $checkSettings->getCheckedPaths(), $checkSettings->getCheckedFileExtensions(), $checkSettings->getExcludedPaths() ), $checkSettings->getUseRelativePaths() ); } } php7cc-1.1.0/src/PathCheckSettings.php000066400000000000000000000042501271610560000175470ustar00rootroot00000000000000checkedPaths = $checkedPaths; $this->checkedFileExtensions = $checkedFileExtensions; } /** * @return array */ public function getCheckedPaths() { return $this->checkedPaths; } /** * @return array */ public function getCheckedFileExtensions() { return $this->checkedFileExtensions; } /** * @return array */ public function getExcludedPaths() { return $this->excludedPaths; } /** * @param array $excludedPaths */ public function setExcludedPaths($excludedPaths) { $this->excludedPaths = $excludedPaths; } /** * @return int */ public function getMessageLevel() { return $this->messageLevel; } /** * @param int $messageLevel */ public function setMessageLevel($messageLevel) { $this->messageLevel = $messageLevel; } /** * @return bool */ public function getUseRelativePaths() { return $this->useRelativePaths; } /** * @param bool $useRelativePaths */ public function setUseRelativePaths($useRelativePaths) { $this->useRelativePaths = $useRelativePaths; } } php7cc-1.1.0/src/PathChecker.php000066400000000000000000000033441271610560000163600ustar00rootroot00000000000000contextChecker = $fileChecker; $this->resultPrinter = $resultPrinter; } /** * @param \Traversable $traversablePaths * @param bool $useRelativePaths */ public function check(\Traversable $traversablePaths, $useRelativePaths) { $checkMetadata = new CheckMetadata(); /** @var SplFileInfo $fileInfo */ foreach ($traversablePaths as $fileInfo) { $this->checkFile($checkMetadata, $fileInfo, $useRelativePaths); } $checkMetadata->endCheck(); $this->resultPrinter->printMetadata($checkMetadata); } /** * @param CheckMetadata $checkMetadata * @param SplFileInfo $fileInfo * @param bool $useRelativePaths */ protected function checkFile(CheckMetadata $checkMetadata, SplFileInfo $fileInfo, $useRelativePaths) { $context = new FileContext($fileInfo, $useRelativePaths); $this->contextChecker->checkContext($context); if ($context->hasMessagesOrErrors()) { $this->resultPrinter->printContext($context); } $checkMetadata->incrementCheckedFileCount(); } } php7cc-1.1.0/src/PathTraversableFactory.php000066400000000000000000000037631271610560000206230ustar00rootroot00000000000000excludedPathCanonicalizer = $excludedPathCanonicalizer; } /** * @param string[] $paths Files and/or directories to check * @param string[] $checkedExtensions Only files having these extensions will be checked * @param string[] $excludedPaths * * @return \Traversable */ public function createTraversable(array $paths, array $checkedExtensions, array $excludedPaths) { $directlyPassedFiles = array(); $excludedPaths = $this->excludedPathCanonicalizer->canonicalize($paths, $excludedPaths); foreach ($paths as $path) { if (is_dir($path) && !$checkedExtensions) { throw new \DomainException('At least 1 extension must be specified to check a directory'); } elseif (is_file($path)) { $directlyPassedFiles[] = realpath($path); } } $fileDirectoryIterator = new FileDirectoryListRecursiveIterator($paths); $extensionFilteringIterator = new ExtensionFilteringRecursiveIterator( $fileDirectoryIterator, $checkedExtensions, $directlyPassedFiles ); $excludedPathFilteringIterator = new ExcludedPathFilteringRecursiveIterator( $extensionFilteringIterator, $excludedPaths ); return new \RecursiveIteratorIterator( $excludedPathFilteringIterator, \RecursiveIteratorIterator::LEAVES_ONLY ); } } php7cc-1.1.0/src/ResultPrinterInterface.php000066400000000000000000000006451271610560000206430ustar00rootroot00000000000000 $rawToken) { if (is_array($rawToken) && count($rawToken) < 3) { throw new \InvalidArgumentException(sprintf('Array token at index %d has less than 3 elements', $i)); } } $this->tokens = $rawTokens; } /** * @param int $tokenPosition * * @return string */ public function getTokenStringValueAt($tokenPosition) { if (!isset($this->tokens[$tokenPosition])) { throw new \OutOfBoundsException(sprintf('Token at offset %d does not exist', $tokenPosition)); } $originalToken = $this->tokens[$tokenPosition]; return is_string($originalToken) ? $originalToken : $originalToken[static::TOKEN_ORIGINAL_VALUE_OFFSET]; } /** * @param int $tokenPosition * @param string $stringValue * * @return bool */ public function isTokenEqualTo($tokenPosition, $stringValue) { return $this->getTokenStringValueAt($tokenPosition) === $stringValue; } /** * @param int $tokenPosition * @param string $stringValue * * @return bool */ public function isTokenPrecededBy($tokenPosition, $stringValue) { return $this->isNextNonWhitespaceTokenEqualTo($tokenPosition, $stringValue, false); } /** * @param int $tokenPosition * @param string $stringValue * * @return bool */ public function isTokenFollowedBy($tokenPosition, $stringValue) { return $this->isNextNonWhitespaceTokenEqualTo($tokenPosition, $stringValue, true); } /** * @param int $tokenPosition * @param string $stringValue * * @return bool */ public function isTokenEqualToOrPrecededBy($tokenPosition, $stringValue) { return $this->isTokenEqualTo($tokenPosition, $stringValue) || $this->isTokenPrecededBy($tokenPosition, $stringValue); } /** * @param int $tokenPosition * @param int $stringValue * * @return bool */ public function isTokenEqualToOrFollowedBy($tokenPosition, $stringValue) { return $this->isTokenEqualTo($tokenPosition, $stringValue) || $this->isTokenFollowedBy($tokenPosition, $stringValue); } /** * Whitespace tokens are ignored when $stringValue is not whitespace. * * @param int $tokenPosition * @param string $stringValue * @param bool $scanForward Scan forward if true, otherwise backward * * @return bool */ protected function isNextNonWhitespaceTokenEqualTo($tokenPosition, $stringValue, $scanForward) { $ignoreWhitespace = !ctype_space($stringValue); while (isset($this->tokens[$scanForward ? ++$tokenPosition : --$tokenPosition])) { $currentTokenString = $this->getTokenStringValueAt($tokenPosition); if ($ignoreWhitespace && ctype_space($currentTokenString)) { continue; } return $stringValue === $currentTokenString; } return false; } } php7cc-1.1.0/test/000077500000000000000000000000001271610560000136525ustar00rootroot00000000000000php7cc-1.1.0/test/code/000077500000000000000000000000001271610560000145645ustar00rootroot00000000000000php7cc-1.1.0/test/code/CompatibilityViolation/000077500000000000000000000000001271610560000212625ustar00rootroot00000000000000php7cc-1.1.0/test/code/CompatibilityViolation/FileContextTest.php000066400000000000000000000026371271610560000250670ustar00rootroot00000000000000assertSame( $useRelativePaths ? $file->getRelativePathname() : $file->getRealPath(), $context->getCheckedResourceName() ); } public function testGetCheckedResourceNameProvider() { return array( array('/foo/bar.php', 'bar.php', true), array('C:\baz.php', 'test\bar.php', true), array('/foo/bar/baz.php', 'test/bar.php', false), array('C:\bar\baz.php', 'bar.php', false), ); } } class SplFileInfo extends BaseSplFileInfo { /** * @var string */ protected $fullPath; /** * {@inheritdoc} */ public function __construct($file, $relativePath, $relativePathname) { parent::__construct($file, $relativePath, $relativePathname); $this->fullPath = $file; } public function getRealPath() { return $this->fullPath; } } php7cc-1.1.0/test/code/ContextCheckerTest.php000066400000000000000000000132071271610560000210510ustar00rootroot00000000000000buildContainer( new Symfony\Component\Console\Output\NullOutput(), \Sstalle\php7cc\NodeVisitor\BitwiseShiftVisitor::MIN_INT_SIZE ); $contextChecker = $container['contextChecker']; /** @var \PhpParser\NodeTraverserInterface $traverser */ $traverser = $container['traverser']; /** @var \Sstalle\php7cc\NodeVisitor\ResolverInterface $resolver */ $resolver = $container['nodeVisitorResolver']; $resolver->setLevel(\Sstalle\php7cc\CompatibilityViolation\Message::LEVEL_INFO); foreach ($resolver->resolve() as $visitor) { $traverser->addVisitor($visitor); } $context = new \Sstalle\php7cc\CompatibilityViolation\StringContext($code, 'test'); $contextChecker->checkContext($context); $expectedMessageCount = count($expectedMessages); $actualMessages = array_merge($context->getMessages(), $context->getErrors()); $actualMessageCount = count($actualMessages); $this->assertEquals($expectedMessageCount, $actualMessageCount, $name); if ($expectedMessageCount == $actualMessageCount) { /** @var \Sstalle\php7cc\AbstractBaseMessage $message */ foreach ($actualMessages as $i => $message) { $this->assertEquals( $this->canonicalize($expectedMessages[$i]), $this->canonicalize($message->getRawText()), $name ); } } } /** * Copypasted from PhpParser\CodeTestAbstract. * * @return array */ public function messageProvider() { $it = new \RecursiveDirectoryIterator(__DIR__ . '/../resource'); $it = new \RecursiveIteratorIterator($it, \RecursiveIteratorIterator::LEAVES_ONLY); $it = new \RegexIterator($it, '(\.' . preg_quote('test') . '$)'); $tests = array(); foreach ($it as $file) { $fileName = realpath($file->getPathname()); $fileContents = file_get_contents($fileName); // parse sections $fileContents = explode('-----', $fileContents); $parts = array_map(function ($i, $section) { return $i % 2 != 0 ? $section : trim($section); }, array_keys($fileContents), $fileContents); // first part is the name $name = $this->canonicalize(array_shift($parts)); if ($this->containsVersionConstraint($name)) { if (!$this->satisfiesVersionConstraint($name)) { continue; } $name = $this->stripVersionConstraint($name); } $fullName = $name . ' (' . $fileName . ')'; // multiple sections possible with always two forming a pair foreach (array_chunk($parts, 2) as $chunk) { $messages = array_filter(explode("\n", $this->canonicalize($chunk[1]))); $tests[] = array($fullName, ltrim($chunk[0]), $messages); } } return $tests; } /** * @param string $name * * @return string */ protected function stripVersionConstraint($name) { $nameParts = explode("\n", $name); array_pop($nameParts); return implode("\n", $nameParts); } /** * @param string $name * * @return bool */ protected function containsVersionConstraint($name) { $nameParts = explode("\n", $name); return count($nameParts) > 1 && substr(end($nameParts), 0, 3) === 'PHP'; } /** * @param string $name * * @return bool */ protected function satisfiesVersionConstraint($name) { if ($this->containsVersionConstraint($name)) { $nameParts = explode("\n", $name); // last line contains version constraints $versionConstraints = array(); preg_match_all( '/\\s+(<|lt|<=|le|>|gt|>=|ge|==|=|eq|!=|<>|ne)([a-zA-Z0-9\\.\\-]+)/', end($nameParts), $versionConstraints ); if (!count(array_shift($versionConstraints))) { throw new \RuntimeException( sprintf( 'Version constraint %s was specified for test suite "%s" but no constraints could be extracted', end($nameParts), $this->stripVersionConstraint($name) ) ); }; foreach (range(0, count($versionConstraints[0]) - 1) as $constraintIndex) { if (!version_compare( PHP_VERSION, $versionConstraints[1][$constraintIndex], $versionConstraints[0][$constraintIndex] )) { return false; } } } return true; } /** * Copypasted from PhpParser\CodeTestAbstract. * * @param $str string * * @return string */ protected function canonicalize($str) { // trim from both sides $str = trim($str); // normalize EOL to \n $str = str_replace(array("\r\n", "\r"), "\n", $str); // trim right side of all lines return implode("\n", array_map('rtrim', explode("\n", $str))); } } php7cc-1.1.0/test/code/ExcludedPathCanonicalizerTest.php000066400000000000000000000075661271610560000232270ustar00rootroot00000000000000canonicalize(false, $checkedPaths, $excludedPaths, $expectedPaths); } /** * @dataProvider canonicalizeRelativePathsProvider */ public function testCanonicalizeRelativePaths($checkedPaths, $excludedPaths, $expectedPaths) { $this->canonicalize(true, $checkedPaths, $excludedPaths, $expectedPaths); } protected function canonicalize( $isDirectoryRelative, $checkedPaths, $excludedPaths, $expectedPaths ) { $stub = $this->getMockBuilder('Sstalle\\php7cc\\Helper\\Path\\PathHelperInterface') ->getMock(); $stub->method('isDirectoryRelative') ->willReturn($isDirectoryRelative); $canonicalizer = new ExcludedPathCanonicalizer($stub); $this->assertEquals($expectedPaths, $canonicalizer->canonicalize($checkedPaths, $excludedPaths)); } public function canonicalizeAbsolutePathsProvider() { return array( array( array('/foo'), array(), array(), ), array( array('/foo', '/bar'), array('baz'), array('baz'), ), array( array('/foo', '/bar'), array('baz', 'quux'), array('baz', 'quux'), ), array( array(), array('bar', 'baz'), array('bar', 'baz'), ), array( array('foo', 'bar'), array('baz', 'quux'), array('baz', 'quux'), ), ); } public function canonicalizeRelativePathsProvider() { return array( array( array('/foo'), array(), array(), ), array( array('/foo'), array('bar'), array( $this->implodeWithDirectorySeparator(array('/foo', 'bar')), ), ), array( array('/foo', '/bar'), array('baz'), array( $this->implodeWithDirectorySeparator(array('/foo', 'baz')), $this->implodeWithDirectorySeparator(array('/bar', 'baz')), ), ), array( array('/foo'), array('bar', 'baz'), array( $this->implodeWithDirectorySeparator(array('/foo', 'bar')), $this->implodeWithDirectorySeparator(array('/foo', 'baz')), ), ), array( array('/foo', '/bar'), array('baz', 'quux'), array( $this->implodeWithDirectorySeparator(array('/foo', 'baz')), $this->implodeWithDirectorySeparator(array('/bar', 'baz')), $this->implodeWithDirectorySeparator(array('/foo', 'quux')), $this->implodeWithDirectorySeparator(array('/bar', 'quux')), ), ), array( array('foo', 'bar'), array('baz', 'quux'), array(), ), array( array('foo'), array('baz'), array(), ), ); } protected function implodeWithDirectorySeparator(array $pieces) { return implode(DIRECTORY_SEPARATOR, $pieces); } } php7cc-1.1.0/test/code/Helper/000077500000000000000000000000001271610560000160035ustar00rootroot00000000000000php7cc-1.1.0/test/code/Helper/Path/000077500000000000000000000000001271610560000166775ustar00rootroot00000000000000php7cc-1.1.0/test/code/Helper/Path/AbstractPathHelperTest.php000066400000000000000000000021131271610560000237650ustar00rootroot00000000000000pathHelper = $this->createPathHelper(); } /** * @dataProvider isAbsolutePathProvider */ public function testIsAbsolutePath($path, $isAbsolute) { $this->assertSame($isAbsolute, $this->pathHelper->isAbsolute($path)); } /** * @dataProvider isDirectoryRelativePathProvider */ public function testIsDirectoryRelativePath($path, $isDirectoryRelative) { $this->assertSame($isDirectoryRelative, $this->pathHelper->isDirectoryRelative($path)); } /** * @return array */ abstract public function isAbsolutePathProvider(); /** * @return array */ abstract public function isDirectoryRelativePathProvider(); /** * @return PathHelperInterface */ abstract public function createPathHelper(); } php7cc-1.1.0/test/code/Helper/Path/UnixPathHelperTest.php000066400000000000000000000015311271610560000231500ustar00rootroot00000000000000isAbsolutePathProvider(); foreach ($absolutePathData as $i => $data) { $absolutePathData[$i][1] = !$absolutePathData[$i][1]; } return $absolutePathData; } } php7cc-1.1.0/test/code/Helper/Path/WindowsPathHelperTest.php000066400000000000000000000021371271610560000236620ustar00rootroot00000000000000parser = new RegExpParser(); } /** * @expectedException \InvalidArgumentException */ public function testThrowsExceptionOnEmptyRegExp() { $this->parser->parse(''); } /** * @dataProvider throwsExceptionOnRegExpWithoutClosingDelimiterProvider * @expectedException \InvalidArgumentException */ public function testThrowsExceptionOnRegExpWithoutClosingDelimiter($regExp) { $this->parser->parse($regExp); } /** * @dataProvider parsesRegExpCorrectlyProvider */ public function testParsesRegExpCorrectly( $regExp, $expectedStartDelimiter, $expectedEndDelimiter, $expectedExpression, $expectedModifiers ) { $parsedRegExp = $this->parser->parse($regExp); $this->assertEquals($expectedStartDelimiter, $parsedRegExp->getStartDelimiter()); $this->assertEquals($expectedEndDelimiter, $parsedRegExp->getEndDelimiter()); $this->assertEquals($expectedExpression, $parsedRegExp->getExpression()); $this->assertEquals($expectedModifiers, $parsedRegExp->getModifiers()); } public function throwsExceptionOnRegExpWithoutClosingDelimiterProvider() { return array( array('/foo'), array('#foo'), ); } public function parsesRegExpCorrectlyProvider() { return array( array( '/foo/bar', '/', '/', 'foo', 'bar', ), array( '(foo)b', '(', ')', 'foo', 'b', ), array( '#foo#', '#', '#', 'foo', '', ), array( '{a}', '{', '}', 'a', '', ), array( '[a]', '[', ']', 'a', '', ), array( '', '<', '>', 'a', '', ), ); } } php7cc-1.1.0/test/code/Helper/RegExp/RegExpTest.php000066400000000000000000000053211271610560000217410ustar00rootroot00000000000000assertSame($hasModifier, $regexp->hasModifier($testedModifier)); } public function throwsExceptionWithEmptyDelimiterProvider() { return array( array(null), array(''), ); } public function throwsExceptionWithInvalidDelimiterProvider() { return array( array('a'), array('A'), array('0'), array('\\'), array(' '), ); } public function throwsExceptionWithNonMatchingDelimitersProvider() { return array( array('/', '#'), array('(', '('), array('[', '['), array('{', '{'), array('<', '<'), ); } public function hasModifierProvider() { return array( array('abc', 'a', true), array('abc', 'b', true), array('b', 'b', true), array('', 'b', false), array('a', 'b', false), array('aec', 'b', false), ); } } php7cc-1.1.0/test/code/Iterator/000077500000000000000000000000001271610560000163555ustar00rootroot00000000000000php7cc-1.1.0/test/code/Iterator/AbstractFilteringIteratorTest.php000066400000000000000000000064441271610560000250570ustar00rootroot00000000000000url(), \RecursiveDirectoryIterator::CURRENT_AS_FILEINFO | \RecursiveDirectoryIterator::KEY_AS_PATHNAME | \RecursiveDirectoryIterator::SKIP_DOTS | \RecursiveDirectoryIterator::UNIX_PATHS ); $iteratorClassReflection = new \ReflectionClass($this->getIteratorClass()); /** @var \RecursiveFilterIterator $filteringIterator */ array_unshift($filterArguments, $directoryIterator); $filteringIterator = $iteratorClassReflection->newInstanceArgs($filterArguments); $actualResult = array(); foreach ( new \RecursiveIteratorIterator($filteringIterator, \RecursiveIteratorIterator::LEAVES_ONLY) as $fileName ) { $actualResult[] = pathinfo($fileName, PATHINFO_BASENAME); } $this->assertEquals($expectedResult, $actualResult); } /** * @dataProvider throwsExceptionForInnerIteratorInvalidFlagsProvider */ public function testExceptionsForInnerIteratorFlags($flags, $expectException) { $dir = vfsStream::setup('root', null, array()); $directoryIterator = new \RecursiveDirectoryIterator( $dir->url(), $flags ); if ($expectException) { $this->setExpectedException('\\InvalidArgumentException'); } $iteratorClassReflection = new \ReflectionClass($this->getIteratorClass()); $iteratorClassReflection->newInstanceArgs( array_merge(array($directoryIterator), $this->getDefaultConstructorArguments()) ); } public function throwsExceptionForInnerIteratorInvalidFlagsProvider() { return array( array( \RecursiveDirectoryIterator::CURRENT_AS_PATHNAME | \RecursiveDirectoryIterator::KEY_AS_PATHNAME, true, ), array( \RecursiveDirectoryIterator::CURRENT_AS_SELF | \RecursiveDirectoryIterator::KEY_AS_PATHNAME, true, ), array( \RecursiveDirectoryIterator::CURRENT_AS_FILEINFO | \RecursiveDirectoryIterator::KEY_AS_FILENAME, true, ), array( \RecursiveDirectoryIterator::CURRENT_AS_PATHNAME | \RecursiveDirectoryIterator::KEY_AS_FILENAME, true, ), array( \RecursiveDirectoryIterator::CURRENT_AS_FILEINFO | \RecursiveDirectoryIterator::KEY_AS_PATHNAME, false, ), ); } /** * @return array */ abstract public function filterFilesProvider(); /** * @return string */ abstract public function getIteratorClass(); /** * @return array */ abstract public function getDefaultConstructorArguments(); } php7cc-1.1.0/test/code/Iterator/ExcludedPathFilteringRecursiveIteratorTest.php000066400000000000000000000063061271610560000275530ustar00rootroot00000000000000 array(), 'folder' => array( 'subfolder' => array( 'subfolderphp.php' => '1', ), 'folderphp.php' => '1', 'folderphp.test' => '1', ), 'topphp.php' => '1', ), array( array('vfs://root/folder'), ), array( 'topphp.php', ), ), array( array( 'empty' => array(), 'folder' => array( 'subfolder' => array( 'subfolderphp.php' => '1', ), 'folderphp.php' => '1', 'folderphp.test' => '1', ), 'topphp.php' => '1', ), array( array('vfs://root/folder/subfolder'), ), array( 'folderphp.php', 'folderphp.test', 'topphp.php', ), ), array( array( 'empty' => array(), 'folder' => array( 'subfolder' => array( 'subfolderphp.php' => '1', ), 'folderphp.php' => '1', 'folderphp.test' => '1', ), 'topphp.php' => '1', ), array( array(), ), array( 'subfolderphp.php', 'folderphp.php', 'folderphp.test', 'topphp.php', ), ), array( array( 'empty' => array( 'empty.php' => 'empty', ), 'folder' => array( 'subfolder' => array( 'subfolderphp.php' => '1', ), 'folderphp.php' => '1', 'folderphp.test' => '1', ), 'topphp.php' => '1', ), array( array('vfs://root/folder', 'vfs://root/empty'), ), array( 'topphp.php', ), ), ); } /** * {@inheritdoc} */ public function getIteratorClass() { return '\\Sstalle\\php7cc\\Iterator\\ExcludedPathFilteringRecursiveIterator'; } /** * {@inheritdoc} */ public function getDefaultConstructorArguments() { return array(array()); } } php7cc-1.1.0/test/code/Iterator/ExtensionFilteringRecursiveIteratorTest.php000066400000000000000000000060631271610560000271550ustar00rootroot00000000000000 array(), 'folder' => array( 'subfolder' => array( 'subfolderphp.php' => '1', ), 'folderphp.php' => '1', 'folderphp.test' => '1', ), 'topphp.php' => '1', ), array( array('test'), ), array( 'folderphp.test', ), ), array( array( 'empty' => array(), 'folder' => array( 'subfolder' => array( 'subfolderphp.php' => '1', ), 'folderphp.php' => '1', 'folderphp.test' => '1', ), 'topphp.php' => '1', ), array( array('php'), ), array( 'subfolderphp.php', 'folderphp.php', 'topphp.php', ), ), array( array( 'empty' => array(), 'folder' => array( 'subfolder' => array( 'subfolderphp.php' => '1', ), 'folderphp.php' => '1', 'folderphp.test' => '1', ), 'topphp.php' => '1', ), array( array('php', 'test'), ), array( 'subfolderphp.php', 'folderphp.php', 'folderphp.test', 'topphp.php', ), ), array( array( 'empty' => array(), 'folder' => array( 'subfolder' => array( 'subfolderphp.php' => '1', ), 'folderphp.php' => '1', 'folderphp.test' => '1', ), 'topphp.php' => '1', ), array( array(), ), array(), ), ); } /** * {@inheritdoc} */ public function getIteratorClass() { return '\\Sstalle\\php7cc\\Iterator\\ExtensionFilteringRecursiveIterator'; } /** * {@inheritdoc} */ public function getDefaultConstructorArguments() { return array(); } } php7cc-1.1.0/test/code/Iterator/FileDirectoryListRecursiveIteratorTest.php000066400000000000000000000057631271610560000267430ustar00rootroot00000000000000getChild($path)->url(); } $i = 0; $iterator = new \RecursiveIteratorIterator( new \Sstalle\php7cc\Iterator\FileDirectoryListRecursiveIterator($pathUrls), \RecursiveIteratorIterator::LEAVES_ONLY ); /** @var SplFileInfo $fileInfo */ foreach ($iterator as $fileInfo) { $this->assertEquals($expectedFileNames[$i++], $fileInfo->getRelativePathname()); } } public function testRelativePathNamesProvider() { return array( array( array( 'folder' => array( 'subfolder' => array( 'test.php' => '1', ), 'anothersubfolder' => array( 'test2.php' => '1', ), ), ), array( 'folder', ), array( 'subfolder/test.php', 'anothersubfolder/test2.php', ), ), array( array( 'folder' => array( 'subfolder' => array( 'test.php' => '1', ), 'anothersubfolder' => array( 'test2.php' => '1', ), ), ), array( 'folder/subfolder/test.php', ), array( 'test.php', ), ), array( array( 'folder' => array( 'subfolder' => array( 'test.php' => '1', ), 'anothersubfolder' => array( 'test2.php' => '1', ), ), 'anotherfolder' => array( 'test3.php' => '1', ), ), array( 'folder/subfolder', 'folder/anothersubfolder/test2.php', ), array( 'test.php', 'test2.php', 'test3.php', ), ), ); } } php7cc-1.1.0/test/code/Iterator/realpath.php000066400000000000000000000002501271610560000206630ustar00rootroot00000000000000assertSame($this->functionAnalyzer->isFunctionCallByStaticName($node, 'foo'), false); } public function testIsFunctionCallByStaticNameReturnsFalseForDynamicName() { $node = new FuncCall(new Variable('foo')); $this->assertSame($this->functionAnalyzer->isFunctionCallByStaticName($node, 'foo'), false); } /** * @dataProvider isFunctionCallByStaticNameChecksLowercaseFunctionNameCorrectlyProvider */ public function testIsFunctionCallByStaticNameChecksLowercaseFunctionNameCorrectly($node, $checkedFunctionNames, $result) { $this->assertSame($this->functionAnalyzer->isFunctionCallByStaticName($node, $checkedFunctionNames), $result); } /** * @dataProvider isFunctionCallByStaticNameChecksMixedCaseFunctionNameCorrectlyProvider */ public function testIsFunctionCallByStaticNameChecksMixedCaseFunctionNameCorrectly($node, $checkedFunctionNames, $result) { $this->assertSame($this->functionAnalyzer->isFunctionCallByStaticName($node, $checkedFunctionNames), $result); } public function isFunctionCallByStaticNameChecksLowercaseFunctionNameCorrectlyProvider() { return array( array( $this->buildFuncCallNodeWithStaticName('foo'), 'foo', true, ), array( $this->buildFuncCallNodeWithStaticName('foo'), array('foo' => true), true, ), array( $this->buildFuncCallNodeWithStaticName('bar'), array('foo' => true, 'bar' => true), true, ), array( $this->buildFuncCallNodeWithStaticName('foo'), 'bar', false, ), array( $this->buildFuncCallNodeWithStaticName('foo'), array('bar' => true), false, ), array( $this->buildFuncCallNodeWithStaticName('baz'), array('foo' => true, 'bar' => true), false, ), ); } public function isFunctionCallByStaticNameChecksMixedCaseFunctionNameCorrectlyProvider() { return array( array( $this->buildFuncCallNodeWithStaticName('fOo'), 'foo', true, ), array( $this->buildFuncCallNodeWithStaticName('FoO'), array('foo' => true), true, ), ); } /** * @param string $name * * @return FuncCall */ protected function buildFuncCallNodeWithStaticName($name) { return new FuncCall(new Name(array($name))); } /** * {@inheritdoc} */ protected function setUp() { $this->functionAnalyzer = new FunctionAnalyzer(); } } php7cc-1.1.0/test/code/NodeVisitor/000077500000000000000000000000001271610560000170315ustar00rootroot00000000000000php7cc-1.1.0/test/code/NodeVisitor/BitwiseShiftVisitorTest.php000066400000000000000000000040131271610560000243640ustar00rootroot00000000000000setExpectedException('\InvalidArgumentException'); } new \Sstalle\php7cc\NodeVisitor\BitwiseShiftVisitor($intSize); } /** * @dataProvider testDetectsShiftsLargerThanIntSizeProvider */ public function testDetectsShiftsLargerThanIntSize($intSize, $node, $expectedMessageCount) { $visitor = new \Sstalle\php7cc\NodeVisitor\BitwiseShiftVisitor($intSize); $testContext = new StringContext('', 'test'); $visitor->initializeContext($testContext); $visitor->enterNode($node); $this->assertEquals($expectedMessageCount, count($testContext->getMessages())); } public function testThrowsExceptionForInvalidIntSizeProvider() { return array( array(0, false), array(-5, false), array(-1, false), array(8, true), array(32, true), ); } public function testDetectsShiftsLargerThanIntSizeProvider() { $data = array(); foreach (array(16, 32, 64) as $intSize) { foreach (array(8, 16, 32, 64, 128) as $shiftWidth) { $data[] = array( $intSize, new Expr\BinaryOp\ShiftLeft(new LNumber(1), new LNumber($shiftWidth)), $shiftWidth >= $intSize ? 1 : 0, ); $data[] = array( $intSize, new Expr\BinaryOp\ShiftRight(new LNumber(1), new LNumber($shiftWidth)), $shiftWidth >= $intSize ? 1 : 0, ); } } return $data; } } php7cc-1.1.0/test/code/NodeVisitor/PHP4ConstructorVisitorTest.php000066400000000000000000000013161271610560000247440ustar00rootroot00000000000000getMockBuilder('PhpParser\Node\Stmt\Class_') ->disableOriginalConstructor() ->getMock(); // triggers a notice that it shouldn't $visitor->enterNode($node); $this->assertTrue(true); } } php7cc-1.1.0/test/code/NodeVisitor/ResolverTest.php000066400000000000000000000037041271610560000222070ustar00rootroot00000000000000getLevel() >= $level) { $expectedVisitors[] = $visitor; } } $this->assertSame($expectedVisitors, $resolver->resolve()); } public function testResolvesCorrectlyAccordingToLevelProvider() { $data = array( array(array(), Message::LEVEL_INFO), array(array(Message::LEVEL_INFO, Message::LEVEL_INFO), Message::LEVEL_INFO), array(array(Message::LEVEL_INFO, Message::LEVEL_WARNING), Message::LEVEL_WARNING), array(array(Message::LEVEL_INFO, Message::LEVEL_WARNING, Message::LEVEL_ERROR, Message::LEVEL_WARNING), Message::LEVEL_ERROR), array(array(Message::LEVEL_INFO, Message::LEVEL_INFO), Message::LEVEL_ERROR), ); foreach ($data as $i => $item) { $visitors = array(); foreach ($item[0] as $level) { $visitors[] = new DummyVisitor($level); } $data[$i][0] = $visitors; } return $data; } } class DummyVisitor extends AbstractVisitor { /** * @var int */ protected $level; /** * @param int $level */ public function __construct($level) { $this->level = $level; } public function getLevel() { return $this->level; } } php7cc-1.1.0/test/code/Token/000077500000000000000000000000001271610560000156445ustar00rootroot00000000000000php7cc-1.1.0/test/code/Token/TokenCollectionTest.php000066400000000000000000000165311271610560000223170ustar00rootroot00000000000000getTokenStringValueAt(0); } /** * @dataProvider getTokenStringValueAtReturnsCorrectStringValueProvider */ public function testGetTokenStringValueAtReturnsCorrectStringValue($rawToken, $stringValue) { $collection = new TokenCollection(array($rawToken)); $this->assertSame($stringValue, $collection->getTokenStringValueAt(0)); } public function testGetTokenStringValueAtReturnTokenAtCorrectIndex() { $rawTokens = self::$tokens; $collection = new TokenCollection($rawTokens); foreach ($rawTokens as $i => $rawValue) { $this->assertSame($rawValue, $collection->getTokenStringValueAt($i)); } } /** * @dataProvider isTokenEqualToProvider */ public function testIsTokenEqualTo($tokens, $position, $value, $isEqualTo) { $collection = new TokenCollection($tokens); $this->assertSame($isEqualTo, $collection->isTokenEqualTo($position, $value)); } /** * @dataProvider isTokenPrecededByProvider */ public function testIsTokenPrecededBy($tokens, $position, $value, $result) { $collection = new TokenCollection($tokens); $this->assertSame($result, $collection->isTokenPrecededBy($position, $value)); } /** * @dataProvider isTokenFollowedByProvider */ public function testIsTokenFollowedBy($tokens, $position, $value, $result) { $collection = new TokenCollection($tokens); $this->assertSame($result, $collection->isTokenFollowedBy($position, $value)); } /** * @dataProvider isTokenEqualToOrPrecededByProvider */ public function testIsTokenEqualToOrPrecededBy($tokens, $position, $value, $result) { $collection = new TokenCollection($tokens); $this->assertSame($result, $collection->isTokenEqualToOrPrecededBy($position, $value)); } /** * @dataProvider isTokenEqualToOrFollowedByProvider */ public function testIsTokenEqualToOrFollowedBy($tokens, $position, $value, $result) { $collection = new TokenCollection($tokens); $this->assertSame($result, $collection->isTokenEqualToOrFollowedBy($position, $value)); } public function isTokenEqualToProvider() { $data = array(); $tokenCount = count(self::$tokens); $testedIndexes = array(0, floor($tokenCount / 2), $tokenCount - 1); foreach ($testedIndexes as $i) { $data[] = array( self::$tokens, $i, self::$tokens[$i], true, ); $data[] = array( self::$tokens, $i, self::$tokens[$i] . mt_rand(), false, ); } return $data; } public function isTokenPrecededByProvider() { return array( array( self::$tokens, 0, 'foo', false, ), array( self::$tokens, 1, 'foo', true, ), array( self::$tokens, 8, 'foo', false, ), array( self::$tokens, 0, 'bar', false, ), array( self::$tokens, 1, 'bar', false, ), array( self::$tokens, 2, 'bar', true, ), array( self::$tokens, 8, 'bar', false, ), array( self::$tokens, 5, 'bar', true, ), array( self::$tokens, 4, "\r\n", true, ), array( self::$tokens, 4, "\t", false, ), ); } public function isTokenFollowedByProvider() { return array( array( self::$tokens, 0, 'foo', false, ), array( self::$tokens, 1, 'foo', false, ), array( self::$tokens, 8, 'foo', false, ), array( self::$tokens, 0, 'bar', true, ), array( self::$tokens, 1, 'bar', false, ), array( self::$tokens, 2, 'bar', false, ), array( self::$tokens, 8, 'bar', false, ), array( self::$tokens, 1, 'baz', true, ), array( self::$tokens, 2, "\r\n", true, ), array( self::$tokens, 2, "\t", false, ), ); } public function isTokenEqualToOrPrecededByProvider() { return $this->addEqualsToCurentConditionToPrecededOrFollowedByData($this->isTokenPrecededByProvider()); } public function isTokenEqualToOrFollowedByProvider() { return $this->addEqualsToCurentConditionToPrecededOrFollowedByData($this->isTokenFollowedByProvider()); } public function throwsExceptionOnArrayTokenWithNotEnoughElementsProvider() { return array( array(array()), array(array(1)), array(array(1, '')), ); } public function getTokenStringValueAtReturnsCorrectStringValueProvider() { return array( array( 'foo', 'foo', ), array( array(1, 'foo', 'bar'), 'foo', ), ); } protected function addEqualsToCurentConditionToPrecededOrFollowedByData($data) { foreach ($data as &$testCase) { $testCase[3] = $testCase[3] || self::$tokens[$testCase[1]] === $testCase[2]; } unset($testCase); return $data; } } php7cc-1.1.0/test/resource/000077500000000000000000000000001271610560000155015ustar00rootroot00000000000000php7cc-1.1.0/test/resource/arrayAssignByRef/000077500000000000000000000000001271610560000207145ustar00rootroot00000000000000php7cc-1.1.0/test/resource/arrayAssignByRef/arrayAssignmentByReference.test000066400000000000000000000005321271610560000270760ustar00rootroot00000000000000Assignment of array value by reference ----- b = &$a->bar; ----- Possible object property creation during by-reference assignment ----- {'foo'} = &$a->bar; ----- Possible object property creation during by-reference assignment ----- $b = &$a->$c; ----- Possible object property creation during by-reference assignment ----- b = $a->bar; ----- ----- b = &$c; ----- ----- $b = &$c; ----- ----- b = $c; ----- php7cc-1.1.0/test/resource/bitwiseShift/000077500000000000000000000000001271610560000201455ustar00rootroot00000000000000php7cc-1.1.0/test/resource/bitwiseShift/bitwiseShiftByNegativeBinaryNumber.test000066400000000000000000000004511271610560000300060ustar00rootroot00000000000000Bitwise shift by a negative binary number ----- > -0b10; ----- Bitwise shift by a negative number ----- > 0b0; ----- ----- > 0b1010; ----- ----- > -2; ----- Bitwise shift by a negative number ----- > 0; ----- ----- > 10; ----- ----- > -0x2; ----- Bitwise shift by a negative number ----- > 0x0; ----- ----- > 0xa; ----- ----- > -02; ----- Bitwise shift by a negative number ----- > 00; ----- ----- > 012; ----- ----- > 0b100000; ----- Bitwise shift by 32 bits ----- > 0b1000000; ----- Bitwise shift by 64 bits ----- > 0b10000; ----- ----- > 32; ----- Bitwise shift by 32 bits ----- > 64; ----- Bitwise shift by 64 bits ----- > 16; ----- ----- > 0x20; ----- Bitwise shift by 32 bits ----- > 0x40; ----- Bitwise shift by 64 bits ----- > 0x10; ----- ----- > 040; ----- Bitwise shift by 32 bits ----- > 0100; ----- Bitwise shift by 64 bits ----- > 020; ----- ----- &$b) { $a[] = $c; } ----- Possible adding to array on the last iteration of a by-reference foreach loop ----- &$b) { array_push($a, $c); } ----- Possible array modification using internal function in a by-reference foreach loop ----- >= 1; func_get_args(); } ----- Function argument(s) returned by "func_get_args" might have been modified ----- >= 1; func_get_arg(); } ----- Function argument(s) returned by "func_get_arg" might have been modified ----- >= 1; func_get_arg(1); } ----- Function argument(s) returned by "func_get_arg" might have been modified ----- bar(); func_get_args(); } ----- Function argument(s) returned by "func_get_args" might have been modified ----- bar(); func_get_arg(); } ----- Function argument(s) returned by "func_get_arg" might have been modified ----- bar(); func_get_arg(1); } ----- Function argument(s) returned by "func_get_arg" might have been modified ----- bar; ----- Complex variable without curly braces in global keyword ----- bar}; ----- ----- bar }; ----- php7cc-1.1.0/test/resource/hexadecimalStringNumber/000077500000000000000000000000001271610560000223055ustar00rootroot00000000000000php7cc-1.1.0/test/resource/hexadecimalStringNumber/hexadecimalStringNumber.test000066400000000000000000000007051271610560000300140ustar00rootroot00000000000000Hexadecimal number in string ----- $bar['baz'](); ----- Indirect variable, property or method access ----- {$bar['baz']}(); ----- ----- { $bar['baz'] }(); ----- ----- $bar['baz']; ----- Indirect variable, property or method access ----- $params['name']; ----- Indirect variable, property or method access ----- $field['name']; ----- Indirect variable, property or method access ----- $schema['node_name']; ----- Indirect variable, property or method access ----- {$bar['baz']}; ----- ----- { $bar['baz'] }; ----- ----- db->{$this->config[$name]}; ----- ----- db->$this->config[$name]; ----- ----- {$params['name']}; ----- ----- {$field['name']}; ----- ----- record->{$detail->to['name']}; ----- ----- record->$detail->to['name']; ----- ----- record->sku->getFirst()->{$detail->to['name']}; ----- ----- record->sku->getFirst()->$detail->to['name']; ----- ----- record->{$detail->to['name']}; ----- ----- record->$detail->to['name']; ----- ----- {$schema['node_name']}; ----- php7cc-1.1.0/test/resource/indirectVariableOrMethodAccess/indirectVariableAccess.test000066400000000000000000000003051271610560000310240ustar00rootroot00000000000000Indirect variable access ----- 's')); ----- Deprecated option "salt" passed to password_hash function ----- 'bar')); ----- -----